From a1cd9fcf73685a5b0c4e721d405550096d85d566 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 9 Jul 2018 14:53:20 +0200 Subject: Reduce line width, adding some switchboxes Signed-off-by: David Shah --- gui/fpgaviewwidget.cc | 6 +++--- ice40/arch.cc | 32 ++++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 0c6b1a98..831f80d4 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -346,7 +346,7 @@ void FPGAViewWidget::paintGL() matrix.scale(zoom_ * 0.01f, zoom_ * 0.01f, 0); // Draw grid. - auto grid = LineShaderData(0.01f, QColor("#DDD")); + auto grid = LineShaderData(0.001f, QColor("#DDD")); for (float i = -100.0f; i < 100.0f; i += 1.0f) { PolyLine(-100.0f, i, 100.0f, i).build(grid); PolyLine(i, -100.0f, i, 100.0f).build(grid); @@ -354,7 +354,7 @@ void FPGAViewWidget::paintGL() lineShader_.draw(grid, matrix); // Draw Bels. - auto bels = LineShaderData(0.02f, QColor("#b000ba")); + auto bels = LineShaderData(0.002f, QColor("#b000ba")); if (ctx_) { for (auto bel : ctx_->getBels()) { for (auto &el : ctx_->getBelGraphics(bel)) @@ -364,7 +364,7 @@ void FPGAViewWidget::paintGL() } // Draw Frame Graphics. - auto frames = LineShaderData(0.02f, QColor("#0066ba")); + auto frames = LineShaderData(0.002f, QColor("#0066ba")); if (ctx_) { for (auto &el : ctx_->getFrameGraphics()) { drawElement(frames, el); diff --git a/ice40/arch.cc b/ice40/arch.cc index 72f9c1f3..aed99b7b 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -424,12 +424,36 @@ std::vector Arch::getBelGraphics(BelId bel) const if (bel_type == TYPE_ICESTORM_LC) { GraphicElement el; el.type = GraphicElement::G_BOX; - el.x1 = chip_info->bel_data[bel.index].x + 0.1; - el.x2 = chip_info->bel_data[bel.index].x + 0.9; - el.y1 = chip_info->bel_data[bel.index].y + 0.10 + (chip_info->bel_data[bel.index].z) * (0.8 / 8); - el.y2 = chip_info->bel_data[bel.index].y + 0.18 + (chip_info->bel_data[bel.index].z) * (0.8 / 8); + el.x1 = chip_info->bel_data[bel.index].x + 0.82; + el.x2 = chip_info->bel_data[bel.index].x + 0.92; + el.y1 = chip_info->bel_data[bel.index].y + 0.30 + (chip_info->bel_data[bel.index].z) * (0.6 / 8); + el.y2 = chip_info->bel_data[bel.index].y + 0.35 + (chip_info->bel_data[bel.index].z) * (0.6 / 8); el.z = 0; ret.push_back(el); + + if (chip_info->bel_data[bel.index].z == 0) { + int tx = chip_info->bel_data[bel.index].x; + int ty = chip_info->bel_data[bel.index].y; + // Local tracks to LUT input switchbox + GraphicElement lc_lut_sw; + lc_lut_sw.type = GraphicElement::G_BOX; + lc_lut_sw.x1 = tx + 0.75; + lc_lut_sw.x2 = tx + 0.8; + lc_lut_sw.y1 = ty + 0.30; + lc_lut_sw.y2 = ty + 0.875; + lc_lut_sw.z = 0; + ret.push_back(lc_lut_sw); + // Local tracks switchbox + GraphicElement lc_sw; + lc_sw.type = GraphicElement::G_BOX; + lc_sw.x1 = tx + 0.6; + lc_sw.x2 = tx + 0.7; + lc_sw.y1 = ty + 0.65; + lc_sw.y2 = ty + 0.75; + ret.push_back(lc_sw); + + + } } if (bel_type == TYPE_SB_IO) { -- cgit v1.2.3 From 3be10f629a7a5eb68cfca01ac8a1464585817f22 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 9 Jul 2018 15:02:29 +0200 Subject: Add ice40 wire gfx enums Signed-off-by: Clifford Wolf --- ice40/arch.cc | 6 +- ice40/gfx.cc | 28 ++++ ice40/gfx.h | 456 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 489 insertions(+), 1 deletion(-) create mode 100644 ice40/gfx.cc create mode 100644 ice40/gfx.h diff --git a/ice40/arch.cc b/ice40/arch.cc index aed99b7b..ecd0a411 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -22,6 +22,8 @@ #include "log.h" #include "nextpnr.h" #include "util.h" +#include "gfx.h" + NEXTPNR_NAMESPACE_BEGIN // ----------------------------------------------------------------------- @@ -452,7 +454,9 @@ std::vector Arch::getBelGraphics(BelId bel) const lc_sw.y2 = ty + 0.75; ret.push_back(lc_sw); - + // All the wires + for (int i = TILE_WIRE_GLB2LOCAL_0; i <= TILE_WIRE_SP12_H_L_23; i++) + gfxTileWire(ret, tx, ty, GfxTileWireId(i)); } } diff --git a/ice40/gfx.cc b/ice40/gfx.cc new file mode 100644 index 00000000..46824b06 --- /dev/null +++ b/ice40/gfx.cc @@ -0,0 +1,28 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * 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 "gfx.h" + +NEXTPNR_NAMESPACE_BEGIN + +void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) +{ +} + +NEXTPNR_NAMESPACE_END diff --git a/ice40/gfx.h b/ice40/gfx.h new file mode 100644 index 00000000..e9cc0e16 --- /dev/null +++ b/ice40/gfx.h @@ -0,0 +1,456 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * 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. + * + */ + +#ifndef GFX_H +#define GFX_H + +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +enum GfxTileWireId { + TILE_WIRE_GLB2LOCAL_0, + TILE_WIRE_GLB2LOCAL_1, + TILE_WIRE_GLB2LOCAL_2, + TILE_WIRE_GLB2LOCAL_3, + + TILE_WIRE_GLB_NETWK_0, + TILE_WIRE_GLB_NETWK_1, + TILE_WIRE_GLB_NETWK_2, + TILE_WIRE_GLB_NETWK_3, + TILE_WIRE_GLB_NETWK_4, + TILE_WIRE_GLB_NETWK_5, + TILE_WIRE_GLB_NETWK_6, + TILE_WIRE_GLB_NETWK_7, + + TILE_WIRE_LOCAL_G0_0, + TILE_WIRE_LOCAL_G0_1, + TILE_WIRE_LOCAL_G0_2, + TILE_WIRE_LOCAL_G0_3, + TILE_WIRE_LOCAL_G0_4, + TILE_WIRE_LOCAL_G0_5, + TILE_WIRE_LOCAL_G0_6, + TILE_WIRE_LOCAL_G0_7, + + TILE_WIRE_LOCAL_G1_0, + TILE_WIRE_LOCAL_G1_1, + TILE_WIRE_LOCAL_G1_2, + TILE_WIRE_LOCAL_G1_3, + TILE_WIRE_LOCAL_G1_4, + TILE_WIRE_LOCAL_G1_5, + TILE_WIRE_LOCAL_G1_6, + TILE_WIRE_LOCAL_G1_7, + + TILE_WIRE_LOCAL_G2_0, + TILE_WIRE_LOCAL_G2_1, + TILE_WIRE_LOCAL_G2_2, + TILE_WIRE_LOCAL_G2_3, + TILE_WIRE_LOCAL_G2_4, + TILE_WIRE_LOCAL_G2_5, + TILE_WIRE_LOCAL_G2_6, + TILE_WIRE_LOCAL_G2_7, + + TILE_WIRE_LOCAL_G3_0, + TILE_WIRE_LOCAL_G3_1, + TILE_WIRE_LOCAL_G3_2, + TILE_WIRE_LOCAL_G3_3, + TILE_WIRE_LOCAL_G3_4, + TILE_WIRE_LOCAL_G3_5, + TILE_WIRE_LOCAL_G3_6, + TILE_WIRE_LOCAL_G3_7, + + TILE_WIRE_CARRY_IN, + TILE_WIRE_CARRY_IN_MUX, + + TILE_WIRE_LUTFF_0_COUT, + TILE_WIRE_LUTFF_0_IN_0, + TILE_WIRE_LUTFF_0_IN_1, + TILE_WIRE_LUTFF_0_IN_2, + TILE_WIRE_LUTFF_0_IN_3, + TILE_WIRE_LUTFF_0_LOUT, + TILE_WIRE_LUTFF_0_OUT, + + TILE_WIRE_LUTFF_1_COUT, + TILE_WIRE_LUTFF_1_IN_0, + TILE_WIRE_LUTFF_1_IN_1, + TILE_WIRE_LUTFF_1_IN_2, + TILE_WIRE_LUTFF_1_IN_3, + TILE_WIRE_LUTFF_1_LOUT, + TILE_WIRE_LUTFF_1_OUT, + + TILE_WIRE_LUTFF_2_COUT, + TILE_WIRE_LUTFF_2_IN_0, + TILE_WIRE_LUTFF_2_IN_1, + TILE_WIRE_LUTFF_2_IN_2, + TILE_WIRE_LUTFF_2_IN_3, + TILE_WIRE_LUTFF_2_LOUT, + TILE_WIRE_LUTFF_2_OUT, + + TILE_WIRE_LUTFF_3_COUT, + TILE_WIRE_LUTFF_3_IN_0, + TILE_WIRE_LUTFF_3_IN_1, + TILE_WIRE_LUTFF_3_IN_2, + TILE_WIRE_LUTFF_3_IN_3, + TILE_WIRE_LUTFF_3_LOUT, + TILE_WIRE_LUTFF_3_OUT, + + TILE_WIRE_LUTFF_4_COUT, + TILE_WIRE_LUTFF_4_IN_0, + TILE_WIRE_LUTFF_4_IN_1, + TILE_WIRE_LUTFF_4_IN_2, + TILE_WIRE_LUTFF_4_IN_3, + TILE_WIRE_LUTFF_4_LOUT, + TILE_WIRE_LUTFF_4_OUT, + + TILE_WIRE_LUTFF_5_COUT, + TILE_WIRE_LUTFF_5_IN_0, + TILE_WIRE_LUTFF_5_IN_1, + TILE_WIRE_LUTFF_5_IN_2, + TILE_WIRE_LUTFF_5_IN_3, + TILE_WIRE_LUTFF_5_LOUT, + TILE_WIRE_LUTFF_5_OUT, + + TILE_WIRE_LUTFF_6_COUT, + TILE_WIRE_LUTFF_6_IN_0, + TILE_WIRE_LUTFF_6_IN_1, + TILE_WIRE_LUTFF_6_IN_2, + TILE_WIRE_LUTFF_6_IN_3, + TILE_WIRE_LUTFF_6_LOUT, + TILE_WIRE_LUTFF_6_OUT, + + TILE_WIRE_LUTFF_7_COUT, + TILE_WIRE_LUTFF_7_IN_0, + TILE_WIRE_LUTFF_7_IN_1, + TILE_WIRE_LUTFF_7_IN_2, + TILE_WIRE_LUTFF_7_IN_3, + TILE_WIRE_LUTFF_7_OUT, + + TILE_WIRE_LUTFF_GLOBAL_CEN, + TILE_WIRE_LUTFF_GLOBAL_CLK, + TILE_WIRE_LUTFF_GLOBAL_S_R, + + TILE_WIRE_NEIGH_OP_BNL_0, + TILE_WIRE_NEIGH_OP_BNR_0, + TILE_WIRE_NEIGH_OP_BOT_0, + TILE_WIRE_NEIGH_OP_LFT_0, + TILE_WIRE_NEIGH_OP_RGT_0, + TILE_WIRE_NEIGH_OP_TNL_0, + TILE_WIRE_NEIGH_OP_TNR_0, + TILE_WIRE_NEIGH_OP_TOP_0, + + TILE_WIRE_NEIGH_OP_BNL_1, + TILE_WIRE_NEIGH_OP_BNR_1, + TILE_WIRE_NEIGH_OP_BOT_1, + TILE_WIRE_NEIGH_OP_LFT_1, + TILE_WIRE_NEIGH_OP_RGT_1, + TILE_WIRE_NEIGH_OP_TNL_1, + TILE_WIRE_NEIGH_OP_TNR_1, + TILE_WIRE_NEIGH_OP_TOP_1, + + TILE_WIRE_NEIGH_OP_BNL_2, + TILE_WIRE_NEIGH_OP_BNR_2, + TILE_WIRE_NEIGH_OP_BOT_2, + TILE_WIRE_NEIGH_OP_LFT_2, + TILE_WIRE_NEIGH_OP_RGT_2, + TILE_WIRE_NEIGH_OP_TNL_2, + TILE_WIRE_NEIGH_OP_TNR_2, + TILE_WIRE_NEIGH_OP_TOP_2, + + TILE_WIRE_NEIGH_OP_BNL_3, + TILE_WIRE_NEIGH_OP_BNR_3, + TILE_WIRE_NEIGH_OP_BOT_3, + TILE_WIRE_NEIGH_OP_LFT_3, + TILE_WIRE_NEIGH_OP_RGT_3, + TILE_WIRE_NEIGH_OP_TNL_3, + TILE_WIRE_NEIGH_OP_TNR_3, + TILE_WIRE_NEIGH_OP_TOP_3, + + TILE_WIRE_NEIGH_OP_BNL_4, + TILE_WIRE_NEIGH_OP_BNR_4, + TILE_WIRE_NEIGH_OP_BOT_4, + TILE_WIRE_NEIGH_OP_LFT_4, + TILE_WIRE_NEIGH_OP_RGT_4, + TILE_WIRE_NEIGH_OP_TNL_4, + TILE_WIRE_NEIGH_OP_TNR_4, + TILE_WIRE_NEIGH_OP_TOP_4, + + TILE_WIRE_NEIGH_OP_BNL_5, + TILE_WIRE_NEIGH_OP_BNR_5, + TILE_WIRE_NEIGH_OP_BOT_5, + TILE_WIRE_NEIGH_OP_LFT_5, + TILE_WIRE_NEIGH_OP_RGT_5, + TILE_WIRE_NEIGH_OP_TNL_5, + TILE_WIRE_NEIGH_OP_TNR_5, + TILE_WIRE_NEIGH_OP_TOP_5, + + TILE_WIRE_NEIGH_OP_BNL_6, + TILE_WIRE_NEIGH_OP_BNR_6, + TILE_WIRE_NEIGH_OP_BOT_6, + TILE_WIRE_NEIGH_OP_LFT_6, + TILE_WIRE_NEIGH_OP_RGT_6, + TILE_WIRE_NEIGH_OP_TNL_6, + TILE_WIRE_NEIGH_OP_TNR_6, + TILE_WIRE_NEIGH_OP_TOP_6, + + TILE_WIRE_NEIGH_OP_BNL_7, + TILE_WIRE_NEIGH_OP_BNR_7, + TILE_WIRE_NEIGH_OP_BOT_7, + TILE_WIRE_NEIGH_OP_LFT_7, + TILE_WIRE_NEIGH_OP_RGT_7, + TILE_WIRE_NEIGH_OP_TNL_7, + TILE_WIRE_NEIGH_OP_TNR_7, + TILE_WIRE_NEIGH_OP_TOP_7, + + TILE_WIRE_SP4_V_B_0, + TILE_WIRE_SP4_V_B_1, + TILE_WIRE_SP4_V_B_2, + TILE_WIRE_SP4_V_B_3, + TILE_WIRE_SP4_V_B_4, + TILE_WIRE_SP4_V_B_5, + TILE_WIRE_SP4_V_B_6, + TILE_WIRE_SP4_V_B_7, + TILE_WIRE_SP4_V_B_8, + TILE_WIRE_SP4_V_B_9, + TILE_WIRE_SP4_V_B_10, + TILE_WIRE_SP4_V_B_11, + TILE_WIRE_SP4_V_B_12, + TILE_WIRE_SP4_V_B_13, + TILE_WIRE_SP4_V_B_14, + TILE_WIRE_SP4_V_B_15, + TILE_WIRE_SP4_V_B_16, + TILE_WIRE_SP4_V_B_17, + TILE_WIRE_SP4_V_B_18, + TILE_WIRE_SP4_V_B_19, + TILE_WIRE_SP4_V_B_20, + TILE_WIRE_SP4_V_B_21, + TILE_WIRE_SP4_V_B_22, + TILE_WIRE_SP4_V_B_23, + TILE_WIRE_SP4_V_B_24, + TILE_WIRE_SP4_V_B_25, + TILE_WIRE_SP4_V_B_26, + TILE_WIRE_SP4_V_B_27, + TILE_WIRE_SP4_V_B_28, + TILE_WIRE_SP4_V_B_29, + TILE_WIRE_SP4_V_B_30, + TILE_WIRE_SP4_V_B_31, + TILE_WIRE_SP4_V_B_32, + TILE_WIRE_SP4_V_B_33, + TILE_WIRE_SP4_V_B_34, + TILE_WIRE_SP4_V_B_35, + TILE_WIRE_SP4_V_B_36, + TILE_WIRE_SP4_V_B_37, + TILE_WIRE_SP4_V_B_38, + TILE_WIRE_SP4_V_B_39, + TILE_WIRE_SP4_V_B_40, + TILE_WIRE_SP4_V_B_41, + TILE_WIRE_SP4_V_B_42, + TILE_WIRE_SP4_V_B_43, + TILE_WIRE_SP4_V_B_44, + TILE_WIRE_SP4_V_B_45, + TILE_WIRE_SP4_V_B_46, + TILE_WIRE_SP4_V_B_47, + + TILE_WIRE_SP4_V_T_36, + TILE_WIRE_SP4_V_T_37, + TILE_WIRE_SP4_V_T_38, + TILE_WIRE_SP4_V_T_39, + TILE_WIRE_SP4_V_T_40, + TILE_WIRE_SP4_V_T_41, + TILE_WIRE_SP4_V_T_42, + TILE_WIRE_SP4_V_T_43, + TILE_WIRE_SP4_V_T_44, + TILE_WIRE_SP4_V_T_45, + TILE_WIRE_SP4_V_T_46, + TILE_WIRE_SP4_V_T_47, + + TILE_WIRE_sp4_R_V_B_0, + TILE_WIRE_sp4_R_V_B_1, + TILE_WIRE_sp4_R_V_B_2, + TILE_WIRE_sp4_R_V_B_3, + TILE_WIRE_sp4_R_V_B_4, + TILE_WIRE_sp4_R_V_B_5, + TILE_WIRE_sp4_R_V_B_6, + TILE_WIRE_sp4_R_V_B_7, + TILE_WIRE_sp4_R_V_B_8, + TILE_WIRE_sp4_R_V_B_9, + TILE_WIRE_sp4_R_V_B_10, + TILE_WIRE_sp4_R_V_B_11, + TILE_WIRE_sp4_R_V_B_12, + TILE_WIRE_sp4_R_V_B_13, + TILE_WIRE_sp4_R_V_B_14, + TILE_WIRE_sp4_R_V_B_15, + TILE_WIRE_sp4_R_V_B_16, + TILE_WIRE_sp4_R_V_B_17, + TILE_WIRE_sp4_R_V_B_18, + TILE_WIRE_sp4_R_V_B_19, + TILE_WIRE_sp4_R_V_B_20, + TILE_WIRE_sp4_R_V_B_21, + TILE_WIRE_sp4_R_V_B_22, + TILE_WIRE_sp4_R_V_B_23, + TILE_WIRE_sp4_R_V_B_24, + TILE_WIRE_sp4_R_V_B_25, + TILE_WIRE_sp4_R_V_B_26, + TILE_WIRE_sp4_R_V_B_27, + TILE_WIRE_sp4_R_V_B_28, + TILE_WIRE_sp4_R_V_B_29, + TILE_WIRE_sp4_R_V_B_30, + TILE_WIRE_sp4_R_V_B_31, + TILE_WIRE_sp4_R_V_B_32, + TILE_WIRE_sp4_R_V_B_33, + TILE_WIRE_sp4_R_V_B_34, + TILE_WIRE_sp4_R_V_B_35, + TILE_WIRE_sp4_R_V_B_36, + TILE_WIRE_sp4_R_V_B_37, + TILE_WIRE_sp4_R_V_B_38, + TILE_WIRE_sp4_R_V_B_39, + TILE_WIRE_sp4_R_V_B_40, + TILE_WIRE_sp4_R_V_B_41, + TILE_WIRE_sp4_R_V_B_42, + TILE_WIRE_sp4_R_V_B_43, + TILE_WIRE_sp4_R_V_B_44, + TILE_WIRE_sp4_R_V_B_45, + TILE_WIRE_sp4_R_V_B_46, + TILE_WIRE_sp4_R_V_B_47, + + TILE_WIRE_SP4_H_L_36, + TILE_WIRE_SP4_H_L_37, + TILE_WIRE_SP4_H_L_38, + TILE_WIRE_SP4_H_L_39, + TILE_WIRE_SP4_H_L_40, + TILE_WIRE_SP4_H_L_41, + TILE_WIRE_SP4_H_L_42, + TILE_WIRE_SP4_H_L_43, + TILE_WIRE_SP4_H_L_44, + TILE_WIRE_SP4_H_L_45, + TILE_WIRE_SP4_H_L_46, + TILE_WIRE_SP4_H_L_47, + + TILE_WIRE_SP4_H_R_0, + TILE_WIRE_SP4_H_R_1, + TILE_WIRE_SP4_H_R_2, + TILE_WIRE_SP4_H_R_3, + TILE_WIRE_SP4_H_R_4, + TILE_WIRE_SP4_H_R_5, + TILE_WIRE_SP4_H_R_6, + TILE_WIRE_SP4_H_R_7, + TILE_WIRE_SP4_H_R_8, + TILE_WIRE_SP4_H_R_9, + TILE_WIRE_SP4_H_R_10, + TILE_WIRE_SP4_H_R_11, + TILE_WIRE_SP4_H_R_12, + TILE_WIRE_SP4_H_R_13, + TILE_WIRE_SP4_H_R_14, + TILE_WIRE_SP4_H_R_15, + TILE_WIRE_SP4_H_R_16, + TILE_WIRE_SP4_H_R_17, + TILE_WIRE_SP4_H_R_18, + TILE_WIRE_SP4_H_R_19, + TILE_WIRE_SP4_H_R_20, + TILE_WIRE_SP4_H_R_21, + TILE_WIRE_SP4_H_R_22, + TILE_WIRE_SP4_H_R_23, + TILE_WIRE_SP4_H_R_24, + TILE_WIRE_SP4_H_R_25, + TILE_WIRE_SP4_H_R_26, + TILE_WIRE_SP4_H_R_27, + TILE_WIRE_SP4_H_R_28, + TILE_WIRE_SP4_H_R_29, + TILE_WIRE_SP4_H_R_30, + TILE_WIRE_SP4_H_R_31, + TILE_WIRE_SP4_H_R_32, + TILE_WIRE_SP4_H_R_33, + TILE_WIRE_SP4_H_R_34, + TILE_WIRE_SP4_H_R_35, + TILE_WIRE_SP4_H_R_36, + TILE_WIRE_SP4_H_R_37, + TILE_WIRE_SP4_H_R_38, + TILE_WIRE_SP4_H_R_39, + TILE_WIRE_SP4_H_R_40, + TILE_WIRE_SP4_H_R_41, + TILE_WIRE_SP4_H_R_42, + TILE_WIRE_SP4_H_R_43, + TILE_WIRE_SP4_H_R_44, + TILE_WIRE_SP4_H_R_45, + TILE_WIRE_SP4_H_R_46, + TILE_WIRE_SP4_H_R_47, + + TILE_WIRE_SP12_V_B_0, + TILE_WIRE_SP12_V_B_1, + TILE_WIRE_SP12_V_B_2, + TILE_WIRE_SP12_V_B_3, + TILE_WIRE_SP12_V_B_4, + TILE_WIRE_SP12_V_B_5, + TILE_WIRE_SP12_V_B_6, + TILE_WIRE_SP12_V_B_7, + TILE_WIRE_SP12_V_B_8, + TILE_WIRE_SP12_V_B_9, + TILE_WIRE_SP12_V_B_10, + TILE_WIRE_SP12_V_B_11, + TILE_WIRE_SP12_V_B_12, + TILE_WIRE_SP12_V_B_13, + TILE_WIRE_SP12_V_B_14, + TILE_WIRE_SP12_V_B_15, + TILE_WIRE_SP12_V_B_16, + TILE_WIRE_SP12_V_B_17, + TILE_WIRE_SP12_V_B_18, + TILE_WIRE_SP12_V_B_19, + TILE_WIRE_SP12_V_B_20, + TILE_WIRE_SP12_V_B_21, + TILE_WIRE_SP12_V_B_22, + TILE_WIRE_SP12_V_B_23, + + TILE_WIRE_SP12_V_T_22, + TILE_WIRE_SP12_V_T_23, + + TILE_WIRE_SP12_H_R_0, + TILE_WIRE_SP12_H_R_1, + TILE_WIRE_SP12_H_R_2, + TILE_WIRE_SP12_H_R_3, + TILE_WIRE_SP12_H_R_4, + TILE_WIRE_SP12_H_R_5, + TILE_WIRE_SP12_H_R_6, + TILE_WIRE_SP12_H_R_7, + TILE_WIRE_SP12_H_R_8, + TILE_WIRE_SP12_H_R_9, + + TILE_WIRE_SP12_H_R_10, + TILE_WIRE_SP12_H_R_11, + TILE_WIRE_SP12_H_R_12, + TILE_WIRE_SP12_H_R_13, + TILE_WIRE_SP12_H_R_14, + TILE_WIRE_SP12_H_R_15, + TILE_WIRE_SP12_H_R_16, + TILE_WIRE_SP12_H_R_17, + TILE_WIRE_SP12_H_R_18, + TILE_WIRE_SP12_H_R_19, + + TILE_WIRE_SP12_H_R_20, + TILE_WIRE_SP12_H_R_21, + TILE_WIRE_SP12_H_R_22, + TILE_WIRE_SP12_H_R_23, + + TILE_WIRE_SP12_H_L_22, + TILE_WIRE_SP12_H_L_23 +}; + +void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id); + +NEXTPNR_NAMESPACE_END + +#endif // GFX_H -- cgit v1.2.3 From 1f36242d43eca636a82aa198e15cf821b59681e1 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 9 Jul 2018 15:09:17 +0200 Subject: Add lutff_global switchbox Signed-off-by: David Shah --- ice40/arch.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ice40/arch.cc b/ice40/arch.cc index ecd0a411..7016bc07 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -457,6 +457,14 @@ std::vector Arch::getBelGraphics(BelId bel) const // All the wires for (int i = TILE_WIRE_GLB2LOCAL_0; i <= TILE_WIRE_SP12_H_L_23; i++) gfxTileWire(ret, tx, ty, GfxTileWireId(i)); + // lutff_global switchbox + GraphicElement lff_glb_sw; + lff_glb_sw.type = GraphicElement::G_BOX; + lff_glb_sw.x1 = tx + 0.65; + lff_glb_sw.x2 = tx + 0.7; + lff_glb_sw.y1 = ty + 0.875; + lff_glb_sw.y2 = ty + 0.925; + ret.push_back(lff_glb_sw); } } -- cgit v1.2.3 From a4129036518678ee35d5d8adde3dfe0b699491ea Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 9 Jul 2018 15:33:09 +0200 Subject: Increase max zoom, decrease line width Signed-off-by: David Shah --- gui/fpgaviewwidget.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 831f80d4..ae0b9240 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -297,8 +297,8 @@ void FPGAViewWidget::setZoom(float t_z) if (zoom_ < 1.0f) zoom_ = 1.0f; - if (zoom_ > 100.f) - zoom_ = 100.0f; + if (zoom_ > 500.f) + zoom_ = 500.0f; update(); } @@ -354,7 +354,7 @@ void FPGAViewWidget::paintGL() lineShader_.draw(grid, matrix); // Draw Bels. - auto bels = LineShaderData(0.002f, QColor("#b000ba")); + auto bels = LineShaderData(0.0005f, QColor("#b000ba")); if (ctx_) { for (auto bel : ctx_->getBels()) { for (auto &el : ctx_->getBelGraphics(bel)) -- cgit v1.2.3 From 6198a68968c6e8c66ad8209bf31b77b9511102d8 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 9 Jul 2018 15:45:01 +0200 Subject: Add horizontal ice40 span4 wire gfx Signed-off-by: Clifford Wolf --- ice40/gfx.cc | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/ice40/gfx.cc b/ice40/gfx.cc index 46824b06..5a30c79d 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -23,6 +23,55 @@ NEXTPNR_NAMESPACE_BEGIN void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) { + if (id >= TILE_WIRE_SP4_H_L_36 && id <= TILE_WIRE_SP4_H_L_47) { + int idx = (id - TILE_WIRE_SP4_H_L_36) + 48; + GraphicElement el; + el.type = GraphicElement::G_LINE; + + float y1 = y + 0.03 + 0.0025 * (60 - idx); + + el.x1 = x + 0.0; + el.x2 = x + 0.9; + el.y1 = y1; + el.y2 = y1; + g.push_back(el); + } + + if (id >= TILE_WIRE_SP4_H_R_0 && id <= TILE_WIRE_SP4_H_R_47) { + int idx = id - TILE_WIRE_SP4_H_R_0; + GraphicElement el; + el.type = GraphicElement::G_LINE; + + float y1 = y + 0.03 + 0.0025 * (60 - idx); + float y2 = y + 0.03 + 0.0025 * (60 - (idx ^ 1)); + float y3 = y + 0.03 + 0.0025 * (60 - (idx ^ 1) - 12); + + if (idx >= 12) { + el.x1 = x; + el.x2 = x + 0.01; + el.y1 = y1; + el.y2 = y1; + g.push_back(el); + + el.x1 = x + 0.01; + el.x2 = x + 0.02; + el.y1 = y1; + el.y2 = y2; + g.push_back(el); + } + + el.x1 = x + 0.02; + el.x2 = x + 0.9; + el.y1 = y2; + el.y2 = y2; + g.push_back(el); + + el.x1 = x + 0.9; + el.x2 = x + 1.0; + el.y1 = y2; + el.y2 = y3; + g.push_back(el); + } } NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From 953560ae17aa54a94c35e7475b908b628aadd647 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 9 Jul 2018 16:02:02 +0200 Subject: Add switchboxes Signed-off-by: David Shah --- ice40/arch.cc | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 7016bc07..d6947834 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -454,9 +454,6 @@ std::vector Arch::getBelGraphics(BelId bel) const lc_sw.y2 = ty + 0.75; ret.push_back(lc_sw); - // All the wires - for (int i = TILE_WIRE_GLB2LOCAL_0; i <= TILE_WIRE_SP12_H_L_23; i++) - gfxTileWire(ret, tx, ty, GfxTileWireId(i)); // lutff_global switchbox GraphicElement lff_glb_sw; lff_glb_sw.type = GraphicElement::G_BOX; @@ -465,6 +462,47 @@ std::vector Arch::getBelGraphics(BelId bel) const lff_glb_sw.y1 = ty + 0.875; lff_glb_sw.y2 = ty + 0.925; ret.push_back(lff_glb_sw); + + // glb2local switchbox + GraphicElement glb2local_sw; + glb2local_sw.type = GraphicElement::G_BOX; + glb2local_sw.x1 = tx + 0.45; + glb2local_sw.x2 = tx + 0.55; + glb2local_sw.y1 = ty + 0.80; + glb2local_sw.y2 = ty + 0.85; + ret.push_back(glb2local_sw); + + // span12 switchbox + GraphicElement sp12_sw; + sp12_sw.type = GraphicElement::G_BOX; + sp12_sw.x1 = tx + 0.500; + sp12_sw.x2 = tx + 0.575; + sp12_sw.y1 = ty + 0.525; + sp12_sw.y2 = ty + 0.625; + ret.push_back(sp12_sw); + + // span4v switchbox + GraphicElement sp4v_sw; + sp4v_sw.type = GraphicElement::G_BOX; + sp4v_sw.x1 = tx + 0.400; + sp4v_sw.x2 = tx + 0.475; + sp4v_sw.y1 = ty + 0.425; + sp4v_sw.y2 = ty + 0.525; + ret.push_back(sp4v_sw); + + // span4h switchbox + GraphicElement sp4h_sw; + sp4h_sw.type = GraphicElement::G_BOX; + sp4h_sw.x1 = tx + 0.300; + sp4h_sw.x2 = tx + 0.375; + sp4h_sw.y1 = ty + 0.3; + sp4h_sw.y2 = ty + 0.4; + ret.push_back(sp4h_sw); + + + // All the wires + for (int i = TILE_WIRE_GLB2LOCAL_0; i <= TILE_WIRE_SP12_H_L_23; i++) + gfxTileWire(ret, tx, ty, GfxTileWireId(i)); } } -- cgit v1.2.3 From 5b6fa934d87b838cef9037bf2b14465b7e5cf742 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 9 Jul 2018 16:07:16 +0200 Subject: Make LCs smaller and move them down Signed-off-by: David Shah --- ice40/arch.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index d6947834..a86d6e56 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -428,8 +428,8 @@ std::vector Arch::getBelGraphics(BelId bel) const el.type = GraphicElement::G_BOX; el.x1 = chip_info->bel_data[bel.index].x + 0.82; el.x2 = chip_info->bel_data[bel.index].x + 0.92; - el.y1 = chip_info->bel_data[bel.index].y + 0.30 + (chip_info->bel_data[bel.index].z) * (0.6 / 8); - el.y2 = chip_info->bel_data[bel.index].y + 0.35 + (chip_info->bel_data[bel.index].z) * (0.6 / 8); + el.y1 = chip_info->bel_data[bel.index].y + 0.45 + (chip_info->bel_data[bel.index].z) * (0.5 / 8); + el.y2 = chip_info->bel_data[bel.index].y + 0.5 + (chip_info->bel_data[bel.index].z) * (0.5 / 8); el.z = 0; ret.push_back(el); @@ -441,8 +441,8 @@ std::vector Arch::getBelGraphics(BelId bel) const lc_lut_sw.type = GraphicElement::G_BOX; lc_lut_sw.x1 = tx + 0.75; lc_lut_sw.x2 = tx + 0.8; - lc_lut_sw.y1 = ty + 0.30; - lc_lut_sw.y2 = ty + 0.875; + lc_lut_sw.y1 = ty + 0.45; + lc_lut_sw.y2 = ty + 0.9375; lc_lut_sw.z = 0; ret.push_back(lc_lut_sw); // Local tracks switchbox @@ -459,8 +459,8 @@ std::vector Arch::getBelGraphics(BelId bel) const lff_glb_sw.type = GraphicElement::G_BOX; lff_glb_sw.x1 = tx + 0.65; lff_glb_sw.x2 = tx + 0.7; - lff_glb_sw.y1 = ty + 0.875; - lff_glb_sw.y2 = ty + 0.925; + lff_glb_sw.y1 = ty + 0.910; + lff_glb_sw.y2 = ty + 0.960; ret.push_back(lff_glb_sw); // glb2local switchbox -- cgit v1.2.3 From 4576fc7c20c7a211556b9b160a9eb35b5f8bb5b7 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 9 Jul 2018 16:12:41 +0200 Subject: Vertical wires and span-12 wires Signed-off-by: Clifford Wolf --- ice40/gfx.cc | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ice40/gfx.h | 2 - 2 files changed, 158 insertions(+), 2 deletions(-) diff --git a/ice40/gfx.cc b/ice40/gfx.cc index 5a30c79d..613f1a31 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -23,6 +23,8 @@ NEXTPNR_NAMESPACE_BEGIN void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) { + // Horizontal Span-4 Wires + if (id >= TILE_WIRE_SP4_H_L_36 && id <= TILE_WIRE_SP4_H_L_47) { int idx = (id - TILE_WIRE_SP4_H_L_36) + 48; GraphicElement el; @@ -72,6 +74,162 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.y2 = y3; g.push_back(el); } + + // Vertical Span-4 Wires + + if (id >= TILE_WIRE_SP4_V_T_36 && id <= TILE_WIRE_SP4_V_T_47) { + int idx = (id - TILE_WIRE_SP4_V_T_36) + 48; + GraphicElement el; + el.type = GraphicElement::G_LINE; + + float x1 = x + 0.03 + 0.0025 * (60 - idx); + + el.y1 = y + 0.0; + el.y2 = y + 0.9; + el.x1 = x1; + el.x2 = x1; + g.push_back(el); + } + + if (id >= TILE_WIRE_SP4_V_B_0 && id <= TILE_WIRE_SP4_V_B_47) { + int idx = id - TILE_WIRE_SP4_V_B_0; + GraphicElement el; + el.type = GraphicElement::G_LINE; + + float x1 = x + 0.03 + 0.0025 * (60 - idx); + float x2 = x + 0.03 + 0.0025 * (60 - (idx ^ 1)); + float x3 = x + 0.03 + 0.0025 * (60 - (idx ^ 1) - 12); + + if (idx >= 12) { + el.y1 = y; + el.y2 = y + 0.01; + el.x1 = x1; + el.x2 = x1; + g.push_back(el); + + el.y1 = y + 0.01; + el.y2 = y + 0.02; + el.x1 = x1; + el.x2 = x2; + g.push_back(el); + } + + el.y1 = y + 0.02; + el.y2 = y + 0.9; + el.x1 = x2; + el.x2 = x2; + g.push_back(el); + + el.y1 = y + 0.9; + el.y2 = y + 1.0; + el.x1 = x2; + el.x2 = x3; + g.push_back(el); + } + + // Horizontal Span-12 Wires + + if (id >= TILE_WIRE_SP12_H_L_22 && id <= TILE_WIRE_SP12_H_L_23) { + int idx = (id - TILE_WIRE_SP12_H_L_22) + 24; + GraphicElement el; + el.type = GraphicElement::G_LINE; + + float y1 = y + 0.03 + 0.0025 * (90 - idx); + + el.x1 = x + 0.0; + el.x2 = x + 0.98333; + el.y1 = y1; + el.y2 = y1; + g.push_back(el); + } + + if (id >= TILE_WIRE_SP12_H_R_0 && id <= TILE_WIRE_SP12_H_R_23) { + int idx = id - TILE_WIRE_SP12_H_R_0; + GraphicElement el; + el.type = GraphicElement::G_LINE; + + float y1 = y + 0.03 + 0.0025 * (90 - idx); + float y2 = y + 0.03 + 0.0025 * (90 - (idx ^ 1)); + float y3 = y + 0.03 + 0.0025 * (90 - (idx ^ 1) - 2); + + if (idx >= 2) { + el.x1 = x; + el.x2 = x + 0.01; + el.y1 = y1; + el.y2 = y1; + g.push_back(el); + + el.x1 = x + 0.01; + el.x2 = x + 0.02; + el.y1 = y1; + el.y2 = y2; + g.push_back(el); + } + + el.x1 = x + 0.02; + el.x2 = x + 0.98333; + el.y1 = y2; + el.y2 = y2; + g.push_back(el); + + el.x1 = x + 0.98333; + el.x2 = x + 1.0; + el.y1 = y2; + el.y2 = y3; + g.push_back(el); + } + + // Vertical Span-12 Wires + + if (id >= TILE_WIRE_SP12_V_T_22 && id <= TILE_WIRE_SP12_V_T_23) { + int idx = (id - TILE_WIRE_SP12_V_T_22) + 24; + GraphicElement el; + el.type = GraphicElement::G_LINE; + + float x1 = x + 0.03 + 0.0025 * (90 - idx); + + el.y1 = y + 0.0; + el.y2 = y + 0.98333; + el.x1 = x1; + el.x2 = x1; + g.push_back(el); + } + + if (id >= TILE_WIRE_SP12_V_B_0 && id <= TILE_WIRE_SP12_V_B_23) { + int idx = id - TILE_WIRE_SP12_V_B_0; + GraphicElement el; + el.type = GraphicElement::G_LINE; + + float x1 = x + 0.03 + 0.0025 * (90 - idx); + float x2 = x + 0.03 + 0.0025 * (90 - (idx ^ 1)); + float x3 = x + 0.03 + 0.0025 * (90 - (idx ^ 1) - 2); + + if (idx >= 2) { + el.y1 = y; + el.y2 = y + 0.01; + el.x1 = x1; + el.x2 = x1; + g.push_back(el); + + el.y1 = y + 0.01; + el.y2 = y + 0.02; + el.x1 = x1; + el.x2 = x2; + g.push_back(el); + } + + el.y1 = y + 0.02; + el.y2 = y + 0.98333; + el.x1 = x2; + el.x2 = x2; + g.push_back(el); + + el.y1 = y + 0.98333; + el.y2 = y + 1.0; + el.x1 = x2; + el.x2 = x3; + g.push_back(el); + } } NEXTPNR_NAMESPACE_END diff --git a/ice40/gfx.h b/ice40/gfx.h index e9cc0e16..fa8d51eb 100644 --- a/ice40/gfx.h +++ b/ice40/gfx.h @@ -428,7 +428,6 @@ enum GfxTileWireId { TILE_WIRE_SP12_H_R_7, TILE_WIRE_SP12_H_R_8, TILE_WIRE_SP12_H_R_9, - TILE_WIRE_SP12_H_R_10, TILE_WIRE_SP12_H_R_11, TILE_WIRE_SP12_H_R_12, @@ -439,7 +438,6 @@ enum GfxTileWireId { TILE_WIRE_SP12_H_R_17, TILE_WIRE_SP12_H_R_18, TILE_WIRE_SP12_H_R_19, - TILE_WIRE_SP12_H_R_20, TILE_WIRE_SP12_H_R_21, TILE_WIRE_SP12_H_R_22, -- cgit v1.2.3 From ba6f3b45b84be2aca06d82ce5b32f68a70f05ebb Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 9 Jul 2018 16:39:18 +0200 Subject: Add ice40 gfx right vertical span-4 Signed-off-by: Clifford Wolf --- ice40/gfx.cc | 36 +++++++++++++++++++---- ice40/gfx.h | 96 ++++++++++++++++++++++++++++++------------------------------ 2 files changed, 78 insertions(+), 54 deletions(-) diff --git a/ice40/gfx.cc b/ice40/gfx.cc index 613f1a31..1006f7b9 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -96,9 +96,9 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) GraphicElement el; el.type = GraphicElement::G_LINE; - float x1 = x + 0.03 + 0.0025 * (60 - idx); - float x2 = x + 0.03 + 0.0025 * (60 - (idx ^ 1)); - float x3 = x + 0.03 + 0.0025 * (60 - (idx ^ 1) - 12); + float x1 = x + 0.03 + 0.0025 * (60 - (idx ^ 1)); + float x2 = x + 0.03 + 0.0025 * (60 - idx); + float x3 = x + 0.03 + 0.0025 * (60 - idx - 12); if (idx >= 12) { el.y1 = y; @@ -125,6 +125,14 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x1 = x2; el.x2 = x3; g.push_back(el); + + float y1 = y + 0.03 + 0.0025 * (142 - idx); + + el.y1 = y1; + el.y2 = y1; + el.x1 = x; + el.x2 = x2; + g.push_back(el); } // Horizontal Span-12 Wires @@ -148,9 +156,9 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) GraphicElement el; el.type = GraphicElement::G_LINE; - float y1 = y + 0.03 + 0.0025 * (90 - idx); - float y2 = y + 0.03 + 0.0025 * (90 - (idx ^ 1)); - float y3 = y + 0.03 + 0.0025 * (90 - (idx ^ 1) - 2); + float y1 = y + 0.03 + 0.0025 * (90 - (idx ^ 1)); + float y2 = y + 0.03 + 0.0025 * (90 - idx); + float y3 = y + 0.03 + 0.0025 * (90 - idx - 2); if (idx >= 2) { el.x1 = x; @@ -179,6 +187,22 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) g.push_back(el); } + // Veritcal Right Span-4 + + if (id >= TILE_WIRE_SP4_R_V_B_0 && id <= TILE_WIRE_SP4_R_V_B_47) { + int idx = id - TILE_WIRE_SP4_R_V_B_0; + GraphicElement el; + el.type = GraphicElement::G_LINE; + + float y1 = y + 0.03 + 0.0025 * (142 - idx); + + el.y1 = y1; + el.y2 = y1; + el.x1 = x + 0.6; + el.x2 = x + 1.0; + g.push_back(el); + } + // Vertical Span-12 Wires if (id >= TILE_WIRE_SP12_V_T_22 && id <= TILE_WIRE_SP12_V_T_23) { diff --git a/ice40/gfx.h b/ice40/gfx.h index fa8d51eb..07643bca 100644 --- a/ice40/gfx.h +++ b/ice40/gfx.h @@ -279,54 +279,54 @@ enum GfxTileWireId { TILE_WIRE_SP4_V_T_46, TILE_WIRE_SP4_V_T_47, - TILE_WIRE_sp4_R_V_B_0, - TILE_WIRE_sp4_R_V_B_1, - TILE_WIRE_sp4_R_V_B_2, - TILE_WIRE_sp4_R_V_B_3, - TILE_WIRE_sp4_R_V_B_4, - TILE_WIRE_sp4_R_V_B_5, - TILE_WIRE_sp4_R_V_B_6, - TILE_WIRE_sp4_R_V_B_7, - TILE_WIRE_sp4_R_V_B_8, - TILE_WIRE_sp4_R_V_B_9, - TILE_WIRE_sp4_R_V_B_10, - TILE_WIRE_sp4_R_V_B_11, - TILE_WIRE_sp4_R_V_B_12, - TILE_WIRE_sp4_R_V_B_13, - TILE_WIRE_sp4_R_V_B_14, - TILE_WIRE_sp4_R_V_B_15, - TILE_WIRE_sp4_R_V_B_16, - TILE_WIRE_sp4_R_V_B_17, - TILE_WIRE_sp4_R_V_B_18, - TILE_WIRE_sp4_R_V_B_19, - TILE_WIRE_sp4_R_V_B_20, - TILE_WIRE_sp4_R_V_B_21, - TILE_WIRE_sp4_R_V_B_22, - TILE_WIRE_sp4_R_V_B_23, - TILE_WIRE_sp4_R_V_B_24, - TILE_WIRE_sp4_R_V_B_25, - TILE_WIRE_sp4_R_V_B_26, - TILE_WIRE_sp4_R_V_B_27, - TILE_WIRE_sp4_R_V_B_28, - TILE_WIRE_sp4_R_V_B_29, - TILE_WIRE_sp4_R_V_B_30, - TILE_WIRE_sp4_R_V_B_31, - TILE_WIRE_sp4_R_V_B_32, - TILE_WIRE_sp4_R_V_B_33, - TILE_WIRE_sp4_R_V_B_34, - TILE_WIRE_sp4_R_V_B_35, - TILE_WIRE_sp4_R_V_B_36, - TILE_WIRE_sp4_R_V_B_37, - TILE_WIRE_sp4_R_V_B_38, - TILE_WIRE_sp4_R_V_B_39, - TILE_WIRE_sp4_R_V_B_40, - TILE_WIRE_sp4_R_V_B_41, - TILE_WIRE_sp4_R_V_B_42, - TILE_WIRE_sp4_R_V_B_43, - TILE_WIRE_sp4_R_V_B_44, - TILE_WIRE_sp4_R_V_B_45, - TILE_WIRE_sp4_R_V_B_46, - TILE_WIRE_sp4_R_V_B_47, + TILE_WIRE_SP4_R_V_B_0, + TILE_WIRE_SP4_R_V_B_1, + TILE_WIRE_SP4_R_V_B_2, + TILE_WIRE_SP4_R_V_B_3, + TILE_WIRE_SP4_R_V_B_4, + TILE_WIRE_SP4_R_V_B_5, + TILE_WIRE_SP4_R_V_B_6, + TILE_WIRE_SP4_R_V_B_7, + TILE_WIRE_SP4_R_V_B_8, + TILE_WIRE_SP4_R_V_B_9, + TILE_WIRE_SP4_R_V_B_10, + TILE_WIRE_SP4_R_V_B_11, + TILE_WIRE_SP4_R_V_B_12, + TILE_WIRE_SP4_R_V_B_13, + TILE_WIRE_SP4_R_V_B_14, + TILE_WIRE_SP4_R_V_B_15, + TILE_WIRE_SP4_R_V_B_16, + TILE_WIRE_SP4_R_V_B_17, + TILE_WIRE_SP4_R_V_B_18, + TILE_WIRE_SP4_R_V_B_19, + TILE_WIRE_SP4_R_V_B_20, + TILE_WIRE_SP4_R_V_B_21, + TILE_WIRE_SP4_R_V_B_22, + TILE_WIRE_SP4_R_V_B_23, + TILE_WIRE_SP4_R_V_B_24, + TILE_WIRE_SP4_R_V_B_25, + TILE_WIRE_SP4_R_V_B_26, + TILE_WIRE_SP4_R_V_B_27, + TILE_WIRE_SP4_R_V_B_28, + TILE_WIRE_SP4_R_V_B_29, + TILE_WIRE_SP4_R_V_B_30, + TILE_WIRE_SP4_R_V_B_31, + TILE_WIRE_SP4_R_V_B_32, + TILE_WIRE_SP4_R_V_B_33, + TILE_WIRE_SP4_R_V_B_34, + TILE_WIRE_SP4_R_V_B_35, + TILE_WIRE_SP4_R_V_B_36, + TILE_WIRE_SP4_R_V_B_37, + TILE_WIRE_SP4_R_V_B_38, + TILE_WIRE_SP4_R_V_B_39, + TILE_WIRE_SP4_R_V_B_40, + TILE_WIRE_SP4_R_V_B_41, + TILE_WIRE_SP4_R_V_B_42, + TILE_WIRE_SP4_R_V_B_43, + TILE_WIRE_SP4_R_V_B_44, + TILE_WIRE_SP4_R_V_B_45, + TILE_WIRE_SP4_R_V_B_46, + TILE_WIRE_SP4_R_V_B_47, TILE_WIRE_SP4_H_L_36, TILE_WIRE_SP4_H_L_37, -- cgit v1.2.3 From c6043ed570dd90095fdbee3435b83e626b74e327 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 9 Jul 2018 16:42:30 +0200 Subject: Reorder gfx.h, add LUT0 inputs Signed-off-by: David Shah --- ice40/gfx.cc | 10 ++++++++++ ice40/gfx.h | 47 +++++++++++++++++++++++++---------------------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/ice40/gfx.cc b/ice40/gfx.cc index 1006f7b9..6954a9fb 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -254,6 +254,16 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x2 = x3; g.push_back(el); } + + if (id >= TILE_WIRE_LUTFF_0_IN_0 && id <= TILE_WIRE_LUTFF_0_IN_3) { + GraphicElement el; + el.type = GraphicElement::G_LINE; + el.x1 = x + 0.8; + el.x2 = x + 0.82; + el.y1 = y + 0.4675 + (0.005 * (id - TILE_WIRE_LUTFF_0_IN_0)); + el.y2 = el.y1; + g.push_back(el); + } } NEXTPNR_NAMESPACE_END diff --git a/ice40/gfx.h b/ice40/gfx.h index 07643bca..4cd7d081 100644 --- a/ice40/gfx.h +++ b/ice40/gfx.h @@ -78,69 +78,72 @@ enum GfxTileWireId { TILE_WIRE_CARRY_IN, TILE_WIRE_CARRY_IN_MUX, - TILE_WIRE_LUTFF_0_COUT, TILE_WIRE_LUTFF_0_IN_0, TILE_WIRE_LUTFF_0_IN_1, TILE_WIRE_LUTFF_0_IN_2, TILE_WIRE_LUTFF_0_IN_3, - TILE_WIRE_LUTFF_0_LOUT, - TILE_WIRE_LUTFF_0_OUT, - TILE_WIRE_LUTFF_1_COUT, TILE_WIRE_LUTFF_1_IN_0, TILE_WIRE_LUTFF_1_IN_1, TILE_WIRE_LUTFF_1_IN_2, TILE_WIRE_LUTFF_1_IN_3, - TILE_WIRE_LUTFF_1_LOUT, - TILE_WIRE_LUTFF_1_OUT, - TILE_WIRE_LUTFF_2_COUT, TILE_WIRE_LUTFF_2_IN_0, TILE_WIRE_LUTFF_2_IN_1, TILE_WIRE_LUTFF_2_IN_2, TILE_WIRE_LUTFF_2_IN_3, - TILE_WIRE_LUTFF_2_LOUT, - TILE_WIRE_LUTFF_2_OUT, - TILE_WIRE_LUTFF_3_COUT, TILE_WIRE_LUTFF_3_IN_0, TILE_WIRE_LUTFF_3_IN_1, TILE_WIRE_LUTFF_3_IN_2, TILE_WIRE_LUTFF_3_IN_3, - TILE_WIRE_LUTFF_3_LOUT, - TILE_WIRE_LUTFF_3_OUT, - TILE_WIRE_LUTFF_4_COUT, TILE_WIRE_LUTFF_4_IN_0, TILE_WIRE_LUTFF_4_IN_1, TILE_WIRE_LUTFF_4_IN_2, TILE_WIRE_LUTFF_4_IN_3, - TILE_WIRE_LUTFF_4_LOUT, - TILE_WIRE_LUTFF_4_OUT, - TILE_WIRE_LUTFF_5_COUT, TILE_WIRE_LUTFF_5_IN_0, TILE_WIRE_LUTFF_5_IN_1, TILE_WIRE_LUTFF_5_IN_2, TILE_WIRE_LUTFF_5_IN_3, - TILE_WIRE_LUTFF_5_LOUT, - TILE_WIRE_LUTFF_5_OUT, - TILE_WIRE_LUTFF_6_COUT, TILE_WIRE_LUTFF_6_IN_0, TILE_WIRE_LUTFF_6_IN_1, TILE_WIRE_LUTFF_6_IN_2, TILE_WIRE_LUTFF_6_IN_3, - TILE_WIRE_LUTFF_6_LOUT, - TILE_WIRE_LUTFF_6_OUT, - TILE_WIRE_LUTFF_7_COUT, TILE_WIRE_LUTFF_7_IN_0, TILE_WIRE_LUTFF_7_IN_1, TILE_WIRE_LUTFF_7_IN_2, TILE_WIRE_LUTFF_7_IN_3, + + TILE_WIRE_LUTFF_0_LOUT, + TILE_WIRE_LUTFF_1_LOUT, + TILE_WIRE_LUTFF_2_LOUT, + TILE_WIRE_LUTFF_3_LOUT, + TILE_WIRE_LUTFF_4_LOUT, + TILE_WIRE_LUTFF_5_LOUT, + TILE_WIRE_LUTFF_6_LOUT, + + TILE_WIRE_LUTFF_0_OUT, + TILE_WIRE_LUTFF_1_OUT, + TILE_WIRE_LUTFF_2_OUT, + TILE_WIRE_LUTFF_3_OUT, + TILE_WIRE_LUTFF_4_OUT, + TILE_WIRE_LUTFF_5_OUT, + TILE_WIRE_LUTFF_6_OUT, TILE_WIRE_LUTFF_7_OUT, + TILE_WIRE_LUTFF_0_COUT, + TILE_WIRE_LUTFF_1_COUT, + TILE_WIRE_LUTFF_2_COUT, + TILE_WIRE_LUTFF_3_COUT, + TILE_WIRE_LUTFF_4_COUT, + TILE_WIRE_LUTFF_5_COUT, + TILE_WIRE_LUTFF_6_COUT, + TILE_WIRE_LUTFF_7_COUT, + TILE_WIRE_LUTFF_GLOBAL_CEN, TILE_WIRE_LUTFF_GLOBAL_CLK, TILE_WIRE_LUTFF_GLOBAL_S_R, -- cgit v1.2.3 From c921e4f24b24f4c14ecf3d4f8cb999cd8ead2a41 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 9 Jul 2018 16:50:01 +0200 Subject: Add constants for switchbox locations Signed-off-by: David Shah --- ice40/arch.cc | 56 ++++++++++++++++++++++++++++---------------------------- ice40/gfx.h | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 28 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index a86d6e56..a50310cf 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -439,64 +439,64 @@ std::vector Arch::getBelGraphics(BelId bel) const // Local tracks to LUT input switchbox GraphicElement lc_lut_sw; lc_lut_sw.type = GraphicElement::G_BOX; - lc_lut_sw.x1 = tx + 0.75; - lc_lut_sw.x2 = tx + 0.8; - lc_lut_sw.y1 = ty + 0.45; - lc_lut_sw.y2 = ty + 0.9375; + lc_lut_sw.x1 = tx + lc_lut_swbox_x1; + lc_lut_sw.x2 = tx + lc_lut_swbox_x2; + lc_lut_sw.y1 = ty + lc_lut_swbox_y1; + lc_lut_sw.y2 = ty + lc_lut_swbox_y2; lc_lut_sw.z = 0; ret.push_back(lc_lut_sw); // Local tracks switchbox GraphicElement lc_sw; lc_sw.type = GraphicElement::G_BOX; - lc_sw.x1 = tx + 0.6; - lc_sw.x2 = tx + 0.7; - lc_sw.y1 = ty + 0.65; - lc_sw.y2 = ty + 0.75; + lc_sw.x1 = tx + locals_swbox_x1; + lc_sw.x2 = tx + locals_swbox_x2; + lc_sw.y1 = ty + locals_swbox_y1; + lc_sw.y2 = ty + locals_swbox_y2; ret.push_back(lc_sw); // lutff_global switchbox GraphicElement lff_glb_sw; lff_glb_sw.type = GraphicElement::G_BOX; - lff_glb_sw.x1 = tx + 0.65; - lff_glb_sw.x2 = tx + 0.7; - lff_glb_sw.y1 = ty + 0.910; - lff_glb_sw.y2 = ty + 0.960; + lff_glb_sw.x1 = tx + lutff_global_swbox_x1; + lff_glb_sw.x2 = tx + lutff_global_swbox_x2; + lff_glb_sw.y1 = ty + lutff_global_swbox_y1; + lff_glb_sw.y2 = ty + lutff_global_swbox_y2; ret.push_back(lff_glb_sw); // glb2local switchbox GraphicElement glb2local_sw; glb2local_sw.type = GraphicElement::G_BOX; - glb2local_sw.x1 = tx + 0.45; - glb2local_sw.x2 = tx + 0.55; - glb2local_sw.y1 = ty + 0.80; - glb2local_sw.y2 = ty + 0.85; + glb2local_sw.x1 = tx + glb2local_swbox_x1; + glb2local_sw.x2 = tx + glb2local_swbox_x2; + glb2local_sw.y1 = ty + glb2local_swbox_y1; + glb2local_sw.y2 = ty + glb2local_swbox_y2; ret.push_back(glb2local_sw); // span12 switchbox GraphicElement sp12_sw; sp12_sw.type = GraphicElement::G_BOX; - sp12_sw.x1 = tx + 0.500; - sp12_sw.x2 = tx + 0.575; - sp12_sw.y1 = ty + 0.525; - sp12_sw.y2 = ty + 0.625; + sp12_sw.x1 = tx + span12_swbox_x1; + sp12_sw.x2 = tx + span12_swbox_x2; + sp12_sw.y1 = ty + span12_swbox_y1; + sp12_sw.y2 = ty + span12_swbox_y2; ret.push_back(sp12_sw); // span4v switchbox GraphicElement sp4v_sw; sp4v_sw.type = GraphicElement::G_BOX; - sp4v_sw.x1 = tx + 0.400; - sp4v_sw.x2 = tx + 0.475; - sp4v_sw.y1 = ty + 0.425; - sp4v_sw.y2 = ty + 0.525; + sp4v_sw.x1 = tx + span4h_swbox_x1; + sp4v_sw.x2 = tx + span4h_swbox_x2; + sp4v_sw.y1 = ty + span4h_swbox_y1; + sp4v_sw.y2 = ty + span4h_swbox_y2; ret.push_back(sp4v_sw); // span4h switchbox GraphicElement sp4h_sw; sp4h_sw.type = GraphicElement::G_BOX; - sp4h_sw.x1 = tx + 0.300; - sp4h_sw.x2 = tx + 0.375; - sp4h_sw.y1 = ty + 0.3; - sp4h_sw.y2 = ty + 0.4; + sp4h_sw.x1 = tx + span4v_swbox_x1; + sp4h_sw.x2 = tx + span4v_swbox_x2; + sp4h_sw.y1 = ty + span4v_swbox_y1; + sp4h_sw.y2 = ty + span4v_swbox_y2; ret.push_back(sp4h_sw); diff --git a/ice40/gfx.h b/ice40/gfx.h index 4cd7d081..15bb7300 100644 --- a/ice40/gfx.h +++ b/ice40/gfx.h @@ -24,6 +24,41 @@ NEXTPNR_NAMESPACE_BEGIN +const float lc_lut_swbox_x1 = 0.75; +const float lc_lut_swbox_x2 = 0.8; +const float lc_lut_swbox_y1 = 0.45; +const float lc_lut_swbox_y2 = 0.9375; + +const float locals_swbox_x1 = 0.6; +const float locals_swbox_x2 = 0.7; +const float locals_swbox_y1 = 0.65; +const float locals_swbox_y2 = 0.75; + +const float lutff_global_swbox_x1 = 0.65; +const float lutff_global_swbox_x2 = 0.7; +const float lutff_global_swbox_y1 = 0.91; +const float lutff_global_swbox_y2 = 0.96; + +const float glb2local_swbox_x1 = 0.45; +const float glb2local_swbox_x2 = 0.55; +const float glb2local_swbox_y1 = 0.80; +const float glb2local_swbox_y2 = 0.85; + +const float span12_swbox_x1 = 0.500; +const float span12_swbox_x2 = 0.575; +const float span12_swbox_y1 = 0.525; +const float span12_swbox_y2 = 0.625; + +const float span4h_swbox_x1 = 0.400; +const float span4h_swbox_x2 = 0.475; +const float span4h_swbox_y1 = 0.425; +const float span4h_swbox_y2 = 0.525; + +const float span4v_swbox_x1 = 0.300; +const float span4v_swbox_x2 = 0.375; +const float span4v_swbox_y1 = 0.300; +const float span4v_swbox_y2 = 0.400; + enum GfxTileWireId { TILE_WIRE_GLB2LOCAL_0, TILE_WIRE_GLB2LOCAL_1, -- cgit v1.2.3 From b5cf1c8257de6e6c5a6d757231879d7aba0798cb Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 9 Jul 2018 16:52:03 +0200 Subject: Adding all LUT input wires Signed-off-by: David Shah --- ice40/gfx.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ice40/gfx.cc b/ice40/gfx.cc index 6954a9fb..f29b38dc 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -255,12 +255,15 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) g.push_back(el); } - if (id >= TILE_WIRE_LUTFF_0_IN_0 && id <= TILE_WIRE_LUTFF_0_IN_3) { + if (id >= TILE_WIRE_LUTFF_0_IN_0 && id <= TILE_WIRE_LUTFF_7_IN_3) { + int idx = id - TILE_WIRE_LUTFF_0_IN_0; + int z = idx / 4; + int input = idx % 4; GraphicElement el; el.type = GraphicElement::G_LINE; - el.x1 = x + 0.8; + el.x1 = x + lc_lut_swbox_x2; el.x2 = x + 0.82; - el.y1 = y + 0.4675 + (0.005 * (id - TILE_WIRE_LUTFF_0_IN_0)); + el.y1 = y + 0.4675 + (0.005 * input) + z * (0.5 / 8); el.y2 = el.y1; g.push_back(el); } -- cgit v1.2.3 From 132c5b5019fa485d7e99311bb27cfdb47fc05226 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 9 Jul 2018 17:00:54 +0200 Subject: Make logic cell positioning a constant Signed-off-by: David Shah --- ice40/arch.cc | 8 ++++---- ice40/gfx.cc | 4 ++-- ice40/gfx.h | 6 ++++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index a50310cf..2eb7d1c3 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -426,10 +426,10 @@ std::vector Arch::getBelGraphics(BelId bel) const if (bel_type == TYPE_ICESTORM_LC) { GraphicElement el; el.type = GraphicElement::G_BOX; - el.x1 = chip_info->bel_data[bel.index].x + 0.82; - el.x2 = chip_info->bel_data[bel.index].x + 0.92; - el.y1 = chip_info->bel_data[bel.index].y + 0.45 + (chip_info->bel_data[bel.index].z) * (0.5 / 8); - el.y2 = chip_info->bel_data[bel.index].y + 0.5 + (chip_info->bel_data[bel.index].z) * (0.5 / 8); + el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; + el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; + el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; + el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; el.z = 0; ret.push_back(el); diff --git a/ice40/gfx.cc b/ice40/gfx.cc index f29b38dc..d59c00aa 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -262,8 +262,8 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) GraphicElement el; el.type = GraphicElement::G_LINE; el.x1 = x + lc_lut_swbox_x2; - el.x2 = x + 0.82; - el.y1 = y + 0.4675 + (0.005 * input) + z * (0.5 / 8); + el.x2 = x + logic_cell_x1; + el.y1 = y + 0.4675 + (0.005 * input) + z * logic_cell_pitch; el.y2 = el.y1; g.push_back(el); } diff --git a/ice40/gfx.h b/ice40/gfx.h index 15bb7300..784ba23f 100644 --- a/ice40/gfx.h +++ b/ice40/gfx.h @@ -59,6 +59,12 @@ const float span4v_swbox_x2 = 0.375; const float span4v_swbox_y1 = 0.300; const float span4v_swbox_y2 = 0.400; +const float logic_cell_x1 = 0.82; +const float logic_cell_x2 = 0.92; +const float logic_cell_y1 = 0.45; +const float logic_cell_y2 = 0.50; +const float logic_cell_pitch = 0.0625; + enum GfxTileWireId { TILE_WIRE_GLB2LOCAL_0, TILE_WIRE_GLB2LOCAL_1, -- cgit v1.2.3 From 46d28551fca591ce6b1cd2e1de5385661077b7e3 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 9 Jul 2018 17:13:26 +0200 Subject: Add ice40 LC output gfx Signed-off-by: Clifford Wolf --- ice40/gfx.cc | 31 +++++++++++++++++++++++++++++-- ice40/gfx.h | 2 +- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/ice40/gfx.cc b/ice40/gfx.cc index d59c00aa..58e52d65 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -126,7 +126,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x2 = x3; g.push_back(el); - float y1 = y + 0.03 + 0.0025 * (142 - idx); + float y1 = y + 0.03 + 0.0025 * (154 - idx); el.y1 = y1; el.y2 = y1; @@ -194,7 +194,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) GraphicElement el; el.type = GraphicElement::G_LINE; - float y1 = y + 0.03 + 0.0025 * (142 - idx); + float y1 = y + 0.03 + 0.0025 * (154 - idx); el.y1 = y1; el.y2 = y1; @@ -255,6 +255,8 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) g.push_back(el); } + // LC Inputs + if (id >= TILE_WIRE_LUTFF_0_IN_0 && id <= TILE_WIRE_LUTFF_7_IN_3) { int idx = id - TILE_WIRE_LUTFF_0_IN_0; int z = idx / 4; @@ -267,6 +269,31 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.y2 = el.y1; g.push_back(el); } + + // LC Outputs + + if (id >= TILE_WIRE_LUTFF_0_OUT && id <= TILE_WIRE_LUTFF_7_OUT) { + int idx = id - TILE_WIRE_LUTFF_0_OUT; + + float y1 = y + 0.03 + 0.0025 * (102 - idx); + + GraphicElement el; + el.type = GraphicElement::G_LINE; + el.y1 = y1; + el.y2 = y1; + el.x1 = x + 0.3; + el.x2 = x + 0.97 + 0.0025 * idx; + g.push_back(el); + + el.y1 = y1; + el.y2 = y + (logic_cell_y1 + logic_cell_y2) / 2 + idx * logic_cell_pitch; + el.x1 = el.x2; + g.push_back(el); + + el.y1 = el.y2; + el.x1 = x + logic_cell_x2; + g.push_back(el); + } } NEXTPNR_NAMESPACE_END diff --git a/ice40/gfx.h b/ice40/gfx.h index 784ba23f..0fdfc326 100644 --- a/ice40/gfx.h +++ b/ice40/gfx.h @@ -60,7 +60,7 @@ const float span4v_swbox_y1 = 0.300; const float span4v_swbox_y2 = 0.400; const float logic_cell_x1 = 0.82; -const float logic_cell_x2 = 0.92; +const float logic_cell_x2 = 0.95; const float logic_cell_y1 = 0.45; const float logic_cell_y2 = 0.50; const float logic_cell_pitch = 0.0625; -- cgit v1.2.3 From f88f86125dcdfcdb3bd53685a6a3f670a7baab49 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 10 Jul 2018 13:54:05 +0200 Subject: Set family specific parameters for GUI --- gui/CMakeLists.txt | 1 + gui/generic/family.cmake | 0 gui/ice40/family.cmake | 3 +++ 3 files changed, 4 insertions(+) create mode 100644 gui/generic/family.cmake create mode 100644 gui/ice40/family.cmake diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 68fd0229..5ac4d955 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -26,6 +26,7 @@ qt5_add_resources(GUI_RESOURCE_FILES ${_RESOURCES}) set(GUI_LIBRARY_FILES_${ufamily} Qt5::Widgets Qt5::OpenGL ${OPENGL_LIBRARIES} QtPropertyBrowser PARENT_SCOPE) add_library(gui_${family} STATIC ${GUI_SOURCE_FILES} ${PYTHON_CONSOLE_SRC} ${GUI_RESOURCE_FILES}) +include(${family}/family.cmake) target_include_directories(gui_${family} PRIVATE ../${family} ${family} ../3rdparty/QtPropertyBrowser/src) if (BUILD_PYTHON) diff --git a/gui/generic/family.cmake b/gui/generic/family.cmake new file mode 100644 index 00000000..e69de29b diff --git a/gui/ice40/family.cmake b/gui/ice40/family.cmake new file mode 100644 index 00000000..ede5b805 --- /dev/null +++ b/gui/ice40/family.cmake @@ -0,0 +1,3 @@ +if(ICE40_HX1K_ONLY) + target_compile_definitions(gui_${family} PRIVATE ICE40_HX1K_ONLY=1) +endif() -- cgit v1.2.3 From bfc47e9cd4512a503266c3f9cbe8841ed6136580 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 10 Jul 2018 13:58:20 +0200 Subject: Added ICE40_HX1K_ONLY check in gui and main --- gui/ice40/mainwindow.cc | 4 ++++ ice40/main.cc | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index f423ee37..c4e568a3 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -220,12 +220,16 @@ QStringList getSupportedPackages(ArchArgs::ArchArgsTypes chip) void MainWindow::new_proj() { QMap arch; +#ifdef ICE40_HX1K_ONLY + arch.insert("Lattice HX1K", ArchArgs::HX1K); +#else arch.insert("Lattice LP384", ArchArgs::LP384); arch.insert("Lattice LP1K", ArchArgs::LP1K); arch.insert("Lattice HX1K", ArchArgs::HX1K); arch.insert("Lattice UP5K", ArchArgs::UP5K); arch.insert("Lattice LP8K", ArchArgs::LP8K); arch.insert("Lattice HX8K", ArchArgs::HX8K); +#endif bool ok; QString item = QInputDialog::getItem(this, "Select new context", "Chip:", arch.keys(), 0, false, &ok); if (ok && !item.isEmpty()) { diff --git a/ice40/main.cc b/ice40/main.cc index 87a32ded..ff823cbe 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -98,12 +98,16 @@ int main(int argc, char *argv[]) options.add_options()("seed", po::value(), "seed value for random number generator"); options.add_options()("version,V", "show version"); options.add_options()("tmfuzz", "run path delay estimate fuzzer"); +#ifdef ICE40_HX1K_ONLY + options.add_options()("hx1k", "set device type to iCE40HX1K"); +#else options.add_options()("lp384", "set device type to iCE40LP384"); options.add_options()("lp1k", "set device type to iCE40LP1K"); options.add_options()("lp8k", "set device type to iCE40LP8K"); options.add_options()("hx1k", "set device type to iCE40HX1K"); options.add_options()("hx8k", "set device type to iCE40HX8K"); options.add_options()("up5k", "set device type to iCE40UP5K"); +#endif options.add_options()("freq", po::value(), "set target frequency for design in MHz"); options.add_options()("no-tmdriv", "disable timing-driven placement"); options.add_options()("package", po::value(), "set device package"); -- cgit v1.2.3 From 841714a3d6bf475586812db3ba39bbd4dd4606de Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 10 Jul 2018 15:09:11 +0200 Subject: Improve ic40 gfx Signed-off-by: Clifford Wolf --- ice40/arch.cc | 80 +++++++---------------------- ice40/gfx.cc | 141 +++++++++++++++++++++++++++++++++++++++++++++++---- ice40/gfx.h | 159 +++++++++++++++++++++++++--------------------------------- 3 files changed, 216 insertions(+), 164 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 2eb7d1c3..0b82914a 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -436,69 +436,25 @@ std::vector Arch::getBelGraphics(BelId bel) const if (chip_info->bel_data[bel.index].z == 0) { int tx = chip_info->bel_data[bel.index].x; int ty = chip_info->bel_data[bel.index].y; - // Local tracks to LUT input switchbox - GraphicElement lc_lut_sw; - lc_lut_sw.type = GraphicElement::G_BOX; - lc_lut_sw.x1 = tx + lc_lut_swbox_x1; - lc_lut_sw.x2 = tx + lc_lut_swbox_x2; - lc_lut_sw.y1 = ty + lc_lut_swbox_y1; - lc_lut_sw.y2 = ty + lc_lut_swbox_y2; - lc_lut_sw.z = 0; - ret.push_back(lc_lut_sw); - // Local tracks switchbox - GraphicElement lc_sw; - lc_sw.type = GraphicElement::G_BOX; - lc_sw.x1 = tx + locals_swbox_x1; - lc_sw.x2 = tx + locals_swbox_x2; - lc_sw.y1 = ty + locals_swbox_y1; - lc_sw.y2 = ty + locals_swbox_y2; - ret.push_back(lc_sw); - - // lutff_global switchbox - GraphicElement lff_glb_sw; - lff_glb_sw.type = GraphicElement::G_BOX; - lff_glb_sw.x1 = tx + lutff_global_swbox_x1; - lff_glb_sw.x2 = tx + lutff_global_swbox_x2; - lff_glb_sw.y1 = ty + lutff_global_swbox_y1; - lff_glb_sw.y2 = ty + lutff_global_swbox_y2; - ret.push_back(lff_glb_sw); - - // glb2local switchbox - GraphicElement glb2local_sw; - glb2local_sw.type = GraphicElement::G_BOX; - glb2local_sw.x1 = tx + glb2local_swbox_x1; - glb2local_sw.x2 = tx + glb2local_swbox_x2; - glb2local_sw.y1 = ty + glb2local_swbox_y1; - glb2local_sw.y2 = ty + glb2local_swbox_y2; - ret.push_back(glb2local_sw); - - // span12 switchbox - GraphicElement sp12_sw; - sp12_sw.type = GraphicElement::G_BOX; - sp12_sw.x1 = tx + span12_swbox_x1; - sp12_sw.x2 = tx + span12_swbox_x2; - sp12_sw.y1 = ty + span12_swbox_y1; - sp12_sw.y2 = ty + span12_swbox_y2; - ret.push_back(sp12_sw); - - // span4v switchbox - GraphicElement sp4v_sw; - sp4v_sw.type = GraphicElement::G_BOX; - sp4v_sw.x1 = tx + span4h_swbox_x1; - sp4v_sw.x2 = tx + span4h_swbox_x2; - sp4v_sw.y1 = ty + span4h_swbox_y1; - sp4v_sw.y2 = ty + span4h_swbox_y2; - ret.push_back(sp4v_sw); - - // span4h switchbox - GraphicElement sp4h_sw; - sp4h_sw.type = GraphicElement::G_BOX; - sp4h_sw.x1 = tx + span4v_swbox_x1; - sp4h_sw.x2 = tx + span4v_swbox_x2; - sp4h_sw.y1 = ty + span4v_swbox_y1; - sp4h_sw.y2 = ty + span4v_swbox_y2; - ret.push_back(sp4h_sw); + // Main switchbox + GraphicElement main_sw; + main_sw.type = GraphicElement::G_BOX; + main_sw.x1 = tx + main_swbox_x1; + main_sw.x2 = tx + main_swbox_x2; + main_sw.y1 = ty + main_swbox_y1; + main_sw.y2 = ty + main_swbox_y2; + ret.push_back(main_sw); + + // Local tracks to LUT input switchbox + GraphicElement local_sw; + local_sw.type = GraphicElement::G_BOX; + local_sw.x1 = tx + local_swbox_x1; + local_sw.x2 = tx + local_swbox_x2; + local_sw.y1 = ty + local_swbox_y1; + local_sw.y2 = ty + local_swbox_y2; + local_sw.z = 0; + ret.push_back(local_sw); // All the wires for (int i = TILE_WIRE_GLB2LOCAL_0; i <= TILE_WIRE_SP12_H_L_23; i++) diff --git a/ice40/gfx.cc b/ice40/gfx.cc index 58e52d65..e72b2515 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -37,6 +37,12 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.y1 = y1; el.y2 = y1; g.push_back(el); + + el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 35); + el.x2 = el.x1; + el.y1 = y1; + el.y2 = y + main_swbox_y1; + g.push_back(el); } if (id >= TILE_WIRE_SP4_H_R_0 && id <= TILE_WIRE_SP4_H_R_47) { @@ -73,6 +79,12 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.y1 = y2; el.y2 = y3; g.push_back(el); + + el.x1 = x + main_swbox_x1 + 0.0025 * ((idx ^ 1) + 35); + el.x2 = el.x1; + el.y1 = y2; + el.y2 = y + main_swbox_y1; + g.push_back(el); } // Vertical Span-4 Wires @@ -89,6 +101,12 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x1 = x1; el.x2 = x1; g.push_back(el); + + el.y1 = y + 0.03 + 0.0025 * (270 - idx); + el.y2 = el.y1; + el.x1 = x1; + el.x2 = x + main_swbox_x1; + g.push_back(el); } if (id >= TILE_WIRE_SP4_V_B_0 && id <= TILE_WIRE_SP4_V_B_47) { @@ -126,13 +144,17 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x2 = x3; g.push_back(el); - float y1 = y + 0.03 + 0.0025 * (154 - idx); - - el.y1 = y1; - el.y2 = y1; + el.y1 = y + 0.03 + 0.0025 * (145 - idx); + el.y2 = el.y1; el.x1 = x; el.x2 = x2; g.push_back(el); + + el.y1 = y + 0.03 + 0.0025 * (270 - idx); + el.y2 = el.y1; + el.x1 = x2; + el.x2 = x + main_swbox_x1; + g.push_back(el); } // Horizontal Span-12 Wires @@ -149,6 +171,12 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.y1 = y1; el.y2 = y1; g.push_back(el); + + el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 5); + el.x2 = el.x1; + el.y1 = y1; + el.y2 = y + main_swbox_y1; + g.push_back(el); } if (id >= TILE_WIRE_SP12_H_R_0 && id <= TILE_WIRE_SP12_H_R_23) { @@ -185,20 +213,26 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.y1 = y2; el.y2 = y3; g.push_back(el); + + el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 5); + el.x2 = el.x1; + el.y1 = y2; + el.y2 = y + main_swbox_y1; + g.push_back(el); } - // Veritcal Right Span-4 + // Vertical Right Span-4 if (id >= TILE_WIRE_SP4_R_V_B_0 && id <= TILE_WIRE_SP4_R_V_B_47) { int idx = id - TILE_WIRE_SP4_R_V_B_0; GraphicElement el; el.type = GraphicElement::G_LINE; - float y1 = y + 0.03 + 0.0025 * (154 - idx); + float y1 = y + 0.03 + 0.0025 * (145 - idx); el.y1 = y1; el.y2 = y1; - el.x1 = x + 0.6; + el.x1 = x + main_swbox_x2; el.x2 = x + 1.0; g.push_back(el); } @@ -217,6 +251,12 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x1 = x1; el.x2 = x1; g.push_back(el); + + el.y1 = y + 0.03 + 0.0025 * (300 - idx); + el.y2 = el.y1; + el.x1 = x1; + el.x2 = x + main_swbox_x1; + g.push_back(el); } if (id >= TILE_WIRE_SP12_V_B_0 && id <= TILE_WIRE_SP12_V_B_23) { @@ -253,6 +293,65 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x1 = x2; el.x2 = x3; g.push_back(el); + + el.y1 = y + 0.03 + 0.0025 * (300 - (idx ^ 1)); + el.y2 = el.y1; + el.x1 = x2; + el.x2 = x + main_swbox_x1; + g.push_back(el); + } + + // Global2Local + + if (id >= TILE_WIRE_GLB2LOCAL_0 && id <= TILE_WIRE_GLB2LOCAL_3) { + int idx = id - TILE_WIRE_GLB2LOCAL_0; + GraphicElement el; + el.type = GraphicElement::G_LINE; + el.x1 = x + main_swbox_x1 + 0.005 * (idx + 5); + el.x2 = el.x1; + el.y1 = y + main_swbox_y2; + el.y2 = el.y1 + 0.02; + g.push_back(el); + } + + // GlobalNets + + if (id >= TILE_WIRE_GLB_NETWK_0 && id <= TILE_WIRE_GLB_NETWK_7) { + int idx = id - TILE_WIRE_GLB_NETWK_0; + GraphicElement el; + el.type = GraphicElement::G_LINE; + el.x1 = x + main_swbox_x1 - 0.05; + el.x2 = x + main_swbox_x1; + el.y1 = y + main_swbox_y2 - 0.005 * (13 - idx); + el.y2 = el.y1; + g.push_back(el); + } + + // Neighbours + + if (id >= TILE_WIRE_NEIGH_OP_BNL_0 && id <= TILE_WIRE_NEIGH_OP_TOP_7) { + int idx = id - TILE_WIRE_NEIGH_OP_BNL_0; + GraphicElement el; + el.type = GraphicElement::G_LINE; + el.y1 = y + main_swbox_y1 + 0.0025 * (idx + 10) + 0.01 * (idx / 8); + el.y2 = el.y1; + el.x1 = x + main_swbox_x1 - 0.05; + el.x2 = x + main_swbox_x1; + g.push_back(el); + } + + // Local Tracks + + if (id >= TILE_WIRE_LOCAL_G0_0 && id <= TILE_WIRE_LOCAL_G3_7) { + int idx = id - TILE_WIRE_LOCAL_G0_0; + GraphicElement el; + el.type = GraphicElement::G_LINE; + el.x1 = x + main_swbox_x2; + el.x2 = x + local_swbox_x1; + float yoff = y + (local_swbox_y1 + local_swbox_y2) / 2 - 0.005 * 16 - 0.075; + el.y1 = yoff + 0.005 * idx + 0.05 * (idx / 8); + el.y2 = el.y1; + g.push_back(el); } // LC Inputs @@ -263,7 +362,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) int input = idx % 4; GraphicElement el; el.type = GraphicElement::G_LINE; - el.x1 = x + lc_lut_swbox_x2; + el.x1 = x + local_swbox_x2; el.x2 = x + logic_cell_x1; el.y1 = y + 0.4675 + (0.005 * input) + z * logic_cell_pitch; el.y2 = el.y1; @@ -275,13 +374,13 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_LUTFF_0_OUT && id <= TILE_WIRE_LUTFF_7_OUT) { int idx = id - TILE_WIRE_LUTFF_0_OUT; - float y1 = y + 0.03 + 0.0025 * (102 - idx); + float y1 = y + 0.03 + 0.0025 * (159 - idx); GraphicElement el; el.type = GraphicElement::G_LINE; el.y1 = y1; el.y2 = y1; - el.x1 = x + 0.3; + el.x1 = x + main_swbox_x2; el.x2 = x + 0.97 + 0.0025 * idx; g.push_back(el); @@ -294,6 +393,28 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x1 = x + logic_cell_x2; g.push_back(el); } + + // LC Control + + if (id >= TILE_WIRE_LUTFF_GLOBAL_CEN && id <= TILE_WIRE_LUTFF_GLOBAL_S_R) { + int idx = id - TILE_WIRE_LUTFF_GLOBAL_CEN; + GraphicElement el; + el.type = GraphicElement::G_LINE; + + el.x1 = x + main_swbox_x2 - 0.005 * (idx + 5); + el.x2 = el.x1; + el.y1 = y + main_swbox_y2; + el.y2 = el.y1 + 0.005 * (idx + 3); + g.push_back(el); + + el.y1 = el.y2; + el.x2 = x + logic_cell_x2 - 0.005 * (2 - idx + 5); + g.push_back(el); + + el.y2 = y + logic_cell_y2 + 7*logic_cell_pitch; + el.x1 = el.x2; + g.push_back(el); + } } NEXTPNR_NAMESPACE_END diff --git a/ice40/gfx.h b/ice40/gfx.h index 0fdfc326..9fce27e8 100644 --- a/ice40/gfx.h +++ b/ice40/gfx.h @@ -24,42 +24,17 @@ NEXTPNR_NAMESPACE_BEGIN -const float lc_lut_swbox_x1 = 0.75; -const float lc_lut_swbox_x2 = 0.8; -const float lc_lut_swbox_y1 = 0.45; -const float lc_lut_swbox_y2 = 0.9375; - -const float locals_swbox_x1 = 0.6; -const float locals_swbox_x2 = 0.7; -const float locals_swbox_y1 = 0.65; -const float locals_swbox_y2 = 0.75; - -const float lutff_global_swbox_x1 = 0.65; -const float lutff_global_swbox_x2 = 0.7; -const float lutff_global_swbox_y1 = 0.91; -const float lutff_global_swbox_y2 = 0.96; - -const float glb2local_swbox_x1 = 0.45; -const float glb2local_swbox_x2 = 0.55; -const float glb2local_swbox_y1 = 0.80; -const float glb2local_swbox_y2 = 0.85; - -const float span12_swbox_x1 = 0.500; -const float span12_swbox_x2 = 0.575; -const float span12_swbox_y1 = 0.525; -const float span12_swbox_y2 = 0.625; - -const float span4h_swbox_x1 = 0.400; -const float span4h_swbox_x2 = 0.475; -const float span4h_swbox_y1 = 0.425; -const float span4h_swbox_y2 = 0.525; - -const float span4v_swbox_x1 = 0.300; -const float span4v_swbox_x2 = 0.375; -const float span4v_swbox_y1 = 0.300; -const float span4v_swbox_y2 = 0.400; - -const float logic_cell_x1 = 0.82; +const float main_swbox_x1 = 0.35; +const float main_swbox_x2 = 0.60; +const float main_swbox_y1 = 0.27; +const float main_swbox_y2 = 0.95; + +const float local_swbox_x1 = 0.63; +const float local_swbox_x2 = 0.73; +const float local_swbox_y1 = 0.45; +const float local_swbox_y2 = 0.9375; + +const float logic_cell_x1 = 0.76; const float logic_cell_x2 = 0.95; const float logic_cell_y1 = 0.45; const float logic_cell_y2 = 0.50; @@ -190,75 +165,75 @@ enum GfxTileWireId { TILE_WIRE_LUTFF_GLOBAL_S_R, TILE_WIRE_NEIGH_OP_BNL_0, - TILE_WIRE_NEIGH_OP_BNR_0, - TILE_WIRE_NEIGH_OP_BOT_0, - TILE_WIRE_NEIGH_OP_LFT_0, - TILE_WIRE_NEIGH_OP_RGT_0, - TILE_WIRE_NEIGH_OP_TNL_0, - TILE_WIRE_NEIGH_OP_TNR_0, - TILE_WIRE_NEIGH_OP_TOP_0, - TILE_WIRE_NEIGH_OP_BNL_1, - TILE_WIRE_NEIGH_OP_BNR_1, - TILE_WIRE_NEIGH_OP_BOT_1, - TILE_WIRE_NEIGH_OP_LFT_1, - TILE_WIRE_NEIGH_OP_RGT_1, - TILE_WIRE_NEIGH_OP_TNL_1, - TILE_WIRE_NEIGH_OP_TNR_1, - TILE_WIRE_NEIGH_OP_TOP_1, - TILE_WIRE_NEIGH_OP_BNL_2, - TILE_WIRE_NEIGH_OP_BNR_2, - TILE_WIRE_NEIGH_OP_BOT_2, - TILE_WIRE_NEIGH_OP_LFT_2, - TILE_WIRE_NEIGH_OP_RGT_2, - TILE_WIRE_NEIGH_OP_TNL_2, - TILE_WIRE_NEIGH_OP_TNR_2, - TILE_WIRE_NEIGH_OP_TOP_2, - TILE_WIRE_NEIGH_OP_BNL_3, - TILE_WIRE_NEIGH_OP_BNR_3, - TILE_WIRE_NEIGH_OP_BOT_3, - TILE_WIRE_NEIGH_OP_LFT_3, - TILE_WIRE_NEIGH_OP_RGT_3, - TILE_WIRE_NEIGH_OP_TNL_3, - TILE_WIRE_NEIGH_OP_TNR_3, - TILE_WIRE_NEIGH_OP_TOP_3, - TILE_WIRE_NEIGH_OP_BNL_4, - TILE_WIRE_NEIGH_OP_BNR_4, - TILE_WIRE_NEIGH_OP_BOT_4, - TILE_WIRE_NEIGH_OP_LFT_4, - TILE_WIRE_NEIGH_OP_RGT_4, - TILE_WIRE_NEIGH_OP_TNL_4, - TILE_WIRE_NEIGH_OP_TNR_4, - TILE_WIRE_NEIGH_OP_TOP_4, - TILE_WIRE_NEIGH_OP_BNL_5, - TILE_WIRE_NEIGH_OP_BNR_5, - TILE_WIRE_NEIGH_OP_BOT_5, - TILE_WIRE_NEIGH_OP_LFT_5, - TILE_WIRE_NEIGH_OP_RGT_5, - TILE_WIRE_NEIGH_OP_TNL_5, - TILE_WIRE_NEIGH_OP_TNR_5, - TILE_WIRE_NEIGH_OP_TOP_5, - TILE_WIRE_NEIGH_OP_BNL_6, - TILE_WIRE_NEIGH_OP_BNR_6, - TILE_WIRE_NEIGH_OP_BOT_6, - TILE_WIRE_NEIGH_OP_LFT_6, - TILE_WIRE_NEIGH_OP_RGT_6, - TILE_WIRE_NEIGH_OP_TNL_6, - TILE_WIRE_NEIGH_OP_TNR_6, - TILE_WIRE_NEIGH_OP_TOP_6, - TILE_WIRE_NEIGH_OP_BNL_7, + + TILE_WIRE_NEIGH_OP_BNR_0, + TILE_WIRE_NEIGH_OP_BNR_1, + TILE_WIRE_NEIGH_OP_BNR_2, + TILE_WIRE_NEIGH_OP_BNR_3, + TILE_WIRE_NEIGH_OP_BNR_4, + TILE_WIRE_NEIGH_OP_BNR_5, + TILE_WIRE_NEIGH_OP_BNR_6, TILE_WIRE_NEIGH_OP_BNR_7, + + TILE_WIRE_NEIGH_OP_BOT_0, + TILE_WIRE_NEIGH_OP_BOT_1, + TILE_WIRE_NEIGH_OP_BOT_2, + TILE_WIRE_NEIGH_OP_BOT_3, + TILE_WIRE_NEIGH_OP_BOT_4, + TILE_WIRE_NEIGH_OP_BOT_5, + TILE_WIRE_NEIGH_OP_BOT_6, TILE_WIRE_NEIGH_OP_BOT_7, + + TILE_WIRE_NEIGH_OP_LFT_0, + TILE_WIRE_NEIGH_OP_LFT_1, + TILE_WIRE_NEIGH_OP_LFT_2, + TILE_WIRE_NEIGH_OP_LFT_3, + TILE_WIRE_NEIGH_OP_LFT_4, + TILE_WIRE_NEIGH_OP_LFT_5, + TILE_WIRE_NEIGH_OP_LFT_6, TILE_WIRE_NEIGH_OP_LFT_7, + + TILE_WIRE_NEIGH_OP_RGT_0, + TILE_WIRE_NEIGH_OP_RGT_1, + TILE_WIRE_NEIGH_OP_RGT_2, + TILE_WIRE_NEIGH_OP_RGT_3, + TILE_WIRE_NEIGH_OP_RGT_4, + TILE_WIRE_NEIGH_OP_RGT_5, + TILE_WIRE_NEIGH_OP_RGT_6, TILE_WIRE_NEIGH_OP_RGT_7, + + TILE_WIRE_NEIGH_OP_TNL_0, + TILE_WIRE_NEIGH_OP_TNL_1, + TILE_WIRE_NEIGH_OP_TNL_2, + TILE_WIRE_NEIGH_OP_TNL_3, + TILE_WIRE_NEIGH_OP_TNL_4, + TILE_WIRE_NEIGH_OP_TNL_5, + TILE_WIRE_NEIGH_OP_TNL_6, TILE_WIRE_NEIGH_OP_TNL_7, + + TILE_WIRE_NEIGH_OP_TNR_0, + TILE_WIRE_NEIGH_OP_TNR_1, + TILE_WIRE_NEIGH_OP_TNR_2, + TILE_WIRE_NEIGH_OP_TNR_3, + TILE_WIRE_NEIGH_OP_TNR_4, + TILE_WIRE_NEIGH_OP_TNR_5, + TILE_WIRE_NEIGH_OP_TNR_6, TILE_WIRE_NEIGH_OP_TNR_7, + + TILE_WIRE_NEIGH_OP_TOP_0, + TILE_WIRE_NEIGH_OP_TOP_1, + TILE_WIRE_NEIGH_OP_TOP_2, + TILE_WIRE_NEIGH_OP_TOP_3, + TILE_WIRE_NEIGH_OP_TOP_4, + TILE_WIRE_NEIGH_OP_TOP_5, + TILE_WIRE_NEIGH_OP_TOP_6, TILE_WIRE_NEIGH_OP_TOP_7, TILE_WIRE_SP4_V_B_0, -- cgit v1.2.3 From 2ad355ebeb00d9698efe2bb910a500e401f5d50b Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 11 Jul 2018 08:05:42 +0200 Subject: Renamed dummy->generic for tests, also fix warning --- common/pybindings.cc | 2 ++ tests/dummy/main.cc | 28 ---------------------------- tests/generic/main.cc | 28 ++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 28 deletions(-) delete mode 100644 tests/dummy/main.cc create mode 100644 tests/generic/main.cc diff --git a/common/pybindings.cc b/common/pybindings.cc index 64055755..1a0eba8f 100644 --- a/common/pybindings.cc +++ b/common/pybindings.cc @@ -151,7 +151,9 @@ BOOST_PYTHON_MODULE(MODULE_NAME) arch_wrap_python(); } +#ifdef MAIN_EXECUTABLE static wchar_t *program; +#endif void init_python(const char *executable, bool first) { diff --git a/tests/dummy/main.cc b/tests/dummy/main.cc deleted file mode 100644 index a2634711..00000000 --- a/tests/dummy/main.cc +++ /dev/null @@ -1,28 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2018 Miodrag Milanovic - * - * 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 "gtest/gtest.h" - -#include - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/tests/generic/main.cc b/tests/generic/main.cc new file mode 100644 index 00000000..a2634711 --- /dev/null +++ b/tests/generic/main.cc @@ -0,0 +1,28 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Miodrag Milanovic + * + * 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 "gtest/gtest.h" + +#include + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} -- cgit v1.2.3 From d5be9ff5845e17f17a22fb11cdb5099a84a6bb4d Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 11 Jul 2018 10:23:23 +0200 Subject: Added cmake parameter ARCH to specify architecture to build --- CMakeLists.txt | 34 +++++++++++++++++++++++++++++----- README.md | 3 +++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b4493486..dc4e2a4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,29 @@ option(BUILD_TESTS "Build GUI" OFF) # List of families to build set(FAMILIES generic ice40) +set(ARCH "" CACHE STRING "Architecture family for nextpnr build") +set_property(CACHE ARCH PROPERTY STRINGS ${FAMILIES}) + +if (NOT ARCH) + message(STATUS "Architecture needs to be set, set desired one with -DARCH=xxx") + message(STATUS "Supported architectures are :") + message(STATUS " all") + foreach(item ${FAMILIES}) + message(STATUS " ${item}") + endforeach() + message(FATAL_ERROR "Architecture setting is mandatory") +endif () + +if (ARCH STREQUAL "all") + SET(ARCH ${FAMILIES}) +endif() + +foreach(item ${ARCH}) + if (NOT item IN_LIST FAMILIES) + message(FATAL_ERROR "Architecture '${item}' not in list of supported architectures") + endif() +endforeach() + set(CMAKE_CXX_STANDARD 11) if (MSVC) set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) @@ -62,7 +85,7 @@ if (BUILD_TESTS) endif() if (BUILD_GUI) - add_subdirectory(3rdparty/QtPropertyBrowser ${CMAKE_CURRENT_BINARY_DIR}/generated/3rdparty/QtPropertyBrowser) + add_subdirectory(3rdparty/QtPropertyBrowser ${CMAKE_CURRENT_BINARY_DIR}/generated/3rdparty/QtPropertyBrowser EXCLUDE_FROM_ALL) endif() add_definitions("-DGIT_COMMIT_HASH=${GIT_COMMIT_HASH}") @@ -132,22 +155,23 @@ if(MINGW) add_definitions("-Wa,-mbig-obj") endif(MINGW) -foreach (family ${FAMILIES}) +foreach (family ${ARCH}) + message(STATUS "Configuring architecture : ${family}") string(TOUPPER ${family} ufamily) aux_source_directory(${family}/ ${ufamily}_FILES) if (BUILD_GUI) - add_subdirectory(gui ${CMAKE_CURRENT_BINARY_DIR}/generated/gui/${family}) + add_subdirectory(gui ${CMAKE_CURRENT_BINARY_DIR}/generated/gui/${family} EXCLUDE_FROM_ALL) endif() # Add the CLI binary target - add_executable(nextpnr-${family} ${COMMON_FILES} ${${ufamily}_FILES} ) + add_executable(nextpnr-${family} ${COMMON_FILES} ${${ufamily}_FILES}) install(TARGETS nextpnr-${family} RUNTIME DESTINATION bin) target_compile_definitions(nextpnr-${family} PRIVATE MAIN_EXECUTABLE) if (BUILD_PYTHON) # Add the importable Python module target - PYTHON_ADD_MODULE(nextpnrpy_${family} EXCLUDE_FROM_ALL ${COMMON_FILES} ${${ufamily}_FILES}) + PYTHON_ADD_MODULE(nextpnrpy_${family} ${COMMON_FILES} ${${ufamily}_FILES}) endif() # Add any new per-architecture targets here diff --git a/README.md b/README.md index 195f08c3..7fe49328 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,9 @@ Prequisites Building -------- + - Specifying target architecture is mandatory use ARCH parameter to set it. It is semicolon separated list. + - Use `cmake . -DARCH=all` to build all supported targets + - For example `cmake . -DARCH=ice40` would build just ICE40 support - Use CMake to generate the Makefiles (only needs to be done when `CMakeLists.txt` changes) - For a debug build, run `cmake -DCMAKE_BUILD_TYPE=Debug .` - For a debug build with HX1K support only, run ` cmake -DCMAKE_BUILD_TYPE=Debug -DICE40_HX1K_ONLY=1 .` -- cgit v1.2.3 From eaae6b7dca43d90fabb7676c514d630b1575e9c4 Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 5 Jul 2018 13:32:13 +0200 Subject: ecp5: Begin planning data structures Signed-off-by: David Shah --- ecp5/arch.h | 639 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ecp5/archdefs.h | 126 +++++++++++ ecp5/portpins.inc | 28 +++ 3 files changed, 793 insertions(+) create mode 100644 ecp5/arch.h create mode 100644 ecp5/archdefs.h create mode 100644 ecp5/portpins.inc diff --git a/ecp5/arch.h b/ecp5/arch.h new file mode 100644 index 00000000..c0dbc60b --- /dev/null +++ b/ecp5/arch.h @@ -0,0 +1,639 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * 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. + * + */ + +#ifndef NEXTPNR_H +#error Include "arch.h" via "nextpnr.h" only. +#endif + +NEXTPNR_NAMESPACE_BEGIN + +/**** Everything in this section must be kept in sync with chipdb.py ****/ + +template struct RelPtr +{ + int32_t offset; + + // void set(const T *ptr) { + // offset = reinterpret_cast(ptr) - + // reinterpret_cast(this); + // } + + const T *get() const { return reinterpret_cast(reinterpret_cast(this) + offset); } + + const T &operator[](size_t index) const { return get()[index]; } + + const T &operator*() const { return *(get()); } + + const T *operator->() const { return get(); } +}; + +NPNR_PACKED_STRUCT(struct BelWirePOD { + Location rel_wire_loc; + int32_t wire_index; + PortPin port; + }); + +NPNR_PACKED_STRUCT(struct BelInfoPOD { + RelPtr name; + BelType type; + int32_t num_bel_wires; + RelPtr bel_wires; + int8_t x, y, z; + int8_t padding_0; + }); + +NPNR_PACKED_STRUCT(struct BelPortPOD { + Location rel_bel_loc; + int32_t bel_index; + PortPin port; + }); + +NPNR_PACKED_STRUCT(struct PipInfoPOD { + Location rel_src_loc, rel_dst_loc; + int32_t src_idx, dst_idx; + int32_t delay; + Location rel_tile_loc; + int16_t tile_type; + int8_t pip_type; + int8_t padding_0; + }); + +NPNR_PACKED_STRUCT(struct PipLocatorPOD { + Location rel_loc; + int32_t index; +}); + +NPNR_PACKED_STRUCT(struct WireInfoPOD { + RelPtr name; + int32_t num_uphill, num_downhill; + RelPtr pips_uphill, pips_downhill; + + int32_t num_bels_downhill; + BelPortPOD bel_uphill; + RelPtr bels_downhill; + }); + +NPNR_PACKED_STRUCT(struct LocationTypePOD { + int32_t num_bels, num_wires, num_pips; + RelPtr bel_data; + RelPtr wire_data; + RelPtr pip_data; +}); + +NPNR_PACKED_STRUCT(struct ChipInfoPOD { + int32_t width, height; + int32_t num_location_types; + RelPtr locations; + RelPtr location_type; + }); + +#if defined(_MSC_VER) +extern const char *chipdb_blob_384; +extern const char *chipdb_blob_1k; +extern const char *chipdb_blob_5k; +extern const char *chipdb_blob_8k; +#else +extern const char chipdb_blob_384[]; +extern const char chipdb_blob_1k[]; +extern const char chipdb_blob_5k[]; +extern const char chipdb_blob_8k[]; +#endif + +/************************ End of chipdb section. ************************/ + +struct BelIterator +{ + int cursor; + + BelIterator operator++() + { + cursor++; + return *this; + } + BelIterator operator++(int) + { + BelIterator prior(*this); + cursor++; + return prior; + } + + bool operator!=(const BelIterator &other) const { return cursor != other.cursor; } + + bool operator==(const BelIterator &other) const { return cursor == other.cursor; } + + BelId operator*() const + { + BelId ret; + ret.index = cursor; + return ret; + } +}; + +struct BelRange +{ + BelIterator b, e; + BelIterator begin() const { return b; } + BelIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +struct BelPinIterator +{ + const BelPortPOD *ptr = nullptr; + + void operator++() { ptr++; } + bool operator!=(const BelPinIterator &other) const { return ptr != other.ptr; } + + BelPin operator*() const + { + BelPin ret; + ret.bel.index = ptr->bel_index; + ret.pin = ptr->port; + return ret; + } +}; + +struct BelPinRange +{ + BelPinIterator b, e; + BelPinIterator begin() const { return b; } + BelPinIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +struct WireIterator +{ + int cursor = -1; + + void operator++() { cursor++; } + bool operator!=(const WireIterator &other) const { return cursor != other.cursor; } + + WireId operator*() const + { + WireId ret; + ret.index = cursor; + return ret; + } +}; + +struct WireRange +{ + WireIterator b, e; + WireIterator begin() const { return b; } + WireIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +struct AllPipIterator +{ + int cursor = -1; + + void operator++() { cursor++; } + bool operator!=(const AllPipIterator &other) const { return cursor != other.cursor; } + + PipId operator*() const + { + PipId ret; + ret.index = cursor; + return ret; + } +}; + +struct AllPipRange +{ + AllPipIterator b, e; + AllPipIterator begin() const { return b; } + AllPipIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +struct PipIterator +{ + const int *cursor = nullptr; + + void operator++() { cursor++; } + bool operator!=(const PipIterator &other) const { return cursor != other.cursor; } + + PipId operator*() const + { + PipId ret; + ret.index = *cursor; + return ret; + } +}; + +struct PipRange +{ + PipIterator b, e; + PipIterator begin() const { return b; } + PipIterator end() const { return e; } +}; + +struct ArchArgs +{ + enum + { + NONE, + LP384, + LP1K, + LP8K, + HX1K, + HX8K, + UP5K + } type = NONE; + std::string package; +}; + +struct Arch : BaseCtx +{ + const ChipInfoPOD *chip_info; + const PackageInfoPOD *package_info; + + mutable std::unordered_map bel_by_name; + mutable std::unordered_map wire_by_name; + mutable std::unordered_map pip_by_name; + + std::vector bel_to_cell; + std::vector wire_to_net; + std::vector pip_to_net; + std::vector switches_locked; + + ArchArgs args; + Arch(ArchArgs args); + + std::string getChipName(); + + IdString archId() const { return id("ice40"); } + IdString archArgsToId(ArchArgs args) const; + + IdString belTypeToId(BelType type) const; + BelType belTypeFromId(IdString id) const; + + IdString portPinToId(PortPin type) const; + PortPin portPinFromId(IdString id) const; + + // ------------------------------------------------- + + BelId getBelByName(IdString name) const; + + IdString getBelName(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return id(chip_info->bel_data[bel.index].name.get()); + } + + uint32_t getBelChecksum(BelId bel) const { return bel.index; } + + void bindBel(BelId bel, IdString cell, PlaceStrength strength) + { + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); + bel_to_cell[bel.index] = cell; + cells[cell]->bel = bel; + cells[cell]->belStrength = strength; + } + + void unbindBel(BelId bel) + { + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); + cells[bel_to_cell[bel.index]]->bel = BelId(); + cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; + bel_to_cell[bel.index] = IdString(); + } + + bool checkBelAvail(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index] == IdString(); + } + + IdString getBoundBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index]; + } + + IdString getConflictingBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index]; + } + + BelRange getBels() const + { + BelRange range; + range.b.cursor = 0; + range.e.cursor = chip_info->num_bels; + return range; + } + + BelRange getBelsByType(BelType type) const + { + BelRange range; +// FIXME +#if 0 + if (type == "TYPE_A") { + range.b.cursor = bels_type_a_begin; + range.e.cursor = bels_type_a_end; + } + ... +#endif + return range; + } + + BelRange getBelsAtSameTile(BelId bel) const; + + BelType getBelType(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return chip_info->bel_data[bel.index].type; + } + + WireId getWireBelPin(BelId bel, PortPin pin) const; + + BelPin getBelPinUphill(WireId wire) const + { + BelPin ret; + NPNR_ASSERT(wire != WireId()); + + if (chip_info->wire_data[wire.index].bel_uphill.bel_index >= 0) { + ret.bel.index = chip_info->wire_data[wire.index].bel_uphill.bel_index; + ret.pin = chip_info->wire_data[wire.index].bel_uphill.port; + } + + return ret; + } + + BelPinRange getBelPinsDownhill(WireId wire) const + { + BelPinRange range; + NPNR_ASSERT(wire != WireId()); + range.b.ptr = chip_info->wire_data[wire.index].bels_downhill.get(); + range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bels_downhill; + return range; + } + + // ------------------------------------------------- + + WireId getWireByName(IdString name) const; + + IdString getWireName(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return id(chip_info->wire_data[wire.index].name.get()); + } + + uint32_t getWireChecksum(WireId wire) const { return wire.index; } + + void bindWire(WireId wire, IdString net, PlaceStrength strength) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire.index] == IdString()); + wire_to_net[wire.index] = net; + nets[net]->wires[wire].pip = PipId(); + nets[net]->wires[wire].strength = strength; + } + + void unbindWire(WireId wire) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire.index] != IdString()); + + auto &net_wires = nets[wire_to_net[wire.index]]->wires; + auto it = net_wires.find(wire); + NPNR_ASSERT(it != net_wires.end()); + + auto pip = it->second.pip; + if (pip != PipId()) { + pip_to_net[pip.index] = IdString(); + switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + } + + net_wires.erase(it); + wire_to_net[wire.index] = IdString(); + } + + bool checkWireAvail(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index] == IdString(); + } + + IdString getBoundWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index]; + } + + IdString getConflictingWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index]; + } + + WireRange getWires() const + { + WireRange range; + range.b.cursor = 0; + range.e.cursor = chip_info->num_wires; + return range; + } + + // ------------------------------------------------- + + PipId getPipByName(IdString name) const; + IdString getPipName(PipId pip) const; + + uint32_t getPipChecksum(PipId pip) const { return pip.index; } + + void bindPip(PipId pip, IdString net, PlaceStrength strength) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip.index] == IdString()); + NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); + + pip_to_net[pip.index] = net; + switches_locked[chip_info->pip_data[pip.index].switch_index] = net; + + WireId dst; + dst.index = chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(wire_to_net[dst.index] == IdString()); + wire_to_net[dst.index] = net; + nets[net]->wires[dst].pip = pip; + nets[net]->wires[dst].strength = strength; + } + + void unbindPip(PipId pip) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip.index] != IdString()); + NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); + + WireId dst; + dst.index = chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(wire_to_net[dst.index] != IdString()); + wire_to_net[dst.index] = IdString(); + nets[pip_to_net[pip.index]]->wires.erase(dst); + + pip_to_net[pip.index] = IdString(); + switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + } + + bool checkPipAvail(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); + } + + IdString getBoundPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return pip_to_net[pip.index]; + } + + IdString getConflictingPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return switches_locked[chip_info->pip_data[pip.index].switch_index]; + } + + AllPipRange getPips() const + { + AllPipRange range; + range.b.cursor = 0; + range.e.cursor = chip_info->num_pips; + return range; + } + + WireId getPipSrcWire(PipId pip) const + { + WireId wire; + NPNR_ASSERT(pip != PipId()); + wire.index = chip_info->pip_data[pip.index].src; + return wire; + } + + WireId getPipDstWire(PipId pip) const + { + WireId wire; + NPNR_ASSERT(pip != PipId()); + wire.index = chip_info->pip_data[pip.index].dst; + return wire; + } + + DelayInfo getPipDelay(PipId pip) const + { + DelayInfo delay; + NPNR_ASSERT(pip != PipId()); + delay.delay = chip_info->pip_data[pip.index].delay; + return delay; + } + + PipRange getPipsDownhill(WireId wire) const + { + PipRange range; + NPNR_ASSERT(wire != WireId()); + range.b.cursor = chip_info->wire_data[wire.index].pips_downhill.get(); + range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_downhill; + return range; + } + + PipRange getPipsUphill(WireId wire) const + { + PipRange range; + NPNR_ASSERT(wire != WireId()); + range.b.cursor = chip_info->wire_data[wire.index].pips_uphill.get(); + range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_uphill; + return range; + } + + PipRange getWireAliases(WireId wire) const + { + PipRange range; + NPNR_ASSERT(wire != WireId()); + range.b.cursor = nullptr; + range.e.cursor = nullptr; + return range; + } + + BelId getPackagePinBel(const std::string &pin) const; + std::string getBelPackagePin(BelId bel) const; + + // ------------------------------------------------- + + void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; + delay_t estimateDelay(WireId src, WireId dst) const; + delay_t getDelayEpsilon() const { return 20; } + delay_t getRipupDelayPenalty() const { return 200; } + float getDelayNS(delay_t v) const { return v * 0.001; } + uint32_t getDelayChecksum(delay_t v) const { return v; } + + // ------------------------------------------------- + + std::vector getFrameGraphics() const; + std::vector getBelGraphics(BelId bel) const; + std::vector getWireGraphics(WireId wire) const; + std::vector getPipGraphics(PipId pip) const; + + bool allGraphicsReload = false; + bool frameGraphicsReload = false; + std::unordered_set belGraphicsReload; + std::unordered_set wireGraphicsReload; + std::unordered_set pipGraphicsReload; + + // ------------------------------------------------- + + // Get the delay through a cell from one port to another, returning false + // if no path exists + bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, delay_t &delay) const; + // Get the associated clock to a port, or empty if the port is combinational + IdString getPortClock(const CellInfo *cell, IdString port) const; + // Return true if a port is a clock + bool isClockPort(const CellInfo *cell, IdString port) const; + // Return true if a port is a net + bool isGlobalNet(const NetInfo *net) const; + + // ------------------------------------------------- + + // Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) + + // Whether or not a given cell can be placed at a given Bel + // This is not intended for Bel type checks, but finer-grained constraints + // such as conflicting set/reset signals, etc + bool isValidBelForCell(CellInfo *cell, BelId bel) const; + + // Return true whether all Bels at a given location are valid + bool isBelLocationValid(BelId bel) const; + + // Helper function for above + bool logicCellsCompatible(const std::vector &cells) const; + + IdString id_glb_buf_out; + IdString id_icestorm_lc, id_sb_io, id_sb_gb; + IdString id_cen, id_clk, id_sr; + IdString id_i0, id_i1, id_i2, id_i3; + IdString id_dff_en, id_neg_clk; +}; + +NEXTPNR_NAMESPACE_END diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h new file mode 100644 index 00000000..f185da72 --- /dev/null +++ b/ecp5/archdefs.h @@ -0,0 +1,126 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Clifford Wolf + * + * 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. + * + */ + +#ifndef NEXTPNR_H +#error Include "archdefs.h" via "nextpnr.h" only. +#endif + +NEXTPNR_NAMESPACE_BEGIN + +typedef int delay_t; + +struct DelayInfo +{ + delay_t delay = 0; + + delay_t raiseDelay() const { return delay; } + delay_t fallDelay() const { return delay; } + delay_t avgDelay() const { return delay; } + + DelayInfo operator+(const DelayInfo &other) const + { + DelayInfo ret; + ret.delay = this->delay + other.delay; + return ret; + } +}; + +// ----------------------------------------------------------------------- + +enum BelType : int32_t +{ + TYPE_NONE, + TYPE_TRELLIS_SLICE, + TYPE_TRELLIS_IO +}; + +enum PortPin : int32_t +{ + PIN_NONE, +#define X(t) PIN_##t, +#include "portpins.inc" +#undef X + PIN_MAXIDX +}; + +NPNR_PACKED_STRUCT( +struct Location { + int16_t x = -1, y = -1; + bool operator==(const Location &other) const { return x == other.x && y == other.y; } + bool operator!=(const Location &other) const { return x != other.x || y == other.y; } +} +); + +struct BelId +{ + Location location; + int32_t index = -1; + + bool operator==(const BelId &other) const { return index == other.index && location == other.location; } + bool operator!=(const BelId &other) const { return index != other.index || location != other.location; } +}; + +struct WireId +{ + Location location; + int32_t index = -1; + + bool operator==(const WireId &other) const { return index == other.index && location == other.location; } + bool operator!=(const WireId &other) const { return index != other.index || location != other.location; } +}; + +struct PipId +{ + Location location; + int32_t index = -1; + + bool operator==(const WireId &other) const { return index == other.index && location == other.location; } + bool operator!=(const WireId &other) const { return index != other.index || location != other.location; } +}; + +NEXTPNR_NAMESPACE_END + +namespace std { +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept { return hash()(bel.index); } +}; + +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept + { + return hash()(wire.index); + } +}; + +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept { return hash()(pip.index); } +}; + +template <> struct hash : hash +{ +}; + +template <> struct hash : hash +{ +}; +} // namespace std diff --git a/ecp5/portpins.inc b/ecp5/portpins.inc new file mode 100644 index 00000000..cfe0a349 --- /dev/null +++ b/ecp5/portpins.inc @@ -0,0 +1,28 @@ +X(A0) +X(B0) +X(C0) +X(D0) +X(A1) +X(B1) +X(C1) +X(D1) +X(M0) +X(M1) +X(FCI) +X(FXA) +X(FXB) +X(CLK) +X(LSR) +X(CE) +X(F0) +X(Q0) +X(F1) +X(Q1) +X(FCO) +X(OFX0) +X(OFX1) + +X(I) +X(O) +X(T) +X(B) -- cgit v1.2.3 From c4af52dd5b3830905e2b9e8f7135f886882841ba Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 5 Jul 2018 20:59:11 +0200 Subject: ecp5: Working on arch implementation Signed-off-by: David Shah --- CMakeLists.txt | 2 +- common/pybindings.cc | 8 +- ecp5/arch.h | 231 ++++++++++++++++++++++++++++------------------- ecp5/archdefs.h | 8 +- ecp5/family.cmake | 0 ice40/arch_pybindings.cc | 8 +- 6 files changed, 153 insertions(+), 104 deletions(-) create mode 100644 ecp5/family.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index dc4e2a4f..f4586dfa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ option(BUILD_PYTHON "Build Python Integration" ON) option(BUILD_TESTS "Build GUI" OFF) # List of families to build -set(FAMILIES generic ice40) +set(FAMILIES generic ice40 ecp5) set(ARCH "" CACHE STRING "Architecture family for nextpnr build") set_property(CACHE ARCH PROPERTY STRINGS ${FAMILIES}) diff --git a/common/pybindings.cc b/common/pybindings.cc index 1a0eba8f..061dfc47 100644 --- a/common/pybindings.cc +++ b/common/pybindings.cc @@ -110,13 +110,13 @@ BOOST_PYTHON_MODULE(MODULE_NAME) readwrite_wrapper, pass_through>::def_wrap(ci_cls, "belStrength"); readonly_wrapper>::def_wrap(ci_cls, - "pins"); + "pins"); auto pi_cls = class_>("PortInfo", no_init); readwrite_wrapper, conv_from_str>::def_wrap(pi_cls, "name"); readonly_wrapper>::def_wrap(pi_cls, - "net"); + "net"); readwrite_wrapper, pass_through>::def_wrap(pi_cls, "type"); @@ -131,11 +131,11 @@ BOOST_PYTHON_MODULE(MODULE_NAME) readonly_wrapper>::def_wrap( ni_cls, "users"); readonly_wrapper>::def_wrap(ni_cls, - "wires"); + "wires"); auto pr_cls = class_>("PortRef", no_init); readonly_wrapper>::def_wrap(pr_cls, - "cell"); + "cell"); readwrite_wrapper, conv_from_str>::def_wrap(pr_cls, "port"); readwrite_wrapper, diff --git a/ecp5/arch.h b/ecp5/arch.h index c0dbc60b..98c4cd76 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -44,35 +44,35 @@ template struct RelPtr }; NPNR_PACKED_STRUCT(struct BelWirePOD { - Location rel_wire_loc; - int32_t wire_index; - PortPin port; - }); + Location rel_wire_loc; + int32_t wire_index; + PortPin port; +}); NPNR_PACKED_STRUCT(struct BelInfoPOD { - RelPtr name; - BelType type; - int32_t num_bel_wires; - RelPtr bel_wires; - int8_t x, y, z; - int8_t padding_0; - }); + RelPtr name; + BelType type; + int32_t num_bel_wires; + RelPtr bel_wires; + int8_t x, y, z; + int8_t padding_0; +}); NPNR_PACKED_STRUCT(struct BelPortPOD { - Location rel_bel_loc; - int32_t bel_index; - PortPin port; - }); + Location rel_bel_loc; + int32_t bel_index; + PortPin port; +}); NPNR_PACKED_STRUCT(struct PipInfoPOD { - Location rel_src_loc, rel_dst_loc; - int32_t src_idx, dst_idx; - int32_t delay; - Location rel_tile_loc; - int16_t tile_type; - int8_t pip_type; - int8_t padding_0; - }); + Location rel_src_loc, rel_dst_loc; + int32_t src_idx, dst_idx; + int32_t delay; + Location rel_tile_loc; + int16_t tile_type; + int8_t pip_type; + int8_t padding_0; +}); NPNR_PACKED_STRUCT(struct PipLocatorPOD { Location rel_loc; @@ -80,28 +80,28 @@ NPNR_PACKED_STRUCT(struct PipLocatorPOD { }); NPNR_PACKED_STRUCT(struct WireInfoPOD { - RelPtr name; - int32_t num_uphill, num_downhill; - RelPtr pips_uphill, pips_downhill; + RelPtr name; + int32_t num_uphill, num_downhill; + RelPtr pips_uphill, pips_downhill; - int32_t num_bels_downhill; - BelPortPOD bel_uphill; - RelPtr bels_downhill; - }); + int32_t num_bels_downhill; + BelPortPOD bel_uphill; + RelPtr bels_downhill; +}); NPNR_PACKED_STRUCT(struct LocationTypePOD { - int32_t num_bels, num_wires, num_pips; - RelPtr bel_data; - RelPtr wire_data; - RelPtr pip_data; + int32_t num_bels, num_wires, num_pips; + RelPtr bel_data; + RelPtr wire_data; + RelPtr pip_data; }); NPNR_PACKED_STRUCT(struct ChipInfoPOD { - int32_t width, height; - int32_t num_location_types; - RelPtr locations; - RelPtr location_type; - }); + int32_t width, height; + int32_t num_location_types; + RelPtr locations; + RelPtr location_type; +}); #if defined(_MSC_VER) extern const char *chipdb_blob_384; @@ -119,11 +119,17 @@ extern const char chipdb_blob_8k[]; struct BelIterator { - int cursor; + const ChipInfoPOD *chip; + int cursor_index; + int cursor_tile; BelIterator operator++() { - cursor++; + cursor_index++; + while (cursor_index >= ci->locations[ci->location_type[cursor_tile]]->num_bels) { + cursor_index = 0; + cursor_tile++; + } return *this; } BelIterator operator++(int) @@ -133,14 +139,22 @@ struct BelIterator return prior; } - bool operator!=(const BelIterator &other) const { return cursor != other.cursor; } + bool operator!=(const BelIterator &other) const + { + return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; + } - bool operator==(const BelIterator &other) const { return cursor == other.cursor; } + bool operator==(const BelIterator &other) const + { + return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; + } BelId operator*() const { BelId ret; - ret.index = cursor; + ret.location.x = cursor_tile % chip->width; + ret.location.y = cursor_tile / chip->width; + ret.index = cursor_index; return ret; } }; @@ -157,7 +171,7 @@ struct BelRange struct BelPinIterator { const BelPortPOD *ptr = nullptr; - + const Location wire_loc; void operator++() { ptr++; } bool operator!=(const BelPinIterator &other) const { return ptr != other.ptr; } @@ -165,6 +179,7 @@ struct BelPinIterator { BelPin ret; ret.bel.index = ptr->bel_index; + ret.bel.location = wire_loc + ptr->rel_bel_loc; ret.pin = ptr->port; return ret; } @@ -181,15 +196,42 @@ struct BelPinRange struct WireIterator { - int cursor = -1; + const ChipInfoPOD *chip; + int cursor_index; + int cursor_tile; - void operator++() { cursor++; } - bool operator!=(const WireIterator &other) const { return cursor != other.cursor; } + WireIterator operator++() + { + cursor_index++; + while (cursor_index >= ci->locations[ci->location_type[cursor_tile]]->num_wires) { + cursor_index = 0; + cursor_tile++; + } + return *this; + } + WireIterator operator++(int) + { + WireIterator prior(*this); + cursor++; + return prior; + } + + bool operator!=(const WireIterator &other) const + { + return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; + } + + bool operator==(const WireIterator &other) const + { + return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; + } WireId operator*() const { WireId ret; - ret.index = cursor; + ret.location.x = cursor_tile % chip->width; + ret.location.y = cursor_tile / chip->width; + ret.index = cursor_index; return ret; } }; @@ -205,15 +247,42 @@ struct WireRange struct AllPipIterator { - int cursor = -1; + const ChipInfoPOD *chip; + int cursor_index; + int cursor_tile; - void operator++() { cursor++; } - bool operator!=(const AllPipIterator &other) const { return cursor != other.cursor; } + AllPipIterator operator++() + { + cursor_index++; + while (cursor_index >= ci->locations[ci->location_type[cursor_tile]]->num_pips) { + cursor_index = 0; + cursor_tile++; + } + return *this; + } + AllPipIterator operator++(int) + { + WireIterator prior(*this); + cursor++; + return prior; + } + + bool operator!=(const AllPipIterator &other) const + { + return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; + } + + bool operator==(const AllPipIterator &other) const + { + return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; + } PipId operator*() const { PipId ret; - ret.index = cursor; + ret.location.x = cursor_tile % chip->width; + ret.location.y = cursor_tile / chip->width; + ret.index = cursor_index; return ret; } }; @@ -229,7 +298,9 @@ struct AllPipRange struct PipIterator { - const int *cursor = nullptr; + + const PipLocatorPOD *cursor = nullptr; + Location wire_loc; void operator++() { cursor++; } bool operator!=(const PipIterator &other) const { return cursor != other.cursor; } @@ -237,7 +308,8 @@ struct PipIterator PipId operator*() const { PipId ret; - ret.index = *cursor; + ret.index = cursor->index; + ret.location = wire_loc + cursor->location; return ret; } }; @@ -254,14 +326,12 @@ struct ArchArgs enum { NONE, - LP384, - LP1K, - LP8K, - HX1K, - HX8K, - UP5K + LFE5U_25F, + LFE5U_45F, + LFE5U_85F, } type = NONE; std::string package; + int speed = 6; }; struct Arch : BaseCtx @@ -273,17 +343,17 @@ struct Arch : BaseCtx mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; - std::vector bel_to_cell; - std::vector wire_to_net; - std::vector pip_to_net; - std::vector switches_locked; + std::unordered_map bel_to_cell; + std::unordered_map wire_to_net; + std::unordered_map pip_to_net; + std::unordered_map switches_locked; ArchArgs args; Arch(ArchArgs args); std::string getChipName(); - IdString archId() const { return id("ice40"); } + IdString archId() const { return id("ecp5"); } IdString archArgsToId(ArchArgs args) const; IdString belTypeToId(BelType type) const; @@ -307,8 +377,8 @@ struct Arch : BaseCtx void bindBel(BelId bel, IdString cell, PlaceStrength strength) { NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); - bel_to_cell[bel.index] = cell; + NPNR_ASSERT(bel_to_cell[bel] == IdString()); + bel_to_cell[bel] = cell; cells[cell]->bel = bel; cells[cell]->belStrength = strength; } @@ -331,13 +401,13 @@ struct Arch : BaseCtx IdString getBoundBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index]; + return bel_to_cell.at(bel); } IdString getConflictingBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index]; + return bel_to_cell.at(bel); } BelRange getBels() const @@ -613,27 +683,6 @@ struct Arch : BaseCtx bool isClockPort(const CellInfo *cell, IdString port) const; // Return true if a port is a net bool isGlobalNet(const NetInfo *net) const; - - // ------------------------------------------------- - - // Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) - - // Whether or not a given cell can be placed at a given Bel - // This is not intended for Bel type checks, but finer-grained constraints - // such as conflicting set/reset signals, etc - bool isValidBelForCell(CellInfo *cell, BelId bel) const; - - // Return true whether all Bels at a given location are valid - bool isBelLocationValid(BelId bel) const; - - // Helper function for above - bool logicCellsCompatible(const std::vector &cells) const; - - IdString id_glb_buf_out; - IdString id_icestorm_lc, id_sb_io, id_sb_gb; - IdString id_cen, id_clk, id_sr; - IdString id_i0, id_i1, id_i2, id_i3; - IdString id_dff_en, id_neg_clk; }; NEXTPNR_NAMESPACE_END diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index f185da72..0af48753 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -60,13 +60,13 @@ enum PortPin : int32_t PIN_MAXIDX }; -NPNR_PACKED_STRUCT( -struct Location { +NPNR_PACKED_STRUCT(struct Location { int16_t x = -1, y = -1; bool operator==(const Location &other) const { return x == other.x && y == other.y; } bool operator!=(const Location &other) const { return x != other.x || y == other.y; } -} -); +}); + +Location operator+(const Location &a, const Location &b) { return Location{a.x + b.x, a.y + b.y};} struct BelId { diff --git a/ecp5/family.cmake b/ecp5/family.cmake new file mode 100644 index 00000000..e69de29b diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc index 67a37983..ac8c189a 100644 --- a/ice40/arch_pybindings.cc +++ b/ice40/arch_pybindings.cc @@ -75,7 +75,7 @@ void arch_wrap_python() fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingBelCell"); fn_wrapper_0a>::def_wrap(ctx_cls, - "getBels"); + "getBels"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelsAtSameTile"); @@ -139,15 +139,15 @@ void arch_wrap_python() fn_wrapper_0a>::def_wrap( ctx_cls, "getChipName"); fn_wrapper_0a>::def_wrap(ctx_cls, - "archId"); + "archId"); typedef std::unordered_map> CellMap; typedef std::unordered_map> NetMap; readonly_wrapper>::def_wrap(ctx_cls, - "cells"); + "cells"); readonly_wrapper>::def_wrap(ctx_cls, - "nets"); + "nets"); WRAP_RANGE(Bel, conv_to_str); WRAP_RANGE(Wire, conv_to_str); WRAP_RANGE(AllPip, conv_to_str); -- cgit v1.2.3 From 7862d1b84b9f770a97f1650cf4a1eb2e02b6389f Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 6 Jul 2018 12:15:07 +0200 Subject: ecp5: Implementing core arch.h functions Signed-off-by: David Shah --- ecp5/arch.cc | 386 ++++++++++++++++++++++++++++++++++++++++++++++++ ecp5/arch.h | 199 +++++++++++++++---------- ecp5/arch_pybindings.cc | 32 ++++ ecp5/arch_pybindings.h | 31 ++++ ecp5/archdefs.h | 46 +++++- ecp5/main.cc | 139 +++++++++++++++++ 6 files changed, 746 insertions(+), 87 deletions(-) create mode 100644 ecp5/arch.cc create mode 100644 ecp5/arch_pybindings.cc create mode 100644 ecp5/arch_pybindings.h create mode 100644 ecp5/main.cc diff --git a/ecp5/arch.cc b/ecp5/arch.cc new file mode 100644 index 00000000..41c73cf8 --- /dev/null +++ b/ecp5/arch.cc @@ -0,0 +1,386 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * 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 +#include +#include "log.h" +#include "nextpnr.h" +#include "util.h" +NEXTPNR_NAMESPACE_BEGIN + +// ----------------------------------------------------------------------- + +IdString Arch::belTypeToId(BelType type) const +{ + if (type == TYPE_ICESTORM_LC) + return id("ICESTORM_LC"); + if (type == TYPE_ICESTORM_RAM) + return id("ICESTORM_RAM"); + if (type == TYPE_SB_IO) + return id("SB_IO"); + if (type == TYPE_SB_GB) + return id("SB_GB"); + if (type == TYPE_ICESTORM_PLL) + return id("ICESTORM_PLL"); + if (type == TYPE_SB_WARMBOOT) + return id("SB_WARMBOOT"); + if (type == TYPE_SB_MAC16) + return id("SB_MAC16"); + if (type == TYPE_ICESTORM_HFOSC) + return id("ICESTORM_HFOSC"); + if (type == TYPE_ICESTORM_LFOSC) + return id("ICESTORM_LFOSC"); + if (type == TYPE_SB_I2C) + return id("SB_I2C"); + if (type == TYPE_SB_SPI) + return id("SB_SPI"); + if (type == TYPE_IO_I3C) + return id("IO_I3C"); + if (type == TYPE_SB_LEDDA_IP) + return id("SB_LEDDA_IP"); + if (type == TYPE_SB_RGBA_DRV) + return id("SB_RGBA_DRV"); + if (type == TYPE_ICESTORM_SPRAM) + return id("ICESTORM_SPRAM"); + return IdString(); +} + +BelType Arch::belTypeFromId(IdString type) const +{ + if (type == id("ICESTORM_LC")) + return TYPE_ICESTORM_LC; + if (type == id("ICESTORM_RAM")) + return TYPE_ICESTORM_RAM; + if (type == id("SB_IO")) + return TYPE_SB_IO; + if (type == id("SB_GB")) + return TYPE_SB_GB; + if (type == id("ICESTORM_PLL")) + return TYPE_ICESTORM_PLL; + if (type == id("SB_WARMBOOT")) + return TYPE_SB_WARMBOOT; + if (type == id("SB_MAC16")) + return TYPE_SB_MAC16; + if (type == id("ICESTORM_HFOSC")) + return TYPE_ICESTORM_HFOSC; + if (type == id("ICESTORM_LFOSC")) + return TYPE_ICESTORM_LFOSC; + if (type == id("SB_I2C")) + return TYPE_SB_I2C; + if (type == id("SB_SPI")) + return TYPE_SB_SPI; + if (type == id("IO_I3C")) + return TYPE_IO_I3C; + if (type == id("SB_LEDDA_IP")) + return TYPE_SB_LEDDA_IP; + if (type == id("SB_RGBA_DRV")) + return TYPE_SB_RGBA_DRV; + if (type == id("ICESTORM_SPRAM")) + return TYPE_ICESTORM_SPRAM; + return TYPE_NONE; +} + +// ----------------------------------------------------------------------- + +void IdString::initialize_arch(const BaseCtx *ctx) +{ +#define X(t) initialize_add(ctx, #t, PIN_##t); +#include "portpins.inc" +#undef X +} + +IdString Arch::portPinToId(PortPin type) const +{ + IdString ret; + if (type > 0 && type < PIN_MAXIDX) + ret.index = type; + return ret; +} + +PortPin Arch::portPinFromId(IdString type) const +{ + if (type.index > 0 && type.index < PIN_MAXIDX) + return PortPin(type.index); + return PIN_NONE; +} + +// ----------------------------------------------------------------------- + +static const ChipInfoPOD *get_chip_info(const RelPtr *ptr) { return ptr->get(); } + +#if defined(_MSC_VER) +void load_chipdb(); +#endif + +Arch::Arch(ArchArgs args) : args(args) +{ +#if defined(_MSC_VER) + load_chipdb(); +#endif + +#ifdef ICE40_HX1K_ONLY + if (args.type == ArchArgs::HX1K) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_1k)); + } else { + log_error("Unsupported iCE40 chip type.\n"); + } +#else + if (args.type == ArchArgs::LP384) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_384)); + } else if (args.type == ArchArgs::LP1K || args.type == ArchArgs::HX1K) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_1k)); + } else if (args.type == ArchArgs::UP5K) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_5k)); + } else if (args.type == ArchArgs::LP8K || args.type == ArchArgs::HX8K) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_8k)); + } else { + log_error("Unsupported iCE40 chip type.\n"); + } +#endif + + package_info = nullptr; + for (int i = 0; i < chip_info->num_packages; i++) { + if (chip_info->packages_data[i].name.get() == args.package) { + package_info = &(chip_info->packages_data[i]); + break; + } + } + if (package_info == nullptr) + log_error("Unsupported package '%s'.\n", args.package.c_str()); + + bel_to_cell.resize(chip_info->num_bels); + wire_to_net.resize(chip_info->num_wires); + pip_to_net.resize(chip_info->num_pips); + switches_locked.resize(chip_info->num_switches); + + // Initialise regularly used IDStrings for performance + id_glb_buf_out = id("GLOBAL_BUFFER_OUTPUT"); + id_icestorm_lc = id("ICESTORM_LC"); + id_sb_io = id("SB_IO"); + id_sb_gb = id("SB_GB"); + id_cen = id("CEN"); + id_clk = id("CLK"); + id_sr = id("SR"); + id_i0 = id("I0"); + id_i1 = id("I1"); + id_i2 = id("I2"); + id_i3 = id("I3"); + id_dff_en = id("DFF_ENABLE"); + id_neg_clk = id("NEG_CLK"); +} + +// ----------------------------------------------------------------------- + +std::string Arch::getChipName() +{ +#ifdef ICE40_HX1K_ONLY + if (args.type == ArchArgs::HX1K) { + return "Lattice LP1K"; + } else { + log_error("Unsupported iCE40 chip type.\n"); + } +#else + if (args.type == ArchArgs::LP384) { + return "Lattice LP384"; + } else if (args.type == ArchArgs::LP1K) { + return "Lattice LP1K"; + } else if (args.type == ArchArgs::HX1K) { + return "Lattice HX1K"; + } else if (args.type == ArchArgs::UP5K) { + return "Lattice UP5K"; + } else if (args.type == ArchArgs::LP8K) { + return "Lattice LP8K"; + } else if (args.type == ArchArgs::HX8K) { + return "Lattice HX8K"; + } else { + log_error("Unknown chip\n"); + } +#endif +} + +// ----------------------------------------------------------------------- + +IdString Arch::archArgsToId(ArchArgs args) const +{ + if (args.type == ArchArgs::LP384) + return id("lp384"); + if (args.type == ArchArgs::LP1K) + return id("lp1k"); + if (args.type == ArchArgs::HX1K) + return id("hx1k"); + if (args.type == ArchArgs::UP5K) + return id("up5k"); + if (args.type == ArchArgs::LP8K) + return id("lp8k"); + if (args.type == ArchArgs::HX8K) + return id("hx8k"); + return IdString(); +} + +// ----------------------------------------------------------------------- + +BelId Arch::getBelByName(IdString name) const +{ + BelId ret; + + if (bel_by_name.empty()) { + for (int i = 0; i < chip_info->num_bels; i++) + bel_by_name[id(chip_info->bel_data[i].name.get())] = i; + } + + auto it = bel_by_name.find(name); + if (it != bel_by_name.end()) + ret.index = it->second; + + return ret; +} + +BelRange Arch::getBelsAtSameTile(BelId bel) const +{ + BelRange br; + NPNR_ASSERT(bel != BelId()); + // This requires Bels at the same tile are consecutive + int x = chip_info->bel_data[bel.index].x; + int y = chip_info->bel_data[bel.index].y; + int start = bel.index, end = bel.index; + while (start >= 0 && chip_info->bel_data[start].x == x && chip_info->bel_data[start].y == y) + start--; + start++; + br.b.cursor = start; + while (end < chip_info->num_bels && chip_info->bel_data[end].x == x && chip_info->bel_data[end].y == y) + end++; + br.e.cursor = end; + return br; +} + +WireId Arch::getWireBelPin(BelId bel, PortPin pin) const +{ + WireId ret; + + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); + + for (int i = 0; i < num_bel_wires; i++) + if (bel_wires[i].port == pin) { + ret.index = bel_wires[i].wire_index; + break; + } + + return ret; +} + +// ----------------------------------------------------------------------- + +WireId Arch::getWireByName(IdString name) const +{ + WireId ret; + + if (wire_by_name.empty()) { + for (int i = 0; i < chip_info->num_wires; i++) + wire_by_name[id(chip_info->wire_data[i].name.get())] = i; + } + + auto it = wire_by_name.find(name); + if (it != wire_by_name.end()) + ret.index = it->second; + + return ret; +} + +// ----------------------------------------------------------------------- + +PipId Arch::getPipByName(IdString name) const +{ + PipId ret; + + if (pip_by_name.empty()) { + for (int i = 0; i < chip_info->num_pips; i++) { + PipId pip; + pip.index = i; + pip_by_name[getPipName(pip)] = i; + } + } + + auto it = pip_by_name.find(name); + if (it != pip_by_name.end()) + ret.index = it->second; + + return ret; +} + +IdString Arch::getPipName(PipId pip) const +{ + NPNR_ASSERT(pip != PipId()); + + int x = chip_info->pip_data[pip.index].x; + int y = chip_info->pip_data[pip.index].y; + + std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get(); + std::replace(src_name.begin(), src_name.end(), '/', '.'); + + std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get(); + std::replace(dst_name.begin(), dst_name.end(), '/', '.'); + + return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); +} + +// ----------------------------------------------------------------------- + +BelId Arch::getPackagePinBel(const std::string &pin) const { return BelId(); } + +std::string Arch::getBelPackagePin(BelId bel) const { return ""; } +// ----------------------------------------------------------------------- + +void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const {} + +delay_t Arch::estimateDelay(WireId src, WireId dst) const { return 1; } + +// ----------------------------------------------------------------------- + +std::vector Arch::getFrameGraphics() const +{ + std::vector ret; + + return ret; +} + +std::vector Arch::getBelGraphics(BelId bel) const +{ + std::vector ret; + + return ret; +} + +std::vector Arch::getWireGraphics(WireId wire) const +{ + std::vector ret; + // FIXME + return ret; +} + +std::vector Arch::getPipGraphics(PipId pip) const +{ + std::vector ret; + // FIXME + return ret; +}; + +NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch.h b/ecp5/arch.h index 98c4cd76..85a3e44c 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -44,7 +44,7 @@ template struct RelPtr }; NPNR_PACKED_STRUCT(struct BelWirePOD { - Location rel_wire_loc; + LocationPOD rel_wire_loc; int32_t wire_index; PortPin port; }); @@ -59,23 +59,23 @@ NPNR_PACKED_STRUCT(struct BelInfoPOD { }); NPNR_PACKED_STRUCT(struct BelPortPOD { - Location rel_bel_loc; + LocationPOD rel_bel_loc; int32_t bel_index; PortPin port; }); NPNR_PACKED_STRUCT(struct PipInfoPOD { - Location rel_src_loc, rel_dst_loc; + LocationPOD rel_src_loc, rel_dst_loc; int32_t src_idx, dst_idx; int32_t delay; - Location rel_tile_loc; + LocationPOD rel_tile_loc; int16_t tile_type; int8_t pip_type; int8_t padding_0; }); NPNR_PACKED_STRUCT(struct PipLocatorPOD { - Location rel_loc; + LocationPOD rel_loc; int32_t index; }); @@ -98,21 +98,20 @@ NPNR_PACKED_STRUCT(struct LocationTypePOD { NPNR_PACKED_STRUCT(struct ChipInfoPOD { int32_t width, height; + int32_t num_tiles; int32_t num_location_types; RelPtr locations; RelPtr location_type; }); #if defined(_MSC_VER) -extern const char *chipdb_blob_384; -extern const char *chipdb_blob_1k; -extern const char *chipdb_blob_5k; -extern const char *chipdb_blob_8k; +extern const char *chipdb_blob_25k; +extern const char *chipdb_blob_45k; +extern const char *chipdb_blob_85k; #else -extern const char chipdb_blob_384[]; -extern const char chipdb_blob_1k[]; -extern const char chipdb_blob_5k[]; -extern const char chipdb_blob_8k[]; +extern const char chipdb_blob_25k[]; +extern const char chipdb_blob_45k[]; +extern const char chipdb_blob_85k[]; #endif /************************ End of chipdb section. ************************/ @@ -126,7 +125,8 @@ struct BelIterator BelIterator operator++() { cursor_index++; - while (cursor_index >= ci->locations[ci->location_type[cursor_tile]]->num_bels) { + while (cursor_tile < chip->num_tiles && + cursor_index >= chip->locations[chip->location_type[cursor_tile]].num_bels) { cursor_index = 0; cursor_tile++; } @@ -135,7 +135,7 @@ struct BelIterator BelIterator operator++(int) { BelIterator prior(*this); - cursor++; + ++(*this); return prior; } @@ -171,7 +171,7 @@ struct BelRange struct BelPinIterator { const BelPortPOD *ptr = nullptr; - const Location wire_loc; + Location wire_loc; void operator++() { ptr++; } bool operator!=(const BelPinIterator &other) const { return ptr != other.ptr; } @@ -203,7 +203,8 @@ struct WireIterator WireIterator operator++() { cursor_index++; - while (cursor_index >= ci->locations[ci->location_type[cursor_tile]]->num_wires) { + while (cursor_tile < chip->num_tiles && + cursor_index >= chip->locations[chip->location_type[cursor_tile]].num_wires) { cursor_index = 0; cursor_tile++; } @@ -212,7 +213,7 @@ struct WireIterator WireIterator operator++(int) { WireIterator prior(*this); - cursor++; + ++(*this); return prior; } @@ -254,7 +255,8 @@ struct AllPipIterator AllPipIterator operator++() { cursor_index++; - while (cursor_index >= ci->locations[ci->location_type[cursor_tile]]->num_pips) { + while (cursor_tile < chip->num_tiles && + cursor_index >= chip->locations[chip->location_type[cursor_tile]].num_pips) { cursor_index = 0; cursor_tile++; } @@ -262,8 +264,8 @@ struct AllPipIterator } AllPipIterator operator++(int) { - WireIterator prior(*this); - cursor++; + AllPipIterator prior(*this); + ++(*this); return prior; } @@ -309,7 +311,7 @@ struct PipIterator { PipId ret; ret.index = cursor->index; - ret.location = wire_loc + cursor->location; + ret.location = wire_loc + cursor->rel_loc; return ret; } }; @@ -337,7 +339,6 @@ struct ArchArgs struct Arch : BaseCtx { const ChipInfoPOD *chip_info; - const PackageInfoPOD *package_info; mutable std::unordered_map bel_by_name; mutable std::unordered_map wire_by_name; @@ -366,10 +367,15 @@ struct Arch : BaseCtx BelId getBelByName(IdString name) const; + template const LocationTypePOD *locInfo(Id &id) const + { + return &(chip_info->locations[chip_info->location_type[id.location.y * chip_info->width + id.location.x]]); + } + IdString getBelName(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return id(chip_info->bel_data[bel.index].name.get()); + return id(locInfo(bel)->bel_data[bel.index].name.get()); } uint32_t getBelChecksum(BelId bel) const { return bel.index; } @@ -386,35 +392,46 @@ struct Arch : BaseCtx void unbindBel(BelId bel) { NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); - cells[bel_to_cell[bel.index]]->bel = BelId(); - cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; - bel_to_cell[bel.index] = IdString(); + NPNR_ASSERT(bel_to_cell[bel] != IdString()); + cells[bel_to_cell[bel]]->bel = BelId(); + cells[bel_to_cell[bel]]->belStrength = STRENGTH_NONE; + bel_to_cell[bel] = IdString(); } bool checkBelAvail(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index] == IdString(); + return bel_to_cell.find(bel) == bel_to_cell.end() || bel_to_cell.at(bel) == IdString(); } IdString getBoundBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return bel_to_cell.at(bel); + if (bel_to_cell.find(bel) == bel_to_cell.end()) + return IdString(); + else + return bel_to_cell.at(bel); } IdString getConflictingBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return bel_to_cell.at(bel); + if (bel_to_cell.find(bel) == bel_to_cell.end()) + return IdString(); + else + return bel_to_cell.at(bel); } BelRange getBels() const { BelRange range; - range.b.cursor = 0; - range.e.cursor = chip_info->num_bels; + range.b.cursor_tile = 0; + range.b.cursor_index = -1; + range.b.chip = chip_info; + ++range.b; //-1 and then ++ deals with the case of no Bels in the first tile + range.e.cursor_tile = chip_info->width * chip_info->height; + range.e.cursor_index = 0; + range.e.chip = chip_info; return range; } @@ -437,7 +454,7 @@ struct Arch : BaseCtx BelType getBelType(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return chip_info->bel_data[bel.index].type; + return locInfo(bel)->bel_data[bel.index].type; } WireId getWireBelPin(BelId bel, PortPin pin) const; @@ -447,9 +464,10 @@ struct Arch : BaseCtx BelPin ret; NPNR_ASSERT(wire != WireId()); - if (chip_info->wire_data[wire.index].bel_uphill.bel_index >= 0) { - ret.bel.index = chip_info->wire_data[wire.index].bel_uphill.bel_index; - ret.pin = chip_info->wire_data[wire.index].bel_uphill.port; + if (locInfo(wire)->wire_data[wire.index].bel_uphill.bel_index >= 0) { + ret.bel.index = locInfo(wire)->wire_data[wire.index].bel_uphill.bel_index; + ret.bel.location = wire.location + locInfo(wire)->wire_data[wire.index].bel_uphill.rel_bel_loc; + ret.pin = locInfo(wire)->wire_data[wire.index].bel_uphill.port; } return ret; @@ -459,8 +477,10 @@ struct Arch : BaseCtx { BelPinRange range; NPNR_ASSERT(wire != WireId()); - range.b.ptr = chip_info->wire_data[wire.index].bels_downhill.get(); - range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bels_downhill; + range.b.ptr = locInfo(wire)->wire_data[wire.index].bels_downhill.get(); + range.b.wire_loc = wire.location; + range.e.ptr = range.b.ptr + locInfo(wire)->wire_data[wire.index].num_bels_downhill; + range.e.wire_loc = wire.location; return range; } @@ -471,7 +491,7 @@ struct Arch : BaseCtx IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return id(chip_info->wire_data[wire.index].name.get()); + return id(locInfo(wire)->wire_data[wire.index].name.get()); } uint32_t getWireChecksum(WireId wire) const { return wire.index; } @@ -479,8 +499,8 @@ struct Arch : BaseCtx void bindWire(WireId wire, IdString net, PlaceStrength strength) { NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] == IdString()); - wire_to_net[wire.index] = net; + NPNR_ASSERT(wire_to_net[wire] == IdString()); + wire_to_net[wire] = net; nets[net]->wires[wire].pip = PipId(); nets[net]->wires[wire].strength = strength; } @@ -488,45 +508,55 @@ struct Arch : BaseCtx void unbindWire(WireId wire) { NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] != IdString()); + NPNR_ASSERT(wire_to_net[wire] != IdString()); - auto &net_wires = nets[wire_to_net[wire.index]]->wires; + auto &net_wires = nets[wire_to_net[wire]]->wires; auto it = net_wires.find(wire); NPNR_ASSERT(it != net_wires.end()); auto pip = it->second.pip; if (pip != PipId()) { - pip_to_net[pip.index] = IdString(); - switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + pip_to_net[pip] = IdString(); } net_wires.erase(it); - wire_to_net[wire.index] = IdString(); + wire_to_net[wire] = IdString(); } bool checkWireAvail(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index] == IdString(); + return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == IdString(); } IdString getBoundWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; + if (wire_to_net.find(wire) == wire_to_net.end()) + return IdString(); + else + return wire_to_net.at(wire); } IdString getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; + if (wire_to_net.find(wire) == wire_to_net.end()) + return IdString(); + else + return wire_to_net.at(wire); } WireRange getWires() const { WireRange range; - range.b.cursor = 0; - range.e.cursor = chip_info->num_wires; + range.b.cursor_tile = 0; + range.b.cursor_index = -1; + range.b.chip = chip_info; + ++range.b; //-1 and then ++ deals with the case of no wries in the first tile + range.e.cursor_tile = chip_info->width * chip_info->height; + range.e.cursor_index = 0; + range.e.chip = chip_info; return range; } @@ -540,16 +570,15 @@ struct Arch : BaseCtx void bindPip(PipId pip, IdString net, PlaceStrength strength) { NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip.index] == IdString()); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); + NPNR_ASSERT(pip_to_net[pip] == IdString()); - pip_to_net[pip.index] = net; - switches_locked[chip_info->pip_data[pip.index].switch_index] = net; + pip_to_net[pip] = net; WireId dst; - dst.index = chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst.index] == IdString()); - wire_to_net[dst.index] = net; + dst.index = locInfo(pip)->pip_data[pip.index].dst_idx; + dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc; + NPNR_ASSERT(wire_to_net[dst] == IdString()); + wire_to_net[dst] = net; nets[net]->wires[dst].pip = pip; nets[net]->wires[dst].strength = strength; } @@ -557,42 +586,52 @@ struct Arch : BaseCtx void unbindPip(PipId pip) { NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip.index] != IdString()); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); + NPNR_ASSERT(pip_to_net[pip] != IdString()); WireId dst; - dst.index = chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst.index] != IdString()); - wire_to_net[dst.index] = IdString(); - nets[pip_to_net[pip.index]]->wires.erase(dst); + dst.index = locInfo(pip)->pip_data[pip.index].dst_idx; + dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc; + NPNR_ASSERT(wire_to_net[dst] != IdString()); + wire_to_net[dst] = IdString(); + nets[pip_to_net[pip]]->wires.erase(dst); - pip_to_net[pip.index] = IdString(); - switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + pip_to_net[pip] = IdString(); } bool checkPipAvail(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); + return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == IdString(); } IdString getBoundPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return pip_to_net[pip.index]; + if (pip_to_net.find(pip) == pip_to_net.end()) + return IdString(); + else + return pip_to_net.at(pip); } IdString getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index]; + if (pip_to_net.find(pip) == pip_to_net.end()) + return IdString(); + else + return pip_to_net.at(pip); } AllPipRange getPips() const { AllPipRange range; - range.b.cursor = 0; - range.e.cursor = chip_info->num_pips; + range.b.cursor_tile = 0; + range.b.cursor_index = -1; + range.b.chip = chip_info; + ++range.b; //-1 and then ++ deals with the case of no wries in the first tile + range.e.cursor_tile = chip_info->width * chip_info->height; + range.e.cursor_index = 0; + range.e.chip = chip_info; return range; } @@ -600,7 +639,8 @@ struct Arch : BaseCtx { WireId wire; NPNR_ASSERT(pip != PipId()); - wire.index = chip_info->pip_data[pip.index].src; + wire.index = locInfo(pip)->pip_data[pip.index].src_idx; + wire.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_src_loc; return wire; } @@ -608,7 +648,8 @@ struct Arch : BaseCtx { WireId wire; NPNR_ASSERT(pip != PipId()); - wire.index = chip_info->pip_data[pip.index].dst; + wire.index = locInfo(pip)->pip_data[pip.index].dst_idx; + wire.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc; return wire; } @@ -616,7 +657,7 @@ struct Arch : BaseCtx { DelayInfo delay; NPNR_ASSERT(pip != PipId()); - delay.delay = chip_info->pip_data[pip.index].delay; + delay.delay = locInfo(pip)->pip_data[pip.index].delay; return delay; } @@ -624,8 +665,8 @@ struct Arch : BaseCtx { PipRange range; NPNR_ASSERT(wire != WireId()); - range.b.cursor = chip_info->wire_data[wire.index].pips_downhill.get(); - range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_downhill; + range.b.cursor = locInfo(wire)->wire_data[wire.index].pips_downhill.get(); + range.e.cursor = range.b.cursor + locInfo(wire)->wire_data[wire.index].num_downhill; return range; } @@ -633,8 +674,8 @@ struct Arch : BaseCtx { PipRange range; NPNR_ASSERT(wire != WireId()); - range.b.cursor = chip_info->wire_data[wire.index].pips_uphill.get(); - range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_uphill; + range.b.cursor = locInfo(wire)->wire_data[wire.index].pips_uphill.get(); + range.e.cursor = range.b.cursor + locInfo(wire)->wire_data[wire.index].num_uphill; return range; } diff --git a/ecp5/arch_pybindings.cc b/ecp5/arch_pybindings.cc new file mode 100644 index 00000000..8310c3a1 --- /dev/null +++ b/ecp5/arch_pybindings.cc @@ -0,0 +1,32 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah + * + * 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. + * + */ + +#ifndef NO_PYTHON + +#include "nextpnr.h" +#include "pybindings.h" + +NEXTPNR_NAMESPACE_BEGIN + +void arch_wrap_python() {} + +NEXTPNR_NAMESPACE_END + +#endif diff --git a/ecp5/arch_pybindings.h b/ecp5/arch_pybindings.h new file mode 100644 index 00000000..f7f07529 --- /dev/null +++ b/ecp5/arch_pybindings.h @@ -0,0 +1,31 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah + * + * 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. + * + */ +#ifndef ARCH_PYBINDINGS_H +#define ARCH_PYBINDINGS_H +#ifndef NO_PYTHON + +#include "nextpnr.h" +#include "pybindings.h" + +NEXTPNR_NAMESPACE_BEGIN + +NEXTPNR_NAMESPACE_END +#endif +#endif diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index 0af48753..f913e445 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -60,13 +60,21 @@ enum PortPin : int32_t PIN_MAXIDX }; -NPNR_PACKED_STRUCT(struct Location { +NPNR_PACKED_STRUCT(struct LocationPOD { int16_t x, y; }); + +struct Location +{ int16_t x = -1, y = -1; + Location() : x(-1), y(-1){}; + Location(int16_t x, int16_t y) : x(x), y(y){}; + Location(const LocationPOD &pod) : x(pod.x), y(pod.y){}; + Location(const Location &loc) : x(loc.x), y(loc.y){}; + bool operator==(const Location &other) const { return x == other.x && y == other.y; } bool operator!=(const Location &other) const { return x != other.x || y == other.y; } -}); +}; -Location operator+(const Location &a, const Location &b) { return Location{a.x + b.x, a.y + b.y};} +Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); } struct BelId { @@ -91,29 +99,51 @@ struct PipId Location location; int32_t index = -1; - bool operator==(const WireId &other) const { return index == other.index && location == other.location; } - bool operator!=(const WireId &other) const { return index != other.index || location != other.location; } + bool operator==(const PipId &other) const { return index == other.index && location == other.location; } + bool operator!=(const PipId &other) const { return index != other.index || location != other.location; } }; NEXTPNR_NAMESPACE_END namespace std { +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX Location &loc) const noexcept + { + std::size_t seed = std::hash()(loc.x); + seed ^= std::hash()(loc.y) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; + template <> struct hash { - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept { return hash()(bel.index); } + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept + { + std::size_t seed = std::hash()(bel.location); + seed ^= std::hash()(bel.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } }; template <> struct hash { std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept { - return hash()(wire.index); + std::size_t seed = std::hash()(wire.location); + seed ^= std::hash()(wire.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; } }; template <> struct hash { - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept { return hash()(pip.index); } + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept + { + std::size_t seed = std::hash()(pip.location); + seed ^= std::hash()(pip.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } }; template <> struct hash : hash diff --git a/ecp5/main.cc b/ecp5/main.cc new file mode 100644 index 00000000..d025d8d4 --- /dev/null +++ b/ecp5/main.cc @@ -0,0 +1,139 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * 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. + * + */ + +#ifdef MAIN_EXECUTABLE + +#ifndef NO_GUI +#include +#include "application.h" +#include "mainwindow.h" +#endif +#ifndef NO_PYTHON +#include "pybindings.h" +#endif +#include +#include +#include +#include "log.h" +#include "nextpnr.h" +#include "version.h" + +USING_NEXTPNR_NAMESPACE + +int main(int argc, char *argv[]) +{ + try { + + namespace po = boost::program_options; + int rc = 0; + + log_files.push_back(stdout); + + po::options_description options("Allowed options"); + options.add_options()("help,h", "show help"); + options.add_options()("verbose,v", "verbose output"); + options.add_options()("force,f", "keep running after errors"); +#ifndef NO_GUI + options.add_options()("gui", "start gui"); +#endif + + po::positional_options_description pos; +#ifndef NO_PYTHON + options.add_options()("run", po::value>(), "python file to execute"); + pos.add("run", -1); +#endif + options.add_options()("version,V", "show version"); + + po::variables_map vm; + try { + po::parsed_options parsed = po::command_line_parser(argc, argv).options(options).positional(pos).run(); + + po::store(parsed, vm); + + po::notify(vm); + } + + catch (std::exception &e) { + std::cout << e.what() << "\n"; + return 1; + } + + if (vm.count("help") || argc == 1) { + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << "\n"; + std::cout << options << "\n"; + return argc != 1; + } + + if (vm.count("version")) { + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; + return 1; + } + + Context ctx(ArchArgs{}); + + if (vm.count("verbose")) { + ctx.verbose = true; + } + + if (vm.count("force")) { + ctx.force = true; + } + + if (vm.count("seed")) { + ctx.rngseed(vm["seed"].as()); + } + +#ifndef NO_PYTHON + if (vm.count("run")) { + init_python(argv[0], true); + python_export_global("ctx", ctx); + + std::vector files = vm["run"].as>(); + for (auto filename : files) + execute_python_file(filename.c_str()); + + deinit_python(); + } +#endif + +#ifndef NO_GUI + if (vm.count("gui")) { + Application a(argc, argv); + MainWindow w; + w.show(); + + rc = a.exec(); + } +#endif + return rc; + } catch (log_execution_error_exception) { +#if defined(_MSC_VER) + _exit(EXIT_FAILURE); +#else + _Exit(EXIT_FAILURE); +#endif + } +} + +#endif -- cgit v1.2.3 From 074df03c593f03ba93ac19804c551e22a404d8d6 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 6 Jul 2018 12:20:15 +0200 Subject: ecp5: Add stub for UI Signed-off-by: David Shah --- gui/ecp5/mainwindow.cc | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ gui/ecp5/mainwindow.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ gui/ecp5/nextpnr.qrc | 2 ++ 3 files changed, 98 insertions(+) create mode 100644 gui/ecp5/mainwindow.cc create mode 100644 gui/ecp5/mainwindow.h create mode 100644 gui/ecp5/nextpnr.qrc diff --git a/gui/ecp5/mainwindow.cc b/gui/ecp5/mainwindow.cc new file mode 100644 index 00000000..6cc3dd15 --- /dev/null +++ b/gui/ecp5/mainwindow.cc @@ -0,0 +1,50 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Miodrag Milanovic + * + * 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 "mainwindow.h" + +static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } + +NEXTPNR_NAMESPACE_BEGIN + +MainWindow::MainWindow(QWidget *parent) : BaseMainWindow(parent) +{ + initMainResource(); + + std::string title = "nextpnr-ecp5 - [EMPTY]"; + setWindowTitle(title.c_str()); + + createMenu(); +} + +MainWindow::~MainWindow() {} + +void MainWindow::createMenu() +{ + QMenu *menu_Custom = new QMenu("&Generic", menuBar); + menuBar->addAction(menu_Custom->menuAction()); +} + +void MainWindow::new_proj() {} + +void MainWindow::open_proj() {} + +bool MainWindow::save_proj() { return false; } + +NEXTPNR_NAMESPACE_END diff --git a/gui/ecp5/mainwindow.h b/gui/ecp5/mainwindow.h new file mode 100644 index 00000000..fd9812cd --- /dev/null +++ b/gui/ecp5/mainwindow.h @@ -0,0 +1,46 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Miodrag Milanovic + * + * 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. + * + */ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "../basewindow.h" + +NEXTPNR_NAMESPACE_BEGIN + +class MainWindow : public BaseMainWindow +{ + Q_OBJECT + + public: + explicit MainWindow(QWidget *parent = 0); + virtual ~MainWindow(); + + public: + void createMenu(); + + protected Q_SLOTS: + virtual void new_proj(); + virtual void open_proj(); + virtual bool save_proj(); +}; + +NEXTPNR_NAMESPACE_END + +#endif // MAINWINDOW_H diff --git a/gui/ecp5/nextpnr.qrc b/gui/ecp5/nextpnr.qrc new file mode 100644 index 00000000..03585ec0 --- /dev/null +++ b/gui/ecp5/nextpnr.qrc @@ -0,0 +1,2 @@ + + -- cgit v1.2.3 From 83303bae5aec42ef411478dc2841b28aeecfd5e0 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 6 Jul 2018 14:02:37 +0200 Subject: ecp5: Implementing (at least stubs) most of arch.cc Signed-off-by: David Shah --- ecp5/arch.cc | 289 +++++++++++++++++------------------------------- ecp5/arch.h | 24 +++- ecp5/arch_pybindings.h | 44 ++++++++ ecp5/archdefs.h | 2 +- ecp5/place_legaliser.cc | 26 +++++ ecp5/place_legaliser.h | 31 ++++++ 6 files changed, 225 insertions(+), 191 deletions(-) create mode 100644 ecp5/place_legaliser.cc create mode 100644 ecp5/place_legaliser.h diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 41c73cf8..fe10d415 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,80 +20,41 @@ #include #include +#include #include "log.h" #include "nextpnr.h" #include "util.h" + NEXTPNR_NAMESPACE_BEGIN +static std::tuple split_identifier_name(const std::string &name) +{ + size_t first_slash = name.find('/'); + NPNR_ASSERT(first_slash != std::string::npos); + size_t second_slash = name.find('/', first_slash + 1); + NPNR_ASSERT(second_slash != std::string::npos); + return std::make_tuple(std::stoi(name.substr(1, first_slash)), + std::stoi(name.substr(first_slash + 2, second_slash - first_slash)), + name.substr(second_slash + 1)); +}; + // ----------------------------------------------------------------------- IdString Arch::belTypeToId(BelType type) const { - if (type == TYPE_ICESTORM_LC) - return id("ICESTORM_LC"); - if (type == TYPE_ICESTORM_RAM) - return id("ICESTORM_RAM"); - if (type == TYPE_SB_IO) - return id("SB_IO"); - if (type == TYPE_SB_GB) - return id("SB_GB"); - if (type == TYPE_ICESTORM_PLL) - return id("ICESTORM_PLL"); - if (type == TYPE_SB_WARMBOOT) - return id("SB_WARMBOOT"); - if (type == TYPE_SB_MAC16) - return id("SB_MAC16"); - if (type == TYPE_ICESTORM_HFOSC) - return id("ICESTORM_HFOSC"); - if (type == TYPE_ICESTORM_LFOSC) - return id("ICESTORM_LFOSC"); - if (type == TYPE_SB_I2C) - return id("SB_I2C"); - if (type == TYPE_SB_SPI) - return id("SB_SPI"); - if (type == TYPE_IO_I3C) - return id("IO_I3C"); - if (type == TYPE_SB_LEDDA_IP) - return id("SB_LEDDA_IP"); - if (type == TYPE_SB_RGBA_DRV) - return id("SB_RGBA_DRV"); - if (type == TYPE_ICESTORM_SPRAM) - return id("ICESTORM_SPRAM"); + if (type == TYPE_TRELLIS_SLICE) + return id("TRELLIS_SLICE"); + if (type == TYPE_TRELLIS_IO) + return id("TRELLIS_IO"); return IdString(); } BelType Arch::belTypeFromId(IdString type) const { - if (type == id("ICESTORM_LC")) - return TYPE_ICESTORM_LC; - if (type == id("ICESTORM_RAM")) - return TYPE_ICESTORM_RAM; - if (type == id("SB_IO")) - return TYPE_SB_IO; - if (type == id("SB_GB")) - return TYPE_SB_GB; - if (type == id("ICESTORM_PLL")) - return TYPE_ICESTORM_PLL; - if (type == id("SB_WARMBOOT")) - return TYPE_SB_WARMBOOT; - if (type == id("SB_MAC16")) - return TYPE_SB_MAC16; - if (type == id("ICESTORM_HFOSC")) - return TYPE_ICESTORM_HFOSC; - if (type == id("ICESTORM_LFOSC")) - return TYPE_ICESTORM_LFOSC; - if (type == id("SB_I2C")) - return TYPE_SB_I2C; - if (type == id("SB_SPI")) - return TYPE_SB_SPI; - if (type == id("IO_I3C")) - return TYPE_IO_I3C; - if (type == id("SB_LEDDA_IP")) - return TYPE_SB_LEDDA_IP; - if (type == id("SB_RGBA_DRV")) - return TYPE_SB_RGBA_DRV; - if (type == id("ICESTORM_SPRAM")) - return TYPE_ICESTORM_SPRAM; + if (type == id("TRELLIS_SLICE")) + return TYPE_TRELLIS_SLICE; + if (type == id("TRELLIS_IO")) + return TYPE_TRELLIS_IO; return TYPE_NONE; } @@ -101,7 +63,9 @@ BelType Arch::belTypeFromId(IdString type) const void IdString::initialize_arch(const BaseCtx *ctx) { #define X(t) initialize_add(ctx, #t, PIN_##t); + #include "portpins.inc" + #undef X } @@ -134,102 +98,43 @@ Arch::Arch(ArchArgs args) : args(args) load_chipdb(); #endif -#ifdef ICE40_HX1K_ONLY - if (args.type == ArchArgs::HX1K) { - chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_1k)); + if (args.type == ArchArgs::LFE5U_25F) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_25k)); + } else if (args.type == ArchArgs::LFE5U_45F) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_45k)); + } else if (args.type == ArchArgs::LFE5U_85F) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_85k)); } else { - log_error("Unsupported iCE40 chip type.\n"); - } -#else - if (args.type == ArchArgs::LP384) { - chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_384)); - } else if (args.type == ArchArgs::LP1K || args.type == ArchArgs::HX1K) { - chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_1k)); - } else if (args.type == ArchArgs::UP5K) { - chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_5k)); - } else if (args.type == ArchArgs::LP8K || args.type == ArchArgs::HX8K) { - chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_8k)); - } else { - log_error("Unsupported iCE40 chip type.\n"); - } -#endif - - package_info = nullptr; - for (int i = 0; i < chip_info->num_packages; i++) { - if (chip_info->packages_data[i].name.get() == args.package) { - package_info = &(chip_info->packages_data[i]); - break; - } + log_error("Unsupported ECP5 chip type.\n"); } - if (package_info == nullptr) - log_error("Unsupported package '%s'.\n", args.package.c_str()); - - bel_to_cell.resize(chip_info->num_bels); - wire_to_net.resize(chip_info->num_wires); - pip_to_net.resize(chip_info->num_pips); - switches_locked.resize(chip_info->num_switches); - - // Initialise regularly used IDStrings for performance - id_glb_buf_out = id("GLOBAL_BUFFER_OUTPUT"); - id_icestorm_lc = id("ICESTORM_LC"); - id_sb_io = id("SB_IO"); - id_sb_gb = id("SB_GB"); - id_cen = id("CEN"); - id_clk = id("CLK"); - id_sr = id("SR"); - id_i0 = id("I0"); - id_i1 = id("I1"); - id_i2 = id("I2"); - id_i3 = id("I3"); - id_dff_en = id("DFF_ENABLE"); - id_neg_clk = id("NEG_CLK"); } // ----------------------------------------------------------------------- std::string Arch::getChipName() { -#ifdef ICE40_HX1K_ONLY - if (args.type == ArchArgs::HX1K) { - return "Lattice LP1K"; - } else { - log_error("Unsupported iCE40 chip type.\n"); - } -#else - if (args.type == ArchArgs::LP384) { - return "Lattice LP384"; - } else if (args.type == ArchArgs::LP1K) { - return "Lattice LP1K"; - } else if (args.type == ArchArgs::HX1K) { - return "Lattice HX1K"; - } else if (args.type == ArchArgs::UP5K) { - return "Lattice UP5K"; - } else if (args.type == ArchArgs::LP8K) { - return "Lattice LP8K"; - } else if (args.type == ArchArgs::HX8K) { - return "Lattice HX8K"; + + if (args.type == ArchArgs::LFE5U_25F) { + return "Lattice LFE5U-25F"; + } else if (args.type == ArchArgs::LFE5U_45F) { + return "Lattice LFE5U-45F"; + } else if (args.type == ArchArgs::LFE5U_85F) { + return "Lattice LFE5U-85F"; } else { log_error("Unknown chip\n"); } -#endif } // ----------------------------------------------------------------------- IdString Arch::archArgsToId(ArchArgs args) const { - if (args.type == ArchArgs::LP384) - return id("lp384"); - if (args.type == ArchArgs::LP1K) - return id("lp1k"); - if (args.type == ArchArgs::HX1K) - return id("hx1k"); - if (args.type == ArchArgs::UP5K) - return id("up5k"); - if (args.type == ArchArgs::LP8K) - return id("lp8k"); - if (args.type == ArchArgs::HX8K) - return id("hx8k"); + if (args.type == ArchArgs::LFE5U_25F) + return id("lfe5u_25f"); + if (args.type == ArchArgs::LFE5U_45F) + return id("lfe5u_45f"); + if (args.type == ArchArgs::LFE5U_85F) + return id("lfe5u_85f"); return IdString(); } @@ -238,16 +143,23 @@ IdString Arch::archArgsToId(ArchArgs args) const BelId Arch::getBelByName(IdString name) const { BelId ret; - - if (bel_by_name.empty()) { - for (int i = 0; i < chip_info->num_bels; i++) - bel_by_name[id(chip_info->bel_data[i].name.get())] = i; - } - auto it = bel_by_name.find(name); if (it != bel_by_name.end()) - ret.index = it->second; - + return it->second; + + Location loc; + std::string basename; + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + ret.location = loc; + const LocationTypePOD *loci = locInfo(ret); + for (int i = 0; i < loci->num_bels; i++) { + if (std::strcmp(loci->bel_data[i].name.get(), basename.c_str()) == 0) { + ret.index = i; + break; + } + } + if (ret.index >= 0) + bel_by_name[name] = ret; return ret; } @@ -255,17 +167,10 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const { BelRange br; NPNR_ASSERT(bel != BelId()); - // This requires Bels at the same tile are consecutive - int x = chip_info->bel_data[bel.index].x; - int y = chip_info->bel_data[bel.index].y; - int start = bel.index, end = bel.index; - while (start >= 0 && chip_info->bel_data[start].x == x && chip_info->bel_data[start].y == y) - start--; - start++; - br.b.cursor = start; - while (end < chip_info->num_bels && chip_info->bel_data[end].x == x && chip_info->bel_data[end].y == y) - end++; - br.e.cursor = end; + br.b.cursor_tile = bel.location.y * chip_info->width + bel.location.x; + br.e.cursor_tile = bel.location.y * chip_info->width + bel.location.x; + br.b.cursor_index = 0; + br.e.cursor_index = locInfo(bel)->num_bels; return br; } @@ -275,11 +180,11 @@ WireId Arch::getWireBelPin(BelId bel, PortPin pin) const NPNR_ASSERT(bel != BelId()); - int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); - + int num_bel_wires = locInfo(bel)->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = locInfo(bel)->bel_data[bel.index].bel_wires.get(); for (int i = 0; i < num_bel_wires; i++) if (bel_wires[i].port == pin) { + ret.location = bel.location + bel_wires[i].rel_wire_loc; ret.index = bel_wires[i].wire_index; break; } @@ -292,16 +197,23 @@ WireId Arch::getWireBelPin(BelId bel, PortPin pin) const WireId Arch::getWireByName(IdString name) const { WireId ret; - - if (wire_by_name.empty()) { - for (int i = 0; i < chip_info->num_wires; i++) - wire_by_name[id(chip_info->wire_data[i].name.get())] = i; - } - auto it = wire_by_name.find(name); if (it != wire_by_name.end()) - ret.index = it->second; - + return it->second; + + Location loc; + std::string basename; + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + ret.location = loc; + const LocationTypePOD *loci = locInfo(ret); + for (int i = 0; i < loci->num_wires; i++) { + if (std::strcmp(loci->wire_data[i].name.get(), basename.c_str()) == 0) { + ret.index = i; + break; + } + } + if (ret.index >= 0) + wire_by_name[name] = ret; return ret; } @@ -309,34 +221,35 @@ WireId Arch::getWireByName(IdString name) const PipId Arch::getPipByName(IdString name) const { - PipId ret; - - if (pip_by_name.empty()) { - for (int i = 0; i < chip_info->num_pips; i++) { - PipId pip; - pip.index = i; - pip_by_name[getPipName(pip)] = i; - } - } - auto it = pip_by_name.find(name); if (it != pip_by_name.end()) - ret.index = it->second; + return it->second; - return ret; + PipId ret; + Location loc; + std::string basename; + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + const LocationTypePOD *loci = locInfo(ret); + for (int i = 0; i < loci->num_pips; i++) { + PipId curr; + curr.location = loc; + curr.index = i; + pip_by_name[getPipName(curr)] = curr; + } + return pip_by_name[name]; } IdString Arch::getPipName(PipId pip) const { NPNR_ASSERT(pip != PipId()); - int x = chip_info->pip_data[pip.index].x; - int y = chip_info->pip_data[pip.index].y; + int x = pip.location.x; + int y = pip.location.y; - std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get(); + std::string src_name = getWireName(getPipSrcWire(pip)).str(this); std::replace(src_name.begin(), src_name.end(), '/', '.'); - std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get(); + std::string dst_name = getWireName(getPipDstWire(pip)).str(this); std::replace(dst_name.begin(), dst_name.end(), '/', '.'); return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); @@ -383,4 +296,10 @@ std::vector Arch::getPipGraphics(PipId pip) const return ret; }; +// ----------------------------------------------------------------------- + +bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; } + +bool Arch::isBelLocationValid(BelId bel) const { return true; } + NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch.h b/ecp5/arch.h index 85a3e44c..91e9fdcd 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,6 +22,8 @@ #error Include "arch.h" via "nextpnr.h" only. #endif +#include + NEXTPNR_NAMESPACE_BEGIN /**** Everything in this section must be kept in sync with chipdb.py ****/ @@ -340,9 +343,9 @@ struct Arch : BaseCtx { const ChipInfoPOD *chip_info; - mutable std::unordered_map bel_by_name; - mutable std::unordered_map wire_by_name; - mutable std::unordered_map pip_by_name; + mutable std::unordered_map bel_by_name; + mutable std::unordered_map wire_by_name; + mutable std::unordered_map pip_by_name; std::unordered_map bel_to_cell; std::unordered_map wire_to_net; @@ -375,7 +378,9 @@ struct Arch : BaseCtx IdString getBelName(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return id(locInfo(bel)->bel_data[bel.index].name.get()); + std::stringstream name; + name << "X" << bel.location.x << "/Y" << bel.location.y << "/" << locInfo(bel)->bel_data[bel.index].name.get(); + return id(name.str()); } uint32_t getBelChecksum(BelId bel) const { return bel.index; } @@ -491,7 +496,11 @@ struct Arch : BaseCtx IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return id(locInfo(wire)->wire_data[wire.index].name.get()); + + std::stringstream name; + name << "X" << wire.location.x << "/Y" << wire.location.y << "/" + << locInfo(wire)->wire_data[wire.index].name.get(); + return id(name.str()); } uint32_t getWireChecksum(WireId wire) const { return wire.index; } @@ -724,6 +733,11 @@ struct Arch : BaseCtx bool isClockPort(const CellInfo *cell, IdString port) const; // Return true if a port is a net bool isGlobalNet(const NetInfo *net) const; + + // ------------------------------------------------- + // Placement validity checks + bool isValidBelForCell(CellInfo *cell, BelId bel) const; + bool isBelLocationValid(BelId bel) const; }; NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch_pybindings.h b/ecp5/arch_pybindings.h index f7f07529..a5044f29 100644 --- a/ecp5/arch_pybindings.h +++ b/ecp5/arch_pybindings.h @@ -26,6 +26,50 @@ NEXTPNR_NAMESPACE_BEGIN +namespace PythonConversion { + +template <> struct string_converter +{ + BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); } + + std::string to_str(Context *ctx, BelId id) + { + if (id == BelId()) + throw bad_wrap(); + return ctx->getBelName(id).str(ctx); + } +}; + +template <> struct string_converter +{ + BelType from_str(Context *ctx, std::string name) { return ctx->belTypeFromId(ctx->id(name)); } + + std::string to_str(Context *ctx, BelType typ) { return ctx->belTypeToId(typ).str(ctx); } +}; + +template <> struct string_converter +{ + WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); } + + std::string to_str(Context *ctx, WireId id) { return ctx->getWireName(id).str(ctx); } +}; + +template <> struct string_converter +{ + PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(ctx->id(name)); } + + std::string to_str(Context *ctx, PipId id) { return ctx->getPipName(id).str(ctx); } +}; + +template <> struct string_converter +{ + PortPin from_str(Context *ctx, std::string name) { return ctx->portPinFromId(ctx->id(name)); } + + std::string to_str(Context *ctx, PortPin id) { return ctx->portPinToId(id).str(ctx); } +}; + +} // namespace PythonConversion + NEXTPNR_NAMESPACE_END #endif #endif diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index f913e445..b05ac22c 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -74,7 +74,7 @@ struct Location bool operator!=(const Location &other) const { return x != other.x || y == other.y; } }; -Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); } +inline Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); } struct BelId { diff --git a/ecp5/place_legaliser.cc b/ecp5/place_legaliser.cc new file mode 100644 index 00000000..0d23f15b --- /dev/null +++ b/ecp5/place_legaliser.cc @@ -0,0 +1,26 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 David Shah + * + * 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 "place_legaliser.h" + +NEXTPNR_NAMESPACE_BEGIN + +bool legalise_design(Context *ctx) { return true; } + +NEXTPNR_NAMESPACE_END diff --git a/ecp5/place_legaliser.h b/ecp5/place_legaliser.h new file mode 100644 index 00000000..5f4df6aa --- /dev/null +++ b/ecp5/place_legaliser.h @@ -0,0 +1,31 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 David Shah + * + * 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. + * + */ + +#ifndef PLACE_LEGALISER_H +#define PLACE_LEGALISER_H + +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +bool legalise_design(Context *ctx); + +NEXTPNR_NAMESPACE_END + +#endif -- cgit v1.2.3 From fdd13edff0b9c8263f251a3d2c2bbfeb31ad8bee Mon Sep 17 00:00:00 2001 From: David Shah Date: Sat, 7 Jul 2018 15:29:02 +0200 Subject: ecp5: Starting to develop a Trellis importer Signed-off-by: David Shah --- ecp5/.gitignore | 2 + ecp5/arch.h | 2 - ecp5/trellis_import.py | 120 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 ecp5/.gitignore create mode 100755 ecp5/trellis_import.py diff --git a/ecp5/.gitignore b/ecp5/.gitignore new file mode 100644 index 00000000..c20c2ab7 --- /dev/null +++ b/ecp5/.gitignore @@ -0,0 +1,2 @@ +__pycache__ + diff --git a/ecp5/arch.h b/ecp5/arch.h index 91e9fdcd..53385acf 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -57,8 +57,6 @@ NPNR_PACKED_STRUCT(struct BelInfoPOD { BelType type; int32_t num_bel_wires; RelPtr bel_wires; - int8_t x, y, z; - int8_t padding_0; }); NPNR_PACKED_STRUCT(struct BelPortPOD { diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py new file mode 100755 index 00000000..59027d8a --- /dev/null +++ b/ecp5/trellis_import.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +import pytrellis +import database + +location_types = dict() +type_at_location = dict() +tiletype_names = dict() + + +def is_global(loc): + return loc.x == -2 and loc.y == -2 + + +# Get the index for a tiletype +def get_tiletype_index(name): + if name in tiletype_names: + return tiletype_names[name] + idx = len(tiletype_names) + tiletype_names[name] = idx + return idx + + +loc_wire_indices = dict() +loc_wires = dict() + +# Import all wire names at all locations +def import_location_wires(rg, x, y): + loc_wire_indices[x, y] = dict() + loc_wires[x, y] = list() + rtile = rg.tiles[pytrellis.Location(x, y)] + for wire in rtile.wires: + name = rg.to_str(wire.key()) + idx = len(loc_wires[x, y]) + loc_wires[x, y].append(name) + loc_wire_indices[x, y][name] = idx + + +# Take a RoutingId from Trellis and make into a (relx, rely, name) tuple +def resolve_wirename(rg, rid, cur_x, cur_y): + if is_global(rid.loc): + return (cur_x, cur_y, rg.to_str(rid.id)) + else: + x = rid.loc.x + y = rid.loc.y + widx = loc_wire_indices[x, y][rg.to_str(rid.id)] + return (x - cur_x, y - cur_y, widx) + + +loc_arc_indices = dict() # Map RoutingId index to nextpnr index +loc_arcs = dict() + + +# Import all arc indices at a location +def index_location_arcs(rg, x, y): + loc_arc_indices[x, y] = dict() + loc_arcs[x, y] = list() + rtile = rg.tiles[pytrellis.Location(x, y)] + for arc in rtile.arcs: + idx = len(loc_arcs) + trid = arc.key() + loc_arcs[x, y].append(trid) + loc_arc_indices[x, y][trid] = idx + +# Import a location, deduplicating if appropriate +def import_location(rg, x, y): + rtile = rg.tiles[pytrellis.Location(x, y)] + arcs = [] # (src, dst, configurable, tiletype) + wires = [] # (name, uphill, downhill, belpin_uphill, belpins_downhill) + bels = [] # (name, (pin, wire)) + for name in loc_wires[x, y]: + w = rtile.wires[rg.ident(name)] + arcs_uphill = [] + arcs_downhill = [] + for uh in w.uphill: + arcidx = loc_arc_indices[uh.loc.x, uh.loc.y][uh.id] + arcs_uphill.append((uh.loc.x - x, uh.loc.y - y, arcidx)) + for dh in w.downhill: + arcidx = loc_arc_indices[dh.loc.x, dh.loc.y][dh.id] + arcs_downhill.append((dh.loc.x - x, dh.loc.y - y, arcidx)) + # TODO: Bel pins + wires.append((name, tuple(arcs_downhill), tuple(arcs_uphill), tuple(), tuple())) + + for arcidx in loc_arcs[x, y]: + a = rtile.arcs[arcidx] + source_wire = resolve_wirename(rg, a.source, x, y) + dest_wire = resolve_wirename(rg, a.sink, x, y) + arcs.append((source_wire, dest_wire, a.configurable, get_tiletype_index(rg.to_str(a.tiletype)))) + + tile_data = (tuple(wires), tuple(arcs), tuple(bels)) + if tile_data in location_types: + type_at_location[x, y] = location_types[tile_data] + else: + idx = len(location_types) + location_types[tile_data] = idx + type_at_location[x, y] = idx + +def main(): + pytrellis.load_database(database.get_db_root()) + print("Initialising chip...") + chip = pytrellis.Chip("LFE5U-45F") + print("Building routing graph...") + rg = chip.get_routing_graph() + max_row = chip.get_max_row() + max_col = chip.get_max_col() + print("Indexing wires...") + for y in range(0, max_row+1): + for x in range(0, max_col+1): + import_location_wires(rg, x, y) + print("Indexing arcs...") + for y in range(0, max_row+1): + for x in range(0, max_col+1): + index_location_arcs(rg, x, y) + print("Importing tiles...") + for y in range(0, max_row+1): + for x in range(0, max_col+1): + print(" At R{}C{}".format(y, x)) + import_location(rg, x, y) + +if __name__ == "__main__": + main() -- cgit v1.2.3 From 12b0f7f162b80a43fba81a0948b4ea7ef7b6b0c6 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sat, 7 Jul 2018 17:11:46 +0200 Subject: ecp5: Adding Bels to import script Signed-off-by: David Shah --- ecp5/trellis_import.py | 128 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 118 insertions(+), 10 deletions(-) diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index 59027d8a..2081cda9 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -23,16 +23,25 @@ def get_tiletype_index(name): loc_wire_indices = dict() loc_wires = dict() +loc_bels = dict() +wire_bel_pins_uphill = dict() +wire_bel_pins_downhill = dict() + + # Import all wire names at all locations def import_location_wires(rg, x, y): loc_wire_indices[x, y] = dict() loc_wires[x, y] = list() + wire_bel_pins_uphill[x, y] = list() + wire_bel_pins_downhill[x, y] = list() rtile = rg.tiles[pytrellis.Location(x, y)] for wire in rtile.wires: name = rg.to_str(wire.key()) idx = len(loc_wires[x, y]) loc_wires[x, y].append(name) loc_wire_indices[x, y][name] = idx + wire_bel_pins_uphill[x, y].append([]) + wire_bel_pins_downhill[x, y].append([]) # Take a RoutingId from Trellis and make into a (relx, rely, name) tuple @@ -61,24 +70,117 @@ def index_location_arcs(rg, x, y): loc_arcs[x, y].append(trid) loc_arc_indices[x, y][trid] = idx + +def add_bel_input(bel_x, bel_y, bel_idx, bel_pin, wire_x, wire_y, wire_name): + loc_bels[bel_x, bel_y][bel_idx][2].append((bel_pin, (wire_x, wire_y, loc_wire_indices[wire_x, wire_y][wire_name]))) + wire_bel_pins_downhill[wire_x, wire_y][loc_wire_indices[wire_x, wire_y][wire_name]].append(( + (bel_x, bel_y, bel_idx), bel_pin)) + + +def add_bel_output(bel_x, bel_y, bel_idx, bel_pin, wire_x, wire_y, wire_name): + loc_bels[bel_x, bel_y][bel_idx][2].append((bel_pin, (wire_x, wire_y, loc_wire_indices[wire_x, wire_y][wire_name]))) + wire_bel_pins_uphill[wire_x, wire_y][loc_wire_indices[wire_x, wire_y][wire_name]].append(( + (bel_x, bel_y, bel_idx), bel_pin)) + + +def add_slice(x, y, z): + idx = len(loc_bels[x, y]) + l = ("A", "B", "C", "D")[z] + name = "SLICE" + l + loc_bels[x, y].append((name, "SLICE", [])) + lc0 = z * 2 + lc1 = z * 2 + 1 + add_bel_input(x, y, idx, "A0", x, y, "A{}_SLICE".format(lc0)) + add_bel_input(x, y, idx, "B0", x, y, "B{}_SLICE".format(lc0)) + add_bel_input(x, y, idx, "C0", x, y, "C{}_SLICE".format(lc0)) + add_bel_input(x, y, idx, "D0", x, y, "D{}_SLICE".format(lc0)) + add_bel_input(x, y, idx, "M0", x, y, "M{}_SLICE".format(lc0)) + + add_bel_input(x, y, idx, "A1", x, y, "A{}_SLICE".format(lc1)) + add_bel_input(x, y, idx, "B1", x, y, "B{}_SLICE".format(lc1)) + add_bel_input(x, y, idx, "C1", x, y, "C{}_SLICE".format(lc1)) + add_bel_input(x, y, idx, "D1", x, y, "D{}_SLICE".format(lc1)) + add_bel_input(x, y, idx, "M1", x, y, "M{}_SLICE".format(lc1)) + + add_bel_input(x, y, idx, "FCI", x, y, "FCI{}_SLICE".format(l if z > 0 else "")) + add_bel_input(x, y, idx, "FXA", x, y, "FXA{}_SLICE".format(l)) + add_bel_input(x, y, idx, "FXB", x, y, "FXB{}_SLICE".format(l)) + + add_bel_input(x, y, idx, "CLK", x, y, "CLK{}_SLICE".format(z)) + add_bel_input(x, y, idx, "LSR", x, y, "LSR{}_SLICE".format(z)) + add_bel_input(x, y, idx, "CE", x, y, "CE{}_SLICE".format(z)) + + add_bel_output(x, y, idx, "F0", x, y, "F{}_SLICE".format(lc0)) + add_bel_output(x, y, idx, "Q0", x, y, "Q{}_SLICE".format(lc0)) + + add_bel_output(x, y, idx, "F1", x, y, "F{}_SLICE".format(lc1)) + add_bel_output(x, y, idx, "Q1", x, y, "Q{}_SLICE".format(lc1)) + + add_bel_output(x, y, idx, "FCO", x, y, "FCO{}_SLICE".format(l if z < 3 else "")) + + +def add_pio(x, y, z): + idx = len(loc_bels[x, y]) + l = ("A", "B", "C", "D")[z] + name = "PIO" + l + loc_bels[x, y].append((name, "PIO", [])) + add_bel_input(x, y, idx, "I", x, y, "PADDO{}_PIO".format(l)) + add_bel_input(x, y, idx, "T", x, y, "PADDT{}_PIO".format(l)) + add_bel_output(x, y, idx, "O", x, y, "JPADDI{}_PIO".format(l)) + + +def add_bels(chip, x, y): + loc_bels[x, y] = [] + tiles = chip.get_tiles_by_position(y, x) + num_slices = 0 + num_pios = 0 + for tile in tiles: + tt = tile.info.type + if tt == "PLC2": + num_slices = 4 + elif "PICL0" in tt or "PICR0" in tt: + num_pios = 4 + elif "PIOT0" in tt or "PIOB0" in tt: + num_pios = 2 + for i in range(num_slices): + add_slice(x, y, i) + for i in range(num_pios): + add_pio(x, y, i) + + # Import a location, deduplicating if appropriate def import_location(rg, x, y): rtile = rg.tiles[pytrellis.Location(x, y)] arcs = [] # (src, dst, configurable, tiletype) wires = [] # (name, uphill, downhill, belpin_uphill, belpins_downhill) - bels = [] # (name, (pin, wire)) + bels = [] # (name, [(pin, wire)]) for name in loc_wires[x, y]: w = rtile.wires[rg.ident(name)] arcs_uphill = [] arcs_downhill = [] + belpins_uphill = [] + belpins_downhill = [] for uh in w.uphill: arcidx = loc_arc_indices[uh.loc.x, uh.loc.y][uh.id] arcs_uphill.append((uh.loc.x - x, uh.loc.y - y, arcidx)) for dh in w.downhill: arcidx = loc_arc_indices[dh.loc.x, dh.loc.y][dh.id] arcs_downhill.append((dh.loc.x - x, dh.loc.y - y, arcidx)) - # TODO: Bel pins - wires.append((name, tuple(arcs_downhill), tuple(arcs_uphill), tuple(), tuple())) + for bp in wire_bel_pins_uphill[x, y][loc_wire_indices[x, y][name]]: + bel, pin = bp + bel_x, bel_y, bel_idx = bel + belpins_uphill.append(((bel_x - x, bel_y - y, bel_idx), pin)) + for bp in wire_bel_pins_downhill[x, y][loc_wire_indices[x, y][name]]: + bel, pin = bp + bel_x, bel_y, bel_idx = bel + belpins_downhill.append(((bel_x - x, bel_y - y, bel_idx), pin)) + assert len(belpins_uphill) <= 1 + wires.append((name, tuple(arcs_downhill), tuple(arcs_uphill), tuple(belpins_uphill), tuple(belpins_downhill))) + + for bel in loc_bels[x, y]: + name, beltype, pins = bel + xformed_pins = tuple((p[0], (p[1][0] - x, p[1][1] - y, p[1][2])) for p in pins) + bels.append((name, beltype, xformed_pins)) for arcidx in loc_arcs[x, y]: a = rtile.arcs[arcidx] @@ -94,27 +196,33 @@ def import_location(rg, x, y): location_types[tile_data] = idx type_at_location[x, y] = idx + def main(): pytrellis.load_database(database.get_db_root()) print("Initialising chip...") - chip = pytrellis.Chip("LFE5U-45F") + chip = pytrellis.Chip("LFE5U-25F") print("Building routing graph...") rg = chip.get_routing_graph() max_row = chip.get_max_row() max_col = chip.get_max_col() print("Indexing wires...") - for y in range(0, max_row+1): - for x in range(0, max_col+1): + for y in range(0, max_row + 1): + for x in range(0, max_col + 1): import_location_wires(rg, x, y) print("Indexing arcs...") - for y in range(0, max_row+1): - for x in range(0, max_col+1): + for y in range(0, max_row + 1): + for x in range(0, max_col + 1): index_location_arcs(rg, x, y) + print("Adding bels...") + for y in range(0, max_row + 1): + for x in range(0, max_col + 1): + add_bels(chip, x, y) print("Importing tiles...") - for y in range(0, max_row+1): - for x in range(0, max_col+1): + for y in range(0, max_row + 1): + for x in range(0, max_col + 1): print(" At R{}C{}".format(y, x)) import_location(rg, x, y) + if __name__ == "__main__": main() -- cgit v1.2.3 From ee45f5790978f7f776bb559707826802335918b8 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sat, 7 Jul 2018 17:37:33 +0200 Subject: ecp5: Starting to add BBA to importer Signed-off-by: David Shah --- ecp5/arch.h | 1 - ecp5/trellis_import.py | 313 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 313 insertions(+), 1 deletion(-) diff --git a/ecp5/arch.h b/ecp5/arch.h index 53385acf..b9cedd2c 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -69,7 +69,6 @@ NPNR_PACKED_STRUCT(struct PipInfoPOD { LocationPOD rel_src_loc, rel_dst_loc; int32_t src_idx, dst_idx; int32_t delay; - LocationPOD rel_tile_loc; int16_t tile_type; int8_t pip_type; int8_t padding_0; diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index 2081cda9..88420c6f 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -197,6 +197,319 @@ def import_location(rg, x, y): type_at_location[x, y] = idx +class BinaryBlobAssembler: + def __init__(self, cname, endianness, nodebug=False): + assert endianness in ["le", "be"] + self.cname = cname + self.endianness = endianness + self.finalized = False + self.data = bytearray() + self.comments = dict() + self.labels = dict() + self.exports = set() + self.labels_byaddr = dict() + self.ltypes_byaddr = dict() + self.strings = dict() + self.refs = dict() + self.nodebug = nodebug + + def l(self, name, ltype=None, export=False): + assert not self.finalized + assert name not in self.labels + assert len(self.data) not in self.labels_byaddr + self.labels[name] = len(self.data) + if ltype is not None: + self.ltypes_byaddr[len(self.data)] = ltype + self.labels_byaddr[len(self.data)] = name + if export: + assert ltype is not None + self.exports.add(len(self.data)) + + def r(self, name, comment): + assert not self.finalized + assert len(self.data) % 4 == 0 + assert len(self.data) not in self.refs + if self.nodebug: + comment = None + if name is not None: + self.refs[len(self.data)] = (name, comment) + self.data.append(0) + self.data.append(0) + self.data.append(0) + self.data.append(0) + if (name is None) and (comment is not None): + self.comments[len(self.data)] = comment + " (null reference)" + + def s(self, s, comment): + assert not self.finalized + if self.nodebug: + comment = None + if s not in self.strings: + index = len(self.strings) + self.strings[s] = index + else: + index = self.strings[s] + if comment is not None: + self.r("str%d" % index, '%s: "%s"' % (comment, s)) + else: + self.r("str%d" % index, None) + + def u8(self, v, comment): + assert not self.finalized + if self.nodebug: + comment = None + self.data.append(v) + if comment is not None: + self.comments[len(self.data)] = comment + + def u16(self, v, comment): + assert not self.finalized + assert len(self.data) % 2 == 0 + if self.nodebug: + comment = None + if self.endianness == "le": + self.data.append(v & 255) + self.data.append((v >> 8) & 255) + elif self.endianness == "be": + self.data.append((v >> 8) & 255) + self.data.append(v & 255) + else: + assert 0 + if comment is not None: + self.comments[len(self.data)] = comment + + def s16(self, v, comment): + assert not self.finalized + assert len(self.data) % 2 == 0 + if self.nodebug: + comment = None + c2val = (~v + 1) if v < 0 else v + if self.endianness == "le": + self.data.append(c2val & 255) + self.data.append((c2val >> 8) & 255) + elif self.endianness == "be": + self.data.append((c2val >> 8) & 255) + self.data.append(c2val & 255) + else: + assert 0 + if comment is not None: + self.comments[len(self.data)] = comment + + def u32(self, v, comment): + assert not self.finalized + assert len(self.data) % 4 == 0 + if self.nodebug: + comment = None + if self.endianness == "le": + self.data.append(v & 255) + self.data.append((v >> 8) & 255) + self.data.append((v >> 16) & 255) + self.data.append((v >> 24) & 255) + elif self.endianness == "be": + self.data.append((v >> 24) & 255) + self.data.append((v >> 16) & 255) + self.data.append((v >> 8) & 255) + self.data.append(v & 255) + else: + assert 0 + if comment is not None: + self.comments[len(self.data)] = comment + + def finalize(self): + assert not self.finalized + for s, index in self.strings.items(): + self.l("str%d" % index, "char") + for c in s: + self.data.append(ord(c)) + self.data.append(0) + self.finalized = True + cursor = 0 + while cursor < len(self.data): + if cursor in self.refs: + v = self.labels[self.refs[cursor][0]] - cursor + if self.endianness == "le": + self.data[cursor + 0] = (v & 255) + self.data[cursor + 1] = ((v >> 8) & 255) + self.data[cursor + 2] = ((v >> 16) & 255) + self.data[cursor + 3] = ((v >> 24) & 255) + elif self.endianness == "be": + self.data[cursor + 0] = ((v >> 24) & 255) + self.data[cursor + 1] = ((v >> 16) & 255) + self.data[cursor + 2] = ((v >> 8) & 255) + self.data[cursor + 3] = (v & 255) + else: + assert 0 + cursor += 4 + else: + cursor += 1 + + def write_verbose_c(self, f, ctype="const unsigned char"): + assert self.finalized + print("%s %s[%d] = {" % (ctype, self.cname, len(self.data)), file=f) + cursor = 0 + bytecnt = 0 + while cursor < len(self.data): + if cursor in self.comments: + if bytecnt == 0: + print(" ", end="", file=f) + print(" // %s" % self.comments[cursor], file=f) + bytecnt = 0 + if cursor in self.labels_byaddr: + if bytecnt != 0: + print(file=f) + if cursor in self.exports: + print("#define %s ((%s*)(%s+%d))" % ( + self.labels_byaddr[cursor], self.ltypes_byaddr[cursor], self.cname, cursor), file=f) + else: + print(" // [%d] %s" % (cursor, self.labels_byaddr[cursor]), file=f) + bytecnt = 0 + if cursor in self.refs: + if bytecnt != 0: + print(file=f) + print(" ", end="", file=f) + print(" %-4s" % ("%d," % self.data[cursor + 0]), end="", file=f) + print(" %-4s" % ("%d," % self.data[cursor + 1]), end="", file=f) + print(" %-4s" % ("%d," % self.data[cursor + 2]), end="", file=f) + print(" %-4s" % ("%d," % self.data[cursor + 3]), end="", file=f) + print(" // [%d] %s (reference to %s)" % (cursor, self.refs[cursor][1], self.refs[cursor][0]), file=f) + bytecnt = 0 + cursor += 4 + else: + if bytecnt == 0: + print(" ", end="", file=f) + print(" %-4s" % ("%d," % self.data[cursor]), end=("" if bytecnt < 15 else "\n"), file=f) + bytecnt = (bytecnt + 1) & 15 + cursor += 1 + if bytecnt != 0: + print(file=f) + print("};", file=f) + + def write_compact_c(self, f, ctype="const unsigned char"): + assert self.finalized + print("%s %s[%d] = {" % (ctype, self.cname, len(self.data)), file=f) + column = 0 + for v in self.data: + if column == 0: + print(" ", end="", file=f) + column += 2 + s = "%d," % v + print(s, end="", file=f) + column += len(s) + if column > 75: + print(file=f) + column = 0 + if column != 0: + print(file=f) + for cursor in self.exports: + print("#define %s ((%s*)(%s+%d))" % ( + self.labels_byaddr[cursor], self.ltypes_byaddr[cursor], self.cname, cursor), file=f) + print("};", file=f) + + def write_uint64_c(self, f, ctype="const uint64_t"): + assert self.finalized + print("%s %s[%d] = {" % (ctype, self.cname, (len(self.data) + 7) // 8), file=f) + column = 0 + for i in range((len(self.data) + 7) // 8): + v0 = self.data[8 * i + 0] if 8 * i + 0 < len(self.data) else 0 + v1 = self.data[8 * i + 1] if 8 * i + 1 < len(self.data) else 0 + v2 = self.data[8 * i + 2] if 8 * i + 2 < len(self.data) else 0 + v3 = self.data[8 * i + 3] if 8 * i + 3 < len(self.data) else 0 + v4 = self.data[8 * i + 4] if 8 * i + 4 < len(self.data) else 0 + v5 = self.data[8 * i + 5] if 8 * i + 5 < len(self.data) else 0 + v6 = self.data[8 * i + 6] if 8 * i + 6 < len(self.data) else 0 + v7 = self.data[8 * i + 7] if 8 * i + 7 < len(self.data) else 0 + if self.endianness == "le": + v = v0 << 0 + v |= v1 << 8 + v |= v2 << 16 + v |= v3 << 24 + v |= v4 << 32 + v |= v5 << 40 + v |= v6 << 48 + v |= v7 << 56 + elif self.endianness == "be": + v = v7 << 0 + v |= v6 << 8 + v |= v5 << 16 + v |= v4 << 24 + v |= v3 << 32 + v |= v2 << 40 + v |= v1 << 48 + v |= v0 << 56 + else: + assert 0 + if column == 3: + print(" 0x%016x," % v, file=f) + column = 0 + else: + if column == 0: + print(" ", end="", file=f) + print(" 0x%016x," % v, end="", file=f) + column += 1 + if column != 0: + print("", file=f) + print("};", file=f) + + def write_string_c(self, f, ctype="const char"): + assert self.finalized + assert self.data[len(self.data) - 1] == 0 + print("%s %s[%d] =" % (ctype, self.cname, len(self.data)), file=f) + print(" \"", end="", file=f) + column = 0 + for i in range(len(self.data) - 1): + if (self.data[i] < 32) or (self.data[i] > 126): + print("\\%03o" % self.data[i], end="", file=f) + column += 4 + elif self.data[i] == ord('"') or self.data[i] == ord('\\'): + print("\\" + chr(self.data[i]), end="", file=f) + column += 2 + else: + print(chr(self.data[i]), end="", file=f) + column += 1 + if column > 70 and (i != len(self.data) - 2): + print("\"\n \"", end="", file=f) + column = 0 + print("\";", file=f) + + def write_binary(self, f): + assert self.finalized + assert self.data[len(self.data) - 1] == 0 + f.buffer.write(self.data) + + +def write_database(bba): + def write_loc(x, y, sym_name): + bba.s16(x, "%s_x" % sym_name) + bba.s16(y, "%s_y" % sym_name) + + for loctype, idx in sorted(location_types.items(), key=lambda x: x[1]): + wires, arcs, bels = loctype + bba.l("loc%d_pips" % idx, "PipInfoPOD") + for arc in arcs: + src_wire, dst_wire, configurable, tile_type = arc + write_loc(src_wire[0], src_wire[1], "src") + write_loc(dst_wire[0], dst_wire[1], "dst") + bba.u32(src_wire[2], "src_idx") + bba.u32(dst_wire[2], "dst_idx") + bba.u32(1, "delay") # TODO:delay + bba.u16(tile_type, "tile_type") + bba.u8(1 if not configurable else 0, "pip_type") + bba.u8(0, "padding") + for wire_idx in range(len(wires)): + wire = wires[wire_idx] + name, downpips, uppips, downbels, upbels = wire + if len(downpips) > 0: + bba.l("loc%d_wire%d_downpips" % (idx, wire_idx), "PipLocatorPOD") + for dp in downpips: + write_loc(dp[0], dp[1], "rel_loc") + bba.u32(dp[2], "idx") + if len(uppips) > 0: + bba.l("loc%d_wire%d_uppips" % (idx, wire_idx), "PipLocatorPOD") + for up in uppips: + write_loc(up[0], up[1], "rel_loc") + bba.u32(up[2], "idx") + + def main(): pytrellis.load_database(database.get_db_root()) print("Initialising chip...") -- cgit v1.2.3 From 6f90c3df6118a857b24ee3ef031b54ef8aa8b7a8 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sat, 7 Jul 2018 19:58:42 +0200 Subject: ecp5: Adding complete binary blob writer to Trellis importer Signed-off-by: David Shah --- ecp5/.gitignore | 2 +- ecp5/trellis_import.py | 190 ++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 159 insertions(+), 33 deletions(-) diff --git a/ecp5/.gitignore b/ecp5/.gitignore index c20c2ab7..3249a7bb 100644 --- a/ecp5/.gitignore +++ b/ecp5/.gitignore @@ -1,2 +1,2 @@ __pycache__ - +chipdbs/ diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index 88420c6f..ff86098b 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -1,11 +1,21 @@ #!/usr/bin/env python3 import pytrellis import database +import argparse location_types = dict() type_at_location = dict() tiletype_names = dict() +parser = argparse.ArgumentParser(description="import ECP5 routing and bels from Project Trellis") +group = parser.add_mutually_exclusive_group() +group.add_argument("-b", "--binary", action="store_true") +group.add_argument("-c", "--c_file", action="store_true") +parser.add_argument("device", type=str, help="target device") +parser.add_argument("outfile", type=argparse.FileType('w'), help="output filename") +parser.add_argument("-p", "--portspins", type=str, help="path to portpins.inc") +args = parser.parse_args() + def is_global(loc): return loc.x == -2 and loc.y == -2 @@ -20,6 +30,8 @@ def get_tiletype_index(name): return idx +portpins = dict() + loc_wire_indices = dict() loc_wires = dict() @@ -65,19 +77,21 @@ def index_location_arcs(rg, x, y): loc_arcs[x, y] = list() rtile = rg.tiles[pytrellis.Location(x, y)] for arc in rtile.arcs: - idx = len(loc_arcs) + idx = len(loc_arcs[x, y]) trid = arc.key() loc_arcs[x, y].append(trid) loc_arc_indices[x, y][trid] = idx def add_bel_input(bel_x, bel_y, bel_idx, bel_pin, wire_x, wire_y, wire_name): + bel_pin = portpins[bel_pin] loc_bels[bel_x, bel_y][bel_idx][2].append((bel_pin, (wire_x, wire_y, loc_wire_indices[wire_x, wire_y][wire_name]))) wire_bel_pins_downhill[wire_x, wire_y][loc_wire_indices[wire_x, wire_y][wire_name]].append(( (bel_x, bel_y, bel_idx), bel_pin)) def add_bel_output(bel_x, bel_y, bel_idx, bel_pin, wire_x, wire_y, wire_name): + bel_pin = portpins[bel_pin] loc_bels[bel_x, bel_y][bel_idx][2].append((bel_pin, (wire_x, wire_y, loc_wire_indices[wire_x, wire_y][wire_name]))) wire_bel_pins_uphill[wire_x, wire_y][loc_wire_indices[wire_x, wire_y][wire_name]].append(( (bel_x, bel_y, bel_idx), bel_pin)) @@ -359,7 +373,7 @@ class BinaryBlobAssembler: print(file=f) if cursor in self.exports: print("#define %s ((%s*)(%s+%d))" % ( - self.labels_byaddr[cursor], self.ltypes_byaddr[cursor], self.cname, cursor), file=f) + self.labels_byaddr[cursor], self.ltypes_byaddr[cursor], self.cname, cursor), file=f) else: print(" // [%d] %s" % (cursor, self.labels_byaddr[cursor]), file=f) bytecnt = 0 @@ -402,7 +416,7 @@ class BinaryBlobAssembler: print(file=f) for cursor in self.exports: print("#define %s ((%s*)(%s+%d))" % ( - self.labels_byaddr[cursor], self.ltypes_byaddr[cursor], self.cname, cursor), file=f) + self.labels_byaddr[cursor], self.ltypes_byaddr[cursor], self.cname, cursor), file=f) print("};", file=f) def write_uint64_c(self, f, ctype="const uint64_t"): @@ -477,43 +491,139 @@ class BinaryBlobAssembler: f.buffer.write(self.data) -def write_database(bba): +bel_types = { + "NONE": 0, + "SLICE": 1, + "PIO": 2 +} + +def write_database(dev_name, endianness): def write_loc(x, y, sym_name): - bba.s16(x, "%s_x" % sym_name) - bba.s16(y, "%s_y" % sym_name) + bba.s16(x, "%s.x" % sym_name) + bba.s16(y, "%s.y" % sym_name) + + bba = BinaryBlobAssembler("chipdb_blob_%s" % dev_name, endianness) + bba.r("chip_info", "chip_info") for loctype, idx in sorted(location_types.items(), key=lambda x: x[1]): wires, arcs, bels = loctype - bba.l("loc%d_pips" % idx, "PipInfoPOD") - for arc in arcs: - src_wire, dst_wire, configurable, tile_type = arc - write_loc(src_wire[0], src_wire[1], "src") - write_loc(dst_wire[0], dst_wire[1], "dst") - bba.u32(src_wire[2], "src_idx") - bba.u32(dst_wire[2], "dst_idx") - bba.u32(1, "delay") # TODO:delay - bba.u16(tile_type, "tile_type") - bba.u8(1 if not configurable else 0, "pip_type") - bba.u8(0, "padding") - for wire_idx in range(len(wires)): - wire = wires[wire_idx] - name, downpips, uppips, downbels, upbels = wire - if len(downpips) > 0: - bba.l("loc%d_wire%d_downpips" % (idx, wire_idx), "PipLocatorPOD") - for dp in downpips: - write_loc(dp[0], dp[1], "rel_loc") - bba.u32(dp[2], "idx") - if len(uppips) > 0: - bba.l("loc%d_wire%d_uppips" % (idx, wire_idx), "PipLocatorPOD") - for up in uppips: - write_loc(up[0], up[1], "rel_loc") - bba.u32(up[2], "idx") - + if len(arcs) > 0: + bba.l("loc%d_pips" % idx, "PipInfoPOD") + for arc in arcs: + src_wire, dst_wire, configurable, tile_type = arc + write_loc(src_wire[0], src_wire[1], "src") + write_loc(dst_wire[0], dst_wire[1], "dst") + bba.u32(src_wire[2], "src_idx") + bba.u32(dst_wire[2], "dst_idx") + bba.u32(1, "delay") # TODO:delay + bba.u16(tile_type, "tile_type") + bba.u8(1 if not configurable else 0, "pip_type") + bba.u8(0, "padding") + if len(wires) > 0: + for wire_idx in range(len(wires)): + wire = wires[wire_idx] + name, downpips, uppips, downbels, upbels = wire + if len(downpips) > 0: + bba.l("loc%d_wire%d_downpips" % (idx, wire_idx), "PipLocatorPOD") + for dp in downpips: + write_loc(dp[0], dp[1], "rel_loc") + bba.u32(dp[2], "index") + if len(uppips) > 0: + bba.l("loc%d_wire%d_uppips" % (idx, wire_idx), "PipLocatorPOD") + for up in uppips: + write_loc(up[0], up[1], "rel_loc") + bba.u32(up[2], "index") + if len(downbels) > 0: + bba.l("loc%d_wire%d_downbels" % (idx, wire_idx), "BelPortPOD") + for db in downbels: + bel, pin = db + write_loc(bel[0], bel[1], "rel_bel_loc") + bba.u32(bel[2], "bel_index") + bba.u32(pin, "port") + bba.l("loc%d_wires" % idx, "WireInfoPOD") + for wire_idx in range(len(wires)): + wire = wires[wire_idx] + name, downpips, uppips, downbels, upbels = wire + bba.s(name, "name") + bba.u32(len(uppips), "num_uphill") + bba.u32(len(downpips), "num_downhill") + bba.r("loc%d_wire%d_uppips" % (idx, wire_idx) if len(uppips) > 0 else None, "pips_uphill") + bba.r("loc%d_wire%d_downpips" % (idx, wire_idx) if len(downpips) > 0 else None, "pips_downhill") + bba.u32(len(downbels), "num_bels_downhill") + if len(upbels) == 1: + bel, pin = upbels[0] + write_loc(bel[0], bel[1], "uphill_bel_loc") + bba.u32(bel[2], "uphill_bel_idx") + bba.u32(pin, "uphill_bel_pin") + else: + write_loc(-1, -1, "bel_uphill.rel_bel_loc") + bba.u32(0xFFFFFFFF, "bel_uphill.bel_index") + bba.u32(0, "bel_uphill.port") + bba.r("loc%d_wire%d_downbels" % (idx, wire_idx) if len(downbels) > 0 else None, "bels_downhill") + if len(bels) > 0: + for bel_idx in range(len(bels)): + bel, beltype, pins = bels[bel_idx] + bba.l("loc%d_bel%d_wires" % (idx, bel_idx), "BelPortPOD") + for pin in pins: + port, wire = pin + write_loc(wire[0], wire[1], "rel_wire_loc") + bba.u32(wire[2], "wire_index") + bba.u32(port, "port") + bba.l("loc%d_bels" % idx, "BelInfoPOD") + for bel_idx in range(len(bels)): + bel, beltype, pins = bels[bel_idx] + bba.s(bel, "name") + bba.u32(bel_types[beltype], "type") + bba.u32(len(pins), "num_bel_wires") + bba.r("loc%d_bel%d_wires" % (idx, bel_idx), "bel_wires") + + bba.l("locations", "LocationTypePOD") + for loctype, idx in sorted(location_types.items(), key=lambda x: x[1]): + wires, arcs, bels = loctype + bba.u32(len(bels), "num_bels") + bba.u32(len(wires), "num_wires") + bba.u32(len(arcs), "num_pips") + bba.r("loc%d_bels" % idx if len(bels) > 0 else None, "bel_data") + bba.r("loc%d_wires" % idx if len(wires) > 0 else None, "wire_data") + bba.r("loc%d_pips" % idx if len(arcs) > 0 else None, "pips_data") + + bba.l("location_types", "int32_t") + for y in range(0, max_row+1): + for x in range(0, max_col+1): + bba.u32(type_at_location[x, y], "loctype") + + bba.l("chip_info") + bba.u32(max_col + 1, "width") + bba.u32(max_row + 1, "height") + bba.u32((max_col + 1) * (max_row + 1), "num_tiles") + bba.u32(len(location_types), "num_location_types") + bba.r("locations", "locations") + bba.r("location_types", "location_type") + bba.finalize() + return bba + +dev_names = {"LFE5U-25F": "25k", "LFE5U-45F": "45k", "LFE5U-85F": "85k"} def main(): + global max_row, max_col pytrellis.load_database(database.get_db_root()) + args = parser.parse_args() + + # Read port pin file + with open(args.portspins) as f: + for line in f: + line = line.replace("(", " ") + line = line.replace(")", " ") + line = line.split() + if len(line) == 0: + continue + assert len(line) == 2 + assert line[0] == "X" + idx = len(portpins) + 1 + portpins[line[1]] = idx + print("Initialising chip...") - chip = pytrellis.Chip("LFE5U-25F") + chip = pytrellis.Chip(args.device) print("Building routing graph...") rg = chip.get_routing_graph() max_row = chip.get_max_row() @@ -535,7 +645,23 @@ def main(): for x in range(0, max_col + 1): print(" At R{}C{}".format(y, x)) import_location(rg, x, y) + print("{} unique location types".format(len(location_types))) + bba = write_database(dev_names[args.device], "le") + + + if args.c_file: + print('#include "nextpnr.h"', file=args.outfile) + print('NEXTPNR_NAMESPACE_BEGIN', file=args.outfile) + + + if args.binary: + bba.write_binary(args.outfile) + + if args.c_file: + bba.write_string_c(args.outfile) + if args.c_file: + print('NEXTPNR_NAMESPACE_END', file=args.outfile) if __name__ == "__main__": main() -- cgit v1.2.3 From bb683d71d698481f472df26747c5332d49d933c1 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 8 Jul 2018 11:15:30 +0200 Subject: ecp5: Add 25k database Signed-off-by: David Shah --- .gitignore | 1 + ecp5/arch.cc | 25 ++++++++++++++++++++++++- ecp5/family.cmake | 41 +++++++++++++++++++++++++++++++++++++++++ ecp5/main.cc | 7 +++++-- ecp5/trellis_import.py | 6 +++--- 5 files changed, 74 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index f308b34a..6ca9e19f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /objs/ /nextpnr-generic* /nextpnr-ice40* +/nextpnr-ecp5* cmake-build-*/ Makefile cmake_install.cmake diff --git a/ecp5/arch.cc b/ecp5/arch.cc index fe10d415..a200e102 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -92,12 +92,20 @@ static const ChipInfoPOD *get_chip_info(const RelPtr *ptr) { return void load_chipdb(); #endif +#define LFE5U_25F_ONLY + Arch::Arch(ArchArgs args) : args(args) { #if defined(_MSC_VER) load_chipdb(); #endif - +#ifdef LFE5U_25F_ONLY + if (args.type == ArchArgs::LFE5U_25F) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_25k)); + } else { + log_error("Unsupported ECP5 chip type.\n"); + } +#else if (args.type == ArchArgs::LFE5U_25F) { chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_25k)); } else if (args.type == ArchArgs::LFE5U_45F) { @@ -107,6 +115,8 @@ Arch::Arch(ArchArgs args) : args(args) } else { log_error("Unsupported ECP5 chip type.\n"); } +#endif + } // ----------------------------------------------------------------------- @@ -302,4 +312,17 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; } bool Arch::isBelLocationValid(BelId bel) const { return true; } +// ----------------------------------------------------------------------- + + +bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, delay_t &delay) const +{ + return false; +} + +IdString Arch::getPortClock(const CellInfo *cell, IdString port) const { return IdString(); } + +bool Arch::isClockPort(const CellInfo *cell, IdString port) const { return false; } + + NEXTPNR_NAMESPACE_END diff --git a/ecp5/family.cmake b/ecp5/family.cmake index e69de29b..7f528886 100644 --- a/ecp5/family.cmake +++ b/ecp5/family.cmake @@ -0,0 +1,41 @@ + +set(devices 25k) + +set(DB_PY ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/trellis_import.py) + +file(MAKE_DIRECTORY ecp5/chipdbs/) +add_library(ecp5_chipdb OBJECT ecp5/chipdbs/) +target_compile_definitions(ecp5_chipdb PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family}) +target_include_directories(ecp5_chipdb PRIVATE ${family}/) +set(ENV_CMD ${CMAKE_COMMAND} -E env "PYTHONPATH=${TRELLIS_ROOT}/libtrellis:${TRELLIS_ROOT}/util/common") +if (MSVC) + target_sources(ecp5_chipdb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/resource/embed.cc) + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ecp5/resources/chipdb.rc PROPERTIES LANGUAGE RC) + foreach (dev ${devices}) + set(DEV_CC_DB ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/chipdbs/chipdb-${dev}.bin) + set(DEV_PORTS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/portpins.inc) + add_custom_command(OUTPUT ${DEV_CC_DB} + COMMAND ${ENV_CMD} python3 ${DB_PY} -b -p ${DEV_PORTS_INC} ${dev} ${DEV_CC_DB} + DEPENDS ${DB_PY} + ) + target_sources(ecp5_chipdb PRIVATE ${DEV_CC_DB}) + set_source_files_properties(${DEV_CC_DB} PROPERTIES HEADER_FILE_ONLY TRUE) + foreach (target ${family_targets}) + target_sources(${target} PRIVATE $ ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/resource/chipdb.rc) + endforeach (target) + endforeach (dev) +else() + target_compile_options(ecp5_chipdb PRIVATE -g0 -O0 -w) + foreach (dev ${devices}) + set(DEV_CC_DB ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/chipdbs/chipdb-${dev}.cc) + set(DEV_PORTS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/portpins.inc) + add_custom_command(OUTPUT ${DEV_CC_DB} + COMMAND ${ENV_CMD} python3 ${DB_PY} -c -p ${DEV_PORTS_INC} ${dev} ${DEV_CC_DB} + DEPENDS ${DB_PY} + ) + target_sources(ecp5_chipdb PRIVATE ${DEV_CC_DB}) + foreach (target ${family_targets}) + target_sources(${target} PRIVATE $) + endforeach (target) + endforeach (dev) +endif() diff --git a/ecp5/main.cc b/ecp5/main.cc index d025d8d4..55e835e3 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -89,8 +89,11 @@ int main(int argc, char *argv[]) "sha1 " GIT_COMMIT_HASH_STR ")\n"; return 1; } - - Context ctx(ArchArgs{}); + ArchArgs args; + args.type = ArchArgs::LFE5U_25F; + args.package = "CABGA381"; + args.speed = 6; + Context ctx(args); if (vm.count("verbose")) { ctx.verbose = true; diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index ff86098b..aabcffb1 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -602,7 +602,7 @@ def write_database(dev_name, endianness): bba.finalize() return bba -dev_names = {"LFE5U-25F": "25k", "LFE5U-45F": "45k", "LFE5U-85F": "85k"} +dev_names = {"25k": "LFE5U-25F", "45k": "LFE5U-45F", "85k": "LFE5U-85F"} def main(): global max_row, max_col @@ -623,7 +623,7 @@ def main(): portpins[line[1]] = idx print("Initialising chip...") - chip = pytrellis.Chip(args.device) + chip = pytrellis.Chip(dev_names[args.device]) print("Building routing graph...") rg = chip.get_routing_graph() max_row = chip.get_max_row() @@ -646,7 +646,7 @@ def main(): print(" At R{}C{}".format(y, x)) import_location(rg, x, y) print("{} unique location types".format(len(location_types))) - bba = write_database(dev_names[args.device], "le") + bba = write_database(args.device, "le") if args.c_file: -- cgit v1.2.3 From 738b410bf84d5508942014a14344593ac99ce3b7 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 8 Jul 2018 11:20:04 +0200 Subject: cmake: Only add ECP5 target when TRELLIS_ROOT specified Signed-off-by: David Shah --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f4586dfa..e9d25abc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,9 @@ option(BUILD_PYTHON "Build Python Integration" ON) option(BUILD_TESTS "Build GUI" OFF) # List of families to build +if(DEFINED TRELLIS_ROOT) set(FAMILIES generic ice40 ecp5) + set(ARCH "" CACHE STRING "Architecture family for nextpnr build") set_property(CACHE ARCH PROPERTY STRINGS ${FAMILIES}) -- cgit v1.2.3 From c33aa259ad822d9c4ce3f46922504a70e730704c Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 8 Jul 2018 12:35:27 +0200 Subject: ecp5: Adding a simple prepacked synth script Signed-off-by: David Shah --- ecp5/synth/.gitignore | 0 ecp5/synth/blinky.v | 16 ++++++++++++ ecp5/synth/blinky.ys | 9 +++++++ ecp5/synth/cells.v | 39 ++++++++++++++++++++++++++++ ecp5/synth/simple_map.v | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 132 insertions(+) create mode 100644 ecp5/synth/.gitignore create mode 100644 ecp5/synth/blinky.v create mode 100644 ecp5/synth/blinky.ys create mode 100644 ecp5/synth/cells.v create mode 100644 ecp5/synth/simple_map.v diff --git a/ecp5/synth/.gitignore b/ecp5/synth/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/ecp5/synth/blinky.v b/ecp5/synth/blinky.v new file mode 100644 index 00000000..aba58801 --- /dev/null +++ b/ecp5/synth/blinky.v @@ -0,0 +1,16 @@ +module top(input clk_pin, output [3:0] led_pin); + + wire clk; + wire [3:0] led; + + TRELLIS_IO #(.DIR("INPUT")) clk_buf (.B(clk_pin), .O(clk)); + TRELLIS_IO #(.DIR("OUTPUT")) led_buf [3:0] (.B(led_pin), .I(led)); + + reg [25:0] ctr = 0; + + always@(posedge clk) + ctr <= ctr + 1'b1; + + assign led = ctr[25:22]; + +endmodule diff --git a/ecp5/synth/blinky.ys b/ecp5/synth/blinky.ys new file mode 100644 index 00000000..c0b74636 --- /dev/null +++ b/ecp5/synth/blinky.ys @@ -0,0 +1,9 @@ +read_verilog blinky.v +read_verilog -lib cells.v +synth -top top +abc -lut 4 +techmap -map simple_map.v +splitnets +opt_clean +stat +write_json blinky.json diff --git a/ecp5/synth/cells.v b/ecp5/synth/cells.v new file mode 100644 index 00000000..2435713a --- /dev/null +++ b/ecp5/synth/cells.v @@ -0,0 +1,39 @@ +(* blackbox *) +module TRELLIS_SLICE( + input A0, B0, C0, D0, + input A1, B1, C1, D1, + input M0, M1, + input FCI, FXA, FXB, + input CLK, LSR, CE, + output F0, Q0, + output F1, Q1, + output FCO, OFX0, OFX1 +); + +parameter MODE = "LOGIC"; +parameter GSR = "ENABLED"; +parameter SRMODE = "LSR_OVER_CE"; +parameter CEMUX = "1"; +parameter CLKMUX = "CLK"; +parameter LSRMUX = "LSR"; +parameter LUT0_INITVAL = 16'h0000; +parameter LUT1_INITVAL = 16'h0000; +parameter REG0_SD = "0"; +parameter REG1_SD = "0"; +parameter REG0_REGSET = "RESET"; +parameter REG1_REGSET = "RESET"; +parameter CCU2_INJECT1_0 = "NO"; +parameter CCU2_INJECT1_1 = "NO"; + +endmodule + +(* blackbox *) +module TRELLIS_IO( + inout B, + input I, + input T, + output O, +); +parameter DIR = "INPUT"; + +endmodule diff --git a/ecp5/synth/simple_map.v b/ecp5/synth/simple_map.v new file mode 100644 index 00000000..4a50fd01 --- /dev/null +++ b/ecp5/synth/simple_map.v @@ -0,0 +1,68 @@ +module \$_DFF_P_ (input D, C, output Q); + TRELLIS_SLICE #( + .MODE("LOGIC"), + .CLKMUX("CLK"), + .CEMUX("1"), + .REG0_SD("0"), + .REG0_REGSET("RESET"), + .SRMODE("LSR_OVER_CE"), + .GSR("DISABLED") + ) _TECHMAP_REPLACE_ ( + .CLK(C), + .M0(D), + .Q0(Q) + ); +endmodule + +module \$lut (A, Y); + parameter WIDTH = 0; + parameter LUT = 0; + + input [WIDTH-1:0] A; + output Y; + + generate + if (WIDTH == 1) begin + TRELLIS_SLICE #( + .MODE("LOGIC"), + .LUT0_INITVAL(LUT) + ) _TECHMAP_REPLACE_ ( + .A0(A[0]), + .F0(Y) + ); + end + if (WIDTH == 2) begin + TRELLIS_SLICE #( + .MODE("LOGIC"), + .LUT0_INITVAL(LUT) + ) _TECHMAP_REPLACE_ ( + .A0(A[0]), + .B0(A[1]), + .F0(Y) + ); + end + if (WIDTH == 3) begin + TRELLIS_SLICE #( + .MODE("LOGIC"), + .LUT0_INITVAL(LUT) + ) _TECHMAP_REPLACE_ ( + .A0(A[0]), + .B0(A[1]), + .C0(A[2]), + .F0(Y) + ); + end + if (WIDTH == 4) begin + TRELLIS_SLICE #( + .MODE("LOGIC"), + .LUT0_INITVAL(LUT) + ) _TECHMAP_REPLACE_ ( + .A0(A[0]), + .B0(A[1]), + .C0(A[2]), + .D0(A[3]), + .F0(Y) + ); + end + endgenerate +endmodule -- cgit v1.2.3 From 93f379a488ae9f4c103c6d61cad49fba8012bc5a Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 8 Jul 2018 12:41:11 +0200 Subject: ecp5: Adding JSON input option (not working yet) Signed-off-by: David Shah --- ecp5/main.cc | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ecp5/main.cc b/ecp5/main.cc index 55e835e3..a9b02537 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -30,10 +30,18 @@ #include #include #include +#include #include "log.h" #include "nextpnr.h" #include "version.h" +#include "place_sa.h" +#include "route.h" +#include "design_utils.h" +#include "timing.h" +#include "jsonparse.h" + + USING_NEXTPNR_NAMESPACE int main(int argc, char *argv[]) @@ -52,6 +60,8 @@ int main(int argc, char *argv[]) #ifndef NO_GUI options.add_options()("gui", "start gui"); #endif + options.add_options()("json", po::value(), "JSON design file to ingest"); + options.add_options()("seed", po::value(), "seed value for random number generator"); po::positional_options_description pos; #ifndef NO_PYTHON @@ -107,6 +117,31 @@ int main(int argc, char *argv[]) ctx.rngseed(vm["seed"].as()); } + if (vm.count("json")) { + std::string filename = vm["json"].as(); + std::ifstream f(filename); + if (!parse_json_file(f, filename, &ctx)) + log_error("Loading design failed.\n"); + + //if (!pack_design(&ctx) && !ctx.force) + // log_error("Packing design failed.\n"); + if (vm.count("freq")) + ctx.target_freq = vm["freq"].as() * 1e6; + assign_budget(&ctx); + ctx.check(); + print_utilisation(&ctx); + ctx.timing_driven = true; + if (vm.count("no-tmdriv")) + ctx.timing_driven = false; + + if (!place_design_sa(&ctx) && !ctx.force) + log_error("Placing design failed.\n"); + ctx.check(); + if (!route_design(&ctx) && !ctx.force) + log_error("Routing design failed.\n"); + + } + #ifndef NO_PYTHON if (vm.count("run")) { init_python(argv[0], true); -- cgit v1.2.3 From 59cb1600d9995eb52af41caea7bc364dcf47ea35 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 8 Jul 2018 12:48:25 +0200 Subject: ecp5: Fixing arch bugs Signed-off-by: David Shah --- ecp5/arch.cc | 6 +++++- ecp5/archdefs.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ecp5/arch.cc b/ecp5/arch.cc index a200e102..6708c339 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -272,7 +272,11 @@ BelId Arch::getPackagePinBel(const std::string &pin) const { return BelId(); } std::string Arch::getBelPackagePin(BelId bel) const { return ""; } // ----------------------------------------------------------------------- -void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const {} +void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const { + x = bel.location.x; + y = bel.location.y; + gb = false; +} delay_t Arch::estimateDelay(WireId src, WireId dst) const { return 1; } diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index b05ac22c..4facc786 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -71,7 +71,7 @@ struct Location Location(const Location &loc) : x(loc.x), y(loc.y){}; bool operator==(const Location &other) const { return x == other.x && y == other.y; } - bool operator!=(const Location &other) const { return x != other.x || y == other.y; } + bool operator!=(const Location &other) const { return x != other.x || y != other.y; } }; inline Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); } -- cgit v1.2.3 From 49f39b8d5635e607764f12c31d2f18a0f79b1969 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 8 Jul 2018 12:56:43 +0200 Subject: ecp5: Place design working, router now segfaults due to db issue Signed-off-by: David Shah --- CMakeLists.txt | 1 + ecp5/arch.cc | 6 ++-- ecp5/main.cc | 13 ++++---- ecp5/pack.cc | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ecp5/pack.h | 31 ++++++++++++++++++ 5 files changed, 139 insertions(+), 11 deletions(-) create mode 100644 ecp5/pack.cc create mode 100644 ecp5/pack.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e9d25abc..32063af6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -219,6 +219,7 @@ endforeach (family) file(GLOB_RECURSE CLANGFORMAT_FILES *.cc *.h) string(REGEX REPLACE "[^;]*/ice40/chipdbs/chipdb-[^;]*.cc" "" CLANGFORMAT_FILES "${CLANGFORMAT_FILES}") +string(REGEX REPLACE "[^;]*/ecp5/chipdbs/chipdb-[^;]*.cc" "" CLANGFORMAT_FILES "${CLANGFORMAT_FILES}") string(REGEX REPLACE "[^;]*/3rdparty[^;]*" "" CLANGFORMAT_FILES "${CLANGFORMAT_FILES}") string(REGEX REPLACE "[^;]*/generated[^;]*" "" CLANGFORMAT_FILES "${CLANGFORMAT_FILES}") diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 6708c339..e80ad829 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -116,7 +116,6 @@ Arch::Arch(ArchArgs args) : args(args) log_error("Unsupported ECP5 chip type.\n"); } #endif - } // ----------------------------------------------------------------------- @@ -272,7 +271,8 @@ BelId Arch::getPackagePinBel(const std::string &pin) const { return BelId(); } std::string Arch::getBelPackagePin(BelId bel) const { return ""; } // ----------------------------------------------------------------------- -void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const { +void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const +{ x = bel.location.x; y = bel.location.y; gb = false; @@ -318,7 +318,6 @@ bool Arch::isBelLocationValid(BelId bel) const { return true; } // ----------------------------------------------------------------------- - bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, delay_t &delay) const { return false; @@ -328,5 +327,4 @@ IdString Arch::getPortClock(const CellInfo *cell, IdString port) const { return bool Arch::isClockPort(const CellInfo *cell, IdString port) const { return false; } - NEXTPNR_NAMESPACE_END diff --git a/ecp5/main.cc b/ecp5/main.cc index a9b02537..245d1cc3 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -29,18 +29,18 @@ #endif #include #include -#include #include +#include #include "log.h" #include "nextpnr.h" #include "version.h" +#include "design_utils.h" +#include "jsonparse.h" +#include "pack.h" #include "place_sa.h" #include "route.h" -#include "design_utils.h" #include "timing.h" -#include "jsonparse.h" - USING_NEXTPNR_NAMESPACE @@ -123,8 +123,8 @@ int main(int argc, char *argv[]) if (!parse_json_file(f, filename, &ctx)) log_error("Loading design failed.\n"); - //if (!pack_design(&ctx) && !ctx.force) - // log_error("Packing design failed.\n"); + if (!pack_design(&ctx) && !ctx.force) + log_error("Packing design failed.\n"); if (vm.count("freq")) ctx.target_freq = vm["freq"].as() * 1e6; assign_budget(&ctx); @@ -139,7 +139,6 @@ int main(int argc, char *argv[]) ctx.check(); if (!route_design(&ctx) && !ctx.force) log_error("Routing design failed.\n"); - } #ifndef NO_PYTHON diff --git a/ecp5/pack.cc b/ecp5/pack.cc new file mode 100644 index 00000000..7f54c231 --- /dev/null +++ b/ecp5/pack.cc @@ -0,0 +1,99 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 David Shah + * + * 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 "pack.h" +#include +#include +#include +#include "design_utils.h" +#include "log.h" +#include "util.h" + +NEXTPNR_NAMESPACE_BEGIN + +static bool is_nextpnr_iob(Context *ctx, CellInfo *cell) +{ + return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") || + cell->type == ctx->id("$nextpnr_iobuf"); +} + +static bool is_trellis_io(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("TRELLIS_IO"); } + +// Simple "packer" to remove nextpnr IOBUFs, this assumes IOBUFs are manually instantiated +void pack_io(Context *ctx) +{ + std::unordered_set packed_cells; + std::vector> new_cells; + log_info("Packing IOs..\n"); + + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (is_nextpnr_iob(ctx, ci)) { + CellInfo *trio = nullptr; + if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) { + trio = net_only_drives(ctx, ci->ports.at(ctx->id("O")).net, is_trellis_io, ctx->id("B"), true, ci); + + } else if (ci->type == ctx->id("$nextpnr_obuf")) { + trio = net_only_drives(ctx, ci->ports.at(ctx->id("I")).net, is_trellis_io, ctx->id("B"), true, ci); + } + if (trio != nullptr) { + // Trivial case, TRELLIS_IO used. Just destroy the net and the + // iobuf + log_info("%s feeds TRELLIS_IO %s, removing %s %s.\n", ci->name.c_str(ctx), trio->name.c_str(ctx), + ci->type.c_str(ctx), ci->name.c_str(ctx)); + NetInfo *net = trio->ports.at(ctx->id("B")).net; + if (net != nullptr) { + ctx->nets.erase(net->name); + trio->ports.at(ctx->id("B")).net = nullptr; + } + if (ci->type == ctx->id("$nextpnr_iobuf")) { + NetInfo *net2 = ci->ports.at(ctx->id("I")).net; + if (net2 != nullptr) { + ctx->nets.erase(net2->name); + } + } + } else { + log_error("TRELLIS_IO required on all top level IOs...\n"); + } + packed_cells.insert(ci->name); + std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(trio->attrs, trio->attrs.begin())); + } + } + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } + for (auto &ncell : new_cells) { + ctx->cells[ncell->name] = std::move(ncell); + } +} + +// Main pack function +bool pack_design(Context *ctx) +{ + try { + log_break(); + pack_io(ctx); + log_info("Checksum: 0x%08x\n", ctx->checksum()); + return true; + } catch (log_execution_error_exception) { + return false; + } +} + +NEXTPNR_NAMESPACE_END diff --git a/ecp5/pack.h b/ecp5/pack.h new file mode 100644 index 00000000..cc051a41 --- /dev/null +++ b/ecp5/pack.h @@ -0,0 +1,31 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 David Shah + * + * 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. + * + */ + +#ifndef PACK_H +#define PACK_H + +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +bool pack_design(Context *ctx); + +NEXTPNR_NAMESPACE_END + +#endif // ROUTE_H -- cgit v1.2.3 From 417913fd8509a44edf8421184c46d15d6763908b Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 8 Jul 2018 13:29:13 +0200 Subject: ecp5: Architecture fixes Signed-off-by: David Shah --- ecp5/arch.h | 4 ++++ ecp5/trellis_import.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ecp5/arch.h b/ecp5/arch.h index b9cedd2c..029caef0 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -672,7 +672,9 @@ struct Arch : BaseCtx PipRange range; NPNR_ASSERT(wire != WireId()); range.b.cursor = locInfo(wire)->wire_data[wire.index].pips_downhill.get(); + range.b.wire_loc = wire.location; range.e.cursor = range.b.cursor + locInfo(wire)->wire_data[wire.index].num_downhill; + range.e.wire_loc = wire.location; return range; } @@ -681,7 +683,9 @@ struct Arch : BaseCtx PipRange range; NPNR_ASSERT(wire != WireId()); range.b.cursor = locInfo(wire)->wire_data[wire.index].pips_uphill.get(); + range.b.wire_loc = wire.location; range.e.cursor = range.b.cursor + locInfo(wire)->wire_data[wire.index].num_uphill; + range.e.wire_loc = wire.location; return range; } diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index aabcffb1..62aa4d81 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -297,7 +297,7 @@ class BinaryBlobAssembler: assert len(self.data) % 2 == 0 if self.nodebug: comment = None - c2val = (~v + 1) if v < 0 else v + c2val = (((-v) ^ 0xffff) + 1) if v < 0 else v if self.endianness == "le": self.data.append(c2val & 255) self.data.append((c2val >> 8) & 255) -- cgit v1.2.3 From 981522b10ead3b3c2cbc5f9f270b9fae9320395b Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 8 Jul 2018 14:24:32 +0200 Subject: ecp5: Blinky example places and routes Signed-off-by: David Shah --- ecp5/arch.cc | 8 +++++++- ecp5/synth/wire.v | 11 +++++++++++ ecp5/synth/wire.ys | 9 +++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 ecp5/synth/wire.v create mode 100644 ecp5/synth/wire.ys diff --git a/ecp5/arch.cc b/ecp5/arch.cc index e80ad829..d0dc63f0 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -218,11 +218,14 @@ WireId Arch::getWireByName(IdString name) const for (int i = 0; i < loci->num_wires; i++) { if (std::strcmp(loci->wire_data[i].name.get(), basename.c_str()) == 0) { ret.index = i; + ret.location = loc; break; } } if (ret.index >= 0) wire_by_name[name] = ret; + else + ret.location = Location(); return ret; } @@ -278,7 +281,10 @@ void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const gb = false; } -delay_t Arch::estimateDelay(WireId src, WireId dst) const { return 1; } +delay_t Arch::estimateDelay(WireId src, WireId dst) const +{ + return abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y); +} // ----------------------------------------------------------------------- diff --git a/ecp5/synth/wire.v b/ecp5/synth/wire.v new file mode 100644 index 00000000..2af68ed2 --- /dev/null +++ b/ecp5/synth/wire.v @@ -0,0 +1,11 @@ +module top(input a_pin, output [3:0] led_pin); + + wire a; + wire [3:0] led; + + TRELLIS_IO #(.DIR("INPUT")) a_buf (.B(a_pin), .O(a)); + TRELLIS_IO #(.DIR("OUTPUT")) led_buf [3:0] (.B(led_pin), .I(led)); + + //assign led[0] = !a; + always @(posedge a) led[0] <= !led[0]; +endmodule diff --git a/ecp5/synth/wire.ys b/ecp5/synth/wire.ys new file mode 100644 index 00000000..f916588b --- /dev/null +++ b/ecp5/synth/wire.ys @@ -0,0 +1,9 @@ +read_verilog wire.v +read_verilog -lib cells.v +synth -top top +abc -lut 4 +techmap -map simple_map.v +splitnets +opt_clean +stat +write_json wire.json -- cgit v1.2.3 From 863c22620b58d1043a32cdc22b23c954afcccc10 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 8 Jul 2018 15:29:53 +0200 Subject: ecp5: Dump routing as a sanity check Signed-off-by: David Shah --- ecp5/main.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ecp5/main.cc b/ecp5/main.cc index 245d1cc3..c07e08de 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -139,6 +139,14 @@ int main(int argc, char *argv[]) ctx.check(); if (!route_design(&ctx) && !ctx.force) log_error("Routing design failed.\n"); + + // TEST BEGIN + for (auto pip : ctx.getPips()) { + if (!ctx.checkPipAvail(pip)) { + std::cout << ctx.getWireName(ctx.getPipSrcWire(pip)).str(&ctx) << " -> " << ctx.getWireName(ctx.getPipDstWire(pip)).str(&ctx) << std::endl; + } + } + // TEST END } #ifndef NO_PYTHON -- cgit v1.2.3 From 6cc6113d5a5e3a6463f3e3923efee613acc50579 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 8 Jul 2018 17:24:35 +0200 Subject: ecp5: Link libtrellis library to ecp5 binary Signed-off-by: David Shah --- ecp5/family.cmake | 8 ++++++++ ecp5/main.cc | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/ecp5/family.cmake b/ecp5/family.cmake index 7f528886..190a3345 100644 --- a/ecp5/family.cmake +++ b/ecp5/family.cmake @@ -39,3 +39,11 @@ else() endforeach (target) endforeach (dev) endif() + +find_library(TRELLIS_LIB trellis PATHS ${TRELLIS_ROOT}/libtrellis) + +foreach (target ${family_targets}) + target_compile_definitions(${target} PRIVATE TRELLIS_ROOT="${TRELLIS_ROOT}") + target_include_directories(${target} PRIVATE ${TRELLIS_ROOT}/libtrellis/include) + target_link_libraries(${target} PRIVATE ${TRELLIS_LIB}) +endforeach (target) diff --git a/ecp5/main.cc b/ecp5/main.cc index c07e08de..c16e23bb 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -31,6 +31,9 @@ #include #include #include + +#include "Database.hpp" + #include "log.h" #include "nextpnr.h" #include "version.h" @@ -99,6 +102,9 @@ int main(int argc, char *argv[]) "sha1 " GIT_COMMIT_HASH_STR ")\n"; return 1; } + + Trellis::load_database(TRELLIS_ROOT"/database"); + ArchArgs args; args.type = ArchArgs::LFE5U_25F; args.package = "CABGA381"; -- cgit v1.2.3 From 54f06fdf72307579a6808a051f81a6d67e89f0ff Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 8 Jul 2018 18:25:53 +0200 Subject: ecp5: Adding tiletypes to database Signed-off-by: David Shah --- ecp5/arch.h | 6 ++++++ ecp5/main.cc | 10 ++++++++-- ecp5/trellis_import.py | 5 +++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/ecp5/arch.h b/ecp5/arch.h index 029caef0..219a960e 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -102,6 +102,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { int32_t num_location_types; RelPtr locations; RelPtr location_type; + RelPtr> tiletype_names; }); #if defined(_MSC_VER) @@ -698,6 +699,11 @@ struct Arch : BaseCtx return range; } + std::string getPipTiletype(PipId pip) const + { + return chip_info->tiletype_names[locInfo(pip)->pip_data[pip.index].tile_type].get(); + } + BelId getPackagePinBel(const std::string &pin) const; std::string getBelPackagePin(BelId bel) const; diff --git a/ecp5/main.cc b/ecp5/main.cc index c16e23bb..6456a11e 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -33,6 +33,8 @@ #include #include "Database.hpp" +#include "Chip.hpp" +#include "Tile.hpp" #include "log.h" #include "nextpnr.h" @@ -103,7 +105,7 @@ int main(int argc, char *argv[]) return 1; } - Trellis::load_database(TRELLIS_ROOT"/database"); + Trellis::load_database(TRELLIS_ROOT "/database"); ArchArgs args; args.type = ArchArgs::LFE5U_25F; @@ -147,9 +149,13 @@ int main(int argc, char *argv[]) log_error("Routing design failed.\n"); // TEST BEGIN + Trellis::Chip c("LFE5U-25F"); for (auto pip : ctx.getPips()) { if (!ctx.checkPipAvail(pip)) { - std::cout << ctx.getWireName(ctx.getPipSrcWire(pip)).str(&ctx) << " -> " << ctx.getWireName(ctx.getPipDstWire(pip)).str(&ctx) << std::endl; + auto tile = c.get_tile_by_position_and_type(pip.location.y, pip.location.x, ctx.getPipTiletype(pip)); + std::cout << ctx.getWireName(ctx.getPipSrcWire(pip)).str(&ctx) << " -> " + << ctx.getWireName(ctx.getPipDstWire(pip)).str(&ctx) << " [in tile " + << tile->info.name << "]" << std::endl; } } // TEST END diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index 62aa4d81..6ff929f7 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -592,6 +592,10 @@ def write_database(dev_name, endianness): for x in range(0, max_col+1): bba.u32(type_at_location[x, y], "loctype") + bba.l("tiletype_names", "RelPtr") + for tt in tiletype_names: + bba.s(tt, "name") + bba.l("chip_info") bba.u32(max_col + 1, "width") bba.u32(max_row + 1, "height") @@ -599,6 +603,7 @@ def write_database(dev_name, endianness): bba.u32(len(location_types), "num_location_types") bba.r("locations", "locations") bba.r("location_types", "location_type") + bba.r("tiletype_names", "tiletype_names") bba.finalize() return bba -- cgit v1.2.3 From de82ecad592a98a7061bfccb62d3df40d50b1354 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 8 Jul 2018 18:36:59 +0200 Subject: ecp5: Make target device 45k on account of current hardware access Signed-off-by: David Shah --- ecp5/arch.cc | 8 ++++---- ecp5/family.cmake | 2 +- ecp5/main.cc | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ecp5/arch.cc b/ecp5/arch.cc index d0dc63f0..47546ccc 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -92,16 +92,16 @@ static const ChipInfoPOD *get_chip_info(const RelPtr *ptr) { return void load_chipdb(); #endif -#define LFE5U_25F_ONLY +#define LFE5U_45F_ONLY Arch::Arch(ArchArgs args) : args(args) { #if defined(_MSC_VER) load_chipdb(); #endif -#ifdef LFE5U_25F_ONLY - if (args.type == ArchArgs::LFE5U_25F) { - chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_25k)); +#ifdef LFE5U_45F_ONLY + if (args.type == ArchArgs::LFE5U_45F) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_45k)); } else { log_error("Unsupported ECP5 chip type.\n"); } diff --git a/ecp5/family.cmake b/ecp5/family.cmake index 190a3345..f58cdbb2 100644 --- a/ecp5/family.cmake +++ b/ecp5/family.cmake @@ -1,5 +1,5 @@ -set(devices 25k) +set(devices 45k) set(DB_PY ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/trellis_import.py) diff --git a/ecp5/main.cc b/ecp5/main.cc index 6456a11e..ae229d51 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -108,7 +108,7 @@ int main(int argc, char *argv[]) Trellis::load_database(TRELLIS_ROOT "/database"); ArchArgs args; - args.type = ArchArgs::LFE5U_25F; + args.type = ArchArgs::LFE5U_45F; args.package = "CABGA381"; args.speed = 6; Context ctx(args); @@ -149,7 +149,7 @@ int main(int argc, char *argv[]) log_error("Routing design failed.\n"); // TEST BEGIN - Trellis::Chip c("LFE5U-25F"); + Trellis::Chip c("LFE5U-45F"); for (auto pip : ctx.getPips()) { if (!ctx.checkPipAvail(pip)) { auto tile = c.get_tile_by_position_and_type(pip.location.y, pip.location.x, ctx.getPipTiletype(pip)); -- cgit v1.2.3 From bad926bcc3e4d77bcb76d54eff689a91233c71fb Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 9 Jul 2018 12:02:31 +0200 Subject: ecp5: Adding bitstream gen for pips and LUT init Signed-off-by: David Shah --- ecp5/arch.cc | 6 +-- ecp5/arch.h | 2 + ecp5/bitstream.cc | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++ ecp5/bitstream.h | 32 ++++++++++++ ecp5/main.cc | 30 ++++++----- ecp5/synth/.gitignore | 2 + 6 files changed, 192 insertions(+), 15 deletions(-) create mode 100644 ecp5/bitstream.cc create mode 100644 ecp5/bitstream.h diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 47546ccc..7217af78 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -124,11 +124,11 @@ std::string Arch::getChipName() { if (args.type == ArchArgs::LFE5U_25F) { - return "Lattice LFE5U-25F"; + return "LFE5U-25F"; } else if (args.type == ArchArgs::LFE5U_45F) { - return "Lattice LFE5U-45F"; + return "LFE5U-45F"; } else if (args.type == ArchArgs::LFE5U_85F) { - return "Lattice LFE5U-85F"; + return "LFE5U-85F"; } else { log_error("Unknown chip\n"); } diff --git a/ecp5/arch.h b/ecp5/arch.h index 219a960e..cc63eeaa 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -704,6 +704,8 @@ struct Arch : BaseCtx return chip_info->tiletype_names[locInfo(pip)->pip_data[pip.index].tile_type].get(); } + int8_t getPipType(PipId pip) const { return locInfo(pip)->pip_data[pip.index].pip_type; } + BelId getPackagePinBel(const std::string &pin) const; std::string getBelPackagePin(BelId bel) const; diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc new file mode 100644 index 00000000..e44892ed --- /dev/null +++ b/ecp5/bitstream.cc @@ -0,0 +1,135 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 David Shah + * + * 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 "bitstream.h" + +// From Project Trellis +#include "BitDatabase.hpp" +#include "Bitstream.hpp" +#include "Chip.hpp" +#include "ChipConfig.hpp" +#include "Tile.hpp" +#include "TileConfig.hpp" + +#include +#include + +#include "log.h" +#include "util.h" + +NEXTPNR_NAMESPACE_BEGIN + +// Convert an absolute wire name to a relative Trellis one +static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire) +{ + std::string basename = ctx->locInfo(wire)->wire_data[wire.index].name.get(); + std::string prefix2 = basename.substr(0, 2); + if (prefix2 == "G_" || prefix2 == "L_" || prefix2 == "R_") + return basename; + if (loc == wire.location) + return basename; + std::string rel_prefix; + if (wire.location.y < loc.y) + rel_prefix += "N" + to_string(loc.y - wire.location.y); + if (wire.location.y > loc.y) + rel_prefix += "S" + to_string(wire.location.y - loc.y); + if (wire.location.x > loc.x) + rel_prefix += "E" + to_string(wire.location.x - loc.x); + if (wire.location.x < loc.x) + rel_prefix += "W" + to_string(loc.x - wire.location.x); + return rel_prefix + "_" + basename; +} + +static std::vector int_to_bitvector(int val, int size) +{ + std::vector bv; + for (int i = 0; i < size; i++) { + bv.push_back((val & (1 << i)) != 0); + } + return bv; +} + +void write_bitstream(Context *ctx, std::string base_config_file, std::string text_config_file, + std::string bitstream_file) +{ + Trellis::Chip empty_chip(ctx->getChipName()); + Trellis::ChipConfig cc; + if (!base_config_file.empty()) { + std::ifstream config_file(base_config_file); + if (!config_file) { + log_error("failed to open base config file '%s'\n", base_config_file.c_str()); + } + std::string str((std::istreambuf_iterator(config_file)), std::istreambuf_iterator()); + cc = Trellis::ChipConfig::from_string(str); + } else { + cc.chip_name = ctx->getChipName(); + // TODO: .bit metadata + } + + // Add all set, configurable pips to the config + for (auto pip : ctx->getPips()) { + if (ctx->getBoundPipNet(pip) != IdString()) { + if (ctx->getPipType(pip) == 0) { // ignore fixed pips + auto tile = empty_chip.get_tile_by_position_and_type(pip.location.y, pip.location.x, + ctx->getPipTiletype(pip)); + std::string source = get_trellis_wirename(ctx, pip.location, ctx->getPipSrcWire(pip)); + std::string sink = get_trellis_wirename(ctx, pip.location, ctx->getPipDstWire(pip)); + cc.tiles[tile->info.name].add_arc(sink, source); + } + } + } + + // Set all bankref tiles to 3.3V (TODO) + for (const auto &tile : empty_chip.tiles) { + std::string type = tile.second->info.type; + if (type.find("BANKREF") != std::string::npos && type != "BANKREF8") { + cc.tiles[type].add_enum("BANK.VCCIO", "3V3"); + } + } + + // Configure slices + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); + if (ci->bel == BelId()) { + log_warning("found unplaced cell '%s' during bitstream gen\n", ci->name.c_str(ctx)); + } + BelId bel = ci->bel; + if (ci->type == ctx->id("TRELLIS_SLICE")) { + auto tile = empty_chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, "PLC2"); + std::string tname = tile->info.name; + std::string slice = ctx->locInfo(bel)->bel_data[bel.index].name.get(); + int lut0_init = int_or_default(ci->params, ctx->id("LUT0_INITVAL")); + int lut1_init = int_or_default(ci->params, ctx->id("LUT1_INITVAL")); + cc.tiles[tname].add_word(slice + ".K0.INIT", int_to_bitvector(lut0_init, 16)); + cc.tiles[tname].add_word(slice + ".K1.INIT", int_to_bitvector(lut1_init, 16)); + } + } + + // Configure chip + Trellis::Chip cfg_chip = cc.to_chip(); + if (!bitstream_file.empty()) { + Trellis::Bitstream::serialise_chip(cfg_chip).write_bit_py(bitstream_file); + } + if (!text_config_file.empty()) { + std::ofstream out_config(text_config_file); + out_config << cc.to_string(); + } +} + +NEXTPNR_NAMESPACE_END diff --git a/ecp5/bitstream.h b/ecp5/bitstream.h new file mode 100644 index 00000000..62617470 --- /dev/null +++ b/ecp5/bitstream.h @@ -0,0 +1,32 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 David Shah + * + * 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. + * + */ + +#ifndef BITSTREAM_H +#define BITSTREAM_H + +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +void write_bitstream(Context *ctx, std::string base_config_file = "", std::string text_config_file = "", + std::string bitstream_file = ""); + +NEXTPNR_NAMESPACE_END + +#endif // BITSTREAM_H diff --git a/ecp5/main.cc b/ecp5/main.cc index ae229d51..caa28563 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -32,14 +32,15 @@ #include #include -#include "Database.hpp" #include "Chip.hpp" +#include "Database.hpp" #include "Tile.hpp" #include "log.h" #include "nextpnr.h" #include "version.h" +#include "bitstream.h" #include "design_utils.h" #include "jsonparse.h" #include "pack.h" @@ -68,6 +69,10 @@ int main(int argc, char *argv[]) options.add_options()("json", po::value(), "JSON design file to ingest"); options.add_options()("seed", po::value(), "seed value for random number generator"); + options.add_options()("basecfg", po::value(), "base chip configuration in Trellis text format"); + options.add_options()("bit", po::value(), "bitstream file to write"); + options.add_options()("textcfg", po::value(), "textual configuration in Trellis format to write"); + po::positional_options_description pos; #ifndef NO_PYTHON options.add_options()("run", po::value>(), "python file to execute"); @@ -148,17 +153,18 @@ int main(int argc, char *argv[]) if (!route_design(&ctx) && !ctx.force) log_error("Routing design failed.\n"); - // TEST BEGIN - Trellis::Chip c("LFE5U-45F"); - for (auto pip : ctx.getPips()) { - if (!ctx.checkPipAvail(pip)) { - auto tile = c.get_tile_by_position_and_type(pip.location.y, pip.location.x, ctx.getPipTiletype(pip)); - std::cout << ctx.getWireName(ctx.getPipSrcWire(pip)).str(&ctx) << " -> " - << ctx.getWireName(ctx.getPipDstWire(pip)).str(&ctx) << " [in tile " - << tile->info.name << "]" << std::endl; - } - } - // TEST END + std::string basecfg; + if (vm.count("basecfg")) + basecfg = vm["basecfg"].as(); + + std::string bitstream; + if (vm.count("bit")) + bitstream = vm["bit"].as(); + + std::string textcfg; + if (vm.count("textcfg")) + textcfg = vm["textcfg"].as(); + write_bitstream(&ctx, basecfg, textcfg, bitstream); } #ifndef NO_PYTHON diff --git a/ecp5/synth/.gitignore b/ecp5/synth/.gitignore index e69de29b..23844244 100644 --- a/ecp5/synth/.gitignore +++ b/ecp5/synth/.gitignore @@ -0,0 +1,2 @@ +*.config +*.bit -- cgit v1.2.3 From b397dd80712005e4c71b492e27d6af35e6bdc1e9 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 9 Jul 2018 12:55:56 +0200 Subject: ecp5: Adding bitstream gen for slice config Signed-off-by: David Shah --- common/util.h | 12 ++++++++++++ ecp5/bitstream.cc | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/common/util.h b/common/util.h index 60eb35af..b492b98c 100644 --- a/common/util.h +++ b/common/util.h @@ -39,6 +39,18 @@ ValueType get_or_default(const Container &ct, const KeyType &key, ValueType def return found->second; }; +// Get a value from a map-style container, returning default if value is not +// found (forces string) +template +std::string str_or_default(const Container &ct, const KeyType &key, std::string def = "") +{ + auto found = ct.find(key); + if (found == ct.end()) + return def; + else + return found->second; +}; + // Get a value from a map-style container, converting to int, and returning // default if value is not found template int int_or_default(const Container &ct, const KeyType &key, int def = 0) diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index e44892ed..5f9294c2 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -118,6 +118,20 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex int lut1_init = int_or_default(ci->params, ctx->id("LUT1_INITVAL")); cc.tiles[tname].add_word(slice + ".K0.INIT", int_to_bitvector(lut0_init, 16)); cc.tiles[tname].add_word(slice + ".K1.INIT", int_to_bitvector(lut1_init, 16)); + cc.tiles[tname].add_enum(slice + ".MODE", str_or_default(ci->params, ctx->id("MODE"), "LOGIC")); + cc.tiles[tname].add_enum(slice + ".GSR", str_or_default(ci->params, ctx->id("GSR"), "ENABLED")); + cc.tiles[tname].add_enum(slice + ".REG0.SD", str_or_default(ci->params, ctx->id("REG0_SD"), "0")); + cc.tiles[tname].add_enum(slice + ".REG1.SD", str_or_default(ci->params, ctx->id("REG1_SD"), "0")); + cc.tiles[tname].add_enum(slice + ".REG0.REGSET", + str_or_default(ci->params, ctx->id("REG0_REGSET"), "RESET")); + cc.tiles[tname].add_enum(slice + ".REG1.REGSET", + str_or_default(ci->params, ctx->id("REG1_REGSET"), "RESET")); + cc.tiles[tname].add_enum(slice + ".CEMUX", str_or_default(ci->params, ctx->id("CEMUX"), "1")); + // TODO: CLKMUX, CEMUX, carry + } else if (ci->type == ctx->id("TRELLIS_IO")) { + // TODO: IO config + } else { + NPNR_ASSERT_FALSE("unsupported cell type"); } } -- cgit v1.2.3 From 29d65bd368fa32f7ea13515902df752d30ec4f39 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 10 Jul 2018 11:24:30 +0200 Subject: ecp5: Working on bitstream gen Signed-off-by: David Shah --- CMakeLists.txt | 2 +- common/util.h | 1 + ecp5/bitstream.cc | 106 +++++++++- ecp5/synth/.gitignore | 1 - ecp5/synth/ulx3s.v | 16 ++ ecp5/synth/ulx3s.ys | 9 + ecp5/synth/ulx3s_empty.config | 453 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 585 insertions(+), 3 deletions(-) create mode 100644 ecp5/synth/ulx3s.v create mode 100644 ecp5/synth/ulx3s.ys create mode 100644 ecp5/synth/ulx3s_empty.config diff --git a/CMakeLists.txt b/CMakeLists.txt index 32063af6..f9dc10ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /W4 /wd4100 /wd4244 set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /W4 /wd4100 /wd4244 /wd4125 /wd4800 /wd4456 /wd4458 /wd4305 /wd4459 /wd4121 /wd4996 /wd4127") else() set(CMAKE_CXX_FLAGS_DEBUG "-Wall -fPIC -ggdb") -set(CMAKE_CXX_FLAGS_RELEASE "-Wall -fPIC -O3 -g") +set(CMAKE_CXX_FLAGS_RELEASE "-Wall -fPIC -O0 -ggdb") endif() set(CMAKE_DEFIN) diff --git a/common/util.h b/common/util.h index b492b98c..8f361dc8 100644 --- a/common/util.h +++ b/common/util.h @@ -96,6 +96,7 @@ inline const NetInfo *get_net_or_empty(const CellInfo *cell, const IdString port else return nullptr; }; + NEXTPNR_NAMESPACE_END #endif diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index 5f9294c2..04bbc24f 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -33,6 +33,8 @@ #include "log.h" #include "util.h" +#define fmt_str(x) (static_cast(std::ostringstream() << x).str()) + NEXTPNR_NAMESPACE_BEGIN // Convert an absolute wire name to a relative Trellis one @@ -65,11 +67,97 @@ static std::vector int_to_bitvector(int val, int size) return bv; } +// Get the PIO tile corresponding to a PIO bel +static std::string get_pio_tile(Context *ctx, Trellis::Chip &chip, BelId bel) +{ + static const std::set pioabcd_l = {"PICL1", "PICL1_DQS0", "PICL1_DQS3"}; + static const std::set pioabcd_r = {"PICR1", "PICR1_DQS0", "PICR1_DQS3"}; + static const std::set pioa_b = {"PICB0", "EFB0_PICB0", "EFB2_PICB0"}; + static const std::set piob_b = {"PICB1", "EFB1_PICB1", "EFB3_PICB1"}; + + std::string pio_name = ctx->locInfo(bel)->bel_data[bel.index].name.get(); + if (bel.location.y == 0) { + if (pio_name == "PIOA") { + return chip.get_tile_by_position_and_type(0, bel.location.x, "PIOT0")->info.name; + } else if (pio_name == "PIOB") { + return chip.get_tile_by_position_and_type(0, bel.location.x + 1, "PIOT1")->info.name; + } else { + NPNR_ASSERT_FALSE("bad PIO location"); + } + } else if (bel.location.y == ctx->chip_info->height - 1) { + if (pio_name == "PIOA") { + return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, pioa_b)->info.name; + } else if (pio_name == "PIOB") { + return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x + 1, piob_b)->info.name; + } else { + NPNR_ASSERT_FALSE("bad PIO location"); + } + } else if (bel.location.x == 0) { + return chip.get_tile_by_position_and_type(bel.location.y + 1, bel.location.x, pioabcd_l)->info.name; + } else if (bel.location.x == ctx->chip_info->width - 1) { + return chip.get_tile_by_position_and_type(bel.location.y + 1, bel.location.x, pioabcd_r)->info.name; + } else { + NPNR_ASSERT_FALSE("bad PIO location"); + } +} + +// Get the PIC tile corresponding to a PIO bel +static std::string get_pic_tile(Context *ctx, Trellis::Chip &chip, BelId bel) +{ + static const std::set picab_l = {"PICL0", "PICL0_DQS2"}; + static const std::set piccd_l = {"PICL2", "PICL2_DQS1", "MIB_CIB_LR"}; + static const std::set picab_r = {"PICR0", "PICR0_DQS2"}; + static const std::set piccd_r = {"PICR2", "PICR2_DQS1", "MIB_CIB_LR_A"}; + + static const std::set pica_b = {"PICB0", "EFB0_PICB0", "EFB2_PICB0"}; + static const std::set picb_b = {"PICB1", "EFB1_PICB1", "EFB3_PICB1"}; + + std::string pio_name = ctx->locInfo(bel)->bel_data[bel.index].name.get(); + if (bel.location.y == 0) { + if (pio_name == "PIOA") { + return chip.get_tile_by_position_and_type(1, bel.location.x, "PICT0")->info.name; + } else if (pio_name == "PIOB") { + return chip.get_tile_by_position_and_type(1, bel.location.x + 1, "PICT1")->info.name; + } else { + NPNR_ASSERT_FALSE("bad PIO location"); + } + } else if (bel.location.y == ctx->chip_info->height - 1) { + if (pio_name == "PIOA") { + return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, pica_b)->info.name; + } else if (pio_name == "PIOB") { + return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x + 1, picb_b)->info.name; + } else { + NPNR_ASSERT_FALSE("bad PIO location"); + } + } else if (bel.location.x == 0) { + if (pio_name == "PIOA" || pio_name == "PIOB") { + return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, picab_l)->info.name; + } else if (pio_name == "PIOC" || pio_name == "PIOD") { + return chip.get_tile_by_position_and_type(bel.location.y + 2, bel.location.x, piccd_l)->info.name; + } else { + NPNR_ASSERT_FALSE("bad PIO location"); + } + } else if (bel.location.x == ctx->chip_info->width - 1) { + if (pio_name == "PIOA" || pio_name == "PIOB") { + return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, picab_r)->info.name; + } else if (pio_name == "PIOC" || pio_name == "PIOD") { + return chip.get_tile_by_position_and_type(bel.location.y + 2, bel.location.x, piccd_r)->info.name; + } else { + NPNR_ASSERT_FALSE("bad PIO location"); + } + } else { + NPNR_ASSERT_FALSE("bad PIO location"); + } +} + void write_bitstream(Context *ctx, std::string base_config_file, std::string text_config_file, std::string bitstream_file) { Trellis::Chip empty_chip(ctx->getChipName()); Trellis::ChipConfig cc; + + std::set cib_tiles = {"CIB", "CIB_LR", "CIB_LR_S", "CIB_EFB0", "CIB_EFB1"}; + if (!base_config_file.empty()) { std::ifstream config_file(base_config_file); if (!config_file) { @@ -129,7 +217,23 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex cc.tiles[tname].add_enum(slice + ".CEMUX", str_or_default(ci->params, ctx->id("CEMUX"), "1")); // TODO: CLKMUX, CEMUX, carry } else if (ci->type == ctx->id("TRELLIS_IO")) { - // TODO: IO config + std::string pio = ctx->locInfo(bel)->bel_data[bel.index].name.get(); + std::string iotype = str_or_default(ci->attrs, ctx->id("IO_TYPE"), "LVCMOS33"); + std::string dir = str_or_default(ci->params, ctx->id("DIR"), "INPUT"); + std::string pio_tile = get_pio_tile(ctx, empty_chip, bel); + std::string pic_tile = get_pic_tile(ctx, empty_chip, bel); + cc.tiles[pio_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype); + cc.tiles[pic_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype); + if (dir != "INPUT" && (ci->ports.find(ctx->id("T")) == ci->ports.end() || ci->ports.at(ctx->id("T")).net == nullptr)) { + // Tie tristate low if unconnected for outputs or bidir + std::string jpt = fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/JPADDT" << pio.back()); + WireId jpt_wire = ctx->getWireByName(ctx->id(jpt)); + PipId jpt_pip = *ctx->getPipsUphill(jpt_wire).begin(); + WireId cib_wire = ctx->getPipSrcWire(jpt_pip); + std::string cib_tile = empty_chip.get_tile_by_position_and_type(cib_wire.location.y, cib_wire.location.x, cib_tiles)->info.name; + std::string cib_wirename = ctx->locInfo(cib_wire)->wire_data[cib_wire.index].name.get(); + cc.tiles[cib_tile].add_enum("CIB." + cib_wirename + "MUX", "0"); + } } else { NPNR_ASSERT_FALSE("unsupported cell type"); } diff --git a/ecp5/synth/.gitignore b/ecp5/synth/.gitignore index 23844244..5b3bf578 100644 --- a/ecp5/synth/.gitignore +++ b/ecp5/synth/.gitignore @@ -1,2 +1 @@ -*.config *.bit diff --git a/ecp5/synth/ulx3s.v b/ecp5/synth/ulx3s.v new file mode 100644 index 00000000..7f0786f5 --- /dev/null +++ b/ecp5/synth/ulx3s.v @@ -0,0 +1,16 @@ +module top(input a_pin, output led_pin, output gpio0_pin); + + wire a; + wire led; + wire gpio0; + (* BEL="X90/Y65/PIOB" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("INPUT")) a_buf (.B(a_pin), .O(a)); + (* BEL="X0/Y23/PIOC" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf (.B(led_pin), .I(led), .T(t)); + (* BEL="X0/Y62/PIOD" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) gpio0_buf (.B(gpio0_pin), .I(gpio0), .T(t)); + assign led = !a; + wire t; + TRELLIS_SLICE #(.MODE("LOGIC"), .LUT0_INITVAL(16'h0000)) gnd (.F0(t)); + TRELLIS_SLICE #(.MODE("LOGIC"), .LUT0_INITVAL(16'hFFFF)) vcc (.F0(gpio0)); +endmodule diff --git a/ecp5/synth/ulx3s.ys b/ecp5/synth/ulx3s.ys new file mode 100644 index 00000000..d741c985 --- /dev/null +++ b/ecp5/synth/ulx3s.ys @@ -0,0 +1,9 @@ +read_verilog ulx3s.v +read_verilog -lib cells.v +synth -top top +abc -lut 4 +techmap -map simple_map.v +splitnets +opt_clean +stat +write_json ulx3s.json diff --git a/ecp5/synth/ulx3s_empty.config b/ecp5/synth/ulx3s_empty.config new file mode 100644 index 00000000..8b641943 --- /dev/null +++ b/ecp5/synth/ulx3s_empty.config @@ -0,0 +1,453 @@ +.device LFE5U-45F + +.comment Lattice Semiconductor Corporation Bitstream +.comment Version: Diamond (64-bit) 3.10.0.111.2 +.comment Bitstream Status: Final Version 10.25 +.comment Design name: wire_impl1.ncd +.comment Architecture: sa5p00 +.comment Part: LFE5U-45F-6CABGA381 +.comment Date: Sun Jul 8 15:46:42 2018 +.comment Rows: 9470 +.comment Cols: 846 +.comment Bits: 8011620 +.comment Readback: Off +.comment Security: Off +.comment Bitstream CRC: 0x66BA + +.tile CIB_R10C3:PVT_COUNT2 +unknown: F2B0 +unknown: F3B0 +unknown: F5B0 +unknown: F11B0 +unknown: F13B0 + +.tile CIB_R5C1:CIB_PLL1 +enum: CIB.JA3MUX 0 +enum: CIB.JB3MUX 0 + + +.tile CIB_R5C89:CIB_PLL1 +enum: CIB.JA3MUX 0 +enum: CIB.JB3MUX 0 + + +.tile CIB_R70C3:CIB_PLL3 +enum: CIB.JA3MUX 0 +enum: CIB.JB3MUX 0 + + +.tile CIB_R70C42:VCIB_DCU0 +enum: CIB.JA1MUX 0 +enum: CIB.JA3MUX 0 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC2MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C43:VCIB_DCUA +enum: CIB.JA1MUX 0 +enum: CIB.JA3MUX 0 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC2MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C44:VCIB_DCUB +enum: CIB.JA1MUX 0 +enum: CIB.JA3MUX 0 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC2MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C45:VCIB_DCUC +enum: CIB.JA1MUX 0 +enum: CIB.JA3MUX 0 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC2MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C46:VCIB_DCUD +enum: CIB.JA1MUX 0 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC2MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C47:VCIB_DCUF +enum: CIB.JA1MUX 0 +enum: CIB.JA3MUX 0 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC2MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C48:VCIB_DCU3 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C49:VCIB_DCU2 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C50:VCIB_DCUG +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C51:VCIB_DCUH +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C52:VCIB_DCUI +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C53:VCIB_DCU1 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 + + +.tile CIB_R70C69:VCIB_DCU0 +enum: CIB.JA1MUX 0 +enum: CIB.JA3MUX 0 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC2MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C6:CIB_EFB0 +enum: CIB.JB3MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C70:VCIB_DCUA +enum: CIB.JA1MUX 0 +enum: CIB.JA3MUX 0 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC2MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C71:VCIB_DCUB +enum: CIB.JA1MUX 0 +enum: CIB.JA3MUX 0 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC2MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C72:VCIB_DCUC +enum: CIB.JA1MUX 0 +enum: CIB.JA3MUX 0 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC2MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C73:VCIB_DCUD +enum: CIB.JA1MUX 0 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC2MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C74:VCIB_DCUF +enum: CIB.JA1MUX 0 +enum: CIB.JA3MUX 0 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC2MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C75:VCIB_DCU3 +enum: CIB.JA5MUX 0 +enum: CIB.JA7MUX 0 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JC0MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC6MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C76:VCIB_DCU2 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C77:VCIB_DCUG +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C78:VCIB_DCUH +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C79:VCIB_DCUI +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB7MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD6MUX 0 + + +.tile CIB_R70C7:CIB_EFB1 +enum: CIB.JA3MUX 0 +enum: CIB.JA4MUX 0 +enum: CIB.JA5MUX 0 +enum: CIB.JA6MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB4MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JB6MUX 0 +enum: CIB.JC3MUX 0 +enum: CIB.JC4MUX 0 +enum: CIB.JC5MUX 0 +enum: CIB.JD3MUX 0 +enum: CIB.JD4MUX 0 +enum: CIB.JD5MUX 0 + + +.tile CIB_R70C80:VCIB_DCU1 +enum: CIB.JB1MUX 0 +enum: CIB.JB3MUX 0 +enum: CIB.JB5MUX 0 +enum: CIB.JD0MUX 0 +enum: CIB.JD2MUX 0 + + +.tile CIB_R70C87:CIB_PLL3 +enum: CIB.JA3MUX 0 +enum: CIB.JB3MUX 0 + + +.tile MIB_R10C40:CMUX_UL_0 +arc: G_DCS0CLK0 G_VPFN0000 + + +.tile MIB_R10C41:CMUX_UR_0 +arc: G_DCS0CLK1 G_VPFN0000 + + +.tile MIB_R58C40:CMUX_LL_0 +arc: G_DCS1CLK0 G_VPFN0000 + + +.tile MIB_R58C41:CMUX_LR_0 +arc: G_DCS1CLK1 G_VPFN0000 + + +.tile MIB_R71C4:EFB0_PICB0 +unknown: F54B1 +unknown: F56B1 +unknown: F82B1 +unknown: F94B1 + +.tile MIB_R71C3:BANKREF8 +unknown: F18B0 + -- cgit v1.2.3 From 98cdb6082d1f916bd47676c3e7f1feab6b585216 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 10 Jul 2018 11:57:58 +0200 Subject: ecp5: Bitstream progress Signed-off-by: David Shah --- ecp5/bitstream.cc | 2 +- ecp5/synth/cells.v | 2 +- ecp5/synth/simple_map.v | 6 +++--- ecp5/synth/ulx3s.v | 9 ++++----- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index 04bbc24f..f4f175bb 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -187,7 +187,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex for (const auto &tile : empty_chip.tiles) { std::string type = tile.second->info.type; if (type.find("BANKREF") != std::string::npos && type != "BANKREF8") { - cc.tiles[type].add_enum("BANK.VCCIO", "3V3"); + cc.tiles[tile.first].add_enum("BANK.VCCIO", "3V3"); } } diff --git a/ecp5/synth/cells.v b/ecp5/synth/cells.v index 2435713a..d2c6d560 100644 --- a/ecp5/synth/cells.v +++ b/ecp5/synth/cells.v @@ -27,7 +27,7 @@ parameter CCU2_INJECT1_1 = "NO"; endmodule -(* blackbox *) +(* blackbox *) (* keep *) module TRELLIS_IO( inout B, input I, diff --git a/ecp5/synth/simple_map.v b/ecp5/synth/simple_map.v index 4a50fd01..550fa92c 100644 --- a/ecp5/synth/simple_map.v +++ b/ecp5/synth/simple_map.v @@ -25,7 +25,7 @@ module \$lut (A, Y); if (WIDTH == 1) begin TRELLIS_SLICE #( .MODE("LOGIC"), - .LUT0_INITVAL(LUT) + .LUT0_INITVAL({8{LUT[1:0]}}) ) _TECHMAP_REPLACE_ ( .A0(A[0]), .F0(Y) @@ -34,7 +34,7 @@ module \$lut (A, Y); if (WIDTH == 2) begin TRELLIS_SLICE #( .MODE("LOGIC"), - .LUT0_INITVAL(LUT) + .LUT0_INITVAL({4{LUT[3:0]}}) ) _TECHMAP_REPLACE_ ( .A0(A[0]), .B0(A[1]), @@ -44,7 +44,7 @@ module \$lut (A, Y); if (WIDTH == 3) begin TRELLIS_SLICE #( .MODE("LOGIC"), - .LUT0_INITVAL(LUT) + .LUT0_INITVAL({2{LUT[7:0]}}) ) _TECHMAP_REPLACE_ ( .A0(A[0]), .B0(A[1]), diff --git a/ecp5/synth/ulx3s.v b/ecp5/synth/ulx3s.v index 7f0786f5..25535e35 100644 --- a/ecp5/synth/ulx3s.v +++ b/ecp5/synth/ulx3s.v @@ -3,14 +3,13 @@ module top(input a_pin, output led_pin, output gpio0_pin); wire a; wire led; wire gpio0; - (* BEL="X90/Y65/PIOB" *) (* IO_TYPE="LVCMOS33" *) + (* BEL="X6/Y0/PIOB" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("INPUT")) a_buf (.B(a_pin), .O(a)); (* BEL="X0/Y23/PIOC" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("OUTPUT")) led_buf (.B(led_pin), .I(led), .T(t)); + TRELLIS_IO #(.DIR("OUTPUT")) led_buf (.B(led_pin), .I(led)); (* BEL="X0/Y62/PIOD" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("OUTPUT")) gpio0_buf (.B(gpio0_pin), .I(gpio0), .T(t)); + TRELLIS_IO #(.DIR("OUTPUT")) gpio0_buf (.B(gpio0_pin), .I(gpio0)); assign led = !a; - wire t; - TRELLIS_SLICE #(.MODE("LOGIC"), .LUT0_INITVAL(16'h0000)) gnd (.F0(t)); + TRELLIS_SLICE #(.MODE("LOGIC"), .LUT0_INITVAL(16'hFFFF)) vcc (.F0(gpio0)); endmodule -- cgit v1.2.3 From 1830c9372e9bb959cb886c8271d64778550a7ebb Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 10 Jul 2018 12:31:58 +0200 Subject: ecp5: *** Blinky working *** Signed-off-by: David Shah --- CMakeLists.txt | 2 +- ecp5/bitstream.cc | 3 +++ ecp5/synth/blinky.v | 22 ++++++++++++++++++++-- ecp5/synth/ulx3s.v | 11 +++++++---- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f9dc10ec..32063af6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /W4 /wd4100 /wd4244 set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /W4 /wd4100 /wd4244 /wd4125 /wd4800 /wd4456 /wd4458 /wd4305 /wd4459 /wd4121 /wd4996 /wd4127") else() set(CMAKE_CXX_FLAGS_DEBUG "-Wall -fPIC -ggdb") -set(CMAKE_CXX_FLAGS_RELEASE "-Wall -fPIC -O0 -ggdb") +set(CMAKE_CXX_FLAGS_RELEASE "-Wall -fPIC -O3 -g") endif() set(CMAKE_DEFIN) diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index f4f175bb..0e8d4aa4 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -234,6 +234,9 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex std::string cib_wirename = ctx->locInfo(cib_wire)->wire_data[cib_wire.index].name.get(); cc.tiles[cib_tile].add_enum("CIB." + cib_wirename + "MUX", "0"); } + if (dir == "INPUT") { + cc.tiles[pio_tile].add_enum(pio + ".HYSTERESIS", "ON"); + } } else { NPNR_ASSERT_FALSE("unsupported cell type"); } diff --git a/ecp5/synth/blinky.v b/ecp5/synth/blinky.v index aba58801..bda627cc 100644 --- a/ecp5/synth/blinky.v +++ b/ecp5/synth/blinky.v @@ -1,10 +1,25 @@ -module top(input clk_pin, output [3:0] led_pin); +module top(input clk_pin, output [3:0] led_pin, output gpio0_pin); wire clk; wire [3:0] led; + wire gpio0; + + (* BEL="X0/Y35/PIOA" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("INPUT")) clk_buf (.B(clk_pin), .O(clk)); - TRELLIS_IO #(.DIR("OUTPUT")) led_buf [3:0] (.B(led_pin), .I(led)); + + (* BEL="X0/Y23/PIOC" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_0 (.B(led_pin[0]), .I(led[0])); + (* BEL="X0/Y23/PIOD" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_1 (.B(led_pin[1]), .I(led[1])); + (* BEL="X0/Y26/PIOA" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_2 (.B(led_pin[2]), .I(led[2])); + (* BEL="X0/Y26/PIOC" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_3 (.B(led_pin[3]), .I(led[3])); + + + (* BEL="X0/Y62/PIOD" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) gpio0_buf (.B(gpio0_pin), .I(gpio0)); reg [25:0] ctr = 0; @@ -13,4 +28,7 @@ module top(input clk_pin, output [3:0] led_pin); assign led = ctr[25:22]; + // Tie GPIO0, keep board from rebooting + TRELLIS_SLICE #(.MODE("LOGIC"), .LUT0_INITVAL(16'hFFFF)) vcc (.F0(gpio0)); + endmodule diff --git a/ecp5/synth/ulx3s.v b/ecp5/synth/ulx3s.v index 25535e35..486366fa 100644 --- a/ecp5/synth/ulx3s.v +++ b/ecp5/synth/ulx3s.v @@ -1,15 +1,18 @@ -module top(input a_pin, output led_pin, output gpio0_pin); +module top(input a_pin, output led_pin, output led2_pin, output gpio0_pin); wire a; - wire led; + wire led, led2; wire gpio0; - (* BEL="X6/Y0/PIOB" *) (* IO_TYPE="LVCMOS33" *) + (* BEL="X90/Y65/PIOB" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("INPUT")) a_buf (.B(a_pin), .O(a)); (* BEL="X0/Y23/PIOC" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) led_buf (.B(led_pin), .I(led)); + (* BEL="X0/Y26/PIOA" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led2_buf (.B(led2_pin), .I(led2)); (* BEL="X0/Y62/PIOD" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) gpio0_buf (.B(gpio0_pin), .I(gpio0)); - assign led = !a; + assign led = a; + assign led2 = !a; TRELLIS_SLICE #(.MODE("LOGIC"), .LUT0_INITVAL(16'hFFFF)) vcc (.F0(gpio0)); endmodule -- cgit v1.2.3 From 9a2e8caf1c40ede0922a9c492e5c774ec66e61d3 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 10 Jul 2018 14:02:01 +0200 Subject: ecp5: Buttons working Signed-off-by: David Shah --- ecp5/synth/blinky.v | 15 ++++++++++++--- ecp5/synth/ulx3s.v | 2 +- ecp5/trellis_import.py | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ecp5/synth/blinky.v b/ecp5/synth/blinky.v index bda627cc..11ba5e4c 100644 --- a/ecp5/synth/blinky.v +++ b/ecp5/synth/blinky.v @@ -1,7 +1,7 @@ module top(input clk_pin, output [3:0] led_pin, output gpio0_pin); wire clk; - wire [3:0] led; + wire [7:0] led; wire gpio0; @@ -17,16 +17,25 @@ module top(input clk_pin, output [3:0] led_pin, output gpio0_pin); (* BEL="X0/Y26/PIOC" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) led_buf_3 (.B(led_pin[3]), .I(led[3])); + (* BEL="X0/Y26/PIOB" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_4 (.B(led_pin[4]), .I(led[4])); + (* BEL="X0/Y32/PIOD" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_5 (.B(led_pin[5]), .I(led[5])); + (* BEL="X0/Y26/PIOD" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_6 (.B(led_pin[6]), .I(led[6])); + (* BEL="X0/Y29/PIOD" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_7 (.B(led_pin[7]), .I(led[7])); + (* BEL="X0/Y62/PIOD" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) gpio0_buf (.B(gpio0_pin), .I(gpio0)); - reg [25:0] ctr = 0; + reg [27:0] ctr = 0; always@(posedge clk) ctr <= ctr + 1'b1; - assign led = ctr[25:22]; + assign led = ctr[27:20]; // Tie GPIO0, keep board from rebooting TRELLIS_SLICE #(.MODE("LOGIC"), .LUT0_INITVAL(16'hFFFF)) vcc (.F0(gpio0)); diff --git a/ecp5/synth/ulx3s.v b/ecp5/synth/ulx3s.v index 486366fa..08f6e65b 100644 --- a/ecp5/synth/ulx3s.v +++ b/ecp5/synth/ulx3s.v @@ -3,7 +3,7 @@ module top(input a_pin, output led_pin, output led2_pin, output gpio0_pin); wire a; wire led, led2; wire gpio0; - (* BEL="X90/Y65/PIOB" *) (* IO_TYPE="LVCMOS33" *) + (* BEL="X4/Y71/PIOA" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("INPUT")) a_buf (.B(a_pin), .O(a)); (* BEL="X0/Y23/PIOC" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) led_buf (.B(led_pin), .I(led)); diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index 6ff929f7..60e48844 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -154,7 +154,7 @@ def add_bels(chip, x, y): num_slices = 4 elif "PICL0" in tt or "PICR0" in tt: num_pios = 4 - elif "PIOT0" in tt or "PIOB0" in tt: + elif "PIOT0" in tt or ("PICB0" in tt and "SPICB" not in tt): num_pios = 2 for i in range(num_slices): add_slice(x, y, i) -- cgit v1.2.3 From 610adfef7ea72493de7a6ff2de727b208cd88920 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 10 Jul 2018 14:21:37 +0200 Subject: ecp5: Make blinky more fancy Signed-off-by: David Shah --- ecp5/synth/blinky.v | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/ecp5/synth/blinky.v b/ecp5/synth/blinky.v index 11ba5e4c..5327ab35 100644 --- a/ecp5/synth/blinky.v +++ b/ecp5/synth/blinky.v @@ -30,12 +30,32 @@ module top(input clk_pin, output [3:0] led_pin, output gpio0_pin); (* BEL="X0/Y62/PIOD" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) gpio0_buf (.B(gpio0_pin), .I(gpio0)); - reg [27:0] ctr = 0; + localparam ctr_width = 28; + reg [ctr_width-1:0] ctr = 0; always@(posedge clk) ctr <= ctr + 1'b1; - assign led = ctr[27:20]; + reg [9:0] brightness [0:7]; + + reg [7:0] led_reg; + + genvar i; + generate + for (i = 0; i < 8; i=i+1) begin + always @ (posedge clk) begin + if (ctr[ctr_width-1 : ctr_width-3] > i) + brightness[i] <= 10'h3FF; + else if (ctr[ctr_width-1 : ctr_width-3] == i) + brightness[i] <= ctr[ctr_width-4:ctr_width-13]; + else + brightness[i] <= 0; + led_reg[i] <= ctr[9:0] < brightness[i]; + end + end + endgenerate + + assign led = led_reg; // Tie GPIO0, keep board from rebooting TRELLIS_SLICE #(.MODE("LOGIC"), .LUT0_INITVAL(16'hFFFF)) vcc (.F0(gpio0)); -- cgit v1.2.3 From eac5a6dbd829b82117f814ed99f6959c82973935 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 11 Jul 2018 10:09:02 +0200 Subject: ecp5: Blinky tweaks Signed-off-by: David Shah --- ecp5/synth/blinky.v | 34 ++++++++++++++++++++++++---------- ecp5/synth/ulx3s_empty.config | 14 -------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ecp5/synth/blinky.v b/ecp5/synth/blinky.v index 5327ab35..ac7c6ea3 100644 --- a/ecp5/synth/blinky.v +++ b/ecp5/synth/blinky.v @@ -1,13 +1,16 @@ -module top(input clk_pin, output [3:0] led_pin, output gpio0_pin); +module top(input clk_pin, input btn_pin, output [3:0] led_pin, output gpio0_pin); wire clk; wire [7:0] led; - + wire btn; wire gpio0; (* BEL="X0/Y35/PIOA" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("INPUT")) clk_buf (.B(clk_pin), .O(clk)); + (* BEL="X4/Y71/PIOA" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("INPUT")) btn_buf (.B(btn_pin), .O(btn)); + (* BEL="X0/Y23/PIOC" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) led_buf_0 (.B(led_pin[0]), .I(led[0])); (* BEL="X0/Y23/PIOD" *) (* IO_TYPE="LVCMOS33" *) @@ -30,27 +33,38 @@ module top(input clk_pin, output [3:0] led_pin, output gpio0_pin); (* BEL="X0/Y62/PIOD" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) gpio0_buf (.B(gpio0_pin), .I(gpio0)); - localparam ctr_width = 28; + localparam ctr_width = 24; + localparam ctr_max = 2**ctr_width - 1; reg [ctr_width-1:0] ctr = 0; + reg [9:0] pwm_ctr = 0; + reg dir = 0; - always@(posedge clk) - ctr <= ctr + 1'b1; + always@(posedge clk) begin + ctr <= btn ? ctr : (dir ? ctr - 1'b1 : ctr + 1'b1); + if (ctr[ctr_width-1 : ctr_width-3] == 0 && dir == 1) + dir <= 1'b0; + else if (ctr[ctr_width-1 : ctr_width-3] == 7 && dir == 0) + dir <= 1'b1; + pwm_ctr <= pwm_ctr + 1'b1; + end reg [9:0] brightness [0:7]; - + localparam bright_max = 2**10 - 1; reg [7:0] led_reg; genvar i; generate for (i = 0; i < 8; i=i+1) begin always @ (posedge clk) begin - if (ctr[ctr_width-1 : ctr_width-3] > i) - brightness[i] <= 10'h3FF; - else if (ctr[ctr_width-1 : ctr_width-3] == i) + if (ctr[ctr_width-1 : ctr_width-3] == i) + brightness[i] <= bright_max; + else if (ctr[ctr_width-1 : ctr_width-3] == (i - 1)) brightness[i] <= ctr[ctr_width-4:ctr_width-13]; + else if (ctr[ctr_width-1 : ctr_width-3] == (i + 1)) + brightness[i] <= bright_max - ctr[ctr_width-4:ctr_width-13]; else brightness[i] <= 0; - led_reg[i] <= ctr[9:0] < brightness[i]; + led_reg[i] <= pwm_ctr < brightness[i]; end end endgenerate diff --git a/ecp5/synth/ulx3s_empty.config b/ecp5/synth/ulx3s_empty.config index 8b641943..815e7f0d 100644 --- a/ecp5/synth/ulx3s_empty.config +++ b/ecp5/synth/ulx3s_empty.config @@ -1,19 +1,5 @@ .device LFE5U-45F -.comment Lattice Semiconductor Corporation Bitstream -.comment Version: Diamond (64-bit) 3.10.0.111.2 -.comment Bitstream Status: Final Version 10.25 -.comment Design name: wire_impl1.ncd -.comment Architecture: sa5p00 -.comment Part: LFE5U-45F-6CABGA381 -.comment Date: Sun Jul 8 15:46:42 2018 -.comment Rows: 9470 -.comment Cols: 846 -.comment Bits: 8011620 -.comment Readback: Off -.comment Security: Off -.comment Bitstream CRC: 0x66BA - .tile CIB_R10C3:PVT_COUNT2 unknown: F2B0 unknown: F3B0 -- cgit v1.2.3 From 6601adf76074e793501b52cf0f0ad0ec1f049855 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 11 Jul 2018 10:44:06 +0200 Subject: cmake: Post-rebase ecp5 fixes Signed-off-by: David Shah --- CMakeLists.txt | 1 - gui/ecp5/family.cmake | 0 2 files changed, 1 deletion(-) create mode 100644 gui/ecp5/family.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 32063af6..cbcdf67d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,6 @@ option(BUILD_PYTHON "Build Python Integration" ON) option(BUILD_TESTS "Build GUI" OFF) # List of families to build -if(DEFINED TRELLIS_ROOT) set(FAMILIES generic ice40 ecp5) set(ARCH "" CACHE STRING "Architecture family for nextpnr build") diff --git a/gui/ecp5/family.cmake b/gui/ecp5/family.cmake new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From bcc63091fb30ac15c9f98bfc3b3a41d921af0bd4 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 11 Jul 2018 11:08:12 +0200 Subject: ecp5: New libtrellis tile lookup API Signed-off-by: David Shah --- ecp5/bitstream.cc | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index 0e8d4aa4..a04a4250 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -78,24 +78,24 @@ static std::string get_pio_tile(Context *ctx, Trellis::Chip &chip, BelId bel) std::string pio_name = ctx->locInfo(bel)->bel_data[bel.index].name.get(); if (bel.location.y == 0) { if (pio_name == "PIOA") { - return chip.get_tile_by_position_and_type(0, bel.location.x, "PIOT0")->info.name; + return chip.get_tile_by_position_and_type(0, bel.location.x, "PIOT0"); } else if (pio_name == "PIOB") { - return chip.get_tile_by_position_and_type(0, bel.location.x + 1, "PIOT1")->info.name; + return chip.get_tile_by_position_and_type(0, bel.location.x + 1, "PIOT1"); } else { NPNR_ASSERT_FALSE("bad PIO location"); } } else if (bel.location.y == ctx->chip_info->height - 1) { if (pio_name == "PIOA") { - return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, pioa_b)->info.name; + return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, pioa_b); } else if (pio_name == "PIOB") { - return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x + 1, piob_b)->info.name; + return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x + 1, piob_b); } else { NPNR_ASSERT_FALSE("bad PIO location"); } } else if (bel.location.x == 0) { - return chip.get_tile_by_position_and_type(bel.location.y + 1, bel.location.x, pioabcd_l)->info.name; + return chip.get_tile_by_position_and_type(bel.location.y + 1, bel.location.x, pioabcd_l); } else if (bel.location.x == ctx->chip_info->width - 1) { - return chip.get_tile_by_position_and_type(bel.location.y + 1, bel.location.x, pioabcd_r)->info.name; + return chip.get_tile_by_position_and_type(bel.location.y + 1, bel.location.x, pioabcd_r); } else { NPNR_ASSERT_FALSE("bad PIO location"); } @@ -115,33 +115,33 @@ static std::string get_pic_tile(Context *ctx, Trellis::Chip &chip, BelId bel) std::string pio_name = ctx->locInfo(bel)->bel_data[bel.index].name.get(); if (bel.location.y == 0) { if (pio_name == "PIOA") { - return chip.get_tile_by_position_and_type(1, bel.location.x, "PICT0")->info.name; + return chip.get_tile_by_position_and_type(1, bel.location.x, "PICT0"); } else if (pio_name == "PIOB") { - return chip.get_tile_by_position_and_type(1, bel.location.x + 1, "PICT1")->info.name; + return chip.get_tile_by_position_and_type(1, bel.location.x + 1, "PICT1"); } else { NPNR_ASSERT_FALSE("bad PIO location"); } } else if (bel.location.y == ctx->chip_info->height - 1) { if (pio_name == "PIOA") { - return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, pica_b)->info.name; + return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, pica_b); } else if (pio_name == "PIOB") { - return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x + 1, picb_b)->info.name; + return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x + 1, picb_b); } else { NPNR_ASSERT_FALSE("bad PIO location"); } } else if (bel.location.x == 0) { if (pio_name == "PIOA" || pio_name == "PIOB") { - return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, picab_l)->info.name; + return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, picab_l); } else if (pio_name == "PIOC" || pio_name == "PIOD") { - return chip.get_tile_by_position_and_type(bel.location.y + 2, bel.location.x, piccd_l)->info.name; + return chip.get_tile_by_position_and_type(bel.location.y + 2, bel.location.x, piccd_l); } else { NPNR_ASSERT_FALSE("bad PIO location"); } } else if (bel.location.x == ctx->chip_info->width - 1) { if (pio_name == "PIOA" || pio_name == "PIOB") { - return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, picab_r)->info.name; + return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, picab_r); } else if (pio_name == "PIOC" || pio_name == "PIOD") { - return chip.get_tile_by_position_and_type(bel.location.y + 2, bel.location.x, piccd_r)->info.name; + return chip.get_tile_by_position_and_type(bel.location.y + 2, bel.location.x, piccd_r); } else { NPNR_ASSERT_FALSE("bad PIO location"); } @@ -174,11 +174,11 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex for (auto pip : ctx->getPips()) { if (ctx->getBoundPipNet(pip) != IdString()) { if (ctx->getPipType(pip) == 0) { // ignore fixed pips - auto tile = empty_chip.get_tile_by_position_and_type(pip.location.y, pip.location.x, + std::string tile = empty_chip.get_tile_by_position_and_type(pip.location.y, pip.location.x, ctx->getPipTiletype(pip)); std::string source = get_trellis_wirename(ctx, pip.location, ctx->getPipSrcWire(pip)); std::string sink = get_trellis_wirename(ctx, pip.location, ctx->getPipDstWire(pip)); - cc.tiles[tile->info.name].add_arc(sink, source); + cc.tiles[tile].add_arc(sink, source); } } } @@ -199,8 +199,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex } BelId bel = ci->bel; if (ci->type == ctx->id("TRELLIS_SLICE")) { - auto tile = empty_chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, "PLC2"); - std::string tname = tile->info.name; + std::string tname = empty_chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, "PLC2"); std::string slice = ctx->locInfo(bel)->bel_data[bel.index].name.get(); int lut0_init = int_or_default(ci->params, ctx->id("LUT0_INITVAL")); int lut1_init = int_or_default(ci->params, ctx->id("LUT1_INITVAL")); @@ -230,7 +229,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex WireId jpt_wire = ctx->getWireByName(ctx->id(jpt)); PipId jpt_pip = *ctx->getPipsUphill(jpt_wire).begin(); WireId cib_wire = ctx->getPipSrcWire(jpt_pip); - std::string cib_tile = empty_chip.get_tile_by_position_and_type(cib_wire.location.y, cib_wire.location.x, cib_tiles)->info.name; + std::string cib_tile = empty_chip.get_tile_by_position_and_type(cib_wire.location.y, cib_wire.location.x, cib_tiles); std::string cib_wirename = ctx->locInfo(cib_wire)->wire_data[cib_wire.index].name.get(); cc.tiles[cib_tile].add_enum("CIB." + cib_wirename + "MUX", "0"); } -- cgit v1.2.3 From 75fda0fa59b081d3de89fdcfcb1fa5461b683a24 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 11 Jul 2018 11:15:29 +0200 Subject: Add ECP5 notes to README Signed-off-by: David Shah --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7fe49328..c8e4a840 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Supported Architectures ----------------------- - iCE40 +- ECP5 Prequisites ----------- @@ -23,7 +24,10 @@ Prequisites - For building on macOS, brew utility is needed. - Install all needed packages `brew install cmake python boost boost-python3 qt5` - Do not forget to add qt5 in path as well `echo 'export PATH="/usr/local/opt/qt/bin:$PATH"' >> ~/.bash_profile` - + - For ECP5 support, you must download [Project Trellis](https://github.com/SymbiFlow/prjtrellis), then follow its instructions to + download the latest database and build _libtrellis_. + + Building -------- @@ -37,6 +41,7 @@ Building - Add `-DCMAKE_INSTALL_PREFIX=/your/install/prefix` to use a different install prefix to the default `/usr/local` - For MSVC build with vcpkg use `cmake . -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake` using your vcpkg location - For MSVC x64 build adding `-G"Visual Studio 14 2015 Win64"` is needed. + - For ECP5 support, you must also specify the path to Project Trellis using `-DTRELLIS_ROOT=/path/trellis` - Use Make to run the build itself - For all binary targets, just run `make` - For just the iCE40 CLI&GUI binary, run `make nextpnr-ice40` @@ -68,6 +73,12 @@ Running produce `blinky.json`. - To place-and-route the blinky using nextpnr, run `./nextpnr-ice40 --hx1k --json ice40/blinky.json --pcf ice40/blinky.pcf --asc blinky.asc` + - For an ECP5 blinky, first synthesise using `yosys blinky.ys` in `ecp5/synth`. + - Then run ECP5 place-and route using + `./nextpnr-ecp5 --json ecp5/synth/blinky.json --basecfg ecp5/synth/ulx3s_empty.config --bit ecp5/synth/ulx3s.bit` + - Note that `ulx3s_empty.config` contains fixed/unknown bits to be copied to the output bitstream + - You can also use `--textcfg out.config` to write a text file describing the bitstream for debugging + Notes ------- -- cgit v1.2.3 From 0d71ed76cbc80d6ef317a3ae743dcb92baca45ed Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 11 Jul 2018 11:53:24 +0200 Subject: reversed Y coordinate in gui --- gui/fpgaviewwidget.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 0c6b1a98..2c69f865 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -343,7 +343,7 @@ void FPGAViewWidget::paintGL() QMatrix4x4 matrix; matrix.ortho(QRectF(-aspect / 2.0, -0.5, aspect, 1.0f)); matrix.translate(moveX_, moveY_, -0.5); - matrix.scale(zoom_ * 0.01f, zoom_ * 0.01f, 0); + matrix.scale(zoom_ * 0.01f, -zoom_ * 0.01f, 0); // Draw grid. auto grid = LineShaderData(0.01f, QColor("#DDD")); -- cgit v1.2.3 From 7081cca01654030f9a3b731cebf36e68590e3ed1 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 11 Jul 2018 14:03:23 +0200 Subject: Add GUI Decals API Signed-off-by: Clifford Wolf --- common/nextpnr.h | 60 +++++++++++++++ generic/arch.cc | 31 +++++--- generic/arch.h | 28 ++++--- generic/archdefs.h | 1 + gui/fpgaviewwidget.cc | 20 +++++ ice40/arch.cc | 207 +++++++++++++++++++++++++++----------------------- ice40/arch.h | 10 ++- ice40/archdefs.h | 22 ++++++ 8 files changed, 255 insertions(+), 124 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 37e193b9..0b41ff81 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -155,6 +155,12 @@ NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_BEGIN +struct DecalXY +{ + DecalId decal; + float x = 0, y = 0; +}; + struct BelPin { BelId bel; @@ -273,6 +279,60 @@ struct Context : Arch // -------------------------------------------------------------- + std::vector getFrameGraphics() const __attribute__ ((deprecated)) { + std::vector ret; + DecalXY decalxy = getFrameDecal(); + ret = getDecalGraphics(decalxy.decal); + for (auto &it : ret) { + it.x1 += decalxy.x; + it.x2 += decalxy.x; + it.y1 += decalxy.y; + it.y2 += decalxy.y; + } + return ret; + } + + std::vector getBelGraphics(BelId bel) const __attribute__ ((deprecated)) { + std::vector ret; + DecalXY decalxy = getBelDecal(bel); + ret = getDecalGraphics(decalxy.decal); + for (auto &it : ret) { + it.x1 += decalxy.x; + it.x2 += decalxy.x; + it.y1 += decalxy.y; + it.y2 += decalxy.y; + } + return ret; + } + + std::vector getWireGraphics(WireId wire) const __attribute__ ((deprecated)) { + std::vector ret; + DecalXY decalxy = getWireDecal(wire); + ret = getDecalGraphics(decalxy.decal); + for (auto &it : ret) { + it.x1 += decalxy.x; + it.x2 += decalxy.x; + it.y1 += decalxy.y; + it.y2 += decalxy.y; + } + return ret; + } + + std::vector getPipGraphics(PipId pip) const __attribute__ ((deprecated)) { + std::vector ret; + DecalXY decalxy = getPipDecal(pip); + ret = getDecalGraphics(decalxy.decal); + for (auto &it : ret) { + it.x1 += decalxy.x; + it.x2 += decalxy.x; + it.y1 += decalxy.y; + it.y2 += decalxy.y; + } + return ret; + } + + // -------------------------------------------------------------- + uint64_t rngstate = 0x3141592653589793; uint64_t rng64() diff --git a/generic/arch.cc b/generic/arch.cc index 8f897604..b3854401 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -107,27 +107,32 @@ void Arch::addBelInout(IdString bel, IdString name, IdString wire) wires.at(wire).downhill_bel_pins.push_back(BelPin{bel, name}); } -void Arch::addFrameGraphic(const GraphicElement &graphic) +void Arch::addDecalGraphic(DecalId decal, const GraphicElement &graphic) { - frame_graphics.push_back(graphic); + decal_graphics[decal].push_back(graphic); +} + +void Arch::setFrameDecal(DecalXY decalxy) +{ + frame_decalxy = decalxy; frameGraphicsReload = true; } -void Arch::addWireGraphic(WireId wire, const GraphicElement &graphic) +void Arch::setWireDecal(WireId wire, DecalXY decalxy) { - wires.at(wire).graphics.push_back(graphic); + wires.at(wire).decalxy = decalxy; wireGraphicsReload.insert(wire); } -void Arch::addPipGraphic(PipId pip, const GraphicElement &graphic) +void Arch::setPipDecal(PipId pip, DecalXY decalxy) { - pips.at(pip).graphics.push_back(graphic); + pips.at(pip).decalxy = decalxy; pipGraphicsReload.insert(pip); } -void Arch::addBelGraphic(BelId bel, const GraphicElement &graphic) +void Arch::setBelDecal(BelId bel, DecalXY decalxy) { - bels.at(bel).graphics.push_back(graphic); + bels.at(bel).decalxy = decalxy; belGraphicsReload.insert(bel); } @@ -310,13 +315,15 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const // --------------------------------------------------------------- -const std::vector &Arch::getFrameGraphics() const { return frame_graphics; } +const std::vector &Arch::getDecalGraphics(DecalId decal) const { return decal_graphics.at(decal); } + +DecalXY Arch::getFrameDecal() const { return frame_decalxy; } -const std::vector &Arch::getBelGraphics(BelId bel) const { return bels.at(bel).graphics; } +DecalXY Arch::getBelDecal(BelId bel) const { return bels.at(bel).decalxy; } -const std::vector &Arch::getWireGraphics(WireId wire) const { return wires.at(wire).graphics; } +DecalXY Arch::getWireDecal(WireId wire) const { return wires.at(wire).decalxy; } -const std::vector &Arch::getPipGraphics(PipId pip) const { return pips.at(pip).graphics; } +DecalXY Arch::getPipDecal(PipId pip) const { return pips.at(pip).decalxy; } // --------------------------------------------------------------- diff --git a/generic/arch.h b/generic/arch.h index e739cfab..dafbfec3 100644 --- a/generic/arch.h +++ b/generic/arch.h @@ -34,16 +34,16 @@ struct PipInfo IdString name, bound_net; WireId srcWire, dstWire; DelayInfo delay; - std::vector graphics; + DecalXY decalxy; }; struct WireInfo { IdString name, bound_net; - std::vector graphics; std::vector downhill, uphill, aliases; BelPin uphill_bel_pin; std::vector downhill_bel_pins; + DecalXY decalxy; int grid_x, grid_y; }; @@ -58,7 +58,7 @@ struct BelInfo { IdString name, type, bound_cell; std::unordered_map pins; - std::vector graphics; + DecalXY decalxy; int grid_x, grid_y; bool gb; }; @@ -74,7 +74,9 @@ struct Arch : BaseCtx std::vector bel_ids, wire_ids, pip_ids; std::unordered_map> bel_ids_by_type; - std::vector frame_graphics; + std::unordered_map> decal_graphics; + DecalXY frame_decalxy; + float grid_distance_to_delay; void addWire(IdString name, int x, int y); @@ -86,10 +88,11 @@ struct Arch : BaseCtx void addBelOutput(IdString bel, IdString name, IdString wire); void addBelInout(IdString bel, IdString name, IdString wire); - void addFrameGraphic(const GraphicElement &graphic); - void addWireGraphic(WireId wire, const GraphicElement &graphic); - void addPipGraphic(PipId pip, const GraphicElement &graphic); - void addBelGraphic(BelId bel, const GraphicElement &graphic); + void addDecalGraphic(DecalId decal, const GraphicElement &graphic); + void setFrameDecal(DecalXY decalxy); + void setWireDecal(WireId wire, DecalXY decalxy); + void setPipDecal(PipId pip, DecalXY decalxy); + void setBelDecal(BelId bel, DecalXY decalxy); // --------------------------------------------------------------- // Common Arch API. Every arch must provide the following methods. @@ -155,10 +158,11 @@ struct Arch : BaseCtx float getDelayNS(delay_t v) const { return v; } uint32_t getDelayChecksum(delay_t v) const { return 0; } - const std::vector &getFrameGraphics() const; - const std::vector &getBelGraphics(BelId bel) const; - const std::vector &getWireGraphics(WireId wire) const; - const std::vector &getPipGraphics(PipId pip) const; + const std::vector &getDecalGraphics(DecalId decal) const; + DecalXY getFrameDecal() const; + DecalXY getBelDecal(BelId bel) const; + DecalXY getWireDecal(WireId wire) const; + DecalXY getPipDecal(PipId pip) const; bool allGraphicsReload = false; bool frameGraphicsReload = false; diff --git a/generic/archdefs.h b/generic/archdefs.h index 9e8462e0..8e6dcb2f 100644 --- a/generic/archdefs.h +++ b/generic/archdefs.h @@ -49,5 +49,6 @@ typedef IdString PortPin; typedef IdString BelId; typedef IdString WireId; typedef IdString PipId; +typedef IdString DecalId; NEXTPNR_NAMESPACE_END diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index ae0b9240..49ec4529 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -363,6 +363,26 @@ void FPGAViewWidget::paintGL() lineShader_.draw(bels, matrix); } + // Draw Wires. + auto wires = LineShaderData(0.0005f, QColor("#b000ba")); + if (ctx_) { + for (auto wire : ctx_->getWires()) { + for (auto &el : ctx_->getWireGraphics(wire)) + drawElement(wires, el); + } + lineShader_.draw(wires, matrix); + } + + // Draw Pips. + auto pips = LineShaderData(0.0005f, QColor("#b000ba")); + if (ctx_) { + for (auto wire : ctx_->getPips()) { + for (auto &el : ctx_->getPipGraphics(wire)) + drawElement(pips, el); + } + lineShader_.draw(pips, matrix); + } + // Draw Frame Graphics. auto frames = LineShaderData(0.002f, QColor("#0066ba")); if (ctx_) { diff --git a/ice40/arch.cc b/ice40/arch.cc index 0b82914a..a25c3d87 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -400,128 +400,143 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const // ----------------------------------------------------------------------- -std::vector Arch::getFrameGraphics() const +DecalXY Arch::getFrameDecal() const { - std::vector ret; + DecalXY decalxy; + decalxy.decal.type = 'f'; + return decalxy; +} - for (int x = 0; x <= chip_info->width; x++) - for (int y = 0; y <= chip_info->height; y++) { - GraphicElement el; - el.type = GraphicElement::G_LINE; - el.x1 = x - 0.05, el.x2 = x + 0.05, el.y1 = y, el.y2 = y, el.z = 0; - ret.push_back(el); - el.x1 = x, el.x2 = x, el.y1 = y - 0.05, el.y2 = y + 0.05, el.z = 0; - ret.push_back(el); - } +DecalXY Arch::getBelDecal(BelId bel) const +{ + DecalXY decalxy; + decalxy.decal.type = 'b'; + decalxy.decal.z = bel.index; + return decalxy; +} - return ret; +DecalXY Arch::getWireDecal(WireId wire) const +{ + DecalXY decalxy; + return decalxy; } -std::vector Arch::getBelGraphics(BelId bel) const +DecalXY Arch::getPipDecal(PipId pip) const +{ + DecalXY decalxy; + return decalxy; +}; + +std::vector Arch::getDecalGraphics(DecalId decal) const { std::vector ret; - auto bel_type = getBelType(bel); - - if (bel_type == TYPE_ICESTORM_LC) { - GraphicElement el; - el.type = GraphicElement::G_BOX; - el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; - el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; - el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; - el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; - el.z = 0; - ret.push_back(el); - - if (chip_info->bel_data[bel.index].z == 0) { - int tx = chip_info->bel_data[bel.index].x; - int ty = chip_info->bel_data[bel.index].y; - - // Main switchbox - GraphicElement main_sw; - main_sw.type = GraphicElement::G_BOX; - main_sw.x1 = tx + main_swbox_x1; - main_sw.x2 = tx + main_swbox_x2; - main_sw.y1 = ty + main_swbox_y1; - main_sw.y2 = ty + main_swbox_y2; - ret.push_back(main_sw); - - // Local tracks to LUT input switchbox - GraphicElement local_sw; - local_sw.type = GraphicElement::G_BOX; - local_sw.x1 = tx + local_swbox_x1; - local_sw.x2 = tx + local_swbox_x2; - local_sw.y1 = ty + local_swbox_y1; - local_sw.y2 = ty + local_swbox_y2; - local_sw.z = 0; - ret.push_back(local_sw); - - // All the wires - for (int i = TILE_WIRE_GLB2LOCAL_0; i <= TILE_WIRE_SP12_H_L_23; i++) - gfxTileWire(ret, tx, ty, GfxTileWireId(i)); - } + if (decal.type == 'f') + { + for (int x = 0; x <= chip_info->width; x++) + for (int y = 0; y <= chip_info->height; y++) { + GraphicElement el; + el.type = GraphicElement::G_LINE; + el.x1 = x - 0.05, el.x2 = x + 0.05, el.y1 = y, el.y2 = y, el.z = 0; + ret.push_back(el); + el.x1 = x, el.x2 = x, el.y1 = y - 0.05, el.y2 = y + 0.05, el.z = 0; + ret.push_back(el); + } } - if (bel_type == TYPE_SB_IO) { - if (chip_info->bel_data[bel.index].x == 0 || chip_info->bel_data[bel.index].x == chip_info->width - 1) { + if (decal.type == 'b') + { + BelId bel; + bel.index = decal.z; + + auto bel_type = getBelType(bel); + + if (bel_type == TYPE_ICESTORM_LC) { GraphicElement el; el.type = GraphicElement::G_BOX; - el.x1 = chip_info->bel_data[bel.index].x + 0.1; - el.x2 = chip_info->bel_data[bel.index].x + 0.9; - if (chip_info->bel_data[bel.index].z == 0) { - el.y1 = chip_info->bel_data[bel.index].y + 0.10; - el.y2 = chip_info->bel_data[bel.index].y + 0.45; - } else { - el.y1 = chip_info->bel_data[bel.index].y + 0.55; - el.y2 = chip_info->bel_data[bel.index].y + 0.90; - } + el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; + el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; + el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; + el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; el.z = 0; ret.push_back(el); - } else { - GraphicElement el; - el.type = GraphicElement::G_BOX; + if (chip_info->bel_data[bel.index].z == 0) { - el.x1 = chip_info->bel_data[bel.index].x + 0.10; - el.x2 = chip_info->bel_data[bel.index].x + 0.45; + int tx = chip_info->bel_data[bel.index].x; + int ty = chip_info->bel_data[bel.index].y; + + // Main switchbox + GraphicElement main_sw; + main_sw.type = GraphicElement::G_BOX; + main_sw.x1 = tx + main_swbox_x1; + main_sw.x2 = tx + main_swbox_x2; + main_sw.y1 = ty + main_swbox_y1; + main_sw.y2 = ty + main_swbox_y2; + ret.push_back(main_sw); + + // Local tracks to LUT input switchbox + GraphicElement local_sw; + local_sw.type = GraphicElement::G_BOX; + local_sw.x1 = tx + local_swbox_x1; + local_sw.x2 = tx + local_swbox_x2; + local_sw.y1 = ty + local_swbox_y1; + local_sw.y2 = ty + local_swbox_y2; + local_sw.z = 0; + ret.push_back(local_sw); + + // All the wires + for (int i = TILE_WIRE_GLB2LOCAL_0; i <= TILE_WIRE_SP12_H_L_23; i++) + gfxTileWire(ret, tx, ty, GfxTileWireId(i)); + } + } + + if (bel_type == TYPE_SB_IO) { + if (chip_info->bel_data[bel.index].x == 0 || chip_info->bel_data[bel.index].x == chip_info->width - 1) { + GraphicElement el; + el.type = GraphicElement::G_BOX; + el.x1 = chip_info->bel_data[bel.index].x + 0.1; + el.x2 = chip_info->bel_data[bel.index].x + 0.9; + if (chip_info->bel_data[bel.index].z == 0) { + el.y1 = chip_info->bel_data[bel.index].y + 0.10; + el.y2 = chip_info->bel_data[bel.index].y + 0.45; + } else { + el.y1 = chip_info->bel_data[bel.index].y + 0.55; + el.y2 = chip_info->bel_data[bel.index].y + 0.90; + } + el.z = 0; + ret.push_back(el); } else { - el.x1 = chip_info->bel_data[bel.index].x + 0.55; - el.x2 = chip_info->bel_data[bel.index].x + 0.90; + GraphicElement el; + el.type = GraphicElement::G_BOX; + if (chip_info->bel_data[bel.index].z == 0) { + el.x1 = chip_info->bel_data[bel.index].x + 0.10; + el.x2 = chip_info->bel_data[bel.index].x + 0.45; + } else { + el.x1 = chip_info->bel_data[bel.index].x + 0.55; + el.x2 = chip_info->bel_data[bel.index].x + 0.90; + } + el.y1 = chip_info->bel_data[bel.index].y + 0.1; + el.y2 = chip_info->bel_data[bel.index].y + 0.9; + el.z = 0; + ret.push_back(el); } + } + + if (bel_type == TYPE_ICESTORM_RAM) { + GraphicElement el; + el.type = GraphicElement::G_BOX; + el.x1 = chip_info->bel_data[bel.index].x + 0.1; + el.x2 = chip_info->bel_data[bel.index].x + 0.9; el.y1 = chip_info->bel_data[bel.index].y + 0.1; - el.y2 = chip_info->bel_data[bel.index].y + 0.9; + el.y2 = chip_info->bel_data[bel.index].y + 1.9; el.z = 0; ret.push_back(el); } } - if (bel_type == TYPE_ICESTORM_RAM) { - GraphicElement el; - el.type = GraphicElement::G_BOX; - el.x1 = chip_info->bel_data[bel.index].x + 0.1; - el.x2 = chip_info->bel_data[bel.index].x + 0.9; - el.y1 = chip_info->bel_data[bel.index].y + 0.1; - el.y2 = chip_info->bel_data[bel.index].y + 1.9; - el.z = 0; - ret.push_back(el); - } - - return ret; -} - -std::vector Arch::getWireGraphics(WireId wire) const -{ - std::vector ret; - // FIXME return ret; } -std::vector Arch::getPipGraphics(PipId pip) const -{ - std::vector ret; - // FIXME - return ret; -}; - // ----------------------------------------------------------------------- bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, delay_t &delay) const diff --git a/ice40/arch.h b/ice40/arch.h index 43aa0829..03685152 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -643,10 +643,12 @@ struct Arch : BaseCtx // ------------------------------------------------- - std::vector getFrameGraphics() const; - std::vector getBelGraphics(BelId bel) const; - std::vector getWireGraphics(WireId wire) const; - std::vector getPipGraphics(PipId pip) const; + std::vector getDecalGraphics(DecalId decal) const; + + DecalXY getFrameDecal() const; + DecalXY getBelDecal(BelId bel) const; + DecalXY getWireDecal(WireId wire) const; + DecalXY getPipDecal(PipId pip) const; bool allGraphicsReload = false; bool frameGraphicsReload = false; diff --git a/ice40/archdefs.h b/ice40/archdefs.h index be2e406d..061e9b44 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -21,6 +21,8 @@ #error Include "archdefs.h" via "nextpnr.h" only. #endif +#include + NEXTPNR_NAMESPACE_BEGIN typedef int delay_t; @@ -107,6 +109,13 @@ struct PipId bool operator!=(const PipId &other) const { return index != other.index; } }; +struct DecalId +{ + char type = 0; // Bel/Wire/Pip/Frame (b/w/p/f) + uint8_t x = 0, y = 0; + uint32_t z = 0; +}; + NEXTPNR_NAMESPACE_END namespace std { @@ -135,4 +144,17 @@ template <> struct hash : hash template <> struct hash : hash { }; + +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept { + std::size_t seed = 0; + boost::hash_combine(seed, hash()(decal.type)); + boost::hash_combine(seed, hash()(decal.x)); + boost::hash_combine(seed, hash()(decal.y)); + boost::hash_combine(seed, hash()(decal.z)); + return seed; + } +}; + } // namespace std -- cgit v1.2.3 From 35216298d5538c0121ae98399518e8c82b7f7577 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 11 Jul 2018 14:27:15 +0200 Subject: ecp5: Update arch to use new graphics API Signed-off-by: David Shah --- ecp5/arch.cc | 25 ++++++------------------- ecp5/arch.h | 10 ++++++---- ecp5/archdefs.h | 21 +++++++++++++++++++++ ecp5/bitstream.cc | 10 ++++++---- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 7217af78..6d320996 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -288,33 +288,20 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const // ----------------------------------------------------------------------- -std::vector Arch::getFrameGraphics() const +std::vector Arch::getDecalGraphics(DecalId decalId) const { std::vector ret; - + // FIXME return ret; } -std::vector Arch::getBelGraphics(BelId bel) const -{ - std::vector ret; +DecalXY Arch::getFrameDecal() const { return {}; } - return ret; -} +DecalXY Arch::getBelDecal(BelId bel) const { return {}; } -std::vector Arch::getWireGraphics(WireId wire) const -{ - std::vector ret; - // FIXME - return ret; -} +DecalXY Arch::getWireDecal(WireId wire) const { return {}; } -std::vector Arch::getPipGraphics(PipId pip) const -{ - std::vector ret; - // FIXME - return ret; -}; +DecalXY Arch::getPipDecal(PipId pip) const { return {}; }; // ----------------------------------------------------------------------- diff --git a/ecp5/arch.h b/ecp5/arch.h index cc63eeaa..fc8c1356 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -720,10 +720,12 @@ struct Arch : BaseCtx // ------------------------------------------------- - std::vector getFrameGraphics() const; - std::vector getBelGraphics(BelId bel) const; - std::vector getWireGraphics(WireId wire) const; - std::vector getPipGraphics(PipId pip) const; + std::vector getDecalGraphics(DecalId decal) const; + + DecalXY getFrameDecal() const; + DecalXY getBelDecal(BelId bel) const; + DecalXY getWireDecal(WireId wire) const; + DecalXY getPipDecal(PipId pip) const; bool allGraphicsReload = false; bool frameGraphicsReload = false; diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index 4facc786..79b20619 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -22,6 +22,8 @@ #error Include "archdefs.h" via "nextpnr.h" only. #endif +#include + NEXTPNR_NAMESPACE_BEGIN typedef int delay_t; @@ -103,6 +105,13 @@ struct PipId bool operator!=(const PipId &other) const { return index != other.index || location != other.location; } }; +struct DecalId +{ + char type = 0; // Bel/Wire/Pip/Frame (b/w/p/f) + Location location; + uint32_t z = 0; +}; + NEXTPNR_NAMESPACE_END namespace std { @@ -146,6 +155,18 @@ template <> struct hash } }; +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept + { + std::size_t seed = 0; + boost::hash_combine(seed, hash()(decal.type)); + boost::hash_combine(seed, hash()(decal.location)); + boost::hash_combine(seed, hash()(decal.z)); + return seed; + } +}; + template <> struct hash : hash { }; diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index a04a4250..e70d6bb2 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -33,7 +33,7 @@ #include "log.h" #include "util.h" -#define fmt_str(x) (static_cast(std::ostringstream() << x).str()) +#define fmt_str(x) (static_cast(std::ostringstream() << x).str()) NEXTPNR_NAMESPACE_BEGIN @@ -175,7 +175,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex if (ctx->getBoundPipNet(pip) != IdString()) { if (ctx->getPipType(pip) == 0) { // ignore fixed pips std::string tile = empty_chip.get_tile_by_position_and_type(pip.location.y, pip.location.x, - ctx->getPipTiletype(pip)); + ctx->getPipTiletype(pip)); std::string source = get_trellis_wirename(ctx, pip.location, ctx->getPipSrcWire(pip)); std::string sink = get_trellis_wirename(ctx, pip.location, ctx->getPipDstWire(pip)); cc.tiles[tile].add_arc(sink, source); @@ -223,13 +223,15 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex std::string pic_tile = get_pic_tile(ctx, empty_chip, bel); cc.tiles[pio_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype); cc.tiles[pic_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype); - if (dir != "INPUT" && (ci->ports.find(ctx->id("T")) == ci->ports.end() || ci->ports.at(ctx->id("T")).net == nullptr)) { + if (dir != "INPUT" && + (ci->ports.find(ctx->id("T")) == ci->ports.end() || ci->ports.at(ctx->id("T")).net == nullptr)) { // Tie tristate low if unconnected for outputs or bidir std::string jpt = fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/JPADDT" << pio.back()); WireId jpt_wire = ctx->getWireByName(ctx->id(jpt)); PipId jpt_pip = *ctx->getPipsUphill(jpt_wire).begin(); WireId cib_wire = ctx->getPipSrcWire(jpt_pip); - std::string cib_tile = empty_chip.get_tile_by_position_and_type(cib_wire.location.y, cib_wire.location.x, cib_tiles); + std::string cib_tile = + empty_chip.get_tile_by_position_and_type(cib_wire.location.y, cib_wire.location.x, cib_tiles); std::string cib_wirename = ctx->locInfo(cib_wire)->wire_data[cib_wire.index].name.get(); cc.tiles[cib_tile].add_enum("CIB." + cib_wirename + "MUX", "0"); } -- cgit v1.2.3 From 09735694b28f9d1807dad5cb52232b4a40b48a77 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 11 Jul 2018 14:39:42 +0200 Subject: Fixed MSVC build --- common/nextpnr.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 0b41ff81..bf3a5c28 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -279,7 +279,7 @@ struct Context : Arch // -------------------------------------------------------------- - std::vector getFrameGraphics() const __attribute__ ((deprecated)) { + NPNR_DEPRECATED std::vector getFrameGraphics() const { std::vector ret; DecalXY decalxy = getFrameDecal(); ret = getDecalGraphics(decalxy.decal); @@ -292,7 +292,7 @@ struct Context : Arch return ret; } - std::vector getBelGraphics(BelId bel) const __attribute__ ((deprecated)) { + NPNR_DEPRECATED std::vector getBelGraphics(BelId bel) const { std::vector ret; DecalXY decalxy = getBelDecal(bel); ret = getDecalGraphics(decalxy.decal); @@ -305,7 +305,7 @@ struct Context : Arch return ret; } - std::vector getWireGraphics(WireId wire) const __attribute__ ((deprecated)) { + NPNR_DEPRECATED std::vector getWireGraphics(WireId wire) const { std::vector ret; DecalXY decalxy = getWireDecal(wire); ret = getDecalGraphics(decalxy.decal); @@ -318,7 +318,7 @@ struct Context : Arch return ret; } - std::vector getPipGraphics(PipId pip) const __attribute__ ((deprecated)) { + NPNR_DEPRECATED std::vector getPipGraphics(PipId pip) const { std::vector ret; DecalXY decalxy = getPipDecal(pip); ret = getDecalGraphics(decalxy.decal); -- cgit v1.2.3 From 77818f53bd7cb866d7d8404bb176b21c142f0fa2 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 11 Jul 2018 16:20:33 +0200 Subject: GUI preparation for search and browse history --- gui/base.qrc | 5 +++++ gui/designwidget.cc | 32 ++++++++++++++++++++++++++++++++ gui/resources/resultset_first.png | Bin 0 -> 522 bytes gui/resources/resultset_last.png | Bin 0 -> 524 bytes gui/resources/resultset_next.png | Bin 0 -> 395 bytes gui/resources/resultset_previous.png | Bin 0 -> 389 bytes gui/resources/zoom.png | Bin 0 -> 692 bytes 7 files changed, 37 insertions(+) create mode 100644 gui/resources/resultset_first.png create mode 100644 gui/resources/resultset_last.png create mode 100644 gui/resources/resultset_next.png create mode 100644 gui/resources/resultset_previous.png create mode 100644 gui/resources/zoom.png diff --git a/gui/base.qrc b/gui/base.qrc index b9e2f237..8f07aabe 100644 --- a/gui/base.qrc +++ b/gui/base.qrc @@ -4,5 +4,10 @@ resources/open.png resources/save.png resources/exit.png + resources/zoom.png + resources/resultset_first.png + resources/resultset_previous.png + resources/resultset_next.png + resources/resultset_last.png diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 4922074b..b38d5a4c 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -20,8 +20,10 @@ #include "designwidget.h" #include #include +#include #include #include +#include #include #include "fpgaviewwidget.h" @@ -88,8 +90,38 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net propertyEditor->show(); + const QIcon searchIcon(":/icons/resources/zoom.png"); + QLineEdit* lineEdit = new QLineEdit(); + lineEdit->setClearButtonEnabled(true); + lineEdit->addAction(searchIcon, QLineEdit::LeadingPosition); + lineEdit->setPlaceholderText("Search..."); + + QAction *actionFirst = new QAction("", this); + QIcon iconFirst(QStringLiteral(":/icons/resources/resultset_first.png")); + actionFirst->setIcon(iconFirst); + + QAction *actionPrev = new QAction("", this); + QIcon iconPrev(QStringLiteral(":/icons/resources/resultset_previous.png")); + actionPrev->setIcon(iconPrev); + + QAction *actionNext = new QAction("", this); + QIcon iconNext(QStringLiteral(":/icons/resources/resultset_next.png")); + actionNext->setIcon(iconNext); + + QAction *actionLast = new QAction("", this); + QIcon iconLast(QStringLiteral(":/icons/resources/resultset_last.png")); + actionLast->setIcon(iconLast); + + QToolBar *toolbar = new QToolBar(); + toolbar->addAction(actionFirst); + toolbar->addAction(actionPrev); + toolbar->addAction(actionNext); + toolbar->addAction(actionLast); + QSplitter *splitter = new QSplitter(Qt::Vertical); + splitter->addWidget(lineEdit); splitter->addWidget(treeWidget); + splitter->addWidget(toolbar); splitter->addWidget(propertyEditor); QGridLayout *mainLayout = new QGridLayout(); diff --git a/gui/resources/resultset_first.png b/gui/resources/resultset_first.png new file mode 100644 index 00000000..b03eaf8b Binary files /dev/null and b/gui/resources/resultset_first.png differ diff --git a/gui/resources/resultset_last.png b/gui/resources/resultset_last.png new file mode 100644 index 00000000..8ec89478 Binary files /dev/null and b/gui/resources/resultset_last.png differ diff --git a/gui/resources/resultset_next.png b/gui/resources/resultset_next.png new file mode 100644 index 00000000..e252606d Binary files /dev/null and b/gui/resources/resultset_next.png differ diff --git a/gui/resources/resultset_previous.png b/gui/resources/resultset_previous.png new file mode 100644 index 00000000..18f9cc10 Binary files /dev/null and b/gui/resources/resultset_previous.png differ diff --git a/gui/resources/zoom.png b/gui/resources/zoom.png new file mode 100644 index 00000000..908612e3 Binary files /dev/null and b/gui/resources/zoom.png differ -- cgit v1.2.3 From 2a01b5e4d326f697636c592b7589080f88d5fa2c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 11 Jul 2018 17:02:13 +0200 Subject: New refreshUi API Signed-off-by: Clifford Wolf --- common/nextpnr.h | 33 +++++++++++++++++++++++++++++++++ ecp5/arch.h | 6 ------ generic/arch.h | 6 ------ ice40/arch.h | 6 ------ 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index bf3a5c28..856d8993 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -259,6 +259,39 @@ struct BaseCtx delete idstring_str_to_idx; delete idstring_idx_to_str; } + + // -------------------------------------------------------------- + + bool allUiReload = false; + bool frameUiReload = false; + std::unordered_set belUiReload; + std::unordered_set wireUiReload; + std::unordered_set pipUiReload; + + void refreshUi() + { + allUiReload = true; + } + + void refreshUiFrame() + { + frameUiReload = true; + } + + void refreshUiBel(BelId bel) + { + belUiReload.insert(bel); + } + + void refreshUiWire(WireId wire) + { + wireUiReload.insert(wire); + } + + void refreshUiPip(PipId pip) + { + pipUiReload.insert(pip); + } }; NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch.h b/ecp5/arch.h index fc8c1356..ba26682e 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -727,12 +727,6 @@ struct Arch : BaseCtx DecalXY getWireDecal(WireId wire) const; DecalXY getPipDecal(PipId pip) const; - bool allGraphicsReload = false; - bool frameGraphicsReload = false; - std::unordered_set belGraphicsReload; - std::unordered_set wireGraphicsReload; - std::unordered_set pipGraphicsReload; - // ------------------------------------------------- // Get the delay through a cell from one port to another, returning false diff --git a/generic/arch.h b/generic/arch.h index dafbfec3..c73bbf3f 100644 --- a/generic/arch.h +++ b/generic/arch.h @@ -164,12 +164,6 @@ struct Arch : BaseCtx DecalXY getWireDecal(WireId wire) const; DecalXY getPipDecal(PipId pip) const; - bool allGraphicsReload = false; - bool frameGraphicsReload = false; - std::unordered_set belGraphicsReload; - std::unordered_set wireGraphicsReload; - std::unordered_set pipGraphicsReload; - bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, delay_t &delay) const; IdString getPortClock(const CellInfo *cell, IdString port) const; bool isClockPort(const CellInfo *cell, IdString port) const; diff --git a/ice40/arch.h b/ice40/arch.h index 03685152..28e913e4 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -650,12 +650,6 @@ struct Arch : BaseCtx DecalXY getWireDecal(WireId wire) const; DecalXY getPipDecal(PipId pip) const; - bool allGraphicsReload = false; - bool frameGraphicsReload = false; - std::unordered_set belGraphicsReload; - std::unordered_set wireGraphicsReload; - std::unordered_set pipGraphicsReload; - // ------------------------------------------------- // Get the delay through a cell from one port to another, returning false -- cgit v1.2.3 From e9b27860daa97eb66c3268be247c28d15d33db1e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 11 Jul 2018 17:40:02 +0200 Subject: Unflip iCE40 tile graphics Signed-off-by: Clifford Wolf --- ice40/gfx.cc | 96 ++++++++++++++++++++++++++++++------------------------------ ice40/gfx.h | 12 ++++---- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/ice40/gfx.cc b/ice40/gfx.cc index e72b2515..2d6b048b 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -30,7 +30,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) GraphicElement el; el.type = GraphicElement::G_LINE; - float y1 = y + 0.03 + 0.0025 * (60 - idx); + float y1 = y + 1.0 - (0.03 + 0.0025 * (60 - idx)); el.x1 = x + 0.0; el.x2 = x + 0.9; @@ -41,7 +41,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 35); el.x2 = el.x1; el.y1 = y1; - el.y2 = y + main_swbox_y1; + el.y2 = y + main_swbox_y2; g.push_back(el); } @@ -50,9 +50,9 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) GraphicElement el; el.type = GraphicElement::G_LINE; - float y1 = y + 0.03 + 0.0025 * (60 - idx); - float y2 = y + 0.03 + 0.0025 * (60 - (idx ^ 1)); - float y3 = y + 0.03 + 0.0025 * (60 - (idx ^ 1) - 12); + float y1 = y + 1.0 - (0.03 + 0.0025 * (60 - idx)); + float y2 = y + 1.0 - (0.03 + 0.0025 * (60 - (idx ^ 1))); + float y3 = y + 1.0 - (0.03 + 0.0025 * (60 - (idx ^ 1) - 12)); if (idx >= 12) { el.x1 = x; @@ -83,7 +83,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x1 = x + main_swbox_x1 + 0.0025 * ((idx ^ 1) + 35); el.x2 = el.x1; el.y1 = y2; - el.y2 = y + main_swbox_y1; + el.y2 = y + main_swbox_y2; g.push_back(el); } @@ -96,13 +96,13 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) float x1 = x + 0.03 + 0.0025 * (60 - idx); - el.y1 = y + 0.0; - el.y2 = y + 0.9; + el.y1 = y + 1.0; + el.y2 = y + 0.1; el.x1 = x1; el.x2 = x1; g.push_back(el); - el.y1 = y + 0.03 + 0.0025 * (270 - idx); + el.y1 = y + 1.0 - (0.03 + 0.0025 * (270 - idx)); el.y2 = el.y1; el.x1 = x1; el.x2 = x + main_swbox_x1; @@ -119,38 +119,38 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) float x3 = x + 0.03 + 0.0025 * (60 - idx - 12); if (idx >= 12) { - el.y1 = y; - el.y2 = y + 0.01; + el.y1 = y + 1.00; + el.y2 = y + 0.99; el.x1 = x1; el.x2 = x1; g.push_back(el); - el.y1 = y + 0.01; - el.y2 = y + 0.02; + el.y1 = y + 0.99; + el.y2 = y + 0.98; el.x1 = x1; el.x2 = x2; g.push_back(el); } - el.y1 = y + 0.02; - el.y2 = y + 0.9; + el.y1 = y + 0.98; + el.y2 = y + 0.10; el.x1 = x2; el.x2 = x2; g.push_back(el); - el.y1 = y + 0.9; - el.y2 = y + 1.0; + el.y1 = y + 0.10; + el.y2 = y; el.x1 = x2; el.x2 = x3; g.push_back(el); - el.y1 = y + 0.03 + 0.0025 * (145 - idx); + el.y1 = y + 1.0 - (0.03 + 0.0025 * (145 - idx)); el.y2 = el.y1; el.x1 = x; el.x2 = x2; g.push_back(el); - el.y1 = y + 0.03 + 0.0025 * (270 - idx); + el.y1 = y + 1.0 - (0.03 + 0.0025 * (270 - idx)); el.y2 = el.y1; el.x1 = x2; el.x2 = x + main_swbox_x1; @@ -164,7 +164,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) GraphicElement el; el.type = GraphicElement::G_LINE; - float y1 = y + 0.03 + 0.0025 * (90 - idx); + float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - idx)); el.x1 = x + 0.0; el.x2 = x + 0.98333; @@ -175,7 +175,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 5); el.x2 = el.x1; el.y1 = y1; - el.y2 = y + main_swbox_y1; + el.y2 = y + main_swbox_y2; g.push_back(el); } @@ -184,9 +184,9 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) GraphicElement el; el.type = GraphicElement::G_LINE; - float y1 = y + 0.03 + 0.0025 * (90 - (idx ^ 1)); - float y2 = y + 0.03 + 0.0025 * (90 - idx); - float y3 = y + 0.03 + 0.0025 * (90 - idx - 2); + float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - (idx ^ 1))); + float y2 = y + 1.0 - (0.03 + 0.0025 * (90 - idx)); + float y3 = y + 1.0 - (0.03 + 0.0025 * (90 - idx - 2)); if (idx >= 2) { el.x1 = x; @@ -217,7 +217,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 5); el.x2 = el.x1; el.y1 = y2; - el.y2 = y + main_swbox_y1; + el.y2 = y + main_swbox_y2; g.push_back(el); } @@ -228,7 +228,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) GraphicElement el; el.type = GraphicElement::G_LINE; - float y1 = y + 0.03 + 0.0025 * (145 - idx); + float y1 = y + 1.0 - (0.03 + 0.0025 * (145 - idx)); el.y1 = y1; el.y2 = y1; @@ -246,13 +246,13 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) float x1 = x + 0.03 + 0.0025 * (90 - idx); - el.y1 = y + 0.0; - el.y2 = y + 0.98333; + el.y1 = y + 1.00; + el.y2 = y + 0.01667; el.x1 = x1; el.x2 = x1; g.push_back(el); - el.y1 = y + 0.03 + 0.0025 * (300 - idx); + el.y1 = y + 1.0 - (0.03 + 0.0025 * (300 - idx)); el.y2 = el.y1; el.x1 = x1; el.x2 = x + main_swbox_x1; @@ -269,32 +269,32 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) float x3 = x + 0.03 + 0.0025 * (90 - (idx ^ 1) - 2); if (idx >= 2) { - el.y1 = y; - el.y2 = y + 0.01; + el.y1 = y + 1.00; + el.y2 = y + 0.99; el.x1 = x1; el.x2 = x1; g.push_back(el); - el.y1 = y + 0.01; - el.y2 = y + 0.02; + el.y1 = y + 0.99; + el.y2 = y + 0.98; el.x1 = x1; el.x2 = x2; g.push_back(el); } - el.y1 = y + 0.02; - el.y2 = y + 0.98333; + el.y1 = y + 0.98; + el.y2 = y + 0.01667; el.x1 = x2; el.x2 = x2; g.push_back(el); - el.y1 = y + 0.98333; - el.y2 = y + 1.0; + el.y1 = y + 0.01667; + el.y2 = y; el.x1 = x2; el.x2 = x3; g.push_back(el); - el.y1 = y + 0.03 + 0.0025 * (300 - (idx ^ 1)); + el.y1 = y + 1.0 - (0.03 + 0.0025 * (300 - (idx ^ 1))); el.y2 = el.y1; el.x1 = x2; el.x2 = x + main_swbox_x1; @@ -309,8 +309,8 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.type = GraphicElement::G_LINE; el.x1 = x + main_swbox_x1 + 0.005 * (idx + 5); el.x2 = el.x1; - el.y1 = y + main_swbox_y2; - el.y2 = el.y1 + 0.02; + el.y1 = y + main_swbox_y1; + el.y2 = el.y1 - 0.02; g.push_back(el); } @@ -322,7 +322,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.type = GraphicElement::G_LINE; el.x1 = x + main_swbox_x1 - 0.05; el.x2 = x + main_swbox_x1; - el.y1 = y + main_swbox_y2 - 0.005 * (13 - idx); + el.y1 = y + main_swbox_y1 + 0.005 * (13 - idx); el.y2 = el.y1; g.push_back(el); } @@ -333,7 +333,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) int idx = id - TILE_WIRE_NEIGH_OP_BNL_0; GraphicElement el; el.type = GraphicElement::G_LINE; - el.y1 = y + main_swbox_y1 + 0.0025 * (idx + 10) + 0.01 * (idx / 8); + el.y1 = y + main_swbox_y2 - (0.0025 * (idx + 10) + 0.01 * (idx / 8)); el.y2 = el.y1; el.x1 = x + main_swbox_x1 - 0.05; el.x2 = x + main_swbox_x1; @@ -364,7 +364,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.type = GraphicElement::G_LINE; el.x1 = x + local_swbox_x2; el.x2 = x + logic_cell_x1; - el.y1 = y + 0.4675 + (0.005 * input) + z * logic_cell_pitch; + el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0125 + (0.005 * input) + z * logic_cell_pitch; el.y2 = el.y1; g.push_back(el); } @@ -374,14 +374,14 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_LUTFF_0_OUT && id <= TILE_WIRE_LUTFF_7_OUT) { int idx = id - TILE_WIRE_LUTFF_0_OUT; - float y1 = y + 0.03 + 0.0025 * (159 - idx); + float y1 = y + 1.0 - (0.03 + 0.0025 * (152 + idx)); GraphicElement el; el.type = GraphicElement::G_LINE; el.y1 = y1; el.y2 = y1; el.x1 = x + main_swbox_x2; - el.x2 = x + 0.97 + 0.0025 * idx; + el.x2 = x + 0.97 + 0.0025 * (7-idx); g.push_back(el); el.y1 = y1; @@ -403,15 +403,15 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x1 = x + main_swbox_x2 - 0.005 * (idx + 5); el.x2 = el.x1; - el.y1 = y + main_swbox_y2; - el.y2 = el.y1 + 0.005 * (idx + 3); + el.y1 = y + main_swbox_y1; + el.y2 = el.y1 - 0.005 * (idx + 3); g.push_back(el); el.y1 = el.y2; el.x2 = x + logic_cell_x2 - 0.005 * (2 - idx + 5); g.push_back(el); - el.y2 = y + logic_cell_y2 + 7*logic_cell_pitch; + el.y2 = y + logic_cell_y1; el.x1 = el.x2; g.push_back(el); } diff --git a/ice40/gfx.h b/ice40/gfx.h index 9fce27e8..b0009b59 100644 --- a/ice40/gfx.h +++ b/ice40/gfx.h @@ -26,18 +26,18 @@ NEXTPNR_NAMESPACE_BEGIN const float main_swbox_x1 = 0.35; const float main_swbox_x2 = 0.60; -const float main_swbox_y1 = 0.27; -const float main_swbox_y2 = 0.95; +const float main_swbox_y1 = 0.05; +const float main_swbox_y2 = 0.73; const float local_swbox_x1 = 0.63; const float local_swbox_x2 = 0.73; -const float local_swbox_y1 = 0.45; -const float local_swbox_y2 = 0.9375; +const float local_swbox_y1 = 0.05; +const float local_swbox_y2 = 0.55; const float logic_cell_x1 = 0.76; const float logic_cell_x2 = 0.95; -const float logic_cell_y1 = 0.45; -const float logic_cell_y2 = 0.50; +const float logic_cell_y1 = 0.05; +const float logic_cell_y2 = 0.10; const float logic_cell_pitch = 0.0625; enum GfxTileWireId { -- cgit v1.2.3 From 7df67c91b38433e8a1002f8e9f53926aafaa4d1b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 11 Jul 2018 18:04:09 +0200 Subject: Add ctx->route() API Signed-off-by: Clifford Wolf --- common/nextpnr.h | 9 + common/route.cc | 655 ------------------------------------------------ common/route.h | 32 --- common/router1.cc | 655 ++++++++++++++++++++++++++++++++++++++++++++++++ common/router1.h | 31 +++ ecp5/arch.cc | 8 + ecp5/arch.h | 4 + ecp5/main.cc | 3 +- generic/arch.cc | 9 + generic/arch.h | 2 + gui/ice40/mainwindow.cc | 3 +- gui/ice40/worker.cc | 3 +- ice40/arch.cc | 8 + ice40/arch.h | 4 + ice40/main.cc | 5 +- 15 files changed, 735 insertions(+), 696 deletions(-) delete mode 100644 common/route.cc delete mode 100644 common/route.h create mode 100644 common/router1.cc create mode 100644 common/router1.h diff --git a/common/nextpnr.h b/common/nextpnr.h index 856d8993..09bd1554 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -260,6 +260,10 @@ struct BaseCtx delete idstring_idx_to_str; } + Context *getCtx() { return reinterpret_cast(this); } + + const Context *getCtx() const { return reinterpret_cast(this); } + // -------------------------------------------------------------- bool allUiReload = false; @@ -366,6 +370,11 @@ struct Context : Arch // -------------------------------------------------------------- + // provided by router1.cc + bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t &delay); + + // -------------------------------------------------------------- + uint64_t rngstate = 0x3141592653589793; uint64_t rng64() diff --git a/common/route.cc b/common/route.cc deleted file mode 100644 index 82525fcc..00000000 --- a/common/route.cc +++ /dev/null @@ -1,655 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2018 Clifford Wolf - * - * 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 -#include - -#include "log.h" -#include "route.h" - -namespace { - -USING_NEXTPNR_NAMESPACE - -struct hash_id_wire -{ - std::size_t operator()(const std::pair &arg) const noexcept - { - std::size_t seed = std::hash()(arg.first); - seed ^= std::hash()(arg.second) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } -}; - -struct hash_id_pip -{ - std::size_t operator()(const std::pair &arg) const noexcept - { - std::size_t seed = std::hash()(arg.first); - seed ^= std::hash()(arg.second) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } -}; - -struct QueuedWire -{ - WireId wire; - PipId pip; - - delay_t delay = 0, togo = 0; - int randtag = 0; - - struct Greater - { - bool operator()(const QueuedWire &lhs, const QueuedWire &rhs) const noexcept - { - delay_t l = lhs.delay + lhs.togo, r = rhs.delay + rhs.togo; - return l == r ? lhs.randtag > rhs.randtag : l > r; - } - }; -}; - -struct RipupScoreboard -{ - std::unordered_map wireScores; - std::unordered_map pipScores; - std::unordered_map, int, hash_id_wire> netWireScores; - std::unordered_map, int, hash_id_pip> netPipScores; -}; - -void ripup_net(Context *ctx, IdString net_name) -{ - auto net_info = ctx->nets.at(net_name).get(); - std::vector pips; - std::vector wires; - - pips.reserve(net_info->wires.size()); - wires.reserve(net_info->wires.size()); - - for (auto &it : net_info->wires) { - if (it.second.pip != PipId()) - pips.push_back(it.second.pip); - else - wires.push_back(it.first); - } - - for (auto pip : pips) - ctx->unbindPip(pip); - - for (auto wire : wires) - ctx->unbindWire(wire); - - NPNR_ASSERT(net_info->wires.empty()); -} - -struct Router -{ - Context *ctx; - RipupScoreboard scores; - IdString net_name; - - bool ripup; - delay_t ripup_penalty; - - std::unordered_set rippedNets; - std::unordered_map visited; - int visitCnt = 0, revisitCnt = 0, overtimeRevisitCnt = 0; - bool routedOkay = false; - delay_t maxDelay = 0.0; - WireId failedDest; - - void route(const std::unordered_map &src_wires, WireId dst_wire) - { - std::priority_queue, QueuedWire::Greater> queue; - - visited.clear(); - - for (auto &it : src_wires) { - QueuedWire qw; - qw.wire = it.first; - qw.pip = PipId(); - qw.delay = it.second; - qw.togo = ctx->estimateDelay(qw.wire, dst_wire); - qw.randtag = ctx->rng(); - - queue.push(qw); - visited[qw.wire] = qw; - } - - int thisVisitCnt = 0; - int thisVisitCntLimit = 0; - - while (!queue.empty() && (thisVisitCntLimit == 0 || thisVisitCnt < thisVisitCntLimit)) { - QueuedWire qw = queue.top(); - queue.pop(); - - if (thisVisitCntLimit == 0 && visited.count(dst_wire)) - thisVisitCntLimit = (thisVisitCnt * 3) / 2; - - for (auto pip : ctx->getPipsDownhill(qw.wire)) { - delay_t next_delay = qw.delay + ctx->getPipDelay(pip).avgDelay(); - WireId next_wire = ctx->getPipDstWire(pip); - bool foundRipupNet = false; - thisVisitCnt++; - - if (!ctx->checkWireAvail(next_wire)) { - if (!ripup) - continue; - IdString ripupWireNet = ctx->getConflictingWireNet(next_wire); - if (ripupWireNet == net_name || ripupWireNet == IdString()) - continue; - - auto it1 = scores.wireScores.find(next_wire); - if (it1 != scores.wireScores.end()) - next_delay += (it1->second * ripup_penalty) / 8; - - auto it2 = scores.netWireScores.find(std::make_pair(ripupWireNet, next_wire)); - if (it2 != scores.netWireScores.end()) - next_delay += it2->second * ripup_penalty; - - foundRipupNet = true; - } - - if (!ctx->checkPipAvail(pip)) { - if (!ripup) - continue; - IdString ripupPipNet = ctx->getConflictingPipNet(pip); - if (ripupPipNet == net_name || ripupPipNet == IdString()) - continue; - - auto it1 = scores.pipScores.find(pip); - if (it1 != scores.pipScores.end()) - next_delay += (it1->second * ripup_penalty) / 8; - - auto it2 = scores.netPipScores.find(std::make_pair(ripupPipNet, pip)); - if (it2 != scores.netPipScores.end()) - next_delay += it2->second * ripup_penalty; - - foundRipupNet = true; - } - - if (foundRipupNet) - next_delay += ripup_penalty; - - NPNR_ASSERT(next_delay >= 0); - - if (visited.count(next_wire)) { - if (visited.at(next_wire).delay <= next_delay + ctx->getDelayEpsilon()) - continue; -#if 0 // FIXME - if (ctx->debug) - log("Found better route to %s. Old vs new delay " - "estimate: %.3f %.3f\n", - ctx->getWireName(next_wire).c_str(), - ctx->getDelayNS(visited.at(next_wire).delay), - ctx->getDelayNS(next_delay)); -#endif - if (thisVisitCntLimit == 0) - revisitCnt++; - else - overtimeRevisitCnt++; - } - - QueuedWire next_qw; - next_qw.wire = next_wire; - next_qw.pip = pip; - next_qw.delay = next_delay; - next_qw.togo = ctx->estimateDelay(next_wire, dst_wire); - qw.randtag = ctx->rng(); - - visited[next_qw.wire] = next_qw; - queue.push(next_qw); - } - } - - visitCnt += thisVisitCnt; - } - - Router(Context *ctx, RipupScoreboard &scores, WireId src_wire, WireId dst_wire, bool ripup = false, - delay_t ripup_penalty = 0) - : ctx(ctx), scores(scores), ripup(ripup), ripup_penalty(ripup_penalty) - { - std::unordered_map src_wires; - src_wires[src_wire] = 0; - route(src_wires, dst_wire); - routedOkay = visited.count(dst_wire); - - if (ctx->debug) { - log("Route (from destination to source):\n"); - - WireId cursor = dst_wire; - - while (1) { - log(" %8.3f %s\n", ctx->getDelayNS(visited[cursor].delay), ctx->getWireName(cursor).c_str(ctx)); - - if (cursor == src_wire) - break; - - cursor = ctx->getPipSrcWire(visited[cursor].pip); - } - } - } - - Router(Context *ctx, RipupScoreboard &scores, IdString net_name, bool ripup = false, delay_t ripup_penalty = 0) - : ctx(ctx), scores(scores), net_name(net_name), ripup(ripup), ripup_penalty(ripup_penalty) - { - auto net_info = ctx->nets.at(net_name).get(); - - if (ctx->debug) - log("Routing net %s.\n", net_name.c_str(ctx)); - - if (ctx->debug) - log(" Source: %s.%s.\n", net_info->driver.cell->name.c_str(ctx), net_info->driver.port.c_str(ctx)); - - auto src_bel = net_info->driver.cell->bel; - - if (src_bel == BelId()) - log_error("Source cell %s (%s) is not mapped to a bel.\n", net_info->driver.cell->name.c_str(ctx), - net_info->driver.cell->type.c_str(ctx)); - - if (ctx->debug) - log(" Source bel: %s\n", ctx->getBelName(src_bel).c_str(ctx)); - - IdString driver_port = net_info->driver.port; - - auto driver_port_it = net_info->driver.cell->pins.find(driver_port); - if (driver_port_it != net_info->driver.cell->pins.end()) - driver_port = driver_port_it->second; - - auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); - - if (src_wire == WireId()) - log_error("No wire found for port %s (pin %s) on source cell %s " - "(bel %s).\n", - net_info->driver.port.c_str(ctx), driver_port.c_str(ctx), net_info->driver.cell->name.c_str(ctx), - ctx->getBelName(src_bel).c_str(ctx)); - - if (ctx->debug) - log(" Source wire: %s\n", ctx->getWireName(src_wire).c_str(ctx)); - - std::unordered_map src_wires; - src_wires[src_wire] = 0; - - ripup_net(ctx, net_name); - ctx->bindWire(src_wire, net_name, STRENGTH_WEAK); - - std::vector users_array = net_info->users; - ctx->shuffle(users_array); - - for (auto &user_it : users_array) { - if (ctx->debug) - log(" Route to: %s.%s.\n", user_it.cell->name.c_str(ctx), user_it.port.c_str(ctx)); - - auto dst_bel = user_it.cell->bel; - - if (dst_bel == BelId()) - log_error("Destination cell %s (%s) is not mapped to a bel.\n", user_it.cell->name.c_str(ctx), - user_it.cell->type.c_str(ctx)); - - if (ctx->debug) - log(" Destination bel: %s\n", ctx->getBelName(dst_bel).c_str(ctx)); - - IdString user_port = user_it.port; - - auto user_port_it = user_it.cell->pins.find(user_port); - - if (user_port_it != user_it.cell->pins.end()) - user_port = user_port_it->second; - - auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); - - if (dst_wire == WireId()) - log_error("No wire found for port %s (pin %s) on destination " - "cell %s (bel %s).\n", - user_it.port.c_str(ctx), user_port.c_str(ctx), user_it.cell->name.c_str(ctx), - ctx->getBelName(dst_bel).c_str(ctx)); - - if (ctx->debug) { - log(" Destination wire: %s\n", ctx->getWireName(dst_wire).c_str(ctx)); - log(" Path delay estimate: %.2f\n", float(ctx->estimateDelay(src_wire, dst_wire))); - } - - route(src_wires, dst_wire); - - if (visited.count(dst_wire) == 0) { - if (ctx->debug) - log("Failed to route %s -> %s.\n", ctx->getWireName(src_wire).c_str(ctx), - ctx->getWireName(dst_wire).c_str(ctx)); - else if (ripup) - log_info("Failed to route %s -> %s.\n", ctx->getWireName(src_wire).c_str(ctx), - ctx->getWireName(dst_wire).c_str(ctx)); - ripup_net(ctx, net_name); - failedDest = dst_wire; - return; - } - - if (ctx->debug) - log(" Final path delay: %.3f\n", ctx->getDelayNS(visited[dst_wire].delay)); - maxDelay = fmaxf(maxDelay, visited[dst_wire].delay); - - if (ctx->debug) - log(" Route (from destination to source):\n"); - - WireId cursor = dst_wire; - - while (1) { - if (ctx->debug) - log(" %8.3f %s\n", ctx->getDelayNS(visited[cursor].delay), ctx->getWireName(cursor).c_str(ctx)); - - if (src_wires.count(cursor)) - break; - - IdString conflicting_wire_net = ctx->getConflictingWireNet(cursor); - - if (conflicting_wire_net != IdString()) { - NPNR_ASSERT(ripup); - NPNR_ASSERT(conflicting_wire_net != net_name); - - ctx->unbindWire(cursor); - if (!ctx->checkWireAvail(cursor)) - ripup_net(ctx, conflicting_wire_net); - - rippedNets.insert(conflicting_wire_net); - scores.wireScores[cursor]++; - scores.netWireScores[std::make_pair(net_name, cursor)]++; - scores.netWireScores[std::make_pair(conflicting_wire_net, cursor)]++; - } - - PipId pip = visited[cursor].pip; - IdString conflicting_pip_net = ctx->getConflictingPipNet(pip); - - if (conflicting_pip_net != IdString()) { - NPNR_ASSERT(ripup); - NPNR_ASSERT(conflicting_pip_net != net_name); - - ctx->unbindPip(pip); - if (!ctx->checkPipAvail(pip)) - ripup_net(ctx, conflicting_pip_net); - - rippedNets.insert(conflicting_pip_net); - scores.pipScores[visited[cursor].pip]++; - scores.netPipScores[std::make_pair(net_name, visited[cursor].pip)]++; - scores.netPipScores[std::make_pair(conflicting_pip_net, visited[cursor].pip)]++; - } - - ctx->bindPip(visited[cursor].pip, net_name, STRENGTH_WEAK); - src_wires[cursor] = visited[cursor].delay; - cursor = ctx->getPipSrcWire(visited[cursor].pip); - } - } - - routedOkay = true; - } -}; - -} // namespace - -NEXTPNR_NAMESPACE_BEGIN - -bool route_design(Context *ctx) -{ - try { - int totalVisitCnt = 0, totalRevisitCnt = 0, totalOvertimeRevisitCnt = 0; - delay_t ripup_penalty = ctx->getRipupDelayPenalty(); - RipupScoreboard scores; - - log_break(); - log_info("Routing..\n"); - - std::unordered_set netsQueue; - - for (auto &net_it : ctx->nets) { - auto net_name = net_it.first; - auto net_info = net_it.second.get(); - - if (net_info->driver.cell == nullptr) - continue; - - if (!net_info->wires.empty()) - continue; - - netsQueue.insert(net_name); - } - - if (netsQueue.empty()) { - log_info("found no unrouted nets. no routing necessary.\n"); - return true; - } - - log_info("found %d unrouted nets. starting routing procedure.\n", int(netsQueue.size())); - - delay_t estimatedTotalDelay = 0.0; - int estimatedTotalDelayCnt = 0; - - for (auto net_name : netsQueue) { - auto net_info = ctx->nets.at(net_name).get(); - - auto src_bel = net_info->driver.cell->bel; - - if (src_bel == BelId()) - continue; - - IdString driver_port = net_info->driver.port; - - auto driver_port_it = net_info->driver.cell->pins.find(driver_port); - if (driver_port_it != net_info->driver.cell->pins.end()) - driver_port = driver_port_it->second; - - auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); - - if (src_wire == WireId()) - continue; - - for (auto &user_it : net_info->users) { - auto dst_bel = user_it.cell->bel; - - if (dst_bel == BelId()) - continue; - - IdString user_port = user_it.port; - - auto user_port_it = user_it.cell->pins.find(user_port); - - if (user_port_it != user_it.cell->pins.end()) - user_port = user_port_it->second; - - auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); - - if (dst_wire == WireId()) - continue; - - estimatedTotalDelay += ctx->estimateDelay(src_wire, dst_wire); - estimatedTotalDelayCnt++; - } - } - - log_info("estimated total wire delay: %.2f (avg %.2f)\n", float(estimatedTotalDelay), - float(estimatedTotalDelay) / estimatedTotalDelayCnt); - - int iterCnt = 0; - - while (!netsQueue.empty()) { - if (iterCnt == 200) { - log_warning("giving up after %d iterations.\n", iterCnt); - log_info("Checksum: 0x%08x\n", ctx->checksum()); -#ifndef NDEBUG - ctx->check(); -#endif - return false; - } - - iterCnt++; - if (ctx->verbose) - log_info("-- %d --\n", iterCnt); - - int visitCnt = 0, revisitCnt = 0, overtimeRevisitCnt = 0, netCnt = 0; - - std::unordered_set ripupQueue; - - if (ctx->verbose || iterCnt == 1) - log_info("routing queue contains %d nets.\n", int(netsQueue.size())); - - bool printNets = ctx->verbose && (netsQueue.size() < 10); - - std::vector netsArray(netsQueue.begin(), netsQueue.end()); - ctx->sorted_shuffle(netsArray); - netsQueue.clear(); - - for (auto net_name : netsArray) { - if (printNets) - log_info(" routing net %s. (%d users)\n", net_name.c_str(ctx), - int(ctx->nets.at(net_name)->users.size())); - - Router router(ctx, scores, net_name, false); - - netCnt++; - visitCnt += router.visitCnt; - revisitCnt += router.revisitCnt; - overtimeRevisitCnt += router.overtimeRevisitCnt; - - if (!router.routedOkay) { - if (printNets) - log_info(" failed to route to %s.\n", ctx->getWireName(router.failedDest).c_str(ctx)); - ripupQueue.insert(net_name); - } - - if ((ctx->verbose || iterCnt == 1) && !printNets && (netCnt % 100 == 0)) - log_info(" processed %d nets. (%d routed, %d failed)\n", netCnt, netCnt - int(ripupQueue.size()), - int(ripupQueue.size())); - } - - int normalRouteCnt = netCnt - int(ripupQueue.size()); - - if ((ctx->verbose || iterCnt == 1) && (netCnt % 100 != 0)) - log_info(" processed %d nets. (%d routed, %d failed)\n", netCnt, normalRouteCnt, - int(ripupQueue.size())); - - if (ctx->verbose) - log_info(" visited %d PIPs (%.2f%% revisits, %.2f%% overtime " - "revisits).\n", - visitCnt, (100.0 * revisitCnt) / visitCnt, (100.0 * overtimeRevisitCnt) / visitCnt); - - if (!ripupQueue.empty()) { - if (ctx->verbose || iterCnt == 1) - log_info("failed to route %d nets. re-routing in ripup " - "mode.\n", - int(ripupQueue.size())); - - printNets = ctx->verbose && (ripupQueue.size() < 10); - - visitCnt = 0; - revisitCnt = 0; - overtimeRevisitCnt = 0; - netCnt = 0; - int ripCnt = 0; - - std::vector ripupArray(ripupQueue.begin(), ripupQueue.end()); - ctx->sorted_shuffle(ripupArray); - - for (auto net_name : ripupArray) { - if (printNets) - log_info(" routing net %s. (%d users)\n", net_name.c_str(ctx), - int(ctx->nets.at(net_name)->users.size())); - - Router router(ctx, scores, net_name, true, ripup_penalty); - - netCnt++; - visitCnt += router.visitCnt; - revisitCnt += router.revisitCnt; - overtimeRevisitCnt += router.overtimeRevisitCnt; - - if (!router.routedOkay) - log_error("Net %s is impossible to route.\n", net_name.c_str(ctx)); - - for (auto it : router.rippedNets) - netsQueue.insert(it); - - if (printNets) { - if (router.rippedNets.size() < 10) { - log_info(" ripped up %d other nets:\n", int(router.rippedNets.size())); - for (auto n : router.rippedNets) - log_info(" %s (%d users)\n", n.c_str(ctx), int(ctx->nets.at(n)->users.size())); - } else { - log_info(" ripped up %d other nets.\n", int(router.rippedNets.size())); - } - } - - ripCnt += router.rippedNets.size(); - - if ((ctx->verbose || iterCnt == 1) && !printNets && (netCnt % 100 == 0)) - log_info(" routed %d nets, ripped %d nets.\n", netCnt, ripCnt); - } - - if ((ctx->verbose || iterCnt == 1) && (netCnt % 100 != 0)) - log_info(" routed %d nets, ripped %d nets.\n", netCnt, ripCnt); - - if (ctx->verbose) - log_info(" visited %d PIPs (%.2f%% revisits, %.2f%% " - "overtime revisits).\n", - visitCnt, (100.0 * revisitCnt) / visitCnt, (100.0 * overtimeRevisitCnt) / visitCnt); - - if (ctx->verbose && !netsQueue.empty()) - log_info(" ripped up %d previously routed nets. continue " - "routing.\n", - int(netsQueue.size())); - } - - if (!ctx->verbose) - log_info("iteration %d: routed %d nets without ripup, routed %d " - "nets with ripup.\n", - iterCnt, normalRouteCnt, int(ripupQueue.size())); - - totalVisitCnt += visitCnt; - totalRevisitCnt += revisitCnt; - totalOvertimeRevisitCnt += overtimeRevisitCnt; - - if (iterCnt == 8 || iterCnt == 16 || iterCnt == 32 || iterCnt == 64 || iterCnt == 128) - ripup_penalty += ctx->getRipupDelayPenalty(); - } - - log_info("routing complete after %d iterations.\n", iterCnt); - - log_info("visited %d PIPs (%.2f%% revisits, %.2f%% " - "overtime revisits).\n", - totalVisitCnt, (100.0 * totalRevisitCnt) / totalVisitCnt, - (100.0 * totalOvertimeRevisitCnt) / totalVisitCnt); - - log_info("Checksum: 0x%08x\n", ctx->checksum()); -#ifndef NDEBUG - ctx->check(); -#endif - return true; - } catch (log_execution_error_exception) { -#ifndef NDEBUG - ctx->check(); -#endif - return false; - } -} - -bool get_actual_route_delay(Context *ctx, WireId src_wire, WireId dst_wire, delay_t &delay) -{ - RipupScoreboard scores; - Router router(ctx, scores, src_wire, dst_wire); - if (router.routedOkay) - delay = router.visited.at(dst_wire).delay; - return router.routedOkay; -} - -NEXTPNR_NAMESPACE_END diff --git a/common/route.h b/common/route.h deleted file mode 100644 index 1da9edc2..00000000 --- a/common/route.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2018 Clifford Wolf - * - * 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. - * - */ - -#ifndef ROUTE_H -#define ROUTE_H - -#include "nextpnr.h" - -NEXTPNR_NAMESPACE_BEGIN - -extern bool route_design(Context *ctx); -extern bool get_actual_route_delay(Context *ctx, WireId src_wire, WireId dst_wire, delay_t &delay); - -NEXTPNR_NAMESPACE_END - -#endif // ROUTE_H diff --git a/common/router1.cc b/common/router1.cc new file mode 100644 index 00000000..94c7070e --- /dev/null +++ b/common/router1.cc @@ -0,0 +1,655 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * 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 +#include + +#include "log.h" +#include "router1.h" + +namespace { + +USING_NEXTPNR_NAMESPACE + +struct hash_id_wire +{ + std::size_t operator()(const std::pair &arg) const noexcept + { + std::size_t seed = std::hash()(arg.first); + seed ^= std::hash()(arg.second) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; + +struct hash_id_pip +{ + std::size_t operator()(const std::pair &arg) const noexcept + { + std::size_t seed = std::hash()(arg.first); + seed ^= std::hash()(arg.second) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; + +struct QueuedWire +{ + WireId wire; + PipId pip; + + delay_t delay = 0, togo = 0; + int randtag = 0; + + struct Greater + { + bool operator()(const QueuedWire &lhs, const QueuedWire &rhs) const noexcept + { + delay_t l = lhs.delay + lhs.togo, r = rhs.delay + rhs.togo; + return l == r ? lhs.randtag > rhs.randtag : l > r; + } + }; +}; + +struct RipupScoreboard +{ + std::unordered_map wireScores; + std::unordered_map pipScores; + std::unordered_map, int, hash_id_wire> netWireScores; + std::unordered_map, int, hash_id_pip> netPipScores; +}; + +void ripup_net(Context *ctx, IdString net_name) +{ + auto net_info = ctx->nets.at(net_name).get(); + std::vector pips; + std::vector wires; + + pips.reserve(net_info->wires.size()); + wires.reserve(net_info->wires.size()); + + for (auto &it : net_info->wires) { + if (it.second.pip != PipId()) + pips.push_back(it.second.pip); + else + wires.push_back(it.first); + } + + for (auto pip : pips) + ctx->unbindPip(pip); + + for (auto wire : wires) + ctx->unbindWire(wire); + + NPNR_ASSERT(net_info->wires.empty()); +} + +struct Router +{ + Context *ctx; + RipupScoreboard scores; + IdString net_name; + + bool ripup; + delay_t ripup_penalty; + + std::unordered_set rippedNets; + std::unordered_map visited; + int visitCnt = 0, revisitCnt = 0, overtimeRevisitCnt = 0; + bool routedOkay = false; + delay_t maxDelay = 0.0; + WireId failedDest; + + void route(const std::unordered_map &src_wires, WireId dst_wire) + { + std::priority_queue, QueuedWire::Greater> queue; + + visited.clear(); + + for (auto &it : src_wires) { + QueuedWire qw; + qw.wire = it.first; + qw.pip = PipId(); + qw.delay = it.second; + qw.togo = ctx->estimateDelay(qw.wire, dst_wire); + qw.randtag = ctx->rng(); + + queue.push(qw); + visited[qw.wire] = qw; + } + + int thisVisitCnt = 0; + int thisVisitCntLimit = 0; + + while (!queue.empty() && (thisVisitCntLimit == 0 || thisVisitCnt < thisVisitCntLimit)) { + QueuedWire qw = queue.top(); + queue.pop(); + + if (thisVisitCntLimit == 0 && visited.count(dst_wire)) + thisVisitCntLimit = (thisVisitCnt * 3) / 2; + + for (auto pip : ctx->getPipsDownhill(qw.wire)) { + delay_t next_delay = qw.delay + ctx->getPipDelay(pip).avgDelay(); + WireId next_wire = ctx->getPipDstWire(pip); + bool foundRipupNet = false; + thisVisitCnt++; + + if (!ctx->checkWireAvail(next_wire)) { + if (!ripup) + continue; + IdString ripupWireNet = ctx->getConflictingWireNet(next_wire); + if (ripupWireNet == net_name || ripupWireNet == IdString()) + continue; + + auto it1 = scores.wireScores.find(next_wire); + if (it1 != scores.wireScores.end()) + next_delay += (it1->second * ripup_penalty) / 8; + + auto it2 = scores.netWireScores.find(std::make_pair(ripupWireNet, next_wire)); + if (it2 != scores.netWireScores.end()) + next_delay += it2->second * ripup_penalty; + + foundRipupNet = true; + } + + if (!ctx->checkPipAvail(pip)) { + if (!ripup) + continue; + IdString ripupPipNet = ctx->getConflictingPipNet(pip); + if (ripupPipNet == net_name || ripupPipNet == IdString()) + continue; + + auto it1 = scores.pipScores.find(pip); + if (it1 != scores.pipScores.end()) + next_delay += (it1->second * ripup_penalty) / 8; + + auto it2 = scores.netPipScores.find(std::make_pair(ripupPipNet, pip)); + if (it2 != scores.netPipScores.end()) + next_delay += it2->second * ripup_penalty; + + foundRipupNet = true; + } + + if (foundRipupNet) + next_delay += ripup_penalty; + + NPNR_ASSERT(next_delay >= 0); + + if (visited.count(next_wire)) { + if (visited.at(next_wire).delay <= next_delay + ctx->getDelayEpsilon()) + continue; +#if 0 // FIXME + if (ctx->debug) + log("Found better route to %s. Old vs new delay " + "estimate: %.3f %.3f\n", + ctx->getWireName(next_wire).c_str(), + ctx->getDelayNS(visited.at(next_wire).delay), + ctx->getDelayNS(next_delay)); +#endif + if (thisVisitCntLimit == 0) + revisitCnt++; + else + overtimeRevisitCnt++; + } + + QueuedWire next_qw; + next_qw.wire = next_wire; + next_qw.pip = pip; + next_qw.delay = next_delay; + next_qw.togo = ctx->estimateDelay(next_wire, dst_wire); + qw.randtag = ctx->rng(); + + visited[next_qw.wire] = next_qw; + queue.push(next_qw); + } + } + + visitCnt += thisVisitCnt; + } + + Router(Context *ctx, RipupScoreboard &scores, WireId src_wire, WireId dst_wire, bool ripup = false, + delay_t ripup_penalty = 0) + : ctx(ctx), scores(scores), ripup(ripup), ripup_penalty(ripup_penalty) + { + std::unordered_map src_wires; + src_wires[src_wire] = 0; + route(src_wires, dst_wire); + routedOkay = visited.count(dst_wire); + + if (ctx->debug) { + log("Route (from destination to source):\n"); + + WireId cursor = dst_wire; + + while (1) { + log(" %8.3f %s\n", ctx->getDelayNS(visited[cursor].delay), ctx->getWireName(cursor).c_str(ctx)); + + if (cursor == src_wire) + break; + + cursor = ctx->getPipSrcWire(visited[cursor].pip); + } + } + } + + Router(Context *ctx, RipupScoreboard &scores, IdString net_name, bool ripup = false, delay_t ripup_penalty = 0) + : ctx(ctx), scores(scores), net_name(net_name), ripup(ripup), ripup_penalty(ripup_penalty) + { + auto net_info = ctx->nets.at(net_name).get(); + + if (ctx->debug) + log("Routing net %s.\n", net_name.c_str(ctx)); + + if (ctx->debug) + log(" Source: %s.%s.\n", net_info->driver.cell->name.c_str(ctx), net_info->driver.port.c_str(ctx)); + + auto src_bel = net_info->driver.cell->bel; + + if (src_bel == BelId()) + log_error("Source cell %s (%s) is not mapped to a bel.\n", net_info->driver.cell->name.c_str(ctx), + net_info->driver.cell->type.c_str(ctx)); + + if (ctx->debug) + log(" Source bel: %s\n", ctx->getBelName(src_bel).c_str(ctx)); + + IdString driver_port = net_info->driver.port; + + auto driver_port_it = net_info->driver.cell->pins.find(driver_port); + if (driver_port_it != net_info->driver.cell->pins.end()) + driver_port = driver_port_it->second; + + auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + + if (src_wire == WireId()) + log_error("No wire found for port %s (pin %s) on source cell %s " + "(bel %s).\n", + net_info->driver.port.c_str(ctx), driver_port.c_str(ctx), net_info->driver.cell->name.c_str(ctx), + ctx->getBelName(src_bel).c_str(ctx)); + + if (ctx->debug) + log(" Source wire: %s\n", ctx->getWireName(src_wire).c_str(ctx)); + + std::unordered_map src_wires; + src_wires[src_wire] = 0; + + ripup_net(ctx, net_name); + ctx->bindWire(src_wire, net_name, STRENGTH_WEAK); + + std::vector users_array = net_info->users; + ctx->shuffle(users_array); + + for (auto &user_it : users_array) { + if (ctx->debug) + log(" Route to: %s.%s.\n", user_it.cell->name.c_str(ctx), user_it.port.c_str(ctx)); + + auto dst_bel = user_it.cell->bel; + + if (dst_bel == BelId()) + log_error("Destination cell %s (%s) is not mapped to a bel.\n", user_it.cell->name.c_str(ctx), + user_it.cell->type.c_str(ctx)); + + if (ctx->debug) + log(" Destination bel: %s\n", ctx->getBelName(dst_bel).c_str(ctx)); + + IdString user_port = user_it.port; + + auto user_port_it = user_it.cell->pins.find(user_port); + + if (user_port_it != user_it.cell->pins.end()) + user_port = user_port_it->second; + + auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + + if (dst_wire == WireId()) + log_error("No wire found for port %s (pin %s) on destination " + "cell %s (bel %s).\n", + user_it.port.c_str(ctx), user_port.c_str(ctx), user_it.cell->name.c_str(ctx), + ctx->getBelName(dst_bel).c_str(ctx)); + + if (ctx->debug) { + log(" Destination wire: %s\n", ctx->getWireName(dst_wire).c_str(ctx)); + log(" Path delay estimate: %.2f\n", float(ctx->estimateDelay(src_wire, dst_wire))); + } + + route(src_wires, dst_wire); + + if (visited.count(dst_wire) == 0) { + if (ctx->debug) + log("Failed to route %s -> %s.\n", ctx->getWireName(src_wire).c_str(ctx), + ctx->getWireName(dst_wire).c_str(ctx)); + else if (ripup) + log_info("Failed to route %s -> %s.\n", ctx->getWireName(src_wire).c_str(ctx), + ctx->getWireName(dst_wire).c_str(ctx)); + ripup_net(ctx, net_name); + failedDest = dst_wire; + return; + } + + if (ctx->debug) + log(" Final path delay: %.3f\n", ctx->getDelayNS(visited[dst_wire].delay)); + maxDelay = fmaxf(maxDelay, visited[dst_wire].delay); + + if (ctx->debug) + log(" Route (from destination to source):\n"); + + WireId cursor = dst_wire; + + while (1) { + if (ctx->debug) + log(" %8.3f %s\n", ctx->getDelayNS(visited[cursor].delay), ctx->getWireName(cursor).c_str(ctx)); + + if (src_wires.count(cursor)) + break; + + IdString conflicting_wire_net = ctx->getConflictingWireNet(cursor); + + if (conflicting_wire_net != IdString()) { + NPNR_ASSERT(ripup); + NPNR_ASSERT(conflicting_wire_net != net_name); + + ctx->unbindWire(cursor); + if (!ctx->checkWireAvail(cursor)) + ripup_net(ctx, conflicting_wire_net); + + rippedNets.insert(conflicting_wire_net); + scores.wireScores[cursor]++; + scores.netWireScores[std::make_pair(net_name, cursor)]++; + scores.netWireScores[std::make_pair(conflicting_wire_net, cursor)]++; + } + + PipId pip = visited[cursor].pip; + IdString conflicting_pip_net = ctx->getConflictingPipNet(pip); + + if (conflicting_pip_net != IdString()) { + NPNR_ASSERT(ripup); + NPNR_ASSERT(conflicting_pip_net != net_name); + + ctx->unbindPip(pip); + if (!ctx->checkPipAvail(pip)) + ripup_net(ctx, conflicting_pip_net); + + rippedNets.insert(conflicting_pip_net); + scores.pipScores[visited[cursor].pip]++; + scores.netPipScores[std::make_pair(net_name, visited[cursor].pip)]++; + scores.netPipScores[std::make_pair(conflicting_pip_net, visited[cursor].pip)]++; + } + + ctx->bindPip(visited[cursor].pip, net_name, STRENGTH_WEAK); + src_wires[cursor] = visited[cursor].delay; + cursor = ctx->getPipSrcWire(visited[cursor].pip); + } + } + + routedOkay = true; + } +}; + +} // namespace + +NEXTPNR_NAMESPACE_BEGIN + +bool router1(Context *ctx) +{ + try { + int totalVisitCnt = 0, totalRevisitCnt = 0, totalOvertimeRevisitCnt = 0; + delay_t ripup_penalty = ctx->getRipupDelayPenalty(); + RipupScoreboard scores; + + log_break(); + log_info("Routing..\n"); + + std::unordered_set netsQueue; + + for (auto &net_it : ctx->nets) { + auto net_name = net_it.first; + auto net_info = net_it.second.get(); + + if (net_info->driver.cell == nullptr) + continue; + + if (!net_info->wires.empty()) + continue; + + netsQueue.insert(net_name); + } + + if (netsQueue.empty()) { + log_info("found no unrouted nets. no routing necessary.\n"); + return true; + } + + log_info("found %d unrouted nets. starting routing procedure.\n", int(netsQueue.size())); + + delay_t estimatedTotalDelay = 0.0; + int estimatedTotalDelayCnt = 0; + + for (auto net_name : netsQueue) { + auto net_info = ctx->nets.at(net_name).get(); + + auto src_bel = net_info->driver.cell->bel; + + if (src_bel == BelId()) + continue; + + IdString driver_port = net_info->driver.port; + + auto driver_port_it = net_info->driver.cell->pins.find(driver_port); + if (driver_port_it != net_info->driver.cell->pins.end()) + driver_port = driver_port_it->second; + + auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + + if (src_wire == WireId()) + continue; + + for (auto &user_it : net_info->users) { + auto dst_bel = user_it.cell->bel; + + if (dst_bel == BelId()) + continue; + + IdString user_port = user_it.port; + + auto user_port_it = user_it.cell->pins.find(user_port); + + if (user_port_it != user_it.cell->pins.end()) + user_port = user_port_it->second; + + auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + + if (dst_wire == WireId()) + continue; + + estimatedTotalDelay += ctx->estimateDelay(src_wire, dst_wire); + estimatedTotalDelayCnt++; + } + } + + log_info("estimated total wire delay: %.2f (avg %.2f)\n", float(estimatedTotalDelay), + float(estimatedTotalDelay) / estimatedTotalDelayCnt); + + int iterCnt = 0; + + while (!netsQueue.empty()) { + if (iterCnt == 200) { + log_warning("giving up after %d iterations.\n", iterCnt); + log_info("Checksum: 0x%08x\n", ctx->checksum()); +#ifndef NDEBUG + ctx->check(); +#endif + return false; + } + + iterCnt++; + if (ctx->verbose) + log_info("-- %d --\n", iterCnt); + + int visitCnt = 0, revisitCnt = 0, overtimeRevisitCnt = 0, netCnt = 0; + + std::unordered_set ripupQueue; + + if (ctx->verbose || iterCnt == 1) + log_info("routing queue contains %d nets.\n", int(netsQueue.size())); + + bool printNets = ctx->verbose && (netsQueue.size() < 10); + + std::vector netsArray(netsQueue.begin(), netsQueue.end()); + ctx->sorted_shuffle(netsArray); + netsQueue.clear(); + + for (auto net_name : netsArray) { + if (printNets) + log_info(" routing net %s. (%d users)\n", net_name.c_str(ctx), + int(ctx->nets.at(net_name)->users.size())); + + Router router(ctx, scores, net_name, false); + + netCnt++; + visitCnt += router.visitCnt; + revisitCnt += router.revisitCnt; + overtimeRevisitCnt += router.overtimeRevisitCnt; + + if (!router.routedOkay) { + if (printNets) + log_info(" failed to route to %s.\n", ctx->getWireName(router.failedDest).c_str(ctx)); + ripupQueue.insert(net_name); + } + + if ((ctx->verbose || iterCnt == 1) && !printNets && (netCnt % 100 == 0)) + log_info(" processed %d nets. (%d routed, %d failed)\n", netCnt, netCnt - int(ripupQueue.size()), + int(ripupQueue.size())); + } + + int normalRouteCnt = netCnt - int(ripupQueue.size()); + + if ((ctx->verbose || iterCnt == 1) && (netCnt % 100 != 0)) + log_info(" processed %d nets. (%d routed, %d failed)\n", netCnt, normalRouteCnt, + int(ripupQueue.size())); + + if (ctx->verbose) + log_info(" visited %d PIPs (%.2f%% revisits, %.2f%% overtime " + "revisits).\n", + visitCnt, (100.0 * revisitCnt) / visitCnt, (100.0 * overtimeRevisitCnt) / visitCnt); + + if (!ripupQueue.empty()) { + if (ctx->verbose || iterCnt == 1) + log_info("failed to route %d nets. re-routing in ripup " + "mode.\n", + int(ripupQueue.size())); + + printNets = ctx->verbose && (ripupQueue.size() < 10); + + visitCnt = 0; + revisitCnt = 0; + overtimeRevisitCnt = 0; + netCnt = 0; + int ripCnt = 0; + + std::vector ripupArray(ripupQueue.begin(), ripupQueue.end()); + ctx->sorted_shuffle(ripupArray); + + for (auto net_name : ripupArray) { + if (printNets) + log_info(" routing net %s. (%d users)\n", net_name.c_str(ctx), + int(ctx->nets.at(net_name)->users.size())); + + Router router(ctx, scores, net_name, true, ripup_penalty); + + netCnt++; + visitCnt += router.visitCnt; + revisitCnt += router.revisitCnt; + overtimeRevisitCnt += router.overtimeRevisitCnt; + + if (!router.routedOkay) + log_error("Net %s is impossible to route.\n", net_name.c_str(ctx)); + + for (auto it : router.rippedNets) + netsQueue.insert(it); + + if (printNets) { + if (router.rippedNets.size() < 10) { + log_info(" ripped up %d other nets:\n", int(router.rippedNets.size())); + for (auto n : router.rippedNets) + log_info(" %s (%d users)\n", n.c_str(ctx), int(ctx->nets.at(n)->users.size())); + } else { + log_info(" ripped up %d other nets.\n", int(router.rippedNets.size())); + } + } + + ripCnt += router.rippedNets.size(); + + if ((ctx->verbose || iterCnt == 1) && !printNets && (netCnt % 100 == 0)) + log_info(" routed %d nets, ripped %d nets.\n", netCnt, ripCnt); + } + + if ((ctx->verbose || iterCnt == 1) && (netCnt % 100 != 0)) + log_info(" routed %d nets, ripped %d nets.\n", netCnt, ripCnt); + + if (ctx->verbose) + log_info(" visited %d PIPs (%.2f%% revisits, %.2f%% " + "overtime revisits).\n", + visitCnt, (100.0 * revisitCnt) / visitCnt, (100.0 * overtimeRevisitCnt) / visitCnt); + + if (ctx->verbose && !netsQueue.empty()) + log_info(" ripped up %d previously routed nets. continue " + "routing.\n", + int(netsQueue.size())); + } + + if (!ctx->verbose) + log_info("iteration %d: routed %d nets without ripup, routed %d " + "nets with ripup.\n", + iterCnt, normalRouteCnt, int(ripupQueue.size())); + + totalVisitCnt += visitCnt; + totalRevisitCnt += revisitCnt; + totalOvertimeRevisitCnt += overtimeRevisitCnt; + + if (iterCnt == 8 || iterCnt == 16 || iterCnt == 32 || iterCnt == 64 || iterCnt == 128) + ripup_penalty += ctx->getRipupDelayPenalty(); + } + + log_info("routing complete after %d iterations.\n", iterCnt); + + log_info("visited %d PIPs (%.2f%% revisits, %.2f%% " + "overtime revisits).\n", + totalVisitCnt, (100.0 * totalRevisitCnt) / totalVisitCnt, + (100.0 * totalOvertimeRevisitCnt) / totalVisitCnt); + + log_info("Checksum: 0x%08x\n", ctx->checksum()); +#ifndef NDEBUG + ctx->check(); +#endif + return true; + } catch (log_execution_error_exception) { +#ifndef NDEBUG + ctx->check(); +#endif + return false; + } +} + +bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t &delay) +{ + RipupScoreboard scores; + Router router(this, scores, src_wire, dst_wire); + if (router.routedOkay) + delay = router.visited.at(dst_wire).delay; + return router.routedOkay; +} + +NEXTPNR_NAMESPACE_END diff --git a/common/router1.h b/common/router1.h new file mode 100644 index 00000000..38552c58 --- /dev/null +++ b/common/router1.h @@ -0,0 +1,31 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * 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. + * + */ + +#ifndef ROUTER1_H +#define ROUTER1_H + +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +extern bool router1(Context *ctx); + +NEXTPNR_NAMESPACE_END + +#endif // ROUTER1_H diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 6d320996..74548391 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -23,6 +23,7 @@ #include #include "log.h" #include "nextpnr.h" +#include "router1.h" #include "util.h" NEXTPNR_NAMESPACE_BEGIN @@ -288,6 +289,13 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const // ----------------------------------------------------------------------- +bool Arch::route() +{ + return router1(getCtx()); +} + +// ----------------------------------------------------------------------- + std::vector Arch::getDecalGraphics(DecalId decalId) const { std::vector ret; diff --git a/ecp5/arch.h b/ecp5/arch.h index ba26682e..c9c5a6a1 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -720,6 +720,10 @@ struct Arch : BaseCtx // ------------------------------------------------- + bool route(); + + // ------------------------------------------------- + std::vector getDecalGraphics(DecalId decal) const; DecalXY getFrameDecal() const; diff --git a/ecp5/main.cc b/ecp5/main.cc index caa28563..a6128d0f 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -45,7 +45,6 @@ #include "jsonparse.h" #include "pack.h" #include "place_sa.h" -#include "route.h" #include "timing.h" USING_NEXTPNR_NAMESPACE @@ -150,7 +149,7 @@ int main(int argc, char *argv[]) if (!place_design_sa(&ctx) && !ctx.force) log_error("Placing design failed.\n"); ctx.check(); - if (!route_design(&ctx) && !ctx.force) + if (!ctx.route() && !ctx.force) log_error("Routing design failed.\n"); std::string basecfg; diff --git a/generic/arch.cc b/generic/arch.cc index b3854401..b82d8ce6 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -19,6 +19,7 @@ #include #include "nextpnr.h" +#include "router1.h" NEXTPNR_NAMESPACE_BEGIN @@ -315,6 +316,14 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const // --------------------------------------------------------------- +bool Arch::route() +{ + return router1(getCtx()); +} + +// --------------------------------------------------------------- + + const std::vector &Arch::getDecalGraphics(DecalId decal) const { return decal_graphics.at(decal); } DecalXY Arch::getFrameDecal() const { return frame_decalxy; } diff --git a/generic/arch.h b/generic/arch.h index c73bbf3f..60ac9435 100644 --- a/generic/arch.h +++ b/generic/arch.h @@ -158,6 +158,8 @@ struct Arch : BaseCtx float getDelayNS(delay_t v) const { return v; } uint32_t getDelayChecksum(delay_t v) const { return 0; } + bool route(); + const std::vector &getDecalGraphics(DecalId decal) const; DecalXY getFrameDecal() const; DecalXY getBelDecal(BelId bel) const; diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index c4e568a3..ea7e0667 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -30,7 +30,6 @@ #include "pack.h" #include "pcf.h" #include "place_sa.h" -#include "route.h" static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } @@ -444,4 +443,4 @@ void MainWindow::budget() void MainWindow::place() { Q_EMIT task->place(timing_driven); } -NEXTPNR_NAMESPACE_END \ No newline at end of file +NEXTPNR_NAMESPACE_END diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc index ab82b6bb..fc21ed34 100644 --- a/gui/ice40/worker.cc +++ b/gui/ice40/worker.cc @@ -26,7 +26,6 @@ #include "pack.h" #include "pcf.h" #include "place_sa.h" -#include "route.h" #include "timing.h" NEXTPNR_NAMESPACE_BEGIN @@ -134,7 +133,7 @@ void Worker::route() { Q_EMIT taskStarted(); try { - Q_EMIT route_finished(route_design(ctx)); + Q_EMIT route_finished(ctx->route()); } catch (WorkerInterruptionRequested) { Q_EMIT taskCanceled(); } diff --git a/ice40/arch.cc b/ice40/arch.cc index a25c3d87..0bb27d38 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -21,6 +21,7 @@ #include #include "log.h" #include "nextpnr.h" +#include "router1.h" #include "util.h" #include "gfx.h" @@ -400,6 +401,13 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const // ----------------------------------------------------------------------- +bool Arch::route() +{ + return router1(getCtx()); +} + +// ----------------------------------------------------------------------- + DecalXY Arch::getFrameDecal() const { DecalXY decalxy; diff --git a/ice40/arch.h b/ice40/arch.h index 28e913e4..02c37fae 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -643,6 +643,10 @@ struct Arch : BaseCtx // ------------------------------------------------- + bool route(); + + // ------------------------------------------------- + std::vector getDecalGraphics(DecalId decal) const; DecalXY getFrameDecal() const; diff --git a/ice40/main.cc b/ice40/main.cc index ff823cbe..f586a079 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -43,7 +43,6 @@ #include "pcf.h" #include "place_legaliser.h" #include "place_sa.h" -#include "route.h" #include "timing.h" #include "version.h" @@ -339,7 +338,7 @@ int main(int argc, char *argv[]) for (int i = 0; i < int(src_wires.size()) && i < int(dst_wires.size()); i++) { delay_t actual_delay; WireId src = src_wires[i], dst = dst_wires[i]; - if (!get_actual_route_delay(&ctx, src, dst, actual_delay)) + if (!ctx.getActualRouteDelay(src, dst, actual_delay)) continue; printf("%s %s %.3f %.3f %d %d %d %d %d %d\n", ctx.getWireName(src).c_str(&ctx), ctx.getWireName(dst).c_str(&ctx), ctx.getDelayNS(actual_delay), @@ -376,7 +375,7 @@ int main(int argc, char *argv[]) if (!place_design_sa(&ctx) && !ctx.force) log_error("Placing design failed.\n"); ctx.check(); - if (!route_design(&ctx) && !ctx.force) + if (!ctx.route() && !ctx.force) log_error("Routing design failed.\n"); } } -- cgit v1.2.3 From 7daa8524c8ab8c9ff5400d5074b80573b0d39a14 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 11 Jul 2018 18:15:08 +0200 Subject: Add ctx->place() API Signed-off-by: Clifford Wolf --- common/place_sa.cc | 450 ------------------------------------------------ common/place_sa.h | 30 ---- common/placer1.cc | 450 ++++++++++++++++++++++++++++++++++++++++++++++++ common/placer1.h | 30 ++++ ecp5/arch.cc | 6 + ecp5/arch.h | 1 + ecp5/main.cc | 3 +- generic/arch.cc | 6 + generic/arch.h | 1 + gui/ice40/mainwindow.cc | 1 - gui/ice40/worker.cc | 3 +- ice40/arch.cc | 6 + ice40/arch.h | 1 + ice40/main.cc | 3 +- 14 files changed, 504 insertions(+), 487 deletions(-) delete mode 100644 common/place_sa.cc delete mode 100644 common/place_sa.h create mode 100644 common/placer1.cc create mode 100644 common/placer1.h diff --git a/common/place_sa.cc b/common/place_sa.cc deleted file mode 100644 index ab161c57..00000000 --- a/common/place_sa.cc +++ /dev/null @@ -1,450 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2018 Clifford Wolf - * Copyright (C) 2018 David Shah - * - * Simulated annealing implementation based on arachne-pnr - * Copyright (C) 2015-2018 Cotton Seed - * - * 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 "place_sa.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "log.h" -#include "place_common.h" -#include "place_legaliser.h" -#include "timing.h" -#include "util.h" -NEXTPNR_NAMESPACE_BEGIN - -class SAPlacer -{ - public: - SAPlacer(Context *ctx) : ctx(ctx) - { - int num_bel_types = 0; - for (auto bel : ctx->getBels()) { - int x, y; - bool gb; - ctx->estimatePosition(bel, x, y, gb); - BelType type = ctx->getBelType(bel); - int type_idx; - if (bel_types.find(type) == bel_types.end()) { - type_idx = num_bel_types++; - bel_types[type] = type_idx; - } else { - type_idx = bel_types.at(type); - } - if (int(fast_bels.size()) < type_idx + 1) - fast_bels.resize(type_idx + 1); - if (int(fast_bels.at(type_idx).size()) < (x + 1)) - fast_bels.at(type_idx).resize(x + 1); - if (int(fast_bels.at(type_idx).at(x).size()) < (y + 1)) - fast_bels.at(type_idx).at(x).resize(y + 1); - max_x = std::max(max_x, x); - max_y = std::max(max_y, y); - fast_bels.at(type_idx).at(x).at(y).push_back(bel); - } - diameter = std::max(max_x, max_y) + 1; - } - - bool place() - { - log_break(); - - size_t placed_cells = 0; - // Initial constraints placer - for (auto &cell_entry : ctx->cells) { - CellInfo *cell = cell_entry.second.get(); - auto loc = cell->attrs.find(ctx->id("BEL")); - if (loc != cell->attrs.end()) { - std::string loc_name = loc->second; - BelId bel = ctx->getBelByName(ctx->id(loc_name)); - if (bel == BelId()) { - log_error("No Bel named \'%s\' located for " - "this chip (processing BEL attribute on \'%s\')\n", - loc_name.c_str(), cell->name.c_str(ctx)); - } - - BelType bel_type = ctx->getBelType(bel); - if (bel_type != ctx->belTypeFromId(cell->type)) { - log_error("Bel \'%s\' of type \'%s\' does not match cell " - "\'%s\' of type \'%s\'", - loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(ctx), cell->name.c_str(ctx), - cell->type.c_str(ctx)); - } - - ctx->bindBel(bel, cell->name, STRENGTH_USER); - locked_bels.insert(bel); - placed_cells++; - } - } - int constr_placed_cells = placed_cells; - log_info("Placed %d cells based on constraints.\n", int(placed_cells)); - - // Sort to-place cells for deterministic initial placement - std::vector autoplaced; - for (auto &cell : ctx->cells) { - CellInfo *ci = cell.second.get(); - if (ci->bel == BelId()) { - autoplaced.push_back(cell.second.get()); - } - } - std::sort(autoplaced.begin(), autoplaced.end(), [](CellInfo *a, CellInfo *b) { return a->name < b->name; }); - ctx->shuffle(autoplaced); - - // Place cells randomly initially - log_info("Creating initial placement for remaining %d cells.\n", int(autoplaced.size())); - - for (auto cell : autoplaced) { - place_initial(cell); - placed_cells++; - if ((placed_cells - constr_placed_cells) % 500 == 0) - log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells), - int(autoplaced.size())); - } - if ((placed_cells - constr_placed_cells) % 500 != 0) - log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells), - int(autoplaced.size())); - - log_info("Running simulated annealing placer.\n"); - - // Calculate wirelength after initial placement - curr_wirelength = 0; - curr_tns = 0; - for (auto &net : ctx->nets) { - wirelen_t wl = get_net_wirelength(ctx, net.second.get(), curr_tns); - wirelengths[net.first] = wl; - curr_wirelength += wl; - } - - int n_no_progress = 0; - double avg_wirelength = curr_wirelength; - temp = 10000; - - // Main simulated annealing loop - for (int iter = 1;; iter++) { - n_move = n_accept = 0; - improved = false; - - if (iter % 5 == 0 || iter == 1) - log_info(" at iteration #%d: temp = %f, wire length = " - "%.0f, est tns = %.02fns\n", - iter, temp, double(curr_wirelength), curr_tns); - - for (int m = 0; m < 15; ++m) { - // Loop through all automatically placed cells - for (auto cell : autoplaced) { - // Find another random Bel for this cell - BelId try_bel = random_bel_for_cell(cell); - // If valid, try and swap to a new position and see if - // the new position is valid/worthwhile - if (try_bel != BelId() && try_bel != cell->bel) - try_swap_position(cell, try_bel); - } - } - // Heuristic to improve placement on the 8k - if (improved) - n_no_progress = 0; - else - n_no_progress++; - - if (temp <= 1e-3 && n_no_progress >= 5) { - if (iter % 5 != 0) - log_info(" at iteration #%d: temp = %f, wire length = %f\n", iter, temp, double(curr_wirelength)); - break; - } - - double Raccept = double(n_accept) / double(n_move); - - int M = std::max(max_x, max_y) + 1; - - double upper = 0.6, lower = 0.4; - - if (curr_wirelength < 0.95 * avg_wirelength) { - avg_wirelength = 0.8 * avg_wirelength + 0.2 * curr_wirelength; - } else { - if (Raccept >= 0.8) { - temp *= 0.7; - } else if (Raccept > upper) { - if (diameter < M) - diameter++; - else - temp *= 0.9; - } else if (Raccept > lower) { - temp *= 0.95; - } else { - // Raccept < 0.3 - if (diameter > 1) - diameter--; - else - temp *= 0.8; - } - } - // Once cooled below legalise threshold, run legalisation and start requiring - // legal moves only - if (temp < legalise_temp && !require_legal) { - legalise_design(ctx); - require_legal = true; - autoplaced.clear(); - for (auto cell : sorted(ctx->cells)) { - if (cell.second->belStrength < STRENGTH_STRONG) - autoplaced.push_back(cell.second); - } - temp = post_legalise_temp; - diameter *= post_legalise_dia_scale; - ctx->shuffle(autoplaced); - assign_budget(ctx); - } - - // Recalculate total wirelength entirely to avoid rounding errors - // accumulating over time - curr_wirelength = 0; - curr_tns = 0; - for (auto &net : ctx->nets) { - wirelen_t wl = get_net_wirelength(ctx, net.second.get(), curr_tns); - wirelengths[net.first] = wl; - curr_wirelength += wl; - } - } - // Final post-pacement validitiy check - for (auto bel : ctx->getBels()) { - IdString cell = ctx->getBoundBelCell(bel); - if (!ctx->isBelLocationValid(bel)) { - std::string cell_text = "no cell"; - if (cell != IdString()) - cell_text = std::string("cell '") + cell.str(ctx) + "'"; - if (ctx->force) { - log_warning("post-placement validity check failed for Bel '%s' " - "(%s)\n", - ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); - } else { - log_error("post-placement validity check failed for Bel '%s' " - "(%s)\n", - ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); - } - } - } - return true; - } - - private: - // Initial random placement - void place_initial(CellInfo *cell) - { - bool all_placed = false; - int iters = 25; - while (!all_placed) { - BelId best_bel = BelId(); - uint64_t best_score = std::numeric_limits::max(), - best_ripup_score = std::numeric_limits::max(); - CellInfo *ripup_target = nullptr; - BelId ripup_bel = BelId(); - if (cell->bel != BelId()) { - ctx->unbindBel(cell->bel); - } - BelType targetType = ctx->belTypeFromId(cell->type); - for (auto bel : ctx->getBels()) { - if (ctx->getBelType(bel) == targetType && (ctx->isValidBelForCell(cell, bel) || !require_legal)) { - if (ctx->checkBelAvail(bel)) { - uint64_t score = ctx->rng64(); - if (score <= best_score) { - best_score = score; - best_bel = bel; - } - } else { - uint64_t score = ctx->rng64(); - if (score <= best_ripup_score) { - best_ripup_score = score; - ripup_target = ctx->cells.at(ctx->getBoundBelCell(bel)).get(); - ripup_bel = bel; - } - } - } - } - if (best_bel == BelId()) { - if (iters == 0 || ripup_bel == BelId()) - log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx)); - --iters; - ctx->unbindBel(ripup_target->bel); - best_bel = ripup_bel; - } else { - all_placed = true; - } - ctx->bindBel(best_bel, cell->name, STRENGTH_WEAK); - - // Back annotate location - cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx); - cell = ripup_target; - } - } - - // Attempt a SA position swap, return true on success or false on failure - bool try_swap_position(CellInfo *cell, BelId newBel) - { - static std::unordered_set update; - static std::vector> new_lengths; - new_lengths.clear(); - update.clear(); - BelId oldBel = cell->bel; - IdString other = ctx->getBoundBelCell(newBel); - CellInfo *other_cell = nullptr; - if (other != IdString()) { - other_cell = ctx->cells[other].get(); - if (other_cell->belStrength > STRENGTH_WEAK) - return false; - } - wirelen_t new_wirelength = 0, delta; - ctx->unbindBel(oldBel); - if (other != IdString()) { - ctx->unbindBel(newBel); - } - - for (const auto &port : cell->ports) - if (port.second.net != nullptr) - update.insert(port.second.net); - - if (other != IdString()) { - for (const auto &port : other_cell->ports) - if (port.second.net != nullptr) - update.insert(port.second.net); - } - - ctx->bindBel(newBel, cell->name, STRENGTH_WEAK); - - if (other != IdString()) { - ctx->bindBel(oldBel, other_cell->name, STRENGTH_WEAK); - } - if (require_legal) { - if (!ctx->isBelLocationValid(newBel) || ((other != IdString() && !ctx->isBelLocationValid(oldBel)))) { - ctx->unbindBel(newBel); - if (other != IdString()) - ctx->unbindBel(oldBel); - goto swap_fail; - } - } - - new_wirelength = curr_wirelength; - - // Recalculate wirelengths for all nets touched by the peturbation - for (auto net : update) { - new_wirelength -= wirelengths.at(net->name); - float temp_tns = 0; - wirelen_t net_new_wl = get_net_wirelength(ctx, net, temp_tns); - new_wirelength += net_new_wl; - new_lengths.push_back(std::make_pair(net->name, net_new_wl)); - } - delta = new_wirelength - curr_wirelength; - n_move++; - // SA acceptance criterea - if (delta < 0 || (temp > 1e-6 && (ctx->rng() / float(0x3fffffff)) <= std::exp(-delta / temp))) { - n_accept++; - if (delta < 2) - improved = true; - } else { - if (other != IdString()) - ctx->unbindBel(oldBel); - ctx->unbindBel(newBel); - goto swap_fail; - } - curr_wirelength = new_wirelength; - for (auto new_wl : new_lengths) - wirelengths.at(new_wl.first) = new_wl.second; - - return true; - swap_fail: - ctx->bindBel(oldBel, cell->name, STRENGTH_WEAK); - if (other != IdString()) { - ctx->bindBel(newBel, other, STRENGTH_WEAK); - } - return false; - } - - // Find a random Bel of the correct type for a cell, within the specified - // diameter - BelId random_bel_for_cell(CellInfo *cell) - { - BelType targetType = ctx->belTypeFromId(cell->type); - int x, y; - bool gb; - ctx->estimatePosition(cell->bel, x, y, gb); - while (true) { - int nx = ctx->rng(2 * diameter + 1) + std::max(x - diameter, 0); - int ny = ctx->rng(2 * diameter + 1) + std::max(y - diameter, 0); - int beltype_idx = bel_types.at(targetType); - if (nx >= int(fast_bels.at(beltype_idx).size())) - continue; - if (ny >= int(fast_bels.at(beltype_idx).at(nx).size())) - continue; - const auto &fb = fast_bels.at(beltype_idx).at(nx).at(ny); - if (fb.size() == 0) - continue; - BelId bel = fb.at(ctx->rng(int(fb.size()))); - if (locked_bels.find(bel) != locked_bels.end()) - continue; - return bel; - } - } - - Context *ctx; - std::unordered_map wirelengths; - wirelen_t curr_wirelength = std::numeric_limits::max(); - float curr_tns = 0; - float temp = 1000; - bool improved = false; - int n_move, n_accept; - int diameter = 35, max_x = 1, max_y = 1; - std::unordered_map bel_types; - std::vector>>> fast_bels; - std::unordered_set locked_bels; - bool require_legal = false; - const float legalise_temp = 1; - const float post_legalise_temp = 20; - const float post_legalise_dia_scale = 2; -}; - -bool place_design_sa(Context *ctx) -{ - try { - SAPlacer placer(ctx); - placer.place(); - log_info("Checksum: 0x%08x\n", ctx->checksum()); -#ifndef NDEBUG - ctx->check(); -#endif - return true; - } catch (log_execution_error_exception) { -#ifndef NDEBUG - ctx->check(); -#endif - return false; - } -} - -NEXTPNR_NAMESPACE_END diff --git a/common/place_sa.h b/common/place_sa.h deleted file mode 100644 index 1fd8c712..00000000 --- a/common/place_sa.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2018 Clifford Wolf - * - * 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. - * - */ -#ifndef PLACE_H -#define PLACE_H - -#include "nextpnr.h" - -NEXTPNR_NAMESPACE_BEGIN - -extern bool place_design_sa(Context *ctx); - -NEXTPNR_NAMESPACE_END - -#endif // PLACE_H diff --git a/common/placer1.cc b/common/placer1.cc new file mode 100644 index 00000000..53295a91 --- /dev/null +++ b/common/placer1.cc @@ -0,0 +1,450 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah + * + * Simulated annealing implementation based on arachne-pnr + * Copyright (C) 2015-2018 Cotton Seed + * + * 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 "placer1.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "place_common.h" +#include "place_legaliser.h" +#include "timing.h" +#include "util.h" +NEXTPNR_NAMESPACE_BEGIN + +class SAPlacer +{ + public: + SAPlacer(Context *ctx) : ctx(ctx) + { + int num_bel_types = 0; + for (auto bel : ctx->getBels()) { + int x, y; + bool gb; + ctx->estimatePosition(bel, x, y, gb); + BelType type = ctx->getBelType(bel); + int type_idx; + if (bel_types.find(type) == bel_types.end()) { + type_idx = num_bel_types++; + bel_types[type] = type_idx; + } else { + type_idx = bel_types.at(type); + } + if (int(fast_bels.size()) < type_idx + 1) + fast_bels.resize(type_idx + 1); + if (int(fast_bels.at(type_idx).size()) < (x + 1)) + fast_bels.at(type_idx).resize(x + 1); + if (int(fast_bels.at(type_idx).at(x).size()) < (y + 1)) + fast_bels.at(type_idx).at(x).resize(y + 1); + max_x = std::max(max_x, x); + max_y = std::max(max_y, y); + fast_bels.at(type_idx).at(x).at(y).push_back(bel); + } + diameter = std::max(max_x, max_y) + 1; + } + + bool place() + { + log_break(); + + size_t placed_cells = 0; + // Initial constraints placer + for (auto &cell_entry : ctx->cells) { + CellInfo *cell = cell_entry.second.get(); + auto loc = cell->attrs.find(ctx->id("BEL")); + if (loc != cell->attrs.end()) { + std::string loc_name = loc->second; + BelId bel = ctx->getBelByName(ctx->id(loc_name)); + if (bel == BelId()) { + log_error("No Bel named \'%s\' located for " + "this chip (processing BEL attribute on \'%s\')\n", + loc_name.c_str(), cell->name.c_str(ctx)); + } + + BelType bel_type = ctx->getBelType(bel); + if (bel_type != ctx->belTypeFromId(cell->type)) { + log_error("Bel \'%s\' of type \'%s\' does not match cell " + "\'%s\' of type \'%s\'", + loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(ctx), cell->name.c_str(ctx), + cell->type.c_str(ctx)); + } + + ctx->bindBel(bel, cell->name, STRENGTH_USER); + locked_bels.insert(bel); + placed_cells++; + } + } + int constr_placed_cells = placed_cells; + log_info("Placed %d cells based on constraints.\n", int(placed_cells)); + + // Sort to-place cells for deterministic initial placement + std::vector autoplaced; + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); + if (ci->bel == BelId()) { + autoplaced.push_back(cell.second.get()); + } + } + std::sort(autoplaced.begin(), autoplaced.end(), [](CellInfo *a, CellInfo *b) { return a->name < b->name; }); + ctx->shuffle(autoplaced); + + // Place cells randomly initially + log_info("Creating initial placement for remaining %d cells.\n", int(autoplaced.size())); + + for (auto cell : autoplaced) { + place_initial(cell); + placed_cells++; + if ((placed_cells - constr_placed_cells) % 500 == 0) + log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells), + int(autoplaced.size())); + } + if ((placed_cells - constr_placed_cells) % 500 != 0) + log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells), + int(autoplaced.size())); + + log_info("Running simulated annealing placer.\n"); + + // Calculate wirelength after initial placement + curr_wirelength = 0; + curr_tns = 0; + for (auto &net : ctx->nets) { + wirelen_t wl = get_net_wirelength(ctx, net.second.get(), curr_tns); + wirelengths[net.first] = wl; + curr_wirelength += wl; + } + + int n_no_progress = 0; + double avg_wirelength = curr_wirelength; + temp = 10000; + + // Main simulated annealing loop + for (int iter = 1;; iter++) { + n_move = n_accept = 0; + improved = false; + + if (iter % 5 == 0 || iter == 1) + log_info(" at iteration #%d: temp = %f, wire length = " + "%.0f, est tns = %.02fns\n", + iter, temp, double(curr_wirelength), curr_tns); + + for (int m = 0; m < 15; ++m) { + // Loop through all automatically placed cells + for (auto cell : autoplaced) { + // Find another random Bel for this cell + BelId try_bel = random_bel_for_cell(cell); + // If valid, try and swap to a new position and see if + // the new position is valid/worthwhile + if (try_bel != BelId() && try_bel != cell->bel) + try_swap_position(cell, try_bel); + } + } + // Heuristic to improve placement on the 8k + if (improved) + n_no_progress = 0; + else + n_no_progress++; + + if (temp <= 1e-3 && n_no_progress >= 5) { + if (iter % 5 != 0) + log_info(" at iteration #%d: temp = %f, wire length = %f\n", iter, temp, double(curr_wirelength)); + break; + } + + double Raccept = double(n_accept) / double(n_move); + + int M = std::max(max_x, max_y) + 1; + + double upper = 0.6, lower = 0.4; + + if (curr_wirelength < 0.95 * avg_wirelength) { + avg_wirelength = 0.8 * avg_wirelength + 0.2 * curr_wirelength; + } else { + if (Raccept >= 0.8) { + temp *= 0.7; + } else if (Raccept > upper) { + if (diameter < M) + diameter++; + else + temp *= 0.9; + } else if (Raccept > lower) { + temp *= 0.95; + } else { + // Raccept < 0.3 + if (diameter > 1) + diameter--; + else + temp *= 0.8; + } + } + // Once cooled below legalise threshold, run legalisation and start requiring + // legal moves only + if (temp < legalise_temp && !require_legal) { + legalise_design(ctx); + require_legal = true; + autoplaced.clear(); + for (auto cell : sorted(ctx->cells)) { + if (cell.second->belStrength < STRENGTH_STRONG) + autoplaced.push_back(cell.second); + } + temp = post_legalise_temp; + diameter *= post_legalise_dia_scale; + ctx->shuffle(autoplaced); + assign_budget(ctx); + } + + // Recalculate total wirelength entirely to avoid rounding errors + // accumulating over time + curr_wirelength = 0; + curr_tns = 0; + for (auto &net : ctx->nets) { + wirelen_t wl = get_net_wirelength(ctx, net.second.get(), curr_tns); + wirelengths[net.first] = wl; + curr_wirelength += wl; + } + } + // Final post-pacement validitiy check + for (auto bel : ctx->getBels()) { + IdString cell = ctx->getBoundBelCell(bel); + if (!ctx->isBelLocationValid(bel)) { + std::string cell_text = "no cell"; + if (cell != IdString()) + cell_text = std::string("cell '") + cell.str(ctx) + "'"; + if (ctx->force) { + log_warning("post-placement validity check failed for Bel '%s' " + "(%s)\n", + ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); + } else { + log_error("post-placement validity check failed for Bel '%s' " + "(%s)\n", + ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); + } + } + } + return true; + } + + private: + // Initial random placement + void place_initial(CellInfo *cell) + { + bool all_placed = false; + int iters = 25; + while (!all_placed) { + BelId best_bel = BelId(); + uint64_t best_score = std::numeric_limits::max(), + best_ripup_score = std::numeric_limits::max(); + CellInfo *ripup_target = nullptr; + BelId ripup_bel = BelId(); + if (cell->bel != BelId()) { + ctx->unbindBel(cell->bel); + } + BelType targetType = ctx->belTypeFromId(cell->type); + for (auto bel : ctx->getBels()) { + if (ctx->getBelType(bel) == targetType && (ctx->isValidBelForCell(cell, bel) || !require_legal)) { + if (ctx->checkBelAvail(bel)) { + uint64_t score = ctx->rng64(); + if (score <= best_score) { + best_score = score; + best_bel = bel; + } + } else { + uint64_t score = ctx->rng64(); + if (score <= best_ripup_score) { + best_ripup_score = score; + ripup_target = ctx->cells.at(ctx->getBoundBelCell(bel)).get(); + ripup_bel = bel; + } + } + } + } + if (best_bel == BelId()) { + if (iters == 0 || ripup_bel == BelId()) + log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx)); + --iters; + ctx->unbindBel(ripup_target->bel); + best_bel = ripup_bel; + } else { + all_placed = true; + } + ctx->bindBel(best_bel, cell->name, STRENGTH_WEAK); + + // Back annotate location + cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx); + cell = ripup_target; + } + } + + // Attempt a SA position swap, return true on success or false on failure + bool try_swap_position(CellInfo *cell, BelId newBel) + { + static std::unordered_set update; + static std::vector> new_lengths; + new_lengths.clear(); + update.clear(); + BelId oldBel = cell->bel; + IdString other = ctx->getBoundBelCell(newBel); + CellInfo *other_cell = nullptr; + if (other != IdString()) { + other_cell = ctx->cells[other].get(); + if (other_cell->belStrength > STRENGTH_WEAK) + return false; + } + wirelen_t new_wirelength = 0, delta; + ctx->unbindBel(oldBel); + if (other != IdString()) { + ctx->unbindBel(newBel); + } + + for (const auto &port : cell->ports) + if (port.second.net != nullptr) + update.insert(port.second.net); + + if (other != IdString()) { + for (const auto &port : other_cell->ports) + if (port.second.net != nullptr) + update.insert(port.second.net); + } + + ctx->bindBel(newBel, cell->name, STRENGTH_WEAK); + + if (other != IdString()) { + ctx->bindBel(oldBel, other_cell->name, STRENGTH_WEAK); + } + if (require_legal) { + if (!ctx->isBelLocationValid(newBel) || ((other != IdString() && !ctx->isBelLocationValid(oldBel)))) { + ctx->unbindBel(newBel); + if (other != IdString()) + ctx->unbindBel(oldBel); + goto swap_fail; + } + } + + new_wirelength = curr_wirelength; + + // Recalculate wirelengths for all nets touched by the peturbation + for (auto net : update) { + new_wirelength -= wirelengths.at(net->name); + float temp_tns = 0; + wirelen_t net_new_wl = get_net_wirelength(ctx, net, temp_tns); + new_wirelength += net_new_wl; + new_lengths.push_back(std::make_pair(net->name, net_new_wl)); + } + delta = new_wirelength - curr_wirelength; + n_move++; + // SA acceptance criterea + if (delta < 0 || (temp > 1e-6 && (ctx->rng() / float(0x3fffffff)) <= std::exp(-delta / temp))) { + n_accept++; + if (delta < 2) + improved = true; + } else { + if (other != IdString()) + ctx->unbindBel(oldBel); + ctx->unbindBel(newBel); + goto swap_fail; + } + curr_wirelength = new_wirelength; + for (auto new_wl : new_lengths) + wirelengths.at(new_wl.first) = new_wl.second; + + return true; + swap_fail: + ctx->bindBel(oldBel, cell->name, STRENGTH_WEAK); + if (other != IdString()) { + ctx->bindBel(newBel, other, STRENGTH_WEAK); + } + return false; + } + + // Find a random Bel of the correct type for a cell, within the specified + // diameter + BelId random_bel_for_cell(CellInfo *cell) + { + BelType targetType = ctx->belTypeFromId(cell->type); + int x, y; + bool gb; + ctx->estimatePosition(cell->bel, x, y, gb); + while (true) { + int nx = ctx->rng(2 * diameter + 1) + std::max(x - diameter, 0); + int ny = ctx->rng(2 * diameter + 1) + std::max(y - diameter, 0); + int beltype_idx = bel_types.at(targetType); + if (nx >= int(fast_bels.at(beltype_idx).size())) + continue; + if (ny >= int(fast_bels.at(beltype_idx).at(nx).size())) + continue; + const auto &fb = fast_bels.at(beltype_idx).at(nx).at(ny); + if (fb.size() == 0) + continue; + BelId bel = fb.at(ctx->rng(int(fb.size()))); + if (locked_bels.find(bel) != locked_bels.end()) + continue; + return bel; + } + } + + Context *ctx; + std::unordered_map wirelengths; + wirelen_t curr_wirelength = std::numeric_limits::max(); + float curr_tns = 0; + float temp = 1000; + bool improved = false; + int n_move, n_accept; + int diameter = 35, max_x = 1, max_y = 1; + std::unordered_map bel_types; + std::vector>>> fast_bels; + std::unordered_set locked_bels; + bool require_legal = false; + const float legalise_temp = 1; + const float post_legalise_temp = 20; + const float post_legalise_dia_scale = 2; +}; + +bool placer1(Context *ctx) +{ + try { + SAPlacer placer(ctx); + placer.place(); + log_info("Checksum: 0x%08x\n", ctx->checksum()); +#ifndef NDEBUG + ctx->check(); +#endif + return true; + } catch (log_execution_error_exception) { +#ifndef NDEBUG + ctx->check(); +#endif + return false; + } +} + +NEXTPNR_NAMESPACE_END diff --git a/common/placer1.h b/common/placer1.h new file mode 100644 index 00000000..477fae56 --- /dev/null +++ b/common/placer1.h @@ -0,0 +1,30 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * 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. + * + */ +#ifndef PLACE_H +#define PLACE_H + +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +extern bool placer1(Context *ctx); + +NEXTPNR_NAMESPACE_END + +#endif // PLACE_H diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 74548391..7383e0e7 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -23,6 +23,7 @@ #include #include "log.h" #include "nextpnr.h" +#include "placer1.h" #include "router1.h" #include "util.h" @@ -289,6 +290,11 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const // ----------------------------------------------------------------------- +bool Arch::place() +{ + return placer1(getCtx()); +} + bool Arch::route() { return router1(getCtx()); diff --git a/ecp5/arch.h b/ecp5/arch.h index c9c5a6a1..5f01c8c8 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -720,6 +720,7 @@ struct Arch : BaseCtx // ------------------------------------------------- + bool place(); bool route(); // ------------------------------------------------- diff --git a/ecp5/main.cc b/ecp5/main.cc index a6128d0f..45774431 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -44,7 +44,6 @@ #include "design_utils.h" #include "jsonparse.h" #include "pack.h" -#include "place_sa.h" #include "timing.h" USING_NEXTPNR_NAMESPACE @@ -146,7 +145,7 @@ int main(int argc, char *argv[]) if (vm.count("no-tmdriv")) ctx.timing_driven = false; - if (!place_design_sa(&ctx) && !ctx.force) + if (!ctx.place() && !ctx.force) log_error("Placing design failed.\n"); ctx.check(); if (!ctx.route() && !ctx.force) diff --git a/generic/arch.cc b/generic/arch.cc index b82d8ce6..2282b2b8 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -19,6 +19,7 @@ #include #include "nextpnr.h" +#include "placer1.h" #include "router1.h" NEXTPNR_NAMESPACE_BEGIN @@ -316,6 +317,11 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const // --------------------------------------------------------------- +bool Arch::place() +{ + return placer1(getCtx()); +} + bool Arch::route() { return router1(getCtx()); diff --git a/generic/arch.h b/generic/arch.h index 60ac9435..85f469f9 100644 --- a/generic/arch.h +++ b/generic/arch.h @@ -158,6 +158,7 @@ struct Arch : BaseCtx float getDelayNS(delay_t v) const { return v; } uint32_t getDelayChecksum(delay_t v) const { return 0; } + bool place(); bool route(); const std::vector &getDecalGraphics(DecalId decal) const; diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index ea7e0667..6f0a9b97 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -29,7 +29,6 @@ #include "log.h" #include "pack.h" #include "pcf.h" -#include "place_sa.h" static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc index fc21ed34..16f5fb89 100644 --- a/gui/ice40/worker.cc +++ b/gui/ice40/worker.cc @@ -25,7 +25,6 @@ #include "log.h" #include "pack.h" #include "pcf.h" -#include "place_sa.h" #include "timing.h" NEXTPNR_NAMESPACE_BEGIN @@ -123,7 +122,7 @@ void Worker::place(bool timing_driven) Q_EMIT taskStarted(); try { ctx->timing_driven = timing_driven; - Q_EMIT place_finished(place_design_sa(ctx)); + Q_EMIT place_finished(ctx->place()); } catch (WorkerInterruptionRequested) { Q_EMIT taskCanceled(); } diff --git a/ice40/arch.cc b/ice40/arch.cc index 0bb27d38..1e6b4569 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -21,6 +21,7 @@ #include #include "log.h" #include "nextpnr.h" +#include "placer1.h" #include "router1.h" #include "util.h" #include "gfx.h" @@ -401,6 +402,11 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const // ----------------------------------------------------------------------- +bool Arch::place() +{ + return placer1(getCtx()); +} + bool Arch::route() { return router1(getCtx()); diff --git a/ice40/arch.h b/ice40/arch.h index 02c37fae..659139a6 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -643,6 +643,7 @@ struct Arch : BaseCtx // ------------------------------------------------- + bool place(); bool route(); // ------------------------------------------------- diff --git a/ice40/main.cc b/ice40/main.cc index f586a079..2427ea6c 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -42,7 +42,6 @@ #include "pack.h" #include "pcf.h" #include "place_legaliser.h" -#include "place_sa.h" #include "timing.h" #include "version.h" @@ -372,7 +371,7 @@ int main(int argc, char *argv[]) if (vm.count("no-tmdriv")) ctx.timing_driven = false; if (!vm.count("pack-only")) { - if (!place_design_sa(&ctx) && !ctx.force) + if (!ctx.place() && !ctx.force) log_error("Placing design failed.\n"); ctx.check(); if (!ctx.route() && !ctx.force) -- cgit v1.2.3 From 0d979b964e1db576fc5c702a80c418ba6a1ffe09 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 11 Jul 2018 18:15:25 +0200 Subject: Fix layout --- gui/designwidget.cc | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index b38d5a4c..98fd3f30 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -118,11 +118,32 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net toolbar->addAction(actionNext); toolbar->addAction(actionLast); + QWidget *topWidget = new QWidget(); + QVBoxLayout *vbox1 = new QVBoxLayout(); + topWidget->setLayout(vbox1); + vbox1->setSpacing(5); + vbox1->setContentsMargins(0, 0, 0, 0); + vbox1->addWidget(lineEdit); + vbox1->addWidget(treeWidget); + + QWidget *toolbarWidget = new QWidget(); + QHBoxLayout *hbox = new QHBoxLayout; + hbox->setAlignment(Qt::AlignCenter); + toolbarWidget->setLayout(hbox); + hbox->addWidget(toolbar); + + QWidget *btmWidget = new QWidget(); + + QVBoxLayout *vbox2 = new QVBoxLayout(); + btmWidget->setLayout(vbox2); + vbox2->setSpacing(5); + vbox2->setContentsMargins(0, 0, 0, 0); + vbox2->addWidget(toolbarWidget); + vbox2->addWidget(propertyEditor); + QSplitter *splitter = new QSplitter(Qt::Vertical); - splitter->addWidget(lineEdit); - splitter->addWidget(treeWidget); - splitter->addWidget(toolbar); - splitter->addWidget(propertyEditor); + splitter->addWidget(topWidget); + splitter->addWidget(btmWidget); QGridLayout *mainLayout = new QGridLayout(); mainLayout->setSpacing(0); -- cgit v1.2.3 From 9baefa27423900e71d5fa2131a349e5dde2547a7 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 11 Jul 2018 18:16:59 +0200 Subject: Fix usage of refreshUi API in generic arch Signed-off-by: Clifford Wolf --- generic/arch.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/generic/arch.cc b/generic/arch.cc index 2282b2b8..60874e1e 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -112,30 +112,31 @@ void Arch::addBelInout(IdString bel, IdString name, IdString wire) void Arch::addDecalGraphic(DecalId decal, const GraphicElement &graphic) { decal_graphics[decal].push_back(graphic); + refreshUi(); } void Arch::setFrameDecal(DecalXY decalxy) { frame_decalxy = decalxy; - frameGraphicsReload = true; + refreshUiFrame(); } void Arch::setWireDecal(WireId wire, DecalXY decalxy) { wires.at(wire).decalxy = decalxy; - wireGraphicsReload.insert(wire); + refreshUiWire(wire); } void Arch::setPipDecal(PipId pip, DecalXY decalxy) { pips.at(pip).decalxy = decalxy; - pipGraphicsReload.insert(pip); + refreshUiPip(pip); } void Arch::setBelDecal(BelId bel, DecalXY decalxy) { bels.at(bel).decalxy = decalxy; - belGraphicsReload.insert(bel); + refreshUiBel(bel); } // --------------------------------------------------------------- -- cgit v1.2.3 From 6ffae27aa14ee48ebd5713e540bfc53568e56fd6 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 11 Jul 2018 18:36:15 +0200 Subject: Deterministic chipdb blobs Signed-off-by: Clifford Wolf --- ecp5/trellis_import.py | 2 +- ice40/chipdb.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index 60e48844..5fdd7296 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -331,7 +331,7 @@ class BinaryBlobAssembler: def finalize(self): assert not self.finalized - for s, index in self.strings.items(): + for s, index in sorted(self.strings.items()): self.l("str%d" % index, "char") for c in s: self.data.append(ord(c)) diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 931c73d1..2a918ed9 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -712,7 +712,7 @@ class BinaryBlobAssembler: def finalize(self): assert not self.finalized - for s, index in self.strings.items(): + for s, index in sorted(self.strings.items()): self.l("str%d" % index, "char") for c in s: self.data.append(ord(c)) @@ -947,7 +947,7 @@ for wire in range(num_wires): if wire in wire_downhill_belports: num_bels_downhill = len(wire_downhill_belports[wire]) bba.l("wire%d_downbels" % wire, "BelPortPOD") - for belport in wire_downhill_belports[wire]: + for belport in sorted(wire_downhill_belports[wire]): bba.u32(belport[0], "bel_index") bba.u32(portpins[belport[1]], "port") else: -- cgit v1.2.3 From ab5798e09efe525d51827773f895c6fd2e9a2d0c Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 11 Jul 2018 18:25:48 +0200 Subject: margins fix --- gui/designwidget.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 98fd3f30..027512af 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -130,13 +130,15 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net QHBoxLayout *hbox = new QHBoxLayout; hbox->setAlignment(Qt::AlignCenter); toolbarWidget->setLayout(hbox); + hbox->setSpacing(0); + hbox->setContentsMargins(0, 0, 0, 0); hbox->addWidget(toolbar); QWidget *btmWidget = new QWidget(); QVBoxLayout *vbox2 = new QVBoxLayout(); btmWidget->setLayout(vbox2); - vbox2->setSpacing(5); + vbox2->setSpacing(0); vbox2->setContentsMargins(0, 0, 0, 0); vbox2->addWidget(toolbarWidget); vbox2->addWidget(propertyEditor); -- cgit v1.2.3 From 93214a2fb041769e2c9f783ec3d187b3d74d3f7c Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 11 Jul 2018 18:30:56 +0200 Subject: disable actions and make them accesible --- gui/designwidget.cc | 12 ++++++++---- gui/designwidget.h | 5 +++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 027512af..14de974e 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -96,21 +96,25 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net lineEdit->addAction(searchIcon, QLineEdit::LeadingPosition); lineEdit->setPlaceholderText("Search..."); - QAction *actionFirst = new QAction("", this); + actionFirst = new QAction("", this); QIcon iconFirst(QStringLiteral(":/icons/resources/resultset_first.png")); actionFirst->setIcon(iconFirst); + actionFirst->setEnabled(false); - QAction *actionPrev = new QAction("", this); + actionPrev = new QAction("", this); QIcon iconPrev(QStringLiteral(":/icons/resources/resultset_previous.png")); actionPrev->setIcon(iconPrev); + actionPrev->setEnabled(false); - QAction *actionNext = new QAction("", this); + actionNext = new QAction("", this); QIcon iconNext(QStringLiteral(":/icons/resources/resultset_next.png")); actionNext->setIcon(iconNext); + actionNext->setEnabled(false); - QAction *actionLast = new QAction("", this); + actionLast = new QAction("", this); QIcon iconLast(QStringLiteral(":/icons/resources/resultset_last.png")); actionLast->setIcon(iconLast); + actionLast->setEnabled(false); QToolBar *toolbar = new QToolBar(); toolbar->addAction(actionFirst); diff --git a/gui/designwidget.h b/gui/designwidget.h index 7785513a..ce0220dd 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -68,6 +68,11 @@ class DesignWidget : public QWidget QMap idToProperty; QTreeWidgetItem *nets_root; QTreeWidgetItem *cells_root; + + QAction *actionFirst; + QAction *actionPrev; + QAction *actionNext; + QAction *actionLast; }; NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From 33e592e55e30e097db08218d4dc0888c6058f5f2 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 11 Jul 2018 19:02:30 +0200 Subject: Add missing wires to ice40 gfx Signed-off-by: Clifford Wolf --- ice40/gfx.cc | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/ice40/gfx.cc b/ice40/gfx.cc index 2d6b048b..64bb66ec 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -364,7 +364,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.type = GraphicElement::G_LINE; el.x1 = x + local_swbox_x2; el.x2 = x + logic_cell_x1; - el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0125 + (0.005 * input) + z * logic_cell_pitch; + el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * input) + z * logic_cell_pitch; el.y2 = el.y1; g.push_back(el); } @@ -404,7 +404,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.x1 = x + main_swbox_x2 - 0.005 * (idx + 5); el.x2 = el.x1; el.y1 = y + main_swbox_y1; - el.y2 = el.y1 - 0.005 * (idx + 3); + el.y2 = el.y1 - 0.005 * (idx + 2); g.push_back(el); el.y1 = el.y2; @@ -414,6 +414,58 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) el.y2 = y + logic_cell_y1; el.x1 = el.x2; g.push_back(el); + + for (int i = 0; i < 7; i ++) { + el.y1 = y + logic_cell_y2 + i * logic_cell_pitch; + el.y2 = y + logic_cell_y1 + (i + 1) * logic_cell_pitch; + g.push_back(el); + } + } + + // LC Cascade + + if (id >= TILE_WIRE_LUTFF_0_LOUT && id <= TILE_WIRE_LUTFF_6_LOUT) { + int idx = id - TILE_WIRE_LUTFF_0_LOUT; + GraphicElement el; + el.type = GraphicElement::G_LINE; + el.x1 = x + logic_cell_x1 + 0.005 * 5; + el.x2 = el.x1; + el.y1 = y + logic_cell_y2 + idx * logic_cell_pitch; + el.y2 = y + logic_cell_y1 + (idx + 1) * logic_cell_pitch; + g.push_back(el); + } + + // Carry Chain + + if (id >= TILE_WIRE_LUTFF_0_COUT && id <= TILE_WIRE_LUTFF_7_COUT) { + int idx = id - TILE_WIRE_LUTFF_0_COUT; + GraphicElement el; + el.type = GraphicElement::G_LINE; + el.x1 = x + logic_cell_x1 + 0.005 * 3; + el.x2 = el.x1; + el.y1 = y + logic_cell_y2 + idx * logic_cell_pitch; + el.y2 = y + (idx < 7 ? logic_cell_y1 + (idx + 1) * logic_cell_pitch : 1.0); + g.push_back(el); + } + + if (id == TILE_WIRE_CARRY_IN) { + GraphicElement el; + el.type = GraphicElement::G_LINE; + el.x1 = x + logic_cell_x1 + 0.005 * 3; + el.x2 = el.x1; + el.y1 = y; + el.y2 = y + 0.01; + g.push_back(el); + } + + if (id == TILE_WIRE_CARRY_IN_MUX) { + GraphicElement el; + el.type = GraphicElement::G_LINE; + el.x1 = x + logic_cell_x1 + 0.005 * 3; + el.x2 = el.x1; + el.y1 = y + 0.02; + el.y2 = y + logic_cell_y1; + g.push_back(el); } } -- cgit v1.2.3 From 9e06954edb1071b4ef2e7ebc525d8c6de42d0fc3 Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 12 Jul 2018 10:09:56 +0200 Subject: ecp5: Improving SLICE bel Signed-off-by: David Shah --- ecp5/portpins.inc | 18 ++++++++++++++++++ ecp5/synth/cells.v | 12 +++++++++++- ecp5/trellis_import.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/ecp5/portpins.inc b/ecp5/portpins.inc index cfe0a349..ab0ebe9f 100644 --- a/ecp5/portpins.inc +++ b/ecp5/portpins.inc @@ -14,6 +14,16 @@ X(FXB) X(CLK) X(LSR) X(CE) +X(DI0) +X(DI1) +X(WD0) +X(WD1) +X(WAD0) +X(WAD1) +X(WAD2) +X(WAD3) +X(WRE) +X(WCK) X(F0) X(Q0) X(F1) @@ -21,6 +31,14 @@ X(Q1) X(FCO) X(OFX0) X(OFX1) +X(WDO0) +X(WDO1) +X(WDO2) +X(WDO3) +X(WADO0) +X(WADO1) +X(WADO2) +X(WADO3) X(I) X(O) diff --git a/ecp5/synth/cells.v b/ecp5/synth/cells.v index d2c6d560..353b8ada 100644 --- a/ecp5/synth/cells.v +++ b/ecp5/synth/cells.v @@ -4,10 +4,20 @@ module TRELLIS_SLICE( input A1, B1, C1, D1, input M0, M1, input FCI, FXA, FXB, + input CLK, LSR, CE, + input DI0, DI1, + + input WD0, WD1, + input WAD0, WAD1, WAD2, WAD3, + input WRE, WCK, + output F0, Q0, output F1, Q1, - output FCO, OFX0, OFX1 + output FCO, OFX0, OFX1, + + output WDO0, WDO1, WDO2, WDO3, + output WADO0, WADO1, WADO2, WADO3 ); parameter MODE = "LOGIC"; diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index 5fdd7296..5eca057a 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -124,14 +124,43 @@ def add_slice(x, y, z): add_bel_input(x, y, idx, "LSR", x, y, "LSR{}_SLICE".format(z)) add_bel_input(x, y, idx, "CE", x, y, "CE{}_SLICE".format(z)) + add_bel_input(x, y, idx, "DI0", x, y, "DI{}_SLICE".format(lc0)) + add_bel_input(x, y, idx, "DI1", x, y, "DI{}_SLICE".format(lc1)) + + if z == 0 or z == 1: + add_bel_input(x, y, idx, "WD0", x, y, "WD0{}_SLICE".format(l)) + add_bel_input(x, y, idx, "WD1", x, y, "WD1{}_SLICE".format(l)) + + add_bel_input(x, y, idx, "WAD0", x, y, "WAD0{}_SLICE".format(l)) + add_bel_input(x, y, idx, "WAD1", x, y, "WAD1{}_SLICE".format(l)) + add_bel_input(x, y, idx, "WAD2", x, y, "WAD2{}_SLICE".format(l)) + add_bel_input(x, y, idx, "WAD3", x, y, "WAD3{}_SLICE".format(l)) + + add_bel_input(x, y, idx, "WRE", x, y, "WRE{}_SLICE".format(z)) + add_bel_input(x, y, idx, "WCK", x, y, "WCK{}_SLICE".format(z)) + add_bel_output(x, y, idx, "F0", x, y, "F{}_SLICE".format(lc0)) add_bel_output(x, y, idx, "Q0", x, y, "Q{}_SLICE".format(lc0)) add_bel_output(x, y, idx, "F1", x, y, "F{}_SLICE".format(lc1)) add_bel_output(x, y, idx, "Q1", x, y, "Q{}_SLICE".format(lc1)) + add_bel_output(x, y, idx, "OFX0", x, y, "F5{}_SLICE".format(l)) + add_bel_output(x, y, idx, "OFX1", x, y, "FX{}_SLICE".format(l)) + add_bel_output(x, y, idx, "FCO", x, y, "FCO{}_SLICE".format(l if z < 3 else "")) + if z == 2: + add_bel_output(x, y, idx, "WDO0", x, y, "WDO0C_SLICE") + add_bel_output(x, y, idx, "WDO1", x, y, "WDO1C_SLICE") + add_bel_output(x, y, idx, "WDO2", x, y, "WDO2C_SLICE") + add_bel_output(x, y, idx, "WDO3", x, y, "WDO3C_SLICE") + + add_bel_output(x, y, idx, "WADO0", x, y, "WADO0C_SLICE") + add_bel_output(x, y, idx, "WADO1", x, y, "WADO1C_SLICE") + add_bel_output(x, y, idx, "WADO2", x, y, "WADO2C_SLICE") + add_bel_output(x, y, idx, "WADO3", x, y, "WADO3C_SLICE") + def add_pio(x, y, z): idx = len(loc_bels[x, y]) -- cgit v1.2.3 From 24618ee80029a2a22bfd288faba4b211aa6dac2a Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 12 Jul 2018 14:36:28 +0200 Subject: Added python37 as well, fixes latest msys2 build and macOS --- CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index cbcdf67d..27265616 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,6 +133,13 @@ if (BUILD_PYTHON) endif () endif () + if (NOT Boost_PYTHON_FOUND) + find_package(Boost COMPONENTS python37 ${boost_libs}) + if ("${Boost_LIBRARIES}" MATCHES ".*(python|PYTHON).*" ) + set(Boost_PYTHON_FOUND TRUE) + endif () + endif () + if (NOT Boost_PYTHON_FOUND) STRING(REGEX REPLACE "([0-9]+\\.[0-9]+).*" "\\1" gentoo_version ${PYTHONLIBS_VERSION_STRING}) find_package(Boost COMPONENTS python-${gentoo_version} ${boost_libs}) -- cgit v1.2.3 From 1245eb6343f272b6aeb096b0d41407c5ea6bc5cd Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 12 Jul 2018 14:54:16 +0200 Subject: added progress bar for future use --- gui/basewindow.cc | 6 ++++++ gui/basewindow.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 2463027a..5a53e9cf 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -145,6 +145,12 @@ void BaseMainWindow::createMenusAndBars() addToolBar(Qt::TopToolBarArea, mainToolBar); statusBar = new QStatusBar(); + progressBar = new QProgressBar(statusBar); + progressBar->setAlignment(Qt::AlignRight); + progressBar->setMaximumSize(180, 19); + statusBar->addPermanentWidget(progressBar); + progressBar->setValue(0); + progressBar->setEnabled(false); setStatusBar(statusBar); menu_File->addAction(actionNew); diff --git a/gui/basewindow.h b/gui/basewindow.h index 5c06fa6e..c98a0356 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -29,6 +29,7 @@ #include #include #include +#include Q_DECLARE_METATYPE(std::string) @@ -68,6 +69,7 @@ class BaseMainWindow : public QMainWindow QStatusBar *statusBar; QAction *actionNew; QAction *actionOpen; + QProgressBar *progressBar; }; NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From a436035424368b3d424822c7b72f99044c93dafd Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 12 Jul 2018 17:22:29 +0200 Subject: Add Groups API Signed-off-by: Clifford Wolf --- common/nextpnr.h | 19 +++++++++++++++ ecp5/arch.cc | 2 ++ ecp5/arch.h | 11 +++++++++ ecp5/archdefs.h | 19 +++++++++++++++ generic/arch.cc | 50 +++++++++++++++++++++++++++++++++++++++- generic/arch.h | 26 +++++++++++++++++++++ generic/archdefs.h | 1 + gui/fpgaviewwidget.cc | 10 ++++++++ ice40/arch.cc | 64 ++++++++++++++++++++++++++++++++++++++++++++++----- ice40/arch.h | 11 +++++++++ ice40/archdefs.h | 52 ++++++++++++++++++++++++++++++++++++----- 11 files changed, 252 insertions(+), 13 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 09bd1554..a162b85c 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -271,6 +271,7 @@ struct BaseCtx std::unordered_set belUiReload; std::unordered_set wireUiReload; std::unordered_set pipUiReload; + std::unordered_set groupUiReload; void refreshUi() { @@ -296,6 +297,11 @@ struct BaseCtx { pipUiReload.insert(pip); } + + void refreshUiGroup(GroupId group) + { + groupUiReload.insert(group); + } }; NEXTPNR_NAMESPACE_END @@ -368,6 +374,19 @@ struct Context : Arch return ret; } + NPNR_DEPRECATED std::vector getGroupGraphics(GroupId group) const { + std::vector ret; + DecalXY decalxy = getGroupDecal(group); + ret = getDecalGraphics(decalxy.decal); + for (auto &it : ret) { + it.x1 += decalxy.x; + it.x2 += decalxy.x; + it.y1 += decalxy.y; + it.y2 += decalxy.y; + } + return ret; + } + // -------------------------------------------------------------- // provided by router1.cc diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 7383e0e7..286151d8 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -317,6 +317,8 @@ DecalXY Arch::getWireDecal(WireId wire) const { return {}; } DecalXY Arch::getPipDecal(PipId pip) const { return {}; }; +DecalXY Arch::getGroupDecal(PipId pip) const { return {}; }; + // ----------------------------------------------------------------------- bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; } diff --git a/ecp5/arch.h b/ecp5/arch.h index 5f01c8c8..bbc7c561 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -711,6 +711,16 @@ struct Arch : BaseCtx // ------------------------------------------------- + GroupId getGroupByName(IdString name) const { return GroupId(); } + IdString getGroupName(GroupId group) const { return IdString(); } + std::vector getGroups() const { return std::vector(); } + std::vector getGroupBels(GroupId group) const { return std::vector(); } + std::vector getGroupWires(GroupId group) const { return std::vector(); } + std::vector getGroupPips(GroupId group) const { return std::vector(); } + std::vector getGroupGroups(GroupId group) const { return std::vector(); } + + // ------------------------------------------------- + void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; delay_t estimateDelay(WireId src, WireId dst) const; delay_t getDelayEpsilon() const { return 20; } @@ -731,6 +741,7 @@ struct Arch : BaseCtx DecalXY getBelDecal(BelId bel) const; DecalXY getWireDecal(WireId wire) const; DecalXY getPipDecal(PipId pip) const; + DecalXY getGroupDecal(GroupId group) const; // ------------------------------------------------- diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index 79b20619..797db5f7 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -105,11 +105,22 @@ struct PipId bool operator!=(const PipId &other) const { return index != other.index || location != other.location; } }; +struct GroupId +{ + int32_t index = -1; + + bool operator==(const GroupId &other) const { return index == other.index; } + bool operator!=(const GroupId &other) const { return index != other.index; } +}; + struct DecalId { char type = 0; // Bel/Wire/Pip/Frame (b/w/p/f) Location location; uint32_t z = 0; + + bool operator==(const DecalId &other) const { return type == other.type && location == other.location && z == other.z; } + bool operator!=(const DecalId &other) const { return type != other.type || location != other.location || z != other.z; } }; NEXTPNR_NAMESPACE_END @@ -155,6 +166,14 @@ template <> struct hash } }; +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept + { + return std::hash()(group.index); + } +}; + template <> struct hash { std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept diff --git a/generic/arch.cc b/generic/arch.cc index 60874e1e..1e1434d3 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -109,6 +109,26 @@ void Arch::addBelInout(IdString bel, IdString name, IdString wire) wires.at(wire).downhill_bel_pins.push_back(BelPin{bel, name}); } +void Arch::addGroupBel(IdString group, IdString bel) +{ + groups[group].bels.push_back(bel); +} + +void Arch::addGroupWire(IdString group, IdString wire) +{ + groups[group].wires.push_back(wire); +} + +void Arch::addGroupPip(IdString group, IdString pip) +{ + groups[group].pips.push_back(pip); +} + +void Arch::addGroupGroup(IdString group, IdString grp) +{ + groups[group].groups.push_back(grp); +} + void Arch::addDecalGraphic(DecalId decal, const GraphicElement &graphic) { decal_graphics[decal].push_back(graphic); @@ -139,6 +159,12 @@ void Arch::setBelDecal(BelId bel, DecalXY decalxy) refreshUiBel(bel); } +void Arch::setGroupDecal(GroupId group, DecalXY decalxy) +{ + groups[group].decalxy = decalxy; + refreshUiGroup(group); +} + // --------------------------------------------------------------- Arch::Arch(ArchArgs) {} @@ -300,6 +326,27 @@ const std::vector &Arch::getWireAliases(WireId wire) const { return wires // --------------------------------------------------------------- +GroupId Arch::getGroupByName(IdString name) const { return name; } + +IdString Arch::getGroupName(GroupId group) const { return group; } + +std::vector Arch::getGroups() const { + std::vector ret; + for (auto &it : groups) + ret.push_back(it.first); + return ret; +} + +const std::vector &Arch::getGroupBels(GroupId group) const { return groups.at(group).bels; } + +const std::vector &Arch::getGroupWires(GroupId group) const { return groups.at(group).wires; } + +const std::vector &Arch::getGroupPips(GroupId group) const { return groups.at(group).pips; } + +const std::vector &Arch::getGroupGroups(GroupId group) const { return groups.at(group).groups; } + +// --------------------------------------------------------------- + void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const { x = bels.at(bel).grid_x; @@ -330,7 +377,6 @@ bool Arch::route() // --------------------------------------------------------------- - const std::vector &Arch::getDecalGraphics(DecalId decal) const { return decal_graphics.at(decal); } DecalXY Arch::getFrameDecal() const { return frame_decalxy; } @@ -341,6 +387,8 @@ DecalXY Arch::getWireDecal(WireId wire) const { return wires.at(wire).decalxy; } DecalXY Arch::getPipDecal(PipId pip) const { return pips.at(pip).decalxy; } +DecalXY Arch::getGroupDecal(GroupId group) const { return groups.at(group).decalxy; } + // --------------------------------------------------------------- bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, delay_t &delay) const diff --git a/generic/arch.h b/generic/arch.h index 85f469f9..f6243404 100644 --- a/generic/arch.h +++ b/generic/arch.h @@ -63,6 +63,16 @@ struct BelInfo bool gb; }; +struct GroupInfo +{ + IdString name; + std::vector bels; + std::vector wires; + std::vector pips; + std::vector groups; + DecalXY decalxy; +}; + struct Arch : BaseCtx { std::string chipName; @@ -70,6 +80,7 @@ struct Arch : BaseCtx std::unordered_map wires; std::unordered_map pips; std::unordered_map bels; + std::unordered_map groups; std::vector bel_ids, wire_ids, pip_ids; std::unordered_map> bel_ids_by_type; @@ -88,11 +99,17 @@ struct Arch : BaseCtx void addBelOutput(IdString bel, IdString name, IdString wire); void addBelInout(IdString bel, IdString name, IdString wire); + void addGroupBel(IdString group, IdString bel); + void addGroupWire(IdString group, IdString wire); + void addGroupPip(IdString group, IdString pip); + void addGroupGroup(IdString group, IdString grp); + void addDecalGraphic(DecalId decal, const GraphicElement &graphic); void setFrameDecal(DecalXY decalxy); void setWireDecal(WireId wire, DecalXY decalxy); void setPipDecal(PipId pip, DecalXY decalxy); void setBelDecal(BelId bel, DecalXY decalxy); + void setGroupDecal(GroupId group, DecalXY decalxy); // --------------------------------------------------------------- // Common Arch API. Every arch must provide the following methods. @@ -151,6 +168,14 @@ struct Arch : BaseCtx const std::vector &getPipsUphill(WireId wire) const; const std::vector &getWireAliases(WireId wire) const; + GroupId getGroupByName(IdString name) const; + IdString getGroupName(GroupId group) const; + std::vector getGroups() const; + const std::vector &getGroupBels(GroupId group) const; + const std::vector &getGroupWires(GroupId group) const; + const std::vector &getGroupPips(GroupId group) const; + const std::vector &getGroupGroups(GroupId group) const; + void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; delay_t estimateDelay(WireId src, WireId dst) const; delay_t getDelayEpsilon() const { return 0.01; } @@ -166,6 +191,7 @@ struct Arch : BaseCtx DecalXY getBelDecal(BelId bel) const; DecalXY getWireDecal(WireId wire) const; DecalXY getPipDecal(PipId pip) const; + DecalXY getGroupDecal(GroupId group) const; bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, delay_t &delay) const; IdString getPortClock(const CellInfo *cell, IdString port) const; diff --git a/generic/archdefs.h b/generic/archdefs.h index 8e6dcb2f..9969014b 100644 --- a/generic/archdefs.h +++ b/generic/archdefs.h @@ -49,6 +49,7 @@ typedef IdString PortPin; typedef IdString BelId; typedef IdString WireId; typedef IdString PipId; +typedef IdString GroupId; typedef IdString DecalId; NEXTPNR_NAMESPACE_END diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 0c70012f..7a188863 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -383,6 +383,16 @@ void FPGAViewWidget::paintGL() lineShader_.draw(pips, matrix); } + // Draw Groups. + auto groups = LineShaderData(0.0005f, QColor("#b000ba")); + if (ctx_) { + for (auto group : ctx_->getGroups()) { + for (auto &el : ctx_->getGroupGraphics(group)) + drawElement(groups, el); + } + lineShader_.draw(groups, matrix); + } + // Draw Frame Graphics. auto frames = LineShaderData(0.002f, QColor("#0066ba")); if (ctx_) { diff --git a/ice40/arch.cc b/ice40/arch.cc index 1e6b4569..26c3b003 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -369,6 +369,52 @@ std::string Arch::getBelPackagePin(BelId bel) const } return ""; } + +// ----------------------------------------------------------------------- + +GroupId Arch::getGroupByName(IdString name) const +{ + for (auto g : getGroups()) + if (getGroupName(g) == name) + return g; + return GroupId(); +} + +IdString Arch::getGroupName(GroupId group) const +{ + return IdString(); +} + +std::vector Arch::getGroups() const +{ + std::vector ret; + return ret; +} + +std::vector Arch::getGroupBels(GroupId group) const +{ + std::vector ret; + return ret; +} + +std::vector Arch::getGroupWires(GroupId group) const +{ + std::vector ret; + return ret; +} + +std::vector Arch::getGroupPips(GroupId group) const +{ + std::vector ret; + return ret; +} + +std::vector Arch::getGroupGroups(GroupId group) const +{ + std::vector ret; + return ret; +} + // ----------------------------------------------------------------------- void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const @@ -417,15 +463,15 @@ bool Arch::route() DecalXY Arch::getFrameDecal() const { DecalXY decalxy; - decalxy.decal.type = 'f'; + decalxy.decal.type = DecalId::TYPE_FRAME; return decalxy; } DecalXY Arch::getBelDecal(BelId bel) const { DecalXY decalxy; - decalxy.decal.type = 'b'; - decalxy.decal.z = bel.index; + decalxy.decal.type = DecalId::TYPE_BEL; + decalxy.decal.index = bel.index; return decalxy; } @@ -441,11 +487,17 @@ DecalXY Arch::getPipDecal(PipId pip) const return decalxy; }; +DecalXY Arch::getGroupDecal(GroupId group) const +{ + DecalXY decalxy; + return decalxy; +}; + std::vector Arch::getDecalGraphics(DecalId decal) const { std::vector ret; - if (decal.type == 'f') + if (decal.type == DecalId::TYPE_FRAME) { for (int x = 0; x <= chip_info->width; x++) for (int y = 0; y <= chip_info->height; y++) { @@ -458,10 +510,10 @@ std::vector Arch::getDecalGraphics(DecalId decal) const } } - if (decal.type == 'b') + if (decal.type == DecalId::TYPE_BEL) { BelId bel; - bel.index = decal.z; + bel.index = decal.index; auto bel_type = getBelType(bel); diff --git a/ice40/arch.h b/ice40/arch.h index 659139a6..96d0d209 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -634,6 +634,16 @@ struct Arch : BaseCtx // ------------------------------------------------- + GroupId getGroupByName(IdString name) const; + IdString getGroupName(GroupId group) const; + std::vector getGroups() const; + std::vector getGroupBels(GroupId group) const; + std::vector getGroupWires(GroupId group) const; + std::vector getGroupPips(GroupId group) const; + std::vector getGroupGroups(GroupId group) const; + + // ------------------------------------------------- + void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; delay_t estimateDelay(WireId src, WireId dst) const; delay_t getDelayEpsilon() const { return 20; } @@ -654,6 +664,7 @@ struct Arch : BaseCtx DecalXY getBelDecal(BelId bel) const; DecalXY getWireDecal(WireId wire) const; DecalXY getPipDecal(PipId pip) const; + DecalXY getGroupDecal(GroupId group) const; // ------------------------------------------------- diff --git a/ice40/archdefs.h b/ice40/archdefs.h index 061e9b44..62c248c7 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -109,11 +109,42 @@ struct PipId bool operator!=(const PipId &other) const { return index != other.index; } }; +struct GroupId +{ + enum : int8_t { + TYPE_NONE, + TYPE_FRAME, + TYPE_MAIN_SW, + TYPE_LOCAL_SW, + TYPE_LC0_SW, + TYPE_LC1_SW, + TYPE_LC2_SW, + TYPE_LC3_SW, + TYPE_LC4_SW, + TYPE_LC5_SW, + TYPE_LC6_SW, + TYPE_LC7_SW + } type = TYPE_NONE; + int8_t x = 0, y = 0; + + bool operator==(const GroupId &other) const { return (type == other.type) && (x == other.x) && (y == other.y); } + bool operator!=(const GroupId &other) const { return (type != other.type) || (x != other.x) || (y == other.y); } +}; + struct DecalId { - char type = 0; // Bel/Wire/Pip/Frame (b/w/p/f) - uint8_t x = 0, y = 0; - uint32_t z = 0; + enum : int8_t { + TYPE_NONE, + TYPE_FRAME, + TYPE_BEL, + TYPE_WIRE, + TYPE_PIP, + TYPE_GROUP + } type = TYPE_NONE; + int32_t index = -1; + + bool operator==(const DecalId &other) const { return (type == other.type) && (index == other.index); } + bool operator!=(const DecalId &other) const { return (type != other.type) || (index != other.index); } }; NEXTPNR_NAMESPACE_END @@ -145,14 +176,23 @@ template <> struct hash : hash { }; +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept { + std::size_t seed = 0; + boost::hash_combine(seed, hash()(group.type)); + boost::hash_combine(seed, hash()(group.x)); + boost::hash_combine(seed, hash()(group.y)); + return seed; + } +}; + template <> struct hash { std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept { std::size_t seed = 0; boost::hash_combine(seed, hash()(decal.type)); - boost::hash_combine(seed, hash()(decal.x)); - boost::hash_combine(seed, hash()(decal.y)); - boost::hash_combine(seed, hash()(decal.z)); + boost::hash_combine(seed, hash()(decal.index)); return seed; } }; -- cgit v1.2.3 From 8fde7935e79d7be317d47fc574fbee506d041a63 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 12 Jul 2018 17:22:44 +0200 Subject: Update README Signed-off-by: Clifford Wolf --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index c8e4a840..da38500d 100644 --- a/README.md +++ b/README.md @@ -35,19 +35,19 @@ Building - Use `cmake . -DARCH=all` to build all supported targets - For example `cmake . -DARCH=ice40` would build just ICE40 support - Use CMake to generate the Makefiles (only needs to be done when `CMakeLists.txt` changes) - - For a debug build, run `cmake -DCMAKE_BUILD_TYPE=Debug .` - - For a debug build with HX1K support only, run ` cmake -DCMAKE_BUILD_TYPE=Debug -DICE40_HX1K_ONLY=1 .` - - For a release build, run `cmake .` + - For an iCE40 debug build, run `cmake -DARCH=ice40 -DCMAKE_BUILD_TYPE=Debug .` + - For an iCE40 debug build with HX1K support only, run `cmake -DARCH=ice40 -DCMAKE_BUILD_TYPE=Debug -DICE40_HX1K_ONLY=1 .` + - For an iCE40 and ECP5 release build, run `cmake -DARCH="ice40;ecp5" .` - Add `-DCMAKE_INSTALL_PREFIX=/your/install/prefix` to use a different install prefix to the default `/usr/local` - - For MSVC build with vcpkg use `cmake . -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake` using your vcpkg location + - For MSVC build with vcpkg use `-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake` using your vcpkg location - For MSVC x64 build adding `-G"Visual Studio 14 2015 Win64"` is needed. - For ECP5 support, you must also specify the path to Project Trellis using `-DTRELLIS_ROOT=/path/trellis` - Use Make to run the build itself - For all binary targets, just run `make` - For just the iCE40 CLI&GUI binary, run `make nextpnr-ice40` - - To build binary without Python support, run `cmake -DBUILD_PYTHON=OFF .` - - To build binary without GUI, run `cmake -DBUILD_GUI=OFF .` - - For minimal binary without Python and GUI, run `cmake -DBUILD_PYTHON=OFF -DBUILD_GUI=OFF .` + - To build binary without Python support, use `-DBUILD_PYTHON=OFF` + - To build binary without GUI, use `-DBUILD_GUI=OFF` + - For minimal binary without Python and GUI, use `-DBUILD_PYTHON=OFF -DBUILD_GUI=OFF` - For just the iCE40 Python module, run `make nextpnrpy_ice40` - Using too many parallel jobs may lead to out-of-memory issues due to the significant memory needed to build the chipdbs - To install nextpnr, run `make install` @@ -55,12 +55,12 @@ Building Testing ------- - - To build test binaries as well, run `cmake -DBUILD_TESTS=OFF .` and after run `make tests` to run them, or you can run separate binaries. - - To use code sanitizers use: - - `cmake . -DSANITIZE_ADDRESS=ON` - - `cmake . -DSANITIZE_MEMORY=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++` - - `cmake . -DSANITIZE_THREAD=ON` - - `cmake . -DSANITIZE_UNDEFINED=ON` + - To build test binaries as well, use `-DBUILD_TESTS=OFF` and after run `make tests` to run them, or you can run separate binaries. + - To use code sanitizers use the `cmake` options: + - `-DSANITIZE_ADDRESS=ON` + - `-DSANITIZE_MEMORY=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++` + - `-DSANITIZE_THREAD=ON` + - `-DSANITIZE_UNDEFINED=ON` - Running valgrind example `valgrind --leak-check=yes --tool=memcheck ./nextpnr-ice40 --json ice40/blinky.json` Running -- cgit v1.2.3 From 8a226626bec3acf09ec8d29aca1000e7efd645d0 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 12 Jul 2018 17:38:58 +0200 Subject: changed order of scale and translate, makes it zoom at center --- gui/fpgaviewwidget.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 7a188863..7d9d3727 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -342,8 +342,8 @@ void FPGAViewWidget::paintGL() QMatrix4x4 matrix; matrix.ortho(QRectF(-aspect / 2.0, -0.5, aspect, 1.0f)); - matrix.translate(moveX_, moveY_, -0.5); matrix.scale(zoom_ * 0.01f, -zoom_ * 0.01f, 0); + matrix.translate(moveX_, -moveY_, 0); // Draw grid. auto grid = LineShaderData(0.001f, QColor("#DDD")); @@ -434,7 +434,7 @@ void FPGAViewWidget::wheelEvent(QWheelEvent *event) QPoint degree = event->angleDelta() / 8; if (!degree.isNull()) { - float steps = degree.y() / 15.0; + float steps = degree.y() / 3.0; setZoom(zoom_ + steps); } } -- cgit v1.2.3 From a8a3ba264704182547639053f71b0be0b31d05af Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 12 Jul 2018 18:01:40 +0200 Subject: ecp5: Unbreaking groups Signed-off-by: David Shah --- ecp5/arch.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 286151d8..ace0703e 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -317,7 +317,7 @@ DecalXY Arch::getWireDecal(WireId wire) const { return {}; } DecalXY Arch::getPipDecal(PipId pip) const { return {}; }; -DecalXY Arch::getGroupDecal(PipId pip) const { return {}; }; +DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; }; // ----------------------------------------------------------------------- -- cgit v1.2.3 From 7b9b2bef3c622bd54225c1c44ee63a211e0e1d3e Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 12 Jul 2018 18:02:57 +0200 Subject: make colors configurable, changed to gray --- gui/fpgaviewwidget.cc | 21 ++++++++++++++------- gui/fpgaviewwidget.h | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 7d9d3727..19f7cf0d 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -243,6 +243,13 @@ void LineShader::draw(const LineShaderData &line, const QMatrix4x4 &projection) FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), moveX_(0), moveY_(0), zoom_(10.0f), lineShader_(this), ctx_(nullptr) { + backgroundColor = QColor("#ffffff"); + gridColor = QColor("#ddd"); + belColor = QColor("#303030"); + wireColor = QColor("#303030"); + pipColor = QColor("#303030"); + groupColor = QColor("#303030"); + frameColor = QColor("#0066ba"); auto fmt = format(); fmt.setMajorVersion(3); fmt.setMinorVersion(1); @@ -309,7 +316,7 @@ void FPGAViewWidget::initializeGL() log_error("Could not compile shader.\n"); } initializeOpenGLFunctions(); - glClearColor(1.0, 1.0, 1.0, 0.0); + glClearColor(backgroundColor.red()/255, backgroundColor.green()/255, backgroundColor.blue()/255, 0.0); } void FPGAViewWidget::drawElement(LineShaderData &out, const GraphicElement &el) @@ -346,7 +353,7 @@ void FPGAViewWidget::paintGL() matrix.translate(moveX_, -moveY_, 0); // Draw grid. - auto grid = LineShaderData(0.001f, QColor("#DDD")); + auto grid = LineShaderData(0.001f, gridColor); for (float i = -100.0f; i < 100.0f; i += 1.0f) { PolyLine(-100.0f, i, 100.0f, i).build(grid); PolyLine(i, -100.0f, i, 100.0f).build(grid); @@ -354,7 +361,7 @@ void FPGAViewWidget::paintGL() lineShader_.draw(grid, matrix); // Draw Bels. - auto bels = LineShaderData(0.0005f, QColor("#b000ba")); + auto bels = LineShaderData(0.0005f, belColor); if (ctx_) { for (auto bel : ctx_->getBels()) { for (auto &el : ctx_->getBelGraphics(bel)) @@ -364,7 +371,7 @@ void FPGAViewWidget::paintGL() } // Draw Wires. - auto wires = LineShaderData(0.0005f, QColor("#b000ba")); + auto wires = LineShaderData(0.0005f, wireColor); if (ctx_) { for (auto wire : ctx_->getWires()) { for (auto &el : ctx_->getWireGraphics(wire)) @@ -374,7 +381,7 @@ void FPGAViewWidget::paintGL() } // Draw Pips. - auto pips = LineShaderData(0.0005f, QColor("#b000ba")); + auto pips = LineShaderData(0.0005f, pipColor); if (ctx_) { for (auto wire : ctx_->getPips()) { for (auto &el : ctx_->getPipGraphics(wire)) @@ -384,7 +391,7 @@ void FPGAViewWidget::paintGL() } // Draw Groups. - auto groups = LineShaderData(0.0005f, QColor("#b000ba")); + auto groups = LineShaderData(0.0005f, groupColor); if (ctx_) { for (auto group : ctx_->getGroups()) { for (auto &el : ctx_->getGroupGraphics(group)) @@ -394,7 +401,7 @@ void FPGAViewWidget::paintGL() } // Draw Frame Graphics. - auto frames = LineShaderData(0.002f, QColor("#0066ba")); + auto frames = LineShaderData(0.002f, frameColor); if (ctx_) { for (auto &el : ctx_->getFrameGraphics()) { drawElement(frames, el); diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index c281fd77..8114a686 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -216,6 +216,13 @@ class LineShader class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT + Q_PROPERTY(QColor backgroundColor MEMBER backgroundColor DESIGNABLE true) + Q_PROPERTY(QColor belColor MEMBER belColor DESIGNABLE true) + Q_PROPERTY(QColor gridColor MEMBER gridColor DESIGNABLE true) + Q_PROPERTY(QColor wireColor MEMBER wireColor DESIGNABLE true) + Q_PROPERTY(QColor pipColor MEMBER pipColor DESIGNABLE true) + Q_PROPERTY(QColor groupColor MEMBER groupColor DESIGNABLE true) + Q_PROPERTY(QColor frameColor MEMBER frameColor DESIGNABLE true) public: FPGAViewWidget(QWidget *parent = 0); @@ -253,6 +260,13 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions float startDragX_; float startDragY_; Context *ctx_; + QColor backgroundColor; + QColor gridColor; + QColor belColor; + QColor wireColor; + QColor pipColor; + QColor groupColor; + QColor frameColor; }; NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From d16d34736f6565e67b5ad3563ed69552abefd305 Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 12 Jul 2018 19:59:18 +0200 Subject: ecp5/cmake: Improve error message when trellis/pytrellis not found Signed-off-by: David Shah --- ecp5/family.cmake | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ecp5/family.cmake b/ecp5/family.cmake index f58cdbb2..f4d0bf87 100644 --- a/ecp5/family.cmake +++ b/ecp5/family.cmake @@ -1,6 +1,17 @@ set(devices 45k) +if (NOT DEFINED TRELLIS_ROOT) + message(FATAL_ERROR "you must define TRELLIS_ROOT using -DTRELLIS_ROOT=/path/to/prjtrellis for ECP5 support") +endif() + + +file( GLOB found_pytrellis ${TRELLIS_ROOT}/libtrellis/pytrellis.*) + +if ("${found_pytrellis}" STREQUAL "") + message(FATAL_ERROR "failed to find pytrellis library in ${TRELLIS_ROOT}/libtrellis/") +endif() + set(DB_PY ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/trellis_import.py) file(MAKE_DIRECTORY ecp5/chipdbs/) -- cgit v1.2.3 From 13e7cd868111300577c36a3fd45ba698ce926160 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 12 Jul 2018 21:04:47 +0200 Subject: Add GraphicElement style enum Signed-off-by: Clifford Wolf --- common/nextpnr.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index a162b85c..00a939a9 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -136,7 +136,7 @@ NEXTPNR_NAMESPACE_BEGIN struct GraphicElement { - enum + enum type_t { G_NONE, G_LINE, @@ -145,6 +145,14 @@ struct GraphicElement G_LABEL } type = G_NONE; + enum style_t + { + G_FRAME, + G_HIDDEN, + G_INACTIVE, + G_ACTIVE, + } style = G_FRAME; + float x1 = 0, y1 = 0, x2 = 0, y2 = 0, z = 0; std::string text; }; -- cgit v1.2.3 From 4f87ea0eb6ae8a4f8fbf9890c8101cd530d4c5da Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 12 Jul 2018 21:05:09 +0200 Subject: Improve iCE40 wire database and gfx Signed-off-by: Clifford Wolf --- ice40/arch.cc | 24 ++++++++++++++++++++---- ice40/arch.h | 8 ++++++++ ice40/chipdb.py | 35 ++++++++++++++++++++++++++++++++++- ice40/family.cmake | 6 ++++-- ice40/gfx.cc | 47 +++++------------------------------------------ ice40/gfx.h | 2 +- 6 files changed, 72 insertions(+), 50 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 26c3b003..8650aeff 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -478,6 +478,8 @@ DecalXY Arch::getBelDecal(BelId bel) const DecalXY Arch::getWireDecal(WireId wire) const { DecalXY decalxy; + decalxy.decal.type = DecalId::TYPE_WIRE; + decalxy.decal.index = wire.index; return decalxy; } @@ -510,6 +512,21 @@ std::vector Arch::getDecalGraphics(DecalId decal) const } } + if (decal.type == DecalId::TYPE_WIRE) + { + WireId wire; + wire.index = decal.index; + + int n = chip_info->wire_data[wire.index].num_segments; + const WireSegmentPOD *p = chip_info->wire_data[wire.index].segments.get(); + + GraphicElement::style_t style = wire_to_net.at(wire.index) != IdString() ? + GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; + + for (int i = 0; i < n; i++) + gfxTileWire(ret, p[i].x, p[i].y, GfxTileWireId(p[i].index), style); + } + if (decal.type == DecalId::TYPE_BEL) { BelId bel; @@ -520,6 +537,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const if (bel_type == TYPE_ICESTORM_LC) { GraphicElement el; el.type = GraphicElement::G_BOX; + el.style = bel_to_cell.at(bel.index) != IdString() ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; @@ -534,6 +552,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const // Main switchbox GraphicElement main_sw; main_sw.type = GraphicElement::G_BOX; + main_sw.style = GraphicElement::G_FRAME; main_sw.x1 = tx + main_swbox_x1; main_sw.x2 = tx + main_swbox_x2; main_sw.y1 = ty + main_swbox_y1; @@ -543,16 +562,13 @@ std::vector Arch::getDecalGraphics(DecalId decal) const // Local tracks to LUT input switchbox GraphicElement local_sw; local_sw.type = GraphicElement::G_BOX; + local_sw.style = GraphicElement::G_FRAME; local_sw.x1 = tx + local_swbox_x1; local_sw.x2 = tx + local_swbox_x2; local_sw.y1 = ty + local_swbox_y1; local_sw.y2 = ty + local_swbox_y2; local_sw.z = 0; ret.push_back(local_sw); - - // All the wires - for (int i = TILE_WIRE_GLB2LOCAL_0; i <= TILE_WIRE_SP12_H_L_23; i++) - gfxTileWire(ret, tx, ty, GfxTileWireId(i)); } } diff --git a/ice40/arch.h b/ice40/arch.h index 96d0d209..04de5178 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -70,6 +70,11 @@ NPNR_PACKED_STRUCT(struct PipInfoPOD { int32_t switch_index; }); +NPNR_PACKED_STRUCT(struct WireSegmentPOD { + int8_t x, y; + int16_t index; +}); + NPNR_PACKED_STRUCT(struct WireInfoPOD { RelPtr name; int32_t num_uphill, num_downhill; @@ -79,6 +84,9 @@ NPNR_PACKED_STRUCT(struct WireInfoPOD { BelPortPOD bel_uphill; RelPtr bels_downhill; + int32_t num_segments; + RelPtr segments; + int8_t x, y; WireType type; int8_t padding_0; diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 2a918ed9..00194deb 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -11,6 +11,7 @@ group.add_argument("-b", "--binary", action="store_true") group.add_argument("-c", "--c_file", action="store_true") parser.add_argument("filename", type=str, help="chipdb input filename") parser.add_argument("-p", "--portspins", type=str, help="path to portpins.inc") +parser.add_argument("-g", "--gfxh", type=str, help="path to gfx.h") args = parser.parse_args() endianness = "le" @@ -54,6 +55,9 @@ beltypes = dict() tiletypes = dict() wiretypes = dict() +gfx_wire_ids = dict() +wire_segments = dict() + with open(args.portspins) as f: for line in f: line = line.replace("(", " ") @@ -66,6 +70,18 @@ with open(args.portspins) as f: idx = len(portpins) + 1 portpins[line[1]] = idx +with open(args.gfxh) as f: + state = 0 + for line in f: + if state == 0 and line.startswith("enum GfxTileWireId "): + state = 1 + elif state == 1 and line.startswith("};"): + state = 0 + elif state == 1: + idx = len(gfx_wire_ids) + name = line.strip().rstrip(",") + gfx_wire_ids[name] = idx + beltypes["ICESTORM_LC"] = 1 beltypes["ICESTORM_RAM"] = 2 beltypes["SB_IO"] = 3 @@ -371,6 +387,10 @@ with open(args.filename, "r") as f: if mode[1] not in wire_xy: wire_xy[mode[1]] = list() wire_xy[mode[1]].append((int(line[0]), int(line[1]))) + if mode[1] not in wire_segments: + wire_segments[mode[1]] = set() + if ("TILE_WIRE_" + wname[2].upper()) in gfx_wire_ids: + wire_segments[mode[1]].add((wname[0], wname[1], gfx_wire_ids["TILE_WIRE_" + wname[2].upper()])) continue if mode[0] in ("buffer", "routing"): @@ -1040,7 +1060,7 @@ for t in range(num_tile_types): tileinfo.append(ti) bba.l("wire_data_%s" % dev_name, "WireInfoPOD") -for info in wireinfo: +for wire, info in enumerate(wireinfo): bba.s(info["name"], "name") bba.u32(info["num_uphill"], "num_uphill") bba.u32(info["num_downhill"], "num_downhill") @@ -1050,11 +1070,24 @@ for info in wireinfo: bba.u32(info["uphill_bel"], "bel_uphill.bel_index") bba.u32(info["uphill_pin"], "bel_uphill.port") bba.r(info["list_bels_downhill"], "bels_downhill") + bba.u32(len(wire_segments[wire]), "num_segments") + if len(wire_segments[wire]): + bba.r("wire_segments_%d" % wire, "segments") + else: + bba.u32(0, "segments") bba.u8(info["x"], "x") bba.u8(info["y"], "y") bba.u8(wiretypes[wire_type(info["name"])], "type") bba.u8(0, "padding") +for wire in range(num_wires): + if len(wire_segments[wire]): + bba.l("wire_segments_%d" % wire, "WireSegmentPOD") + for seg in sorted(wire_segments[wire]): + bba.u8(seg[0], "x") + bba.u8(seg[1], "y") + bba.u16(seg[2], "index") + bba.l("pip_data_%s" % dev_name, "PipInfoPOD") for info in pipinfo: bba.u32(info["src"], "src") diff --git a/ice40/family.cmake b/ice40/family.cmake index e6cefecb..9af06f82 100644 --- a/ice40/family.cmake +++ b/ice40/family.cmake @@ -21,8 +21,9 @@ if (MSVC) set(DEV_TXT_DB ${ICEBOX_ROOT}/chipdb-${dev}.txt) set(DEV_CC_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.bin) set(DEV_PORTS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/portpins.inc) + set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h) add_custom_command(OUTPUT ${DEV_CC_DB} - COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -b -p ${DEV_PORTS_INC} ${DEV_TXT_DB} > ${DEV_CC_DB} + COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -b -p ${DEV_PORTS_INC} -g ${DEV_GFXH} ${DEV_TXT_DB} > ${DEV_CC_DB} DEPENDS ${DEV_TXT_DB} ${DB_PY} ) target_sources(ice40_chipdb PRIVATE ${DEV_CC_DB}) @@ -37,8 +38,9 @@ else() set(DEV_TXT_DB ${ICEBOX_ROOT}/chipdb-${dev}.txt) set(DEV_CC_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.cc) set(DEV_PORTS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/portpins.inc) + set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h) add_custom_command(OUTPUT ${DEV_CC_DB} - COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -c -p ${DEV_PORTS_INC} ${DEV_TXT_DB} > ${DEV_CC_DB}.new + COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -c -p ${DEV_PORTS_INC} -g ${DEV_GFXH} ${DEV_TXT_DB} > ${DEV_CC_DB}.new COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB} DEPENDS ${DEV_TXT_DB} ${DB_PY} ) diff --git a/ice40/gfx.cc b/ice40/gfx.cc index 64bb66ec..d6935b7d 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -21,15 +21,16 @@ NEXTPNR_NAMESPACE_BEGIN -void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) +void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, GraphicElement::style_t style) { + GraphicElement el; + el.type = GraphicElement::G_LINE; + el.style = style; + // Horizontal Span-4 Wires if (id >= TILE_WIRE_SP4_H_L_36 && id <= TILE_WIRE_SP4_H_L_47) { int idx = (id - TILE_WIRE_SP4_H_L_36) + 48; - GraphicElement el; - el.type = GraphicElement::G_LINE; - float y1 = y + 1.0 - (0.03 + 0.0025 * (60 - idx)); el.x1 = x + 0.0; @@ -47,8 +48,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_SP4_H_R_0 && id <= TILE_WIRE_SP4_H_R_47) { int idx = id - TILE_WIRE_SP4_H_R_0; - GraphicElement el; - el.type = GraphicElement::G_LINE; float y1 = y + 1.0 - (0.03 + 0.0025 * (60 - idx)); float y2 = y + 1.0 - (0.03 + 0.0025 * (60 - (idx ^ 1))); @@ -91,8 +90,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_SP4_V_T_36 && id <= TILE_WIRE_SP4_V_T_47) { int idx = (id - TILE_WIRE_SP4_V_T_36) + 48; - GraphicElement el; - el.type = GraphicElement::G_LINE; float x1 = x + 0.03 + 0.0025 * (60 - idx); @@ -111,8 +108,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_SP4_V_B_0 && id <= TILE_WIRE_SP4_V_B_47) { int idx = id - TILE_WIRE_SP4_V_B_0; - GraphicElement el; - el.type = GraphicElement::G_LINE; float x1 = x + 0.03 + 0.0025 * (60 - (idx ^ 1)); float x2 = x + 0.03 + 0.0025 * (60 - idx); @@ -161,8 +156,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_SP12_H_L_22 && id <= TILE_WIRE_SP12_H_L_23) { int idx = (id - TILE_WIRE_SP12_H_L_22) + 24; - GraphicElement el; - el.type = GraphicElement::G_LINE; float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - idx)); @@ -181,8 +174,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_SP12_H_R_0 && id <= TILE_WIRE_SP12_H_R_23) { int idx = id - TILE_WIRE_SP12_H_R_0; - GraphicElement el; - el.type = GraphicElement::G_LINE; float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - (idx ^ 1))); float y2 = y + 1.0 - (0.03 + 0.0025 * (90 - idx)); @@ -225,8 +216,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_SP4_R_V_B_0 && id <= TILE_WIRE_SP4_R_V_B_47) { int idx = id - TILE_WIRE_SP4_R_V_B_0; - GraphicElement el; - el.type = GraphicElement::G_LINE; float y1 = y + 1.0 - (0.03 + 0.0025 * (145 - idx)); @@ -241,8 +230,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_SP12_V_T_22 && id <= TILE_WIRE_SP12_V_T_23) { int idx = (id - TILE_WIRE_SP12_V_T_22) + 24; - GraphicElement el; - el.type = GraphicElement::G_LINE; float x1 = x + 0.03 + 0.0025 * (90 - idx); @@ -261,8 +248,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_SP12_V_B_0 && id <= TILE_WIRE_SP12_V_B_23) { int idx = id - TILE_WIRE_SP12_V_B_0; - GraphicElement el; - el.type = GraphicElement::G_LINE; float x1 = x + 0.03 + 0.0025 * (90 - idx); float x2 = x + 0.03 + 0.0025 * (90 - (idx ^ 1)); @@ -305,8 +290,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_GLB2LOCAL_0 && id <= TILE_WIRE_GLB2LOCAL_3) { int idx = id - TILE_WIRE_GLB2LOCAL_0; - GraphicElement el; - el.type = GraphicElement::G_LINE; el.x1 = x + main_swbox_x1 + 0.005 * (idx + 5); el.x2 = el.x1; el.y1 = y + main_swbox_y1; @@ -318,8 +301,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_GLB_NETWK_0 && id <= TILE_WIRE_GLB_NETWK_7) { int idx = id - TILE_WIRE_GLB_NETWK_0; - GraphicElement el; - el.type = GraphicElement::G_LINE; el.x1 = x + main_swbox_x1 - 0.05; el.x2 = x + main_swbox_x1; el.y1 = y + main_swbox_y1 + 0.005 * (13 - idx); @@ -331,8 +312,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_NEIGH_OP_BNL_0 && id <= TILE_WIRE_NEIGH_OP_TOP_7) { int idx = id - TILE_WIRE_NEIGH_OP_BNL_0; - GraphicElement el; - el.type = GraphicElement::G_LINE; el.y1 = y + main_swbox_y2 - (0.0025 * (idx + 10) + 0.01 * (idx / 8)); el.y2 = el.y1; el.x1 = x + main_swbox_x1 - 0.05; @@ -344,8 +323,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_LOCAL_G0_0 && id <= TILE_WIRE_LOCAL_G3_7) { int idx = id - TILE_WIRE_LOCAL_G0_0; - GraphicElement el; - el.type = GraphicElement::G_LINE; el.x1 = x + main_swbox_x2; el.x2 = x + local_swbox_x1; float yoff = y + (local_swbox_y1 + local_swbox_y2) / 2 - 0.005 * 16 - 0.075; @@ -360,8 +337,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) int idx = id - TILE_WIRE_LUTFF_0_IN_0; int z = idx / 4; int input = idx % 4; - GraphicElement el; - el.type = GraphicElement::G_LINE; el.x1 = x + local_swbox_x2; el.x2 = x + logic_cell_x1; el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * input) + z * logic_cell_pitch; @@ -376,8 +351,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) float y1 = y + 1.0 - (0.03 + 0.0025 * (152 + idx)); - GraphicElement el; - el.type = GraphicElement::G_LINE; el.y1 = y1; el.y2 = y1; el.x1 = x + main_swbox_x2; @@ -398,8 +371,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_LUTFF_GLOBAL_CEN && id <= TILE_WIRE_LUTFF_GLOBAL_S_R) { int idx = id - TILE_WIRE_LUTFF_GLOBAL_CEN; - GraphicElement el; - el.type = GraphicElement::G_LINE; el.x1 = x + main_swbox_x2 - 0.005 * (idx + 5); el.x2 = el.x1; @@ -426,8 +397,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_LUTFF_0_LOUT && id <= TILE_WIRE_LUTFF_6_LOUT) { int idx = id - TILE_WIRE_LUTFF_0_LOUT; - GraphicElement el; - el.type = GraphicElement::G_LINE; el.x1 = x + logic_cell_x1 + 0.005 * 5; el.x2 = el.x1; el.y1 = y + logic_cell_y2 + idx * logic_cell_pitch; @@ -439,8 +408,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) if (id >= TILE_WIRE_LUTFF_0_COUT && id <= TILE_WIRE_LUTFF_7_COUT) { int idx = id - TILE_WIRE_LUTFF_0_COUT; - GraphicElement el; - el.type = GraphicElement::G_LINE; el.x1 = x + logic_cell_x1 + 0.005 * 3; el.x2 = el.x1; el.y1 = y + logic_cell_y2 + idx * logic_cell_pitch; @@ -449,8 +416,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) } if (id == TILE_WIRE_CARRY_IN) { - GraphicElement el; - el.type = GraphicElement::G_LINE; el.x1 = x + logic_cell_x1 + 0.005 * 3; el.x2 = el.x1; el.y1 = y; @@ -459,8 +424,6 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id) } if (id == TILE_WIRE_CARRY_IN_MUX) { - GraphicElement el; - el.type = GraphicElement::G_LINE; el.x1 = x + logic_cell_x1 + 0.005 * 3; el.x2 = el.x1; el.y1 = y + 0.02; diff --git a/ice40/gfx.h b/ice40/gfx.h index b0009b59..aa07c2fa 100644 --- a/ice40/gfx.h +++ b/ice40/gfx.h @@ -466,7 +466,7 @@ enum GfxTileWireId { TILE_WIRE_SP12_H_L_23 }; -void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id); +void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, GraphicElement::style_t style); NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From 284b4750ee6a3a5a4e33590cbbccaaccfd2c5899 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Thu, 12 Jul 2018 20:22:53 +0100 Subject: Fix zoom in fpgawidget --- gui/fpgaviewwidget.cc | 109 ++++++++++++++++++++++++-------------------------- gui/fpgaviewwidget.h | 15 ++++--- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 7d9d3727..4bb101fa 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -241,7 +241,7 @@ void LineShader::draw(const LineShaderData &line, const QMatrix4x4 &projection) } FPGAViewWidget::FPGAViewWidget(QWidget *parent) - : QOpenGLWidget(parent), moveX_(0), moveY_(0), zoom_(10.0f), lineShader_(this), ctx_(nullptr) + : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr) { auto fmt = format(); fmt.setMajorVersion(3); @@ -271,38 +271,6 @@ QSize FPGAViewWidget::minimumSizeHint() const { return QSize(640, 480); } QSize FPGAViewWidget::sizeHint() const { return QSize(640, 480); } -void FPGAViewWidget::setXTranslation(float t_x) -{ - if (t_x == moveX_) - return; - - moveX_ = t_x; - update(); -} - -void FPGAViewWidget::setYTranslation(float t_y) -{ - if (t_y == moveY_) - return; - - moveY_ = t_y; - update(); -} - -void FPGAViewWidget::setZoom(float t_z) -{ - if (t_z == zoom_) - return; - zoom_ = t_z; - - if (zoom_ < 1.0f) - zoom_ = 1.0f; - if (zoom_ > 500.f) - zoom_ = 500.0f; - - update(); -} - void FPGAViewWidget::initializeGL() { if (!lineShader_.compile()) { @@ -331,6 +299,16 @@ void FPGAViewWidget::drawElement(LineShaderData &out, const GraphicElement &el) } } +QMatrix4x4 FPGAViewWidget::getProjection(void) +{ + QMatrix4x4 matrix; + + const float aspect = float(width()) / float(height()); + matrix.perspective(3.14/2, aspect, zoomNear_, zoomFar_); + matrix.translate(0.0f, 0.0f, -zoom_); + return matrix; +} + void FPGAViewWidget::paintGL() { auto gl = QOpenGLContext::currentContext()->functions(); @@ -338,15 +316,16 @@ void FPGAViewWidget::paintGL() gl->glViewport(0, 0, width() * retinaScale, height() * retinaScale); gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - const float aspect = float(width()) / float(height()); + QMatrix4x4 matrix = getProjection(); - QMatrix4x4 matrix; - matrix.ortho(QRectF(-aspect / 2.0, -0.5, aspect, 1.0f)); - matrix.scale(zoom_ * 0.01f, -zoom_ * 0.01f, 0); - matrix.translate(moveX_, -moveY_, 0); + matrix *= viewMove_; + + // Calculate world thickness to achieve a screen 1px/1.1px line. + float thick1Px = mouseToWorldCoordinates(1, 0).x(); + float thick11Px = mouseToWorldCoordinates(1.1, 0).x(); // Draw grid. - auto grid = LineShaderData(0.001f, QColor("#DDD")); + auto grid = LineShaderData(thick1Px, QColor("#DDD")); for (float i = -100.0f; i < 100.0f; i += 1.0f) { PolyLine(-100.0f, i, 100.0f, i).build(grid); PolyLine(i, -100.0f, i, 100.0f).build(grid); @@ -354,7 +333,7 @@ void FPGAViewWidget::paintGL() lineShader_.draw(grid, matrix); // Draw Bels. - auto bels = LineShaderData(0.0005f, QColor("#b000ba")); + auto bels = LineShaderData(thick11Px, QColor("#b000ba")); if (ctx_) { for (auto bel : ctx_->getBels()) { for (auto &el : ctx_->getBelGraphics(bel)) @@ -364,7 +343,7 @@ void FPGAViewWidget::paintGL() } // Draw Wires. - auto wires = LineShaderData(0.0005f, QColor("#b000ba")); + auto wires = LineShaderData(thick11Px, QColor("#b000ba")); if (ctx_) { for (auto wire : ctx_->getWires()) { for (auto &el : ctx_->getWireGraphics(wire)) @@ -374,7 +353,7 @@ void FPGAViewWidget::paintGL() } // Draw Pips. - auto pips = LineShaderData(0.0005f, QColor("#b000ba")); + auto pips = LineShaderData(thick11Px, QColor("#b000ba")); if (ctx_) { for (auto wire : ctx_->getPips()) { for (auto &el : ctx_->getPipGraphics(wire)) @@ -384,7 +363,7 @@ void FPGAViewWidget::paintGL() } // Draw Groups. - auto groups = LineShaderData(0.0005f, QColor("#b000ba")); + auto groups = LineShaderData(thick11Px, QColor("#b000ba")); if (ctx_) { for (auto group : ctx_->getGroups()) { for (auto &el : ctx_->getGroupGraphics(group)) @@ -394,7 +373,7 @@ void FPGAViewWidget::paintGL() } // Draw Frame Graphics. - auto frames = LineShaderData(0.002f, QColor("#0066ba")); + auto frames = LineShaderData(thick11Px, QColor("#0066ba")); if (ctx_) { for (auto &el : ctx_->getFrameGraphics()) { drawElement(frames, el); @@ -407,26 +386,31 @@ void FPGAViewWidget::resizeGL(int width, int height) {} void FPGAViewWidget::mousePressEvent(QMouseEvent *event) { - startDragX_ = moveX_; - startDragY_ = moveY_; lastPos_ = event->pos(); } +// Invert the projection matrix to calculate screen/mouse to world/grid +// coordinates. +QVector4D FPGAViewWidget::mouseToWorldCoordinates(int x, int y) +{ + QMatrix4x4 p = getProjection(); + QVector2D unit = p.map(QVector4D(1, 1, 0, 1)).toVector2DAffine(); + + float sx = (((float)x) / (width()/2)); + float sy = (((float)y) / (height()/2)); + return QVector4D(sx / unit.x(), sy / unit.y(), 0, 1); +} + void FPGAViewWidget::mouseMoveEvent(QMouseEvent *event) { const int dx = event->x() - lastPos_.x(); const int dy = event->y() - lastPos_.y(); + lastPos_ = event->pos(); - const qreal retinaScale = devicePixelRatio(); - float aspect = float(width()) / float(height()); - const float dx_scale = dx * (1 / (float)width() * retinaScale * aspect); - const float dy_scale = dy * (1 / (float)height() * retinaScale); - - float xpos = dx_scale + startDragX_; - float ypos = dy_scale + startDragY_; + auto world = mouseToWorldCoordinates(dx, dy); + viewMove_.translate(world.x(), -world.y()); - setXTranslation(xpos); - setYTranslation(ypos); + update(); } void FPGAViewWidget::wheelEvent(QWheelEvent *event) @@ -434,8 +418,19 @@ void FPGAViewWidget::wheelEvent(QWheelEvent *event) QPoint degree = event->angleDelta() / 8; if (!degree.isNull()) { - float steps = degree.y() / 3.0; - setZoom(zoom_ + steps); + + if (zoom_ < zoomNear_) { + zoom_ = zoomNear_; + } else if (zoom_ < zoomLvl1_) { + zoom_ -= degree.y() / 10.0; + } else if (zoom_ < zoomLvl2_) { + zoom_ -= degree.y() / 5.0; + } else if (zoom_ < zoomFar_) { + zoom_ -= degree.y(); + } else { + zoom_ = zoomFar_; + } + update(); } } diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index c281fd77..b49029dd 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -245,13 +245,18 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions private: QPoint lastPos_; - float moveX_; - float moveY_; - float zoom_; LineShader lineShader_; + QMatrix4x4 viewMove_; + float zoom_; + QMatrix4x4 getProjection(void); + QVector4D mouseToWorldCoordinates(int x, int y); + + const float zoomNear_ = 1.0f; // do not zoom closer than this + const float zoomFar_ = 10000.0f; // do not zoom further than this + + const float zoomLvl1_ = 100.0f; + const float zoomLvl2_ = 50.0f; - float startDragX_; - float startDragY_; Context *ctx_; }; -- cgit v1.2.3 From ad60ab2ef164678cdde4410906cea674d122bf13 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 12 Jul 2018 21:46:16 +0200 Subject: Fix ice40 wire segments in lutff complex Signed-off-by: Clifford Wolf --- ice40/chipdb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 00194deb..97bc3183 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -389,8 +389,8 @@ with open(args.filename, "r") as f: wire_xy[mode[1]].append((int(line[0]), int(line[1]))) if mode[1] not in wire_segments: wire_segments[mode[1]] = set() - if ("TILE_WIRE_" + wname[2].upper()) in gfx_wire_ids: - wire_segments[mode[1]].add((wname[0], wname[1], gfx_wire_ids["TILE_WIRE_" + wname[2].upper()])) + if ("TILE_WIRE_" + wname[2].upper().replace("/", "_")) in gfx_wire_ids: + wire_segments[mode[1]].add((wname[0], wname[1], gfx_wire_ids["TILE_WIRE_" + wname[2].upper().replace("/", "_")])) continue if mode[0] in ("buffer", "routing"): -- cgit v1.2.3 From b8a42ff53b1fbb6e03d169d14e58180a750f4cad Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 12 Jul 2018 22:04:13 +0200 Subject: Updates from clang-format Signed-off-by: Clifford Wolf --- common/nextpnr.h | 49 ++++++++++++++++++------------------------------- ecp5/arch.cc | 10 ++-------- ecp5/archdefs.h | 10 ++++++++-- ecp5/main.cc | 10 ++++------ generic/arch.cc | 33 ++++++++------------------------- generic/main.cc | 10 ++++------ gui/basewindow.h | 2 +- gui/designwidget.cc | 10 +++++----- gui/fpgaviewwidget.cc | 16 ++++++---------- gui/fpgaviewwidget.h | 2 +- ice40/arch.cc | 36 +++++++++++++----------------------- ice40/archdefs.h | 12 ++++++++---- ice40/bitstream.cc | 5 ++--- ice40/chipdb.py | 4 +++- ice40/gfx.cc | 6 +++--- ice40/gfx.h | 3 ++- ice40/main.cc | 10 ++++------ 17 files changed, 92 insertions(+), 136 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 00a939a9..5e8c2362 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -268,9 +268,9 @@ struct BaseCtx delete idstring_idx_to_str; } - Context *getCtx() { return reinterpret_cast(this); } + Context *getCtx() { return reinterpret_cast(this); } - const Context *getCtx() const { return reinterpret_cast(this); } + const Context *getCtx() const { return reinterpret_cast(this); } // -------------------------------------------------------------- @@ -281,35 +281,17 @@ struct BaseCtx std::unordered_set pipUiReload; std::unordered_set groupUiReload; - void refreshUi() - { - allUiReload = true; - } + void refreshUi() { allUiReload = true; } - void refreshUiFrame() - { - frameUiReload = true; - } + void refreshUiFrame() { frameUiReload = true; } - void refreshUiBel(BelId bel) - { - belUiReload.insert(bel); - } + void refreshUiBel(BelId bel) { belUiReload.insert(bel); } - void refreshUiWire(WireId wire) - { - wireUiReload.insert(wire); - } + void refreshUiWire(WireId wire) { wireUiReload.insert(wire); } - void refreshUiPip(PipId pip) - { - pipUiReload.insert(pip); - } + void refreshUiPip(PipId pip) { pipUiReload.insert(pip); } - void refreshUiGroup(GroupId group) - { - groupUiReload.insert(group); - } + void refreshUiGroup(GroupId group) { groupUiReload.insert(group); } }; NEXTPNR_NAMESPACE_END @@ -330,7 +312,8 @@ struct Context : Arch // -------------------------------------------------------------- - NPNR_DEPRECATED std::vector getFrameGraphics() const { + NPNR_DEPRECATED std::vector getFrameGraphics() const + { std::vector ret; DecalXY decalxy = getFrameDecal(); ret = getDecalGraphics(decalxy.decal); @@ -343,7 +326,8 @@ struct Context : Arch return ret; } - NPNR_DEPRECATED std::vector getBelGraphics(BelId bel) const { + NPNR_DEPRECATED std::vector getBelGraphics(BelId bel) const + { std::vector ret; DecalXY decalxy = getBelDecal(bel); ret = getDecalGraphics(decalxy.decal); @@ -356,7 +340,8 @@ struct Context : Arch return ret; } - NPNR_DEPRECATED std::vector getWireGraphics(WireId wire) const { + NPNR_DEPRECATED std::vector getWireGraphics(WireId wire) const + { std::vector ret; DecalXY decalxy = getWireDecal(wire); ret = getDecalGraphics(decalxy.decal); @@ -369,7 +354,8 @@ struct Context : Arch return ret; } - NPNR_DEPRECATED std::vector getPipGraphics(PipId pip) const { + NPNR_DEPRECATED std::vector getPipGraphics(PipId pip) const + { std::vector ret; DecalXY decalxy = getPipDecal(pip); ret = getDecalGraphics(decalxy.decal); @@ -382,7 +368,8 @@ struct Context : Arch return ret; } - NPNR_DEPRECATED std::vector getGroupGraphics(GroupId group) const { + NPNR_DEPRECATED std::vector getGroupGraphics(GroupId group) const + { std::vector ret; DecalXY decalxy = getGroupDecal(group); ret = getDecalGraphics(decalxy.decal); diff --git a/ecp5/arch.cc b/ecp5/arch.cc index ace0703e..51f4db84 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -290,15 +290,9 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const // ----------------------------------------------------------------------- -bool Arch::place() -{ - return placer1(getCtx()); -} +bool Arch::place() { return placer1(getCtx()); } -bool Arch::route() -{ - return router1(getCtx()); -} +bool Arch::route() { return router1(getCtx()); } // ----------------------------------------------------------------------- diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index 797db5f7..c4d25a50 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -119,8 +119,14 @@ struct DecalId Location location; uint32_t z = 0; - bool operator==(const DecalId &other) const { return type == other.type && location == other.location && z == other.z; } - bool operator!=(const DecalId &other) const { return type != other.type || location != other.location || z != other.z; } + bool operator==(const DecalId &other) const + { + return type == other.type && location == other.location && z == other.z; + } + bool operator!=(const DecalId &other) const + { + return type != other.type || location != other.location || z != other.z; + } }; NEXTPNR_NAMESPACE_END diff --git a/ecp5/main.cc b/ecp5/main.cc index 45774431..59403a93 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -93,18 +93,16 @@ int main(int argc, char *argv[]) } if (vm.count("help") || argc == 1) { - std::cout << boost::filesystem::basename(argv[0]) - << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; std::cout << "\n"; std::cout << options << "\n"; return argc != 1; } if (vm.count("version")) { - std::cout << boost::filesystem::basename(argv[0]) - << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; return 1; } diff --git a/generic/arch.cc b/generic/arch.cc index 1e1434d3..ec2443f2 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -109,25 +109,13 @@ void Arch::addBelInout(IdString bel, IdString name, IdString wire) wires.at(wire).downhill_bel_pins.push_back(BelPin{bel, name}); } -void Arch::addGroupBel(IdString group, IdString bel) -{ - groups[group].bels.push_back(bel); -} +void Arch::addGroupBel(IdString group, IdString bel) { groups[group].bels.push_back(bel); } -void Arch::addGroupWire(IdString group, IdString wire) -{ - groups[group].wires.push_back(wire); -} +void Arch::addGroupWire(IdString group, IdString wire) { groups[group].wires.push_back(wire); } -void Arch::addGroupPip(IdString group, IdString pip) -{ - groups[group].pips.push_back(pip); -} +void Arch::addGroupPip(IdString group, IdString pip) { groups[group].pips.push_back(pip); } -void Arch::addGroupGroup(IdString group, IdString grp) -{ - groups[group].groups.push_back(grp); -} +void Arch::addGroupGroup(IdString group, IdString grp) { groups[group].groups.push_back(grp); } void Arch::addDecalGraphic(DecalId decal, const GraphicElement &graphic) { @@ -330,7 +318,8 @@ GroupId Arch::getGroupByName(IdString name) const { return name; } IdString Arch::getGroupName(GroupId group) const { return group; } -std::vector Arch::getGroups() const { +std::vector Arch::getGroups() const +{ std::vector ret; for (auto &it : groups) ret.push_back(it.first); @@ -365,15 +354,9 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const // --------------------------------------------------------------- -bool Arch::place() -{ - return placer1(getCtx()); -} +bool Arch::place() { return placer1(getCtx()); } -bool Arch::route() -{ - return router1(getCtx()); -} +bool Arch::route() { return router1(getCtx()); } // --------------------------------------------------------------- diff --git a/generic/main.cc b/generic/main.cc index d025d8d4..6f4774d1 100644 --- a/generic/main.cc +++ b/generic/main.cc @@ -75,18 +75,16 @@ int main(int argc, char *argv[]) } if (vm.count("help") || argc == 1) { - std::cout << boost::filesystem::basename(argv[0]) - << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; std::cout << "\n"; std::cout << options << "\n"; return argc != 1; } if (vm.count("version")) { - std::cout << boost::filesystem::basename(argv[0]) - << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; return 1; } diff --git a/gui/basewindow.h b/gui/basewindow.h index c98a0356..ef3dcb95 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -26,10 +26,10 @@ #include #include #include +#include #include #include #include -#include Q_DECLARE_METATYPE(std::string) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 14de974e..110cf1b7 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -91,7 +91,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net propertyEditor->show(); const QIcon searchIcon(":/icons/resources/zoom.png"); - QLineEdit* lineEdit = new QLineEdit(); + QLineEdit *lineEdit = new QLineEdit(); lineEdit->setClearButtonEnabled(true); lineEdit->addAction(searchIcon, QLineEdit::LeadingPosition); lineEdit->setPlaceholderText("Search..."); @@ -139,17 +139,17 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net hbox->addWidget(toolbar); QWidget *btmWidget = new QWidget(); - + QVBoxLayout *vbox2 = new QVBoxLayout(); - btmWidget->setLayout(vbox2); + btmWidget->setLayout(vbox2); vbox2->setSpacing(0); vbox2->setContentsMargins(0, 0, 0, 0); vbox2->addWidget(toolbarWidget); vbox2->addWidget(propertyEditor); QSplitter *splitter = new QSplitter(Qt::Vertical); - splitter->addWidget(topWidget); - splitter->addWidget(btmWidget); + splitter->addWidget(topWidget); + splitter->addWidget(btmWidget); QGridLayout *mainLayout = new QGridLayout(); mainLayout->setSpacing(0); diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index edb3aca8..1b105b98 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -240,8 +240,7 @@ void LineShader::draw(const LineShaderData &line, const QMatrix4x4 &projection) vao_.release(); } -FPGAViewWidget::FPGAViewWidget(QWidget *parent) - : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr) +FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr) { backgroundColor = QColor("#ffffff"); gridColor = QColor("#ddd"); @@ -284,7 +283,7 @@ void FPGAViewWidget::initializeGL() log_error("Could not compile shader.\n"); } initializeOpenGLFunctions(); - glClearColor(backgroundColor.red()/255, backgroundColor.green()/255, backgroundColor.blue()/255, 0.0); + glClearColor(backgroundColor.red() / 255, backgroundColor.green() / 255, backgroundColor.blue() / 255, 0.0); } void FPGAViewWidget::drawElement(LineShaderData &out, const GraphicElement &el) @@ -311,7 +310,7 @@ QMatrix4x4 FPGAViewWidget::getProjection(void) QMatrix4x4 matrix; const float aspect = float(width()) / float(height()); - matrix.perspective(3.14/2, aspect, zoomNear_, zoomFar_); + matrix.perspective(3.14 / 2, aspect, zoomNear_, zoomFar_); matrix.translate(0.0f, 0.0f, -zoom_); return matrix; } @@ -391,10 +390,7 @@ void FPGAViewWidget::paintGL() void FPGAViewWidget::resizeGL(int width, int height) {} -void FPGAViewWidget::mousePressEvent(QMouseEvent *event) -{ - lastPos_ = event->pos(); -} +void FPGAViewWidget::mousePressEvent(QMouseEvent *event) { lastPos_ = event->pos(); } // Invert the projection matrix to calculate screen/mouse to world/grid // coordinates. @@ -403,8 +399,8 @@ QVector4D FPGAViewWidget::mouseToWorldCoordinates(int x, int y) QMatrix4x4 p = getProjection(); QVector2D unit = p.map(QVector4D(1, 1, 0, 1)).toVector2DAffine(); - float sx = (((float)x) / (width()/2)); - float sy = (((float)y) / (height()/2)); + float sx = (((float)x) / (width() / 2)); + float sy = (((float)y) / (height() / 2)); return QVector4D(sx / unit.x(), sy / unit.y(), 0, 1); } diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 526c6199..a2495f4e 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -258,7 +258,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions QMatrix4x4 getProjection(void); QVector4D mouseToWorldCoordinates(int x, int y); - const float zoomNear_ = 1.0f; // do not zoom closer than this + const float zoomNear_ = 1.0f; // do not zoom closer than this const float zoomFar_ = 10000.0f; // do not zoom further than this const float zoomLvl1_ = 100.0f; diff --git a/ice40/arch.cc b/ice40/arch.cc index 8650aeff..786bf686 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -19,12 +19,12 @@ #include #include +#include "gfx.h" #include "log.h" #include "nextpnr.h" #include "placer1.h" #include "router1.h" #include "util.h" -#include "gfx.h" NEXTPNR_NAMESPACE_BEGIN @@ -380,10 +380,7 @@ GroupId Arch::getGroupByName(IdString name) const return GroupId(); } -IdString Arch::getGroupName(GroupId group) const -{ - return IdString(); -} +IdString Arch::getGroupName(GroupId group) const { return IdString(); } std::vector Arch::getGroups() const { @@ -448,15 +445,9 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const // ----------------------------------------------------------------------- -bool Arch::place() -{ - return placer1(getCtx()); -} +bool Arch::place() { return placer1(getCtx()); } -bool Arch::route() -{ - return router1(getCtx()); -} +bool Arch::route() { return router1(getCtx()); } // ----------------------------------------------------------------------- @@ -499,8 +490,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const { std::vector ret; - if (decal.type == DecalId::TYPE_FRAME) - { + if (decal.type == DecalId::TYPE_FRAME) { for (int x = 0; x <= chip_info->width; x++) for (int y = 0; y <= chip_info->height; y++) { GraphicElement el; @@ -512,23 +502,21 @@ std::vector Arch::getDecalGraphics(DecalId decal) const } } - if (decal.type == DecalId::TYPE_WIRE) - { + if (decal.type == DecalId::TYPE_WIRE) { WireId wire; wire.index = decal.index; int n = chip_info->wire_data[wire.index].num_segments; const WireSegmentPOD *p = chip_info->wire_data[wire.index].segments.get(); - GraphicElement::style_t style = wire_to_net.at(wire.index) != IdString() ? - GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; + GraphicElement::style_t style = + wire_to_net.at(wire.index) != IdString() ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; for (int i = 0; i < n; i++) gfxTileWire(ret, p[i].x, p[i].y, GfxTileWireId(p[i].index), style); } - if (decal.type == DecalId::TYPE_BEL) - { + if (decal.type == DecalId::TYPE_BEL) { BelId bel; bel.index = decal.index; @@ -540,8 +528,10 @@ std::vector Arch::getDecalGraphics(DecalId decal) const el.style = bel_to_cell.at(bel.index) != IdString() ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; - el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; - el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; + el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; + el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; el.z = 0; ret.push_back(el); diff --git a/ice40/archdefs.h b/ice40/archdefs.h index 62c248c7..3252dabf 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -111,7 +111,8 @@ struct PipId struct GroupId { - enum : int8_t { + enum : int8_t + { TYPE_NONE, TYPE_FRAME, TYPE_MAIN_SW, @@ -133,7 +134,8 @@ struct GroupId struct DecalId { - enum : int8_t { + enum : int8_t + { TYPE_NONE, TYPE_FRAME, TYPE_BEL, @@ -178,7 +180,8 @@ template <> struct hash : hash template <> struct hash { - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept { + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept + { std::size_t seed = 0; boost::hash_combine(seed, hash()(group.type)); boost::hash_combine(seed, hash()(group.x)); @@ -189,7 +192,8 @@ template <> struct hash template <> struct hash { - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept { + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept + { std::size_t seed = 0; boost::hash_combine(seed, hash()(decal.type)); boost::hash_combine(seed, hash()(decal.index)); diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 98a7a0e4..a62c6c09 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -341,9 +341,8 @@ void write_asc(const Context *ctx, std::ostream &out) set_config(ti, config.at(y).at(x), "Cascade.IPCON_LC0" + std::to_string(lc_idx) + "_inmux02_5", true); else - set_config(ti, config.at(y).at(x), - "Cascade.MULT" + std::to_string(int(tile - TILE_DSP0)) + "_LC0" + - std::to_string(lc_idx) + "_inmux02_5", + set_config(ti, config.at(y).at(x), "Cascade.MULT" + std::to_string(int(tile - TILE_DSP0)) + + "_LC0" + std::to_string(lc_idx) + "_inmux02_5", true); } } diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 97bc3183..f52a2283 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -73,10 +73,12 @@ with open(args.portspins) as f: with open(args.gfxh) as f: state = 0 for line in f: - if state == 0 and line.startswith("enum GfxTileWireId "): + if state == 0 and line.startswith("enum GfxTileWireId"): state = 1 elif state == 1 and line.startswith("};"): state = 0 + elif state == 1 and line.startswith("{"): + pass elif state == 1: idx = len(gfx_wire_ids) name = line.strip().rstrip(",") diff --git a/ice40/gfx.cc b/ice40/gfx.cc index d6935b7d..f4941750 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -333,7 +333,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, // LC Inputs - if (id >= TILE_WIRE_LUTFF_0_IN_0 && id <= TILE_WIRE_LUTFF_7_IN_3) { + if (id >= TILE_WIRE_LUTFF_0_IN_0 && id <= TILE_WIRE_LUTFF_7_IN_3) { int idx = id - TILE_WIRE_LUTFF_0_IN_0; int z = idx / 4; int input = idx % 4; @@ -354,7 +354,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, el.y1 = y1; el.y2 = y1; el.x1 = x + main_swbox_x2; - el.x2 = x + 0.97 + 0.0025 * (7-idx); + el.x2 = x + 0.97 + 0.0025 * (7 - idx); g.push_back(el); el.y1 = y1; @@ -386,7 +386,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, el.x1 = el.x2; g.push_back(el); - for (int i = 0; i < 7; i ++) { + for (int i = 0; i < 7; i++) { el.y1 = y + logic_cell_y2 + i * logic_cell_pitch; el.y2 = y + logic_cell_y1 + (i + 1) * logic_cell_pitch; g.push_back(el); diff --git a/ice40/gfx.h b/ice40/gfx.h index aa07c2fa..a65f7683 100644 --- a/ice40/gfx.h +++ b/ice40/gfx.h @@ -40,7 +40,8 @@ const float logic_cell_y1 = 0.05; const float logic_cell_y2 = 0.10; const float logic_cell_pitch = 0.0625; -enum GfxTileWireId { +enum GfxTileWireId +{ TILE_WIRE_GLB2LOCAL_0, TILE_WIRE_GLB2LOCAL_1, TILE_WIRE_GLB2LOCAL_2, diff --git a/ice40/main.cc b/ice40/main.cc index 2427ea6c..5fa58921 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -128,18 +128,16 @@ int main(int argc, char *argv[]) if (vm.count("help") || argc == 1) { help: - std::cout << boost::filesystem::basename(argv[0]) - << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; std::cout << "\n"; std::cout << options << "\n"; return argc != 1; } if (vm.count("version")) { - std::cout << boost::filesystem::basename(argv[0]) - << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; return 1; } -- cgit v1.2.3 From 499951cb65ff31fe15aa360a6b44371b13815d66 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Thu, 12 Jul 2018 21:30:36 +0100 Subject: Remove legacy graphics API For now we do not optimize the OpenGL renderer against the new decal API, but this can be done in the future. --- common/nextpnr.h | 72 --------------------------------------------------- gui/fpgaviewwidget.cc | 52 ++++++++++++++++++------------------- gui/fpgaviewwidget.h | 2 +- ice40/main.cc | 32 +++++++++++------------ 4 files changed, 43 insertions(+), 115 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 5e8c2362..50465869 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -312,78 +312,6 @@ struct Context : Arch // -------------------------------------------------------------- - NPNR_DEPRECATED std::vector getFrameGraphics() const - { - std::vector ret; - DecalXY decalxy = getFrameDecal(); - ret = getDecalGraphics(decalxy.decal); - for (auto &it : ret) { - it.x1 += decalxy.x; - it.x2 += decalxy.x; - it.y1 += decalxy.y; - it.y2 += decalxy.y; - } - return ret; - } - - NPNR_DEPRECATED std::vector getBelGraphics(BelId bel) const - { - std::vector ret; - DecalXY decalxy = getBelDecal(bel); - ret = getDecalGraphics(decalxy.decal); - for (auto &it : ret) { - it.x1 += decalxy.x; - it.x2 += decalxy.x; - it.y1 += decalxy.y; - it.y2 += decalxy.y; - } - return ret; - } - - NPNR_DEPRECATED std::vector getWireGraphics(WireId wire) const - { - std::vector ret; - DecalXY decalxy = getWireDecal(wire); - ret = getDecalGraphics(decalxy.decal); - for (auto &it : ret) { - it.x1 += decalxy.x; - it.x2 += decalxy.x; - it.y1 += decalxy.y; - it.y2 += decalxy.y; - } - return ret; - } - - NPNR_DEPRECATED std::vector getPipGraphics(PipId pip) const - { - std::vector ret; - DecalXY decalxy = getPipDecal(pip); - ret = getDecalGraphics(decalxy.decal); - for (auto &it : ret) { - it.x1 += decalxy.x; - it.x2 += decalxy.x; - it.y1 += decalxy.y; - it.y2 += decalxy.y; - } - return ret; - } - - NPNR_DEPRECATED std::vector getGroupGraphics(GroupId group) const - { - std::vector ret; - DecalXY decalxy = getGroupDecal(group); - ret = getDecalGraphics(decalxy.decal); - for (auto &it : ret) { - it.x1 += decalxy.x; - it.x2 += decalxy.x; - it.y1 += decalxy.y; - it.y2 += decalxy.y; - } - return ret; - } - - // -------------------------------------------------------------- - // provided by router1.cc bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t &delay); diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 1b105b98..84b8f8d2 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -286,22 +286,28 @@ void FPGAViewWidget::initializeGL() glClearColor(backgroundColor.red() / 255, backgroundColor.green() / 255, backgroundColor.blue() / 255, 0.0); } -void FPGAViewWidget::drawElement(LineShaderData &out, const GraphicElement &el) +void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal) { - const float scale = 1.0, offset = 0.0; - - if (el.type == GraphicElement::G_BOX) { - auto line = PolyLine(true); - line.point(offset + scale * el.x1, offset + scale * el.y1); - line.point(offset + scale * el.x2, offset + scale * el.y1); - line.point(offset + scale * el.x2, offset + scale * el.y2); - line.point(offset + scale * el.x1, offset + scale * el.y2); - line.build(out); - } + const float scale = 1.0; + float offsetX = 0.0, offsetY = 0.0; + + for (auto &el : ctx_->getDecalGraphics(decal.decal)) { + offsetX = decal.x; + offsetY = decal.y; + + if (el.type == GraphicElement::G_BOX) { + auto line = PolyLine(true); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); + line.build(out); + } - if (el.type == GraphicElement::G_LINE) { - PolyLine(offset + scale * el.x1, offset + scale * el.y1, offset + scale * el.x2, offset + scale * el.y2) - .build(out); + if (el.type == GraphicElement::G_LINE) { + PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, offsetY + scale * el.y2) + .build(out); + } } } @@ -342,8 +348,7 @@ void FPGAViewWidget::paintGL() auto bels = LineShaderData(thick11Px, belColor); if (ctx_) { for (auto bel : ctx_->getBels()) { - for (auto &el : ctx_->getBelGraphics(bel)) - drawElement(bels, el); + drawDecal(bels, ctx_->getBelDecal(bel)); } lineShader_.draw(bels, matrix); } @@ -352,8 +357,7 @@ void FPGAViewWidget::paintGL() auto wires = LineShaderData(thick11Px, wireColor); if (ctx_) { for (auto wire : ctx_->getWires()) { - for (auto &el : ctx_->getWireGraphics(wire)) - drawElement(wires, el); + drawDecal(wires, ctx_->getWireDecal(wire)); } lineShader_.draw(wires, matrix); } @@ -361,9 +365,8 @@ void FPGAViewWidget::paintGL() // Draw Pips. auto pips = LineShaderData(thick11Px, pipColor); if (ctx_) { - for (auto wire : ctx_->getPips()) { - for (auto &el : ctx_->getPipGraphics(wire)) - drawElement(pips, el); + for (auto pip : ctx_->getPips()) { + drawDecal(pips, ctx_->getPipDecal(pip)); } lineShader_.draw(pips, matrix); } @@ -372,8 +375,7 @@ void FPGAViewWidget::paintGL() auto groups = LineShaderData(thick11Px, groupColor); if (ctx_) { for (auto group : ctx_->getGroups()) { - for (auto &el : ctx_->getGroupGraphics(group)) - drawElement(groups, el); + drawDecal(groups, ctx_->getGroupDecal(group)); } lineShader_.draw(groups, matrix); } @@ -381,9 +383,7 @@ void FPGAViewWidget::paintGL() // Draw Frame Graphics. auto frames = LineShaderData(thick11Px, frameColor); if (ctx_) { - for (auto &el : ctx_->getFrameGraphics()) { - drawElement(frames, el); - } + drawDecal(frames, ctx_->getFrameDecal()); lineShader_.draw(frames, matrix); } } diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index a2495f4e..90e12bbf 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -246,7 +246,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; - void drawElement(LineShaderData &data, const GraphicElement &el); + void drawDecal(LineShaderData &data, const DecalXY &decal); public Q_SLOTS: void newContext(Context *ctx); diff --git a/ice40/main.cc b/ice40/main.cc index 5fa58921..32864703 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -47,20 +47,22 @@ USING_NEXTPNR_NAMESPACE -void svg_dump_el(const GraphicElement &el) +void svg_dump_decal(const Context &ctx, const DecalXY &decal) { - float scale = 10.0, offset = 10.0; - std::string style = "stroke=\"black\" stroke-width=\"0.1\" fill=\"none\""; - - if (el.type == GraphicElement::G_BOX) { - std::cout << "\n"; - } + const float scale = 10.0, offset = 10.0; + const std::string style = "stroke=\"black\" stroke-width=\"0.1\" fill=\"none\""; + + for (auto &el : ctx.getDecalGraphics(decal.decal)) { + if (el.type == GraphicElement::G_BOX) { + std::cout << "\n"; + } - if (el.type == GraphicElement::G_LINE) { - std::cout << "\n"; + if (el.type == GraphicElement::G_LINE) { + std::cout << "\n"; + } } } @@ -291,12 +293,10 @@ int main(int argc, char *argv[]) "xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n"; for (auto bel : ctx.getBels()) { std::cout << "\n"; - for (auto &el : ctx.getBelGraphics(bel)) - svg_dump_el(el); + svg_dump_decal(ctx, ctx.getBelDecal(bel)); } std::cout << "\n"; - for (auto &el : ctx.getFrameGraphics()) - svg_dump_el(el); + svg_dump_decal(ctx, ctx.getFrameDecal()); std::cout << "\n"; } -- cgit v1.2.3 From 8e54ac15421be441ece2a85ff0d61e850a99b2e9 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 13 Jul 2018 09:14:48 +0200 Subject: Use command line parameters settings for GUI as well. --- ecp5/main.cc | 66 ++++++++++---------- generic/main.cc | 39 ++++++------ gui/basewindow.cc | 3 +- gui/basewindow.h | 6 +- gui/ecp5/mainwindow.cc | 3 +- gui/ecp5/mainwindow.h | 2 +- gui/generic/mainwindow.cc | 3 +- gui/generic/mainwindow.h | 2 +- gui/ice40/mainwindow.cc | 49 +++++++++------ gui/ice40/mainwindow.h | 6 +- gui/infotab.h | 3 +- ice40/main.cc | 155 ++++++++++++++++++++++++---------------------- 12 files changed, 184 insertions(+), 153 deletions(-) diff --git a/ecp5/main.cc b/ecp5/main.cc index 59403a93..734ae560 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -93,16 +93,18 @@ int main(int argc, char *argv[]) } if (vm.count("help") || argc == 1) { - std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; std::cout << "\n"; std::cout << options << "\n"; return argc != 1; } if (vm.count("version")) { - std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; return 1; } @@ -112,41 +114,51 @@ int main(int argc, char *argv[]) args.type = ArchArgs::LFE5U_45F; args.package = "CABGA381"; args.speed = 6; - Context ctx(args); + std::unique_ptr ctx = std::unique_ptr(new Context(args)); if (vm.count("verbose")) { - ctx.verbose = true; + ctx->verbose = true; } if (vm.count("force")) { - ctx.force = true; + ctx->force = true; } if (vm.count("seed")) { - ctx.rngseed(vm["seed"].as()); + ctx->rngseed(vm["seed"].as()); } + ctx->timing_driven = true; + if (vm.count("no-tmdriv")) + ctx->timing_driven = false; + +#ifndef NO_GUI + if (vm.count("gui")) { + Application a(argc, argv); + MainWindow w(std::move(ctx)); + w.show(); + + return a.exec(); + } +#endif if (vm.count("json")) { std::string filename = vm["json"].as(); std::ifstream f(filename); - if (!parse_json_file(f, filename, &ctx)) + if (!parse_json_file(f, filename, ctx.get())) log_error("Loading design failed.\n"); - if (!pack_design(&ctx) && !ctx.force) + if (!pack_design(ctx.get()) && !ctx->force) log_error("Packing design failed.\n"); if (vm.count("freq")) - ctx.target_freq = vm["freq"].as() * 1e6; - assign_budget(&ctx); - ctx.check(); - print_utilisation(&ctx); - ctx.timing_driven = true; - if (vm.count("no-tmdriv")) - ctx.timing_driven = false; - - if (!ctx.place() && !ctx.force) + ctx->target_freq = vm["freq"].as() * 1e6; + assign_budget(ctx.get()); + ctx->check(); + print_utilisation(ctx.get()); + + if (!ctx->place() && !ctx->force) log_error("Placing design failed.\n"); - ctx.check(); - if (!ctx.route() && !ctx.force) + ctx->check(); + if (!ctx->route() && !ctx->force) log_error("Routing design failed.\n"); std::string basecfg; @@ -160,7 +172,7 @@ int main(int argc, char *argv[]) std::string textcfg; if (vm.count("textcfg")) textcfg = vm["textcfg"].as(); - write_bitstream(&ctx, basecfg, textcfg, bitstream); + write_bitstream(ctx.get(), basecfg, textcfg, bitstream); } #ifndef NO_PYTHON @@ -175,16 +187,6 @@ int main(int argc, char *argv[]) deinit_python(); } #endif - -#ifndef NO_GUI - if (vm.count("gui")) { - Application a(argc, argv); - MainWindow w; - w.show(); - - rc = a.exec(); - } -#endif return rc; } catch (log_execution_error_exception) { #if defined(_MSC_VER) diff --git a/generic/main.cc b/generic/main.cc index 6f4774d1..3b8b3fe6 100644 --- a/generic/main.cc +++ b/generic/main.cc @@ -75,37 +75,49 @@ int main(int argc, char *argv[]) } if (vm.count("help") || argc == 1) { - std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; std::cout << "\n"; std::cout << options << "\n"; return argc != 1; } if (vm.count("version")) { - std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; return 1; } - Context ctx(ArchArgs{}); + std::unique_ptr ctx = std::unique_ptr(new Context(ArchArgs{})); if (vm.count("verbose")) { - ctx.verbose = true; + ctx->verbose = true; } if (vm.count("force")) { - ctx.force = true; + ctx->force = true; } if (vm.count("seed")) { - ctx.rngseed(vm["seed"].as()); + ctx->rngseed(vm["seed"].as()); } +#ifndef NO_GUI + if (vm.count("gui")) { + Application a(argc, argv); + MainWindow w(std::move(ctx)); + w.show(); + + return a.exec(); + } +#endif + #ifndef NO_PYTHON if (vm.count("run")) { init_python(argv[0], true); - python_export_global("ctx", ctx); + python_export_global("ctx", *ctx.get()); std::vector files = vm["run"].as>(); for (auto filename : files) @@ -115,15 +127,6 @@ int main(int argc, char *argv[]) } #endif -#ifndef NO_GUI - if (vm.count("gui")) { - Application a(argc, argv); - MainWindow w; - w.show(); - - rc = a.exec(); - } -#endif return rc; } catch (log_execution_error_exception) { #if defined(_MSC_VER) diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 5a53e9cf..6bc56c7b 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -36,7 +36,8 @@ static void initBasenameResource() { Q_INIT_RESOURCE(base); } NEXTPNR_NAMESPACE_BEGIN -BaseMainWindow::BaseMainWindow(QWidget *parent) : QMainWindow(parent), ctx(nullptr) +BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent) + : QMainWindow(parent), ctx(std::move(context)) { initBasenameResource(); qRegisterMetaType(); diff --git a/gui/basewindow.h b/gui/basewindow.h index ef3dcb95..d2d0505d 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -40,9 +40,9 @@ class BaseMainWindow : public QMainWindow Q_OBJECT public: - explicit BaseMainWindow(QWidget *parent = 0); + explicit BaseMainWindow(std::unique_ptr context, QWidget *parent = 0); virtual ~BaseMainWindow(); - Context *getContext() { return ctx; } + Context *getContext() { return ctx.get(); } protected: void createMenusAndBars(); @@ -59,7 +59,7 @@ class BaseMainWindow : public QMainWindow void updateTreeView(); protected: - Context *ctx; + std::unique_ptr ctx; QTabWidget *tabWidget; QTabWidget *centralTabWidget; InfoTab *info; diff --git a/gui/ecp5/mainwindow.cc b/gui/ecp5/mainwindow.cc index 6cc3dd15..1168a55c 100644 --- a/gui/ecp5/mainwindow.cc +++ b/gui/ecp5/mainwindow.cc @@ -23,7 +23,7 @@ static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } NEXTPNR_NAMESPACE_BEGIN -MainWindow::MainWindow(QWidget *parent) : BaseMainWindow(parent) +MainWindow::MainWindow(std::unique_ptr context, QWidget *parent) : BaseMainWindow(std::move(context), parent) { initMainResource(); @@ -31,6 +31,7 @@ MainWindow::MainWindow(QWidget *parent) : BaseMainWindow(parent) setWindowTitle(title.c_str()); createMenu(); + Q_EMIT contextChanged(ctx.get()); } MainWindow::~MainWindow() {} diff --git a/gui/ecp5/mainwindow.h b/gui/ecp5/mainwindow.h index fd9812cd..e97bb4e7 100644 --- a/gui/ecp5/mainwindow.h +++ b/gui/ecp5/mainwindow.h @@ -29,7 +29,7 @@ class MainWindow : public BaseMainWindow Q_OBJECT public: - explicit MainWindow(QWidget *parent = 0); + explicit MainWindow(std::unique_ptr context, QWidget *parent = 0); virtual ~MainWindow(); public: diff --git a/gui/generic/mainwindow.cc b/gui/generic/mainwindow.cc index fef63094..88e291e6 100644 --- a/gui/generic/mainwindow.cc +++ b/gui/generic/mainwindow.cc @@ -23,7 +23,7 @@ static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } NEXTPNR_NAMESPACE_BEGIN -MainWindow::MainWindow(QWidget *parent) : BaseMainWindow(parent) +MainWindow::MainWindow(std::unique_ptr context, QWidget *parent) : BaseMainWindow(std::move(context), parent) { initMainResource(); @@ -31,6 +31,7 @@ MainWindow::MainWindow(QWidget *parent) : BaseMainWindow(parent) setWindowTitle(title.c_str()); createMenu(); + Q_EMIT contextChanged(ctx.get()); } MainWindow::~MainWindow() {} diff --git a/gui/generic/mainwindow.h b/gui/generic/mainwindow.h index fd9812cd..e97bb4e7 100644 --- a/gui/generic/mainwindow.h +++ b/gui/generic/mainwindow.h @@ -29,7 +29,7 @@ class MainWindow : public BaseMainWindow Q_OBJECT public: - explicit MainWindow(QWidget *parent = 0); + explicit MainWindow(std::unique_ptr context, QWidget *parent = 0); virtual ~MainWindow(); public: diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index 6f0a9b97..e8476fcf 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -34,7 +34,8 @@ static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } NEXTPNR_NAMESPACE_BEGIN -MainWindow::MainWindow(QWidget *parent) : BaseMainWindow(parent), timing_driven(false) +MainWindow::MainWindow(std::unique_ptr context, QWidget *parent) + : BaseMainWindow(std::move(context), parent), timing_driven(false) { initMainResource(); @@ -60,6 +61,8 @@ MainWindow::MainWindow(QWidget *parent) : BaseMainWindow(parent), timing_driven( connect(this, SIGNAL(contextChanged(Context *)), task, SIGNAL(contextChanged(Context *))); createMenu(); + + Q_EMIT contextChanged(ctx.get()); } MainWindow::~MainWindow() { delete task; } @@ -75,7 +78,7 @@ void MainWindow::createMenu() actionLoadJSON->setIcon(iconLoadJSON); actionLoadJSON->setStatusTip("Open an existing JSON file"); connect(actionLoadJSON, SIGNAL(triggered()), this, SLOT(open_json())); - actionLoadJSON->setEnabled(false); + actionLoadJSON->setEnabled(true); actionLoadPCF = new QAction("Open PCF", this); QIcon iconLoadPCF; @@ -239,22 +242,36 @@ void MainWindow::new_proj() if (ok && !item.isEmpty()) { disableActions(); + preload_pcf = ""; chipArgs.package = package.toStdString().c_str(); - if (ctx) - delete ctx; - ctx = new Context(chipArgs); - - Q_EMIT contextChanged(ctx); + ctx = std::unique_ptr(new Context(chipArgs)); - actionLoadJSON->setEnabled(true); + Q_EMIT contextChanged(ctx.get()); } } } +void MainWindow::load_json(std::string filename, std::string pcf) +{ + tabWidget->setCurrentWidget(info); + preload_pcf = pcf; + disableActions(); + Q_EMIT task->loadfile(filename); +} + +void MainWindow::load_pcf(std::string filename) +{ + tabWidget->setCurrentWidget(info); + + disableActions(); + Q_EMIT task->loadpcf(filename); +} + void MainWindow::newContext(Context *ctx) { std::string title = "nextpnr-ice40 - " + ctx->getChipName() + " ( " + chipArgs.package + " )"; setWindowTitle(title.c_str()); + info->clearBuffer(); } void MainWindow::open_proj() @@ -272,12 +289,7 @@ void MainWindow::open_json() { QString fileName = QFileDialog::getOpenFileName(this, QString("Open JSON"), QString(), QString("*.json")); if (!fileName.isEmpty()) { - tabWidget->setCurrentWidget(info); - - std::string fn = fileName.toStdString(); - disableActions(); - timing_driven = false; - Q_EMIT task->loadfile(fn); + load_json(fileName.toStdString(), ""); } } @@ -285,11 +297,7 @@ void MainWindow::open_pcf() { QString fileName = QFileDialog::getOpenFileName(this, QString("Open PCF"), QString(), QString("*.pcf")); if (!fileName.isEmpty()) { - tabWidget->setCurrentWidget(info); - - std::string fn = fileName.toStdString(); - disableActions(); - Q_EMIT task->loadpcf(fn); + load_pcf(fileName.toStdString()); } } @@ -330,9 +338,12 @@ void MainWindow::loadfile_finished(bool status) log("Loading design successful.\n"); actionLoadPCF->setEnabled(true); actionPack->setEnabled(true); + if (!preload_pcf.empty()) + load_pcf(preload_pcf); Q_EMIT updateTreeView(); } else { log("Loading design failed.\n"); + preload_pcf = ""; } } diff --git a/gui/ice40/mainwindow.h b/gui/ice40/mainwindow.h index 8e847adc..2bed925f 100644 --- a/gui/ice40/mainwindow.h +++ b/gui/ice40/mainwindow.h @@ -30,12 +30,13 @@ class MainWindow : public BaseMainWindow Q_OBJECT public: - explicit MainWindow(QWidget *parent = 0); + explicit MainWindow(std::unique_ptr context, QWidget *parent = 0); virtual ~MainWindow(); public: void createMenu(); - + void load_json(std::string filename, std::string pcf); + void load_pcf(std::string filename); protected Q_SLOTS: virtual void new_proj(); virtual void open_proj(); @@ -78,6 +79,7 @@ class MainWindow : public BaseMainWindow bool timing_driven; ArchArgs chipArgs; + std::string preload_pcf; }; NEXTPNR_NAMESPACE_END diff --git a/gui/infotab.h b/gui/infotab.h index 0116755e..41529973 100644 --- a/gui/infotab.h +++ b/gui/infotab.h @@ -33,9 +33,10 @@ class InfoTab : public QWidget public: explicit InfoTab(QWidget *parent = 0); void info(std::string str); + public Q_SLOTS: + void clearBuffer(); private Q_SLOTS: void showContextMenu(const QPoint &pt); - void clearBuffer(); private: QPlainTextEdit *plainTextEdit; diff --git a/ice40/main.cc b/ice40/main.cc index 32864703..ae988da9 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -47,21 +47,22 @@ USING_NEXTPNR_NAMESPACE -void svg_dump_decal(const Context &ctx, const DecalXY &decal) +void svg_dump_decal(const Context *ctx, const DecalXY &decal) { const float scale = 10.0, offset = 10.0; const std::string style = "stroke=\"black\" stroke-width=\"0.1\" fill=\"none\""; - for (auto &el : ctx.getDecalGraphics(decal.decal)) { + for (auto &el : ctx->getDecalGraphics(decal.decal)) { if (el.type == GraphicElement::G_BOX) { - std::cout << "\n"; + std::cout << "\n"; } if (el.type == GraphicElement::G_LINE) { - std::cout << "\n"; + std::cout << "\n"; } } } @@ -130,16 +131,18 @@ int main(int argc, char *argv[]) if (vm.count("help") || argc == 1) { help: - std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; std::cout << "\n"; std::cout << options << "\n"; return argc != 1; } if (vm.count("version")) { - std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; return 1; } @@ -269,110 +272,126 @@ int main(int argc, char *argv[]) return 1; } - Context ctx(chipArgs); + std::unique_ptr ctx = std::unique_ptr(new Context(chipArgs)); if (vm.count("verbose")) { - ctx.verbose = true; + ctx->verbose = true; } if (vm.count("debug")) { - ctx.verbose = true; - ctx.debug = true; + ctx->verbose = true; + ctx->debug = true; } if (vm.count("force")) { - ctx.force = true; + ctx->force = true; } if (vm.count("seed")) { - ctx.rngseed(vm["seed"].as()); + ctx->rngseed(vm["seed"].as()); } if (vm.count("svg")) { std::cout << "\n"; - for (auto bel : ctx.getBels()) { - std::cout << "\n"; - svg_dump_decal(ctx, ctx.getBelDecal(bel)); + for (auto bel : ctx->getBels()) { + std::cout << "\n"; + svg_dump_decal(ctx.get(), ctx->getBelDecal(bel)); } std::cout << "\n"; - svg_dump_decal(ctx, ctx.getFrameDecal()); + svg_dump_decal(ctx.get(), ctx->getFrameDecal()); std::cout << "\n"; } if (vm.count("tmfuzz")) { std::vector src_wires, dst_wires; - /*for (auto w : ctx.getWires()) + /*for (auto w : ctx->getWires()) src_wires.push_back(w);*/ - for (auto b : ctx.getBels()) { - if (ctx.getBelType(b) == TYPE_ICESTORM_LC) { - src_wires.push_back(ctx.getWireBelPin(b, PIN_O)); + for (auto b : ctx->getBels()) { + if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { + src_wires.push_back(ctx->getWireBelPin(b, PIN_O)); } - if (ctx.getBelType(b) == TYPE_SB_IO) { - src_wires.push_back(ctx.getWireBelPin(b, PIN_D_IN_0)); + if (ctx->getBelType(b) == TYPE_SB_IO) { + src_wires.push_back(ctx->getWireBelPin(b, PIN_D_IN_0)); } } - for (auto b : ctx.getBels()) { - if (ctx.getBelType(b) == TYPE_ICESTORM_LC) { - dst_wires.push_back(ctx.getWireBelPin(b, PIN_I0)); - dst_wires.push_back(ctx.getWireBelPin(b, PIN_I1)); - dst_wires.push_back(ctx.getWireBelPin(b, PIN_I2)); - dst_wires.push_back(ctx.getWireBelPin(b, PIN_I3)); - dst_wires.push_back(ctx.getWireBelPin(b, PIN_CEN)); - dst_wires.push_back(ctx.getWireBelPin(b, PIN_CIN)); + for (auto b : ctx->getBels()) { + if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { + dst_wires.push_back(ctx->getWireBelPin(b, PIN_I0)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_I1)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_I2)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_I3)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_CEN)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_CIN)); } - if (ctx.getBelType(b) == TYPE_SB_IO) { - dst_wires.push_back(ctx.getWireBelPin(b, PIN_D_OUT_0)); - dst_wires.push_back(ctx.getWireBelPin(b, PIN_OUTPUT_ENABLE)); + if (ctx->getBelType(b) == TYPE_SB_IO) { + dst_wires.push_back(ctx->getWireBelPin(b, PIN_D_OUT_0)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_OUTPUT_ENABLE)); } } - ctx.shuffle(src_wires); - ctx.shuffle(dst_wires); + ctx->shuffle(src_wires); + ctx->shuffle(dst_wires); for (int i = 0; i < int(src_wires.size()) && i < int(dst_wires.size()); i++) { delay_t actual_delay; WireId src = src_wires[i], dst = dst_wires[i]; - if (!ctx.getActualRouteDelay(src, dst, actual_delay)) + if (!ctx->getActualRouteDelay(src, dst, actual_delay)) continue; - printf("%s %s %.3f %.3f %d %d %d %d %d %d\n", ctx.getWireName(src).c_str(&ctx), - ctx.getWireName(dst).c_str(&ctx), ctx.getDelayNS(actual_delay), - ctx.getDelayNS(ctx.estimateDelay(src, dst)), ctx.chip_info->wire_data[src.index].x, - ctx.chip_info->wire_data[src.index].y, ctx.chip_info->wire_data[src.index].type, - ctx.chip_info->wire_data[dst.index].x, ctx.chip_info->wire_data[dst.index].y, - ctx.chip_info->wire_data[dst.index].type); + printf("%s %s %.3f %.3f %d %d %d %d %d %d\n", ctx->getWireName(src).c_str(ctx.get()), + ctx->getWireName(dst).c_str(ctx.get()), ctx->getDelayNS(actual_delay), + ctx->getDelayNS(ctx->estimateDelay(src, dst)), ctx->chip_info->wire_data[src.index].x, + ctx->chip_info->wire_data[src.index].y, ctx->chip_info->wire_data[src.index].type, + ctx->chip_info->wire_data[dst.index].x, ctx->chip_info->wire_data[dst.index].y, + ctx->chip_info->wire_data[dst.index].type); } } + if (vm.count("freq")) + ctx->target_freq = vm["freq"].as() * 1e6; + ctx->timing_driven = true; + if (vm.count("no-tmdriv")) + ctx->timing_driven = false; +#ifndef NO_GUI + if (vm.count("gui")) { + Application a(argc, argv); + MainWindow w(std::move(ctx)); + if (vm.count("json")) { + std::string filename = vm["json"].as(); + std::string pcf = ""; + if (vm.count("pcf")) + pcf = vm["pcf"].as(); + w.load_json(filename, pcf); + } + w.show(); + + return a.exec(); + } +#endif if (vm.count("json")) { std::string filename = vm["json"].as(); std::ifstream f(filename); - if (!parse_json_file(f, filename, &ctx)) + if (!parse_json_file(f, filename, ctx.get())) log_error("Loading design failed.\n"); if (vm.count("pcf")) { std::ifstream pcf(vm["pcf"].as()); - if (!apply_pcf(&ctx, pcf)) + if (!apply_pcf(ctx.get(), pcf)) log_error("Loading PCF failed.\n"); } - if (!pack_design(&ctx) && !ctx.force) + if (!pack_design(ctx.get()) && !ctx->force) log_error("Packing design failed.\n"); - if (vm.count("freq")) - ctx.target_freq = vm["freq"].as() * 1e6; - assign_budget(&ctx); - ctx.check(); - print_utilisation(&ctx); - ctx.timing_driven = true; - if (vm.count("no-tmdriv")) - ctx.timing_driven = false; + assign_budget(ctx.get()); + ctx->check(); + print_utilisation(ctx.get()); if (!vm.count("pack-only")) { - if (!ctx.place() && !ctx.force) + if (!ctx->place() && !ctx->force) log_error("Placing design failed.\n"); - ctx.check(); - if (!ctx.route() && !ctx.force) + ctx->check(); + if (!ctx->route() && !ctx->force) log_error("Routing design failed.\n"); } } @@ -380,13 +399,13 @@ int main(int argc, char *argv[]) if (vm.count("asc")) { std::string filename = vm["asc"].as(); std::ofstream f(filename); - write_asc(&ctx, f); + write_asc(ctx.get(), f); } #ifndef NO_PYTHON if (vm.count("run")) { init_python(argv[0], true); - python_export_global("ctx", ctx); + python_export_global("ctx", *ctx.get()); std::vector files = vm["run"].as>(); for (auto filename : files) @@ -395,16 +414,6 @@ int main(int argc, char *argv[]) deinit_python(); } #endif - -#ifndef NO_GUI - if (vm.count("gui")) { - Application a(argc, argv); - MainWindow w; - w.show(); - - rc = a.exec(); - } -#endif return rc; } catch (log_execution_error_exception) { #if defined(_MSC_VER) -- cgit v1.2.3 From 96d862311da878e09ef3fe3666dd10561f0169c6 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 13 Jul 2018 11:03:09 +0200 Subject: Add coloring per graphics element style --- gui/fpgaviewwidget.cc | 100 +++++++++++++++++++++++++++++++++++--------------- gui/fpgaviewwidget.h | 17 +++++---- 2 files changed, 80 insertions(+), 37 deletions(-) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 84b8f8d2..98f1e9e2 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -244,10 +244,10 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineSha { backgroundColor = QColor("#ffffff"); gridColor = QColor("#ddd"); - belColor = QColor("#303030"); - wireColor = QColor("#303030"); - pipColor = QColor("#303030"); - groupColor = QColor("#303030"); + gFrameColor = QColor("#303030"); + gHiddenColor = QColor("#a0a0a0"); + gInactiveColor = QColor("#d0d0d0"); + gActiveColor = QColor("#101010"); frameColor = QColor("#0066ba"); auto fmt = format(); fmt.setMajorVersion(3); @@ -311,6 +311,56 @@ void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal) } } +void FPGAViewWidget::drawDecal(LineShaderData out[], const DecalXY &decal) +{ + const float scale = 1.0; + float offsetX = 0.0, offsetY = 0.0; + + for (auto &el : ctx_->getDecalGraphics(decal.decal)) { + offsetX = decal.x; + offsetY = decal.y; + + if (el.type == GraphicElement::G_BOX) { + auto line = PolyLine(true); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); + switch (el.style) { + case GraphicElement::G_FRAME: + line.build(out[0]); + break; + case GraphicElement::G_HIDDEN: + break; + case GraphicElement::G_INACTIVE: + line.build(out[2]); + break; + case GraphicElement::G_ACTIVE: + line.build(out[3]); + break; + } + } + + if (el.type == GraphicElement::G_LINE) { + auto line = PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, + offsetY + scale * el.y2); + switch (el.style) { + case GraphicElement::G_FRAME: + line.build(out[0]); + break; + case GraphicElement::G_HIDDEN: + break; + case GraphicElement::G_INACTIVE: + line.build(out[2]); + break; + case GraphicElement::G_ACTIVE: + line.build(out[3]); + break; + } + } + } +} + QMatrix4x4 FPGAViewWidget::getProjection(void) { QMatrix4x4 matrix; @@ -344,41 +394,33 @@ void FPGAViewWidget::paintGL() } lineShader_.draw(grid, matrix); - // Draw Bels. - auto bels = LineShaderData(thick11Px, belColor); + LineShaderData shaders[4] = {LineShaderData(thick11Px, gFrameColor), // GraphicElement::G_FRAME + LineShaderData(thick11Px, gHiddenColor), // GraphicElement::G_HIDDEN + LineShaderData(thick11Px, gInactiveColor), // GraphicElement::G_INACTIVE + LineShaderData(thick11Px, gActiveColor)}; // GraphicElement::G_ACTIVE + if (ctx_) { + // Draw Bels. for (auto bel : ctx_->getBels()) { - drawDecal(bels, ctx_->getBelDecal(bel)); + drawDecal(shaders, ctx_->getBelDecal(bel)); } - lineShader_.draw(bels, matrix); - } - - // Draw Wires. - auto wires = LineShaderData(thick11Px, wireColor); - if (ctx_) { + // Draw Wires. for (auto wire : ctx_->getWires()) { - drawDecal(wires, ctx_->getWireDecal(wire)); + drawDecal(shaders, ctx_->getWireDecal(wire)); } - lineShader_.draw(wires, matrix); - } - - // Draw Pips. - auto pips = LineShaderData(thick11Px, pipColor); - if (ctx_) { + // Draw Pips. for (auto pip : ctx_->getPips()) { - drawDecal(pips, ctx_->getPipDecal(pip)); + drawDecal(shaders, ctx_->getPipDecal(pip)); } - lineShader_.draw(pips, matrix); - } - - // Draw Groups. - auto groups = LineShaderData(thick11Px, groupColor); - if (ctx_) { + // Draw Groups. for (auto group : ctx_->getGroups()) { - drawDecal(groups, ctx_->getGroupDecal(group)); + drawDecal(shaders, ctx_->getGroupDecal(group)); } - lineShader_.draw(groups, matrix); } + lineShader_.draw(shaders[0], matrix); + lineShader_.draw(shaders[1], matrix); + lineShader_.draw(shaders[2], matrix); + lineShader_.draw(shaders[3], matrix); // Draw Frame Graphics. auto frames = LineShaderData(thick11Px, frameColor); diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 90e12bbf..8d91224e 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -217,11 +217,11 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT Q_PROPERTY(QColor backgroundColor MEMBER backgroundColor DESIGNABLE true) - Q_PROPERTY(QColor belColor MEMBER belColor DESIGNABLE true) Q_PROPERTY(QColor gridColor MEMBER gridColor DESIGNABLE true) - Q_PROPERTY(QColor wireColor MEMBER wireColor DESIGNABLE true) - Q_PROPERTY(QColor pipColor MEMBER pipColor DESIGNABLE true) - Q_PROPERTY(QColor groupColor MEMBER groupColor DESIGNABLE true) + Q_PROPERTY(QColor gFrameColor MEMBER gFrameColor DESIGNABLE true) + Q_PROPERTY(QColor gHiddenColor MEMBER gHiddenColor DESIGNABLE true) + Q_PROPERTY(QColor gInactiveColor MEMBER gInactiveColor DESIGNABLE true) + Q_PROPERTY(QColor gActiveColor MEMBER gActiveColor DESIGNABLE true) Q_PROPERTY(QColor frameColor MEMBER frameColor DESIGNABLE true) public: @@ -247,6 +247,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; void drawDecal(LineShaderData &data, const DecalXY &decal); + void drawDecal(LineShaderData out[], const DecalXY &decal); public Q_SLOTS: void newContext(Context *ctx); @@ -267,10 +268,10 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions Context *ctx_; QColor backgroundColor; QColor gridColor; - QColor belColor; - QColor wireColor; - QColor pipColor; - QColor groupColor; + QColor gFrameColor; + QColor gHiddenColor; + QColor gInactiveColor; + QColor gActiveColor; QColor frameColor; }; -- cgit v1.2.3 From 0f0259fd9467cf99f1ecc02887d9f8ce7f1427d6 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 13 Jul 2018 11:21:49 +0200 Subject: invert palette for fpga viewer --- gui/fpgaviewwidget.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 98f1e9e2..263e0e60 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -242,6 +242,7 @@ void LineShader::draw(const LineShaderData &line, const QMatrix4x4 &projection) FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr) { + /* backgroundColor = QColor("#ffffff"); gridColor = QColor("#ddd"); gFrameColor = QColor("#303030"); @@ -249,6 +250,15 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineSha gInactiveColor = QColor("#d0d0d0"); gActiveColor = QColor("#101010"); frameColor = QColor("#0066ba"); + */ + backgroundColor = QColor("#000000"); + gridColor = QColor("#333"); + gFrameColor = QColor("#d0d0d0"); + gHiddenColor = QColor("#606060"); + gInactiveColor = QColor("#303030"); + gActiveColor = QColor("#f0f0f0"); + frameColor = QColor("#0066ba"); + auto fmt = format(); fmt.setMajorVersion(3); fmt.setMinorVersion(1); -- cgit v1.2.3 From b5498c8a5366f8ae6c1e6e850a55b49753b0d6a6 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 13 Jul 2018 12:02:49 +0200 Subject: Fixed initial title and actions after new --- gui/ice40/mainwindow.cc | 5 +++-- gui/ice40/mainwindow.h | 2 +- ice40/main.cc | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index e8476fcf..b7f08104 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -34,8 +34,8 @@ static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } NEXTPNR_NAMESPACE_BEGIN -MainWindow::MainWindow(std::unique_ptr context, QWidget *parent) - : BaseMainWindow(std::move(context), parent), timing_driven(false) +MainWindow::MainWindow(std::unique_ptr context, ArchArgs args, QWidget *parent) + : BaseMainWindow(std::move(context), parent), timing_driven(false), chipArgs(args) { initMainResource(); @@ -245,6 +245,7 @@ void MainWindow::new_proj() preload_pcf = ""; chipArgs.package = package.toStdString().c_str(); ctx = std::unique_ptr(new Context(chipArgs)); + actionLoadJSON->setEnabled(true); Q_EMIT contextChanged(ctx.get()); } diff --git a/gui/ice40/mainwindow.h b/gui/ice40/mainwindow.h index 2bed925f..cfd938f8 100644 --- a/gui/ice40/mainwindow.h +++ b/gui/ice40/mainwindow.h @@ -30,7 +30,7 @@ class MainWindow : public BaseMainWindow Q_OBJECT public: - explicit MainWindow(std::unique_ptr context, QWidget *parent = 0); + explicit MainWindow(std::unique_ptr context, ArchArgs args, QWidget *parent = 0); virtual ~MainWindow(); public: diff --git a/ice40/main.cc b/ice40/main.cc index ae988da9..53cd7164 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -357,7 +357,7 @@ int main(int argc, char *argv[]) #ifndef NO_GUI if (vm.count("gui")) { Application a(argc, argv); - MainWindow w(std::move(ctx)); + MainWindow w(std::move(ctx), chipArgs); if (vm.count("json")) { std::string filename = vm["json"].as(); std::string pcf = ""; -- cgit v1.2.3 From 309a533b7c5eab79addfc2b1733d39c1b48d9aae Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 13 Jul 2018 11:38:49 +0100 Subject: Style. --- gui/fpgaviewwidget.cc | 57 ++++++++++++++++++--------------------------------- gui/fpgaviewwidget.h | 29 +++++++++++++------------- 2 files changed, 35 insertions(+), 51 deletions(-) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 263e0e60..6b6a2617 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -242,22 +242,13 @@ void LineShader::draw(const LineShaderData &line, const QMatrix4x4 &projection) FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr) { - /* - backgroundColor = QColor("#ffffff"); - gridColor = QColor("#ddd"); - gFrameColor = QColor("#303030"); - gHiddenColor = QColor("#a0a0a0"); - gInactiveColor = QColor("#d0d0d0"); - gActiveColor = QColor("#101010"); - frameColor = QColor("#0066ba"); - */ - backgroundColor = QColor("#000000"); - gridColor = QColor("#333"); - gFrameColor = QColor("#d0d0d0"); - gHiddenColor = QColor("#606060"); - gInactiveColor = QColor("#303030"); - gActiveColor = QColor("#f0f0f0"); - frameColor = QColor("#0066ba"); + backgroundColor_ = QColor("#000000"); + gridColor_ = QColor("#333"); + gFrameColor_ = QColor("#d0d0d0"); + gHiddenColor_ = QColor("#606060"); + gInactiveColor_ = QColor("#303030"); + gActiveColor_ = QColor("#f0f0f0"); + frameColor_ = QColor("#0066ba"); auto fmt = format(); fmt.setMajorVersion(3); @@ -293,7 +284,7 @@ void FPGAViewWidget::initializeGL() log_error("Could not compile shader.\n"); } initializeOpenGLFunctions(); - glClearColor(backgroundColor.red() / 255, backgroundColor.green() / 255, backgroundColor.blue() / 255, 0.0); + glClearColor(backgroundColor_.red() / 255, backgroundColor_.green() / 255, backgroundColor_.blue() / 255, 0.0); } void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal) @@ -338,15 +329,11 @@ void FPGAViewWidget::drawDecal(LineShaderData out[], const DecalXY &decal) line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); switch (el.style) { case GraphicElement::G_FRAME: - line.build(out[0]); - break; - case GraphicElement::G_HIDDEN: - break; case GraphicElement::G_INACTIVE: - line.build(out[2]); - break; case GraphicElement::G_ACTIVE: - line.build(out[3]); + line.build(out[el.style]); + break; + default: break; } } @@ -356,15 +343,11 @@ void FPGAViewWidget::drawDecal(LineShaderData out[], const DecalXY &decal) offsetY + scale * el.y2); switch (el.style) { case GraphicElement::G_FRAME: - line.build(out[0]); - break; - case GraphicElement::G_HIDDEN: - break; case GraphicElement::G_INACTIVE: - line.build(out[2]); - break; case GraphicElement::G_ACTIVE: - line.build(out[3]); + line.build(out[el.style]); + break; + default: break; } } @@ -397,17 +380,17 @@ void FPGAViewWidget::paintGL() float thick11Px = mouseToWorldCoordinates(1.1, 0).x(); // Draw grid. - auto grid = LineShaderData(thick1Px, gridColor); + auto grid = LineShaderData(thick1Px, gridColor_); for (float i = -100.0f; i < 100.0f; i += 1.0f) { PolyLine(-100.0f, i, 100.0f, i).build(grid); PolyLine(i, -100.0f, i, 100.0f).build(grid); } lineShader_.draw(grid, matrix); - LineShaderData shaders[4] = {LineShaderData(thick11Px, gFrameColor), // GraphicElement::G_FRAME - LineShaderData(thick11Px, gHiddenColor), // GraphicElement::G_HIDDEN - LineShaderData(thick11Px, gInactiveColor), // GraphicElement::G_INACTIVE - LineShaderData(thick11Px, gActiveColor)}; // GraphicElement::G_ACTIVE + LineShaderData shaders[4] = {[GraphicElement::G_FRAME] = LineShaderData(thick11Px, gFrameColor_), + [GraphicElement::G_HIDDEN] = LineShaderData(thick11Px, gHiddenColor_), + [GraphicElement::G_INACTIVE] = LineShaderData(thick11Px, gInactiveColor_), + [GraphicElement::G_ACTIVE] = LineShaderData(thick11Px, gActiveColor_)}; if (ctx_) { // Draw Bels. @@ -433,7 +416,7 @@ void FPGAViewWidget::paintGL() lineShader_.draw(shaders[3], matrix); // Draw Frame Graphics. - auto frames = LineShaderData(thick11Px, frameColor); + auto frames = LineShaderData(thick11Px, frameColor_); if (ctx_) { drawDecal(frames, ctx_->getFrameDecal()); lineShader_.draw(frames, matrix); diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 8d91224e..410b0582 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -216,13 +216,13 @@ class LineShader class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT - Q_PROPERTY(QColor backgroundColor MEMBER backgroundColor DESIGNABLE true) - Q_PROPERTY(QColor gridColor MEMBER gridColor DESIGNABLE true) - Q_PROPERTY(QColor gFrameColor MEMBER gFrameColor DESIGNABLE true) - Q_PROPERTY(QColor gHiddenColor MEMBER gHiddenColor DESIGNABLE true) - Q_PROPERTY(QColor gInactiveColor MEMBER gInactiveColor DESIGNABLE true) - Q_PROPERTY(QColor gActiveColor MEMBER gActiveColor DESIGNABLE true) - Q_PROPERTY(QColor frameColor MEMBER frameColor DESIGNABLE true) + Q_PROPERTY(QColor backgroundColor MEMBER backgroundColor_ DESIGNABLE true) + Q_PROPERTY(QColor gridColor MEMBER gridColor_ DESIGNABLE true) + Q_PROPERTY(QColor gFrameColor MEMBER gFrameColor_ DESIGNABLE true) + Q_PROPERTY(QColor gHiddenColor MEMBER gHiddenColor_ DESIGNABLE true) + Q_PROPERTY(QColor gInactiveColor MEMBER gInactiveColor_ DESIGNABLE true) + Q_PROPERTY(QColor gActiveColor MEMBER gActiveColor_ DESIGNABLE true) + Q_PROPERTY(QColor frameColor MEMBER frameColor_ DESIGNABLE true) public: FPGAViewWidget(QWidget *parent = 0); @@ -266,13 +266,14 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions const float zoomLvl2_ = 50.0f; Context *ctx_; - QColor backgroundColor; - QColor gridColor; - QColor gFrameColor; - QColor gHiddenColor; - QColor gInactiveColor; - QColor gActiveColor; - QColor frameColor; + + QColor backgroundColor_; + QColor gridColor_; + QColor gFrameColor_; + QColor gHiddenColor_; + QColor gInactiveColor_; + QColor gActiveColor_; + QColor frameColor_; }; NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From e9668ed618b054d323fe848fce2bf1e78840316e Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 13 Jul 2018 12:42:04 +0200 Subject: Fixing hash link problem Signed-off-by: David Shah --- ecp5/archdefs.h | 2 +- ice40/archdefs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index c4d25a50..84a431fd 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -22,7 +22,7 @@ #error Include "archdefs.h" via "nextpnr.h" only. #endif -#include +#include NEXTPNR_NAMESPACE_BEGIN diff --git a/ice40/archdefs.h b/ice40/archdefs.h index 3252dabf..2bb718f1 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -21,7 +21,7 @@ #error Include "archdefs.h" via "nextpnr.h" only. #endif -#include +#include NEXTPNR_NAMESPACE_BEGIN -- cgit v1.2.3 From 0816f447b768ebe0632f419e9b696714dda4e860 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 13 Jul 2018 12:35:39 +0100 Subject: Make ice40::Arch thread-safe We move all non-chip data to be private and guard them with an R/W mutex. We then modify all calls that access these fields to lock/shared_lock the mutex as required. Profiling the code before and after is an exercise left to the reader :). --- ice40/arch.cc | 7 +++++++ ice40/arch.h | 38 ++++++++++++++++++++++++++++++++------ ice40/bitstream.cc | 10 +++++----- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 786bf686..88a900d8 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -241,6 +241,7 @@ IdString Arch::archArgsToId(ArchArgs args) const BelId Arch::getBelByName(IdString name) const { + boost::lock_guard lock(mtx_); BelId ret; if (bel_by_name.empty()) { @@ -276,6 +277,7 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const WireId Arch::getWireBelPin(BelId bel, PortPin pin) const { WireId ret; + boost::shared_lock_guard lock(mtx_); NPNR_ASSERT(bel != BelId()); @@ -296,6 +298,7 @@ WireId Arch::getWireBelPin(BelId bel, PortPin pin) const WireId Arch::getWireByName(IdString name) const { WireId ret; + boost::shared_lock_guard lock(mtx_); if (wire_by_name.empty()) { for (int i = 0; i < chip_info->num_wires; i++) @@ -314,6 +317,7 @@ WireId Arch::getWireByName(IdString name) const PipId Arch::getPipByName(IdString name) const { PipId ret; + boost::shared_lock_guard lock(mtx_); if (pip_by_name.empty()) { for (int i = 0; i < chip_info->num_pips; i++) { @@ -372,6 +376,8 @@ std::string Arch::getBelPackagePin(BelId bel) const // ----------------------------------------------------------------------- +// TODO(cliffordvienna): lock all of this + GroupId Arch::getGroupByName(IdString name) const { for (auto g : getGroups()) @@ -488,6 +494,7 @@ DecalXY Arch::getGroupDecal(GroupId group) const std::vector Arch::getDecalGraphics(DecalId decal) const { + boost::shared_lock_guard lock(mtx_); std::vector ret; if (decal.type == DecalId::TYPE_FRAME) { diff --git a/ice40/arch.h b/ice40/arch.h index 04de5178..410df48b 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -21,6 +21,9 @@ #error Include "arch.h" via "nextpnr.h" only. #endif +#include +#include + NEXTPNR_NAMESPACE_BEGIN /**** Everything in this section must be kept in sync with chipdb.py ****/ @@ -324,8 +327,17 @@ struct ArchArgs std::string package; }; -struct Arch : BaseCtx +class Arch : public BaseCtx { +private: + // All of the following... + std::vector bel_to_cell; + std::vector wire_to_net; + std::vector pip_to_net; + std::vector switches_locked; + // ... are guarded by the following lock: + mutable boost::shared_mutex mtx_; +public: const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; @@ -333,11 +345,6 @@ struct Arch : BaseCtx mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; - std::vector bel_to_cell; - std::vector wire_to_net; - std::vector pip_to_net; - std::vector switches_locked; - ArchArgs args; Arch(ArchArgs args); @@ -368,6 +375,7 @@ struct Arch : BaseCtx { NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); + boost::lock_guard lock(mtx_); bel_to_cell[bel.index] = cell; cells[cell]->bel = bel; cells[cell]->belStrength = strength; @@ -377,6 +385,7 @@ struct Arch : BaseCtx { NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); + boost::lock_guard lock(mtx_); cells[bel_to_cell[bel.index]]->bel = BelId(); cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; bel_to_cell[bel.index] = IdString(); @@ -385,18 +394,21 @@ struct Arch : BaseCtx bool checkBelAvail(BelId bel) const { NPNR_ASSERT(bel != BelId()); + boost::shared_lock_guard lock(mtx_); return bel_to_cell[bel.index] == IdString(); } IdString getBoundBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); + boost::shared_lock_guard lock(mtx_); return bel_to_cell[bel.index]; } IdString getConflictingBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); + boost::shared_lock_guard lock(mtx_); return bel_to_cell[bel.index]; } @@ -470,6 +482,8 @@ struct Arch : BaseCtx { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire.index] == IdString()); + boost::lock_guard lock(mtx_); + wire_to_net[wire.index] = net; nets[net]->wires[wire].pip = PipId(); nets[net]->wires[wire].strength = strength; @@ -479,6 +493,7 @@ struct Arch : BaseCtx { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire.index] != IdString()); + boost::lock_guard lock(mtx_); auto &net_wires = nets[wire_to_net[wire.index]]->wires; auto it = net_wires.find(wire); @@ -497,18 +512,24 @@ struct Arch : BaseCtx bool checkWireAvail(WireId wire) const { NPNR_ASSERT(wire != WireId()); + boost::shared_lock_guard lock(mtx_); + return wire_to_net[wire.index] == IdString(); } IdString getBoundWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); + boost::shared_lock_guard lock(mtx_); + return wire_to_net[wire.index]; } IdString getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); + boost::shared_lock_guard lock(mtx_); + return wire_to_net[wire.index]; } @@ -532,6 +553,7 @@ struct Arch : BaseCtx NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] == IdString()); NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); + boost::lock_guard lock(mtx_); pip_to_net[pip.index] = net; switches_locked[chip_info->pip_data[pip.index].switch_index] = net; @@ -549,6 +571,7 @@ struct Arch : BaseCtx NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] != IdString()); NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); + boost::lock_guard lock(mtx_); WireId dst; dst.index = chip_info->pip_data[pip.index].dst; @@ -563,18 +586,21 @@ struct Arch : BaseCtx bool checkPipAvail(PipId pip) const { NPNR_ASSERT(pip != PipId()); + boost::shared_lock_guard lock(mtx_); return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); } IdString getBoundPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); + boost::shared_lock_guard lock(mtx_); return pip_to_net[pip.index]; } IdString getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); + boost::shared_lock_guard lock(mtx_); return switches_locked[chip_info->pip_data[pip.index].switch_index]; } diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index a62c6c09..58a59366 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -128,7 +128,7 @@ void write_asc(const Context *ctx, std::ostream &out) } // Set pips for (auto pip : ctx->getPips()) { - if (ctx->pip_to_net[pip.index] != IdString()) { + if (ctx->getBoundPipNet(pip) != IdString()) { const PipInfoPOD &pi = ci.pip_data[pip.index]; const SwitchInfoPOD &swi = bi.switches[pi.switch_index]; for (int i = 0; i < swi.num_bits; i++) { @@ -199,8 +199,8 @@ void write_asc(const Context *ctx, std::ostream &out) NPNR_ASSERT(iez != -1); bool input_en = false; - if ((ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_0).index] != IdString()) || - (ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_1).index] != IdString())) { + if (!ctx->checkWireAvail(ctx->getWireBelPin(bel, PIN_D_IN_0)) || + !ctx->checkWireAvail(ctx->getWireBelPin(bel, PIN_D_IN_1))) { input_en = true; } @@ -271,7 +271,7 @@ void write_asc(const Context *ctx, std::ostream &out) } // Set config bits in unused IO and RAM for (auto bel : ctx->getBels()) { - if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_SB_IO) { + if (ctx->checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_SB_IO) { const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y, z = beli.z; @@ -284,7 +284,7 @@ void write_asc(const Context *ctx, std::ostream &out) set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); } } - } else if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) { + } else if (ctx->checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) { const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB]; -- cgit v1.2.3 From 45462ef3a714c0d98fe570d96e6761e2b298c7d0 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 13 Jul 2018 14:29:03 +0200 Subject: Fix Ui/Decal handling of active/inactive arch objects Signed-off-by: Clifford Wolf --- generic/arch.cc | 12 +++++++++++- ice40/arch.cc | 14 +++++++++++--- ice40/arch.h | 11 +++++++++++ ice40/archdefs.h | 1 + 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/generic/arch.cc b/generic/arch.cc index ec2443f2..390830aa 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -181,6 +181,7 @@ void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength) bels.at(bel).bound_cell = cell; cells.at(cell)->bel = bel; cells.at(cell)->belStrength = strength; + refreshUiBel(bel); } void Arch::unbindBel(BelId bel) @@ -188,6 +189,7 @@ void Arch::unbindBel(BelId bel) cells.at(bels.at(bel).bound_cell)->bel = BelId(); cells.at(bels.at(bel).bound_cell)->belStrength = STRENGTH_NONE; bels.at(bel).bound_cell = IdString(); + refreshUiBel(bel); } bool Arch::checkBelAvail(BelId bel) const { return bels.at(bel).bound_cell == IdString(); } @@ -236,6 +238,7 @@ void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength) wires.at(wire).bound_net = net; nets.at(net)->wires[wire].pip = PipId(); nets.at(net)->wires[wire].strength = strength; + refreshUiWire(wire); } void Arch::unbindWire(WireId wire) @@ -243,11 +246,14 @@ void Arch::unbindWire(WireId wire) auto &net_wires = nets[wires.at(wire).bound_net]->wires; auto pip = net_wires.at(wire).pip; - if (pip != PipId()) + if (pip != PipId()) { pips.at(pip).bound_net = IdString(); + refreshUiPip(pip); + } net_wires.erase(wire); wires.at(wire).bound_net = IdString(); + refreshUiWire(wire); } bool Arch::checkWireAvail(WireId wire) const { return wires.at(wire).bound_net == IdString(); } @@ -282,6 +288,8 @@ void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength) wires.at(wire).bound_net = net; nets.at(net)->wires[wire].pip = pip; nets.at(net)->wires[wire].strength = strength; + refreshUiPip(pip); + refreshUiWire(wire); } void Arch::unbindPip(PipId pip) @@ -290,6 +298,8 @@ void Arch::unbindPip(PipId pip) nets.at(wires.at(wire).bound_net)->wires.erase(wire); pips.at(pip).bound_net = IdString(); wires.at(wire).bound_net = IdString(); + refreshUiPip(pip); + refreshUiWire(wire); } bool Arch::checkPipAvail(PipId pip) const { return pips.at(pip).bound_net == IdString(); } diff --git a/ice40/arch.cc b/ice40/arch.cc index 786bf686..9b058aa0 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -455,6 +455,7 @@ DecalXY Arch::getFrameDecal() const { DecalXY decalxy; decalxy.decal.type = DecalId::TYPE_FRAME; + decalxy.decal.active = true; return decalxy; } @@ -463,6 +464,7 @@ DecalXY Arch::getBelDecal(BelId bel) const DecalXY decalxy; decalxy.decal.type = DecalId::TYPE_BEL; decalxy.decal.index = bel.index; + decalxy.decal.active = bel_to_cell.at(bel.index) != IdString(); return decalxy; } @@ -471,18 +473,25 @@ DecalXY Arch::getWireDecal(WireId wire) const DecalXY decalxy; decalxy.decal.type = DecalId::TYPE_WIRE; decalxy.decal.index = wire.index; + decalxy.decal.active = wire_to_net.at(wire.index) != IdString(); return decalxy; } DecalXY Arch::getPipDecal(PipId pip) const { DecalXY decalxy; + decalxy.decal.type = DecalId::TYPE_PIP; + decalxy.decal.index = pip.index; + decalxy.decal.active = pip_to_net.at(pip.index) != IdString(); return decalxy; }; DecalXY Arch::getGroupDecal(GroupId group) const { DecalXY decalxy; + decalxy.decal.type = DecalId::TYPE_GROUP; + decalxy.decal.index = (group.type << 16) | (group.x << 8) | (group.y); + decalxy.decal.active = true; return decalxy; }; @@ -509,8 +518,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const int n = chip_info->wire_data[wire.index].num_segments; const WireSegmentPOD *p = chip_info->wire_data[wire.index].segments.get(); - GraphicElement::style_t style = - wire_to_net.at(wire.index) != IdString() ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; + GraphicElement::style_t style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; for (int i = 0; i < n; i++) gfxTileWire(ret, p[i].x, p[i].y, GfxTileWireId(p[i].index), style); @@ -525,7 +533,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const if (bel_type == TYPE_ICESTORM_LC) { GraphicElement el; el.type = GraphicElement::G_BOX; - el.style = bel_to_cell.at(bel.index) != IdString() ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; + el.style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + diff --git a/ice40/arch.h b/ice40/arch.h index 04de5178..b6c64de4 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -371,6 +371,7 @@ struct Arch : BaseCtx bel_to_cell[bel.index] = cell; cells[cell]->bel = bel; cells[cell]->belStrength = strength; + refreshUiBel(bel); } void unbindBel(BelId bel) @@ -380,6 +381,7 @@ struct Arch : BaseCtx cells[bel_to_cell[bel.index]]->bel = BelId(); cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; bel_to_cell[bel.index] = IdString(); + refreshUiBel(bel); } bool checkBelAvail(BelId bel) const @@ -473,6 +475,7 @@ struct Arch : BaseCtx wire_to_net[wire.index] = net; nets[net]->wires[wire].pip = PipId(); nets[net]->wires[wire].strength = strength; + refreshUiWire(wire); } void unbindWire(WireId wire) @@ -488,10 +491,12 @@ struct Arch : BaseCtx if (pip != PipId()) { pip_to_net[pip.index] = IdString(); switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + refreshUiPip(pip); } net_wires.erase(it); wire_to_net[wire.index] = IdString(); + refreshUiWire(wire); } bool checkWireAvail(WireId wire) const @@ -542,6 +547,9 @@ struct Arch : BaseCtx wire_to_net[dst.index] = net; nets[net]->wires[dst].pip = pip; nets[net]->wires[dst].strength = strength; + + refreshUiPip(pip); + refreshUiWire(dst); } void unbindPip(PipId pip) @@ -558,6 +566,9 @@ struct Arch : BaseCtx pip_to_net[pip.index] = IdString(); switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + + refreshUiPip(pip); + refreshUiWire(dst); } bool checkPipAvail(PipId pip) const diff --git a/ice40/archdefs.h b/ice40/archdefs.h index 2bb718f1..75df678a 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -144,6 +144,7 @@ struct DecalId TYPE_GROUP } type = TYPE_NONE; int32_t index = -1; + bool active = false; bool operator==(const DecalId &other) const { return (type == other.type) && (index == other.index); } bool operator!=(const DecalId &other) const { return (type != other.type) || (index != other.index); } -- cgit v1.2.3 From c05bea12e0af7ec847043c832133cbfddfb278b1 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 13 Jul 2018 15:16:44 +0200 Subject: Add ctx->pack() API Signed-off-by: Clifford Wolf --- ecp5/arch.h | 1 + ecp5/main.cc | 3 +-- ecp5/pack.cc | 4 ++-- ecp5/pack.h | 31 ------------------------------- generic/arch.h | 1 + gui/ice40/mainwindow.cc | 1 - gui/ice40/worker.cc | 3 +-- ice40/arch.h | 1 + ice40/arch_pybindings.cc | 5 ++++- ice40/main.cc | 3 +-- ice40/pack.cc | 4 ++-- ice40/pack.h | 32 -------------------------------- 12 files changed, 14 insertions(+), 75 deletions(-) delete mode 100644 ecp5/pack.h delete mode 100644 ice40/pack.h diff --git a/ecp5/arch.h b/ecp5/arch.h index bbc7c561..930c488e 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -730,6 +730,7 @@ struct Arch : BaseCtx // ------------------------------------------------- + bool pack(); bool place(); bool route(); diff --git a/ecp5/main.cc b/ecp5/main.cc index 734ae560..4cb2f10d 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -43,7 +43,6 @@ #include "bitstream.h" #include "design_utils.h" #include "jsonparse.h" -#include "pack.h" #include "timing.h" USING_NEXTPNR_NAMESPACE @@ -147,7 +146,7 @@ int main(int argc, char *argv[]) if (!parse_json_file(f, filename, ctx.get())) log_error("Loading design failed.\n"); - if (!pack_design(ctx.get()) && !ctx->force) + if (!ctx->pack() && !ctx->force) log_error("Packing design failed.\n"); if (vm.count("freq")) ctx->target_freq = vm["freq"].as() * 1e6; diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 7f54c231..e3ddc07d 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -17,7 +17,6 @@ * */ -#include "pack.h" #include #include #include @@ -84,8 +83,9 @@ void pack_io(Context *ctx) } // Main pack function -bool pack_design(Context *ctx) +bool Arch::pack() { + Context *ctx = getCtx(); try { log_break(); pack_io(ctx); diff --git a/ecp5/pack.h b/ecp5/pack.h deleted file mode 100644 index cc051a41..00000000 --- a/ecp5/pack.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2018 David Shah - * - * 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. - * - */ - -#ifndef PACK_H -#define PACK_H - -#include "nextpnr.h" - -NEXTPNR_NAMESPACE_BEGIN - -bool pack_design(Context *ctx); - -NEXTPNR_NAMESPACE_END - -#endif // ROUTE_H diff --git a/generic/arch.h b/generic/arch.h index f6243404..5d7ac540 100644 --- a/generic/arch.h +++ b/generic/arch.h @@ -183,6 +183,7 @@ struct Arch : BaseCtx float getDelayNS(delay_t v) const { return v; } uint32_t getDelayChecksum(delay_t v) const { return 0; } + bool pack() { return true; } bool place(); bool route(); diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index b7f08104..bea5fce7 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -27,7 +27,6 @@ #include "design_utils.h" #include "jsonparse.h" #include "log.h" -#include "pack.h" #include "pcf.h" static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc index 16f5fb89..09093ec8 100644 --- a/gui/ice40/worker.cc +++ b/gui/ice40/worker.cc @@ -23,7 +23,6 @@ #include "design_utils.h" #include "jsonparse.h" #include "log.h" -#include "pack.h" #include "pcf.h" #include "timing.h" @@ -97,7 +96,7 @@ void Worker::pack() { Q_EMIT taskStarted(); try { - bool res = pack_design(ctx); + bool res = ctx->pack(); print_utilisation(ctx); Q_EMIT pack_finished(res); } catch (WorkerInterruptionRequested) { diff --git a/ice40/arch.h b/ice40/arch.h index b6c64de4..34797442 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -672,6 +672,7 @@ struct Arch : BaseCtx // ------------------------------------------------- + bool pack(); bool place(); bool route(); diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc index ac8c189a..fd5109b4 100644 --- a/ice40/arch_pybindings.cc +++ b/ice40/arch_pybindings.cc @@ -58,7 +58,10 @@ void arch_wrap_python() auto arch_cls = class_, boost::noncopyable>("Arch", init()); auto ctx_cls = class_, boost::noncopyable>("Context", no_init) - .def("checksum", &Context::checksum); + .def("checksum", &Context::checksum) + .def("pack", &Context::pack) + .def("place", &Context::place) + .def("route", &Context::route); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelType"); diff --git a/ice40/main.cc b/ice40/main.cc index 53cd7164..e77bdd34 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -39,7 +39,6 @@ #include "jsonparse.h" #include "log.h" #include "nextpnr.h" -#include "pack.h" #include "pcf.h" #include "place_legaliser.h" #include "timing.h" @@ -382,7 +381,7 @@ int main(int argc, char *argv[]) log_error("Loading PCF failed.\n"); } - if (!pack_design(ctx.get()) && !ctx->force) + if (!ctx->pack() && !ctx->force) log_error("Packing design failed.\n"); assign_budget(ctx.get()); ctx->check(); diff --git a/ice40/pack.cc b/ice40/pack.cc index d1be4a29..76a52be0 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -18,7 +18,6 @@ * */ -#include "pack.h" #include #include #include @@ -577,8 +576,9 @@ static void pack_special(Context *ctx) } // Main pack function -bool pack_design(Context *ctx) +bool Arch::pack() { + Context *ctx = getCtx(); try { log_break(); pack_constants(ctx); diff --git a/ice40/pack.h b/ice40/pack.h deleted file mode 100644 index cdebdd79..00000000 --- a/ice40/pack.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2018 Clifford Wolf - * Copyright (C) 2018 David Shah - * - * 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. - * - */ - -#ifndef PACK_H -#define PACK_H - -#include "nextpnr.h" - -NEXTPNR_NAMESPACE_BEGIN - -bool pack_design(Context *ctx); - -NEXTPNR_NAMESPACE_END - -#endif // ROUTE_H -- cgit v1.2.3 From cbfb0302648771851ab386b6843fb0a60d018dad Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 13 Jul 2018 15:40:43 +0200 Subject: remove maximum size restriction for tree/property --- gui/basewindow.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 6bc56c7b..fd9d36f4 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -66,7 +66,6 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent DesignWidget *designview = new DesignWidget(); designview->setMinimumWidth(300); - designview->setMaximumWidth(300); splitter_h->addWidget(designview); connect(this, SIGNAL(contextChanged(Context *)), designview, SLOT(newContext(Context *))); -- cgit v1.2.3 From 44663fa5898ad84ac1e04c597b5037aa41697b94 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 13 Jul 2018 15:44:39 +0200 Subject: Fix ice40 gfx wire indices Signed-off-by: Clifford Wolf --- ice40/chipdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ice40/chipdb.py b/ice40/chipdb.py index f52a2283..51fe169c 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -77,7 +77,7 @@ with open(args.gfxh) as f: state = 1 elif state == 1 and line.startswith("};"): state = 0 - elif state == 1 and line.startswith("{"): + elif state == 1 and (line.startswith("{") or line.strip() == ""): pass elif state == 1: idx = len(gfx_wire_ids) -- cgit v1.2.3 From 9e4f97290a50fc5d9dc0cbe6ead945840b9811b1 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 13 Jul 2018 14:50:58 +0100 Subject: Make PnR use Unlocked methods --- common/place_common.cc | 14 +++--- common/placer1.cc | 38 +++++++-------- common/router1.cc | 36 +++++++-------- ice40/arch.cc | 26 +++++++++-- ice40/arch.h | 117 ++++++++++++++++++++++++++++++++++++++--------- ice40/arch_place.cc | 6 +-- ice40/place_legaliser.cc | 14 +++--- 7 files changed, 173 insertions(+), 78 deletions(-) diff --git a/common/place_common.cc b/common/place_common.cc index 60735890..281e40a2 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -36,7 +36,7 @@ wirelen_t get_net_wirelength(const Context *ctx, const NetInfo *net, float &tns) if (driver_cell->bel == BelId()) return 0; ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb); - WireId drv_wire = ctx->getWireBelPin(driver_cell->bel, ctx->portPinFromId(net->driver.port)); + WireId drv_wire = ctx->getWireBelPinUnlocked(driver_cell->bel, ctx->portPinFromId(net->driver.port)); if (driver_gb) return 0; float worst_slack = 1000; @@ -48,7 +48,7 @@ wirelen_t get_net_wirelength(const Context *ctx, const NetInfo *net, float &tns) if (load_cell->bel == BelId()) continue; if (ctx->timing_driven) { - WireId user_wire = ctx->getWireBelPin(load_cell->bel, ctx->portPinFromId(load.port)); + WireId user_wire = ctx->getWireBelPinUnlocked(load_cell->bel, ctx->portPinFromId(load.port)); delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); float slack = ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl); if (slack < 0) @@ -112,12 +112,12 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality) CellInfo *ripup_target = nullptr; BelId ripup_bel = BelId(); if (cell->bel != BelId()) { - ctx->unbindBel(cell->bel); + ctx->unbindBelUnlocked(cell->bel); } BelType targetType = ctx->belTypeFromId(cell->type); for (auto bel : ctx->getBels()) { if (ctx->getBelType(bel) == targetType && (!require_legality || ctx->isValidBelForCell(cell, bel))) { - if (ctx->checkBelAvail(bel)) { + if (ctx->checkBelAvailUnlocked(bel)) { wirelen_t wirelen = get_cell_wirelength_at_bel(ctx, cell, bel); if (iters >= 4) wirelen += ctx->rng(25); @@ -130,7 +130,7 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality) if (iters >= 4) wirelen += ctx->rng(25); if (wirelen <= best_ripup_wirelen) { - ripup_target = ctx->cells.at(ctx->getBoundBelCell(bel)).get(); + ripup_target = ctx->cells.at(ctx->getBoundBelCellUnlocked(bel)).get(); if (ripup_target->belStrength < STRENGTH_STRONG) { best_ripup_wirelen = wirelen; ripup_bel = bel; @@ -148,12 +148,12 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality) log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx)); } --iters; - ctx->unbindBel(ripup_target->bel); + ctx->unbindBelUnlocked(ripup_target->bel); best_bel = ripup_bel; } else { all_placed = true; } - ctx->bindBel(best_bel, cell->name, STRENGTH_WEAK); + ctx->bindBelUnlocked(best_bel, cell->name, STRENGTH_WEAK); cell = ripup_target; } diff --git a/common/placer1.cc b/common/placer1.cc index 53295a91..05f760a3 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -85,7 +85,7 @@ class SAPlacer auto loc = cell->attrs.find(ctx->id("BEL")); if (loc != cell->attrs.end()) { std::string loc_name = loc->second; - BelId bel = ctx->getBelByName(ctx->id(loc_name)); + BelId bel = ctx->getBelByNameUnlocked(ctx->id(loc_name)); if (bel == BelId()) { log_error("No Bel named \'%s\' located for " "this chip (processing BEL attribute on \'%s\')\n", @@ -100,7 +100,7 @@ class SAPlacer cell->type.c_str(ctx)); } - ctx->bindBel(bel, cell->name, STRENGTH_USER); + ctx->bindBelUnlocked(bel, cell->name, STRENGTH_USER); locked_bels.insert(bel); placed_cells++; } @@ -235,7 +235,7 @@ class SAPlacer } // Final post-pacement validitiy check for (auto bel : ctx->getBels()) { - IdString cell = ctx->getBoundBelCell(bel); + IdString cell = ctx->getBoundBelCellUnlocked(bel); if (!ctx->isBelLocationValid(bel)) { std::string cell_text = "no cell"; if (cell != IdString()) @@ -267,12 +267,12 @@ class SAPlacer CellInfo *ripup_target = nullptr; BelId ripup_bel = BelId(); if (cell->bel != BelId()) { - ctx->unbindBel(cell->bel); + ctx->unbindBelUnlocked(cell->bel); } BelType targetType = ctx->belTypeFromId(cell->type); for (auto bel : ctx->getBels()) { if (ctx->getBelType(bel) == targetType && (ctx->isValidBelForCell(cell, bel) || !require_legal)) { - if (ctx->checkBelAvail(bel)) { + if (ctx->checkBelAvailUnlocked(bel)) { uint64_t score = ctx->rng64(); if (score <= best_score) { best_score = score; @@ -282,7 +282,7 @@ class SAPlacer uint64_t score = ctx->rng64(); if (score <= best_ripup_score) { best_ripup_score = score; - ripup_target = ctx->cells.at(ctx->getBoundBelCell(bel)).get(); + ripup_target = ctx->cells.at(ctx->getBoundBelCellUnlocked(bel)).get(); ripup_bel = bel; } } @@ -292,12 +292,12 @@ class SAPlacer if (iters == 0 || ripup_bel == BelId()) log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx)); --iters; - ctx->unbindBel(ripup_target->bel); + ctx->unbindBelUnlocked(ripup_target->bel); best_bel = ripup_bel; } else { all_placed = true; } - ctx->bindBel(best_bel, cell->name, STRENGTH_WEAK); + ctx->bindBelUnlocked(best_bel, cell->name, STRENGTH_WEAK); // Back annotate location cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx); @@ -313,7 +313,7 @@ class SAPlacer new_lengths.clear(); update.clear(); BelId oldBel = cell->bel; - IdString other = ctx->getBoundBelCell(newBel); + IdString other = ctx->getBoundBelCellUnlocked(newBel); CellInfo *other_cell = nullptr; if (other != IdString()) { other_cell = ctx->cells[other].get(); @@ -321,9 +321,9 @@ class SAPlacer return false; } wirelen_t new_wirelength = 0, delta; - ctx->unbindBel(oldBel); + ctx->unbindBelUnlocked(oldBel); if (other != IdString()) { - ctx->unbindBel(newBel); + ctx->unbindBelUnlocked(newBel); } for (const auto &port : cell->ports) @@ -336,16 +336,16 @@ class SAPlacer update.insert(port.second.net); } - ctx->bindBel(newBel, cell->name, STRENGTH_WEAK); + ctx->bindBelUnlocked(newBel, cell->name, STRENGTH_WEAK); if (other != IdString()) { - ctx->bindBel(oldBel, other_cell->name, STRENGTH_WEAK); + ctx->bindBelUnlocked(oldBel, other_cell->name, STRENGTH_WEAK); } if (require_legal) { if (!ctx->isBelLocationValid(newBel) || ((other != IdString() && !ctx->isBelLocationValid(oldBel)))) { - ctx->unbindBel(newBel); + ctx->unbindBelUnlocked(newBel); if (other != IdString()) - ctx->unbindBel(oldBel); + ctx->unbindBelUnlocked(oldBel); goto swap_fail; } } @@ -369,8 +369,8 @@ class SAPlacer improved = true; } else { if (other != IdString()) - ctx->unbindBel(oldBel); - ctx->unbindBel(newBel); + ctx->unbindBelUnlocked(oldBel); + ctx->unbindBelUnlocked(newBel); goto swap_fail; } curr_wirelength = new_wirelength; @@ -379,9 +379,9 @@ class SAPlacer return true; swap_fail: - ctx->bindBel(oldBel, cell->name, STRENGTH_WEAK); + ctx->bindBelUnlocked(oldBel, cell->name, STRENGTH_WEAK); if (other != IdString()) { - ctx->bindBel(newBel, other, STRENGTH_WEAK); + ctx->bindBelUnlocked(newBel, other, STRENGTH_WEAK); } return false; } diff --git a/common/router1.cc b/common/router1.cc index 94c7070e..cbaf773d 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -90,10 +90,10 @@ void ripup_net(Context *ctx, IdString net_name) } for (auto pip : pips) - ctx->unbindPip(pip); + ctx->unbindPipUnlocked(pip); for (auto wire : wires) - ctx->unbindWire(wire); + ctx->unbindWireUnlocked(wire); NPNR_ASSERT(net_info->wires.empty()); } @@ -148,10 +148,10 @@ struct Router bool foundRipupNet = false; thisVisitCnt++; - if (!ctx->checkWireAvail(next_wire)) { + if (!ctx->checkWireAvailUnlocked(next_wire)) { if (!ripup) continue; - IdString ripupWireNet = ctx->getConflictingWireNet(next_wire); + IdString ripupWireNet = ctx->getConflictingWireNetUnlocked(next_wire); if (ripupWireNet == net_name || ripupWireNet == IdString()) continue; @@ -166,10 +166,10 @@ struct Router foundRipupNet = true; } - if (!ctx->checkPipAvail(pip)) { + if (!ctx->checkPipAvailUnlocked(pip)) { if (!ripup) continue; - IdString ripupPipNet = ctx->getConflictingPipNet(pip); + IdString ripupPipNet = ctx->getConflictingPipNetUnlocked(pip); if (ripupPipNet == net_name || ripupPipNet == IdString()) continue; @@ -272,7 +272,7 @@ struct Router if (driver_port_it != net_info->driver.cell->pins.end()) driver_port = driver_port_it->second; - auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getWireBelPinUnlocked(src_bel, ctx->portPinFromId(driver_port)); if (src_wire == WireId()) log_error("No wire found for port %s (pin %s) on source cell %s " @@ -287,7 +287,7 @@ struct Router src_wires[src_wire] = 0; ripup_net(ctx, net_name); - ctx->bindWire(src_wire, net_name, STRENGTH_WEAK); + ctx->bindWireUnlocked(src_wire, net_name, STRENGTH_WEAK); std::vector users_array = net_info->users; ctx->shuffle(users_array); @@ -312,7 +312,7 @@ struct Router if (user_port_it != user_it.cell->pins.end()) user_port = user_port_it->second; - auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getWireBelPinUnlocked(dst_bel, ctx->portPinFromId(user_port)); if (dst_wire == WireId()) log_error("No wire found for port %s (pin %s) on destination " @@ -355,14 +355,14 @@ struct Router if (src_wires.count(cursor)) break; - IdString conflicting_wire_net = ctx->getConflictingWireNet(cursor); + IdString conflicting_wire_net = ctx->getConflictingWireNetUnlocked(cursor); if (conflicting_wire_net != IdString()) { NPNR_ASSERT(ripup); NPNR_ASSERT(conflicting_wire_net != net_name); - ctx->unbindWire(cursor); - if (!ctx->checkWireAvail(cursor)) + ctx->unbindWireUnlocked(cursor); + if (!ctx->checkWireAvailUnlocked(cursor)) ripup_net(ctx, conflicting_wire_net); rippedNets.insert(conflicting_wire_net); @@ -372,14 +372,14 @@ struct Router } PipId pip = visited[cursor].pip; - IdString conflicting_pip_net = ctx->getConflictingPipNet(pip); + IdString conflicting_pip_net = ctx->getConflictingPipNetUnlocked(pip); if (conflicting_pip_net != IdString()) { NPNR_ASSERT(ripup); NPNR_ASSERT(conflicting_pip_net != net_name); - ctx->unbindPip(pip); - if (!ctx->checkPipAvail(pip)) + ctx->unbindPipUnlocked(pip); + if (!ctx->checkPipAvailUnlocked(pip)) ripup_net(ctx, conflicting_pip_net); rippedNets.insert(conflicting_pip_net); @@ -388,7 +388,7 @@ struct Router scores.netPipScores[std::make_pair(conflicting_pip_net, visited[cursor].pip)]++; } - ctx->bindPip(visited[cursor].pip, net_name, STRENGTH_WEAK); + ctx->bindPipUnlocked(visited[cursor].pip, net_name, STRENGTH_WEAK); src_wires[cursor] = visited[cursor].delay; cursor = ctx->getPipSrcWire(visited[cursor].pip); } @@ -451,7 +451,7 @@ bool router1(Context *ctx) if (driver_port_it != net_info->driver.cell->pins.end()) driver_port = driver_port_it->second; - auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getWireBelPinUnlocked(src_bel, ctx->portPinFromId(driver_port)); if (src_wire == WireId()) continue; @@ -469,7 +469,7 @@ bool router1(Context *ctx) if (user_port_it != user_it.cell->pins.end()) user_port = user_port_it->second; - auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getWireBelPinUnlocked(dst_bel, ctx->portPinFromId(user_port)); if (dst_wire == WireId()) continue; diff --git a/ice40/arch.cc b/ice40/arch.cc index 88a900d8..6c00f0d2 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -242,6 +242,11 @@ IdString Arch::archArgsToId(ArchArgs args) const BelId Arch::getBelByName(IdString name) const { boost::lock_guard lock(mtx_); + return getBelByNameUnlocked(name); +} + +BelId Arch::getBelByNameUnlocked(IdString name) const +{ BelId ret; if (bel_by_name.empty()) { @@ -276,8 +281,13 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const WireId Arch::getWireBelPin(BelId bel, PortPin pin) const { - WireId ret; boost::shared_lock_guard lock(mtx_); + return getWireBelPinUnlocked(bel, pin); +} + +WireId Arch::getWireBelPinUnlocked(BelId bel, PortPin pin) const +{ + WireId ret; NPNR_ASSERT(bel != BelId()); @@ -297,8 +307,13 @@ WireId Arch::getWireBelPin(BelId bel, PortPin pin) const WireId Arch::getWireByName(IdString name) const { - WireId ret; boost::shared_lock_guard lock(mtx_); + return getWireByNameUnlocked(name); +} + +WireId Arch::getWireByNameUnlocked(IdString name) const +{ + WireId ret; if (wire_by_name.empty()) { for (int i = 0; i < chip_info->num_wires; i++) @@ -316,8 +331,13 @@ WireId Arch::getWireByName(IdString name) const PipId Arch::getPipByName(IdString name) const { - PipId ret; boost::shared_lock_guard lock(mtx_); + return getPipByNameUnlocked(name); +} + +PipId Arch::getPipByNameUnlocked(IdString name) const +{ + PipId ret; if (pip_by_name.empty()) { for (int i = 0; i < chip_info->num_pips; i++) { diff --git a/ice40/arch.h b/ice40/arch.h index 410df48b..ab66e7d8 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -362,6 +362,7 @@ public: // ------------------------------------------------- BelId getBelByName(IdString name) const; + BelId getBelByNameUnlocked(IdString name) const; IdString getBelName(BelId bel) const { @@ -371,21 +372,30 @@ public: uint32_t getBelChecksum(BelId bel) const { return bel.index; } - void bindBel(BelId bel, IdString cell, PlaceStrength strength) + void bindBel(BelId bel, IdString cell, PlaceStrength strength) { + boost::lock_guard lock(mtx_); + bindBelUnlocked(bel, cell, strength); + } + + void bindBelUnlocked(BelId bel, IdString cell, PlaceStrength strength) { NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); - boost::lock_guard lock(mtx_); bel_to_cell[bel.index] = cell; cells[cell]->bel = bel; cells[cell]->belStrength = strength; } void unbindBel(BelId bel) + { + boost::lock_guard lock(mtx_); + unbindBelUnlocked(bel); + } + + void unbindBelUnlocked(BelId bel) { NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); - boost::lock_guard lock(mtx_); cells[bel_to_cell[bel.index]]->bel = BelId(); cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; bel_to_cell[bel.index] = IdString(); @@ -393,22 +403,37 @@ public: bool checkBelAvail(BelId bel) const { - NPNR_ASSERT(bel != BelId()); boost::shared_lock_guard lock(mtx_); + return checkBelAvailUnlocked(bel); + } + + bool checkBelAvailUnlocked(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); return bel_to_cell[bel.index] == IdString(); } IdString getBoundBelCell(BelId bel) const { - NPNR_ASSERT(bel != BelId()); boost::shared_lock_guard lock(mtx_); + return getBoundBelCellUnlocked(bel); + } + + IdString getBoundBelCellUnlocked(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); return bel_to_cell[bel.index]; } IdString getConflictingBelCell(BelId bel) const { - NPNR_ASSERT(bel != BelId()); boost::shared_lock_guard lock(mtx_); + return getConflictingBelCellUnlocked(bel); + } + + IdString getConflictingBelCellUnlocked(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); return bel_to_cell[bel.index]; } @@ -425,11 +450,11 @@ public: BelRange range; // FIXME #if 0 - if (type == "TYPE_A") { - range.b.cursor = bels_type_a_begin; - range.e.cursor = bels_type_a_end; - } - ... + if (type == "TYPE_A") { + range.b.cursor = bels_type_a_begin; + range.e.cursor = bels_type_a_end; + } + ... #endif return range; } @@ -443,6 +468,7 @@ public: } WireId getWireBelPin(BelId bel, PortPin pin) const; + WireId getWireBelPinUnlocked(BelId bel, PortPin pin) const; BelPin getBelPinUphill(WireId wire) const { @@ -469,6 +495,7 @@ public: // ------------------------------------------------- WireId getWireByName(IdString name) const; + WireId getWireByNameUnlocked(IdString name) const; IdString getWireName(WireId wire) const { @@ -479,10 +506,15 @@ public: uint32_t getWireChecksum(WireId wire) const { return wire.index; } void bindWire(WireId wire, IdString net, PlaceStrength strength) + { + boost::lock_guard lock(mtx_); + bindWireUnlocked(wire, net, strength); + } + + void bindWireUnlocked(WireId wire, IdString net, PlaceStrength strength) { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire.index] == IdString()); - boost::lock_guard lock(mtx_); wire_to_net[wire.index] = net; nets[net]->wires[wire].pip = PipId(); @@ -490,10 +522,15 @@ public: } void unbindWire(WireId wire) + { + boost::lock_guard lock(mtx_); + unbindWireUnlocked(wire); + } + + void unbindWireUnlocked(WireId wire) { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire.index] != IdString()); - boost::lock_guard lock(mtx_); auto &net_wires = nets[wire_to_net[wire.index]]->wires; auto it = net_wires.find(wire); @@ -511,25 +548,37 @@ public: bool checkWireAvail(WireId wire) const { - NPNR_ASSERT(wire != WireId()); boost::shared_lock_guard lock(mtx_); + return checkWireAvailUnlocked(wire); + } + bool checkWireAvailUnlocked(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index] == IdString(); } IdString getBoundWireNet(WireId wire) const { - NPNR_ASSERT(wire != WireId()); boost::shared_lock_guard lock(mtx_); + return getBoundWireNetUnlocked(wire); + } + IdString getBoundWireNetUnlocked(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index]; } IdString getConflictingWireNet(WireId wire) const { - NPNR_ASSERT(wire != WireId()); boost::shared_lock_guard lock(mtx_); + return getConflictingWireNetUnlocked(wire); + } + IdString getConflictingWireNetUnlocked(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index]; } @@ -544,16 +593,22 @@ public: // ------------------------------------------------- PipId getPipByName(IdString name) const; + PipId getPipByNameUnlocked(IdString name) const; IdString getPipName(PipId pip) const; uint32_t getPipChecksum(PipId pip) const { return pip.index; } void bindPip(PipId pip, IdString net, PlaceStrength strength) + { + boost::lock_guard lock(mtx_); + bindPipUnlocked(pip, net, strength); + } + + void bindPipUnlocked(PipId pip, IdString net, PlaceStrength strength) { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] == IdString()); NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); - boost::lock_guard lock(mtx_); pip_to_net[pip.index] = net; switches_locked[chip_info->pip_data[pip.index].switch_index] = net; @@ -567,11 +622,16 @@ public: } void unbindPip(PipId pip) + { + boost::lock_guard lock(mtx_); + unbindPipUnlocked(pip); + } + + void unbindPipUnlocked(PipId pip) { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] != IdString()); NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); - boost::lock_guard lock(mtx_); WireId dst; dst.index = chip_info->pip_data[pip.index].dst; @@ -585,22 +645,37 @@ public: bool checkPipAvail(PipId pip) const { - NPNR_ASSERT(pip != PipId()); boost::shared_lock_guard lock(mtx_); + return checkPipAvailUnlocked(pip); + } + + bool checkPipAvailUnlocked(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); } IdString getBoundPipNet(PipId pip) const { - NPNR_ASSERT(pip != PipId()); boost::shared_lock_guard lock(mtx_); + return getBoundPipNetUnlocked(pip); + } + + IdString getBoundPipNetUnlocked(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); return pip_to_net[pip.index]; } IdString getConflictingPipNet(PipId pip) const { - NPNR_ASSERT(pip != PipId()); boost::shared_lock_guard lock(mtx_); + return getConflictingPipNetUnlocked(pip); + } + + IdString getConflictingPipNetUnlocked(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); return switches_locked[chip_info->pip_data[pip.index].switch_index]; } diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index dc1bc3eb..c9dd26c5 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -80,7 +80,7 @@ bool Arch::isBelLocationValid(BelId bel) const if (getBelType(bel) == TYPE_ICESTORM_LC) { std::vector bel_cells; for (auto bel_other : getBelsAtSameTile(bel)) { - IdString cell_other = getBoundBelCell(bel_other); + IdString cell_other = getBoundBelCellUnlocked(bel_other); if (cell_other != IdString()) { const CellInfo *ci_other = cells.at(cell_other).get(); bel_cells.push_back(ci_other); @@ -88,7 +88,7 @@ bool Arch::isBelLocationValid(BelId bel) const } return logicCellsCompatible(bel_cells); } else { - IdString cellId = getBoundBelCell(bel); + IdString cellId = getBoundBelCellUnlocked(bel); if (cellId == IdString()) return true; else @@ -104,7 +104,7 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const std::vector bel_cells; for (auto bel_other : getBelsAtSameTile(bel)) { - IdString cell_other = getBoundBelCell(bel_other); + IdString cell_other = getBoundBelCellUnlocked(bel_other); if (cell_other != IdString() && bel_other != bel) { const CellInfo *ci_other = cells.at(cell_other).get(); bel_cells.push_back(ci_other); diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index 559358c7..d42188f0 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -143,7 +143,7 @@ class PlacementLegaliser // Using the non-standard API here to get (x, y, z) rather than just (x, y) auto bi = ctx->chip_info->bel_data[bel.index]; int x = bi.x, y = bi.y, z = bi.z; - IdString cell = ctx->getBoundBelCell(bel); + IdString cell = ctx->getBoundBelCellUnlocked(bel); if (cell != IdString() && ctx->cells.at(cell)->belStrength >= STRENGTH_FIXED) logic_bels.at(x).at(y).at(z) = std::make_pair(bel, true); // locked out of use else @@ -331,16 +331,16 @@ class PlacementLegaliser NPNR_ASSERT(!loc.second); BelId bel = loc.first; // Check if there is a cell presently at the location, which we will need to rip up - IdString existing = ctx->getBoundBelCell(bel); + IdString existing = ctx->getBoundBelCellUnlocked(bel); if (existing != IdString()) { // TODO: keep track of the previous position of the ripped up cell, as a hint rippedCells.insert(existing); - ctx->unbindBel(bel); + ctx->unbindBelUnlocked(bel); } if (cell->bel != BelId()) { - ctx->unbindBel(cell->bel); + ctx->unbindBelUnlocked(cell->bel); } - ctx->bindBel(bel, cell->name, STRENGTH_LOCKED); + ctx->bindBelUnlocked(bel, cell->name, STRENGTH_LOCKED); rippedCells.erase(cell->name); // If cell was ripped up previously, no need to re-place loc.second = true; // Bel is now unavailable for further use } @@ -435,7 +435,7 @@ class PlacementLegaliser CellInfo *target = nullptr; for (int z = 0; z < 8; z++) { BelId bel = logic_bels.at(x).at(y).at(z).first; - IdString cell = ctx->getBoundBelCell(bel); + IdString cell = ctx->getBoundBelCellUnlocked(bel); if (cell != IdString()) { CellInfo *ci = ctx->cells.at(cell).get(); if (ci->belStrength >= STRENGTH_STRONG) @@ -448,7 +448,7 @@ class PlacementLegaliser } } if (target != nullptr) { - ctx->unbindBel(target->bel); + ctx->unbindBelUnlocked(target->bel); rippedCells.insert(target->name); changed = true; } -- cgit v1.2.3 From 0f736f551c30b7689b72b10d1a21ceca58657f23 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 13 Jul 2018 16:15:15 +0200 Subject: Fix iCE40 wire gfx decals Signed-off-by: Clifford Wolf --- ice40/gfx.cc | 103 ++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 25 deletions(-) diff --git a/ice40/gfx.cc b/ice40/gfx.cc index f4941750..19aaed13 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -31,17 +31,31 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, if (id >= TILE_WIRE_SP4_H_L_36 && id <= TILE_WIRE_SP4_H_L_47) { int idx = (id - TILE_WIRE_SP4_H_L_36) + 48; - float y1 = y + 1.0 - (0.03 + 0.0025 * (60 - idx)); - el.x1 = x + 0.0; - el.x2 = x + 0.9; + float y1 = y + 1.0 - (0.03 + 0.0025 * (60 - (idx ^ 1))); + float y2 = y + 1.0 - (0.03 + 0.0025 * (60 - idx)); + + el.x1 = x; + el.x2 = x + 0.01; el.y1 = y1; el.y2 = y1; g.push_back(el); + el.x1 = x + 0.01; + el.x2 = x + 0.02; + el.y1 = y1; + el.y2 = y2; + g.push_back(el); + + el.x1 = x + 0.02; + el.x2 = x + 0.9; + el.y1 = y2; + el.y2 = y2; + g.push_back(el); + el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 35); el.x2 = el.x1; - el.y1 = y1; + el.y1 = y2; el.y2 = y + main_swbox_y2; g.push_back(el); } @@ -91,17 +105,30 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, if (id >= TILE_WIRE_SP4_V_T_36 && id <= TILE_WIRE_SP4_V_T_47) { int idx = (id - TILE_WIRE_SP4_V_T_36) + 48; - float x1 = x + 0.03 + 0.0025 * (60 - idx); + float x1 = x + 0.03 + 0.0025 * (60 - (idx ^ 1)); + float x2 = x + 0.03 + 0.0025 * (60 - idx); - el.y1 = y + 1.0; - el.y2 = y + 0.1; + el.y1 = y + 1.00; + el.y2 = y + 0.99; el.x1 = x1; el.x2 = x1; g.push_back(el); + el.y1 = y + 0.99; + el.y2 = y + 0.98; + el.x1 = x1; + el.x2 = x2; + g.push_back(el); + + el.y1 = y + 0.98; + el.y2 = y + 0.10; + el.x1 = x2; + el.x2 = x2; + g.push_back(el); + el.y1 = y + 1.0 - (0.03 + 0.0025 * (270 - idx)); el.y2 = el.y1; - el.x1 = x1; + el.x1 = x2; el.x2 = x + main_swbox_x1; g.push_back(el); } @@ -109,9 +136,9 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, if (id >= TILE_WIRE_SP4_V_B_0 && id <= TILE_WIRE_SP4_V_B_47) { int idx = id - TILE_WIRE_SP4_V_B_0; - float x1 = x + 0.03 + 0.0025 * (60 - (idx ^ 1)); - float x2 = x + 0.03 + 0.0025 * (60 - idx); - float x3 = x + 0.03 + 0.0025 * (60 - idx - 12); + float x1 = x + 0.03 + 0.0025 * (60 - idx); + float x2 = x + 0.03 + 0.0025 * (60 - (idx ^ 1)); + float x3 = x + 0.03 + 0.0025 * (60 - (idx ^ 1) - 12); if (idx >= 12) { el.y1 = y + 1.00; @@ -139,13 +166,13 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, el.x2 = x3; g.push_back(el); - el.y1 = y + 1.0 - (0.03 + 0.0025 * (145 - idx)); + el.y1 = y + 1.0 - (0.03 + 0.0025 * (145 - (idx ^ 1))); el.y2 = el.y1; el.x1 = x; el.x2 = x2; g.push_back(el); - el.y1 = y + 1.0 - (0.03 + 0.0025 * (270 - idx)); + el.y1 = y + 1.0 - (0.03 + 0.0025 * (270 - (idx ^ 1))); el.y2 = el.y1; el.x1 = x2; el.x2 = x + main_swbox_x1; @@ -157,17 +184,30 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, if (id >= TILE_WIRE_SP12_H_L_22 && id <= TILE_WIRE_SP12_H_L_23) { int idx = (id - TILE_WIRE_SP12_H_L_22) + 24; - float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - idx)); + float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - (idx ^ 1))); + float y2 = y + 1.0 - (0.03 + 0.0025 * (90 - idx)); - el.x1 = x + 0.0; - el.x2 = x + 0.98333; + el.x1 = x; + el.x2 = x + 0.01; el.y1 = y1; el.y2 = y1; g.push_back(el); + el.x1 = x + 0.01; + el.x2 = x + 0.02; + el.y1 = y1; + el.y2 = y2; + g.push_back(el); + + el.x1 = x + 0.02; + el.x2 = x + 0.98333; + el.y1 = y2; + el.y2 = y2; + g.push_back(el); + el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 5); el.x2 = el.x1; - el.y1 = y1; + el.y1 = y2; el.y2 = y + main_swbox_y2; g.push_back(el); } @@ -175,9 +215,9 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, if (id >= TILE_WIRE_SP12_H_R_0 && id <= TILE_WIRE_SP12_H_R_23) { int idx = id - TILE_WIRE_SP12_H_R_0; - float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - (idx ^ 1))); - float y2 = y + 1.0 - (0.03 + 0.0025 * (90 - idx)); - float y3 = y + 1.0 - (0.03 + 0.0025 * (90 - idx - 2)); + float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - idx)); + float y2 = y + 1.0 - (0.03 + 0.0025 * (90 - (idx ^ 1))); + float y3 = y + 1.0 - (0.03 + 0.0025 * (90 - (idx ^ 1) - 2)); if (idx >= 2) { el.x1 = x; @@ -205,7 +245,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, el.y2 = y3; g.push_back(el); - el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 5); + el.x1 = x + main_swbox_x1 + 0.0025 * ((idx ^ 1) + 5); el.x2 = el.x1; el.y1 = y2; el.y2 = y + main_swbox_y2; @@ -217,7 +257,7 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, if (id >= TILE_WIRE_SP4_R_V_B_0 && id <= TILE_WIRE_SP4_R_V_B_47) { int idx = id - TILE_WIRE_SP4_R_V_B_0; - float y1 = y + 1.0 - (0.03 + 0.0025 * (145 - idx)); + float y1 = y + 1.0 - (0.03 + 0.0025 * (145 - (idx ^ 1))); el.y1 = y1; el.y2 = y1; @@ -231,17 +271,30 @@ void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, if (id >= TILE_WIRE_SP12_V_T_22 && id <= TILE_WIRE_SP12_V_T_23) { int idx = (id - TILE_WIRE_SP12_V_T_22) + 24; - float x1 = x + 0.03 + 0.0025 * (90 - idx); + float x1 = x + 0.03 + 0.0025 * (90 - (idx ^ 1)); + float x2 = x + 0.03 + 0.0025 * (90 - idx); el.y1 = y + 1.00; - el.y2 = y + 0.01667; + el.y2 = y + 0.99; el.x1 = x1; el.x2 = x1; g.push_back(el); + el.y1 = y + 0.99; + el.y2 = y + 0.98; + el.x1 = x1; + el.x2 = x2; + g.push_back(el); + + el.y1 = y + 0.98; + el.y2 = y + 0.01667; + el.x1 = x2; + el.x2 = x2; + g.push_back(el); + el.y1 = y + 1.0 - (0.03 + 0.0025 * (300 - idx)); el.y2 = el.y1; - el.x1 = x1; + el.x1 = x2; el.x2 = x + main_swbox_x1; g.push_back(el); } -- cgit v1.2.3 From 013cfebcc5ccdf0fda9cedddd94e5b70ec20a029 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 13 Jul 2018 16:22:28 +0200 Subject: Improve handling of iCE40 BRAM bels Signed-off-by: Clifford Wolf --- ice40/arch.cc | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 9b058aa0..adc37dbd 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -603,14 +603,42 @@ std::vector Arch::getDecalGraphics(DecalId decal) const } if (bel_type == TYPE_ICESTORM_RAM) { - GraphicElement el; - el.type = GraphicElement::G_BOX; - el.x1 = chip_info->bel_data[bel.index].x + 0.1; - el.x2 = chip_info->bel_data[bel.index].x + 0.9; - el.y1 = chip_info->bel_data[bel.index].y + 0.1; - el.y2 = chip_info->bel_data[bel.index].y + 1.9; - el.z = 0; - ret.push_back(el); + for (int i = 0; i < 2; i++) + { + int tx = chip_info->bel_data[bel.index].x; + int ty = chip_info->bel_data[bel.index].y + i; + + GraphicElement el; + el.type = GraphicElement::G_BOX; + el.style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE; + el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; + el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; + el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1; + el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + 7*logic_cell_pitch; + el.z = 0; + ret.push_back(el); + + // Main switchbox + GraphicElement main_sw; + main_sw.type = GraphicElement::G_BOX; + main_sw.style = GraphicElement::G_FRAME; + main_sw.x1 = tx + main_swbox_x1; + main_sw.x2 = tx + main_swbox_x2; + main_sw.y1 = ty + main_swbox_y1; + main_sw.y2 = ty + main_swbox_y2; + ret.push_back(main_sw); + + // Local tracks to LUT input switchbox + GraphicElement local_sw; + local_sw.type = GraphicElement::G_BOX; + local_sw.style = GraphicElement::G_FRAME; + local_sw.x1 = tx + local_swbox_x1; + local_sw.x2 = tx + local_swbox_x2; + local_sw.y1 = ty + local_swbox_y1; + local_sw.y2 = ty + local_swbox_y2; + local_sw.z = 0; + ret.push_back(local_sw); + } } } -- cgit v1.2.3 From 07ff5ad8b8e4d0f87770b81b8478aa257567c504 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 13 Jul 2018 19:56:11 +0200 Subject: Made python console use edit line and better --- 3rdparty/python-console/modified/pyconsole.cc | 322 -------------------------- 3rdparty/python-console/modified/pyconsole.h | 80 ------- gui/CMakeLists.txt | 1 - gui/basewindow.cc | 2 +- gui/line_editor.cc | 56 ++++- gui/line_editor.h | 11 +- gui/pyconsole.cc | 82 +++++++ gui/pyconsole.h | 58 +++++ gui/pythontab.cc | 41 +++- gui/pythontab.h | 8 + 10 files changed, 249 insertions(+), 412 deletions(-) delete mode 100644 3rdparty/python-console/modified/pyconsole.cc delete mode 100644 3rdparty/python-console/modified/pyconsole.h create mode 100644 gui/pyconsole.cc create mode 100644 gui/pyconsole.h diff --git a/3rdparty/python-console/modified/pyconsole.cc b/3rdparty/python-console/modified/pyconsole.cc deleted file mode 100644 index d724553b..00000000 --- a/3rdparty/python-console/modified/pyconsole.cc +++ /dev/null @@ -1,322 +0,0 @@ -#include "pyconsole.h" -#include "pyinterpreter.h" -#include "ColumnFormatter.h" - -#include -#include -#include - -#include "Utils.h" - -const QString PythonConsole::PROMPT = ">>> "; -const QString PythonConsole::MULTILINE_PROMPT = "... "; -const QColor PythonConsole::NORMAL_COLOR = QColor::fromRgbF( 0, 0, 0 ); -const QColor PythonConsole::ERROR_COLOR = QColor::fromRgbF( 1.0, 0, 0 ); -const QColor PythonConsole::OUTPUT_COLOR = QColor::fromRgbF( 0, 0, 1.0 ); - -PythonConsole::PythonConsole( QWidget* parent ): - QTextEdit( parent ) -{ - QFont font("unexistent"); - font.setStyleHint(QFont::Monospace); - setFont(font); - m_parseHelper.subscribe( this ); -} - -void PythonConsole::keyPressEvent( QKeyEvent* e ) -{ - switch ( e->key() ) - { - case Qt::Key_Return: - handleReturnKeyPress( ); - return; - - case Qt::Key_Tab: - autocomplete( ); - return; - - case Qt::Key_Backspace: - if ( ! canBackspace( ) ) - return; - break; - - case Qt::Key_Up: - previousHistory( ); - return; - - case Qt::Key_Down: - nextHistory( ); - return; - - case Qt::Key_Left: - if ( ! canGoLeft( ) ) - return; - } - if (!cursorIsOnInputLine()) return; - if (textCursor().columnNumber() < PythonConsole::PROMPT.size()) return; - QTextEdit::keyPressEvent( e ); -} - -void PythonConsole::handleReturnKeyPress( ) -{ - if ( ! cursorIsOnInputLine( ) ) - { - return; - } - - QString line = getLine( ); - - m_parseHelper.process( line.toStdString( ) ); - if ( m_parseHelper.buffered( ) ) - { - append(""); - displayPrompt( ); - } - if ( line.size( ) ) - { - m_historyBuffer.push_back( line.toStdString( ) ); - m_historyIt = m_historyBuffer.end(); - } - moveCursorToEnd( ); -} - -void PythonConsole::parseEvent( const ParseMessage& message ) -{ - // handle invalid user input - if ( message.errorCode ) - { - setTextColor( ERROR_COLOR ); - append(message.message.c_str()); - - setTextColor( NORMAL_COLOR ); - append(""); - displayPrompt( ); - return; - } - - // interpret valid user input - int errorCode = 0; - std::string res; - if ( message.message.size() ) - res = pyinterpreter_execute( message.message, &errorCode ); - if ( errorCode ) - { - setTextColor( ERROR_COLOR ); - } - else - { - setTextColor( OUTPUT_COLOR ); - } - - if ( res.size( ) ) - { - append(res.c_str()); - } - - setTextColor( NORMAL_COLOR ); - - // set up the next line on the console - append(""); - displayPrompt( ); -} - -QString PythonConsole::getLine( ) -{ - QTextCursor cursor = textCursor(); - cursor.movePosition( QTextCursor::StartOfLine ); - cursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, PythonConsole::PROMPT.size( ) ); - cursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor ); - QString line = cursor.selectedText( ); - cursor.clearSelection( ); - return line; -} - -bool PythonConsole::cursorIsOnInputLine( ) -{ - int cursorBlock = textCursor( ).blockNumber( ); - QTextCursor bottomCursor = textCursor( ); - bottomCursor.movePosition( QTextCursor::End ); - int bottomBlock = bottomCursor.blockNumber( ); - return ( cursorBlock == bottomBlock ); -} - -bool PythonConsole::inputLineIsEmpty( ) -{ - QTextCursor bottomCursor = textCursor( ); - bottomCursor.movePosition( QTextCursor::End ); - int col = bottomCursor.columnNumber( ); - return ( col == PythonConsole::PROMPT.size( ) ); -} - -bool PythonConsole::canBackspace( ) -{ - if ( ! cursorIsOnInputLine( ) ) - { - return false; - } - - if ( inputLineIsEmpty( ) ) - { - return false; - } - - return true; -} - -bool PythonConsole::canGoLeft( ) -{ - if ( cursorIsOnInputLine( ) ) - { - QTextCursor bottomCursor = textCursor( ); - int col = bottomCursor.columnNumber( ); - return (col > PythonConsole::PROMPT.size( )); - } - return true; -} - -void PythonConsole::displayPrompt( ) -{ - QTextCursor cursor = textCursor(); - cursor.movePosition( QTextCursor::End ); - if ( m_parseHelper.buffered( ) ) - { - cursor.insertText( PythonConsole::MULTILINE_PROMPT ); - } - else - { - cursor.insertText( PythonConsole::PROMPT ); - } - cursor.movePosition( QTextCursor::EndOfLine ); -} - -void PythonConsole::displayString(QString text) -{ - QTextCursor cursor = textCursor(); - cursor.movePosition( QTextCursor::End ); - cursor.insertText( text ); - cursor.movePosition( QTextCursor::EndOfLine ); -} - -void PythonConsole::autocomplete( ) -{ - if ( ! cursorIsOnInputLine( ) ) - return; - - QString line = getLine( ); - const std::list& suggestions = - pyinterpreter_suggest( line.toStdString( ) ); - if (suggestions.size() == 1) - { - line = suggestions.back().c_str(); - } - else - { - // try to complete to longest common prefix - std::string prefix = - LongestCommonPrefix(suggestions.begin(), suggestions.end()); - if (prefix.size() > (size_t)line.size()) - { - line = prefix.c_str(); - } - else - { - ColumnFormatter fmt; - fmt.setItems(suggestions.begin(), suggestions.end()); - fmt.format(width() / 10); - setTextColor( OUTPUT_COLOR ); - const std::list& formatted = fmt.formattedOutput(); - for (std::list::const_iterator it = formatted.begin(); - it != formatted.end(); ++it) - { - append(it->c_str()); - } - setTextColor( NORMAL_COLOR ); - } - } - - // set up the next line on the console - append(""); - displayPrompt( ); - moveCursorToEnd( ); - QTextCursor cursor = textCursor(); - cursor.insertText( line ); - moveCursorToEnd( ); -} - -void PythonConsole::previousHistory( ) -{ - if ( ! cursorIsOnInputLine( ) ) - return; - - if ( ! m_historyBuffer.size( ) ) - return; - - QTextCursor cursor = textCursor(); - cursor.movePosition( QTextCursor::StartOfLine ); - cursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, PythonConsole::PROMPT.size( ) ); - cursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor ); - cursor.removeSelectedText( ); - if ( m_historyIt != m_historyBuffer.begin( ) ) - { - --m_historyIt; - } - cursor.insertText( m_historyIt->c_str() ); -} - -void PythonConsole::nextHistory( ) -{ - if ( ! cursorIsOnInputLine( ) ) - return; - - if ( ! m_historyBuffer.size( ) ) - return; - if ( m_historyIt == m_historyBuffer.end( ) ) - { - return; - } - QTextCursor cursor = textCursor(); - cursor.movePosition( QTextCursor::StartOfLine ); - cursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, PythonConsole::PROMPT.size( ) ); - cursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor ); - cursor.removeSelectedText( ); - ++m_historyIt; - if ( m_historyIt == m_historyBuffer.end( ) ) - { - return; - } - cursor.insertText( m_historyIt->c_str() ); -} - -void PythonConsole::moveCursorToEnd( ) -{ - QTextCursor cursor = textCursor(); - cursor.movePosition( QTextCursor::End ); - setTextCursor( cursor ); -} - -void PythonConsole::insertFromMimeData(const QMimeData *src) -{ - if (src->hasText()) { - QStringList list = src->text().split("\n",QString::KeepEmptyParts); - bool lastends = src->text().endsWith("\n"); - for (int i=0;i -#include -#include -#include "ParseHelper.h" -#include "ParseListener.h" - -class QWidget; -class QKeyEvent; - -class PythonConsole : public QTextEdit, ParseListener -{ - Q_OBJECT - - public: - PythonConsole(QWidget *parent = 0); - - void displayPrompt(); - void displayString(QString text); - - protected: - // override QTextEdit - virtual void keyPressEvent(QKeyEvent *e); - - virtual void handleReturnKeyPress(); - - virtual void insertFromMimeData(const QMimeData *src); - - /** - Handle a compilable chunk of Python user input. - */ - virtual void parseEvent(const ParseMessage &message); - - QString getLine(); - bool cursorIsOnInputLine(); - bool inputLineIsEmpty(); - bool canBackspace(); - bool canGoLeft(); - void autocomplete(); - void previousHistory(); - void nextHistory(); - void moveCursorToEnd(); - - static const QString PROMPT; - static const QString MULTILINE_PROMPT; - - static const QColor NORMAL_COLOR; - static const QColor ERROR_COLOR; - static const QColor OUTPUT_COLOR; - - ParseHelper m_parseHelper; - std::list m_historyBuffer; - std::list::const_iterator m_historyIt; -}; - -#endif // PYCONSOLE_H diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 5ac4d955..2e8e367e 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -12,7 +12,6 @@ if (BUILD_PYTHON) ../3rdparty/python-console/modified/pyredirector.cc ../3rdparty/python-console/modified/pyinterpreter.cc - ../3rdparty/python-console/modified/pyconsole.cc ) endif() diff --git a/gui/basewindow.cc b/gui/basewindow.cc index fd9d36f4..b76527e1 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -76,7 +76,7 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent tabWidget = new QTabWidget(); #ifndef NO_PYTHON PythonTab *pythontab = new PythonTab(); - tabWidget->addTab(pythontab, "Python"); + tabWidget->addTab(pythontab, "Console"); connect(this, SIGNAL(contextChanged(Context *)), pythontab, SLOT(newContext(Context *))); #endif info = new InfoTab(); diff --git a/gui/line_editor.cc b/gui/line_editor.cc index 9d9dac25..3c7ebe94 100644 --- a/gui/line_editor.cc +++ b/gui/line_editor.cc @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Miodrag Milanovic + * Copyright (C) 2018 Alex Tsui * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,12 +18,18 @@ * */ +#ifndef NO_PYTHON + #include "line_editor.h" #include +#include +#include "ColumnFormatter.h" +#include "Utils.h" +#include "pyinterpreter.h" NEXTPNR_NAMESPACE_BEGIN -LineEditor::LineEditor(QWidget *parent) : QLineEdit(parent), index(0) +LineEditor::LineEditor(ParseHelper *helper, QWidget *parent) : QLineEdit(parent), index(0), parseHelper(helper) { setContextMenuPolicy(Qt::CustomContextMenu); QAction *clearAction = new QAction("Clear &history", this); @@ -38,10 +45,12 @@ LineEditor::LineEditor(QWidget *parent) : QLineEdit(parent), index(0) void LineEditor::keyPressEvent(QKeyEvent *ev) { + if (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) { + QToolTip::hideText(); if (lines.empty()) return; - + printf("Key_Up\n"); if (ev->key() == Qt::Key_Up) index--; if (ev->key() == Qt::Key_Down) @@ -56,12 +65,21 @@ void LineEditor::keyPressEvent(QKeyEvent *ev) } setText(lines[index]); } else if (ev->key() == Qt::Key_Escape) { + QToolTip::hideText(); clear(); return; + } else if (ev->key() == Qt::Key_Tab) { + autocomplete(); + return; } + QToolTip::hideText(); + QLineEdit::keyPressEvent(ev); } +// This makes TAB work +bool LineEditor::focusNextPrevChild(bool next) { return false; } + void LineEditor::textInserted() { if (lines.empty() || lines.back() != text()) @@ -82,4 +100,36 @@ void LineEditor::clearHistory() clear(); } -NEXTPNR_NAMESPACE_END \ No newline at end of file +void LineEditor::autocomplete() +{ + QString line = text(); + const std::list &suggestions = pyinterpreter_suggest(line.toStdString()); + if (suggestions.size() == 1) { + line = suggestions.back().c_str(); + } else { + // try to complete to longest common prefix + std::string prefix = LongestCommonPrefix(suggestions.begin(), suggestions.end()); + if (prefix.size() > (size_t)line.size()) { + line = prefix.c_str(); + } else { + ColumnFormatter fmt; + fmt.setItems(suggestions.begin(), suggestions.end()); + fmt.format(width() / 5); + QString out = ""; + for (auto &it : fmt.formattedOutput()) { + if (!out.isEmpty()) + out += "\n"; + out += it.c_str(); + } + QToolTip::setFont(font()); + if (!out.trimmed().isEmpty()) + QToolTip::showText(mapToGlobal(QPoint(0, 0)), out); + } + } + // set up the next line on the console + setText(line); +} + +NEXTPNR_NAMESPACE_END + +#endif // NO_PYTHON diff --git a/gui/line_editor.h b/gui/line_editor.h index 91837182..5a57129b 100644 --- a/gui/line_editor.h +++ b/gui/line_editor.h @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Miodrag Milanovic + * Copyright (C) 2018 Alex Tsui * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,8 +21,11 @@ #ifndef LINE_EDITOR_H #define LINE_EDITOR_H +#ifndef NO_PYTHON + #include #include +#include "ParseHelper.h" #include "nextpnr.h" NEXTPNR_NAMESPACE_BEGIN @@ -31,7 +35,7 @@ class LineEditor : public QLineEdit Q_OBJECT public: - explicit LineEditor(QWidget *parent = 0); + explicit LineEditor(ParseHelper *helper, QWidget *parent = 0); private Q_SLOTS: void textInserted(); @@ -43,13 +47,18 @@ class LineEditor : public QLineEdit protected: void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE; + bool focusNextPrevChild(bool next) Q_DECL_OVERRIDE; + void autocomplete(); private: int index; QStringList lines; QMenu *contextMenu; + ParseHelper *parseHelper; }; NEXTPNR_NAMESPACE_END +#endif // NO_PYTHON + #endif // LINE_EDITOR_H diff --git a/gui/pyconsole.cc b/gui/pyconsole.cc new file mode 100644 index 00000000..6da06b7e --- /dev/null +++ b/gui/pyconsole.cc @@ -0,0 +1,82 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Miodrag Milanovic + * Copyright (C) 2018 Alex Tsui + * + * 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. + * + */ + +#ifndef NO_PYTHON + +#include "pyconsole.h" +#include "pyinterpreter.h" + +NEXTPNR_NAMESPACE_BEGIN + +const QColor PythonConsole::NORMAL_COLOR = QColor::fromRgbF(0, 0, 0); +const QColor PythonConsole::ERROR_COLOR = QColor::fromRgbF(1.0, 0, 0); +const QColor PythonConsole::OUTPUT_COLOR = QColor::fromRgbF(0, 0, 1.0); + +PythonConsole::PythonConsole(QWidget *parent) : QTextEdit(parent) {} + +void PythonConsole::parseEvent(const ParseMessage &message) +{ + // handle invalid user input + if (message.errorCode) { + setTextColor(ERROR_COLOR); + append(message.message.c_str()); + + setTextColor(NORMAL_COLOR); + append(""); + return; + } + // interpret valid user input + int errorCode = 0; + std::string res; + if (message.message.size()) + res = pyinterpreter_execute(message.message, &errorCode); + if (errorCode) { + setTextColor(ERROR_COLOR); + } else { + setTextColor(OUTPUT_COLOR); + } + + if (res.size()) { + append(res.c_str()); + } + setTextColor(NORMAL_COLOR); + append(""); + moveCursorToEnd(); +} + +void PythonConsole::displayString(QString text) +{ + QTextCursor cursor = textCursor(); + cursor.movePosition(QTextCursor::End); + setTextColor(NORMAL_COLOR); + cursor.insertText(text); + cursor.movePosition(QTextCursor::EndOfLine); +} + +void PythonConsole::moveCursorToEnd() +{ + QTextCursor cursor = textCursor(); + cursor.movePosition(QTextCursor::End); + setTextCursor(cursor); +} + +NEXTPNR_NAMESPACE_END + +#endif // NO_PYTHON diff --git a/gui/pyconsole.h b/gui/pyconsole.h new file mode 100644 index 00000000..60f10672 --- /dev/null +++ b/gui/pyconsole.h @@ -0,0 +1,58 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Miodrag Milanovic + * Copyright (C) 2018 Alex Tsui + * + * 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. + * + */ + +#ifndef PYCONSOLE_H +#define PYCONSOLE_H + +#ifndef NO_PYTHON + +#include +#include +#include +#include "ParseHelper.h" +#include "ParseListener.h" +#include "nextpnr.h" + +class QWidget; +class QKeyEvent; + +NEXTPNR_NAMESPACE_BEGIN + +class PythonConsole : public QTextEdit, public ParseListener +{ + Q_OBJECT + + public: + PythonConsole(QWidget *parent = 0); + + void displayString(QString text); + void moveCursorToEnd(); + virtual void parseEvent(const ParseMessage &message); + + protected: + static const QColor NORMAL_COLOR; + static const QColor ERROR_COLOR; + static const QColor OUTPUT_COLOR; +}; + +NEXTPNR_NAMESPACE_END +#endif // NO_PYTHON + +#endif // PYCONSOLE_H diff --git a/gui/pythontab.cc b/gui/pythontab.cc index 897f87b3..5c349d7c 100644 --- a/gui/pythontab.cc +++ b/gui/pythontab.cc @@ -25,12 +25,20 @@ NEXTPNR_NAMESPACE_BEGIN +const QString PythonTab::PROMPT = ">>> "; +const QString PythonTab::MULTILINE_PROMPT = "... "; + PythonTab::PythonTab(QWidget *parent) : QWidget(parent), initialized(false) { + QFont f("unexistent"); + f.setStyleHint(QFont::Monospace); + // Add text area for Python output and input line console = new PythonConsole(); console->setMinimumHeight(100); - console->setEnabled(false); + console->setReadOnly(true); + console->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); + console->setFont(f); console->setContextMenuPolicy(Qt::CustomContextMenu); QAction *clearAction = new QAction("Clear &buffer", this); @@ -41,9 +49,21 @@ PythonTab::PythonTab(QWidget *parent) : QWidget(parent), initialized(false) contextMenu->addAction(clearAction); connect(console, SIGNAL(customContextMenuRequested(const QPoint)), this, SLOT(showContextMenu(const QPoint))); + lineEdit = new LineEditor(&parseHelper); + lineEdit->setMinimumHeight(30); + lineEdit->setMaximumHeight(30); + lineEdit->setFont(f); + lineEdit->setPlaceholderText(PythonTab::PROMPT); + connect(lineEdit, SIGNAL(textLineInserted(QString)), this, SLOT(editLineReturnPressed(QString))); + QGridLayout *mainLayout = new QGridLayout(); mainLayout->addWidget(console, 0, 0); + mainLayout->addWidget(lineEdit, 1, 0); setLayout(mainLayout); + + parseHelper.subscribe(console); + + prompt = PythonTab::PROMPT; } PythonTab::~PythonTab() @@ -54,13 +74,27 @@ PythonTab::~PythonTab() } } +void PythonTab::editLineReturnPressed(QString text) +{ + console->displayString(prompt + text + "\n"); + console->moveCursorToEnd(); + + parseHelper.process(text.toStdString()); + + if (parseHelper.buffered()) + prompt = PythonTab::MULTILINE_PROMPT; + else + prompt = PythonTab::PROMPT; + + lineEdit->setPlaceholderText(prompt); +} + void PythonTab::newContext(Context *ctx) { if (initialized) { pyinterpreter_finalize(); deinit_python(); } - console->setEnabled(true); console->clear(); pyinterpreter_preinit(); @@ -74,7 +108,6 @@ void PythonTab::newContext(Context *ctx) QString version = QString("Python %1 on %2\n").arg(Py_GetVersion(), Py_GetPlatform()); console->displayString(version); - console->displayPrompt(); } void PythonTab::showContextMenu(const QPoint &pt) { contextMenu->exec(mapToGlobal(pt)); } @@ -83,4 +116,4 @@ void PythonTab::clearBuffer() { console->clear(); } NEXTPNR_NAMESPACE_END -#endif \ No newline at end of file +#endif // NO_PYTHON diff --git a/gui/pythontab.h b/gui/pythontab.h index 4b22e6a9..3fd12981 100644 --- a/gui/pythontab.h +++ b/gui/pythontab.h @@ -25,6 +25,7 @@ #include #include #include +#include "ParseHelper.h" #include "line_editor.h" #include "nextpnr.h" #include "pyconsole.h" @@ -42,13 +43,20 @@ class PythonTab : public QWidget private Q_SLOTS: void showContextMenu(const QPoint &pt); void clearBuffer(); + void editLineReturnPressed(QString text); public Q_SLOTS: void newContext(Context *ctx); private: PythonConsole *console; + LineEditor *lineEdit; QMenu *contextMenu; bool initialized; + ParseHelper parseHelper; + QString prompt; + + static const QString PROMPT; + static const QString MULTILINE_PROMPT; }; NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From 89809a8b810dd57f50f365d70a0ce547705f8dbb Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 13 Jul 2018 18:57:55 +0100 Subject: Introduce proxies for locked access to ctx --- common/place_common.cc | 95 ++---------- common/place_common.h | 83 +++++++++- common/placer1.cc | 181 ++++++++++++---------- common/router1.cc | 108 +++++++------ ice40/arch.cc | 357 +++++++++++++++++++++++++++++++++++-------- ice40/arch.h | 387 ++++++++++++++++++----------------------------- ice40/arch_place.cc | 75 ++++----- ice40/place_legaliser.cc | 73 +++++---- 8 files changed, 767 insertions(+), 592 deletions(-) diff --git a/common/place_common.cc b/common/place_common.cc index 281e40a2..48416370 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,84 +25,8 @@ NEXTPNR_NAMESPACE_BEGIN -// Get the total estimated wirelength for a net -wirelen_t get_net_wirelength(const Context *ctx, const NetInfo *net, float &tns) -{ - wirelen_t wirelength = 0; - int driver_x, driver_y; - bool driver_gb; - CellInfo *driver_cell = net->driver.cell; - if (!driver_cell) - return 0; - if (driver_cell->bel == BelId()) - return 0; - ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb); - WireId drv_wire = ctx->getWireBelPinUnlocked(driver_cell->bel, ctx->portPinFromId(net->driver.port)); - if (driver_gb) - return 0; - float worst_slack = 1000; - int xmin = driver_x, xmax = driver_x, ymin = driver_y, ymax = driver_y; - for (auto load : net->users) { - if (load.cell == nullptr) - continue; - CellInfo *load_cell = load.cell; - if (load_cell->bel == BelId()) - continue; - if (ctx->timing_driven) { - WireId user_wire = ctx->getWireBelPinUnlocked(load_cell->bel, ctx->portPinFromId(load.port)); - delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); - float slack = ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl); - if (slack < 0) - tns += slack; - worst_slack = std::min(slack, worst_slack); - } - - int load_x, load_y; - bool load_gb; - ctx->estimatePosition(load_cell->bel, load_x, load_y, load_gb); - if (load_gb) - continue; - xmin = std::min(xmin, load_x); - ymin = std::min(ymin, load_y); - xmax = std::max(xmax, load_x); - ymax = std::max(ymax, load_y); - } - if (ctx->timing_driven) { - wirelength = wirelen_t((((ymax - ymin) + (xmax - xmin)) * std::min(5.0, (1.0 + std::exp(-worst_slack / 5))))); - } else { - wirelength = wirelen_t((ymax - ymin) + (xmax - xmin)); - } - - return wirelength; -} - -// Get the total wirelength for a cell -wirelen_t get_cell_wirelength(const Context *ctx, const CellInfo *cell) -{ - std::set nets; - for (auto p : cell->ports) { - if (p.second.net) - nets.insert(p.second.net->name); - } - wirelen_t wirelength = 0; - float tns = 0; - for (auto n : nets) { - wirelength += get_net_wirelength(ctx, ctx->nets.at(n).get(), tns); - } - return wirelength; -} - -wirelen_t get_cell_wirelength_at_bel(const Context *ctx, CellInfo *cell, BelId bel) -{ - BelId oldBel = cell->bel; - cell->bel = bel; - wirelen_t wirelen = get_cell_wirelength(ctx, cell); - cell->bel = oldBel; - return wirelen; -} - // Placing a single cell -bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality) +bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool require_legality) { bool all_placed = false; int iters = 25; @@ -112,13 +37,13 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality) CellInfo *ripup_target = nullptr; BelId ripup_bel = BelId(); if (cell->bel != BelId()) { - ctx->unbindBelUnlocked(cell->bel); + proxy.unbindBel(cell->bel); } BelType targetType = ctx->belTypeFromId(cell->type); for (auto bel : ctx->getBels()) { - if (ctx->getBelType(bel) == targetType && (!require_legality || ctx->isValidBelForCell(cell, bel))) { - if (ctx->checkBelAvailUnlocked(bel)) { - wirelen_t wirelen = get_cell_wirelength_at_bel(ctx, cell, bel); + if (ctx->getBelType(bel) == targetType && (!require_legality || proxy.isValidBelForCell(cell, bel))) { + if (proxy.checkBelAvail(bel)) { + wirelen_t wirelen = get_cell_wirelength_at_bel(proxy, ctx, cell, bel); if (iters >= 4) wirelen += ctx->rng(25); if (wirelen <= best_wirelen) { @@ -126,11 +51,11 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality) best_bel = bel; } } else { - wirelen_t wirelen = get_cell_wirelength_at_bel(ctx, cell, bel); + wirelen_t wirelen = get_cell_wirelength_at_bel(proxy, ctx, cell, bel); if (iters >= 4) wirelen += ctx->rng(25); if (wirelen <= best_ripup_wirelen) { - ripup_target = ctx->cells.at(ctx->getBoundBelCellUnlocked(bel)).get(); + ripup_target = proxy.getCell(proxy.getBoundBelCell(bel)); if (ripup_target->belStrength < STRENGTH_STRONG) { best_ripup_wirelen = wirelen; ripup_bel = bel; @@ -148,12 +73,12 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality) log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx)); } --iters; - ctx->unbindBelUnlocked(ripup_target->bel); + proxy.unbindBel(ripup_target->bel); best_bel = ripup_bel; } else { all_placed = true; } - ctx->bindBelUnlocked(best_bel, cell->name, STRENGTH_WEAK); + proxy.bindBel(best_bel, cell->name, STRENGTH_WEAK); cell = ripup_target; } diff --git a/common/place_common.h b/common/place_common.h index 67956072..57e82510 100644 --- a/common/place_common.h +++ b/common/place_common.h @@ -22,21 +22,94 @@ #include "nextpnr.h" +#include + NEXTPNR_NAMESPACE_BEGIN typedef int64_t wirelen_t; -// Return the wirelength of a net -wirelen_t get_net_wirelength(const Context *ctx, const NetInfo *net, float &tns); +// Get the total estimated wirelength for a net +template +wirelen_t get_net_wirelength(const T &proxy, const Context *ctx, const NetInfo *net, float &tns) +{ + wirelen_t wirelength = 0; + int driver_x, driver_y; + bool driver_gb; + CellInfo *driver_cell = net->driver.cell; + if (!driver_cell) + return 0; + if (driver_cell->bel == BelId()) + return 0; + ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb); + WireId drv_wire = proxy.getWireBelPin(driver_cell->bel, ctx->portPinFromId(net->driver.port)); + if (driver_gb) + return 0; + float worst_slack = 1000; + int xmin = driver_x, xmax = driver_x, ymin = driver_y, ymax = driver_y; + for (auto load : net->users) { + if (load.cell == nullptr) + continue; + CellInfo *load_cell = load.cell; + if (load_cell->bel == BelId()) + continue; + if (ctx->timing_driven) { + WireId user_wire = proxy.getWireBelPin(load_cell->bel, ctx->portPinFromId(load.port)); + delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); + float slack = ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl); + if (slack < 0) + tns += slack; + worst_slack = std::min(slack, worst_slack); + } + + int load_x, load_y; + bool load_gb; + ctx->estimatePosition(load_cell->bel, load_x, load_y, load_gb); + if (load_gb) + continue; + xmin = std::min(xmin, load_x); + ymin = std::min(ymin, load_y); + xmax = std::max(xmax, load_x); + ymax = std::max(ymax, load_y); + } + if (ctx->timing_driven) { + wirelength = wirelen_t((((ymax - ymin) + (xmax - xmin)) * std::min(5.0, (1.0 + std::exp(-worst_slack / 5))))); + } else { + wirelength = wirelen_t((ymax - ymin) + (xmax - xmin)); + } + + return wirelength; +} // Return the wirelength of all nets connected to a cell -wirelen_t get_cell_wirelength(const Context *ctx, const CellInfo *cell); +template +wirelen_t get_cell_wirelength(const T &proxy, const Context *ctx, const CellInfo *cell) +{ + std::set nets; + for (auto p : cell->ports) { + if (p.second.net) + nets.insert(p.second.net->name); + } + wirelen_t wirelength = 0; + float tns = 0; + for (auto n : nets) { + wirelength += get_net_wirelength(proxy, ctx, ctx->nets.at(n).get(), tns); + } + return wirelength; +} // Return the wirelength of all nets connected to a cell, when the cell is at a given bel -wirelen_t get_cell_wirelength_at_bel(const Context *ctx, CellInfo *cell, BelId bel); +template +wirelen_t get_cell_wirelength_at_bel(const T &proxy, const Context *ctx, CellInfo *cell, BelId bel) +{ + BelId oldBel = cell->bel; + cell->bel = bel; + wirelen_t wirelen = get_cell_wirelength(proxy, ctx, cell); + cell->bel = oldBel; + return wirelen; +} // Place a single cell in the lowest wirelength Bel available, optionally requiring validity check -bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality); +bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool require_legality); NEXTPNR_NAMESPACE_END diff --git a/common/placer1.cc b/common/placer1.cc index 05f760a3..0e3a84f7 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -3,6 +3,7 @@ * * Copyright (C) 2018 Clifford Wolf * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski * * Simulated annealing implementation based on arachne-pnr * Copyright (C) 2015-2018 Cotton Seed @@ -79,30 +80,33 @@ class SAPlacer log_break(); size_t placed_cells = 0; - // Initial constraints placer - for (auto &cell_entry : ctx->cells) { - CellInfo *cell = cell_entry.second.get(); - auto loc = cell->attrs.find(ctx->id("BEL")); - if (loc != cell->attrs.end()) { - std::string loc_name = loc->second; - BelId bel = ctx->getBelByNameUnlocked(ctx->id(loc_name)); - if (bel == BelId()) { - log_error("No Bel named \'%s\' located for " - "this chip (processing BEL attribute on \'%s\')\n", - loc_name.c_str(), cell->name.c_str(ctx)); - } + { + auto &&proxy = ctx->rwproxy(); + // Initial constraints placer + for (auto &cell_entry : ctx->cells) { + CellInfo *cell = cell_entry.second.get(); + auto loc = cell->attrs.find(ctx->id("BEL")); + if (loc != cell->attrs.end()) { + std::string loc_name = loc->second; + BelId bel = proxy.getBelByName(ctx->id(loc_name)); + if (bel == BelId()) { + log_error("No Bel named \'%s\' located for " + "this chip (processing BEL attribute on \'%s\')\n", + loc_name.c_str(), cell->name.c_str(ctx)); + } - BelType bel_type = ctx->getBelType(bel); - if (bel_type != ctx->belTypeFromId(cell->type)) { - log_error("Bel \'%s\' of type \'%s\' does not match cell " - "\'%s\' of type \'%s\'", - loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(ctx), cell->name.c_str(ctx), - cell->type.c_str(ctx)); - } + BelType bel_type = ctx->getBelType(bel); + if (bel_type != ctx->belTypeFromId(cell->type)) { + log_error("Bel \'%s\' of type \'%s\' does not match cell " + "\'%s\' of type \'%s\'", + loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(ctx), cell->name.c_str(ctx), + cell->type.c_str(ctx)); + } - ctx->bindBelUnlocked(bel, cell->name, STRENGTH_USER); - locked_bels.insert(bel); - placed_cells++; + proxy.bindBel(bel, cell->name, STRENGTH_USER); + locked_bels.insert(bel); + placed_cells++; + } } } int constr_placed_cells = placed_cells; @@ -122,12 +126,15 @@ class SAPlacer // Place cells randomly initially log_info("Creating initial placement for remaining %d cells.\n", int(autoplaced.size())); - for (auto cell : autoplaced) { - place_initial(cell); - placed_cells++; - if ((placed_cells - constr_placed_cells) % 500 == 0) - log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells), - int(autoplaced.size())); + { + auto &&proxy = ctx->rwproxy(); + for (auto cell : autoplaced) { + place_initial(proxy, cell); + placed_cells++; + if ((placed_cells - constr_placed_cells) % 500 == 0) + log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells), + int(autoplaced.size())); + } } if ((placed_cells - constr_placed_cells) % 500 != 0) log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells), @@ -138,10 +145,13 @@ class SAPlacer // Calculate wirelength after initial placement curr_wirelength = 0; curr_tns = 0; - for (auto &net : ctx->nets) { - wirelen_t wl = get_net_wirelength(ctx, net.second.get(), curr_tns); - wirelengths[net.first] = wl; - curr_wirelength += wl; + { + auto &&proxy = ctx->rproxy(); + for (auto &net : ctx->nets) { + wirelen_t wl = get_net_wirelength(proxy, ctx, net.second.get(), curr_tns); + wirelengths[net.first] = wl; + curr_wirelength += wl; + } } int n_no_progress = 0; @@ -158,15 +168,18 @@ class SAPlacer "%.0f, est tns = %.02fns\n", iter, temp, double(curr_wirelength), curr_tns); - for (int m = 0; m < 15; ++m) { - // Loop through all automatically placed cells - for (auto cell : autoplaced) { - // Find another random Bel for this cell - BelId try_bel = random_bel_for_cell(cell); - // If valid, try and swap to a new position and see if - // the new position is valid/worthwhile - if (try_bel != BelId() && try_bel != cell->bel) - try_swap_position(cell, try_bel); + { + auto &&proxy = ctx->rwproxy(); + for (int m = 0; m < 15; ++m) { + // Loop through all automatically placed cells + for (auto cell : autoplaced) { + // Find another random Bel for this cell + BelId try_bel = random_bel_for_cell(cell); + // If valid, try and swap to a new position and see if + // the new position is valid/worthwhile + if (try_bel != BelId() && try_bel != cell->bel) + try_swap_position(proxy, cell, try_bel); + } } } // Heuristic to improve placement on the 8k @@ -227,27 +240,33 @@ class SAPlacer // accumulating over time curr_wirelength = 0; curr_tns = 0; - for (auto &net : ctx->nets) { - wirelen_t wl = get_net_wirelength(ctx, net.second.get(), curr_tns); - wirelengths[net.first] = wl; - curr_wirelength += wl; + { + auto &&proxy = ctx->rproxy(); + for (auto &net : ctx->nets) { + wirelen_t wl = get_net_wirelength(proxy, ctx, net.second.get(), curr_tns); + wirelengths[net.first] = wl; + curr_wirelength += wl; + } } } - // Final post-pacement validitiy check - for (auto bel : ctx->getBels()) { - IdString cell = ctx->getBoundBelCellUnlocked(bel); - if (!ctx->isBelLocationValid(bel)) { - std::string cell_text = "no cell"; - if (cell != IdString()) - cell_text = std::string("cell '") + cell.str(ctx) + "'"; - if (ctx->force) { - log_warning("post-placement validity check failed for Bel '%s' " - "(%s)\n", - ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); - } else { - log_error("post-placement validity check failed for Bel '%s' " - "(%s)\n", - ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); + { + // Final post-pacement validitiy check + auto &&proxy = ctx->rproxy(); + for (auto bel : ctx->getBels()) { + IdString cell = proxy.getBoundBelCell(bel); + if (!proxy.isBelLocationValid(bel)) { + std::string cell_text = "no cell"; + if (cell != IdString()) + cell_text = std::string("cell '") + cell.str(ctx) + "'"; + if (ctx->force) { + log_warning("post-placement validity check failed for Bel '%s' " + "(%s)\n", + ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); + } else { + log_error("post-placement validity check failed for Bel '%s' " + "(%s)\n", + ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); + } } } } @@ -256,7 +275,7 @@ class SAPlacer private: // Initial random placement - void place_initial(CellInfo *cell) + void place_initial(ArchRWProxy &proxy, CellInfo *cell) { bool all_placed = false; int iters = 25; @@ -267,12 +286,12 @@ class SAPlacer CellInfo *ripup_target = nullptr; BelId ripup_bel = BelId(); if (cell->bel != BelId()) { - ctx->unbindBelUnlocked(cell->bel); + proxy.unbindBel(cell->bel); } BelType targetType = ctx->belTypeFromId(cell->type); for (auto bel : ctx->getBels()) { - if (ctx->getBelType(bel) == targetType && (ctx->isValidBelForCell(cell, bel) || !require_legal)) { - if (ctx->checkBelAvailUnlocked(bel)) { + if (ctx->getBelType(bel) == targetType && (proxy.isValidBelForCell(cell, bel) || !require_legal)) { + if (proxy.checkBelAvail(bel)) { uint64_t score = ctx->rng64(); if (score <= best_score) { best_score = score; @@ -282,7 +301,7 @@ class SAPlacer uint64_t score = ctx->rng64(); if (score <= best_ripup_score) { best_ripup_score = score; - ripup_target = ctx->cells.at(ctx->getBoundBelCellUnlocked(bel)).get(); + ripup_target = ctx->cells.at(proxy.getBoundBelCell(bel)).get(); ripup_bel = bel; } } @@ -292,12 +311,12 @@ class SAPlacer if (iters == 0 || ripup_bel == BelId()) log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx)); --iters; - ctx->unbindBelUnlocked(ripup_target->bel); + proxy.unbindBel(ripup_target->bel); best_bel = ripup_bel; } else { all_placed = true; } - ctx->bindBelUnlocked(best_bel, cell->name, STRENGTH_WEAK); + proxy.bindBel(best_bel, cell->name, STRENGTH_WEAK); // Back annotate location cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx); @@ -306,14 +325,14 @@ class SAPlacer } // Attempt a SA position swap, return true on success or false on failure - bool try_swap_position(CellInfo *cell, BelId newBel) + bool try_swap_position(ArchRWProxy &proxy, CellInfo *cell, BelId newBel) { static std::unordered_set update; static std::vector> new_lengths; new_lengths.clear(); update.clear(); BelId oldBel = cell->bel; - IdString other = ctx->getBoundBelCellUnlocked(newBel); + IdString other = proxy.getBoundBelCell(newBel); CellInfo *other_cell = nullptr; if (other != IdString()) { other_cell = ctx->cells[other].get(); @@ -321,9 +340,9 @@ class SAPlacer return false; } wirelen_t new_wirelength = 0, delta; - ctx->unbindBelUnlocked(oldBel); + proxy.unbindBel(oldBel); if (other != IdString()) { - ctx->unbindBelUnlocked(newBel); + proxy.unbindBel(newBel); } for (const auto &port : cell->ports) @@ -336,16 +355,16 @@ class SAPlacer update.insert(port.second.net); } - ctx->bindBelUnlocked(newBel, cell->name, STRENGTH_WEAK); + proxy.bindBel(newBel, cell->name, STRENGTH_WEAK); if (other != IdString()) { - ctx->bindBelUnlocked(oldBel, other_cell->name, STRENGTH_WEAK); + proxy.bindBel(oldBel, other_cell->name, STRENGTH_WEAK); } if (require_legal) { - if (!ctx->isBelLocationValid(newBel) || ((other != IdString() && !ctx->isBelLocationValid(oldBel)))) { - ctx->unbindBelUnlocked(newBel); + if (!proxy.isBelLocationValid(newBel) || ((other != IdString() && !proxy.isBelLocationValid(oldBel)))) { + proxy.unbindBel(newBel); if (other != IdString()) - ctx->unbindBelUnlocked(oldBel); + proxy.unbindBel(oldBel); goto swap_fail; } } @@ -356,7 +375,7 @@ class SAPlacer for (auto net : update) { new_wirelength -= wirelengths.at(net->name); float temp_tns = 0; - wirelen_t net_new_wl = get_net_wirelength(ctx, net, temp_tns); + wirelen_t net_new_wl = get_net_wirelength<>(proxy, ctx, net, temp_tns); new_wirelength += net_new_wl; new_lengths.push_back(std::make_pair(net->name, net_new_wl)); } @@ -369,8 +388,8 @@ class SAPlacer improved = true; } else { if (other != IdString()) - ctx->unbindBelUnlocked(oldBel); - ctx->unbindBelUnlocked(newBel); + proxy.unbindBel(oldBel); + proxy.unbindBel(newBel); goto swap_fail; } curr_wirelength = new_wirelength; @@ -379,9 +398,9 @@ class SAPlacer return true; swap_fail: - ctx->bindBelUnlocked(oldBel, cell->name, STRENGTH_WEAK); + proxy.bindBel(oldBel, cell->name, STRENGTH_WEAK); if (other != IdString()) { - ctx->bindBelUnlocked(newBel, other, STRENGTH_WEAK); + proxy.bindBel(newBel, other, STRENGTH_WEAK); } return false; } diff --git a/common/router1.cc b/common/router1.cc index cbaf773d..0d26a36d 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -73,7 +74,7 @@ struct RipupScoreboard std::unordered_map, int, hash_id_pip> netPipScores; }; -void ripup_net(Context *ctx, IdString net_name) +void ripup_net(ArchRWProxy &proxy, Context *ctx, IdString net_name) { auto net_info = ctx->nets.at(net_name).get(); std::vector pips; @@ -90,10 +91,10 @@ void ripup_net(Context *ctx, IdString net_name) } for (auto pip : pips) - ctx->unbindPipUnlocked(pip); + proxy.unbindPip(pip); for (auto wire : wires) - ctx->unbindWireUnlocked(wire); + proxy.unbindWire(wire); NPNR_ASSERT(net_info->wires.empty()); } @@ -114,7 +115,7 @@ struct Router delay_t maxDelay = 0.0; WireId failedDest; - void route(const std::unordered_map &src_wires, WireId dst_wire) + void route(ArchRWProxy &proxy, const std::unordered_map &src_wires, WireId dst_wire) { std::priority_queue, QueuedWire::Greater> queue; @@ -135,6 +136,7 @@ struct Router int thisVisitCnt = 0; int thisVisitCntLimit = 0; + while (!queue.empty() && (thisVisitCntLimit == 0 || thisVisitCnt < thisVisitCntLimit)) { QueuedWire qw = queue.top(); queue.pop(); @@ -148,10 +150,10 @@ struct Router bool foundRipupNet = false; thisVisitCnt++; - if (!ctx->checkWireAvailUnlocked(next_wire)) { + if (!proxy.checkWireAvail(next_wire)) { if (!ripup) continue; - IdString ripupWireNet = ctx->getConflictingWireNetUnlocked(next_wire); + IdString ripupWireNet = proxy.getConflictingWireNet(next_wire); if (ripupWireNet == net_name || ripupWireNet == IdString()) continue; @@ -166,10 +168,10 @@ struct Router foundRipupNet = true; } - if (!ctx->checkPipAvailUnlocked(pip)) { + if (!proxy.checkPipAvail(pip)) { if (!ripup) continue; - IdString ripupPipNet = ctx->getConflictingPipNetUnlocked(pip); + IdString ripupPipNet = proxy.getConflictingPipNet(pip); if (ripupPipNet == net_name || ripupPipNet == IdString()) continue; @@ -227,7 +229,10 @@ struct Router { std::unordered_map src_wires; src_wires[src_wire] = 0; - route(src_wires, dst_wire); + { + auto &&proxy = ctx->rwproxy(); + route(proxy, src_wires, dst_wire); + } routedOkay = visited.count(dst_wire); if (ctx->debug) { @@ -272,7 +277,7 @@ struct Router if (driver_port_it != net_info->driver.cell->pins.end()) driver_port = driver_port_it->second; - auto src_wire = ctx->getWireBelPinUnlocked(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->rproxy().getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); if (src_wire == WireId()) log_error("No wire found for port %s (pin %s) on source cell %s " @@ -286,8 +291,10 @@ struct Router std::unordered_map src_wires; src_wires[src_wire] = 0; - ripup_net(ctx, net_name); - ctx->bindWireUnlocked(src_wire, net_name, STRENGTH_WEAK); + auto &&proxy = ctx->rwproxy(); + + ripup_net(proxy, ctx, net_name); + proxy.bindWire(src_wire, net_name, STRENGTH_WEAK); std::vector users_array = net_info->users; ctx->shuffle(users_array); @@ -312,7 +319,7 @@ struct Router if (user_port_it != user_it.cell->pins.end()) user_port = user_port_it->second; - auto dst_wire = ctx->getWireBelPinUnlocked(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = proxy.getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); if (dst_wire == WireId()) log_error("No wire found for port %s (pin %s) on destination " @@ -325,7 +332,7 @@ struct Router log(" Path delay estimate: %.2f\n", float(ctx->estimateDelay(src_wire, dst_wire))); } - route(src_wires, dst_wire); + route(proxy, src_wires, dst_wire); if (visited.count(dst_wire) == 0) { if (ctx->debug) @@ -334,7 +341,7 @@ struct Router else if (ripup) log_info("Failed to route %s -> %s.\n", ctx->getWireName(src_wire).c_str(ctx), ctx->getWireName(dst_wire).c_str(ctx)); - ripup_net(ctx, net_name); + ripup_net(proxy, ctx, net_name); failedDest = dst_wire; return; } @@ -355,15 +362,15 @@ struct Router if (src_wires.count(cursor)) break; - IdString conflicting_wire_net = ctx->getConflictingWireNetUnlocked(cursor); + IdString conflicting_wire_net = proxy.getConflictingWireNet(cursor); if (conflicting_wire_net != IdString()) { NPNR_ASSERT(ripup); NPNR_ASSERT(conflicting_wire_net != net_name); - ctx->unbindWireUnlocked(cursor); - if (!ctx->checkWireAvailUnlocked(cursor)) - ripup_net(ctx, conflicting_wire_net); + proxy.unbindWire(cursor); + if (!proxy.checkWireAvail(cursor)) + ripup_net(proxy, ctx, conflicting_wire_net); rippedNets.insert(conflicting_wire_net); scores.wireScores[cursor]++; @@ -372,15 +379,15 @@ struct Router } PipId pip = visited[cursor].pip; - IdString conflicting_pip_net = ctx->getConflictingPipNetUnlocked(pip); + IdString conflicting_pip_net = proxy.getConflictingPipNet(pip); if (conflicting_pip_net != IdString()) { NPNR_ASSERT(ripup); NPNR_ASSERT(conflicting_pip_net != net_name); - ctx->unbindPipUnlocked(pip); - if (!ctx->checkPipAvailUnlocked(pip)) - ripup_net(ctx, conflicting_pip_net); + proxy.unbindPip(pip); + if (!proxy.checkPipAvail(pip)) + ripup_net(proxy, ctx, conflicting_pip_net); rippedNets.insert(conflicting_pip_net); scores.pipScores[visited[cursor].pip]++; @@ -388,7 +395,7 @@ struct Router scores.netPipScores[std::make_pair(conflicting_pip_net, visited[cursor].pip)]++; } - ctx->bindPipUnlocked(visited[cursor].pip, net_name, STRENGTH_WEAK); + proxy.bindPip(visited[cursor].pip, net_name, STRENGTH_WEAK); src_wires[cursor] = visited[cursor].delay; cursor = ctx->getPipSrcWire(visited[cursor].pip); } @@ -437,45 +444,48 @@ bool router1(Context *ctx) delay_t estimatedTotalDelay = 0.0; int estimatedTotalDelayCnt = 0; - for (auto net_name : netsQueue) { - auto net_info = ctx->nets.at(net_name).get(); + { + auto &&proxy = ctx->rproxy(); + for (auto net_name : netsQueue) { + auto net_info = ctx->nets.at(net_name).get(); - auto src_bel = net_info->driver.cell->bel; + auto src_bel = net_info->driver.cell->bel; - if (src_bel == BelId()) - continue; + if (src_bel == BelId()) + continue; - IdString driver_port = net_info->driver.port; + IdString driver_port = net_info->driver.port; - auto driver_port_it = net_info->driver.cell->pins.find(driver_port); - if (driver_port_it != net_info->driver.cell->pins.end()) - driver_port = driver_port_it->second; + auto driver_port_it = net_info->driver.cell->pins.find(driver_port); + if (driver_port_it != net_info->driver.cell->pins.end()) + driver_port = driver_port_it->second; - auto src_wire = ctx->getWireBelPinUnlocked(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = proxy.getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); - if (src_wire == WireId()) - continue; + if (src_wire == WireId()) + continue; - for (auto &user_it : net_info->users) { - auto dst_bel = user_it.cell->bel; + for (auto &user_it : net_info->users) { + auto dst_bel = user_it.cell->bel; - if (dst_bel == BelId()) - continue; + if (dst_bel == BelId()) + continue; - IdString user_port = user_it.port; + IdString user_port = user_it.port; - auto user_port_it = user_it.cell->pins.find(user_port); + auto user_port_it = user_it.cell->pins.find(user_port); - if (user_port_it != user_it.cell->pins.end()) - user_port = user_port_it->second; + if (user_port_it != user_it.cell->pins.end()) + user_port = user_port_it->second; - auto dst_wire = ctx->getWireBelPinUnlocked(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = proxy.getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); - if (dst_wire == WireId()) - continue; + if (dst_wire == WireId()) + continue; - estimatedTotalDelay += ctx->estimateDelay(src_wire, dst_wire); - estimatedTotalDelayCnt++; + estimatedTotalDelay += ctx->estimateDelay(src_wire, dst_wire); + estimatedTotalDelayCnt++; + } } } diff --git a/ice40/arch.cc b/ice40/arch.cc index 6c00f0d2..7c6af263 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -28,6 +29,16 @@ NEXTPNR_NAMESPACE_BEGIN +ArchRWProxy Arch::rwproxy(void) { + ArchRWProxy res(this); + return res; +} + +ArchRProxy Arch::rproxy(void) const { + ArchRProxy res(this); + return res; +} + // ----------------------------------------------------------------------- IdString Arch::belTypeToId(BelType type) const @@ -239,28 +250,6 @@ IdString Arch::archArgsToId(ArchArgs args) const // ----------------------------------------------------------------------- -BelId Arch::getBelByName(IdString name) const -{ - boost::lock_guard lock(mtx_); - return getBelByNameUnlocked(name); -} - -BelId Arch::getBelByNameUnlocked(IdString name) const -{ - BelId ret; - - if (bel_by_name.empty()) { - for (int i = 0; i < chip_info->num_bels; i++) - bel_by_name[id(chip_info->bel_data[i].name.get())] = i; - } - - auto it = bel_by_name.find(name); - if (it != bel_by_name.end()) - ret.index = it->second; - - return ret; -} - BelRange Arch::getBelsAtSameTile(BelId bel) const { BelRange br; @@ -279,81 +268,105 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const return br; } -WireId Arch::getWireBelPin(BelId bel, PortPin pin) const +// ----------------------------------------------------------------------- +// Shorthands to ArchProxy + +BelId Arch::getBelByName(IdString name) const { - boost::shared_lock_guard lock(mtx_); - return getWireBelPinUnlocked(bel, pin); + return rproxy().getBelByName(name); } -WireId Arch::getWireBelPinUnlocked(BelId bel, PortPin pin) const +void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength) { - WireId ret; + rwproxy().bindWire(wire, net, strength); +} - NPNR_ASSERT(bel != BelId()); +void Arch::unbindWire(WireId wire) +{ + rwproxy().unbindWire(wire); +} - int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); +void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength) { + rwproxy().bindBel(bel, cell, strength); +} - for (int i = 0; i < num_bel_wires; i++) - if (bel_wires[i].port == pin) { - ret.index = bel_wires[i].wire_index; - break; - } +void Arch::unbindBel(BelId bel) +{ + rwproxy().unbindBel(bel); +} - return ret; +bool Arch::checkBelAvail(BelId bel) const +{ + return rproxy().checkBelAvail(bel); } -// ----------------------------------------------------------------------- +IdString Arch::getBoundBelCell(BelId bel) const +{ + return rproxy().getBoundBelCell(bel); +} -WireId Arch::getWireByName(IdString name) const +IdString Arch::getConflictingBelCell(BelId bel) const { - boost::shared_lock_guard lock(mtx_); - return getWireByNameUnlocked(name); + return rproxy().getConflictingBelCell(bel); } -WireId Arch::getWireByNameUnlocked(IdString name) const +WireId Arch::getWireByName(IdString name) const { - WireId ret; + return rproxy().getWireByName(name); +} - if (wire_by_name.empty()) { - for (int i = 0; i < chip_info->num_wires; i++) - wire_by_name[id(chip_info->wire_data[i].name.get())] = i; - } +WireId Arch::getWireBelPin(BelId bel, PortPin pin) const +{ + return rproxy().getWireBelPin(bel, pin); +} - auto it = wire_by_name.find(name); - if (it != wire_by_name.end()) - ret.index = it->second; +bool Arch::checkWireAvail(WireId wire) const +{ + return rproxy().checkWireAvail(wire); +} - return ret; +IdString Arch::getBoundWireNet(WireId wire) const +{ + return rproxy().getBoundWireNet(wire); } -// ----------------------------------------------------------------------- +IdString Arch::getConflictingWireNet(WireId wire) const +{ + return rproxy().getConflictingWireNet(wire); +} PipId Arch::getPipByName(IdString name) const { - boost::shared_lock_guard lock(mtx_); - return getPipByNameUnlocked(name); + return rproxy().getPipByName(name); } -PipId Arch::getPipByNameUnlocked(IdString name) const +void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength) { - PipId ret; + return rwproxy().bindPip(pip, net, strength); +} - if (pip_by_name.empty()) { - for (int i = 0; i < chip_info->num_pips; i++) { - PipId pip; - pip.index = i; - pip_by_name[getPipName(pip)] = i; - } - } +void Arch::unbindPip(PipId pip) +{ + return rwproxy().unbindPip(pip); +} - auto it = pip_by_name.find(name); - if (it != pip_by_name.end()) - ret.index = it->second; +bool Arch::checkPipAvail(PipId pip) const +{ + return rproxy().checkPipAvail(pip); +} - return ret; +IdString Arch::getBoundPipNet(PipId pip) const +{ + return rproxy().getBoundPipNet(pip); } +IdString Arch::getConflictingPipNet(PipId pip) const +{ + return rproxy().getConflictingPipNet(pip); +} + +// ----------------------------------------------------------------------- + IdString Arch::getPipName(PipId pip) const { NPNR_ASSERT(pip != PipId()); @@ -682,4 +695,216 @@ bool Arch::isGlobalNet(const NetInfo *net) const return net->driver.cell != nullptr && net->driver.port == id_glb_buf_out; } +// ----------------------------------------------------------------------- + +bool ArchRProxyMethods::checkBelAvail(BelId bel) const +{ + NPNR_ASSERT(bel != BelId()); + return parent_->bel_to_cell[bel.index] == IdString(); +} + +IdString ArchRProxyMethods::getBoundBelCell(BelId bel) const +{ + NPNR_ASSERT(bel != BelId()); + return parent_->bel_to_cell[bel.index]; +} + +IdString ArchRProxyMethods::getConflictingBelCell(BelId bel) const +{ + NPNR_ASSERT(bel != BelId()); + return parent_->bel_to_cell[bel.index]; +} + +WireId ArchRProxyMethods::getWireBelPin(BelId bel, PortPin pin) const +{ + WireId ret; + + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = parent_->chip_info->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = parent_->chip_info->bel_data[bel.index].bel_wires.get(); + + for (int i = 0; i < num_bel_wires; i++) + if (bel_wires[i].port == pin) { + ret.index = bel_wires[i].wire_index; + break; + } + + return ret; +} + +WireId ArchRProxyMethods::getWireByName(IdString name) const +{ + WireId ret; + + if (parent_->wire_by_name.empty()) { + for (int i = 0; i < parent_->chip_info->num_wires; i++) + parent_->wire_by_name[parent_->id(parent_->chip_info->wire_data[i].name.get())] = i; + } + + auto it = parent_->wire_by_name.find(name); + if (it != parent_->wire_by_name.end()) + ret.index = it->second; + + return ret; +} + +bool ArchRProxyMethods::checkWireAvail(WireId wire) const +{ + NPNR_ASSERT(wire != WireId()); + return parent_->wire_to_net[wire.index] == IdString(); +} + +IdString ArchRProxyMethods::getBoundWireNet(WireId wire) const +{ + NPNR_ASSERT(wire != WireId()); + return parent_->wire_to_net[wire.index]; +} + +IdString ArchRProxyMethods::getConflictingWireNet(WireId wire) const +{ + NPNR_ASSERT(wire != WireId()); + return parent_->wire_to_net[wire.index]; +} + +PipId ArchRProxyMethods::getPipByName(IdString name) const +{ + PipId ret; + + if (parent_->pip_by_name.empty()) { + for (int i = 0; i < parent_->chip_info->num_pips; i++) { + PipId pip; + pip.index = i; + parent_->pip_by_name[parent_->getPipName(pip)] = i; + } + } + + auto it = parent_->pip_by_name.find(name); + if (it != parent_->pip_by_name.end()) + ret.index = it->second; + + return ret; +} + +bool ArchRProxyMethods::checkPipAvail(PipId pip) const +{ + NPNR_ASSERT(pip != PipId()); + return parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] == IdString(); +} + +IdString ArchRProxyMethods::getBoundPipNet(PipId pip) const +{ + NPNR_ASSERT(pip != PipId()); + return parent_->pip_to_net[pip.index]; +} + +IdString ArchRProxyMethods::getConflictingPipNet(PipId pip) const +{ + NPNR_ASSERT(pip != PipId()); + return parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index]; +} + +BelId ArchRProxyMethods::getBelByName(IdString name) const +{ + BelId ret; + + if (parent_->bel_by_name.empty()) { + for (int i = 0; i < parent_->chip_info->num_bels; i++) + parent_->bel_by_name[parent_->id(parent_->chip_info->bel_data[i].name.get())] = i; + } + + auto it = parent_->bel_by_name.find(name); + if (it != parent_->bel_by_name.end()) + ret.index = it->second; + + return ret; +} + +// ----------------------------------------------------------------------- + +void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) +{ + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(parent_->wire_to_net[wire.index] == IdString()); + + parent_->wire_to_net[wire.index] = net; + parent_->nets[net]->wires[wire].pip = PipId(); + parent_->nets[net]->wires[wire].strength = strength; +} + +void ArchRWProxyMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) +{ + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(parent_->bel_to_cell[bel.index] == IdString()); + parent_->bel_to_cell[bel.index] = cell; + parent_->cells[cell]->bel = bel; + parent_->cells[cell]->belStrength = strength; +} + +void ArchRWProxyMethods::unbindBel(BelId bel) +{ + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(parent_->bel_to_cell[bel.index] != IdString()); + parent_->cells[parent_->bel_to_cell[bel.index]]->bel = BelId(); + parent_->cells[parent_->bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; + parent_->bel_to_cell[bel.index] = IdString(); +} + +void ArchRWProxyMethods::unbindWire(WireId wire) +{ + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(parent_->wire_to_net[wire.index] != IdString()); + + auto &net_wires = parent_->nets[parent_->wire_to_net[wire.index]]->wires; + auto it = net_wires.find(wire); + NPNR_ASSERT(it != net_wires.end()); + + auto pip = it->second.pip; + if (pip != PipId()) { + parent_->pip_to_net[pip.index] = IdString(); + parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString(); + } + + net_wires.erase(it); + parent_->wire_to_net[wire.index] = IdString(); +} + +void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) +{ + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(parent_->pip_to_net[pip.index] == IdString()); + NPNR_ASSERT(parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] == IdString()); + + parent_->pip_to_net[pip.index] = net; + parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = net; + + WireId dst; + dst.index = parent_->chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(parent_->wire_to_net[dst.index] == IdString()); + parent_->wire_to_net[dst.index] = net; + parent_->nets[net]->wires[dst].pip = pip; + parent_->nets[net]->wires[dst].strength = strength; +} + +void ArchRWProxyMethods::unbindPip(PipId pip) +{ + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(parent_->pip_to_net[pip.index] != IdString()); + NPNR_ASSERT(parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] != IdString()); + + WireId dst; + dst.index = parent_->chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(parent_->wire_to_net[dst.index] != IdString()); + parent_->wire_to_net[dst.index] = IdString(); + parent_->nets[parent_->pip_to_net[pip.index]]->wires.erase(dst); + + parent_->pip_to_net[pip.index] = IdString(); + parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString(); +} + +CellInfo *ArchRWProxyMethods::getCell(IdString cell) +{ + return parent_->cells.at(cell).get(); +} + NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index ab66e7d8..4462ce9e 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -327,27 +328,40 @@ struct ArchArgs std::string package; }; +class ArchRWProxyMethods; +class ArchRProxyMethods; +class ArchRWProxy; +class ArchRProxy; + class Arch : public BaseCtx { + friend class ArchRWProxyMethods; + friend class ArchRProxyMethods; + friend class ArchRWProxy; + friend class ArchRProxy; private: // All of the following... std::vector bel_to_cell; std::vector wire_to_net; std::vector pip_to_net; std::vector switches_locked; + mutable std::unordered_map bel_by_name; + mutable std::unordered_map wire_by_name; + mutable std::unordered_map pip_by_name; + // ... are guarded by the following lock: mutable boost::shared_mutex mtx_; + public: const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; - mutable std::unordered_map bel_by_name; - mutable std::unordered_map wire_by_name; - mutable std::unordered_map pip_by_name; - ArchArgs args; Arch(ArchArgs args); + ArchRWProxy rwproxy(void); + ArchRProxy rproxy(void) const; + std::string getChipName(); IdString archId() const { return id("ice40"); } @@ -361,8 +375,33 @@ public: // ------------------------------------------------- + /// Wrappers around getting a r(w)proxy and calling a single method. + // Deprecated: please acquire a proxy yourself and call the methods + // you want on it. + void unbindWire(WireId wire); + void unbindPip(PipId pip); + void unbindBel(BelId bel); + void bindWire(WireId wire, IdString net, PlaceStrength strength); + void bindPip(PipId pip, IdString net, PlaceStrength strength); + void bindBel(BelId bel, IdString cell, PlaceStrength strength); + bool checkWireAvail(WireId wire) const; + bool checkPipAvail(PipId pip) const; + bool checkBelAvail(BelId bel) const; + WireId getWireByName(IdString name) const; + WireId getWireBelPin(BelId bel, PortPin pin) const; + PipId getPipByName(IdString name) const; + IdString getConflictingWireNet(WireId wire) const; + IdString getConflictingPipNet(PipId pip) const; + IdString getConflictingBelCell(BelId bel) const; + IdString getBoundWireNet(WireId wire) const; + IdString getBoundPipNet(PipId pip) const; + IdString getBoundBelCell(BelId bel) const; BelId getBelByName(IdString name) const; - BelId getBelByNameUnlocked(IdString name) const; + + // ------------------------------------------------- + + /// Methods to get chip info - don't need to use a wrapper, as these are + /// static per lifetime of object. IdString getBelName(BelId bel) const { @@ -370,71 +409,9 @@ public: return id(chip_info->bel_data[bel.index].name.get()); } - uint32_t getBelChecksum(BelId bel) const { return bel.index; } - - void bindBel(BelId bel, IdString cell, PlaceStrength strength) { - boost::lock_guard lock(mtx_); - bindBelUnlocked(bel, cell, strength); - } - - void bindBelUnlocked(BelId bel, IdString cell, PlaceStrength strength) - { - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); - bel_to_cell[bel.index] = cell; - cells[cell]->bel = bel; - cells[cell]->belStrength = strength; - } - - void unbindBel(BelId bel) + uint32_t getBelChecksum(BelId bel) const { - boost::lock_guard lock(mtx_); - unbindBelUnlocked(bel); - } - - void unbindBelUnlocked(BelId bel) - { - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); - cells[bel_to_cell[bel.index]]->bel = BelId(); - cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; - bel_to_cell[bel.index] = IdString(); - } - - bool checkBelAvail(BelId bel) const - { - boost::shared_lock_guard lock(mtx_); - return checkBelAvailUnlocked(bel); - } - - bool checkBelAvailUnlocked(BelId bel) const - { - NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index] == IdString(); - } - - IdString getBoundBelCell(BelId bel) const - { - boost::shared_lock_guard lock(mtx_); - return getBoundBelCellUnlocked(bel); - } - - IdString getBoundBelCellUnlocked(BelId bel) const - { - NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index]; - } - - IdString getConflictingBelCell(BelId bel) const - { - boost::shared_lock_guard lock(mtx_); - return getConflictingBelCellUnlocked(bel); - } - - IdString getConflictingBelCellUnlocked(BelId bel) const - { - NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index]; + return bel.index; } BelRange getBels() const @@ -467,8 +444,6 @@ public: return chip_info->bel_data[bel.index].type; } - WireId getWireBelPin(BelId bel, PortPin pin) const; - WireId getWireBelPinUnlocked(BelId bel, PortPin pin) const; BelPin getBelPinUphill(WireId wire) const { @@ -494,9 +469,6 @@ public: // ------------------------------------------------- - WireId getWireByName(IdString name) const; - WireId getWireByNameUnlocked(IdString name) const; - IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); @@ -505,82 +477,6 @@ public: uint32_t getWireChecksum(WireId wire) const { return wire.index; } - void bindWire(WireId wire, IdString net, PlaceStrength strength) - { - boost::lock_guard lock(mtx_); - bindWireUnlocked(wire, net, strength); - } - - void bindWireUnlocked(WireId wire, IdString net, PlaceStrength strength) - { - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] == IdString()); - - wire_to_net[wire.index] = net; - nets[net]->wires[wire].pip = PipId(); - nets[net]->wires[wire].strength = strength; - } - - void unbindWire(WireId wire) - { - boost::lock_guard lock(mtx_); - unbindWireUnlocked(wire); - } - - void unbindWireUnlocked(WireId wire) - { - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] != IdString()); - - auto &net_wires = nets[wire_to_net[wire.index]]->wires; - auto it = net_wires.find(wire); - NPNR_ASSERT(it != net_wires.end()); - - auto pip = it->second.pip; - if (pip != PipId()) { - pip_to_net[pip.index] = IdString(); - switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); - } - - net_wires.erase(it); - wire_to_net[wire.index] = IdString(); - } - - bool checkWireAvail(WireId wire) const - { - boost::shared_lock_guard lock(mtx_); - return checkWireAvailUnlocked(wire); - } - - bool checkWireAvailUnlocked(WireId wire) const - { - NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index] == IdString(); - } - - IdString getBoundWireNet(WireId wire) const - { - boost::shared_lock_guard lock(mtx_); - return getBoundWireNetUnlocked(wire); - } - - IdString getBoundWireNetUnlocked(WireId wire) const - { - NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; - } - - IdString getConflictingWireNet(WireId wire) const - { - boost::shared_lock_guard lock(mtx_); - return getConflictingWireNetUnlocked(wire); - } - - IdString getConflictingWireNetUnlocked(WireId wire) const - { - NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; - } WireRange getWires() const { @@ -592,93 +488,10 @@ public: // ------------------------------------------------- - PipId getPipByName(IdString name) const; - PipId getPipByNameUnlocked(IdString name) const; IdString getPipName(PipId pip) const; uint32_t getPipChecksum(PipId pip) const { return pip.index; } - void bindPip(PipId pip, IdString net, PlaceStrength strength) - { - boost::lock_guard lock(mtx_); - bindPipUnlocked(pip, net, strength); - } - - void bindPipUnlocked(PipId pip, IdString net, PlaceStrength strength) - { - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip.index] == IdString()); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); - - pip_to_net[pip.index] = net; - switches_locked[chip_info->pip_data[pip.index].switch_index] = net; - - WireId dst; - dst.index = chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst.index] == IdString()); - wire_to_net[dst.index] = net; - nets[net]->wires[dst].pip = pip; - nets[net]->wires[dst].strength = strength; - } - - void unbindPip(PipId pip) - { - boost::lock_guard lock(mtx_); - unbindPipUnlocked(pip); - } - - void unbindPipUnlocked(PipId pip) - { - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip.index] != IdString()); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); - - WireId dst; - dst.index = chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst.index] != IdString()); - wire_to_net[dst.index] = IdString(); - nets[pip_to_net[pip.index]]->wires.erase(dst); - - pip_to_net[pip.index] = IdString(); - switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); - } - - bool checkPipAvail(PipId pip) const - { - boost::shared_lock_guard lock(mtx_); - return checkPipAvailUnlocked(pip); - } - - bool checkPipAvailUnlocked(PipId pip) const - { - NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); - } - - IdString getBoundPipNet(PipId pip) const - { - boost::shared_lock_guard lock(mtx_); - return getBoundPipNetUnlocked(pip); - } - - IdString getBoundPipNetUnlocked(PipId pip) const - { - NPNR_ASSERT(pip != PipId()); - return pip_to_net[pip.index]; - } - - IdString getConflictingPipNet(PipId pip) const - { - boost::shared_lock_guard lock(mtx_); - return getConflictingPipNetUnlocked(pip); - } - - IdString getConflictingPipNetUnlocked(PipId pip) const - { - NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index]; - } - AllPipRange getPips() const { AllPipRange range; @@ -789,7 +602,26 @@ public: // ------------------------------------------------- - // Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) + IdString id_glb_buf_out; + IdString id_icestorm_lc, id_sb_io, id_sb_gb; + IdString id_cen, id_clk, id_sr; + IdString id_i0, id_i1, id_i2, id_i3; + IdString id_dff_en, id_neg_clk; +}; + +class ArchRProxyMethods { + friend class ArchRProxy; + friend class ArchRWProxy; +private: + const Arch *parent_; + ArchRProxyMethods(const Arch *parent) : parent_(parent) {} + ArchRProxyMethods(ArchRProxyMethods &&other) noexcept : parent_(other.parent_) {} + ArchRProxyMethods(const ArchRProxyMethods &other) : parent_(other.parent_) {} + +public: + ~ArchRProxyMethods() noexcept { } + + /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) // Whether or not a given cell can be placed at a given Bel // This is not intended for Bel type checks, but finer-grained constraints @@ -802,11 +634,88 @@ public: // Helper function for above bool logicCellsCompatible(const std::vector &cells) const; - IdString id_glb_buf_out; - IdString id_icestorm_lc, id_sb_io, id_sb_gb; - IdString id_cen, id_clk, id_sr; - IdString id_i0, id_i1, id_i2, id_i3; - IdString id_dff_en, id_neg_clk; + bool checkWireAvail(WireId wire) const; + bool checkPipAvail(PipId pip) const; + bool checkBelAvail(BelId bel) const; + + WireId getWireByName(IdString name) const; + WireId getWireBelPin(BelId bel, PortPin pin) const; + PipId getPipByName(IdString name) const; + + + IdString getConflictingWireNet(WireId wire) const; + IdString getConflictingPipNet(PipId pip) const; + IdString getConflictingBelCell(BelId bel) const; + + IdString getBoundWireNet(WireId wire) const; + IdString getBoundPipNet(PipId pip) const; + IdString getBoundBelCell(BelId bel) const; + + BelId getBelByName(IdString name) const; +}; + +class ArchRProxy : public ArchRProxyMethods { + friend class Arch; + friend class ArchRWProxy; +private: + boost::shared_mutex *lock_; + ArchRProxy(const Arch *parent) : ArchRProxyMethods(parent), lock_(&parent->mtx_) + { + lock_->lock_shared(); + } + +public: + ~ArchRProxy() { + if (lock_ != nullptr) { + lock_->unlock_shared(); + } + } + ArchRProxy(ArchRProxy &&other) : ArchRProxyMethods(other), lock_(other.lock_) + { + other.lock_ = nullptr; + } +}; + +class ArchRWProxyMethods { + friend class ArchRWProxy; +private: + Arch *parent_; + ArchRWProxyMethods(Arch *parent) : parent_(parent) {} + ArchRWProxyMethods(ArchRWProxyMethods &&other) : parent_(other.parent_) {} + ArchRWProxyMethods(const ArchRWProxyMethods &other) : parent_(other.parent_) {} +public: + ~ArchRWProxyMethods() {} + + void unbindWire(WireId wire); + void unbindPip(PipId pip); + void unbindBel(BelId bel); + void bindWire(WireId wire, IdString net, PlaceStrength strength); + void bindPip(PipId pip, IdString net, PlaceStrength strength); + void bindBel(BelId bel, IdString cell, PlaceStrength strength); + CellInfo *getCell(IdString cell); +}; + +class ArchRWProxy : public ArchRProxyMethods, public ArchRWProxyMethods { + friend class Arch; +private: + boost::shared_mutex *lock_; + ArchRWProxy(Arch *parent) : ArchRProxyMethods(parent), ArchRWProxyMethods(parent), lock_(&parent->mtx_) { + lock_->lock(); + } + +public: + ArchRWProxy(ArchRWProxy &&other) : ArchRProxyMethods(other), ArchRWProxyMethods(other), lock_(other.lock_) + { + other.lock_ = nullptr; + } + ~ArchRWProxy() + { + if (lock_ != nullptr) { + lock_->unlock(); + } + } + + }; NEXTPNR_NAMESPACE_END diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index c9dd26c5..cb7c44b8 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -3,6 +3,7 @@ * * Copyright (C) 2018 Clifford Wolf * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,44 +25,44 @@ NEXTPNR_NAMESPACE_BEGIN -bool Arch::logicCellsCompatible(const std::vector &cells) const +bool ArchRProxyMethods::logicCellsCompatible(const std::vector &cells) const { bool dffs_exist = false, dffs_neg = false; const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; int locals_count = 0; for (auto cell : cells) { - if (bool_or_default(cell->params, id_dff_en)) { + if (bool_or_default(cell->params, parent_->id_dff_en)) { if (!dffs_exist) { dffs_exist = true; - cen = get_net_or_empty(cell, id_cen); - clk = get_net_or_empty(cell, id_clk); - sr = get_net_or_empty(cell, id_sr); + cen = get_net_or_empty(cell, parent_->id_cen); + clk = get_net_or_empty(cell, parent_->id_clk); + sr = get_net_or_empty(cell, parent_->id_sr); - if (!isGlobalNet(cen) && cen != nullptr) + if (!parent_->isGlobalNet(cen) && cen != nullptr) locals_count++; - if (!isGlobalNet(clk) && clk != nullptr) + if (!parent_->isGlobalNet(clk) && clk != nullptr) locals_count++; - if (!isGlobalNet(sr) && sr != nullptr) + if (!parent_->isGlobalNet(sr) && sr != nullptr) locals_count++; - if (bool_or_default(cell->params, id_neg_clk)) { + if (bool_or_default(cell->params, parent_->id_neg_clk)) { dffs_neg = true; } } else { - if (cen != get_net_or_empty(cell, id_cen)) + if (cen != get_net_or_empty(cell, parent_->id_cen)) return false; - if (clk != get_net_or_empty(cell, id_clk)) + if (clk != get_net_or_empty(cell, parent_->id_clk)) return false; - if (sr != get_net_or_empty(cell, id_sr)) + if (sr != get_net_or_empty(cell, parent_->id_sr)) return false; - if (dffs_neg != bool_or_default(cell->params, id_neg_clk)) + if (dffs_neg != bool_or_default(cell->params, parent_->id_neg_clk)) return false; } } - const NetInfo *i0 = get_net_or_empty(cell, id_i0), *i1 = get_net_or_empty(cell, id_i1), - *i2 = get_net_or_empty(cell, id_i2), *i3 = get_net_or_empty(cell, id_i3); + const NetInfo *i0 = get_net_or_empty(cell, parent_->id_i0), *i1 = get_net_or_empty(cell, parent_->id_i1), + *i2 = get_net_or_empty(cell, parent_->id_i2), *i3 = get_net_or_empty(cell, parent_->id_i3); if (i0 != nullptr) locals_count++; if (i1 != nullptr) @@ -75,57 +76,57 @@ bool Arch::logicCellsCompatible(const std::vector &cells) cons return locals_count <= 32; } -bool Arch::isBelLocationValid(BelId bel) const +bool ArchRProxyMethods::isBelLocationValid(BelId bel) const { - if (getBelType(bel) == TYPE_ICESTORM_LC) { + if (parent_->getBelType(bel) == TYPE_ICESTORM_LC) { std::vector bel_cells; - for (auto bel_other : getBelsAtSameTile(bel)) { - IdString cell_other = getBoundBelCellUnlocked(bel_other); + for (auto bel_other : parent_->getBelsAtSameTile(bel)) { + IdString cell_other = getBoundBelCell(bel_other); if (cell_other != IdString()) { - const CellInfo *ci_other = cells.at(cell_other).get(); + const CellInfo *ci_other = parent_->cells.at(cell_other).get(); bel_cells.push_back(ci_other); } } return logicCellsCompatible(bel_cells); } else { - IdString cellId = getBoundBelCellUnlocked(bel); + IdString cellId = getBoundBelCell(bel); if (cellId == IdString()) return true; else - return isValidBelForCell(cells.at(cellId).get(), bel); + return isValidBelForCell(parent_->cells.at(cellId).get(), bel); } } -bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const +bool ArchRProxyMethods::isValidBelForCell(CellInfo *cell, BelId bel) const { - if (cell->type == id_icestorm_lc) { - NPNR_ASSERT(getBelType(bel) == TYPE_ICESTORM_LC); + if (cell->type == parent_->id_icestorm_lc) { + NPNR_ASSERT(parent_->getBelType(bel) == TYPE_ICESTORM_LC); std::vector bel_cells; - for (auto bel_other : getBelsAtSameTile(bel)) { - IdString cell_other = getBoundBelCellUnlocked(bel_other); + for (auto bel_other : parent_->getBelsAtSameTile(bel)) { + IdString cell_other = getBoundBelCell(bel_other); if (cell_other != IdString() && bel_other != bel) { - const CellInfo *ci_other = cells.at(cell_other).get(); + const CellInfo *ci_other = parent_->cells.at(cell_other).get(); bel_cells.push_back(ci_other); } } bel_cells.push_back(cell); return logicCellsCompatible(bel_cells); - } else if (cell->type == id_sb_io) { - return getBelPackagePin(bel) != ""; - } else if (cell->type == id_sb_gb) { + } else if (cell->type == parent_->id_sb_io) { + return parent_->getBelPackagePin(bel) != ""; + } else if (cell->type == parent_->id_sb_gb) { bool is_reset = false, is_cen = false; - NPNR_ASSERT(cell->ports.at(id_glb_buf_out).net != nullptr); - for (auto user : cell->ports.at(id_glb_buf_out).net->users) { - if (is_reset_port(this, user)) + NPNR_ASSERT(cell->ports.at(parent_->id_glb_buf_out).net != nullptr); + for (auto user : cell->ports.at(parent_->id_glb_buf_out).net->users) { + if (is_reset_port(parent_, user)) is_reset = true; - if (is_enable_port(this, user)) + if (is_enable_port(parent_, user)) is_cen = true; } - IdString glb_net = getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT)); - int glb_id = std::stoi(std::string("") + glb_net.str(this).back()); + IdString glb_net = parent_->getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT)); + int glb_id = std::stoi(std::string("") + glb_net.str(parent_).back()); if (is_reset && is_cen) return false; else if (is_reset) diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index d42188f0..10a6f3ff 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -119,13 +119,17 @@ class PlacementLegaliser bool legalise() { - log_info("Legalising design..\n"); + log_info("Legalising logic cells...\n"); init_logic_cells(); + log_info("Legalising carries...\n"); bool legalised_carries = legalise_carries(); if (!legalised_carries && !ctx->force) return false; + log_info("Legalising others...\n"); legalise_others(); + log_info("Legalising logic tiles...\n"); legalise_logic_tiles(); + log_info("Replacing cells...\n"); bool replaced_cells = replace_cells(); return legalised_carries && replaced_cells; } @@ -133,6 +137,7 @@ class PlacementLegaliser private: void init_logic_cells() { + auto &&proxy = ctx->rproxy(); for (auto bel : ctx->getBels()) { // Initialise the logic bels vector with unavailable invalid bels, dimensions [0..width][0..height[0..7] logic_bels.resize(ctx->chip_info->width + 1, @@ -143,7 +148,7 @@ class PlacementLegaliser // Using the non-standard API here to get (x, y, z) rather than just (x, y) auto bi = ctx->chip_info->bel_data[bel.index]; int x = bi.x, y = bi.y, z = bi.z; - IdString cell = ctx->getBoundBelCellUnlocked(bel); + IdString cell = proxy.getBoundBelCell(bel); if (cell != IdString() && ctx->cells.at(cell)->belStrength >= STRENGTH_FIXED) logic_bels.at(x).at(y).at(z) = std::make_pair(bel, true); // locked out of use else @@ -195,28 +200,33 @@ class PlacementLegaliser } } bool success = true; + // Find midpoints for all chains, before we start tearing them up std::vector all_chains; - for (auto &base_chain : carry_chains) { - if (ctx->verbose) { - log_info("Found carry chain: \n"); - for (auto entry : base_chain.cells) - log_info(" %s\n", entry->name.c_str(ctx)); - log_info("\n"); - } - std::vector split_chains = split_carry_chain(base_chain); - for (auto &chain : split_chains) { - get_chain_midpoint(ctx, chain, chain.mid_x, chain.mid_y); - all_chains.push_back(chain); + { + auto &&proxy = ctx->rproxy(); + for (auto &base_chain : carry_chains) { + if (ctx->verbose) { + log_info("Found carry chain: \n"); + for (auto entry : base_chain.cells) + log_info(" %s\n", entry->name.c_str(ctx)); + log_info("\n"); + } + std::vector split_chains = split_carry_chain(proxy, base_chain); + for (auto &chain : split_chains) { + get_chain_midpoint(ctx, chain, chain.mid_x, chain.mid_y); + all_chains.push_back(chain); + } } } // Actual chain placement + auto &&proxy = ctx->rwproxy(); for (auto &chain : all_chains) { if (ctx->verbose) log_info("Placing carry chain starting at '%s'\n", chain.cells.front()->name.c_str(ctx)); float base_x = chain.mid_x, base_y = chain.mid_y - (chain.cells.size() / 16.0f); // Find Bel meeting requirements closest to the target base, returning location as - auto chain_origin_bel = find_closest_bel(base_x, base_y, chain); + auto chain_origin_bel = find_closest_bel(proxy, base_x, base_y, chain); int place_x = std::get<0>(chain_origin_bel), place_y = std::get<1>(chain_origin_bel), place_z = std::get<2>(chain_origin_bel); if (place_x == -1) { @@ -233,7 +243,7 @@ class PlacementLegaliser // Place carry chain for (int i = 0; i < int(chain.cells.size()); i++) { int target_z = place_y * 8 + place_z + i; - place_lc(chain.cells.at(i), place_x, target_z / 8, target_z % 8); + place_lc(proxy, chain.cells.at(i), place_x, target_z / 8, target_z % 8); if (ctx->verbose) log_info(" Cell '%s' placed at (%d, %d, %d)\n", chain.cells.at(i)->name.c_str(ctx), place_x, target_z / 8, target_z % 8); @@ -243,7 +253,7 @@ class PlacementLegaliser } // Find Bel closest to a location, meeting chain requirements - std::tuple find_closest_bel(float target_x, float target_y, CellChain &chain) + std::tuple find_closest_bel(ArchRWProxy &proxy, float target_x, float target_y, CellChain &chain) { std::tuple best_origin = std::make_tuple(-1, -1, -1); wirelen_t best_wirelength = std::numeric_limits::max(); @@ -260,7 +270,7 @@ class PlacementLegaliser valid = false; break; } else { - wirelen += get_cell_wirelength_at_bel(ctx, chain.cells.at(k), lb.first); + wirelen += get_cell_wirelength_at_bel(proxy, ctx, chain.cells.at(k), lb.first); } } if (valid && wirelen < best_wirelength) { @@ -273,7 +283,7 @@ class PlacementLegaliser } // Split a carry chain into multiple legal chains - std::vector split_carry_chain(CellChain &carryc) + std::vector split_carry_chain(const ArchRProxy &proxy, CellChain &carryc) { bool start_of_chain = true; std::vector chains; @@ -298,7 +308,7 @@ class PlacementLegaliser } tile.push_back(cell); chains.back().cells.push_back(cell); - bool split_chain = (!ctx->logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length); + bool split_chain = (!proxy.logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length); if (split_chain) { CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT"))); tile.pop_back(); @@ -325,22 +335,22 @@ class PlacementLegaliser } // Place a logic cell at a given grid location, handling rip-up etc - void place_lc(CellInfo *cell, int x, int y, int z) + void place_lc(ArchRWProxy &proxy, CellInfo *cell, int x, int y, int z) { auto &loc = logic_bels.at(x).at(y).at(z); NPNR_ASSERT(!loc.second); BelId bel = loc.first; // Check if there is a cell presently at the location, which we will need to rip up - IdString existing = ctx->getBoundBelCellUnlocked(bel); + IdString existing = proxy.getBoundBelCell(bel); if (existing != IdString()) { // TODO: keep track of the previous position of the ripped up cell, as a hint rippedCells.insert(existing); - ctx->unbindBelUnlocked(bel); + proxy.unbindBel(bel); } if (cell->bel != BelId()) { - ctx->unbindBelUnlocked(cell->bel); + proxy.unbindBel(cell->bel); } - ctx->bindBelUnlocked(bel, cell->name, STRENGTH_LOCKED); + proxy.bindBel(bel, cell->name, STRENGTH_LOCKED); rippedCells.erase(cell->name); // If cell was ripped up previously, no need to re-place loc.second = true; // Bel is now unavailable for further use } @@ -423,19 +433,20 @@ class PlacementLegaliser // Legalise logic tiles void legalise_logic_tiles() { + auto &&proxy = ctx->rwproxy(); int width = ctx->chip_info->width, height = ctx->chip_info->height; for (int x = 1; x < width; x++) { for (int y = 1; y < height; y++) { BelId tileBel = logic_bels.at(x).at(y).at(0).first; if (tileBel != BelId()) { bool changed = true; - while (!ctx->isBelLocationValid(tileBel) && changed) { + while (!proxy.isBelLocationValid(tileBel) && changed) { changed = false; int max_score = 0; CellInfo *target = nullptr; for (int z = 0; z < 8; z++) { BelId bel = logic_bels.at(x).at(y).at(z).first; - IdString cell = ctx->getBoundBelCellUnlocked(bel); + IdString cell = proxy.getBoundBelCell(bel); if (cell != IdString()) { CellInfo *ci = ctx->cells.at(cell).get(); if (ci->belStrength >= STRENGTH_STRONG) @@ -448,7 +459,7 @@ class PlacementLegaliser } } if (target != nullptr) { - ctx->unbindBelUnlocked(target->bel); + proxy.unbindBel(target->bel); rippedCells.insert(target->name); changed = true; } @@ -461,13 +472,14 @@ class PlacementLegaliser // Legalise other tiles void legalise_others() { + auto &&proxy = ctx->rwproxy(); std::vector legalised_others; for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (!is_lc(ctx, ci)) { if (ci->belStrength < STRENGTH_STRONG && ci->bel != BelId()) { - if (!ctx->isValidBelForCell(ci, ci->bel)) { - place_single_cell(ctx, ci, true); + if (!proxy.isValidBelForCell(ci, ci->bel)) { + place_single_cell(proxy, ctx, ci, true); } legalised_others.push_back(ci); } @@ -482,10 +494,11 @@ class PlacementLegaliser // Replace ripped-up cells bool replace_cells() { + auto &&proxy = ctx->rwproxy(); bool success = true; for (auto cell : sorted(rippedCells)) { CellInfo *ci = ctx->cells.at(cell).get(); - bool placed = place_single_cell(ctx, ci, true); + bool placed = place_single_cell(proxy, ctx, ci, true); if (!placed) { if (ctx->force) { log_warning("failed to place cell '%s' of type '%s'\n", cell.c_str(ctx), ci->type.c_str(ctx)); -- cgit v1.2.3 From dc3256e62fce923a3dc703c521bea5a13cef4443 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 13 Jul 2018 19:20:54 +0100 Subject: Comment arch.h --- ice40/arch.h | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/ice40/arch.h b/ice40/arch.h index 36e34d7b..8428dc29 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -328,15 +328,28 @@ struct ArchArgs std::string package; }; +/// Forward declare proxy classes for Arch. + class ArchRWProxyMethods; class ArchRProxyMethods; class ArchRWProxy; class ArchRProxy; + +/// Arch/Context +// Arch is the main state class of the PnR algorithms. It keeps note of mapped +// cells/nets, locked switches, etc. +// +// In order to mutate state in Arch, you can do one of two things: +// - directly call one of the wrapper methods to mutate state +// - get a read or readwrite proxy to the Arch, and call methods on it + class Arch : public BaseCtx { + // We let proxy methods access our state. friend class ArchRWProxyMethods; friend class ArchRProxyMethods; + // We let proxy objects access our mutex. friend class ArchRWProxy; friend class ArchRProxy; private: @@ -359,7 +372,13 @@ public: ArchArgs args; Arch(ArchArgs args); + // Get a readwrite proxy to arch - this will keep a readwrite lock on the + // entire architecture until the proxy object goes out of scope. ArchRWProxy rwproxy(void); + // Get a read-only proxy to arch - this will keep a read lock on the + // entire architecture until the proxy object goes out of scope. Other read + // locks can be taken while this one still exists. Ie., the UI can draw + // elements while the PnR is going a RO operation. ArchRProxy rproxy(void) const; std::string getChipName(); @@ -378,6 +397,9 @@ public: /// Wrappers around getting a r(w)proxy and calling a single method. // Deprecated: please acquire a proxy yourself and call the methods // you want on it. + // Warning: these will content with locks taken by the r(w)proxies, and + // thus can cause difficult to debug deadlocks - we'll be getting rid of + // them because of that. void unbindWire(WireId wire); void unbindPip(PipId pip); void unbindBel(BelId bel); @@ -554,6 +576,7 @@ public: // ------------------------------------------------- + // TODO(q3k) move this to archproxies? GroupId getGroupByName(IdString name) const; IdString getGroupName(GroupId group) const; std::vector getGroups() const; @@ -564,6 +587,8 @@ public: // ------------------------------------------------- + // These are also specific to the chip and not state, so they're available + // on arch directly. void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; delay_t estimateDelay(WireId src, WireId dst) const; delay_t getDelayEpsilon() const { return 20; } @@ -608,7 +633,9 @@ public: IdString id_dff_en, id_neg_clk; }; +// Read-only methods on Arch that require state access. class ArchRProxyMethods { + // We let proxy objects access our private constructors. friend class ArchRProxy; friend class ArchRWProxy; private: @@ -641,7 +668,6 @@ public: WireId getWireBelPin(BelId bel, PortPin pin) const; PipId getPipByName(IdString name) const; - IdString getConflictingWireNet(WireId wire) const; IdString getConflictingPipNet(PipId pip) const; IdString getConflictingBelCell(BelId bel) const; @@ -653,6 +679,8 @@ public: BelId getBelByName(IdString name) const; }; +// A proxy object that keeps an Arch shared/readonly lock until it goes out +// of scope. All const/read-only ArchRProxyMethods are available on it. class ArchRProxy : public ArchRProxyMethods { friend class Arch; friend class ArchRWProxy; @@ -675,7 +703,9 @@ public: } }; +// State mutating methods on Arch. class ArchRWProxyMethods { + // We let proxy objects access our private constructors. friend class ArchRWProxy; private: Arch *parent_; @@ -691,9 +721,12 @@ public: void bindWire(WireId wire, IdString net, PlaceStrength strength); void bindPip(PipId pip, IdString net, PlaceStrength strength); void bindBel(BelId bel, IdString cell, PlaceStrength strength); + // Returned pointer is valid as long as Proxy object exists. CellInfo *getCell(IdString cell); }; +// A proxy object that keeps an Arch readwrite lock until it goes out of scope. +// All ArchRProxyMethods and ArchRWProxyMethods are available on it. class ArchRWProxy : public ArchRProxyMethods, public ArchRWProxyMethods { friend class Arch; private: -- cgit v1.2.3 From a71b576de6c404572439e30a56c4ff19497523a2 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 13 Jul 2018 19:45:35 +0100 Subject: Slight simplification of proxy code --- ice40/arch.cc | 108 +++++++++++++++++++++++++++++----------------------------- ice40/arch.h | 53 ++++++++++++++++++++-------- 2 files changed, 93 insertions(+), 68 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index af31e147..af6e922c 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -736,19 +736,19 @@ bool Arch::isGlobalNet(const NetInfo *net) const bool ArchRProxyMethods::checkBelAvail(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return parent_->bel_to_cell[bel.index] == IdString(); + return bel_to_cell[bel.index] == IdString(); } IdString ArchRProxyMethods::getBoundBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return parent_->bel_to_cell[bel.index]; + return bel_to_cell[bel.index]; } IdString ArchRProxyMethods::getConflictingBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return parent_->bel_to_cell[bel.index]; + return bel_to_cell[bel.index]; } WireId ArchRProxyMethods::getWireBelPin(BelId bel, PortPin pin) const @@ -757,8 +757,8 @@ WireId ArchRProxyMethods::getWireBelPin(BelId bel, PortPin pin) const NPNR_ASSERT(bel != BelId()); - int num_bel_wires = parent_->chip_info->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = parent_->chip_info->bel_data[bel.index].bel_wires.get(); + int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); for (int i = 0; i < num_bel_wires; i++) if (bel_wires[i].port == pin) { @@ -773,13 +773,13 @@ WireId ArchRProxyMethods::getWireByName(IdString name) const { WireId ret; - if (parent_->wire_by_name.empty()) { - for (int i = 0; i < parent_->chip_info->num_wires; i++) - parent_->wire_by_name[parent_->id(parent_->chip_info->wire_data[i].name.get())] = i; + if (wire_by_name.empty()) { + for (int i = 0; i < chip_info->num_wires; i++) + wire_by_name[parent_->id(chip_info->wire_data[i].name.get())] = i; } - auto it = parent_->wire_by_name.find(name); - if (it != parent_->wire_by_name.end()) + auto it = wire_by_name.find(name); + if (it != wire_by_name.end()) ret.index = it->second; return ret; @@ -788,35 +788,35 @@ WireId ArchRProxyMethods::getWireByName(IdString name) const bool ArchRProxyMethods::checkWireAvail(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return parent_->wire_to_net[wire.index] == IdString(); + return wire_to_net[wire.index] == IdString(); } IdString ArchRProxyMethods::getBoundWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return parent_->wire_to_net[wire.index]; + return wire_to_net[wire.index]; } IdString ArchRProxyMethods::getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return parent_->wire_to_net[wire.index]; + return wire_to_net[wire.index]; } PipId ArchRProxyMethods::getPipByName(IdString name) const { PipId ret; - if (parent_->pip_by_name.empty()) { - for (int i = 0; i < parent_->chip_info->num_pips; i++) { + if (pip_by_name.empty()) { + for (int i = 0; i < chip_info->num_pips; i++) { PipId pip; pip.index = i; - parent_->pip_by_name[parent_->getPipName(pip)] = i; + pip_by_name[parent_->getPipName(pip)] = i; } } - auto it = parent_->pip_by_name.find(name); - if (it != parent_->pip_by_name.end()) + auto it = pip_by_name.find(name); + if (it != pip_by_name.end()) ret.index = it->second; return ret; @@ -825,32 +825,32 @@ PipId ArchRProxyMethods::getPipByName(IdString name) const bool ArchRProxyMethods::checkPipAvail(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] == IdString(); + return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); } IdString ArchRProxyMethods::getBoundPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return parent_->pip_to_net[pip.index]; + return pip_to_net[pip.index]; } IdString ArchRProxyMethods::getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index]; + return switches_locked[chip_info->pip_data[pip.index].switch_index]; } BelId ArchRProxyMethods::getBelByName(IdString name) const { BelId ret; - if (parent_->bel_by_name.empty()) { - for (int i = 0; i < parent_->chip_info->num_bels; i++) - parent_->bel_by_name[parent_->id(parent_->chip_info->bel_data[i].name.get())] = i; + if (bel_by_name.empty()) { + for (int i = 0; i < chip_info->num_bels; i++) + bel_by_name[parent_->id(chip_info->bel_data[i].name.get())] = i; } - auto it = parent_->bel_by_name.find(name); - if (it != parent_->bel_by_name.end()) + auto it = bel_by_name.find(name); + if (it != bel_by_name.end()) ret.index = it->second; return ret; @@ -861,8 +861,8 @@ BelId ArchRProxyMethods::getBelByName(IdString name) const void ArchRWProxyMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) { NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(parent_->bel_to_cell[bel.index] == IdString()); - parent_->bel_to_cell[bel.index] = cell; + NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); + bel_to_cell[bel.index] = cell; parent_->cells[cell]->bel = bel; parent_->cells[cell]->belStrength = strength; parent_->refreshUiBel(bel); @@ -871,19 +871,19 @@ void ArchRWProxyMethods::bindBel(BelId bel, IdString cell, PlaceStrength strengt void ArchRWProxyMethods::unbindBel(BelId bel) { NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(parent_->bel_to_cell[bel.index] != IdString()); - parent_->cells[parent_->bel_to_cell[bel.index]]->bel = BelId(); - parent_->cells[parent_->bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; - parent_->bel_to_cell[bel.index] = IdString(); + NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); + parent_->cells[bel_to_cell[bel.index]]->bel = BelId(); + parent_->cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; + bel_to_cell[bel.index] = IdString(); parent_->refreshUiBel(bel); } void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) { NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(parent_->wire_to_net[wire.index] == IdString()); + NPNR_ASSERT(wire_to_net[wire.index] == IdString()); - parent_->wire_to_net[wire.index] = net; + wire_to_net[wire.index] = net; parent_->nets[net]->wires[wire].pip = PipId(); parent_->nets[net]->wires[wire].strength = strength; parent_->refreshUiWire(wire); @@ -892,37 +892,37 @@ void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength stren void ArchRWProxyMethods::unbindWire(WireId wire) { NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(parent_->wire_to_net[wire.index] != IdString()); + NPNR_ASSERT(wire_to_net[wire.index] != IdString()); - auto &net_wires = parent_->nets[parent_->wire_to_net[wire.index]]->wires; + auto &net_wires = parent_->nets[wire_to_net[wire.index]]->wires; auto it = net_wires.find(wire); NPNR_ASSERT(it != net_wires.end()); auto pip = it->second.pip; if (pip != PipId()) { - parent_->pip_to_net[pip.index] = IdString(); - parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString(); + pip_to_net[pip.index] = IdString(); + switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); parent_->refreshUiPip(pip); } net_wires.erase(it); - parent_->wire_to_net[wire.index] = IdString(); + wire_to_net[wire.index] = IdString(); parent_->refreshUiWire(wire); } void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) { NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(parent_->pip_to_net[pip.index] == IdString()); - NPNR_ASSERT(parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] == IdString()); + NPNR_ASSERT(pip_to_net[pip.index] == IdString()); + NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); - parent_->pip_to_net[pip.index] = net; - parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = net; + pip_to_net[pip.index] = net; + switches_locked[chip_info->pip_data[pip.index].switch_index] = net; WireId dst; - dst.index = parent_->chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(parent_->wire_to_net[dst.index] == IdString()); - parent_->wire_to_net[dst.index] = net; + dst.index = chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(wire_to_net[dst.index] == IdString()); + wire_to_net[dst.index] = net; parent_->nets[net]->wires[dst].pip = pip; parent_->nets[net]->wires[dst].strength = strength; @@ -933,17 +933,17 @@ void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength void ArchRWProxyMethods::unbindPip(PipId pip) { NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(parent_->pip_to_net[pip.index] != IdString()); - NPNR_ASSERT(parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] != IdString()); + NPNR_ASSERT(pip_to_net[pip.index] != IdString()); + NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); WireId dst; - dst.index = parent_->chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(parent_->wire_to_net[dst.index] != IdString()); - parent_->wire_to_net[dst.index] = IdString(); - parent_->nets[parent_->pip_to_net[pip.index]]->wires.erase(dst); + dst.index = chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(wire_to_net[dst.index] != IdString()); + wire_to_net[dst.index] = IdString(); + parent_->nets[pip_to_net[pip.index]]->wires.erase(dst); - parent_->pip_to_net[pip.index] = IdString(); - parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString(); + pip_to_net[pip.index] = IdString(); + switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); parent_->refreshUiPip(pip); parent_->refreshUiWire(dst); diff --git a/ice40/arch.h b/ice40/arch.h index 8428dc29..da1e583a 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -339,7 +339,7 @@ class ArchRProxy; /// Arch/Context // Arch is the main state class of the PnR algorithms. It keeps note of mapped // cells/nets, locked switches, etc. -// +// // In order to mutate state in Arch, you can do one of two things: // - directly call one of the wrapper methods to mutate state // - get a read or readwrite proxy to the Arch, and call methods on it @@ -419,7 +419,7 @@ public: IdString getBoundPipNet(PipId pip) const; IdString getBoundBelCell(BelId bel) const; BelId getBelByName(IdString name) const; - + // ------------------------------------------------- /// Methods to get chip info - don't need to use a wrapper, as these are @@ -506,7 +506,7 @@ public: range.e.cursor = chip_info->num_pips; return range; } - + IdString getPipName(PipId pip) const; uint32_t getPipChecksum(PipId pip) const { return pip.index; } @@ -640,13 +640,27 @@ class ArchRProxyMethods { friend class ArchRWProxy; private: const Arch *parent_; - ArchRProxyMethods(const Arch *parent) : parent_(parent) {} - ArchRProxyMethods(ArchRProxyMethods &&other) noexcept : parent_(other.parent_) {} - ArchRProxyMethods(const ArchRProxyMethods &other) : parent_(other.parent_) {} - + ArchRProxyMethods(const Arch *parent) : parent_(parent), chip_info(parent->chip_info), + bel_to_cell(parent->bel_to_cell), wire_to_net(parent->wire_to_net), + pip_to_net(parent->pip_to_net), switches_locked(parent->switches_locked), + bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), + pip_by_name(parent->pip_by_name) {} + ArchRProxyMethods(ArchRProxyMethods &&other) noexcept : ArchRProxyMethods(other.parent_) {} + ArchRProxyMethods(const ArchRProxyMethods &other) : ArchRProxyMethods(other.parent_) {} + + // Let methods access hot members directly without having to go through + // parent_. + const ChipInfoPOD *chip_info; + const std::vector &bel_to_cell; + const std::vector &wire_to_net; + const std::vector &pip_to_net; + const std::vector &switches_locked; + std::unordered_map &bel_by_name; + std::unordered_map &wire_by_name; + std::unordered_map &pip_by_name; public: ~ArchRProxyMethods() noexcept { } - + /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) // Whether or not a given cell can be placed at a given Bel @@ -667,7 +681,7 @@ public: WireId getWireByName(IdString name) const; WireId getWireBelPin(BelId bel, PortPin pin) const; PipId getPipByName(IdString name) const; - + IdString getConflictingWireNet(WireId wire) const; IdString getConflictingPipNet(PipId pip) const; IdString getConflictingBelCell(BelId bel) const; @@ -709,9 +723,22 @@ class ArchRWProxyMethods { friend class ArchRWProxy; private: Arch *parent_; - ArchRWProxyMethods(Arch *parent) : parent_(parent) {} - ArchRWProxyMethods(ArchRWProxyMethods &&other) : parent_(other.parent_) {} - ArchRWProxyMethods(const ArchRWProxyMethods &other) : parent_(other.parent_) {} + ArchRWProxyMethods(Arch *parent) : parent_(parent), chip_info(parent->chip_info), + bel_to_cell(parent->bel_to_cell), wire_to_net(parent->wire_to_net), + pip_to_net(parent->pip_to_net), switches_locked(parent->switches_locked), + bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), + pip_by_name(parent->pip_by_name) {} + ArchRWProxyMethods(ArchRWProxyMethods &&other) : ArchRWProxyMethods(other.parent_) {} + ArchRWProxyMethods(const ArchRWProxyMethods &other) : ArchRWProxyMethods(other.parent_) {} + + const ChipInfoPOD *chip_info; + std::vector &bel_to_cell; + std::vector &wire_to_net; + std::vector &pip_to_net; + std::vector &switches_locked; + std::unordered_map &bel_by_name; + std::unordered_map &wire_by_name; + std::unordered_map &pip_by_name; public: ~ArchRWProxyMethods() {} @@ -746,8 +773,6 @@ public: lock_->unlock(); } } - - }; NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From a8c84e90a39c54174dd24b5b76bd17aed8311481 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Fri, 13 Jul 2018 20:53:52 +0100 Subject: Make GUI nice and smooth. --- common/nextpnr.h | 31 ++++++++++ gui/fpgaviewwidget.cc | 154 +++++++++++++++++--------------------------------- gui/fpgaviewwidget.h | 99 +++++++++++++++++++++++++------- ice40/arch.cc | 10 +++- ice40/arch.h | 8 ++- ice40/main.cc | 3 +- 6 files changed, 178 insertions(+), 127 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 50465869..efcab9fc 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -238,6 +238,16 @@ struct CellInfo std::unordered_map pins; }; +struct UIUpdatesRequired +{ + bool allUIReload; + bool frameUIReload; + std::unordered_set belUIReload; + std::unordered_set wireUIReload; + std::unordered_set pipUIReload; + std::unordered_set groupUIReload; +}; + struct BaseCtx { // -------------------------------------------------------------- @@ -260,6 +270,8 @@ struct BaseCtx idstring_idx_to_str = new std::vector; IdString::initialize_add(this, "", 0); IdString::initialize_arch(this); + + allUiReload = true; } ~BaseCtx() @@ -292,6 +304,25 @@ struct BaseCtx void refreshUiPip(PipId pip) { pipUiReload.insert(pip); } void refreshUiGroup(GroupId group) { groupUiReload.insert(group); } + + UIUpdatesRequired getUIUpdatesRequired(void) + { + UIUpdatesRequired req; + req.allUIReload = allUiReload; + req.frameUIReload = frameUiReload; + req.belUIReload = belUiReload; + req.wireUIReload = wireUiReload; + req.pipUIReload = pipUiReload; + req.groupUIReload = groupUiReload; + + allUiReload = false; + frameUiReload = false; + belUiReload.clear(); + wireUiReload.clear(); + pipUiReload.clear(); + groupUiReload.clear(); + return req; + } }; NEXTPNR_NAMESPACE_END diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 6b6a2617..21ce5b67 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "fpgaviewwidget.h" @@ -195,7 +196,7 @@ bool LineShader::compile(void) return true; } -void LineShader::draw(const LineShaderData &line, const QMatrix4x4 &projection) +void LineShader::draw(const LineShaderData &line, const QColor &color, const float thickness, const QMatrix4x4 &projection) { auto gl = QOpenGLContext::currentContext()->functions(); vao_.bind(); @@ -214,8 +215,8 @@ void LineShader::draw(const LineShaderData &line, const QMatrix4x4 &projection) buffers_.index.allocate(&line.indices[0], sizeof(GLuint) * line.indices.size()); program_->setUniformValue(uniforms_.projection, projection); - program_->setUniformValue(uniforms_.thickness, line.thickness); - program_->setUniformValue(uniforms_.color, line.color.r, line.color.g, line.color.b, line.color.a); + program_->setUniformValue(uniforms_.thickness, thickness); + program_->setUniformValue(uniforms_.color, color.redF(), color.greenF(), color.blueF(), color.alphaF()); buffers_.position.bind(); program_->enableAttributeArray("position"); @@ -264,6 +265,10 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineSha if (fmt.minorVersion() < 1) { printf("Could not get OpenGL 3.1 context - trying anyway...\n "); } + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(update())); + timer->start(5000); } FPGAViewWidget::~FPGAViewWidget() {} @@ -287,73 +292,6 @@ void FPGAViewWidget::initializeGL() glClearColor(backgroundColor_.red() / 255, backgroundColor_.green() / 255, backgroundColor_.blue() / 255, 0.0); } -void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal) -{ - const float scale = 1.0; - float offsetX = 0.0, offsetY = 0.0; - - for (auto &el : ctx_->getDecalGraphics(decal.decal)) { - offsetX = decal.x; - offsetY = decal.y; - - if (el.type == GraphicElement::G_BOX) { - auto line = PolyLine(true); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); - line.build(out); - } - - if (el.type == GraphicElement::G_LINE) { - PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, offsetY + scale * el.y2) - .build(out); - } - } -} - -void FPGAViewWidget::drawDecal(LineShaderData out[], const DecalXY &decal) -{ - const float scale = 1.0; - float offsetX = 0.0, offsetY = 0.0; - - for (auto &el : ctx_->getDecalGraphics(decal.decal)) { - offsetX = decal.x; - offsetY = decal.y; - - if (el.type == GraphicElement::G_BOX) { - auto line = PolyLine(true); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); - switch (el.style) { - case GraphicElement::G_FRAME: - case GraphicElement::G_INACTIVE: - case GraphicElement::G_ACTIVE: - line.build(out[el.style]); - break; - default: - break; - } - } - - if (el.type == GraphicElement::G_LINE) { - auto line = PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, - offsetY + scale * el.y2); - switch (el.style) { - case GraphicElement::G_FRAME: - case GraphicElement::G_INACTIVE: - case GraphicElement::G_ACTIVE: - line.build(out[el.style]); - break; - default: - break; - } - } - } -} - QMatrix4x4 FPGAViewWidget::getProjection(void) { QMatrix4x4 matrix; @@ -380,47 +318,59 @@ void FPGAViewWidget::paintGL() float thick11Px = mouseToWorldCoordinates(1.1, 0).x(); // Draw grid. - auto grid = LineShaderData(thick1Px, gridColor_); + auto grid = LineShaderData(); for (float i = -100.0f; i < 100.0f; i += 1.0f) { PolyLine(-100.0f, i, 100.0f, i).build(grid); PolyLine(i, -100.0f, i, 100.0f).build(grid); } - lineShader_.draw(grid, matrix); - - LineShaderData shaders[4] = {[GraphicElement::G_FRAME] = LineShaderData(thick11Px, gFrameColor_), - [GraphicElement::G_HIDDEN] = LineShaderData(thick11Px, gHiddenColor_), - [GraphicElement::G_INACTIVE] = LineShaderData(thick11Px, gInactiveColor_), - [GraphicElement::G_ACTIVE] = LineShaderData(thick11Px, gActiveColor_)}; + lineShader_.draw(grid, gridColor_, thick1Px, matrix); if (ctx_) { - // Draw Bels. - for (auto bel : ctx_->getBels()) { - drawDecal(shaders, ctx_->getBelDecal(bel)); - } - // Draw Wires. - for (auto wire : ctx_->getWires()) { - drawDecal(shaders, ctx_->getWireDecal(wire)); - } - // Draw Pips. - for (auto pip : ctx_->getPips()) { - drawDecal(shaders, ctx_->getPipDecal(pip)); - } - // Draw Groups. - for (auto group : ctx_->getGroups()) { - drawDecal(shaders, ctx_->getGroupDecal(group)); + auto &&proxy = ctx_->rwproxy(); + auto updates = proxy.getUIUpdatesRequired(); + + // Collapse all updates to a full redraw. + // TODO(q3k) fix this. + + bool redraw = (updates.allUIReload + || !updates.belUIReload.empty() + || !updates.wireUIReload.empty() + || !updates.pipUIReload.empty() + || !updates.groupUIReload.empty() + || updates.frameUIReload); + + if (redraw) { + shaders_[0].clear(); + shaders_[1].clear(); + shaders_[2].clear(); + shaders_[3].clear(); + + // Draw Bels. + for (auto bel : ctx_->getBels()) { + drawDecal(proxy, shaders_, ctx_->getBelDecal(bel)); + } + // Draw Wires. + for (auto wire : ctx_->getWires()) { + drawDecal(proxy, shaders_, ctx_->getWireDecal(wire)); + } + // Draw Pips. + for (auto pip : ctx_->getPips()) { + drawDecal(proxy, shaders_, ctx_->getPipDecal(pip)); + } + // Draw Groups. + for (auto group : ctx_->getGroups()) { + drawDecal(proxy, shaders_, ctx_->getGroupDecal(group)); + } + // Draw Frame Graphics. + drawDecal(proxy, shaders_, ctx_->getFrameDecal()); } } - lineShader_.draw(shaders[0], matrix); - lineShader_.draw(shaders[1], matrix); - lineShader_.draw(shaders[2], matrix); - lineShader_.draw(shaders[3], matrix); - // Draw Frame Graphics. - auto frames = LineShaderData(thick11Px, frameColor_); - if (ctx_) { - drawDecal(frames, ctx_->getFrameDecal()); - lineShader_.draw(frames, matrix); - } + lineShader_.draw(shaders_[0], gFrameColor_, thick11Px, matrix); + lineShader_.draw(shaders_[1], gHiddenColor_, thick11Px, matrix); + lineShader_.draw(shaders_[2], gInactiveColor_, thick11Px, matrix); + lineShader_.draw(shaders_[3], gActiveColor_, thick11Px, matrix); + //lineShader_.draw(frame, matrix); } void FPGAViewWidget::resizeGL(int width, int height) {} diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 410b0582..3652e82e 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -41,18 +41,6 @@ NPNR_PACKED_STRUCT(struct Vertex2DPOD { Vertex2DPOD(GLfloat X, GLfloat Y) : x(X), y(Y) {} }); -// Vertex2DPOD is a structure of R, G, B, A values that can be passed to OpenGL -// directly. -NPNR_PACKED_STRUCT(struct ColorPOD { - GLfloat r; - GLfloat g; - GLfloat b; - GLfloat a; - - ColorPOD(GLfloat R, GLfloat G, GLfloat B, GLfloat A) : r(R), g(G), b(B), a(A) {} - ColorPOD(const QColor &color) : r(color.redF()), g(color.greenF()), b(color.blueF()), a(color.alphaF()) {} -}); - // LineShaderData is a built set of vertices that can be rendered by the // LineShader. // Each LineShaderData can have its' own color and thickness. @@ -63,10 +51,13 @@ struct LineShaderData std::vector miters; std::vector indices; - GLfloat thickness; - ColorPOD color; - - LineShaderData(GLfloat Thickness, QColor Color) : thickness(Thickness), color(Color) {} + void clear(void) + { + vertices.clear(); + normals.clear(); + miters.clear(); + indices.clear(); + } }; // PolyLine is a set of segments defined by points, that can be built to a @@ -210,7 +201,7 @@ class LineShader bool compile(void); // Render a LineShaderData with a given M/V/P transformation. - void draw(const LineShaderData &data, const QMatrix4x4 &projection); + void draw(const LineShaderData &data, const QColor &color, const float thickness, const QMatrix4x4 &projection); }; class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions @@ -246,8 +237,76 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; - void drawDecal(LineShaderData &data, const DecalXY &decal); - void drawDecal(LineShaderData out[], const DecalXY &decal); + + template + void drawDecal(const T &proxy, LineShaderData &out, const DecalXY &decal) + { + const float scale = 1.0; + float offsetX = 0.0, offsetY = 0.0; + + for (auto &el : proxy.getDecalGraphics(decal.decal)) { + offsetX = decal.x; + offsetY = decal.y; + + if (el.type == GraphicElement::G_BOX) { + auto line = PolyLine(true); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); + line.build(out); + } + + if (el.type == GraphicElement::G_LINE) { + PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, offsetY + scale * el.y2) + .build(out); + } + } + } + + template + void drawDecal(const T &proxy, LineShaderData out[], const DecalXY &decal) + { + const float scale = 1.0; + float offsetX = 0.0, offsetY = 0.0; + + for (auto &el : proxy.getDecalGraphics(decal.decal)) { + offsetX = decal.x; + offsetY = decal.y; + + if (el.type == GraphicElement::G_BOX) { + auto line = PolyLine(true); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); + switch (el.style) { + case GraphicElement::G_FRAME: + case GraphicElement::G_INACTIVE: + case GraphicElement::G_ACTIVE: + line.build(out[el.style]); + break; + default: + break; + } + } + + if (el.type == GraphicElement::G_LINE) { + auto line = PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, + offsetY + scale * el.y2); + switch (el.style) { + case GraphicElement::G_FRAME: + case GraphicElement::G_INACTIVE: + case GraphicElement::G_ACTIVE: + line.build(out[el.style]); + break; + default: + break; + } + } + } + } + public Q_SLOTS: void newContext(Context *ctx); @@ -274,6 +333,8 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions QColor gInactiveColor_; QColor gActiveColor_; QColor frameColor_; + + LineShaderData shaders_[4]; }; NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.cc b/ice40/arch.cc index af6e922c..547dbcd6 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -534,9 +534,8 @@ DecalXY Arch::getGroupDecal(GroupId group) const return decalxy; }; -std::vector Arch::getDecalGraphics(DecalId decal) const +std::vector ArchRProxyMethods::getDecalGraphics(DecalId decal) const { - boost::shared_lock_guard lock(mtx_); std::vector ret; if (decal.type == DecalId::TYPE_FRAME) { @@ -568,7 +567,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const BelId bel; bel.index = decal.index; - auto bel_type = getBelType(bel); + auto bel_type = parent_->getBelType(bel); if (bel_type == TYPE_ICESTORM_LC) { GraphicElement el; @@ -954,4 +953,9 @@ CellInfo *ArchRWProxyMethods::getCell(IdString cell) return parent_->cells.at(cell).get(); } +UIUpdatesRequired ArchRWProxyMethods::getUIUpdatesRequired(void) +{ + return parent_->getUIUpdatesRequired(); +} + NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index da1e583a..4311f4a5 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -604,8 +604,6 @@ public: // ------------------------------------------------- - std::vector getDecalGraphics(DecalId decal) const; - DecalXY getFrameDecal() const; DecalXY getBelDecal(BelId bel) const; DecalXY getWireDecal(WireId wire) const; @@ -691,6 +689,8 @@ public: IdString getBoundBelCell(BelId bel) const; BelId getBelByName(IdString name) const; + + std::vector getDecalGraphics(DecalId decal) const; }; // A proxy object that keeps an Arch shared/readonly lock until it goes out @@ -750,6 +750,10 @@ public: void bindBel(BelId bel, IdString cell, PlaceStrength strength); // Returned pointer is valid as long as Proxy object exists. CellInfo *getCell(IdString cell); + + + // Methods to be used by UI for detecting whether we need to redraw. + UIUpdatesRequired getUIUpdatesRequired(void); }; // A proxy object that keeps an Arch readwrite lock until it goes out of scope. diff --git a/ice40/main.cc b/ice40/main.cc index e77bdd34..d38c786c 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -51,7 +51,8 @@ void svg_dump_decal(const Context *ctx, const DecalXY &decal) const float scale = 10.0, offset = 10.0; const std::string style = "stroke=\"black\" stroke-width=\"0.1\" fill=\"none\""; - for (auto &el : ctx->getDecalGraphics(decal.decal)) { + auto &&proxy = ctx->rproxy(); + for (auto &el : proxy.getDecalGraphics(decal.decal)) { if (el.type == GraphicElement::G_BOX) { std::cout << " Date: Fri, 13 Jul 2018 22:02:53 +0100 Subject: Add Nix(OS) support --- README.md | 15 +++++++++++++++ default.nix | 28 ++++++++++++++++++++++++++++ nextpnr.nix | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 default.nix create mode 100644 nextpnr.nix diff --git a/README.md b/README.md index da38500d..eb96bd1c 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,21 @@ Running `./nextpnr-ecp5 --json ecp5/synth/blinky.json --basecfg ecp5/synth/ulx3s_empty.config --bit ecp5/synth/ulx3s.bit` - Note that `ulx3s_empty.config` contains fixed/unknown bits to be copied to the output bitstream - You can also use `--textcfg out.config` to write a text file describing the bitstream for debugging + +Nix +--- + +As an alternative to getting the prerequisites yourself, you can use Nix/NixOS and run the following to get dropped into a shell with nextpnr built: + + nix-shell + +Or, you can add the `nextpnr.nix` file into your /etc/nixos/configuration.nix: + + environment.systemPackages = [ + ... + ( import /home/q3k/Software/nextpnr/nextpnr.nix ) + ... + ]; Notes ------- diff --git a/default.nix b/default.nix new file mode 100644 index 00000000..664e3669 --- /dev/null +++ b/default.nix @@ -0,0 +1,28 @@ +# +# nextpnr -- Next Generation Place and Route +# +# Copyright (C) 2018 Serge Bazanski +# +# 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. +# + + +with import {}; + +stdenv.mkDerivation rec { + name = "env"; + env = buildEnv { name = name; paths = buildInputs; }; + buildInputs = [ + ( import ./nextpnr.nix ) + ]; +} diff --git a/nextpnr.nix b/nextpnr.nix new file mode 100644 index 00000000..97097749 --- /dev/null +++ b/nextpnr.nix @@ -0,0 +1,53 @@ +# +# nextpnr -- Next Generation Place and Route +# +# Copyright (C) 2018 Serge Bazanski +# +# 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. +# + +with import {}; + +let + gitRev = "a8c84e90a39c54174dd24b5b76bd17aed8311481"; + gitBranch = "master"; +in + stdenv.mkDerivation rec { + name = "nextpnr-${version}"; + version = "1.0.0"; + + src = ./.; + + buildInputs = [ + python3 (boost.override { python = python3; }) + qt5.qtbase + ]; + + nativeBuildInputs = [ cmake icestorm ]; + + cmakeFlags= [ + "-DARCH=ice40" + "-DICEBOX_ROOT=${icestorm}/share/icebox" + ]; + + enableParallelBuilding = true; + + meta = with stdenv.lib; { + description = "A computer-aided design (CAD) tool from a parallel universe"; + homepage = "https://github.com/mkeeter/antimony"; + license = licenses.bsd0; + platforms = platforms.linux; + }; + } + + -- cgit v1.2.3 From 9365bf297c3e1a47d97dbc92e9f2df5aea590126 Mon Sep 17 00:00:00 2001 From: Serge Bazanski Date: Fri, 13 Jul 2018 22:05:27 +0100 Subject: Fix description in Nix derivation --- nextpnr.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nextpnr.nix b/nextpnr.nix index 97097749..bbd2c127 100644 --- a/nextpnr.nix +++ b/nextpnr.nix @@ -43,8 +43,8 @@ in enableParallelBuilding = true; meta = with stdenv.lib; { - description = "A computer-aided design (CAD) tool from a parallel universe"; - homepage = "https://github.com/mkeeter/antimony"; + description = "Next Generation Place-and-Route tool for FPGAs"; + homepage = "https://gitlab.com/symbioticeda/nextpnr"; license = licenses.bsd0; platforms = platforms.linux; }; -- cgit v1.2.3 From a38b4fa1735bd0af78520f6d5320a264914fb838 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sat, 14 Jul 2018 10:28:36 +0200 Subject: cmake: Add missing pthread library Signed-off-by: David Shah --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 27265616..78c8b5a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,7 +210,7 @@ foreach (family ${ARCH}) # Include family-specific source files to all family targets and set defines appropriately target_include_directories(${target} PRIVATE ${family}/ ${CMAKE_CURRENT_BINARY_DIR}/generated/) target_compile_definitions(${target} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family} ARCH_${ufamily} ARCHNAME=${family}) - target_link_libraries(${target} LINK_PUBLIC ${Boost_LIBRARIES}) + target_link_libraries(${target} LINK_PUBLIC ${Boost_LIBRARIES} pthread) add_sanitizers(${target}) if (BUILD_GUI) target_include_directories(${target} PRIVATE gui/${family}/ gui/) -- cgit v1.2.3 From 9b17fe385cf7e8d3025747b5f7c7822ac2d99920 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 11:10:31 +0100 Subject: Refactor proxies to nextpnr. --- common/nextpnr.cc | 11 +++ common/nextpnr.h | 170 ++++++++++++++++++++++++++++++++++++++--------- common/place_common.cc | 2 +- common/place_common.h | 2 +- common/placer1.cc | 4 +- common/router1.cc | 4 +- ice40/arch.cc | 77 +++++++++------------ ice40/arch.h | 130 ++++++++---------------------------- ice40/arch_place.cc | 6 +- ice40/place_legaliser.cc | 6 +- 10 files changed, 218 insertions(+), 194 deletions(-) diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 3861e5fe..54df5de1 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -21,6 +21,17 @@ NEXTPNR_NAMESPACE_BEGIN +MutateContext BaseCtx::rwproxy(void) +{ + return MutateContext(reinterpret_cast(this)); +} + +ReadContext BaseCtx::rproxy(void) const +{ + return ReadContext(reinterpret_cast(this)); +} + + assertion_failure::assertion_failure(std::string msg, std::string expr_str, std::string filename, int line) : runtime_error("Assertion failure: " + msg + " (" + filename + ":" + std::to_string(line) + ")"), msg(msg), expr_str(expr_str), filename(filename), line(line) diff --git a/common/nextpnr.h b/common/nextpnr.h index efcab9fc..c3fb913c 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -26,6 +26,7 @@ #include #include #include +#include #ifndef NEXTPNR_H #define NEXTPNR_H @@ -248,21 +249,37 @@ struct UIUpdatesRequired std::unordered_set groupUIReload; }; -struct BaseCtx +class ReadContext; +class MutateContext; +class BaseReadCtx; +class BaseMutateCtx; + +// Data that every architecture object should contain. +class BaseCtx { - // -------------------------------------------------------------- + friend class ReadContext; + friend class MutateContext; + friend class BaseReadCtx; + friend class BaseMutateCtx; +private: + mutable boost::shared_mutex mtx_; - mutable std::unordered_map *idstring_str_to_idx; - mutable std::vector *idstring_idx_to_str; + bool allUiReload = false; + bool frameUiReload = false; + std::unordered_set belUiReload; + std::unordered_set wireUiReload; + std::unordered_set pipUiReload; + std::unordered_set groupUiReload; +public: IdString id(const std::string &s) const { return IdString(this, s); } - IdString id(const char *s) const { return IdString(this, s); } - // -------------------------------------------------------------- - + // TODO(q3k): These need to be made private. std::unordered_map> nets; std::unordered_map> cells; + mutable std::unordered_map *idstring_str_to_idx; + mutable std::vector *idstring_idx_to_str; BaseCtx() { @@ -286,41 +303,83 @@ struct BaseCtx // -------------------------------------------------------------- - bool allUiReload = false; - bool frameUiReload = false; - std::unordered_set belUiReload; - std::unordered_set wireUiReload; - std::unordered_set pipUiReload; - std::unordered_set groupUiReload; + // Get a readwrite proxy to arch - this will keep a readwrite lock on the + // entire architecture until the proxy object goes out of scope. + MutateContext rwproxy(void); + // Get a read-only proxy to arch - this will keep a read lock on the + // entire architecture until the proxy object goes out of scope. Other read + // locks can be taken while this one still exists. Ie., the UI can draw + // elements while the PnR is going a RO operation. + ReadContext rproxy(void) const; + +}; - void refreshUi() { allUiReload = true; } +// State-accessing read-only methods that every architecture object should +// contain. +class BaseReadCtx +{ +protected: + const BaseCtx *base_; +public: + BaseReadCtx(const BaseCtx *base) : base_(base) {} +}; + +// State-accesssing read/write methods that every architecture object should +// contain. +class BaseMutateCtx +{ +protected: + BaseCtx *base_; + +public: + BaseMutateCtx(BaseCtx *base) : base_(base) {} + + void refreshUi(void) + { + base_->allUiReload = true; + } - void refreshUiFrame() { frameUiReload = true; } + void refreshUiFrame(void) + { + base_->frameUiReload = true; + } - void refreshUiBel(BelId bel) { belUiReload.insert(bel); } + void refreshUiBel(BelId bel) + { + base_->belUiReload.insert(bel); + } - void refreshUiWire(WireId wire) { wireUiReload.insert(wire); } + void refreshUiWire(WireId wire) + { + base_->wireUiReload.insert(wire); + } - void refreshUiPip(PipId pip) { pipUiReload.insert(pip); } + void refreshUiPip(PipId pip) + { + base_->pipUiReload.insert(pip); + } - void refreshUiGroup(GroupId group) { groupUiReload.insert(group); } + void refreshUiGroup(GroupId group) + { + base_->groupUiReload.insert(group); + } UIUpdatesRequired getUIUpdatesRequired(void) { UIUpdatesRequired req; - req.allUIReload = allUiReload; - req.frameUIReload = frameUiReload; - req.belUIReload = belUiReload; - req.wireUIReload = wireUiReload; - req.pipUIReload = pipUiReload; - req.groupUIReload = groupUiReload; - - allUiReload = false; - frameUiReload = false; - belUiReload.clear(); - wireUiReload.clear(); - pipUiReload.clear(); - groupUiReload.clear(); + req.allUIReload = base_->allUiReload; + req.frameUIReload = base_->frameUiReload; + req.belUIReload = base_->belUiReload; + req.wireUIReload = base_->wireUiReload; + req.pipUIReload = base_->pipUiReload; + req.groupUIReload = base_->groupUiReload; + + base_->allUiReload = false; + base_->frameUiReload = false; + base_->belUiReload.clear(); + base_->wireUiReload.clear(); + base_->pipUiReload.clear(); + base_->groupUiReload.clear(); return req; } }; @@ -331,6 +390,53 @@ NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_BEGIN +// Read proxy to access ReadMethods while holding lock on underlying BaseCtx. +class ReadContext : public ArchReadMethods +{ + friend class BaseCtx; +private: + boost::shared_mutex *lock_; + ReadContext(const Arch *parent) : ArchReadMethods(parent), lock_(&parent->mtx_) + { + lock_->lock_shared(); + } +public: + ~ReadContext() + { + if (lock_ != nullptr) { + lock_->unlock_shared(); + } + } + ReadContext(ReadContext &&other): ArchReadMethods(other), lock_(other.lock_) + { + other.lock_ = nullptr; + } +}; + +// Read proxy to access MutateMethods while holding lock on underlying BaseCtx. +class MutateContext : public ArchReadMethods, public ArchMutateMethods +{ + friend class BaseCtx; +private: + boost::shared_mutex *lock_; + MutateContext(Arch *parent) : ArchReadMethods(parent), ArchMutateMethods(parent), lock_(&parent->mtx_) + { + lock_->lock(); + } +public: + ~MutateContext() + { + if (lock_ != nullptr) { + lock_->unlock(); + } + } + MutateContext(MutateContext &&other): ArchReadMethods(other), ArchMutateMethods(other), lock_(other.lock_) + { + other.lock_ = nullptr; + } +}; + + struct Context : Arch { bool verbose = false; diff --git a/common/place_common.cc b/common/place_common.cc index 48416370..9694b6fe 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -26,7 +26,7 @@ NEXTPNR_NAMESPACE_BEGIN // Placing a single cell -bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool require_legality) +bool place_single_cell(MutateContext &proxy, Context *ctx, CellInfo *cell, bool require_legality) { bool all_placed = false; int iters = 25; diff --git a/common/place_common.h b/common/place_common.h index 57e82510..96ac48a9 100644 --- a/common/place_common.h +++ b/common/place_common.h @@ -109,7 +109,7 @@ wirelen_t get_cell_wirelength_at_bel(const T &proxy, const Context *ctx, CellInf } // Place a single cell in the lowest wirelength Bel available, optionally requiring validity check -bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool require_legality); +bool place_single_cell(MutateContext &proxy, Context *ctx, CellInfo *cell, bool require_legality); NEXTPNR_NAMESPACE_END diff --git a/common/placer1.cc b/common/placer1.cc index 0e3a84f7..78515ece 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -275,7 +275,7 @@ class SAPlacer private: // Initial random placement - void place_initial(ArchRWProxy &proxy, CellInfo *cell) + void place_initial(MutateContext &proxy, CellInfo *cell) { bool all_placed = false; int iters = 25; @@ -325,7 +325,7 @@ class SAPlacer } // Attempt a SA position swap, return true on success or false on failure - bool try_swap_position(ArchRWProxy &proxy, CellInfo *cell, BelId newBel) + bool try_swap_position(MutateContext &proxy, CellInfo *cell, BelId newBel) { static std::unordered_set update; static std::vector> new_lengths; diff --git a/common/router1.cc b/common/router1.cc index 0d26a36d..f7a7e8a2 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -74,7 +74,7 @@ struct RipupScoreboard std::unordered_map, int, hash_id_pip> netPipScores; }; -void ripup_net(ArchRWProxy &proxy, Context *ctx, IdString net_name) +void ripup_net(MutateContext &proxy, Context *ctx, IdString net_name) { auto net_info = ctx->nets.at(net_name).get(); std::vector pips; @@ -115,7 +115,7 @@ struct Router delay_t maxDelay = 0.0; WireId failedDest; - void route(ArchRWProxy &proxy, const std::unordered_map &src_wires, WireId dst_wire) + void route(MutateContext &proxy, const std::unordered_map &src_wires, WireId dst_wire) { std::priority_queue, QueuedWire::Greater> queue; diff --git a/ice40/arch.cc b/ice40/arch.cc index 547dbcd6..790167e9 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -29,18 +29,6 @@ NEXTPNR_NAMESPACE_BEGIN -ArchRWProxy Arch::rwproxy(void) { - ArchRWProxy res(this); - return res; -} - -ArchRProxy Arch::rproxy(void) const { - ArchRProxy res(this); - return res; -} - -// ----------------------------------------------------------------------- - IdString Arch::belTypeToId(BelType type) const { if (type == TYPE_ICESTORM_LC) @@ -534,7 +522,7 @@ DecalXY Arch::getGroupDecal(GroupId group) const return decalxy; }; -std::vector ArchRProxyMethods::getDecalGraphics(DecalId decal) const +std::vector ArchReadMethods::getDecalGraphics(DecalId decal) const { std::vector ret; @@ -732,25 +720,25 @@ bool Arch::isGlobalNet(const NetInfo *net) const // ----------------------------------------------------------------------- -bool ArchRProxyMethods::checkBelAvail(BelId bel) const +bool ArchReadMethods::checkBelAvail(BelId bel) const { NPNR_ASSERT(bel != BelId()); return bel_to_cell[bel.index] == IdString(); } -IdString ArchRProxyMethods::getBoundBelCell(BelId bel) const +IdString ArchReadMethods::getBoundBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); return bel_to_cell[bel.index]; } -IdString ArchRProxyMethods::getConflictingBelCell(BelId bel) const +IdString ArchReadMethods::getConflictingBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); return bel_to_cell[bel.index]; } -WireId ArchRProxyMethods::getWireBelPin(BelId bel, PortPin pin) const +WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const { WireId ret; @@ -768,7 +756,7 @@ WireId ArchRProxyMethods::getWireBelPin(BelId bel, PortPin pin) const return ret; } -WireId ArchRProxyMethods::getWireByName(IdString name) const +WireId ArchReadMethods::getWireByName(IdString name) const { WireId ret; @@ -784,25 +772,25 @@ WireId ArchRProxyMethods::getWireByName(IdString name) const return ret; } -bool ArchRProxyMethods::checkWireAvail(WireId wire) const +bool ArchReadMethods::checkWireAvail(WireId wire) const { NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index] == IdString(); } -IdString ArchRProxyMethods::getBoundWireNet(WireId wire) const +IdString ArchReadMethods::getBoundWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index]; } -IdString ArchRProxyMethods::getConflictingWireNet(WireId wire) const +IdString ArchReadMethods::getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index]; } -PipId ArchRProxyMethods::getPipByName(IdString name) const +PipId ArchReadMethods::getPipByName(IdString name) const { PipId ret; @@ -821,25 +809,25 @@ PipId ArchRProxyMethods::getPipByName(IdString name) const return ret; } -bool ArchRProxyMethods::checkPipAvail(PipId pip) const +bool ArchReadMethods::checkPipAvail(PipId pip) const { NPNR_ASSERT(pip != PipId()); return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); } -IdString ArchRProxyMethods::getBoundPipNet(PipId pip) const +IdString ArchReadMethods::getBoundPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); return pip_to_net[pip.index]; } -IdString ArchRProxyMethods::getConflictingPipNet(PipId pip) const +IdString ArchReadMethods::getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); return switches_locked[chip_info->pip_data[pip.index].switch_index]; } -BelId ArchRProxyMethods::getBelByName(IdString name) const +BelId ArchReadMethods::getBelByName(IdString name) const { BelId ret; @@ -857,27 +845,27 @@ BelId ArchRProxyMethods::getBelByName(IdString name) const // ----------------------------------------------------------------------- -void ArchRWProxyMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) +void ArchMutateMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) { NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); bel_to_cell[bel.index] = cell; parent_->cells[cell]->bel = bel; parent_->cells[cell]->belStrength = strength; - parent_->refreshUiBel(bel); + refreshUiBel(bel); } -void ArchRWProxyMethods::unbindBel(BelId bel) +void ArchMutateMethods::unbindBel(BelId bel) { NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); parent_->cells[bel_to_cell[bel.index]]->bel = BelId(); parent_->cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; bel_to_cell[bel.index] = IdString(); - parent_->refreshUiBel(bel); + refreshUiBel(bel); } -void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) +void ArchMutateMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire.index] == IdString()); @@ -885,10 +873,10 @@ void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength stren wire_to_net[wire.index] = net; parent_->nets[net]->wires[wire].pip = PipId(); parent_->nets[net]->wires[wire].strength = strength; - parent_->refreshUiWire(wire); + refreshUiWire(wire); } -void ArchRWProxyMethods::unbindWire(WireId wire) +void ArchMutateMethods::unbindWire(WireId wire) { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire.index] != IdString()); @@ -901,15 +889,15 @@ void ArchRWProxyMethods::unbindWire(WireId wire) if (pip != PipId()) { pip_to_net[pip.index] = IdString(); switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); - parent_->refreshUiPip(pip); + refreshUiPip(pip); } net_wires.erase(it); wire_to_net[wire.index] = IdString(); - parent_->refreshUiWire(wire); + refreshUiWire(wire); } -void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) +void ArchMutateMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] == IdString()); @@ -925,11 +913,11 @@ void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength parent_->nets[net]->wires[dst].pip = pip; parent_->nets[net]->wires[dst].strength = strength; - parent_->refreshUiPip(pip); - parent_->refreshUiWire(dst); + refreshUiPip(pip); + refreshUiWire(dst); } -void ArchRWProxyMethods::unbindPip(PipId pip) +void ArchMutateMethods::unbindPip(PipId pip) { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] != IdString()); @@ -944,18 +932,13 @@ void ArchRWProxyMethods::unbindPip(PipId pip) pip_to_net[pip.index] = IdString(); switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); - parent_->refreshUiPip(pip); - parent_->refreshUiWire(dst); + refreshUiPip(pip); + refreshUiWire(dst); } -CellInfo *ArchRWProxyMethods::getCell(IdString cell) +CellInfo *ArchMutateMethods::getCell(IdString cell) { return parent_->cells.at(cell).get(); } -UIUpdatesRequired ArchRWProxyMethods::getUIUpdatesRequired(void) -{ - return parent_->getUIUpdatesRequired(); -} - NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index 4311f4a5..5d4eaedf 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -22,9 +22,6 @@ #error Include "arch.h" via "nextpnr.h" only. #endif -#include -#include - NEXTPNR_NAMESPACE_BEGIN /**** Everything in this section must be kept in sync with chipdb.py ****/ @@ -330,11 +327,8 @@ struct ArchArgs /// Forward declare proxy classes for Arch. -class ArchRWProxyMethods; -class ArchRProxyMethods; -class ArchRWProxy; -class ArchRProxy; - +class ArchMutateMethods; +class ArchReadMethods; /// Arch/Context // Arch is the main state class of the PnR algorithms. It keeps note of mapped @@ -347,11 +341,8 @@ class ArchRProxy; class Arch : public BaseCtx { // We let proxy methods access our state. - friend class ArchRWProxyMethods; - friend class ArchRProxyMethods; - // We let proxy objects access our mutex. - friend class ArchRWProxy; - friend class ArchRProxy; + friend class ArchMutateMethods; + friend class ArchReadMethods; private: // All of the following... std::vector bel_to_cell; @@ -362,9 +353,6 @@ private: mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; - // ... are guarded by the following lock: - mutable boost::shared_mutex mtx_; - public: const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; @@ -372,15 +360,6 @@ public: ArchArgs args; Arch(ArchArgs args); - // Get a readwrite proxy to arch - this will keep a readwrite lock on the - // entire architecture until the proxy object goes out of scope. - ArchRWProxy rwproxy(void); - // Get a read-only proxy to arch - this will keep a read lock on the - // entire architecture until the proxy object goes out of scope. Other read - // locks can be taken while this one still exists. Ie., the UI can draw - // elements while the PnR is going a RO operation. - ArchRProxy rproxy(void) const; - std::string getChipName(); IdString archId() const { return id("ice40"); } @@ -632,22 +611,9 @@ public: }; // Read-only methods on Arch that require state access. -class ArchRProxyMethods { - // We let proxy objects access our private constructors. - friend class ArchRProxy; - friend class ArchRWProxy; +class ArchReadMethods : public BaseReadCtx { private: const Arch *parent_; - ArchRProxyMethods(const Arch *parent) : parent_(parent), chip_info(parent->chip_info), - bel_to_cell(parent->bel_to_cell), wire_to_net(parent->wire_to_net), - pip_to_net(parent->pip_to_net), switches_locked(parent->switches_locked), - bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), - pip_by_name(parent->pip_by_name) {} - ArchRProxyMethods(ArchRProxyMethods &&other) noexcept : ArchRProxyMethods(other.parent_) {} - ArchRProxyMethods(const ArchRProxyMethods &other) : ArchRProxyMethods(other.parent_) {} - - // Let methods access hot members directly without having to go through - // parent_. const ChipInfoPOD *chip_info; const std::vector &bel_to_cell; const std::vector &wire_to_net; @@ -656,8 +622,17 @@ private: std::unordered_map &bel_by_name; std::unordered_map &wire_by_name; std::unordered_map &pip_by_name; + public: - ~ArchRProxyMethods() noexcept { } + ~ArchReadMethods() noexcept { } + ArchReadMethods(const Arch *parent) : BaseReadCtx(parent), parent_(parent), + chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), + wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), + switches_locked(parent->switches_locked), + bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), + pip_by_name(parent->pip_by_name) {} + ArchReadMethods(ArchReadMethods &&other) noexcept : ArchReadMethods(other.parent_) {} + ArchReadMethods(const ArchReadMethods &other) : ArchReadMethods(other.parent_) {} /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) @@ -693,44 +668,11 @@ public: std::vector getDecalGraphics(DecalId decal) const; }; -// A proxy object that keeps an Arch shared/readonly lock until it goes out -// of scope. All const/read-only ArchRProxyMethods are available on it. -class ArchRProxy : public ArchRProxyMethods { - friend class Arch; - friend class ArchRWProxy; -private: - boost::shared_mutex *lock_; - ArchRProxy(const Arch *parent) : ArchRProxyMethods(parent), lock_(&parent->mtx_) - { - lock_->lock_shared(); - } - -public: - ~ArchRProxy() { - if (lock_ != nullptr) { - lock_->unlock_shared(); - } - } - ArchRProxy(ArchRProxy &&other) : ArchRProxyMethods(other), lock_(other.lock_) - { - other.lock_ = nullptr; - } -}; - // State mutating methods on Arch. -class ArchRWProxyMethods { - // We let proxy objects access our private constructors. - friend class ArchRWProxy; +class ArchMutateMethods : public BaseMutateCtx { + friend class MutateContext; private: Arch *parent_; - ArchRWProxyMethods(Arch *parent) : parent_(parent), chip_info(parent->chip_info), - bel_to_cell(parent->bel_to_cell), wire_to_net(parent->wire_to_net), - pip_to_net(parent->pip_to_net), switches_locked(parent->switches_locked), - bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), - pip_by_name(parent->pip_by_name) {} - ArchRWProxyMethods(ArchRWProxyMethods &&other) : ArchRWProxyMethods(other.parent_) {} - ArchRWProxyMethods(const ArchRWProxyMethods &other) : ArchRWProxyMethods(other.parent_) {} - const ChipInfoPOD *chip_info; std::vector &bel_to_cell; std::vector &wire_to_net; @@ -739,8 +681,17 @@ private: std::unordered_map &bel_by_name; std::unordered_map &wire_by_name; std::unordered_map &pip_by_name; + public: - ~ArchRWProxyMethods() {} + ArchMutateMethods(Arch *parent) : BaseMutateCtx(parent), parent_(parent), + chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), + wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), + switches_locked(parent->switches_locked), + bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), + pip_by_name(parent->pip_by_name) {} + ArchMutateMethods(ArchMutateMethods &&other) : ArchMutateMethods(other.parent_) {} + ArchMutateMethods(const ArchMutateMethods &other) : ArchMutateMethods(other.parent_) {} + ~ArchMutateMethods() {} void unbindWire(WireId wire); void unbindPip(PipId pip); @@ -750,33 +701,6 @@ public: void bindBel(BelId bel, IdString cell, PlaceStrength strength); // Returned pointer is valid as long as Proxy object exists. CellInfo *getCell(IdString cell); - - - // Methods to be used by UI for detecting whether we need to redraw. - UIUpdatesRequired getUIUpdatesRequired(void); -}; - -// A proxy object that keeps an Arch readwrite lock until it goes out of scope. -// All ArchRProxyMethods and ArchRWProxyMethods are available on it. -class ArchRWProxy : public ArchRProxyMethods, public ArchRWProxyMethods { - friend class Arch; -private: - boost::shared_mutex *lock_; - ArchRWProxy(Arch *parent) : ArchRProxyMethods(parent), ArchRWProxyMethods(parent), lock_(&parent->mtx_) { - lock_->lock(); - } - -public: - ArchRWProxy(ArchRWProxy &&other) : ArchRProxyMethods(other), ArchRWProxyMethods(other), lock_(other.lock_) - { - other.lock_ = nullptr; - } - ~ArchRWProxy() - { - if (lock_ != nullptr) { - lock_->unlock(); - } - } }; NEXTPNR_NAMESPACE_END diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index cb7c44b8..42efceab 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -25,7 +25,7 @@ NEXTPNR_NAMESPACE_BEGIN -bool ArchRProxyMethods::logicCellsCompatible(const std::vector &cells) const +bool ArchReadMethods::logicCellsCompatible(const std::vector &cells) const { bool dffs_exist = false, dffs_neg = false; const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; @@ -76,7 +76,7 @@ bool ArchRProxyMethods::logicCellsCompatible(const std::vector return locals_count <= 32; } -bool ArchRProxyMethods::isBelLocationValid(BelId bel) const +bool ArchReadMethods::isBelLocationValid(BelId bel) const { if (parent_->getBelType(bel) == TYPE_ICESTORM_LC) { std::vector bel_cells; @@ -97,7 +97,7 @@ bool ArchRProxyMethods::isBelLocationValid(BelId bel) const } } -bool ArchRProxyMethods::isValidBelForCell(CellInfo *cell, BelId bel) const +bool ArchReadMethods::isValidBelForCell(CellInfo *cell, BelId bel) const { if (cell->type == parent_->id_icestorm_lc) { NPNR_ASSERT(parent_->getBelType(bel) == TYPE_ICESTORM_LC); diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index 10a6f3ff..fcb47cfd 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -253,7 +253,7 @@ class PlacementLegaliser } // Find Bel closest to a location, meeting chain requirements - std::tuple find_closest_bel(ArchRWProxy &proxy, float target_x, float target_y, CellChain &chain) + std::tuple find_closest_bel(MutateContext &proxy, float target_x, float target_y, CellChain &chain) { std::tuple best_origin = std::make_tuple(-1, -1, -1); wirelen_t best_wirelength = std::numeric_limits::max(); @@ -283,7 +283,7 @@ class PlacementLegaliser } // Split a carry chain into multiple legal chains - std::vector split_carry_chain(const ArchRProxy &proxy, CellChain &carryc) + std::vector split_carry_chain(const ReadContext &proxy, CellChain &carryc) { bool start_of_chain = true; std::vector chains; @@ -335,7 +335,7 @@ class PlacementLegaliser } // Place a logic cell at a given grid location, handling rip-up etc - void place_lc(ArchRWProxy &proxy, CellInfo *cell, int x, int y, int z) + void place_lc(MutateContext &proxy, CellInfo *cell, int x, int y, int z) { auto &loc = logic_bels.at(x).at(y).at(z); NPNR_ASSERT(!loc.second); -- cgit v1.2.3 From 8ca7a6da2525463be5be4ee9f62cfae0acc06b01 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 11:10:59 +0100 Subject: clang-format --- common/nextpnr.cc | 11 +----- common/nextpnr.h | 72 +++++++++++++--------------------- common/place_common.h | 6 +-- common/router1.cc | 1 - ice40/arch.cc | 104 +++++++++++--------------------------------------- ice40/arch.h | 55 +++++++++++++------------- 6 files changed, 80 insertions(+), 169 deletions(-) diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 54df5de1..33230db0 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -21,16 +21,9 @@ NEXTPNR_NAMESPACE_BEGIN -MutateContext BaseCtx::rwproxy(void) -{ - return MutateContext(reinterpret_cast(this)); -} - -ReadContext BaseCtx::rproxy(void) const -{ - return ReadContext(reinterpret_cast(this)); -} +MutateContext BaseCtx::rwproxy(void) { return MutateContext(reinterpret_cast(this)); } +ReadContext BaseCtx::rproxy(void) const { return ReadContext(reinterpret_cast(this)); } assertion_failure::assertion_failure(std::string msg, std::string expr_str, std::string filename, int line) : runtime_error("Assertion failure: " + msg + " (" + filename + ":" + std::to_string(line) + ")"), msg(msg), diff --git a/common/nextpnr.h b/common/nextpnr.h index c3fb913c..6228e653 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -26,7 +27,6 @@ #include #include #include -#include #ifndef NEXTPNR_H #define NEXTPNR_H @@ -261,7 +261,8 @@ class BaseCtx friend class MutateContext; friend class BaseReadCtx; friend class BaseMutateCtx; -private: + + private: mutable boost::shared_mutex mtx_; bool allUiReload = false; @@ -271,7 +272,7 @@ private: std::unordered_set pipUiReload; std::unordered_set groupUiReload; -public: + public: IdString id(const std::string &s) const { return IdString(this, s); } IdString id(const char *s) const { return IdString(this, s); } @@ -311,16 +312,16 @@ public: // locks can be taken while this one still exists. Ie., the UI can draw // elements while the PnR is going a RO operation. ReadContext rproxy(void) const; - }; // State-accessing read-only methods that every architecture object should // contain. class BaseReadCtx { -protected: + protected: const BaseCtx *base_; -public: + + public: BaseReadCtx(const BaseCtx *base) : base_(base) {} }; @@ -328,41 +329,23 @@ public: // contain. class BaseMutateCtx { -protected: + protected: BaseCtx *base_; -public: + public: BaseMutateCtx(BaseCtx *base) : base_(base) {} - void refreshUi(void) - { - base_->allUiReload = true; - } + void refreshUi(void) { base_->allUiReload = true; } - void refreshUiFrame(void) - { - base_->frameUiReload = true; - } + void refreshUiFrame(void) { base_->frameUiReload = true; } - void refreshUiBel(BelId bel) - { - base_->belUiReload.insert(bel); - } + void refreshUiBel(BelId bel) { base_->belUiReload.insert(bel); } - void refreshUiWire(WireId wire) - { - base_->wireUiReload.insert(wire); - } + void refreshUiWire(WireId wire) { base_->wireUiReload.insert(wire); } - void refreshUiPip(PipId pip) - { - base_->pipUiReload.insert(pip); - } + void refreshUiPip(PipId pip) { base_->pipUiReload.insert(pip); } - void refreshUiGroup(GroupId group) - { - base_->groupUiReload.insert(group); - } + void refreshUiGroup(GroupId group) { base_->groupUiReload.insert(group); } UIUpdatesRequired getUIUpdatesRequired(void) { @@ -394,49 +377,46 @@ NEXTPNR_NAMESPACE_BEGIN class ReadContext : public ArchReadMethods { friend class BaseCtx; -private: + + private: boost::shared_mutex *lock_; - ReadContext(const Arch *parent) : ArchReadMethods(parent), lock_(&parent->mtx_) - { - lock_->lock_shared(); - } -public: + ReadContext(const Arch *parent) : ArchReadMethods(parent), lock_(&parent->mtx_) { lock_->lock_shared(); } + + public: ~ReadContext() { if (lock_ != nullptr) { lock_->unlock_shared(); } } - ReadContext(ReadContext &&other): ArchReadMethods(other), lock_(other.lock_) - { - other.lock_ = nullptr; - } + ReadContext(ReadContext &&other) : ArchReadMethods(other), lock_(other.lock_) { other.lock_ = nullptr; } }; // Read proxy to access MutateMethods while holding lock on underlying BaseCtx. class MutateContext : public ArchReadMethods, public ArchMutateMethods { friend class BaseCtx; -private: + + private: boost::shared_mutex *lock_; MutateContext(Arch *parent) : ArchReadMethods(parent), ArchMutateMethods(parent), lock_(&parent->mtx_) { lock_->lock(); } -public: + + public: ~MutateContext() { if (lock_ != nullptr) { lock_->unlock(); } } - MutateContext(MutateContext &&other): ArchReadMethods(other), ArchMutateMethods(other), lock_(other.lock_) + MutateContext(MutateContext &&other) : ArchReadMethods(other), ArchMutateMethods(other), lock_(other.lock_) { other.lock_ = nullptr; } }; - struct Context : Arch { bool verbose = false; diff --git a/common/place_common.h b/common/place_common.h index 96ac48a9..dac2e607 100644 --- a/common/place_common.h +++ b/common/place_common.h @@ -29,8 +29,7 @@ NEXTPNR_NAMESPACE_BEGIN typedef int64_t wirelen_t; // Get the total estimated wirelength for a net -template -wirelen_t get_net_wirelength(const T &proxy, const Context *ctx, const NetInfo *net, float &tns) +template wirelen_t get_net_wirelength(const T &proxy, const Context *ctx, const NetInfo *net, float &tns) { wirelen_t wirelength = 0; int driver_x, driver_y; @@ -81,8 +80,7 @@ wirelen_t get_net_wirelength(const T &proxy, const Context *ctx, const NetInfo * } // Return the wirelength of all nets connected to a cell -template -wirelen_t get_cell_wirelength(const T &proxy, const Context *ctx, const CellInfo *cell) +template wirelen_t get_cell_wirelength(const T &proxy, const Context *ctx, const CellInfo *cell) { std::set nets; for (auto p : cell->ports) { diff --git a/common/router1.cc b/common/router1.cc index f7a7e8a2..dc75a153 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -136,7 +136,6 @@ struct Router int thisVisitCnt = 0; int thisVisitCntLimit = 0; - while (!queue.empty() && (thisVisitCntLimit == 0 || thisVisitCnt < thisVisitCntLimit)) { QueuedWire qw = queue.top(); queue.pop(); diff --git a/ice40/arch.cc b/ice40/arch.cc index 790167e9..8f2731c6 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -259,99 +259,43 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const // ----------------------------------------------------------------------- // Shorthands to ArchProxy -BelId Arch::getBelByName(IdString name) const -{ - return rproxy().getBelByName(name); -} +BelId Arch::getBelByName(IdString name) const { return rproxy().getBelByName(name); } -void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength) -{ - rwproxy().bindWire(wire, net, strength); -} +void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength) { rwproxy().bindWire(wire, net, strength); } -void Arch::unbindWire(WireId wire) -{ - rwproxy().unbindWire(wire); -} +void Arch::unbindWire(WireId wire) { rwproxy().unbindWire(wire); } -void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength) { - rwproxy().bindBel(bel, cell, strength); -} +void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength) { rwproxy().bindBel(bel, cell, strength); } -void Arch::unbindBel(BelId bel) -{ - rwproxy().unbindBel(bel); -} +void Arch::unbindBel(BelId bel) { rwproxy().unbindBel(bel); } -bool Arch::checkBelAvail(BelId bel) const -{ - return rproxy().checkBelAvail(bel); -} +bool Arch::checkBelAvail(BelId bel) const { return rproxy().checkBelAvail(bel); } -IdString Arch::getBoundBelCell(BelId bel) const -{ - return rproxy().getBoundBelCell(bel); -} +IdString Arch::getBoundBelCell(BelId bel) const { return rproxy().getBoundBelCell(bel); } -IdString Arch::getConflictingBelCell(BelId bel) const -{ - return rproxy().getConflictingBelCell(bel); -} +IdString Arch::getConflictingBelCell(BelId bel) const { return rproxy().getConflictingBelCell(bel); } -WireId Arch::getWireByName(IdString name) const -{ - return rproxy().getWireByName(name); -} +WireId Arch::getWireByName(IdString name) const { return rproxy().getWireByName(name); } -WireId Arch::getWireBelPin(BelId bel, PortPin pin) const -{ - return rproxy().getWireBelPin(bel, pin); -} +WireId Arch::getWireBelPin(BelId bel, PortPin pin) const { return rproxy().getWireBelPin(bel, pin); } -bool Arch::checkWireAvail(WireId wire) const -{ - return rproxy().checkWireAvail(wire); -} +bool Arch::checkWireAvail(WireId wire) const { return rproxy().checkWireAvail(wire); } -IdString Arch::getBoundWireNet(WireId wire) const -{ - return rproxy().getBoundWireNet(wire); -} +IdString Arch::getBoundWireNet(WireId wire) const { return rproxy().getBoundWireNet(wire); } -IdString Arch::getConflictingWireNet(WireId wire) const -{ - return rproxy().getConflictingWireNet(wire); -} +IdString Arch::getConflictingWireNet(WireId wire) const { return rproxy().getConflictingWireNet(wire); } -PipId Arch::getPipByName(IdString name) const -{ - return rproxy().getPipByName(name); -} +PipId Arch::getPipByName(IdString name) const { return rproxy().getPipByName(name); } -void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength) -{ - return rwproxy().bindPip(pip, net, strength); -} +void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength) { return rwproxy().bindPip(pip, net, strength); } -void Arch::unbindPip(PipId pip) -{ - return rwproxy().unbindPip(pip); -} +void Arch::unbindPip(PipId pip) { return rwproxy().unbindPip(pip); } -bool Arch::checkPipAvail(PipId pip) const -{ - return rproxy().checkPipAvail(pip); -} +bool Arch::checkPipAvail(PipId pip) const { return rproxy().checkPipAvail(pip); } -IdString Arch::getBoundPipNet(PipId pip) const -{ - return rproxy().getBoundPipNet(pip); -} +IdString Arch::getBoundPipNet(PipId pip) const { return rproxy().getBoundPipNet(pip); } -IdString Arch::getConflictingPipNet(PipId pip) const -{ - return rproxy().getConflictingPipNet(pip); -} +IdString Arch::getConflictingPipNet(PipId pip) const { return rproxy().getConflictingPipNet(pip); } // ----------------------------------------------------------------------- @@ -630,8 +574,7 @@ std::vector ArchReadMethods::getDecalGraphics(DecalId decal) con } if (bel_type == TYPE_ICESTORM_RAM) { - for (int i = 0; i < 2; i++) - { + for (int i = 0; i < 2; i++) { int tx = chip_info->bel_data[bel.index].x; int ty = chip_info->bel_data[bel.index].y + i; @@ -641,7 +584,7 @@ std::vector ArchReadMethods::getDecalGraphics(DecalId decal) con el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1; - el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + 7*logic_cell_pitch; + el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + 7 * logic_cell_pitch; el.z = 0; ret.push_back(el); @@ -936,9 +879,6 @@ void ArchMutateMethods::unbindPip(PipId pip) refreshUiWire(dst); } -CellInfo *ArchMutateMethods::getCell(IdString cell) -{ - return parent_->cells.at(cell).get(); -} +CellInfo *ArchMutateMethods::getCell(IdString cell) { return parent_->cells.at(cell).get(); } NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index 5d4eaedf..f41990c3 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -343,7 +343,8 @@ class Arch : public BaseCtx // We let proxy methods access our state. friend class ArchMutateMethods; friend class ArchReadMethods; -private: + + private: // All of the following... std::vector bel_to_cell; std::vector wire_to_net; @@ -353,7 +354,7 @@ private: mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; -public: + public: const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; @@ -410,10 +411,7 @@ public: return id(chip_info->bel_data[bel.index].name.get()); } - uint32_t getBelChecksum(BelId bel) const - { - return bel.index; - } + uint32_t getBelChecksum(BelId bel) const { return bel.index; } BelRange getBels() const { @@ -445,7 +443,6 @@ public: return chip_info->bel_data[bel.index].type; } - BelPin getBelPinUphill(WireId wire) const { BelPin ret; @@ -549,7 +546,6 @@ public: return range; } - BelId getPackagePinBel(const std::string &pin) const; std::string getBelPackagePin(BelId bel) const; @@ -611,8 +607,9 @@ public: }; // Read-only methods on Arch that require state access. -class ArchReadMethods : public BaseReadCtx { -private: +class ArchReadMethods : public BaseReadCtx +{ + private: const Arch *parent_; const ChipInfoPOD *chip_info; const std::vector &bel_to_cell; @@ -623,14 +620,15 @@ private: std::unordered_map &wire_by_name; std::unordered_map &pip_by_name; -public: - ~ArchReadMethods() noexcept { } - ArchReadMethods(const Arch *parent) : BaseReadCtx(parent), parent_(parent), - chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), - bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), - pip_by_name(parent->pip_by_name) {} + public: + ~ArchReadMethods() noexcept {} + ArchReadMethods(const Arch *parent) + : BaseReadCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), + wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), + switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), + wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) + { + } ArchReadMethods(ArchReadMethods &&other) noexcept : ArchReadMethods(other.parent_) {} ArchReadMethods(const ArchReadMethods &other) : ArchReadMethods(other.parent_) {} @@ -669,9 +667,11 @@ public: }; // State mutating methods on Arch. -class ArchMutateMethods : public BaseMutateCtx { +class ArchMutateMethods : public BaseMutateCtx +{ friend class MutateContext; -private: + + private: Arch *parent_; const ChipInfoPOD *chip_info; std::vector &bel_to_cell; @@ -682,13 +682,14 @@ private: std::unordered_map &wire_by_name; std::unordered_map &pip_by_name; -public: - ArchMutateMethods(Arch *parent) : BaseMutateCtx(parent), parent_(parent), - chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), - bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), - pip_by_name(parent->pip_by_name) {} + public: + ArchMutateMethods(Arch *parent) + : BaseMutateCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), + wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), + switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), + wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) + { + } ArchMutateMethods(ArchMutateMethods &&other) : ArchMutateMethods(other.parent_) {} ArchMutateMethods(const ArchMutateMethods &other) : ArchMutateMethods(other.parent_) {} ~ArchMutateMethods() {} -- cgit v1.2.3 From f333a68753655a4ccf7da9a4da96e7fdd19f9d08 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 11:25:38 +0100 Subject: Add read/mutate context stubs for ECP5 --- ecp5/arch.h | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- ice40/arch.h | 4 --- 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/ecp5/arch.h b/ecp5/arch.h index 930c488e..421a7738 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -339,8 +339,10 @@ struct ArchArgs struct Arch : BaseCtx { - const ChipInfoPOD *chip_info; - + // We let proxy methods access our state. + friend class ArchMutateMethods; + friend class ArchReadMethods; +private: mutable std::unordered_map bel_by_name; mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; @@ -350,6 +352,9 @@ struct Arch : BaseCtx std::unordered_map pip_to_net; std::unordered_map switches_locked; +public: + const ChipInfoPOD *chip_info; + ArchArgs args; Arch(ArchArgs args); @@ -762,4 +767,100 @@ struct Arch : BaseCtx bool isBelLocationValid(BelId bel) const; }; +class ArchReadMethods : public BaseReadCtx +{ + private: + const Arch *parent_; + const ChipInfoPOD *chip_info; + + const std::unordered_map &bel_to_cell; + const std::unordered_map &wire_to_net; + const std::unordered_map &pip_to_net; + const std::unordered_map &switches_locked; + std::unordered_map &bel_by_name; + std::unordered_map &wire_by_name; + std::unordered_map &pip_by_name; + + public: + ~ArchReadMethods() noexcept {} + ArchReadMethods(const Arch *parent) + : BaseReadCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), + wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), + switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), + wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) + { + } + ArchReadMethods(ArchReadMethods &&other) noexcept : ArchReadMethods(other.parent_) {} + ArchReadMethods(const ArchReadMethods &other) : ArchReadMethods(other.parent_) {} + + /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) + // Whether or not a given cell can be placed at a given Bel + // This is not intended for Bel type checks, but finer-grained constraints + // such as conflicting set/reset signals, etc + bool isValidBelForCell(CellInfo *cell, BelId bel) const; + // Return true whether all Bels at a given location are valid + bool isBelLocationValid(BelId bel) const; + // Helper function for above + bool logicCellsCompatible(const std::vector &cells) const; + + bool checkWireAvail(WireId wire) const; + bool checkPipAvail(PipId pip) const; + bool checkBelAvail(BelId bel) const; + + WireId getWireByName(IdString name) const; + WireId getWireBelPin(BelId bel, PortPin pin) const; + PipId getPipByName(IdString name) const; + + IdString getConflictingWireNet(WireId wire) const; + IdString getConflictingPipNet(PipId pip) const; + IdString getConflictingBelCell(BelId bel) const; + + IdString getBoundWireNet(WireId wire) const; + IdString getBoundPipNet(PipId pip) const; + IdString getBoundBelCell(BelId bel) const; + + BelId getBelByName(IdString name) const; + + std::vector getDecalGraphics(DecalId decal) const; +}; + +class ArchMutateMethods : public BaseMutateCtx +{ + friend class MutateContext; + + private: + Arch *parent_; + const ChipInfoPOD *chip_info; + + std::unordered_map &bel_to_cell; + std::unordered_map &wire_to_net; + std::unordered_map &pip_to_net; + std::unordered_map &switches_locked; + std::unordered_map &bel_by_name; + std::unordered_map &wire_by_name; + std::unordered_map &pip_by_name; + + public: + ~ArchMutateMethods() noexcept {} + ArchMutateMethods(Arch *parent) + : BaseMutateCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), + wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), + switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), + wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) + { + } + ArchMutateMethods(ArchMutateMethods &&other) noexcept : ArchMutateMethods(other.parent_) {} + ArchMutateMethods(const ArchMutateMethods &other) : ArchMutateMethods(other.parent_) {} + + void unbindWire(WireId wire); + void unbindPip(PipId pip); + void unbindBel(BelId bel); + void bindWire(WireId wire, IdString net, PlaceStrength strength); + void bindPip(PipId pip, IdString net, PlaceStrength strength); + void bindBel(BelId bel, IdString cell, PlaceStrength strength); + // Returned pointer is valid as long as Proxy object exists. + CellInfo *getCell(IdString cell); +}; + + NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index f41990c3..cdee92e4 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -345,7 +345,6 @@ class Arch : public BaseCtx friend class ArchReadMethods; private: - // All of the following... std::vector bel_to_cell; std::vector wire_to_net; std::vector pip_to_net; @@ -633,15 +632,12 @@ class ArchReadMethods : public BaseReadCtx ArchReadMethods(const ArchReadMethods &other) : ArchReadMethods(other.parent_) {} /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) - // Whether or not a given cell can be placed at a given Bel // This is not intended for Bel type checks, but finer-grained constraints // such as conflicting set/reset signals, etc bool isValidBelForCell(CellInfo *cell, BelId bel) const; - // Return true whether all Bels at a given location are valid bool isBelLocationValid(BelId bel) const; - // Helper function for above bool logicCellsCompatible(const std::vector &cells) const; -- cgit v1.2.3 From 3352ff4abbcac563e08d78ed8aa77728d00284a8 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 11:46:32 +0100 Subject: Move read methods to ReadMethods, remove some legacy access to Arch --- common/nextpnr.cc | 9 +++-- ecp5/arch.cc | 105 +++++++++++++++++++++++++++++++++++++++++-------- ecp5/arch.h | 92 ++----------------------------------------- ecp5/arch_pybindings.h | 18 +++++++-- ecp5/bitstream.cc | 5 ++- gui/designwidget.cc | 26 ++++++------ ice40/arch.h | 1 + ice40/picorv32.sh | 8 ++-- 8 files changed, 135 insertions(+), 129 deletions(-) diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 33230db0..01c1397e 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -170,20 +170,21 @@ uint32_t Context::checksum() const void Context::check() const { + auto &&proxy = rproxy(); for (auto &n : nets) { auto ni = n.second.get(); NPNR_ASSERT(n.first == ni->name); for (auto &w : ni->wires) { - NPNR_ASSERT(n.first == getBoundWireNet(w.first)); + NPNR_ASSERT(n.first == proxy.getBoundWireNet(w.first)); if (w.second.pip != PipId()) { NPNR_ASSERT(w.first == getPipDstWire(w.second.pip)); - NPNR_ASSERT(n.first == getBoundPipNet(w.second.pip)); + NPNR_ASSERT(n.first == proxy.getBoundPipNet(w.second.pip)); } } } for (auto w : getWires()) { - IdString net = getBoundWireNet(w); + IdString net = proxy.getBoundWireNet(w); if (net != IdString()) { NPNR_ASSERT(nets.at(net)->wires.count(w)); } @@ -192,7 +193,7 @@ void Context::check() const for (auto &c : cells) { NPNR_ASSERT(c.first == c.second->name); if (c.second->bel != BelId()) - NPNR_ASSERT(getBoundBelCell(c.second->bel) == c.first); + NPNR_ASSERT(proxy.getBoundBelCell(c.second->bel) == c.first); for (auto &port : c.second->ports) { NetInfo *net = port.second.net; if (net != nullptr) { diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 51f4db84..5c5689f0 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -151,7 +151,7 @@ IdString Arch::archArgsToId(ArchArgs args) const // ----------------------------------------------------------------------- -BelId Arch::getBelByName(IdString name) const +BelId ArchReadMethods::getBelByName(IdString name) const { BelId ret; auto it = bel_by_name.find(name); @@ -160,9 +160,9 @@ BelId Arch::getBelByName(IdString name) const Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(parent_)); ret.location = loc; - const LocationTypePOD *loci = locInfo(ret); + const LocationTypePOD *loci = parent_->locInfo(ret); for (int i = 0; i < loci->num_bels; i++) { if (std::strcmp(loci->bel_data[i].name.get(), basename.c_str()) == 0) { ret.index = i; @@ -185,14 +185,14 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const return br; } -WireId Arch::getWireBelPin(BelId bel, PortPin pin) const +WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const { WireId ret; NPNR_ASSERT(bel != BelId()); - int num_bel_wires = locInfo(bel)->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = locInfo(bel)->bel_data[bel.index].bel_wires.get(); + int num_bel_wires = parent_->locInfo(bel)->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = parent_->locInfo(bel)->bel_data[bel.index].bel_wires.get(); for (int i = 0; i < num_bel_wires; i++) if (bel_wires[i].port == pin) { ret.location = bel.location + bel_wires[i].rel_wire_loc; @@ -205,7 +205,7 @@ WireId Arch::getWireBelPin(BelId bel, PortPin pin) const // ----------------------------------------------------------------------- -WireId Arch::getWireByName(IdString name) const +WireId ArchReadMethods::getWireByName(IdString name) const { WireId ret; auto it = wire_by_name.find(name); @@ -214,9 +214,9 @@ WireId Arch::getWireByName(IdString name) const Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(parent_)); ret.location = loc; - const LocationTypePOD *loci = locInfo(ret); + const LocationTypePOD *loci = parent_->locInfo(ret); for (int i = 0; i < loci->num_wires; i++) { if (std::strcmp(loci->wire_data[i].name.get(), basename.c_str()) == 0) { ret.index = i; @@ -233,7 +233,7 @@ WireId Arch::getWireByName(IdString name) const // ----------------------------------------------------------------------- -PipId Arch::getPipByName(IdString name) const +PipId ArchReadMethods::getPipByName(IdString name) const { auto it = pip_by_name.find(name); if (it != pip_by_name.end()) @@ -242,13 +242,13 @@ PipId Arch::getPipByName(IdString name) const PipId ret; Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); - const LocationTypePOD *loci = locInfo(ret); + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(parent_)); + const LocationTypePOD *loci = parent_->locInfo(ret); for (int i = 0; i < loci->num_pips; i++) { PipId curr; curr.location = loc; curr.index = i; - pip_by_name[getPipName(curr)] = curr; + pip_by_name[parent_->getPipName(curr)] = curr; } return pip_by_name[name]; } @@ -296,7 +296,7 @@ bool Arch::route() { return router1(getCtx()); } // ----------------------------------------------------------------------- -std::vector Arch::getDecalGraphics(DecalId decalId) const +std::vector ArchReadMethods::getDecalGraphics(DecalId decalId) const { std::vector ret; // FIXME @@ -315,9 +315,9 @@ DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; }; // ----------------------------------------------------------------------- -bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; } +bool ArchReadMethods::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; } -bool Arch::isBelLocationValid(BelId bel) const { return true; } +bool ArchReadMethods::isBelLocationValid(BelId bel) const { return true; } // ----------------------------------------------------------------------- @@ -330,4 +330,77 @@ IdString Arch::getPortClock(const CellInfo *cell, IdString port) const { return bool Arch::isClockPort(const CellInfo *cell, IdString port) const { return false; } +bool ArchReadMethods::checkWireAvail(WireId wire) const +{ + NPNR_ASSERT(wire != WireId()); + return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == IdString(); +} + +bool ArchReadMethods::checkPipAvail(PipId pip) const +{ + NPNR_ASSERT(pip != PipId()); + return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == IdString(); +} + +bool ArchReadMethods::checkBelAvail(BelId bel) const +{ + NPNR_ASSERT(bel != BelId()); + return bel_to_cell.find(bel) == bel_to_cell.end() || bel_to_cell.at(bel) == IdString(); +} + +IdString ArchReadMethods::getConflictingBelCell(BelId bel) const +{ + NPNR_ASSERT(bel != BelId()); + if (bel_to_cell.find(bel) == bel_to_cell.end()) + return IdString(); + else + return bel_to_cell.at(bel); +} + +IdString ArchReadMethods::getConflictingWireNet(WireId wire) const +{ + NPNR_ASSERT(wire != WireId()); + if (wire_to_net.find(wire) == wire_to_net.end()) + return IdString(); + else + return wire_to_net.at(wire); +} + +IdString ArchReadMethods::getConflictingPipNet(PipId pip) const +{ + NPNR_ASSERT(pip != PipId()); + if (pip_to_net.find(pip) == pip_to_net.end()) + return IdString(); + else + return pip_to_net.at(pip); +} + +IdString ArchReadMethods::getBoundWireNet(WireId wire) const +{ + NPNR_ASSERT(wire != WireId()); + if (wire_to_net.find(wire) == wire_to_net.end()) + return IdString(); + else + return wire_to_net.at(wire); +} + +IdString ArchReadMethods::getBoundPipNet(PipId pip) const +{ + NPNR_ASSERT(pip != PipId()); + if (pip_to_net.find(pip) == pip_to_net.end()) + return IdString(); + else + return pip_to_net.at(pip); +} + +IdString ArchReadMethods::getBoundBelCell(BelId bel) const +{ + NPNR_ASSERT(bel != BelId()); + if (bel_to_cell.find(bel) == bel_to_cell.end()) + return IdString(); + else + return bel_to_cell.at(bel); +} + + NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch.h b/ecp5/arch.h index 421a7738..50897b86 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -371,8 +371,6 @@ public: // ------------------------------------------------- - BelId getBelByName(IdString name) const; - template const LocationTypePOD *locInfo(Id &id) const { return &(chip_info->locations[chip_info->location_type[id.location.y * chip_info->width + id.location.x]]); @@ -406,30 +404,6 @@ public: bel_to_cell[bel] = IdString(); } - bool checkBelAvail(BelId bel) const - { - NPNR_ASSERT(bel != BelId()); - return bel_to_cell.find(bel) == bel_to_cell.end() || bel_to_cell.at(bel) == IdString(); - } - - IdString getBoundBelCell(BelId bel) const - { - NPNR_ASSERT(bel != BelId()); - if (bel_to_cell.find(bel) == bel_to_cell.end()) - return IdString(); - else - return bel_to_cell.at(bel); - } - - IdString getConflictingBelCell(BelId bel) const - { - NPNR_ASSERT(bel != BelId()); - if (bel_to_cell.find(bel) == bel_to_cell.end()) - return IdString(); - else - return bel_to_cell.at(bel); - } - BelRange getBels() const { BelRange range; @@ -465,8 +439,6 @@ public: return locInfo(bel)->bel_data[bel.index].type; } - WireId getWireBelPin(BelId bel, PortPin pin) const; - BelPin getBelPinUphill(WireId wire) const { BelPin ret; @@ -494,8 +466,6 @@ public: // ------------------------------------------------- - WireId getWireByName(IdString name) const; - IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); @@ -535,30 +505,6 @@ public: wire_to_net[wire] = IdString(); } - bool checkWireAvail(WireId wire) const - { - NPNR_ASSERT(wire != WireId()); - return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == IdString(); - } - - IdString getBoundWireNet(WireId wire) const - { - NPNR_ASSERT(wire != WireId()); - if (wire_to_net.find(wire) == wire_to_net.end()) - return IdString(); - else - return wire_to_net.at(wire); - } - - IdString getConflictingWireNet(WireId wire) const - { - NPNR_ASSERT(wire != WireId()); - if (wire_to_net.find(wire) == wire_to_net.end()) - return IdString(); - else - return wire_to_net.at(wire); - } - WireRange getWires() const { WireRange range; @@ -574,7 +520,6 @@ public: // ------------------------------------------------- - PipId getPipByName(IdString name) const; IdString getPipName(PipId pip) const; uint32_t getPipChecksum(PipId pip) const { return pip.index; } @@ -610,30 +555,6 @@ public: pip_to_net[pip] = IdString(); } - bool checkPipAvail(PipId pip) const - { - NPNR_ASSERT(pip != PipId()); - return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == IdString(); - } - - IdString getBoundPipNet(PipId pip) const - { - NPNR_ASSERT(pip != PipId()); - if (pip_to_net.find(pip) == pip_to_net.end()) - return IdString(); - else - return pip_to_net.at(pip); - } - - IdString getConflictingPipNet(PipId pip) const - { - NPNR_ASSERT(pip != PipId()); - if (pip_to_net.find(pip) == pip_to_net.end()) - return IdString(); - else - return pip_to_net.at(pip); - } - AllPipRange getPips() const { AllPipRange range; @@ -716,6 +637,7 @@ public: // ------------------------------------------------- + // TODO(q3k) move this to archproxies? GroupId getGroupByName(IdString name) const { return GroupId(); } IdString getGroupName(GroupId group) const { return IdString(); } std::vector getGroups() const { return std::vector(); } @@ -726,6 +648,8 @@ public: // ------------------------------------------------- + // These are also specific to the chip and not state, so they're available + // on arch directly. void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; delay_t estimateDelay(WireId src, WireId dst) const; delay_t getDelayEpsilon() const { return 20; } @@ -741,8 +665,7 @@ public: // ------------------------------------------------- - std::vector getDecalGraphics(DecalId decal) const; - + // TODO(q3k) move this to archproxies? DecalXY getFrameDecal() const; DecalXY getBelDecal(BelId bel) const; DecalXY getWireDecal(WireId wire) const; @@ -760,11 +683,6 @@ public: bool isClockPort(const CellInfo *cell, IdString port) const; // Return true if a port is a net bool isGlobalNet(const NetInfo *net) const; - - // ------------------------------------------------- - // Placement validity checks - bool isValidBelForCell(CellInfo *cell, BelId bel) const; - bool isBelLocationValid(BelId bel) const; }; class ArchReadMethods : public BaseReadCtx @@ -800,8 +718,6 @@ class ArchReadMethods : public BaseReadCtx bool isValidBelForCell(CellInfo *cell, BelId bel) const; // Return true whether all Bels at a given location are valid bool isBelLocationValid(BelId bel) const; - // Helper function for above - bool logicCellsCompatible(const std::vector &cells) const; bool checkWireAvail(WireId wire) const; bool checkPipAvail(PipId pip) const; diff --git a/ecp5/arch_pybindings.h b/ecp5/arch_pybindings.h index a5044f29..6256af18 100644 --- a/ecp5/arch_pybindings.h +++ b/ecp5/arch_pybindings.h @@ -30,7 +30,11 @@ namespace PythonConversion { template <> struct string_converter { - BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); } + BelId from_str(Context *ctx, std::string name) + { + auto &&proxy = ctx->rproxy(); + return proxy.getBelByName(ctx->id(name)); + } std::string to_str(Context *ctx, BelId id) { @@ -49,14 +53,22 @@ template <> struct string_converter template <> struct string_converter { - WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); } + WireId from_str(Context *ctx, std::string name) + { + auto &&proxy = ctx->rproxy(); + return proxy.getWireByName(ctx->id(name)); + } std::string to_str(Context *ctx, WireId id) { return ctx->getWireName(id).str(ctx); } }; template <> struct string_converter { - PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(ctx->id(name)); } + PipId from_str(Context *ctx, std::string name) + { + auto &&proxy = ctx->rproxy(); + return proxy.getPipByName(ctx->id(name)); + } std::string to_str(Context *ctx, PipId id) { return ctx->getPipName(id).str(ctx); } }; diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index e70d6bb2..b2376391 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -155,6 +155,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex { Trellis::Chip empty_chip(ctx->getChipName()); Trellis::ChipConfig cc; + auto &&proxy = ctx->rproxy(); std::set cib_tiles = {"CIB", "CIB_LR", "CIB_LR_S", "CIB_EFB0", "CIB_EFB1"}; @@ -172,7 +173,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex // Add all set, configurable pips to the config for (auto pip : ctx->getPips()) { - if (ctx->getBoundPipNet(pip) != IdString()) { + if (proxy.getBoundPipNet(pip) != IdString()) { if (ctx->getPipType(pip) == 0) { // ignore fixed pips std::string tile = empty_chip.get_tile_by_position_and_type(pip.location.y, pip.location.x, ctx->getPipTiletype(pip)); @@ -227,7 +228,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex (ci->ports.find(ctx->id("T")) == ci->ports.end() || ci->ports.at(ctx->id("T")).net == nullptr)) { // Tie tristate low if unconnected for outputs or bidir std::string jpt = fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/JPADDT" << pio.back()); - WireId jpt_wire = ctx->getWireByName(ctx->id(jpt)); + WireId jpt_wire = proxy.getWireByName(ctx->id(jpt)); PipId jpt_pip = *ctx->getPipsUphill(jpt_wire).begin(); WireId cib_wire = ctx->getPipSrcWire(jpt_pip); std::string cib_tile = diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 110cf1b7..e839f006 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -335,10 +335,12 @@ void DesignWidget::onItemClicked(QTreeWidgetItem *clickItem, int pos) return; } + auto &&proxy = ctx->rproxy(); + clearProperties(); if (type == ElementType::BEL) { IdString c = static_cast(clickItem)->getData(); - BelId bel = ctx->getBelByName(c); + BelId bel = proxy.getBelByName(c); QtProperty *topItem = groupManager->addProperty("Bel"); addProperty(topItem, "Bel"); @@ -352,20 +354,20 @@ void DesignWidget::onItemClicked(QTreeWidgetItem *clickItem, int pos) topItem->addSubProperty(typeItem); QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available"); - availItem->setValue(ctx->checkBelAvail(bel)); + availItem->setValue(proxy.checkBelAvail(bel)); topItem->addSubProperty(availItem); QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Cell"); - cellItem->setValue(ctx->getBoundBelCell(bel).c_str(ctx)); + cellItem->setValue(proxy.getBoundBelCell(bel).c_str(ctx)); topItem->addSubProperty(cellItem); QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Cell"); - conflictItem->setValue(ctx->getConflictingBelCell(bel).c_str(ctx)); + conflictItem->setValue(proxy.getConflictingBelCell(bel).c_str(ctx)); topItem->addSubProperty(conflictItem); } else if (type == ElementType::WIRE) { IdString c = static_cast(clickItem)->getData(); - WireId wire = ctx->getWireByName(c); + WireId wire = proxy.getWireByName(c); QtProperty *topItem = groupManager->addProperty("Wire"); addProperty(topItem, "Wire"); @@ -375,15 +377,15 @@ void DesignWidget::onItemClicked(QTreeWidgetItem *clickItem, int pos) topItem->addSubProperty(nameItem); QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available"); - availItem->setValue(ctx->checkWireAvail(wire)); + availItem->setValue(proxy.checkWireAvail(wire)); topItem->addSubProperty(availItem); QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Net"); - cellItem->setValue(ctx->getBoundWireNet(wire).c_str(ctx)); + cellItem->setValue(proxy.getBoundWireNet(wire).c_str(ctx)); topItem->addSubProperty(cellItem); QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Net"); - conflictItem->setValue(ctx->getConflictingWireNet(wire).c_str(ctx)); + conflictItem->setValue(proxy.getConflictingWireNet(wire).c_str(ctx)); topItem->addSubProperty(conflictItem); BelPin uphill = ctx->getBelPinUphill(wire); @@ -439,7 +441,7 @@ void DesignWidget::onItemClicked(QTreeWidgetItem *clickItem, int pos) } else if (type == ElementType::PIP) { IdString c = static_cast(clickItem)->getData(); - PipId pip = ctx->getPipByName(c); + PipId pip = proxy.getPipByName(c); QtProperty *topItem = groupManager->addProperty("Pip"); addProperty(topItem, "Pip"); @@ -449,15 +451,15 @@ void DesignWidget::onItemClicked(QTreeWidgetItem *clickItem, int pos) topItem->addSubProperty(nameItem); QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available"); - availItem->setValue(ctx->checkPipAvail(pip)); + availItem->setValue(proxy.checkPipAvail(pip)); topItem->addSubProperty(availItem); QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Net"); - cellItem->setValue(ctx->getBoundPipNet(pip).c_str(ctx)); + cellItem->setValue(proxy.getBoundPipNet(pip).c_str(ctx)); topItem->addSubProperty(cellItem); QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Net"); - conflictItem->setValue(ctx->getConflictingPipNet(pip).c_str(ctx)); + conflictItem->setValue(proxy.getConflictingPipNet(pip).c_str(ctx)); topItem->addSubProperty(conflictItem); QtVariantProperty *srcWireItem = readOnlyManager->addProperty(QVariant::String, "Src Wire"); diff --git a/ice40/arch.h b/ice40/arch.h index cdee92e4..ec1e456f 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -578,6 +578,7 @@ class Arch : public BaseCtx // ------------------------------------------------- + // TODO(q3k) move this to archproxies? DecalXY getFrameDecal() const; DecalXY getBelDecal(BelId bel) const; DecalXY getWireDecal(WireId wire) const; diff --git a/ice40/picorv32.sh b/ice40/picorv32.sh index 2c67f641..0518db83 100755 --- a/ice40/picorv32.sh +++ b/ice40/picorv32.sh @@ -1,6 +1,6 @@ #!/bin/bash set -ex -rm -f picorv32.v -wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v -yosys -p 'synth_ice40 -nocarry -json picorv32.json -top top' picorv32.v picorv32_top.v -../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json +#rm -f picorv32.v +#wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v +#yosys -p 'synth_ice40 -nocarry -json picorv32.json -top top' picorv32.v picorv32_top.v +CPUPROFILE=../profile ../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json -- cgit v1.2.3 From df5d7923ec00d18aa832ae5f8859a1120365cb27 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 11:52:50 +0100 Subject: Make ECP5 proxy context compatible --- ecp5/arch.cc | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ecp5/arch.h | 76 --------------------------------------------------------- 2 files changed, 79 insertions(+), 76 deletions(-) diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 5c5689f0..1938c297 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -402,5 +402,84 @@ IdString ArchReadMethods::getBoundBelCell(BelId bel) const return bel_to_cell.at(bel); } +void ArchMutateMethods::unbindWire(WireId wire) +{ + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire] != IdString()); + + auto &net_wires = parent_->nets[wire_to_net[wire]]->wires; + auto it = net_wires.find(wire); + NPNR_ASSERT(it != net_wires.end()); + + auto pip = it->second.pip; + if (pip != PipId()) { + pip_to_net[pip] = IdString(); + } + + net_wires.erase(it); + wire_to_net[wire] = IdString(); +} + +void ArchMutateMethods::unbindPip(PipId pip) +{ + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip] != IdString()); + + WireId dst; + dst.index = parent_->locInfo(pip)->pip_data[pip.index].dst_idx; + dst.location = pip.location + parent_->locInfo(pip)->pip_data[pip.index].rel_dst_loc; + NPNR_ASSERT(wire_to_net[dst] != IdString()); + wire_to_net[dst] = IdString(); + parent_->nets[pip_to_net[pip]]->wires.erase(dst); + + pip_to_net[pip] = IdString(); +} + +void ArchMutateMethods::unbindBel(BelId bel) +{ + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel] != IdString()); + parent_->cells[bel_to_cell[bel]]->bel = BelId(); + parent_->cells[bel_to_cell[bel]]->belStrength = STRENGTH_NONE; + bel_to_cell[bel] = IdString(); +} + +void ArchMutateMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) +{ + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire] == IdString()); + wire_to_net[wire] = net; + parent_->nets[net]->wires[wire].pip = PipId(); + parent_->nets[net]->wires[wire].strength = strength; +} + +void ArchMutateMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) +{ + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip] == IdString()); + + pip_to_net[pip] = net; + + WireId dst; + dst.index = parent_->locInfo(pip)->pip_data[pip.index].dst_idx; + dst.location = pip.location + parent_->locInfo(pip)->pip_data[pip.index].rel_dst_loc; + NPNR_ASSERT(wire_to_net[dst] == IdString()); + wire_to_net[dst] = net; + parent_->nets[net]->wires[dst].pip = pip; + parent_->nets[net]->wires[dst].strength = strength; +} + +void ArchMutateMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) +{ + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel] == IdString()); + bel_to_cell[bel] = cell; + parent_->cells[cell]->bel = bel; + parent_->cells[cell]->belStrength = strength; +} + +CellInfo *ArchMutateMethods::getCell(IdString cell) { return parent_->cells.at(cell).get(); } + + NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch.h b/ecp5/arch.h index 50897b86..06cf6488 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -386,24 +386,6 @@ public: uint32_t getBelChecksum(BelId bel) const { return bel.index; } - void bindBel(BelId bel, IdString cell, PlaceStrength strength) - { - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel] == IdString()); - bel_to_cell[bel] = cell; - cells[cell]->bel = bel; - cells[cell]->belStrength = strength; - } - - void unbindBel(BelId bel) - { - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel] != IdString()); - cells[bel_to_cell[bel]]->bel = BelId(); - cells[bel_to_cell[bel]]->belStrength = STRENGTH_NONE; - bel_to_cell[bel] = IdString(); - } - BelRange getBels() const { BelRange range; @@ -478,33 +460,6 @@ public: uint32_t getWireChecksum(WireId wire) const { return wire.index; } - void bindWire(WireId wire, IdString net, PlaceStrength strength) - { - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire] == IdString()); - wire_to_net[wire] = net; - nets[net]->wires[wire].pip = PipId(); - nets[net]->wires[wire].strength = strength; - } - - void unbindWire(WireId wire) - { - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire] != IdString()); - - auto &net_wires = nets[wire_to_net[wire]]->wires; - auto it = net_wires.find(wire); - NPNR_ASSERT(it != net_wires.end()); - - auto pip = it->second.pip; - if (pip != PipId()) { - pip_to_net[pip] = IdString(); - } - - net_wires.erase(it); - wire_to_net[wire] = IdString(); - } - WireRange getWires() const { WireRange range; @@ -524,37 +479,6 @@ public: uint32_t getPipChecksum(PipId pip) const { return pip.index; } - void bindPip(PipId pip, IdString net, PlaceStrength strength) - { - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip] == IdString()); - - pip_to_net[pip] = net; - - WireId dst; - dst.index = locInfo(pip)->pip_data[pip.index].dst_idx; - dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc; - NPNR_ASSERT(wire_to_net[dst] == IdString()); - wire_to_net[dst] = net; - nets[net]->wires[dst].pip = pip; - nets[net]->wires[dst].strength = strength; - } - - void unbindPip(PipId pip) - { - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip] != IdString()); - - WireId dst; - dst.index = locInfo(pip)->pip_data[pip.index].dst_idx; - dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc; - NPNR_ASSERT(wire_to_net[dst] != IdString()); - wire_to_net[dst] = IdString(); - nets[pip_to_net[pip]]->wires.erase(dst); - - pip_to_net[pip] = IdString(); - } - AllPipRange getPips() const { AllPipRange range; -- cgit v1.2.3 From 18b4b316782035daa259d65d26ea733ca4d16bea Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 12:02:28 +0100 Subject: Remove legacy access to state via Arch --- ice40/arch.cc | 41 ------------------------------- ice40/arch.h | 28 --------------------- ice40/arch_pybindings.cc | 64 ++++++++++++++++++++++++------------------------ ice40/arch_pybindings.h | 18 +++++++++++--- ice40/bitstream.cc | 13 +++++----- ice40/main.cc | 21 ++++++++-------- 6 files changed, 65 insertions(+), 120 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 8f2731c6..4727597b 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -256,47 +256,6 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const return br; } -// ----------------------------------------------------------------------- -// Shorthands to ArchProxy - -BelId Arch::getBelByName(IdString name) const { return rproxy().getBelByName(name); } - -void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength) { rwproxy().bindWire(wire, net, strength); } - -void Arch::unbindWire(WireId wire) { rwproxy().unbindWire(wire); } - -void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength) { rwproxy().bindBel(bel, cell, strength); } - -void Arch::unbindBel(BelId bel) { rwproxy().unbindBel(bel); } - -bool Arch::checkBelAvail(BelId bel) const { return rproxy().checkBelAvail(bel); } - -IdString Arch::getBoundBelCell(BelId bel) const { return rproxy().getBoundBelCell(bel); } - -IdString Arch::getConflictingBelCell(BelId bel) const { return rproxy().getConflictingBelCell(bel); } - -WireId Arch::getWireByName(IdString name) const { return rproxy().getWireByName(name); } - -WireId Arch::getWireBelPin(BelId bel, PortPin pin) const { return rproxy().getWireBelPin(bel, pin); } - -bool Arch::checkWireAvail(WireId wire) const { return rproxy().checkWireAvail(wire); } - -IdString Arch::getBoundWireNet(WireId wire) const { return rproxy().getBoundWireNet(wire); } - -IdString Arch::getConflictingWireNet(WireId wire) const { return rproxy().getConflictingWireNet(wire); } - -PipId Arch::getPipByName(IdString name) const { return rproxy().getPipByName(name); } - -void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength) { return rwproxy().bindPip(pip, net, strength); } - -void Arch::unbindPip(PipId pip) { return rwproxy().unbindPip(pip); } - -bool Arch::checkPipAvail(PipId pip) const { return rproxy().checkPipAvail(pip); } - -IdString Arch::getBoundPipNet(PipId pip) const { return rproxy().getBoundPipNet(pip); } - -IdString Arch::getConflictingPipNet(PipId pip) const { return rproxy().getConflictingPipNet(pip); } - // ----------------------------------------------------------------------- IdString Arch::getPipName(PipId pip) const diff --git a/ice40/arch.h b/ice40/arch.h index ec1e456f..25ed8ebf 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -373,34 +373,6 @@ class Arch : public BaseCtx // ------------------------------------------------- - /// Wrappers around getting a r(w)proxy and calling a single method. - // Deprecated: please acquire a proxy yourself and call the methods - // you want on it. - // Warning: these will content with locks taken by the r(w)proxies, and - // thus can cause difficult to debug deadlocks - we'll be getting rid of - // them because of that. - void unbindWire(WireId wire); - void unbindPip(PipId pip); - void unbindBel(BelId bel); - void bindWire(WireId wire, IdString net, PlaceStrength strength); - void bindPip(PipId pip, IdString net, PlaceStrength strength); - void bindBel(BelId bel, IdString cell, PlaceStrength strength); - bool checkWireAvail(WireId wire) const; - bool checkPipAvail(PipId pip) const; - bool checkBelAvail(BelId bel) const; - WireId getWireByName(IdString name) const; - WireId getWireBelPin(BelId bel, PortPin pin) const; - PipId getPipByName(IdString name) const; - IdString getConflictingWireNet(WireId wire) const; - IdString getConflictingPipNet(PipId pip) const; - IdString getConflictingBelCell(BelId bel) const; - IdString getBoundWireNet(WireId wire) const; - IdString getBoundPipNet(PipId pip) const; - IdString getBoundBelCell(BelId bel) const; - BelId getBelByName(IdString name) const; - - // ------------------------------------------------- - /// Methods to get chip info - don't need to use a wrapper, as these are /// static per lifetime of object. diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc index fd5109b4..aeb4348a 100644 --- a/ice40/arch_pybindings.cc +++ b/ice40/arch_pybindings.cc @@ -65,25 +65,25 @@ void arch_wrap_python() fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelType"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "checkBelAvail"); + //fn_wrapper_1a, + // conv_from_str>::def_wrap(ctx_cls, "checkBelAvail"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelChecksum"); - fn_wrapper_3a_v, - conv_from_str, pass_through>::def_wrap(ctx_cls, "bindBel"); - fn_wrapper_1a_v>::def_wrap( - ctx_cls, "unbindBel"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getBoundBelCell"); - fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingBelCell"); + //fn_wrapper_3a_v, + // conv_from_str, pass_through>::def_wrap(ctx_cls, "bindBel"); + //fn_wrapper_1a_v>::def_wrap( + // ctx_cls, "unbindBel"); + //fn_wrapper_1a, + // conv_from_str>::def_wrap(ctx_cls, "getBoundBelCell"); + //fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingBelCell"); fn_wrapper_0a>::def_wrap(ctx_cls, "getBels"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelsAtSameTile"); - fn_wrapper_2a, - conv_from_str, conv_from_str>::def_wrap(ctx_cls, "getWireBelPin"); + //fn_wrapper_2a, + // conv_from_str, conv_from_str>::def_wrap(ctx_cls, "getWireBelPin"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelPinUphill"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getWireChecksum"); - fn_wrapper_3a_v, - conv_from_str, pass_through>::def_wrap(ctx_cls, "bindWire"); - fn_wrapper_1a_v>::def_wrap( - ctx_cls, "unbindWire"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "checkWireAvail"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getBoundWireNet"); - fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingWireNet"); + //fn_wrapper_3a_v, + // conv_from_str, pass_through>::def_wrap(ctx_cls, "bindWire"); + //fn_wrapper_1a_v>::def_wrap( + // ctx_cls, "unbindWire"); + //fn_wrapper_1a, + // conv_from_str>::def_wrap(ctx_cls, "checkWireAvail"); + //fn_wrapper_1a, + // conv_from_str>::def_wrap(ctx_cls, "getBoundWireNet"); + //fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingWireNet"); fn_wrapper_0a>::def_wrap( ctx_cls, "getWires"); @@ -109,16 +109,16 @@ void arch_wrap_python() ctx_cls, "getPips"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getPipChecksum"); - fn_wrapper_3a_v, - conv_from_str, pass_through>::def_wrap(ctx_cls, "bindPip"); - fn_wrapper_1a_v>::def_wrap( - ctx_cls, "unbindPip"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "checkPipAvail"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getBoundPipNet"); - fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingPipNet"); + //fn_wrapper_3a_v, + // conv_from_str, pass_through>::def_wrap(ctx_cls, "bindPip"); + //fn_wrapper_1a_v>::def_wrap( + // ctx_cls, "unbindPip"); + //fn_wrapper_1a, + // conv_from_str>::def_wrap(ctx_cls, "checkPipAvail"); + //fn_wrapper_1a, + // conv_from_str>::def_wrap(ctx_cls, "getBoundPipNet"); + //fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingPipNet"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getPipsDownhill"); diff --git a/ice40/arch_pybindings.h b/ice40/arch_pybindings.h index e502905f..7440e29d 100644 --- a/ice40/arch_pybindings.h +++ b/ice40/arch_pybindings.h @@ -31,7 +31,11 @@ namespace PythonConversion { template <> struct string_converter { - BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); } + BelId from_str(Context *ctx, std::string name) + { + auto &&proxy = ctx->rproxy(); + return proxy.getBelByName(ctx->id(name)); + } std::string to_str(Context *ctx, BelId id) { @@ -50,14 +54,22 @@ template <> struct string_converter template <> struct string_converter { - WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); } + WireId from_str(Context *ctx, std::string name) + { + auto &&proxy = ctx->rproxy(); + return proxy.getWireByName(ctx->id(name)); + } std::string to_str(Context *ctx, WireId id) { return ctx->getWireName(id).str(ctx); } }; template <> struct string_converter { - PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(ctx->id(name)); } + PipId from_str(Context *ctx, std::string name) + { + auto &&proxy = ctx->rproxy(); + return proxy.getPipByName(ctx->id(name)); + } std::string to_str(Context *ctx, PipId id) { return ctx->getPipName(id).str(ctx); } }; diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 58a59366..87a96a22 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -92,6 +92,7 @@ char get_hexdigit(int i) { return std::string("0123456789ABCDEF").at(i); } void write_asc(const Context *ctx, std::ostream &out) { + auto &&proxy = ctx->rproxy(); // [y][x][row][col] const ChipInfoPOD &ci = *ctx->chip_info; const BitstreamInfoPOD &bi = *ci.bits_info; @@ -128,7 +129,7 @@ void write_asc(const Context *ctx, std::ostream &out) } // Set pips for (auto pip : ctx->getPips()) { - if (ctx->getBoundPipNet(pip) != IdString()) { + if (proxy.getBoundPipNet(pip) != IdString()) { const PipInfoPOD &pi = ci.pip_data[pip.index]; const SwitchInfoPOD &swi = bi.switches[pi.switch_index]; for (int i = 0; i < swi.num_bits; i++) { @@ -199,8 +200,8 @@ void write_asc(const Context *ctx, std::ostream &out) NPNR_ASSERT(iez != -1); bool input_en = false; - if (!ctx->checkWireAvail(ctx->getWireBelPin(bel, PIN_D_IN_0)) || - !ctx->checkWireAvail(ctx->getWireBelPin(bel, PIN_D_IN_1))) { + if (!proxy.checkWireAvail(proxy.getWireBelPin(bel, PIN_D_IN_0)) || + !proxy.checkWireAvail(proxy.getWireBelPin(bel, PIN_D_IN_1))) { input_en = true; } @@ -271,7 +272,7 @@ void write_asc(const Context *ctx, std::ostream &out) } // Set config bits in unused IO and RAM for (auto bel : ctx->getBels()) { - if (ctx->checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_SB_IO) { + if (proxy.checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_SB_IO) { const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y, z = beli.z; @@ -284,7 +285,7 @@ void write_asc(const Context *ctx, std::ostream &out) set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); } } - } else if (ctx->checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) { + } else if (proxy.checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) { const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB]; @@ -431,7 +432,7 @@ void write_asc(const Context *ctx, std::ostream &out) // Write symbols // const bool write_symbols = 1; for (auto wire : ctx->getWires()) { - IdString net = ctx->getBoundWireNet(wire); + IdString net = proxy.getBoundWireNet(wire); if (net != IdString()) out << ".sym " << wire.index << " " << net.str(ctx) << std::endl; } diff --git a/ice40/main.cc b/ice40/main.cc index d38c786c..fdfe1f25 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -304,31 +304,32 @@ int main(int argc, char *argv[]) } if (vm.count("tmfuzz")) { + auto &&proxy = ctx->rproxy(); std::vector src_wires, dst_wires; /*for (auto w : ctx->getWires()) src_wires.push_back(w);*/ for (auto b : ctx->getBels()) { if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { - src_wires.push_back(ctx->getWireBelPin(b, PIN_O)); + src_wires.push_back(proxy.getWireBelPin(b, PIN_O)); } if (ctx->getBelType(b) == TYPE_SB_IO) { - src_wires.push_back(ctx->getWireBelPin(b, PIN_D_IN_0)); + src_wires.push_back(proxy.getWireBelPin(b, PIN_D_IN_0)); } } for (auto b : ctx->getBels()) { if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { - dst_wires.push_back(ctx->getWireBelPin(b, PIN_I0)); - dst_wires.push_back(ctx->getWireBelPin(b, PIN_I1)); - dst_wires.push_back(ctx->getWireBelPin(b, PIN_I2)); - dst_wires.push_back(ctx->getWireBelPin(b, PIN_I3)); - dst_wires.push_back(ctx->getWireBelPin(b, PIN_CEN)); - dst_wires.push_back(ctx->getWireBelPin(b, PIN_CIN)); + dst_wires.push_back(proxy.getWireBelPin(b, PIN_I0)); + dst_wires.push_back(proxy.getWireBelPin(b, PIN_I1)); + dst_wires.push_back(proxy.getWireBelPin(b, PIN_I2)); + dst_wires.push_back(proxy.getWireBelPin(b, PIN_I3)); + dst_wires.push_back(proxy.getWireBelPin(b, PIN_CEN)); + dst_wires.push_back(proxy.getWireBelPin(b, PIN_CIN)); } if (ctx->getBelType(b) == TYPE_SB_IO) { - dst_wires.push_back(ctx->getWireBelPin(b, PIN_D_OUT_0)); - dst_wires.push_back(ctx->getWireBelPin(b, PIN_OUTPUT_ENABLE)); + dst_wires.push_back(proxy.getWireBelPin(b, PIN_D_OUT_0)); + dst_wires.push_back(proxy.getWireBelPin(b, PIN_OUTPUT_ENABLE)); } } -- cgit v1.2.3 From 53393b993fb211a3ce98262b0dd636d2e8420d2d Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 12:11:20 +0100 Subject: Remove unimplemented pybindings (for now) We need to re-jigger the template magic in common/pywrappers.h to be proxy context aware. --- ice40/arch_pybindings.cc | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc index aeb4348a..a2a90191 100644 --- a/ice40/arch_pybindings.cc +++ b/ice40/arch_pybindings.cc @@ -65,25 +65,13 @@ void arch_wrap_python() fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelType"); - //fn_wrapper_1a, - // conv_from_str>::def_wrap(ctx_cls, "checkBelAvail"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelChecksum"); - //fn_wrapper_3a_v, - // conv_from_str, pass_through>::def_wrap(ctx_cls, "bindBel"); - //fn_wrapper_1a_v>::def_wrap( - // ctx_cls, "unbindBel"); - //fn_wrapper_1a, - // conv_from_str>::def_wrap(ctx_cls, "getBoundBelCell"); - //fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingBelCell"); fn_wrapper_0a>::def_wrap(ctx_cls, "getBels"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelsAtSameTile"); - //fn_wrapper_2a, - // conv_from_str, conv_from_str>::def_wrap(ctx_cls, "getWireBelPin"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelPinUphill"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getWireChecksum"); - //fn_wrapper_3a_v, - // conv_from_str, pass_through>::def_wrap(ctx_cls, "bindWire"); - //fn_wrapper_1a_v>::def_wrap( - // ctx_cls, "unbindWire"); - //fn_wrapper_1a, - // conv_from_str>::def_wrap(ctx_cls, "checkWireAvail"); - //fn_wrapper_1a, - // conv_from_str>::def_wrap(ctx_cls, "getBoundWireNet"); - //fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingWireNet"); fn_wrapper_0a>::def_wrap( ctx_cls, "getWires"); @@ -109,16 +87,6 @@ void arch_wrap_python() ctx_cls, "getPips"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getPipChecksum"); - //fn_wrapper_3a_v, - // conv_from_str, pass_through>::def_wrap(ctx_cls, "bindPip"); - //fn_wrapper_1a_v>::def_wrap( - // ctx_cls, "unbindPip"); - //fn_wrapper_1a, - // conv_from_str>::def_wrap(ctx_cls, "checkPipAvail"); - //fn_wrapper_1a, - // conv_from_str>::def_wrap(ctx_cls, "getBoundPipNet"); - //fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingPipNet"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getPipsDownhill"); -- cgit v1.2.3 From 98c594885698b557311ac84195599b35968719e0 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 12:14:30 +0100 Subject: Undo accidental picorv32.sh commit --- ice40/picorv32.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ice40/picorv32.sh b/ice40/picorv32.sh index 0518db83..2c67f641 100755 --- a/ice40/picorv32.sh +++ b/ice40/picorv32.sh @@ -1,6 +1,6 @@ #!/bin/bash set -ex -#rm -f picorv32.v -#wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v -#yosys -p 'synth_ice40 -nocarry -json picorv32.json -top top' picorv32.v picorv32_top.v -CPUPROFILE=../profile ../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json +rm -f picorv32.v +wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v +yosys -p 'synth_ice40 -nocarry -json picorv32.json -top top' picorv32.v picorv32_top.v +../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json -- cgit v1.2.3 From 5216e488639fc8420d38c35177b796e1cf56ac8b Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sat, 14 Jul 2018 14:06:05 +0200 Subject: join python and info into one tab --- CMakeLists.txt | 4 ++++ gui/basewindow.cc | 16 +++++----------- gui/basewindow.h | 5 +++-- gui/ice40/mainwindow.cc | 6 ------ gui/line_editor.cc | 4 ---- gui/line_editor.h | 4 ---- gui/pyconsole.cc | 5 +---- gui/pyconsole.h | 3 --- gui/pythontab.cc | 6 ++---- gui/pythontab.h | 6 ++---- 10 files changed, 17 insertions(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78c8b5a2..3ca7935e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,10 @@ find_package(Sanitizers) # List of Boost libraries to include set(boost_libs filesystem thread program_options) +if (BUILD_GUI AND NOT BUILD_PYTHON) + message(FATAL_ERROR "GUI requires Python to build") +endif() + if (BUILD_PYTHON) # TODO: sensible minimum Python version find_package(PythonInterp 3.5 REQUIRED) diff --git a/gui/basewindow.cc b/gui/basewindow.cc index b76527e1..04898410 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -27,10 +27,7 @@ #include "jsonparse.h" #include "log.h" #include "mainwindow.h" - -#ifndef NO_PYTHON #include "pythontab.h" -#endif static void initBasenameResource() { Q_INIT_RESOURCE(base); } @@ -74,13 +71,10 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent connect(designview, SIGNAL(info(std::string)), this, SLOT(writeInfo(std::string))); tabWidget = new QTabWidget(); -#ifndef NO_PYTHON - PythonTab *pythontab = new PythonTab(); - tabWidget->addTab(pythontab, "Console"); - connect(this, SIGNAL(contextChanged(Context *)), pythontab, SLOT(newContext(Context *))); -#endif - info = new InfoTab(); - tabWidget->addTab(info, "Info"); + + console = new PythonTab(); + tabWidget->addTab(console, "Console"); + connect(this, SIGNAL(contextChanged(Context *)), console, SLOT(newContext(Context *))); centralTabWidget = new QTabWidget(); FPGAViewWidget *fpgaView = new FPGAViewWidget(); @@ -94,7 +88,7 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent BaseMainWindow::~BaseMainWindow() {} -void BaseMainWindow::writeInfo(std::string text) { info->info(text); } +void BaseMainWindow::writeInfo(std::string text) { console->info(text); } void BaseMainWindow::createMenusAndBars() { diff --git a/gui/basewindow.h b/gui/basewindow.h index d2d0505d..ebbe66f0 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -20,7 +20,6 @@ #ifndef BASEMAINWINDOW_H #define BASEMAINWINDOW_H -#include "infotab.h" #include "nextpnr.h" #include @@ -35,6 +34,8 @@ Q_DECLARE_METATYPE(std::string) NEXTPNR_NAMESPACE_BEGIN +class PythonTab; + class BaseMainWindow : public QMainWindow { Q_OBJECT @@ -62,7 +63,7 @@ class BaseMainWindow : public QMainWindow std::unique_ptr ctx; QTabWidget *tabWidget; QTabWidget *centralTabWidget; - InfoTab *info; + PythonTab *console; QMenuBar *menuBar; QToolBar *mainToolBar; diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index bea5fce7..4ade1f1f 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -253,7 +253,6 @@ void MainWindow::new_proj() void MainWindow::load_json(std::string filename, std::string pcf) { - tabWidget->setCurrentWidget(info); preload_pcf = pcf; disableActions(); Q_EMIT task->loadfile(filename); @@ -261,8 +260,6 @@ void MainWindow::load_json(std::string filename, std::string pcf) void MainWindow::load_pcf(std::string filename) { - tabWidget->setCurrentWidget(info); - disableActions(); Q_EMIT task->loadpcf(filename); } @@ -271,15 +268,12 @@ void MainWindow::newContext(Context *ctx) { std::string title = "nextpnr-ice40 - " + ctx->getChipName() + " ( " + chipArgs.package + " )"; setWindowTitle(title.c_str()); - info->clearBuffer(); } void MainWindow::open_proj() { QString fileName = QFileDialog::getOpenFileName(this, QString("Open Project"), QString(), QString("*.proj")); if (!fileName.isEmpty()) { - tabWidget->setCurrentWidget(info); - std::string fn = fileName.toStdString(); disableActions(); } diff --git a/gui/line_editor.cc b/gui/line_editor.cc index 3c7ebe94..425f2876 100644 --- a/gui/line_editor.cc +++ b/gui/line_editor.cc @@ -18,8 +18,6 @@ * */ -#ifndef NO_PYTHON - #include "line_editor.h" #include #include @@ -131,5 +129,3 @@ void LineEditor::autocomplete() } NEXTPNR_NAMESPACE_END - -#endif // NO_PYTHON diff --git a/gui/line_editor.h b/gui/line_editor.h index 5a57129b..a779072f 100644 --- a/gui/line_editor.h +++ b/gui/line_editor.h @@ -21,8 +21,6 @@ #ifndef LINE_EDITOR_H #define LINE_EDITOR_H -#ifndef NO_PYTHON - #include #include #include "ParseHelper.h" @@ -59,6 +57,4 @@ class LineEditor : public QLineEdit NEXTPNR_NAMESPACE_END -#endif // NO_PYTHON - #endif // LINE_EDITOR_H diff --git a/gui/pyconsole.cc b/gui/pyconsole.cc index 6da06b7e..0ee393ce 100644 --- a/gui/pyconsole.cc +++ b/gui/pyconsole.cc @@ -18,8 +18,6 @@ * */ -#ifndef NO_PYTHON - #include "pyconsole.h" #include "pyinterpreter.h" @@ -68,6 +66,7 @@ void PythonConsole::displayString(QString text) setTextColor(NORMAL_COLOR); cursor.insertText(text); cursor.movePosition(QTextCursor::EndOfLine); + moveCursorToEnd(); } void PythonConsole::moveCursorToEnd() @@ -78,5 +77,3 @@ void PythonConsole::moveCursorToEnd() } NEXTPNR_NAMESPACE_END - -#endif // NO_PYTHON diff --git a/gui/pyconsole.h b/gui/pyconsole.h index 60f10672..9dbd3b95 100644 --- a/gui/pyconsole.h +++ b/gui/pyconsole.h @@ -21,8 +21,6 @@ #ifndef PYCONSOLE_H #define PYCONSOLE_H -#ifndef NO_PYTHON - #include #include #include @@ -53,6 +51,5 @@ class PythonConsole : public QTextEdit, public ParseListener }; NEXTPNR_NAMESPACE_END -#endif // NO_PYTHON #endif // PYCONSOLE_H diff --git a/gui/pythontab.cc b/gui/pythontab.cc index 5c349d7c..e761128d 100644 --- a/gui/pythontab.cc +++ b/gui/pythontab.cc @@ -16,7 +16,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ -#ifndef NO_PYTHON #include "pythontab.h" #include @@ -77,7 +76,6 @@ PythonTab::~PythonTab() void PythonTab::editLineReturnPressed(QString text) { console->displayString(prompt + text + "\n"); - console->moveCursorToEnd(); parseHelper.process(text.toStdString()); @@ -114,6 +112,6 @@ void PythonTab::showContextMenu(const QPoint &pt) { contextMenu->exec(mapToGloba void PythonTab::clearBuffer() { console->clear(); } -NEXTPNR_NAMESPACE_END +void PythonTab::info(std::string str) { console->displayString(str.c_str()); } -#endif // NO_PYTHON +NEXTPNR_NAMESPACE_END diff --git a/gui/pythontab.h b/gui/pythontab.h index 3fd12981..134874b6 100644 --- a/gui/pythontab.h +++ b/gui/pythontab.h @@ -20,8 +20,6 @@ #ifndef PYTHONTAB_H #define PYTHONTAB_H -#ifndef NO_PYTHON - #include #include #include @@ -42,10 +40,11 @@ class PythonTab : public QWidget private Q_SLOTS: void showContextMenu(const QPoint &pt); - void clearBuffer(); void editLineReturnPressed(QString text); public Q_SLOTS: void newContext(Context *ctx); + void info(std::string str); + void clearBuffer(); private: PythonConsole *console; @@ -60,6 +59,5 @@ class PythonTab : public QWidget }; NEXTPNR_NAMESPACE_END -#endif // NO_PYTHON #endif // PYTHONTAB_H -- cgit v1.2.3 From 0b1ae3ce8da9fb3a3b4eaf337d6bf0b7f6aaab1e Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sat, 14 Jul 2018 17:50:06 +0200 Subject: use itemSelectionChanged, keyboard selection works --- gui/designwidget.cc | 8 ++++++-- gui/designwidget.h | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index e839f006..9602a4d3 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -160,7 +160,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net // Connection connect(treeWidget, &QTreeWidget::customContextMenuRequested, this, &DesignWidget::prepareMenu); - connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), SLOT(onItemClicked(QTreeWidgetItem *, int))); + connect(treeWidget, SIGNAL(itemSelectionChanged()), SLOT(onItemSelectionChanged())); } DesignWidget::~DesignWidget() {} @@ -325,8 +325,12 @@ void DesignWidget::clearProperties() idToProperty.clear(); } -void DesignWidget::onItemClicked(QTreeWidgetItem *clickItem, int pos) +void DesignWidget::onItemSelectionChanged() { + if (treeWidget->selectedItems().size()== 0) return; + + QTreeWidgetItem *clickItem = treeWidget->selectedItems().at(0); + if (!clickItem->parent()) return; diff --git a/gui/designwidget.h b/gui/designwidget.h index ce0220dd..843fbb72 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -46,7 +46,7 @@ class DesignWidget : public QWidget private Q_SLOTS: void prepareMenu(const QPoint &pos); - void onItemClicked(QTreeWidgetItem *item, int); + void onItemSelectionChanged(); void selectObject(); public Q_SLOTS: void newContext(Context *ctx); -- cgit v1.2.3 From f339f796a1bd7e98be184085e831e9d44ea85dd1 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sat, 14 Jul 2018 17:58:58 +0200 Subject: simplified Icon allocation --- gui/basewindow.cc | 28 +++++++---------- gui/designwidget.cc | 25 +++++++--------- gui/ice40/mainwindow.cc | 80 +++++++++++++++++++------------------------------ 3 files changed, 50 insertions(+), 83 deletions(-) diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 04898410..b9c1de5e 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -42,7 +42,7 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent log_files.clear(); log_streams.clear(); - setObjectName(QStringLiteral("BaseMainWindow")); + setObjectName("BaseMainWindow"); resize(1024, 768); createMenusAndBars(); @@ -92,35 +92,27 @@ void BaseMainWindow::writeInfo(std::string text) { console->info(text); } void BaseMainWindow::createMenusAndBars() { - actionNew = new QAction("New", this); - QIcon iconNew; - iconNew.addFile(QStringLiteral(":/icons/resources/new.png")); - actionNew->setIcon(iconNew); + actionNew = new QAction("New", this); + actionNew->setIcon(QIcon(":/icons/resources/new.png")); actionNew->setShortcuts(QKeySequence::New); actionNew->setStatusTip("New project file"); connect(actionNew, SIGNAL(triggered()), this, SLOT(new_proj())); - actionOpen = new QAction("Open", this); - QIcon iconOpen; - iconOpen.addFile(QStringLiteral(":/icons/resources/open.png")); - actionOpen->setIcon(iconOpen); + actionOpen = new QAction("Open", this); + actionOpen->setIcon(QIcon(":/icons/resources/open.png")); actionOpen->setShortcuts(QKeySequence::Open); actionOpen->setStatusTip("Open an existing project file"); connect(actionOpen, SIGNAL(triggered()), this, SLOT(open_proj())); - QAction *actionSave = new QAction("Save", this); - QIcon iconSave; - iconSave.addFile(QStringLiteral(":/icons/resources/save.png")); - actionSave->setIcon(iconSave); + QAction *actionSave = new QAction("Save", this); + actionSave->setIcon(QIcon(":/icons/resources/save.png")); actionSave->setShortcuts(QKeySequence::Save); actionSave->setStatusTip("Save existing project to disk"); - connect(actionSave, SIGNAL(triggered()), this, SLOT(save_proj())); actionSave->setEnabled(false); + connect(actionSave, SIGNAL(triggered()), this, SLOT(save_proj())); - QAction *actionExit = new QAction("Exit", this); - QIcon iconExit; - iconExit.addFile(QStringLiteral(":/icons/resources/exit.png")); - actionExit->setIcon(iconExit); + QAction *actionExit = new QAction("Exit", this); + actionExit->setIcon(QIcon(":/icons/resources/exit.png")); actionExit->setShortcuts(QKeySequence::Quit); actionExit->setStatusTip("Exit the application"); connect(actionExit, SIGNAL(triggered()), this, SLOT(close())); diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 9602a4d3..ba2c76f5 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -89,31 +89,26 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net propertyEditor->setPropertiesWithoutValueMarked(true); propertyEditor->show(); - - const QIcon searchIcon(":/icons/resources/zoom.png"); + QLineEdit *lineEdit = new QLineEdit(); lineEdit->setClearButtonEnabled(true); - lineEdit->addAction(searchIcon, QLineEdit::LeadingPosition); + lineEdit->addAction(QIcon(":/icons/resources/zoom.png"), QLineEdit::LeadingPosition); lineEdit->setPlaceholderText("Search..."); - actionFirst = new QAction("", this); - QIcon iconFirst(QStringLiteral(":/icons/resources/resultset_first.png")); - actionFirst->setIcon(iconFirst); + actionFirst = new QAction("", this); + actionFirst->setIcon(QIcon(":/icons/resources/resultset_first.png")); actionFirst->setEnabled(false); - actionPrev = new QAction("", this); - QIcon iconPrev(QStringLiteral(":/icons/resources/resultset_previous.png")); - actionPrev->setIcon(iconPrev); + actionPrev = new QAction("", this); + actionPrev->setIcon(QIcon(":/icons/resources/resultset_previous.png")); actionPrev->setEnabled(false); - actionNext = new QAction("", this); - QIcon iconNext(QStringLiteral(":/icons/resources/resultset_next.png")); - actionNext->setIcon(iconNext); + actionNext = new QAction("", this); + actionNext->setIcon(QIcon(":/icons/resources/resultset_next.png")); actionNext->setEnabled(false); - actionLast = new QAction("", this); - QIcon iconLast(QStringLiteral(":/icons/resources/resultset_last.png")); - actionLast->setIcon(iconLast); + actionLast = new QAction("", this); + actionLast->setIcon(QIcon(":/icons/resources/resultset_last.png")); actionLast->setEnabled(false); QToolBar *toolbar = new QToolBar(); diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index 4ade1f1f..772ca6ac 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -71,61 +71,47 @@ void MainWindow::createMenu() QMenu *menu_Design = new QMenu("&Design", menuBar); menuBar->addAction(menu_Design->menuAction()); - actionLoadJSON = new QAction("Open JSON", this); - QIcon iconLoadJSON; - iconLoadJSON.addFile(QStringLiteral(":/icons/resources/open_json.png")); - actionLoadJSON->setIcon(iconLoadJSON); + actionLoadJSON = new QAction("Open JSON", this); + actionLoadJSON->setIcon(QIcon(":/icons/resources/open_json.png")); actionLoadJSON->setStatusTip("Open an existing JSON file"); - connect(actionLoadJSON, SIGNAL(triggered()), this, SLOT(open_json())); actionLoadJSON->setEnabled(true); + connect(actionLoadJSON, SIGNAL(triggered()), this, SLOT(open_json())); - actionLoadPCF = new QAction("Open PCF", this); - QIcon iconLoadPCF; - iconLoadPCF.addFile(QStringLiteral(":/icons/resources/open_pcf.png")); - actionLoadPCF->setIcon(iconLoadPCF); + actionLoadPCF = new QAction("Open PCF", this); + actionLoadPCF->setIcon(QIcon(":/icons/resources/open_pcf.png")); actionLoadPCF->setStatusTip("Open PCF file"); - connect(actionLoadPCF, SIGNAL(triggered()), this, SLOT(open_pcf())); actionLoadPCF->setEnabled(false); + connect(actionLoadPCF, SIGNAL(triggered()), this, SLOT(open_pcf())); - actionPack = new QAction("Pack", this); - QIcon iconPack; - iconPack.addFile(QStringLiteral(":/icons/resources/pack.png")); - actionPack->setIcon(iconPack); + actionPack = new QAction("Pack", this); + actionPack->setIcon(QIcon(":/icons/resources/pack.png")); actionPack->setStatusTip("Pack current design"); - connect(actionPack, SIGNAL(triggered()), task, SIGNAL(pack())); actionPack->setEnabled(false); + connect(actionPack, SIGNAL(triggered()), task, SIGNAL(pack())); - actionAssignBudget = new QAction("Assign Budget", this); - QIcon iconAssignBudget; - iconAssignBudget.addFile(QStringLiteral(":/icons/resources/time_add.png")); - actionAssignBudget->setIcon(iconAssignBudget); + actionAssignBudget = new QAction("Assign Budget", this); + actionAssignBudget->setIcon(QIcon(":/icons/resources/time_add.png")); actionAssignBudget->setStatusTip("Assign time budget for current design"); - connect(actionAssignBudget, SIGNAL(triggered()), this, SLOT(budget())); actionAssignBudget->setEnabled(false); + connect(actionAssignBudget, SIGNAL(triggered()), this, SLOT(budget())); - actionPlace = new QAction("Place", this); - QIcon iconPlace; - iconPlace.addFile(QStringLiteral(":/icons/resources/place.png")); - actionPlace->setIcon(iconPlace); + actionPlace = new QAction("Place", this); + actionPlace->setIcon(QIcon(":/icons/resources/place.png")); actionPlace->setStatusTip("Place current design"); - connect(actionPlace, SIGNAL(triggered()), this, SLOT(place())); actionPlace->setEnabled(false); + connect(actionPlace, SIGNAL(triggered()), this, SLOT(place())); - actionRoute = new QAction("Route", this); - QIcon iconRoute; - iconRoute.addFile(QStringLiteral(":/icons/resources/route.png")); - actionRoute->setIcon(iconRoute); + actionRoute = new QAction("Route", this); + actionRoute->setIcon(QIcon(":/icons/resources/route.png")); actionRoute->setStatusTip("Route current design"); - connect(actionRoute, SIGNAL(triggered()), task, SIGNAL(route())); actionRoute->setEnabled(false); + connect(actionRoute, SIGNAL(triggered()), task, SIGNAL(route())); - actionSaveAsc = new QAction("Save ASC", this); - QIcon iconSaveAsc; - iconSaveAsc.addFile(QStringLiteral(":/icons/resources/save_asc.png")); - actionSaveAsc->setIcon(iconSaveAsc); + actionSaveAsc = new QAction("Save ASC", this); + actionSaveAsc->setIcon(QIcon(":/icons/resources/save_asc.png")); actionSaveAsc->setStatusTip("Save ASC file"); - connect(actionSaveAsc, SIGNAL(triggered()), this, SLOT(save_asc())); actionSaveAsc->setEnabled(false); + connect(actionSaveAsc, SIGNAL(triggered()), this, SLOT(save_asc())); QToolBar *taskFPGABar = new QToolBar(); addToolBar(Qt::TopToolBarArea, taskFPGABar); @@ -146,29 +132,23 @@ void MainWindow::createMenu() menu_Design->addAction(actionRoute); menu_Design->addAction(actionSaveAsc); - actionPlay = new QAction("Play", this); - QIcon iconPlay; - iconPlay.addFile(QStringLiteral(":/icons/resources/control_play.png")); - actionPlay->setIcon(iconPlay); + actionPlay = new QAction("Play", this); + actionPlay->setIcon(QIcon(":/icons/resources/control_play.png")); actionPlay->setStatusTip("Continue running task"); - connect(actionPlay, SIGNAL(triggered()), task, SLOT(continue_thread())); actionPlay->setEnabled(false); + connect(actionPlay, SIGNAL(triggered()), task, SLOT(continue_thread())); - actionPause = new QAction("Pause", this); - QIcon iconPause; - iconPause.addFile(QStringLiteral(":/icons/resources/control_pause.png")); - actionPause->setIcon(iconPause); + actionPause = new QAction("Pause", this); + actionPause->setIcon(QIcon(":/icons/resources/control_pause.png")); actionPause->setStatusTip("Pause running task"); - connect(actionPause, SIGNAL(triggered()), task, SLOT(pause_thread())); actionPause->setEnabled(false); + connect(actionPause, SIGNAL(triggered()), task, SLOT(pause_thread())); - actionStop = new QAction("Stop", this); - QIcon iconStop; - iconStop.addFile(QStringLiteral(":/icons/resources/control_stop.png")); - actionStop->setIcon(iconStop); + actionStop = new QAction("Stop", this); + actionStop->setIcon(QIcon(":/icons/resources/control_stop.png")); actionStop->setStatusTip("Stop running task"); - connect(actionStop, SIGNAL(triggered()), task, SLOT(terminate_thread())); actionStop->setEnabled(false); + connect(actionStop, SIGNAL(triggered()), task, SLOT(terminate_thread())); QToolBar *taskToolBar = new QToolBar(); addToolBar(Qt::TopToolBarArea, taskToolBar); -- cgit v1.2.3 From 8d1996cae99ff80a2d9390b94db54217ed1d8726 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sat, 14 Jul 2018 19:44:37 +0200 Subject: display selected object from tree --- gui/basewindow.cc | 1 + gui/basewindow.h | 1 + gui/designwidget.cc | 15 +++++++++++++-- gui/designwidget.h | 1 + gui/fpgaviewwidget.cc | 20 +++++++++++++++++++- gui/fpgaviewwidget.h | 7 ++++++- 6 files changed, 41 insertions(+), 4 deletions(-) diff --git a/gui/basewindow.cc b/gui/basewindow.cc index b9c1de5e..0c7632ee 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -81,6 +81,7 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent centralTabWidget->addTab(fpgaView, "Graphics"); connect(this, SIGNAL(contextChanged(Context *)), fpgaView, SLOT(newContext(Context *))); + connect(designview, SIGNAL(selected(std::vector)), fpgaView, SLOT(onSelectedArchItem(std::vector))); splitter_v->addWidget(centralTabWidget); splitter_v->addWidget(tabWidget); diff --git a/gui/basewindow.h b/gui/basewindow.h index ebbe66f0..4d3d80a1 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -31,6 +31,7 @@ #include Q_DECLARE_METATYPE(std::string) +Q_DECLARE_METATYPE(NEXTPNR_NAMESPACE_PREFIX DecalXY) NEXTPNR_NAMESPACE_BEGIN diff --git a/gui/designwidget.cc b/gui/designwidget.cc index ba2c76f5..a6ebba5e 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -336,10 +336,15 @@ void DesignWidget::onItemSelectionChanged() auto &&proxy = ctx->rproxy(); + std::vector decals; + clearProperties(); if (type == ElementType::BEL) { IdString c = static_cast(clickItem)->getData(); BelId bel = proxy.getBelByName(c); + + decals.push_back(ctx->getBelDecal(bel)); + Q_EMIT selected(decals); QtProperty *topItem = groupManager->addProperty("Bel"); addProperty(topItem, "Bel"); @@ -368,6 +373,9 @@ void DesignWidget::onItemSelectionChanged() IdString c = static_cast(clickItem)->getData(); WireId wire = proxy.getWireByName(c); + decals.push_back(ctx->getWireDecal(wire)); + Q_EMIT selected(decals); + QtProperty *topItem = groupManager->addProperty("Wire"); addProperty(topItem, "Wire"); @@ -421,7 +429,7 @@ void DesignWidget::onItemSelectionChanged() portItem->setValue(pinname); dhItem->addSubProperty(portItem); } - +/* QtProperty *pipsDownItem = groupManager->addProperty("Pips Downhill"); topItem->addSubProperty(pipsDownItem); for (const auto &item : ctx->getPipsDownhill(wire)) { @@ -437,11 +445,14 @@ void DesignWidget::onItemSelectionChanged() pipItem->setValue(ctx->getPipName(item).c_str(ctx)); pipsUpItem->addSubProperty(pipItem); } - +*/ } else if (type == ElementType::PIP) { IdString c = static_cast(clickItem)->getData(); PipId pip = proxy.getPipByName(c); + decals.push_back(ctx->getPipDecal(pip)); + Q_EMIT selected(decals); + QtProperty *topItem = groupManager->addProperty("Pip"); addProperty(topItem, "Pip"); diff --git a/gui/designwidget.h b/gui/designwidget.h index 843fbb72..618c7bbf 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -43,6 +43,7 @@ class DesignWidget : public QWidget Q_SIGNALS: void info(std::string text); + void selected(std::vector decal); private Q_SLOTS: void prepareMenu(const QPoint &pos); diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 21ce5b67..f8fefd97 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -241,7 +241,7 @@ void LineShader::draw(const LineShaderData &line, const QColor &color, const flo vao_.release(); } -FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr) +FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), selectedItemsChanged(false) { backgroundColor_ = QColor("#000000"); gridColor_ = QColor("#333"); @@ -249,6 +249,7 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineSha gHiddenColor_ = QColor("#606060"); gInactiveColor_ = QColor("#303030"); gActiveColor_ = QColor("#f0f0f0"); + gSelectedColor_ = QColor("#ff6600"); frameColor_ = QColor("#0066ba"); auto fmt = format(); @@ -364,15 +365,32 @@ void FPGAViewWidget::paintGL() // Draw Frame Graphics. drawDecal(proxy, shaders_, ctx_->getFrameDecal()); } + + if (selectedItemsChanged) + { + selectedItemsChanged = false; + selectedShader_.clear(); + for (auto decal : selectedItems_) { + drawDecal(proxy, selectedShader_, decal); + } + } } lineShader_.draw(shaders_[0], gFrameColor_, thick11Px, matrix); lineShader_.draw(shaders_[1], gHiddenColor_, thick11Px, matrix); lineShader_.draw(shaders_[2], gInactiveColor_, thick11Px, matrix); lineShader_.draw(shaders_[3], gActiveColor_, thick11Px, matrix); + lineShader_.draw(selectedShader_, gSelectedColor_, thick11Px, matrix); //lineShader_.draw(frame, matrix); } +void FPGAViewWidget::onSelectedArchItem(std::vector decals) +{ + selectedItems_ = decals; + selectedItemsChanged = true; + update(); +} + void FPGAViewWidget::resizeGL(int width, int height) {} void FPGAViewWidget::mousePressEvent(QMouseEvent *event) { lastPos_ = event->pos(); } diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 3652e82e..0a9599c9 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -213,6 +213,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions Q_PROPERTY(QColor gHiddenColor MEMBER gHiddenColor_ DESIGNABLE true) Q_PROPERTY(QColor gInactiveColor MEMBER gInactiveColor_ DESIGNABLE true) Q_PROPERTY(QColor gActiveColor MEMBER gActiveColor_ DESIGNABLE true) + Q_PROPERTY(QColor gSelectedColor MEMBER gSelectedColor_ DESIGNABLE true) Q_PROPERTY(QColor frameColor MEMBER frameColor_ DESIGNABLE true) public: @@ -309,7 +310,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions public Q_SLOTS: void newContext(Context *ctx); - + void onSelectedArchItem(std::vector decals); private: QPoint lastPos_; LineShader lineShader_; @@ -332,9 +333,13 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions QColor gHiddenColor_; QColor gInactiveColor_; QColor gActiveColor_; + QColor gSelectedColor_; QColor frameColor_; LineShaderData shaders_[4]; + LineShaderData selectedShader_; + std::vector selectedItems_; + bool selectedItemsChanged; }; NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From 9c013ce74c393c4bb14d1722fefaeb27d57ccae3 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:50:01 +0100 Subject: Revert "Undo accidental picorv32.sh commit" This reverts commit 98c594885698b557311ac84195599b35968719e0. --- ice40/picorv32.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ice40/picorv32.sh b/ice40/picorv32.sh index 2c67f641..0518db83 100755 --- a/ice40/picorv32.sh +++ b/ice40/picorv32.sh @@ -1,6 +1,6 @@ #!/bin/bash set -ex -rm -f picorv32.v -wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v -yosys -p 'synth_ice40 -nocarry -json picorv32.json -top top' picorv32.v picorv32_top.v -../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json +#rm -f picorv32.v +#wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v +#yosys -p 'synth_ice40 -nocarry -json picorv32.json -top top' picorv32.v picorv32_top.v +CPUPROFILE=../profile ../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json -- cgit v1.2.3 From 339198b394b7f2cdd3bafb2c8c819c1561813f65 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:50:07 +0100 Subject: Revert "Remove unimplemented pybindings (for now)" This reverts commit 53393b993fb211a3ce98262b0dd636d2e8420d2d. --- ice40/arch_pybindings.cc | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc index a2a90191..aeb4348a 100644 --- a/ice40/arch_pybindings.cc +++ b/ice40/arch_pybindings.cc @@ -65,13 +65,25 @@ void arch_wrap_python() fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelType"); + //fn_wrapper_1a, + // conv_from_str>::def_wrap(ctx_cls, "checkBelAvail"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelChecksum"); + //fn_wrapper_3a_v, + // conv_from_str, pass_through>::def_wrap(ctx_cls, "bindBel"); + //fn_wrapper_1a_v>::def_wrap( + // ctx_cls, "unbindBel"); + //fn_wrapper_1a, + // conv_from_str>::def_wrap(ctx_cls, "getBoundBelCell"); + //fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingBelCell"); fn_wrapper_0a>::def_wrap(ctx_cls, "getBels"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelsAtSameTile"); + //fn_wrapper_2a, + // conv_from_str, conv_from_str>::def_wrap(ctx_cls, "getWireBelPin"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelPinUphill"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getWireChecksum"); + //fn_wrapper_3a_v, + // conv_from_str, pass_through>::def_wrap(ctx_cls, "bindWire"); + //fn_wrapper_1a_v>::def_wrap( + // ctx_cls, "unbindWire"); + //fn_wrapper_1a, + // conv_from_str>::def_wrap(ctx_cls, "checkWireAvail"); + //fn_wrapper_1a, + // conv_from_str>::def_wrap(ctx_cls, "getBoundWireNet"); + //fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingWireNet"); fn_wrapper_0a>::def_wrap( ctx_cls, "getWires"); @@ -87,6 +109,16 @@ void arch_wrap_python() ctx_cls, "getPips"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getPipChecksum"); + //fn_wrapper_3a_v, + // conv_from_str, pass_through>::def_wrap(ctx_cls, "bindPip"); + //fn_wrapper_1a_v>::def_wrap( + // ctx_cls, "unbindPip"); + //fn_wrapper_1a, + // conv_from_str>::def_wrap(ctx_cls, "checkPipAvail"); + //fn_wrapper_1a, + // conv_from_str>::def_wrap(ctx_cls, "getBoundPipNet"); + //fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingPipNet"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getPipsDownhill"); -- cgit v1.2.3 From 22330402018a212efd4ef2e337e34af2e79eb875 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:50:15 +0100 Subject: Revert "Remove legacy access to state via Arch" This reverts commit 18b4b316782035daa259d65d26ea733ca4d16bea. --- ice40/arch.cc | 41 +++++++++++++++++++++++++++++++ ice40/arch.h | 28 +++++++++++++++++++++ ice40/arch_pybindings.cc | 64 ++++++++++++++++++++++++------------------------ ice40/arch_pybindings.h | 18 +++----------- ice40/bitstream.cc | 13 +++++----- ice40/main.cc | 21 ++++++++-------- 6 files changed, 120 insertions(+), 65 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 4727597b..8f2731c6 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -256,6 +256,47 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const return br; } +// ----------------------------------------------------------------------- +// Shorthands to ArchProxy + +BelId Arch::getBelByName(IdString name) const { return rproxy().getBelByName(name); } + +void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength) { rwproxy().bindWire(wire, net, strength); } + +void Arch::unbindWire(WireId wire) { rwproxy().unbindWire(wire); } + +void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength) { rwproxy().bindBel(bel, cell, strength); } + +void Arch::unbindBel(BelId bel) { rwproxy().unbindBel(bel); } + +bool Arch::checkBelAvail(BelId bel) const { return rproxy().checkBelAvail(bel); } + +IdString Arch::getBoundBelCell(BelId bel) const { return rproxy().getBoundBelCell(bel); } + +IdString Arch::getConflictingBelCell(BelId bel) const { return rproxy().getConflictingBelCell(bel); } + +WireId Arch::getWireByName(IdString name) const { return rproxy().getWireByName(name); } + +WireId Arch::getWireBelPin(BelId bel, PortPin pin) const { return rproxy().getWireBelPin(bel, pin); } + +bool Arch::checkWireAvail(WireId wire) const { return rproxy().checkWireAvail(wire); } + +IdString Arch::getBoundWireNet(WireId wire) const { return rproxy().getBoundWireNet(wire); } + +IdString Arch::getConflictingWireNet(WireId wire) const { return rproxy().getConflictingWireNet(wire); } + +PipId Arch::getPipByName(IdString name) const { return rproxy().getPipByName(name); } + +void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength) { return rwproxy().bindPip(pip, net, strength); } + +void Arch::unbindPip(PipId pip) { return rwproxy().unbindPip(pip); } + +bool Arch::checkPipAvail(PipId pip) const { return rproxy().checkPipAvail(pip); } + +IdString Arch::getBoundPipNet(PipId pip) const { return rproxy().getBoundPipNet(pip); } + +IdString Arch::getConflictingPipNet(PipId pip) const { return rproxy().getConflictingPipNet(pip); } + // ----------------------------------------------------------------------- IdString Arch::getPipName(PipId pip) const diff --git a/ice40/arch.h b/ice40/arch.h index 25ed8ebf..ec1e456f 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -373,6 +373,34 @@ class Arch : public BaseCtx // ------------------------------------------------- + /// Wrappers around getting a r(w)proxy and calling a single method. + // Deprecated: please acquire a proxy yourself and call the methods + // you want on it. + // Warning: these will content with locks taken by the r(w)proxies, and + // thus can cause difficult to debug deadlocks - we'll be getting rid of + // them because of that. + void unbindWire(WireId wire); + void unbindPip(PipId pip); + void unbindBel(BelId bel); + void bindWire(WireId wire, IdString net, PlaceStrength strength); + void bindPip(PipId pip, IdString net, PlaceStrength strength); + void bindBel(BelId bel, IdString cell, PlaceStrength strength); + bool checkWireAvail(WireId wire) const; + bool checkPipAvail(PipId pip) const; + bool checkBelAvail(BelId bel) const; + WireId getWireByName(IdString name) const; + WireId getWireBelPin(BelId bel, PortPin pin) const; + PipId getPipByName(IdString name) const; + IdString getConflictingWireNet(WireId wire) const; + IdString getConflictingPipNet(PipId pip) const; + IdString getConflictingBelCell(BelId bel) const; + IdString getBoundWireNet(WireId wire) const; + IdString getBoundPipNet(PipId pip) const; + IdString getBoundBelCell(BelId bel) const; + BelId getBelByName(IdString name) const; + + // ------------------------------------------------- + /// Methods to get chip info - don't need to use a wrapper, as these are /// static per lifetime of object. diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc index aeb4348a..fd5109b4 100644 --- a/ice40/arch_pybindings.cc +++ b/ice40/arch_pybindings.cc @@ -65,25 +65,25 @@ void arch_wrap_python() fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelType"); - //fn_wrapper_1a, - // conv_from_str>::def_wrap(ctx_cls, "checkBelAvail"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "checkBelAvail"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelChecksum"); - //fn_wrapper_3a_v, - // conv_from_str, pass_through>::def_wrap(ctx_cls, "bindBel"); - //fn_wrapper_1a_v>::def_wrap( - // ctx_cls, "unbindBel"); - //fn_wrapper_1a, - // conv_from_str>::def_wrap(ctx_cls, "getBoundBelCell"); - //fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingBelCell"); + fn_wrapper_3a_v, + conv_from_str, pass_through>::def_wrap(ctx_cls, "bindBel"); + fn_wrapper_1a_v>::def_wrap( + ctx_cls, "unbindBel"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBoundBelCell"); + fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingBelCell"); fn_wrapper_0a>::def_wrap(ctx_cls, "getBels"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelsAtSameTile"); - //fn_wrapper_2a, - // conv_from_str, conv_from_str>::def_wrap(ctx_cls, "getWireBelPin"); + fn_wrapper_2a, + conv_from_str, conv_from_str>::def_wrap(ctx_cls, "getWireBelPin"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelPinUphill"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getWireChecksum"); - //fn_wrapper_3a_v, - // conv_from_str, pass_through>::def_wrap(ctx_cls, "bindWire"); - //fn_wrapper_1a_v>::def_wrap( - // ctx_cls, "unbindWire"); - //fn_wrapper_1a, - // conv_from_str>::def_wrap(ctx_cls, "checkWireAvail"); - //fn_wrapper_1a, - // conv_from_str>::def_wrap(ctx_cls, "getBoundWireNet"); - //fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingWireNet"); + fn_wrapper_3a_v, + conv_from_str, pass_through>::def_wrap(ctx_cls, "bindWire"); + fn_wrapper_1a_v>::def_wrap( + ctx_cls, "unbindWire"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "checkWireAvail"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBoundWireNet"); + fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingWireNet"); fn_wrapper_0a>::def_wrap( ctx_cls, "getWires"); @@ -109,16 +109,16 @@ void arch_wrap_python() ctx_cls, "getPips"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getPipChecksum"); - //fn_wrapper_3a_v, - // conv_from_str, pass_through>::def_wrap(ctx_cls, "bindPip"); - //fn_wrapper_1a_v>::def_wrap( - // ctx_cls, "unbindPip"); - //fn_wrapper_1a, - // conv_from_str>::def_wrap(ctx_cls, "checkPipAvail"); - //fn_wrapper_1a, - // conv_from_str>::def_wrap(ctx_cls, "getBoundPipNet"); - //fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingPipNet"); + fn_wrapper_3a_v, + conv_from_str, pass_through>::def_wrap(ctx_cls, "bindPip"); + fn_wrapper_1a_v>::def_wrap( + ctx_cls, "unbindPip"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "checkPipAvail"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBoundPipNet"); + fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingPipNet"); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getPipsDownhill"); diff --git a/ice40/arch_pybindings.h b/ice40/arch_pybindings.h index 7440e29d..e502905f 100644 --- a/ice40/arch_pybindings.h +++ b/ice40/arch_pybindings.h @@ -31,11 +31,7 @@ namespace PythonConversion { template <> struct string_converter { - BelId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getBelByName(ctx->id(name)); - } + BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); } std::string to_str(Context *ctx, BelId id) { @@ -54,22 +50,14 @@ template <> struct string_converter template <> struct string_converter { - WireId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getWireByName(ctx->id(name)); - } + WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); } std::string to_str(Context *ctx, WireId id) { return ctx->getWireName(id).str(ctx); } }; template <> struct string_converter { - PipId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getPipByName(ctx->id(name)); - } + PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(ctx->id(name)); } std::string to_str(Context *ctx, PipId id) { return ctx->getPipName(id).str(ctx); } }; diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 87a96a22..58a59366 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -92,7 +92,6 @@ char get_hexdigit(int i) { return std::string("0123456789ABCDEF").at(i); } void write_asc(const Context *ctx, std::ostream &out) { - auto &&proxy = ctx->rproxy(); // [y][x][row][col] const ChipInfoPOD &ci = *ctx->chip_info; const BitstreamInfoPOD &bi = *ci.bits_info; @@ -129,7 +128,7 @@ void write_asc(const Context *ctx, std::ostream &out) } // Set pips for (auto pip : ctx->getPips()) { - if (proxy.getBoundPipNet(pip) != IdString()) { + if (ctx->getBoundPipNet(pip) != IdString()) { const PipInfoPOD &pi = ci.pip_data[pip.index]; const SwitchInfoPOD &swi = bi.switches[pi.switch_index]; for (int i = 0; i < swi.num_bits; i++) { @@ -200,8 +199,8 @@ void write_asc(const Context *ctx, std::ostream &out) NPNR_ASSERT(iez != -1); bool input_en = false; - if (!proxy.checkWireAvail(proxy.getWireBelPin(bel, PIN_D_IN_0)) || - !proxy.checkWireAvail(proxy.getWireBelPin(bel, PIN_D_IN_1))) { + if (!ctx->checkWireAvail(ctx->getWireBelPin(bel, PIN_D_IN_0)) || + !ctx->checkWireAvail(ctx->getWireBelPin(bel, PIN_D_IN_1))) { input_en = true; } @@ -272,7 +271,7 @@ void write_asc(const Context *ctx, std::ostream &out) } // Set config bits in unused IO and RAM for (auto bel : ctx->getBels()) { - if (proxy.checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_SB_IO) { + if (ctx->checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_SB_IO) { const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y, z = beli.z; @@ -285,7 +284,7 @@ void write_asc(const Context *ctx, std::ostream &out) set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); } } - } else if (proxy.checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) { + } else if (ctx->checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) { const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB]; @@ -432,7 +431,7 @@ void write_asc(const Context *ctx, std::ostream &out) // Write symbols // const bool write_symbols = 1; for (auto wire : ctx->getWires()) { - IdString net = proxy.getBoundWireNet(wire); + IdString net = ctx->getBoundWireNet(wire); if (net != IdString()) out << ".sym " << wire.index << " " << net.str(ctx) << std::endl; } diff --git a/ice40/main.cc b/ice40/main.cc index fdfe1f25..d38c786c 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -304,32 +304,31 @@ int main(int argc, char *argv[]) } if (vm.count("tmfuzz")) { - auto &&proxy = ctx->rproxy(); std::vector src_wires, dst_wires; /*for (auto w : ctx->getWires()) src_wires.push_back(w);*/ for (auto b : ctx->getBels()) { if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { - src_wires.push_back(proxy.getWireBelPin(b, PIN_O)); + src_wires.push_back(ctx->getWireBelPin(b, PIN_O)); } if (ctx->getBelType(b) == TYPE_SB_IO) { - src_wires.push_back(proxy.getWireBelPin(b, PIN_D_IN_0)); + src_wires.push_back(ctx->getWireBelPin(b, PIN_D_IN_0)); } } for (auto b : ctx->getBels()) { if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { - dst_wires.push_back(proxy.getWireBelPin(b, PIN_I0)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_I1)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_I2)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_I3)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_CEN)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_CIN)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_I0)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_I1)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_I2)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_I3)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_CEN)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_CIN)); } if (ctx->getBelType(b) == TYPE_SB_IO) { - dst_wires.push_back(proxy.getWireBelPin(b, PIN_D_OUT_0)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_OUTPUT_ENABLE)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_D_OUT_0)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_OUTPUT_ENABLE)); } } -- cgit v1.2.3 From cb1a5974f4ca087df3729dc3d8576db9029a7874 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:50:18 +0100 Subject: Revert "Make ECP5 proxy context compatible" This reverts commit df5d7923ec00d18aa832ae5f8859a1120365cb27. --- ecp5/arch.cc | 79 ------------------------------------------------------------ ecp5/arch.h | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 79 deletions(-) diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 1938c297..5c5689f0 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -402,84 +402,5 @@ IdString ArchReadMethods::getBoundBelCell(BelId bel) const return bel_to_cell.at(bel); } -void ArchMutateMethods::unbindWire(WireId wire) -{ - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire] != IdString()); - - auto &net_wires = parent_->nets[wire_to_net[wire]]->wires; - auto it = net_wires.find(wire); - NPNR_ASSERT(it != net_wires.end()); - - auto pip = it->second.pip; - if (pip != PipId()) { - pip_to_net[pip] = IdString(); - } - - net_wires.erase(it); - wire_to_net[wire] = IdString(); -} - -void ArchMutateMethods::unbindPip(PipId pip) -{ - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip] != IdString()); - - WireId dst; - dst.index = parent_->locInfo(pip)->pip_data[pip.index].dst_idx; - dst.location = pip.location + parent_->locInfo(pip)->pip_data[pip.index].rel_dst_loc; - NPNR_ASSERT(wire_to_net[dst] != IdString()); - wire_to_net[dst] = IdString(); - parent_->nets[pip_to_net[pip]]->wires.erase(dst); - - pip_to_net[pip] = IdString(); -} - -void ArchMutateMethods::unbindBel(BelId bel) -{ - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel] != IdString()); - parent_->cells[bel_to_cell[bel]]->bel = BelId(); - parent_->cells[bel_to_cell[bel]]->belStrength = STRENGTH_NONE; - bel_to_cell[bel] = IdString(); -} - -void ArchMutateMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) -{ - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire] == IdString()); - wire_to_net[wire] = net; - parent_->nets[net]->wires[wire].pip = PipId(); - parent_->nets[net]->wires[wire].strength = strength; -} - -void ArchMutateMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) -{ - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip] == IdString()); - - pip_to_net[pip] = net; - - WireId dst; - dst.index = parent_->locInfo(pip)->pip_data[pip.index].dst_idx; - dst.location = pip.location + parent_->locInfo(pip)->pip_data[pip.index].rel_dst_loc; - NPNR_ASSERT(wire_to_net[dst] == IdString()); - wire_to_net[dst] = net; - parent_->nets[net]->wires[dst].pip = pip; - parent_->nets[net]->wires[dst].strength = strength; -} - -void ArchMutateMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) -{ - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel] == IdString()); - bel_to_cell[bel] = cell; - parent_->cells[cell]->bel = bel; - parent_->cells[cell]->belStrength = strength; -} - -CellInfo *ArchMutateMethods::getCell(IdString cell) { return parent_->cells.at(cell).get(); } - - NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch.h b/ecp5/arch.h index 06cf6488..50897b86 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -386,6 +386,24 @@ public: uint32_t getBelChecksum(BelId bel) const { return bel.index; } + void bindBel(BelId bel, IdString cell, PlaceStrength strength) + { + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel] == IdString()); + bel_to_cell[bel] = cell; + cells[cell]->bel = bel; + cells[cell]->belStrength = strength; + } + + void unbindBel(BelId bel) + { + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel] != IdString()); + cells[bel_to_cell[bel]]->bel = BelId(); + cells[bel_to_cell[bel]]->belStrength = STRENGTH_NONE; + bel_to_cell[bel] = IdString(); + } + BelRange getBels() const { BelRange range; @@ -460,6 +478,33 @@ public: uint32_t getWireChecksum(WireId wire) const { return wire.index; } + void bindWire(WireId wire, IdString net, PlaceStrength strength) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire] == IdString()); + wire_to_net[wire] = net; + nets[net]->wires[wire].pip = PipId(); + nets[net]->wires[wire].strength = strength; + } + + void unbindWire(WireId wire) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire] != IdString()); + + auto &net_wires = nets[wire_to_net[wire]]->wires; + auto it = net_wires.find(wire); + NPNR_ASSERT(it != net_wires.end()); + + auto pip = it->second.pip; + if (pip != PipId()) { + pip_to_net[pip] = IdString(); + } + + net_wires.erase(it); + wire_to_net[wire] = IdString(); + } + WireRange getWires() const { WireRange range; @@ -479,6 +524,37 @@ public: uint32_t getPipChecksum(PipId pip) const { return pip.index; } + void bindPip(PipId pip, IdString net, PlaceStrength strength) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip] == IdString()); + + pip_to_net[pip] = net; + + WireId dst; + dst.index = locInfo(pip)->pip_data[pip.index].dst_idx; + dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc; + NPNR_ASSERT(wire_to_net[dst] == IdString()); + wire_to_net[dst] = net; + nets[net]->wires[dst].pip = pip; + nets[net]->wires[dst].strength = strength; + } + + void unbindPip(PipId pip) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip] != IdString()); + + WireId dst; + dst.index = locInfo(pip)->pip_data[pip.index].dst_idx; + dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc; + NPNR_ASSERT(wire_to_net[dst] != IdString()); + wire_to_net[dst] = IdString(); + nets[pip_to_net[pip]]->wires.erase(dst); + + pip_to_net[pip] = IdString(); + } + AllPipRange getPips() const { AllPipRange range; -- cgit v1.2.3 From ade67ecf21c274c73c99543e51eda99ac847686c Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:50:23 +0100 Subject: Revert "Move read methods to ReadMethods, remove some legacy access to Arch" This reverts commit 3352ff4abbcac563e08d78ed8aa77728d00284a8. --- common/nextpnr.cc | 9 ++--- ecp5/arch.cc | 105 ++++++++----------------------------------------- ecp5/arch.h | 92 +++++++++++++++++++++++++++++++++++++++++-- ecp5/arch_pybindings.h | 18 ++------- ecp5/bitstream.cc | 5 +-- gui/designwidget.cc | 26 ++++++------ ice40/arch.h | 1 - ice40/picorv32.sh | 8 ++-- 8 files changed, 129 insertions(+), 135 deletions(-) diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 01c1397e..33230db0 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -170,21 +170,20 @@ uint32_t Context::checksum() const void Context::check() const { - auto &&proxy = rproxy(); for (auto &n : nets) { auto ni = n.second.get(); NPNR_ASSERT(n.first == ni->name); for (auto &w : ni->wires) { - NPNR_ASSERT(n.first == proxy.getBoundWireNet(w.first)); + NPNR_ASSERT(n.first == getBoundWireNet(w.first)); if (w.second.pip != PipId()) { NPNR_ASSERT(w.first == getPipDstWire(w.second.pip)); - NPNR_ASSERT(n.first == proxy.getBoundPipNet(w.second.pip)); + NPNR_ASSERT(n.first == getBoundPipNet(w.second.pip)); } } } for (auto w : getWires()) { - IdString net = proxy.getBoundWireNet(w); + IdString net = getBoundWireNet(w); if (net != IdString()) { NPNR_ASSERT(nets.at(net)->wires.count(w)); } @@ -193,7 +192,7 @@ void Context::check() const for (auto &c : cells) { NPNR_ASSERT(c.first == c.second->name); if (c.second->bel != BelId()) - NPNR_ASSERT(proxy.getBoundBelCell(c.second->bel) == c.first); + NPNR_ASSERT(getBoundBelCell(c.second->bel) == c.first); for (auto &port : c.second->ports) { NetInfo *net = port.second.net; if (net != nullptr) { diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 5c5689f0..51f4db84 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -151,7 +151,7 @@ IdString Arch::archArgsToId(ArchArgs args) const // ----------------------------------------------------------------------- -BelId ArchReadMethods::getBelByName(IdString name) const +BelId Arch::getBelByName(IdString name) const { BelId ret; auto it = bel_by_name.find(name); @@ -160,9 +160,9 @@ BelId ArchReadMethods::getBelByName(IdString name) const Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(parent_)); + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); ret.location = loc; - const LocationTypePOD *loci = parent_->locInfo(ret); + const LocationTypePOD *loci = locInfo(ret); for (int i = 0; i < loci->num_bels; i++) { if (std::strcmp(loci->bel_data[i].name.get(), basename.c_str()) == 0) { ret.index = i; @@ -185,14 +185,14 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const return br; } -WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const +WireId Arch::getWireBelPin(BelId bel, PortPin pin) const { WireId ret; NPNR_ASSERT(bel != BelId()); - int num_bel_wires = parent_->locInfo(bel)->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = parent_->locInfo(bel)->bel_data[bel.index].bel_wires.get(); + int num_bel_wires = locInfo(bel)->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = locInfo(bel)->bel_data[bel.index].bel_wires.get(); for (int i = 0; i < num_bel_wires; i++) if (bel_wires[i].port == pin) { ret.location = bel.location + bel_wires[i].rel_wire_loc; @@ -205,7 +205,7 @@ WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const // ----------------------------------------------------------------------- -WireId ArchReadMethods::getWireByName(IdString name) const +WireId Arch::getWireByName(IdString name) const { WireId ret; auto it = wire_by_name.find(name); @@ -214,9 +214,9 @@ WireId ArchReadMethods::getWireByName(IdString name) const Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(parent_)); + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); ret.location = loc; - const LocationTypePOD *loci = parent_->locInfo(ret); + const LocationTypePOD *loci = locInfo(ret); for (int i = 0; i < loci->num_wires; i++) { if (std::strcmp(loci->wire_data[i].name.get(), basename.c_str()) == 0) { ret.index = i; @@ -233,7 +233,7 @@ WireId ArchReadMethods::getWireByName(IdString name) const // ----------------------------------------------------------------------- -PipId ArchReadMethods::getPipByName(IdString name) const +PipId Arch::getPipByName(IdString name) const { auto it = pip_by_name.find(name); if (it != pip_by_name.end()) @@ -242,13 +242,13 @@ PipId ArchReadMethods::getPipByName(IdString name) const PipId ret; Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(parent_)); - const LocationTypePOD *loci = parent_->locInfo(ret); + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + const LocationTypePOD *loci = locInfo(ret); for (int i = 0; i < loci->num_pips; i++) { PipId curr; curr.location = loc; curr.index = i; - pip_by_name[parent_->getPipName(curr)] = curr; + pip_by_name[getPipName(curr)] = curr; } return pip_by_name[name]; } @@ -296,7 +296,7 @@ bool Arch::route() { return router1(getCtx()); } // ----------------------------------------------------------------------- -std::vector ArchReadMethods::getDecalGraphics(DecalId decalId) const +std::vector Arch::getDecalGraphics(DecalId decalId) const { std::vector ret; // FIXME @@ -315,9 +315,9 @@ DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; }; // ----------------------------------------------------------------------- -bool ArchReadMethods::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; } +bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; } -bool ArchReadMethods::isBelLocationValid(BelId bel) const { return true; } +bool Arch::isBelLocationValid(BelId bel) const { return true; } // ----------------------------------------------------------------------- @@ -330,77 +330,4 @@ IdString Arch::getPortClock(const CellInfo *cell, IdString port) const { return bool Arch::isClockPort(const CellInfo *cell, IdString port) const { return false; } -bool ArchReadMethods::checkWireAvail(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == IdString(); -} - -bool ArchReadMethods::checkPipAvail(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == IdString(); -} - -bool ArchReadMethods::checkBelAvail(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - return bel_to_cell.find(bel) == bel_to_cell.end() || bel_to_cell.at(bel) == IdString(); -} - -IdString ArchReadMethods::getConflictingBelCell(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - if (bel_to_cell.find(bel) == bel_to_cell.end()) - return IdString(); - else - return bel_to_cell.at(bel); -} - -IdString ArchReadMethods::getConflictingWireNet(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - if (wire_to_net.find(wire) == wire_to_net.end()) - return IdString(); - else - return wire_to_net.at(wire); -} - -IdString ArchReadMethods::getConflictingPipNet(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - if (pip_to_net.find(pip) == pip_to_net.end()) - return IdString(); - else - return pip_to_net.at(pip); -} - -IdString ArchReadMethods::getBoundWireNet(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - if (wire_to_net.find(wire) == wire_to_net.end()) - return IdString(); - else - return wire_to_net.at(wire); -} - -IdString ArchReadMethods::getBoundPipNet(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - if (pip_to_net.find(pip) == pip_to_net.end()) - return IdString(); - else - return pip_to_net.at(pip); -} - -IdString ArchReadMethods::getBoundBelCell(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - if (bel_to_cell.find(bel) == bel_to_cell.end()) - return IdString(); - else - return bel_to_cell.at(bel); -} - - NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch.h b/ecp5/arch.h index 50897b86..421a7738 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -371,6 +371,8 @@ public: // ------------------------------------------------- + BelId getBelByName(IdString name) const; + template const LocationTypePOD *locInfo(Id &id) const { return &(chip_info->locations[chip_info->location_type[id.location.y * chip_info->width + id.location.x]]); @@ -404,6 +406,30 @@ public: bel_to_cell[bel] = IdString(); } + bool checkBelAvail(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell.find(bel) == bel_to_cell.end() || bel_to_cell.at(bel) == IdString(); + } + + IdString getBoundBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + if (bel_to_cell.find(bel) == bel_to_cell.end()) + return IdString(); + else + return bel_to_cell.at(bel); + } + + IdString getConflictingBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + if (bel_to_cell.find(bel) == bel_to_cell.end()) + return IdString(); + else + return bel_to_cell.at(bel); + } + BelRange getBels() const { BelRange range; @@ -439,6 +465,8 @@ public: return locInfo(bel)->bel_data[bel.index].type; } + WireId getWireBelPin(BelId bel, PortPin pin) const; + BelPin getBelPinUphill(WireId wire) const { BelPin ret; @@ -466,6 +494,8 @@ public: // ------------------------------------------------- + WireId getWireByName(IdString name) const; + IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); @@ -505,6 +535,30 @@ public: wire_to_net[wire] = IdString(); } + bool checkWireAvail(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == IdString(); + } + + IdString getBoundWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + if (wire_to_net.find(wire) == wire_to_net.end()) + return IdString(); + else + return wire_to_net.at(wire); + } + + IdString getConflictingWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + if (wire_to_net.find(wire) == wire_to_net.end()) + return IdString(); + else + return wire_to_net.at(wire); + } + WireRange getWires() const { WireRange range; @@ -520,6 +574,7 @@ public: // ------------------------------------------------- + PipId getPipByName(IdString name) const; IdString getPipName(PipId pip) const; uint32_t getPipChecksum(PipId pip) const { return pip.index; } @@ -555,6 +610,30 @@ public: pip_to_net[pip] = IdString(); } + bool checkPipAvail(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == IdString(); + } + + IdString getBoundPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + if (pip_to_net.find(pip) == pip_to_net.end()) + return IdString(); + else + return pip_to_net.at(pip); + } + + IdString getConflictingPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + if (pip_to_net.find(pip) == pip_to_net.end()) + return IdString(); + else + return pip_to_net.at(pip); + } + AllPipRange getPips() const { AllPipRange range; @@ -637,7 +716,6 @@ public: // ------------------------------------------------- - // TODO(q3k) move this to archproxies? GroupId getGroupByName(IdString name) const { return GroupId(); } IdString getGroupName(GroupId group) const { return IdString(); } std::vector getGroups() const { return std::vector(); } @@ -648,8 +726,6 @@ public: // ------------------------------------------------- - // These are also specific to the chip and not state, so they're available - // on arch directly. void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; delay_t estimateDelay(WireId src, WireId dst) const; delay_t getDelayEpsilon() const { return 20; } @@ -665,7 +741,8 @@ public: // ------------------------------------------------- - // TODO(q3k) move this to archproxies? + std::vector getDecalGraphics(DecalId decal) const; + DecalXY getFrameDecal() const; DecalXY getBelDecal(BelId bel) const; DecalXY getWireDecal(WireId wire) const; @@ -683,6 +760,11 @@ public: bool isClockPort(const CellInfo *cell, IdString port) const; // Return true if a port is a net bool isGlobalNet(const NetInfo *net) const; + + // ------------------------------------------------- + // Placement validity checks + bool isValidBelForCell(CellInfo *cell, BelId bel) const; + bool isBelLocationValid(BelId bel) const; }; class ArchReadMethods : public BaseReadCtx @@ -718,6 +800,8 @@ class ArchReadMethods : public BaseReadCtx bool isValidBelForCell(CellInfo *cell, BelId bel) const; // Return true whether all Bels at a given location are valid bool isBelLocationValid(BelId bel) const; + // Helper function for above + bool logicCellsCompatible(const std::vector &cells) const; bool checkWireAvail(WireId wire) const; bool checkPipAvail(PipId pip) const; diff --git a/ecp5/arch_pybindings.h b/ecp5/arch_pybindings.h index 6256af18..a5044f29 100644 --- a/ecp5/arch_pybindings.h +++ b/ecp5/arch_pybindings.h @@ -30,11 +30,7 @@ namespace PythonConversion { template <> struct string_converter { - BelId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getBelByName(ctx->id(name)); - } + BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); } std::string to_str(Context *ctx, BelId id) { @@ -53,22 +49,14 @@ template <> struct string_converter template <> struct string_converter { - WireId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getWireByName(ctx->id(name)); - } + WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); } std::string to_str(Context *ctx, WireId id) { return ctx->getWireName(id).str(ctx); } }; template <> struct string_converter { - PipId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getPipByName(ctx->id(name)); - } + PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(ctx->id(name)); } std::string to_str(Context *ctx, PipId id) { return ctx->getPipName(id).str(ctx); } }; diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index b2376391..e70d6bb2 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -155,7 +155,6 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex { Trellis::Chip empty_chip(ctx->getChipName()); Trellis::ChipConfig cc; - auto &&proxy = ctx->rproxy(); std::set cib_tiles = {"CIB", "CIB_LR", "CIB_LR_S", "CIB_EFB0", "CIB_EFB1"}; @@ -173,7 +172,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex // Add all set, configurable pips to the config for (auto pip : ctx->getPips()) { - if (proxy.getBoundPipNet(pip) != IdString()) { + if (ctx->getBoundPipNet(pip) != IdString()) { if (ctx->getPipType(pip) == 0) { // ignore fixed pips std::string tile = empty_chip.get_tile_by_position_and_type(pip.location.y, pip.location.x, ctx->getPipTiletype(pip)); @@ -228,7 +227,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex (ci->ports.find(ctx->id("T")) == ci->ports.end() || ci->ports.at(ctx->id("T")).net == nullptr)) { // Tie tristate low if unconnected for outputs or bidir std::string jpt = fmt_str("X" << bel.location.x << "/Y" << bel.location.y << "/JPADDT" << pio.back()); - WireId jpt_wire = proxy.getWireByName(ctx->id(jpt)); + WireId jpt_wire = ctx->getWireByName(ctx->id(jpt)); PipId jpt_pip = *ctx->getPipsUphill(jpt_wire).begin(); WireId cib_wire = ctx->getPipSrcWire(jpt_pip); std::string cib_tile = diff --git a/gui/designwidget.cc b/gui/designwidget.cc index e839f006..110cf1b7 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -335,12 +335,10 @@ void DesignWidget::onItemClicked(QTreeWidgetItem *clickItem, int pos) return; } - auto &&proxy = ctx->rproxy(); - clearProperties(); if (type == ElementType::BEL) { IdString c = static_cast(clickItem)->getData(); - BelId bel = proxy.getBelByName(c); + BelId bel = ctx->getBelByName(c); QtProperty *topItem = groupManager->addProperty("Bel"); addProperty(topItem, "Bel"); @@ -354,20 +352,20 @@ void DesignWidget::onItemClicked(QTreeWidgetItem *clickItem, int pos) topItem->addSubProperty(typeItem); QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available"); - availItem->setValue(proxy.checkBelAvail(bel)); + availItem->setValue(ctx->checkBelAvail(bel)); topItem->addSubProperty(availItem); QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Cell"); - cellItem->setValue(proxy.getBoundBelCell(bel).c_str(ctx)); + cellItem->setValue(ctx->getBoundBelCell(bel).c_str(ctx)); topItem->addSubProperty(cellItem); QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Cell"); - conflictItem->setValue(proxy.getConflictingBelCell(bel).c_str(ctx)); + conflictItem->setValue(ctx->getConflictingBelCell(bel).c_str(ctx)); topItem->addSubProperty(conflictItem); } else if (type == ElementType::WIRE) { IdString c = static_cast(clickItem)->getData(); - WireId wire = proxy.getWireByName(c); + WireId wire = ctx->getWireByName(c); QtProperty *topItem = groupManager->addProperty("Wire"); addProperty(topItem, "Wire"); @@ -377,15 +375,15 @@ void DesignWidget::onItemClicked(QTreeWidgetItem *clickItem, int pos) topItem->addSubProperty(nameItem); QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available"); - availItem->setValue(proxy.checkWireAvail(wire)); + availItem->setValue(ctx->checkWireAvail(wire)); topItem->addSubProperty(availItem); QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Net"); - cellItem->setValue(proxy.getBoundWireNet(wire).c_str(ctx)); + cellItem->setValue(ctx->getBoundWireNet(wire).c_str(ctx)); topItem->addSubProperty(cellItem); QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Net"); - conflictItem->setValue(proxy.getConflictingWireNet(wire).c_str(ctx)); + conflictItem->setValue(ctx->getConflictingWireNet(wire).c_str(ctx)); topItem->addSubProperty(conflictItem); BelPin uphill = ctx->getBelPinUphill(wire); @@ -441,7 +439,7 @@ void DesignWidget::onItemClicked(QTreeWidgetItem *clickItem, int pos) } else if (type == ElementType::PIP) { IdString c = static_cast(clickItem)->getData(); - PipId pip = proxy.getPipByName(c); + PipId pip = ctx->getPipByName(c); QtProperty *topItem = groupManager->addProperty("Pip"); addProperty(topItem, "Pip"); @@ -451,15 +449,15 @@ void DesignWidget::onItemClicked(QTreeWidgetItem *clickItem, int pos) topItem->addSubProperty(nameItem); QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available"); - availItem->setValue(proxy.checkPipAvail(pip)); + availItem->setValue(ctx->checkPipAvail(pip)); topItem->addSubProperty(availItem); QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Net"); - cellItem->setValue(proxy.getBoundPipNet(pip).c_str(ctx)); + cellItem->setValue(ctx->getBoundPipNet(pip).c_str(ctx)); topItem->addSubProperty(cellItem); QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Net"); - conflictItem->setValue(proxy.getConflictingPipNet(pip).c_str(ctx)); + conflictItem->setValue(ctx->getConflictingPipNet(pip).c_str(ctx)); topItem->addSubProperty(conflictItem); QtVariantProperty *srcWireItem = readOnlyManager->addProperty(QVariant::String, "Src Wire"); diff --git a/ice40/arch.h b/ice40/arch.h index ec1e456f..cdee92e4 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -578,7 +578,6 @@ class Arch : public BaseCtx // ------------------------------------------------- - // TODO(q3k) move this to archproxies? DecalXY getFrameDecal() const; DecalXY getBelDecal(BelId bel) const; DecalXY getWireDecal(WireId wire) const; diff --git a/ice40/picorv32.sh b/ice40/picorv32.sh index 0518db83..2c67f641 100755 --- a/ice40/picorv32.sh +++ b/ice40/picorv32.sh @@ -1,6 +1,6 @@ #!/bin/bash set -ex -#rm -f picorv32.v -#wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v -#yosys -p 'synth_ice40 -nocarry -json picorv32.json -top top' picorv32.v picorv32_top.v -CPUPROFILE=../profile ../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json +rm -f picorv32.v +wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v +yosys -p 'synth_ice40 -nocarry -json picorv32.json -top top' picorv32.v picorv32_top.v +../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json -- cgit v1.2.3 From d4a0feb1adb05b8b086422021cde152289e591a7 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:50:29 +0100 Subject: Revert "Add read/mutate context stubs for ECP5" This reverts commit f333a68753655a4ccf7da9a4da96e7fdd19f9d08. --- ecp5/arch.h | 105 ++--------------------------------------------------------- ice40/arch.h | 4 +++ 2 files changed, 6 insertions(+), 103 deletions(-) diff --git a/ecp5/arch.h b/ecp5/arch.h index 421a7738..930c488e 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -339,10 +339,8 @@ struct ArchArgs struct Arch : BaseCtx { - // We let proxy methods access our state. - friend class ArchMutateMethods; - friend class ArchReadMethods; -private: + const ChipInfoPOD *chip_info; + mutable std::unordered_map bel_by_name; mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; @@ -352,9 +350,6 @@ private: std::unordered_map pip_to_net; std::unordered_map switches_locked; -public: - const ChipInfoPOD *chip_info; - ArchArgs args; Arch(ArchArgs args); @@ -767,100 +762,4 @@ public: bool isBelLocationValid(BelId bel) const; }; -class ArchReadMethods : public BaseReadCtx -{ - private: - const Arch *parent_; - const ChipInfoPOD *chip_info; - - const std::unordered_map &bel_to_cell; - const std::unordered_map &wire_to_net; - const std::unordered_map &pip_to_net; - const std::unordered_map &switches_locked; - std::unordered_map &bel_by_name; - std::unordered_map &wire_by_name; - std::unordered_map &pip_by_name; - - public: - ~ArchReadMethods() noexcept {} - ArchReadMethods(const Arch *parent) - : BaseReadCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), - wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) - { - } - ArchReadMethods(ArchReadMethods &&other) noexcept : ArchReadMethods(other.parent_) {} - ArchReadMethods(const ArchReadMethods &other) : ArchReadMethods(other.parent_) {} - - /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) - // Whether or not a given cell can be placed at a given Bel - // This is not intended for Bel type checks, but finer-grained constraints - // such as conflicting set/reset signals, etc - bool isValidBelForCell(CellInfo *cell, BelId bel) const; - // Return true whether all Bels at a given location are valid - bool isBelLocationValid(BelId bel) const; - // Helper function for above - bool logicCellsCompatible(const std::vector &cells) const; - - bool checkWireAvail(WireId wire) const; - bool checkPipAvail(PipId pip) const; - bool checkBelAvail(BelId bel) const; - - WireId getWireByName(IdString name) const; - WireId getWireBelPin(BelId bel, PortPin pin) const; - PipId getPipByName(IdString name) const; - - IdString getConflictingWireNet(WireId wire) const; - IdString getConflictingPipNet(PipId pip) const; - IdString getConflictingBelCell(BelId bel) const; - - IdString getBoundWireNet(WireId wire) const; - IdString getBoundPipNet(PipId pip) const; - IdString getBoundBelCell(BelId bel) const; - - BelId getBelByName(IdString name) const; - - std::vector getDecalGraphics(DecalId decal) const; -}; - -class ArchMutateMethods : public BaseMutateCtx -{ - friend class MutateContext; - - private: - Arch *parent_; - const ChipInfoPOD *chip_info; - - std::unordered_map &bel_to_cell; - std::unordered_map &wire_to_net; - std::unordered_map &pip_to_net; - std::unordered_map &switches_locked; - std::unordered_map &bel_by_name; - std::unordered_map &wire_by_name; - std::unordered_map &pip_by_name; - - public: - ~ArchMutateMethods() noexcept {} - ArchMutateMethods(Arch *parent) - : BaseMutateCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), - wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) - { - } - ArchMutateMethods(ArchMutateMethods &&other) noexcept : ArchMutateMethods(other.parent_) {} - ArchMutateMethods(const ArchMutateMethods &other) : ArchMutateMethods(other.parent_) {} - - void unbindWire(WireId wire); - void unbindPip(PipId pip); - void unbindBel(BelId bel); - void bindWire(WireId wire, IdString net, PlaceStrength strength); - void bindPip(PipId pip, IdString net, PlaceStrength strength); - void bindBel(BelId bel, IdString cell, PlaceStrength strength); - // Returned pointer is valid as long as Proxy object exists. - CellInfo *getCell(IdString cell); -}; - - NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index cdee92e4..f41990c3 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -345,6 +345,7 @@ class Arch : public BaseCtx friend class ArchReadMethods; private: + // All of the following... std::vector bel_to_cell; std::vector wire_to_net; std::vector pip_to_net; @@ -632,12 +633,15 @@ class ArchReadMethods : public BaseReadCtx ArchReadMethods(const ArchReadMethods &other) : ArchReadMethods(other.parent_) {} /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) + // Whether or not a given cell can be placed at a given Bel // This is not intended for Bel type checks, but finer-grained constraints // such as conflicting set/reset signals, etc bool isValidBelForCell(CellInfo *cell, BelId bel) const; + // Return true whether all Bels at a given location are valid bool isBelLocationValid(BelId bel) const; + // Helper function for above bool logicCellsCompatible(const std::vector &cells) const; -- cgit v1.2.3 From d9c3c117a38c8bc42cfb96255b4762965bc1611b Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:50:34 +0100 Subject: Revert "clang-format" This reverts commit 8ca7a6da2525463be5be4ee9f62cfae0acc06b01. --- common/nextpnr.cc | 11 +++++- common/nextpnr.h | 72 +++++++++++++++++++++------------- common/place_common.h | 6 ++- common/router1.cc | 1 + ice40/arch.cc | 104 +++++++++++++++++++++++++++++++++++++++----------- ice40/arch.h | 55 +++++++++++++------------- 6 files changed, 169 insertions(+), 80 deletions(-) diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 33230db0..54df5de1 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -21,9 +21,16 @@ NEXTPNR_NAMESPACE_BEGIN -MutateContext BaseCtx::rwproxy(void) { return MutateContext(reinterpret_cast(this)); } +MutateContext BaseCtx::rwproxy(void) +{ + return MutateContext(reinterpret_cast(this)); +} + +ReadContext BaseCtx::rproxy(void) const +{ + return ReadContext(reinterpret_cast(this)); +} -ReadContext BaseCtx::rproxy(void) const { return ReadContext(reinterpret_cast(this)); } assertion_failure::assertion_failure(std::string msg, std::string expr_str, std::string filename, int line) : runtime_error("Assertion failure: " + msg + " (" + filename + ":" + std::to_string(line) + ")"), msg(msg), diff --git a/common/nextpnr.h b/common/nextpnr.h index 6228e653..c3fb913c 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -27,6 +26,7 @@ #include #include #include +#include #ifndef NEXTPNR_H #define NEXTPNR_H @@ -261,8 +261,7 @@ class BaseCtx friend class MutateContext; friend class BaseReadCtx; friend class BaseMutateCtx; - - private: +private: mutable boost::shared_mutex mtx_; bool allUiReload = false; @@ -272,7 +271,7 @@ class BaseCtx std::unordered_set pipUiReload; std::unordered_set groupUiReload; - public: +public: IdString id(const std::string &s) const { return IdString(this, s); } IdString id(const char *s) const { return IdString(this, s); } @@ -312,16 +311,16 @@ class BaseCtx // locks can be taken while this one still exists. Ie., the UI can draw // elements while the PnR is going a RO operation. ReadContext rproxy(void) const; + }; // State-accessing read-only methods that every architecture object should // contain. class BaseReadCtx { - protected: +protected: const BaseCtx *base_; - - public: +public: BaseReadCtx(const BaseCtx *base) : base_(base) {} }; @@ -329,23 +328,41 @@ class BaseReadCtx // contain. class BaseMutateCtx { - protected: +protected: BaseCtx *base_; - public: +public: BaseMutateCtx(BaseCtx *base) : base_(base) {} - void refreshUi(void) { base_->allUiReload = true; } + void refreshUi(void) + { + base_->allUiReload = true; + } - void refreshUiFrame(void) { base_->frameUiReload = true; } + void refreshUiFrame(void) + { + base_->frameUiReload = true; + } - void refreshUiBel(BelId bel) { base_->belUiReload.insert(bel); } + void refreshUiBel(BelId bel) + { + base_->belUiReload.insert(bel); + } - void refreshUiWire(WireId wire) { base_->wireUiReload.insert(wire); } + void refreshUiWire(WireId wire) + { + base_->wireUiReload.insert(wire); + } - void refreshUiPip(PipId pip) { base_->pipUiReload.insert(pip); } + void refreshUiPip(PipId pip) + { + base_->pipUiReload.insert(pip); + } - void refreshUiGroup(GroupId group) { base_->groupUiReload.insert(group); } + void refreshUiGroup(GroupId group) + { + base_->groupUiReload.insert(group); + } UIUpdatesRequired getUIUpdatesRequired(void) { @@ -377,46 +394,49 @@ NEXTPNR_NAMESPACE_BEGIN class ReadContext : public ArchReadMethods { friend class BaseCtx; - - private: +private: boost::shared_mutex *lock_; - ReadContext(const Arch *parent) : ArchReadMethods(parent), lock_(&parent->mtx_) { lock_->lock_shared(); } - - public: + ReadContext(const Arch *parent) : ArchReadMethods(parent), lock_(&parent->mtx_) + { + lock_->lock_shared(); + } +public: ~ReadContext() { if (lock_ != nullptr) { lock_->unlock_shared(); } } - ReadContext(ReadContext &&other) : ArchReadMethods(other), lock_(other.lock_) { other.lock_ = nullptr; } + ReadContext(ReadContext &&other): ArchReadMethods(other), lock_(other.lock_) + { + other.lock_ = nullptr; + } }; // Read proxy to access MutateMethods while holding lock on underlying BaseCtx. class MutateContext : public ArchReadMethods, public ArchMutateMethods { friend class BaseCtx; - - private: +private: boost::shared_mutex *lock_; MutateContext(Arch *parent) : ArchReadMethods(parent), ArchMutateMethods(parent), lock_(&parent->mtx_) { lock_->lock(); } - - public: +public: ~MutateContext() { if (lock_ != nullptr) { lock_->unlock(); } } - MutateContext(MutateContext &&other) : ArchReadMethods(other), ArchMutateMethods(other), lock_(other.lock_) + MutateContext(MutateContext &&other): ArchReadMethods(other), ArchMutateMethods(other), lock_(other.lock_) { other.lock_ = nullptr; } }; + struct Context : Arch { bool verbose = false; diff --git a/common/place_common.h b/common/place_common.h index dac2e607..96ac48a9 100644 --- a/common/place_common.h +++ b/common/place_common.h @@ -29,7 +29,8 @@ NEXTPNR_NAMESPACE_BEGIN typedef int64_t wirelen_t; // Get the total estimated wirelength for a net -template wirelen_t get_net_wirelength(const T &proxy, const Context *ctx, const NetInfo *net, float &tns) +template +wirelen_t get_net_wirelength(const T &proxy, const Context *ctx, const NetInfo *net, float &tns) { wirelen_t wirelength = 0; int driver_x, driver_y; @@ -80,7 +81,8 @@ template wirelen_t get_net_wirelength(const T &proxy, const Context } // Return the wirelength of all nets connected to a cell -template wirelen_t get_cell_wirelength(const T &proxy, const Context *ctx, const CellInfo *cell) +template +wirelen_t get_cell_wirelength(const T &proxy, const Context *ctx, const CellInfo *cell) { std::set nets; for (auto p : cell->ports) { diff --git a/common/router1.cc b/common/router1.cc index dc75a153..f7a7e8a2 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -136,6 +136,7 @@ struct Router int thisVisitCnt = 0; int thisVisitCntLimit = 0; + while (!queue.empty() && (thisVisitCntLimit == 0 || thisVisitCnt < thisVisitCntLimit)) { QueuedWire qw = queue.top(); queue.pop(); diff --git a/ice40/arch.cc b/ice40/arch.cc index 8f2731c6..790167e9 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -259,43 +259,99 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const // ----------------------------------------------------------------------- // Shorthands to ArchProxy -BelId Arch::getBelByName(IdString name) const { return rproxy().getBelByName(name); } +BelId Arch::getBelByName(IdString name) const +{ + return rproxy().getBelByName(name); +} -void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength) { rwproxy().bindWire(wire, net, strength); } +void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength) +{ + rwproxy().bindWire(wire, net, strength); +} -void Arch::unbindWire(WireId wire) { rwproxy().unbindWire(wire); } +void Arch::unbindWire(WireId wire) +{ + rwproxy().unbindWire(wire); +} -void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength) { rwproxy().bindBel(bel, cell, strength); } +void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength) { + rwproxy().bindBel(bel, cell, strength); +} -void Arch::unbindBel(BelId bel) { rwproxy().unbindBel(bel); } +void Arch::unbindBel(BelId bel) +{ + rwproxy().unbindBel(bel); +} -bool Arch::checkBelAvail(BelId bel) const { return rproxy().checkBelAvail(bel); } +bool Arch::checkBelAvail(BelId bel) const +{ + return rproxy().checkBelAvail(bel); +} -IdString Arch::getBoundBelCell(BelId bel) const { return rproxy().getBoundBelCell(bel); } +IdString Arch::getBoundBelCell(BelId bel) const +{ + return rproxy().getBoundBelCell(bel); +} -IdString Arch::getConflictingBelCell(BelId bel) const { return rproxy().getConflictingBelCell(bel); } +IdString Arch::getConflictingBelCell(BelId bel) const +{ + return rproxy().getConflictingBelCell(bel); +} -WireId Arch::getWireByName(IdString name) const { return rproxy().getWireByName(name); } +WireId Arch::getWireByName(IdString name) const +{ + return rproxy().getWireByName(name); +} -WireId Arch::getWireBelPin(BelId bel, PortPin pin) const { return rproxy().getWireBelPin(bel, pin); } +WireId Arch::getWireBelPin(BelId bel, PortPin pin) const +{ + return rproxy().getWireBelPin(bel, pin); +} -bool Arch::checkWireAvail(WireId wire) const { return rproxy().checkWireAvail(wire); } +bool Arch::checkWireAvail(WireId wire) const +{ + return rproxy().checkWireAvail(wire); +} -IdString Arch::getBoundWireNet(WireId wire) const { return rproxy().getBoundWireNet(wire); } +IdString Arch::getBoundWireNet(WireId wire) const +{ + return rproxy().getBoundWireNet(wire); +} -IdString Arch::getConflictingWireNet(WireId wire) const { return rproxy().getConflictingWireNet(wire); } +IdString Arch::getConflictingWireNet(WireId wire) const +{ + return rproxy().getConflictingWireNet(wire); +} -PipId Arch::getPipByName(IdString name) const { return rproxy().getPipByName(name); } +PipId Arch::getPipByName(IdString name) const +{ + return rproxy().getPipByName(name); +} -void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength) { return rwproxy().bindPip(pip, net, strength); } +void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength) +{ + return rwproxy().bindPip(pip, net, strength); +} -void Arch::unbindPip(PipId pip) { return rwproxy().unbindPip(pip); } +void Arch::unbindPip(PipId pip) +{ + return rwproxy().unbindPip(pip); +} -bool Arch::checkPipAvail(PipId pip) const { return rproxy().checkPipAvail(pip); } +bool Arch::checkPipAvail(PipId pip) const +{ + return rproxy().checkPipAvail(pip); +} -IdString Arch::getBoundPipNet(PipId pip) const { return rproxy().getBoundPipNet(pip); } +IdString Arch::getBoundPipNet(PipId pip) const +{ + return rproxy().getBoundPipNet(pip); +} -IdString Arch::getConflictingPipNet(PipId pip) const { return rproxy().getConflictingPipNet(pip); } +IdString Arch::getConflictingPipNet(PipId pip) const +{ + return rproxy().getConflictingPipNet(pip); +} // ----------------------------------------------------------------------- @@ -574,7 +630,8 @@ std::vector ArchReadMethods::getDecalGraphics(DecalId decal) con } if (bel_type == TYPE_ICESTORM_RAM) { - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { int tx = chip_info->bel_data[bel.index].x; int ty = chip_info->bel_data[bel.index].y + i; @@ -584,7 +641,7 @@ std::vector ArchReadMethods::getDecalGraphics(DecalId decal) con el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1; - el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + 7 * logic_cell_pitch; + el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + 7*logic_cell_pitch; el.z = 0; ret.push_back(el); @@ -879,6 +936,9 @@ void ArchMutateMethods::unbindPip(PipId pip) refreshUiWire(dst); } -CellInfo *ArchMutateMethods::getCell(IdString cell) { return parent_->cells.at(cell).get(); } +CellInfo *ArchMutateMethods::getCell(IdString cell) +{ + return parent_->cells.at(cell).get(); +} NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index f41990c3..5d4eaedf 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -343,8 +343,7 @@ class Arch : public BaseCtx // We let proxy methods access our state. friend class ArchMutateMethods; friend class ArchReadMethods; - - private: +private: // All of the following... std::vector bel_to_cell; std::vector wire_to_net; @@ -354,7 +353,7 @@ class Arch : public BaseCtx mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; - public: +public: const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; @@ -411,7 +410,10 @@ class Arch : public BaseCtx return id(chip_info->bel_data[bel.index].name.get()); } - uint32_t getBelChecksum(BelId bel) const { return bel.index; } + uint32_t getBelChecksum(BelId bel) const + { + return bel.index; + } BelRange getBels() const { @@ -443,6 +445,7 @@ class Arch : public BaseCtx return chip_info->bel_data[bel.index].type; } + BelPin getBelPinUphill(WireId wire) const { BelPin ret; @@ -546,6 +549,7 @@ class Arch : public BaseCtx return range; } + BelId getPackagePinBel(const std::string &pin) const; std::string getBelPackagePin(BelId bel) const; @@ -607,9 +611,8 @@ class Arch : public BaseCtx }; // Read-only methods on Arch that require state access. -class ArchReadMethods : public BaseReadCtx -{ - private: +class ArchReadMethods : public BaseReadCtx { +private: const Arch *parent_; const ChipInfoPOD *chip_info; const std::vector &bel_to_cell; @@ -620,15 +623,14 @@ class ArchReadMethods : public BaseReadCtx std::unordered_map &wire_by_name; std::unordered_map &pip_by_name; - public: - ~ArchReadMethods() noexcept {} - ArchReadMethods(const Arch *parent) - : BaseReadCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), - wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) - { - } +public: + ~ArchReadMethods() noexcept { } + ArchReadMethods(const Arch *parent) : BaseReadCtx(parent), parent_(parent), + chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), + wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), + switches_locked(parent->switches_locked), + bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), + pip_by_name(parent->pip_by_name) {} ArchReadMethods(ArchReadMethods &&other) noexcept : ArchReadMethods(other.parent_) {} ArchReadMethods(const ArchReadMethods &other) : ArchReadMethods(other.parent_) {} @@ -667,11 +669,9 @@ class ArchReadMethods : public BaseReadCtx }; // State mutating methods on Arch. -class ArchMutateMethods : public BaseMutateCtx -{ +class ArchMutateMethods : public BaseMutateCtx { friend class MutateContext; - - private: +private: Arch *parent_; const ChipInfoPOD *chip_info; std::vector &bel_to_cell; @@ -682,14 +682,13 @@ class ArchMutateMethods : public BaseMutateCtx std::unordered_map &wire_by_name; std::unordered_map &pip_by_name; - public: - ArchMutateMethods(Arch *parent) - : BaseMutateCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), - wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) - { - } +public: + ArchMutateMethods(Arch *parent) : BaseMutateCtx(parent), parent_(parent), + chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), + wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), + switches_locked(parent->switches_locked), + bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), + pip_by_name(parent->pip_by_name) {} ArchMutateMethods(ArchMutateMethods &&other) : ArchMutateMethods(other.parent_) {} ArchMutateMethods(const ArchMutateMethods &other) : ArchMutateMethods(other.parent_) {} ~ArchMutateMethods() {} -- cgit v1.2.3 From b0c05c7f751cf68165849a8f28d389541456f956 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:50:37 +0100 Subject: Revert "Refactor proxies to nextpnr." This reverts commit 9b17fe385cf7e8d3025747b5f7c7822ac2d99920. --- common/nextpnr.cc | 11 --- common/nextpnr.h | 170 +++++++++-------------------------------------- common/place_common.cc | 2 +- common/place_common.h | 2 +- common/placer1.cc | 4 +- common/router1.cc | 4 +- ice40/arch.cc | 77 ++++++++++++--------- ice40/arch.h | 130 ++++++++++++++++++++++++++++-------- ice40/arch_place.cc | 6 +- ice40/place_legaliser.cc | 6 +- 10 files changed, 194 insertions(+), 218 deletions(-) diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 54df5de1..3861e5fe 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -21,17 +21,6 @@ NEXTPNR_NAMESPACE_BEGIN -MutateContext BaseCtx::rwproxy(void) -{ - return MutateContext(reinterpret_cast(this)); -} - -ReadContext BaseCtx::rproxy(void) const -{ - return ReadContext(reinterpret_cast(this)); -} - - assertion_failure::assertion_failure(std::string msg, std::string expr_str, std::string filename, int line) : runtime_error("Assertion failure: " + msg + " (" + filename + ":" + std::to_string(line) + ")"), msg(msg), expr_str(expr_str), filename(filename), line(line) diff --git a/common/nextpnr.h b/common/nextpnr.h index c3fb913c..efcab9fc 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -26,7 +26,6 @@ #include #include #include -#include #ifndef NEXTPNR_H #define NEXTPNR_H @@ -249,37 +248,21 @@ struct UIUpdatesRequired std::unordered_set groupUIReload; }; -class ReadContext; -class MutateContext; -class BaseReadCtx; -class BaseMutateCtx; - -// Data that every architecture object should contain. -class BaseCtx +struct BaseCtx { - friend class ReadContext; - friend class MutateContext; - friend class BaseReadCtx; - friend class BaseMutateCtx; -private: - mutable boost::shared_mutex mtx_; + // -------------------------------------------------------------- - bool allUiReload = false; - bool frameUiReload = false; - std::unordered_set belUiReload; - std::unordered_set wireUiReload; - std::unordered_set pipUiReload; - std::unordered_set groupUiReload; + mutable std::unordered_map *idstring_str_to_idx; + mutable std::vector *idstring_idx_to_str; -public: IdString id(const std::string &s) const { return IdString(this, s); } + IdString id(const char *s) const { return IdString(this, s); } - // TODO(q3k): These need to be made private. + // -------------------------------------------------------------- + std::unordered_map> nets; std::unordered_map> cells; - mutable std::unordered_map *idstring_str_to_idx; - mutable std::vector *idstring_idx_to_str; BaseCtx() { @@ -303,83 +286,41 @@ public: // -------------------------------------------------------------- - // Get a readwrite proxy to arch - this will keep a readwrite lock on the - // entire architecture until the proxy object goes out of scope. - MutateContext rwproxy(void); - // Get a read-only proxy to arch - this will keep a read lock on the - // entire architecture until the proxy object goes out of scope. Other read - // locks can be taken while this one still exists. Ie., the UI can draw - // elements while the PnR is going a RO operation. - ReadContext rproxy(void) const; - -}; - -// State-accessing read-only methods that every architecture object should -// contain. -class BaseReadCtx -{ -protected: - const BaseCtx *base_; -public: - BaseReadCtx(const BaseCtx *base) : base_(base) {} -}; - -// State-accesssing read/write methods that every architecture object should -// contain. -class BaseMutateCtx -{ -protected: - BaseCtx *base_; - -public: - BaseMutateCtx(BaseCtx *base) : base_(base) {} + bool allUiReload = false; + bool frameUiReload = false; + std::unordered_set belUiReload; + std::unordered_set wireUiReload; + std::unordered_set pipUiReload; + std::unordered_set groupUiReload; - void refreshUi(void) - { - base_->allUiReload = true; - } + void refreshUi() { allUiReload = true; } - void refreshUiFrame(void) - { - base_->frameUiReload = true; - } + void refreshUiFrame() { frameUiReload = true; } - void refreshUiBel(BelId bel) - { - base_->belUiReload.insert(bel); - } + void refreshUiBel(BelId bel) { belUiReload.insert(bel); } - void refreshUiWire(WireId wire) - { - base_->wireUiReload.insert(wire); - } + void refreshUiWire(WireId wire) { wireUiReload.insert(wire); } - void refreshUiPip(PipId pip) - { - base_->pipUiReload.insert(pip); - } + void refreshUiPip(PipId pip) { pipUiReload.insert(pip); } - void refreshUiGroup(GroupId group) - { - base_->groupUiReload.insert(group); - } + void refreshUiGroup(GroupId group) { groupUiReload.insert(group); } UIUpdatesRequired getUIUpdatesRequired(void) { UIUpdatesRequired req; - req.allUIReload = base_->allUiReload; - req.frameUIReload = base_->frameUiReload; - req.belUIReload = base_->belUiReload; - req.wireUIReload = base_->wireUiReload; - req.pipUIReload = base_->pipUiReload; - req.groupUIReload = base_->groupUiReload; - - base_->allUiReload = false; - base_->frameUiReload = false; - base_->belUiReload.clear(); - base_->wireUiReload.clear(); - base_->pipUiReload.clear(); - base_->groupUiReload.clear(); + req.allUIReload = allUiReload; + req.frameUIReload = frameUiReload; + req.belUIReload = belUiReload; + req.wireUIReload = wireUiReload; + req.pipUIReload = pipUiReload; + req.groupUIReload = groupUiReload; + + allUiReload = false; + frameUiReload = false; + belUiReload.clear(); + wireUiReload.clear(); + pipUiReload.clear(); + groupUiReload.clear(); return req; } }; @@ -390,53 +331,6 @@ NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_BEGIN -// Read proxy to access ReadMethods while holding lock on underlying BaseCtx. -class ReadContext : public ArchReadMethods -{ - friend class BaseCtx; -private: - boost::shared_mutex *lock_; - ReadContext(const Arch *parent) : ArchReadMethods(parent), lock_(&parent->mtx_) - { - lock_->lock_shared(); - } -public: - ~ReadContext() - { - if (lock_ != nullptr) { - lock_->unlock_shared(); - } - } - ReadContext(ReadContext &&other): ArchReadMethods(other), lock_(other.lock_) - { - other.lock_ = nullptr; - } -}; - -// Read proxy to access MutateMethods while holding lock on underlying BaseCtx. -class MutateContext : public ArchReadMethods, public ArchMutateMethods -{ - friend class BaseCtx; -private: - boost::shared_mutex *lock_; - MutateContext(Arch *parent) : ArchReadMethods(parent), ArchMutateMethods(parent), lock_(&parent->mtx_) - { - lock_->lock(); - } -public: - ~MutateContext() - { - if (lock_ != nullptr) { - lock_->unlock(); - } - } - MutateContext(MutateContext &&other): ArchReadMethods(other), ArchMutateMethods(other), lock_(other.lock_) - { - other.lock_ = nullptr; - } -}; - - struct Context : Arch { bool verbose = false; diff --git a/common/place_common.cc b/common/place_common.cc index 9694b6fe..48416370 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -26,7 +26,7 @@ NEXTPNR_NAMESPACE_BEGIN // Placing a single cell -bool place_single_cell(MutateContext &proxy, Context *ctx, CellInfo *cell, bool require_legality) +bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool require_legality) { bool all_placed = false; int iters = 25; diff --git a/common/place_common.h b/common/place_common.h index 96ac48a9..57e82510 100644 --- a/common/place_common.h +++ b/common/place_common.h @@ -109,7 +109,7 @@ wirelen_t get_cell_wirelength_at_bel(const T &proxy, const Context *ctx, CellInf } // Place a single cell in the lowest wirelength Bel available, optionally requiring validity check -bool place_single_cell(MutateContext &proxy, Context *ctx, CellInfo *cell, bool require_legality); +bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool require_legality); NEXTPNR_NAMESPACE_END diff --git a/common/placer1.cc b/common/placer1.cc index 78515ece..0e3a84f7 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -275,7 +275,7 @@ class SAPlacer private: // Initial random placement - void place_initial(MutateContext &proxy, CellInfo *cell) + void place_initial(ArchRWProxy &proxy, CellInfo *cell) { bool all_placed = false; int iters = 25; @@ -325,7 +325,7 @@ class SAPlacer } // Attempt a SA position swap, return true on success or false on failure - bool try_swap_position(MutateContext &proxy, CellInfo *cell, BelId newBel) + bool try_swap_position(ArchRWProxy &proxy, CellInfo *cell, BelId newBel) { static std::unordered_set update; static std::vector> new_lengths; diff --git a/common/router1.cc b/common/router1.cc index f7a7e8a2..0d26a36d 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -74,7 +74,7 @@ struct RipupScoreboard std::unordered_map, int, hash_id_pip> netPipScores; }; -void ripup_net(MutateContext &proxy, Context *ctx, IdString net_name) +void ripup_net(ArchRWProxy &proxy, Context *ctx, IdString net_name) { auto net_info = ctx->nets.at(net_name).get(); std::vector pips; @@ -115,7 +115,7 @@ struct Router delay_t maxDelay = 0.0; WireId failedDest; - void route(MutateContext &proxy, const std::unordered_map &src_wires, WireId dst_wire) + void route(ArchRWProxy &proxy, const std::unordered_map &src_wires, WireId dst_wire) { std::priority_queue, QueuedWire::Greater> queue; diff --git a/ice40/arch.cc b/ice40/arch.cc index 790167e9..547dbcd6 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -29,6 +29,18 @@ NEXTPNR_NAMESPACE_BEGIN +ArchRWProxy Arch::rwproxy(void) { + ArchRWProxy res(this); + return res; +} + +ArchRProxy Arch::rproxy(void) const { + ArchRProxy res(this); + return res; +} + +// ----------------------------------------------------------------------- + IdString Arch::belTypeToId(BelType type) const { if (type == TYPE_ICESTORM_LC) @@ -522,7 +534,7 @@ DecalXY Arch::getGroupDecal(GroupId group) const return decalxy; }; -std::vector ArchReadMethods::getDecalGraphics(DecalId decal) const +std::vector ArchRProxyMethods::getDecalGraphics(DecalId decal) const { std::vector ret; @@ -720,25 +732,25 @@ bool Arch::isGlobalNet(const NetInfo *net) const // ----------------------------------------------------------------------- -bool ArchReadMethods::checkBelAvail(BelId bel) const +bool ArchRProxyMethods::checkBelAvail(BelId bel) const { NPNR_ASSERT(bel != BelId()); return bel_to_cell[bel.index] == IdString(); } -IdString ArchReadMethods::getBoundBelCell(BelId bel) const +IdString ArchRProxyMethods::getBoundBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); return bel_to_cell[bel.index]; } -IdString ArchReadMethods::getConflictingBelCell(BelId bel) const +IdString ArchRProxyMethods::getConflictingBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); return bel_to_cell[bel.index]; } -WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const +WireId ArchRProxyMethods::getWireBelPin(BelId bel, PortPin pin) const { WireId ret; @@ -756,7 +768,7 @@ WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const return ret; } -WireId ArchReadMethods::getWireByName(IdString name) const +WireId ArchRProxyMethods::getWireByName(IdString name) const { WireId ret; @@ -772,25 +784,25 @@ WireId ArchReadMethods::getWireByName(IdString name) const return ret; } -bool ArchReadMethods::checkWireAvail(WireId wire) const +bool ArchRProxyMethods::checkWireAvail(WireId wire) const { NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index] == IdString(); } -IdString ArchReadMethods::getBoundWireNet(WireId wire) const +IdString ArchRProxyMethods::getBoundWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index]; } -IdString ArchReadMethods::getConflictingWireNet(WireId wire) const +IdString ArchRProxyMethods::getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index]; } -PipId ArchReadMethods::getPipByName(IdString name) const +PipId ArchRProxyMethods::getPipByName(IdString name) const { PipId ret; @@ -809,25 +821,25 @@ PipId ArchReadMethods::getPipByName(IdString name) const return ret; } -bool ArchReadMethods::checkPipAvail(PipId pip) const +bool ArchRProxyMethods::checkPipAvail(PipId pip) const { NPNR_ASSERT(pip != PipId()); return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); } -IdString ArchReadMethods::getBoundPipNet(PipId pip) const +IdString ArchRProxyMethods::getBoundPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); return pip_to_net[pip.index]; } -IdString ArchReadMethods::getConflictingPipNet(PipId pip) const +IdString ArchRProxyMethods::getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); return switches_locked[chip_info->pip_data[pip.index].switch_index]; } -BelId ArchReadMethods::getBelByName(IdString name) const +BelId ArchRProxyMethods::getBelByName(IdString name) const { BelId ret; @@ -845,27 +857,27 @@ BelId ArchReadMethods::getBelByName(IdString name) const // ----------------------------------------------------------------------- -void ArchMutateMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) +void ArchRWProxyMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) { NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); bel_to_cell[bel.index] = cell; parent_->cells[cell]->bel = bel; parent_->cells[cell]->belStrength = strength; - refreshUiBel(bel); + parent_->refreshUiBel(bel); } -void ArchMutateMethods::unbindBel(BelId bel) +void ArchRWProxyMethods::unbindBel(BelId bel) { NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); parent_->cells[bel_to_cell[bel.index]]->bel = BelId(); parent_->cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; bel_to_cell[bel.index] = IdString(); - refreshUiBel(bel); + parent_->refreshUiBel(bel); } -void ArchMutateMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) +void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire.index] == IdString()); @@ -873,10 +885,10 @@ void ArchMutateMethods::bindWire(WireId wire, IdString net, PlaceStrength streng wire_to_net[wire.index] = net; parent_->nets[net]->wires[wire].pip = PipId(); parent_->nets[net]->wires[wire].strength = strength; - refreshUiWire(wire); + parent_->refreshUiWire(wire); } -void ArchMutateMethods::unbindWire(WireId wire) +void ArchRWProxyMethods::unbindWire(WireId wire) { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire.index] != IdString()); @@ -889,15 +901,15 @@ void ArchMutateMethods::unbindWire(WireId wire) if (pip != PipId()) { pip_to_net[pip.index] = IdString(); switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); - refreshUiPip(pip); + parent_->refreshUiPip(pip); } net_wires.erase(it); wire_to_net[wire.index] = IdString(); - refreshUiWire(wire); + parent_->refreshUiWire(wire); } -void ArchMutateMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) +void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] == IdString()); @@ -913,11 +925,11 @@ void ArchMutateMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) parent_->nets[net]->wires[dst].pip = pip; parent_->nets[net]->wires[dst].strength = strength; - refreshUiPip(pip); - refreshUiWire(dst); + parent_->refreshUiPip(pip); + parent_->refreshUiWire(dst); } -void ArchMutateMethods::unbindPip(PipId pip) +void ArchRWProxyMethods::unbindPip(PipId pip) { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] != IdString()); @@ -932,13 +944,18 @@ void ArchMutateMethods::unbindPip(PipId pip) pip_to_net[pip.index] = IdString(); switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); - refreshUiPip(pip); - refreshUiWire(dst); + parent_->refreshUiPip(pip); + parent_->refreshUiWire(dst); } -CellInfo *ArchMutateMethods::getCell(IdString cell) +CellInfo *ArchRWProxyMethods::getCell(IdString cell) { return parent_->cells.at(cell).get(); } +UIUpdatesRequired ArchRWProxyMethods::getUIUpdatesRequired(void) +{ + return parent_->getUIUpdatesRequired(); +} + NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index 5d4eaedf..4311f4a5 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -22,6 +22,9 @@ #error Include "arch.h" via "nextpnr.h" only. #endif +#include +#include + NEXTPNR_NAMESPACE_BEGIN /**** Everything in this section must be kept in sync with chipdb.py ****/ @@ -327,8 +330,11 @@ struct ArchArgs /// Forward declare proxy classes for Arch. -class ArchMutateMethods; -class ArchReadMethods; +class ArchRWProxyMethods; +class ArchRProxyMethods; +class ArchRWProxy; +class ArchRProxy; + /// Arch/Context // Arch is the main state class of the PnR algorithms. It keeps note of mapped @@ -341,8 +347,11 @@ class ArchReadMethods; class Arch : public BaseCtx { // We let proxy methods access our state. - friend class ArchMutateMethods; - friend class ArchReadMethods; + friend class ArchRWProxyMethods; + friend class ArchRProxyMethods; + // We let proxy objects access our mutex. + friend class ArchRWProxy; + friend class ArchRProxy; private: // All of the following... std::vector bel_to_cell; @@ -353,6 +362,9 @@ private: mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; + // ... are guarded by the following lock: + mutable boost::shared_mutex mtx_; + public: const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; @@ -360,6 +372,15 @@ public: ArchArgs args; Arch(ArchArgs args); + // Get a readwrite proxy to arch - this will keep a readwrite lock on the + // entire architecture until the proxy object goes out of scope. + ArchRWProxy rwproxy(void); + // Get a read-only proxy to arch - this will keep a read lock on the + // entire architecture until the proxy object goes out of scope. Other read + // locks can be taken while this one still exists. Ie., the UI can draw + // elements while the PnR is going a RO operation. + ArchRProxy rproxy(void) const; + std::string getChipName(); IdString archId() const { return id("ice40"); } @@ -611,9 +632,22 @@ public: }; // Read-only methods on Arch that require state access. -class ArchReadMethods : public BaseReadCtx { +class ArchRProxyMethods { + // We let proxy objects access our private constructors. + friend class ArchRProxy; + friend class ArchRWProxy; private: const Arch *parent_; + ArchRProxyMethods(const Arch *parent) : parent_(parent), chip_info(parent->chip_info), + bel_to_cell(parent->bel_to_cell), wire_to_net(parent->wire_to_net), + pip_to_net(parent->pip_to_net), switches_locked(parent->switches_locked), + bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), + pip_by_name(parent->pip_by_name) {} + ArchRProxyMethods(ArchRProxyMethods &&other) noexcept : ArchRProxyMethods(other.parent_) {} + ArchRProxyMethods(const ArchRProxyMethods &other) : ArchRProxyMethods(other.parent_) {} + + // Let methods access hot members directly without having to go through + // parent_. const ChipInfoPOD *chip_info; const std::vector &bel_to_cell; const std::vector &wire_to_net; @@ -622,17 +656,8 @@ private: std::unordered_map &bel_by_name; std::unordered_map &wire_by_name; std::unordered_map &pip_by_name; - public: - ~ArchReadMethods() noexcept { } - ArchReadMethods(const Arch *parent) : BaseReadCtx(parent), parent_(parent), - chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), - bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), - pip_by_name(parent->pip_by_name) {} - ArchReadMethods(ArchReadMethods &&other) noexcept : ArchReadMethods(other.parent_) {} - ArchReadMethods(const ArchReadMethods &other) : ArchReadMethods(other.parent_) {} + ~ArchRProxyMethods() noexcept { } /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) @@ -668,11 +693,44 @@ public: std::vector getDecalGraphics(DecalId decal) const; }; +// A proxy object that keeps an Arch shared/readonly lock until it goes out +// of scope. All const/read-only ArchRProxyMethods are available on it. +class ArchRProxy : public ArchRProxyMethods { + friend class Arch; + friend class ArchRWProxy; +private: + boost::shared_mutex *lock_; + ArchRProxy(const Arch *parent) : ArchRProxyMethods(parent), lock_(&parent->mtx_) + { + lock_->lock_shared(); + } + +public: + ~ArchRProxy() { + if (lock_ != nullptr) { + lock_->unlock_shared(); + } + } + ArchRProxy(ArchRProxy &&other) : ArchRProxyMethods(other), lock_(other.lock_) + { + other.lock_ = nullptr; + } +}; + // State mutating methods on Arch. -class ArchMutateMethods : public BaseMutateCtx { - friend class MutateContext; +class ArchRWProxyMethods { + // We let proxy objects access our private constructors. + friend class ArchRWProxy; private: Arch *parent_; + ArchRWProxyMethods(Arch *parent) : parent_(parent), chip_info(parent->chip_info), + bel_to_cell(parent->bel_to_cell), wire_to_net(parent->wire_to_net), + pip_to_net(parent->pip_to_net), switches_locked(parent->switches_locked), + bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), + pip_by_name(parent->pip_by_name) {} + ArchRWProxyMethods(ArchRWProxyMethods &&other) : ArchRWProxyMethods(other.parent_) {} + ArchRWProxyMethods(const ArchRWProxyMethods &other) : ArchRWProxyMethods(other.parent_) {} + const ChipInfoPOD *chip_info; std::vector &bel_to_cell; std::vector &wire_to_net; @@ -681,17 +739,8 @@ private: std::unordered_map &bel_by_name; std::unordered_map &wire_by_name; std::unordered_map &pip_by_name; - public: - ArchMutateMethods(Arch *parent) : BaseMutateCtx(parent), parent_(parent), - chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), - bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), - pip_by_name(parent->pip_by_name) {} - ArchMutateMethods(ArchMutateMethods &&other) : ArchMutateMethods(other.parent_) {} - ArchMutateMethods(const ArchMutateMethods &other) : ArchMutateMethods(other.parent_) {} - ~ArchMutateMethods() {} + ~ArchRWProxyMethods() {} void unbindWire(WireId wire); void unbindPip(PipId pip); @@ -701,6 +750,33 @@ public: void bindBel(BelId bel, IdString cell, PlaceStrength strength); // Returned pointer is valid as long as Proxy object exists. CellInfo *getCell(IdString cell); + + + // Methods to be used by UI for detecting whether we need to redraw. + UIUpdatesRequired getUIUpdatesRequired(void); +}; + +// A proxy object that keeps an Arch readwrite lock until it goes out of scope. +// All ArchRProxyMethods and ArchRWProxyMethods are available on it. +class ArchRWProxy : public ArchRProxyMethods, public ArchRWProxyMethods { + friend class Arch; +private: + boost::shared_mutex *lock_; + ArchRWProxy(Arch *parent) : ArchRProxyMethods(parent), ArchRWProxyMethods(parent), lock_(&parent->mtx_) { + lock_->lock(); + } + +public: + ArchRWProxy(ArchRWProxy &&other) : ArchRProxyMethods(other), ArchRWProxyMethods(other), lock_(other.lock_) + { + other.lock_ = nullptr; + } + ~ArchRWProxy() + { + if (lock_ != nullptr) { + lock_->unlock(); + } + } }; NEXTPNR_NAMESPACE_END diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 42efceab..cb7c44b8 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -25,7 +25,7 @@ NEXTPNR_NAMESPACE_BEGIN -bool ArchReadMethods::logicCellsCompatible(const std::vector &cells) const +bool ArchRProxyMethods::logicCellsCompatible(const std::vector &cells) const { bool dffs_exist = false, dffs_neg = false; const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; @@ -76,7 +76,7 @@ bool ArchReadMethods::logicCellsCompatible(const std::vector & return locals_count <= 32; } -bool ArchReadMethods::isBelLocationValid(BelId bel) const +bool ArchRProxyMethods::isBelLocationValid(BelId bel) const { if (parent_->getBelType(bel) == TYPE_ICESTORM_LC) { std::vector bel_cells; @@ -97,7 +97,7 @@ bool ArchReadMethods::isBelLocationValid(BelId bel) const } } -bool ArchReadMethods::isValidBelForCell(CellInfo *cell, BelId bel) const +bool ArchRProxyMethods::isValidBelForCell(CellInfo *cell, BelId bel) const { if (cell->type == parent_->id_icestorm_lc) { NPNR_ASSERT(parent_->getBelType(bel) == TYPE_ICESTORM_LC); diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index fcb47cfd..10a6f3ff 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -253,7 +253,7 @@ class PlacementLegaliser } // Find Bel closest to a location, meeting chain requirements - std::tuple find_closest_bel(MutateContext &proxy, float target_x, float target_y, CellChain &chain) + std::tuple find_closest_bel(ArchRWProxy &proxy, float target_x, float target_y, CellChain &chain) { std::tuple best_origin = std::make_tuple(-1, -1, -1); wirelen_t best_wirelength = std::numeric_limits::max(); @@ -283,7 +283,7 @@ class PlacementLegaliser } // Split a carry chain into multiple legal chains - std::vector split_carry_chain(const ReadContext &proxy, CellChain &carryc) + std::vector split_carry_chain(const ArchRProxy &proxy, CellChain &carryc) { bool start_of_chain = true; std::vector chains; @@ -335,7 +335,7 @@ class PlacementLegaliser } // Place a logic cell at a given grid location, handling rip-up etc - void place_lc(MutateContext &proxy, CellInfo *cell, int x, int y, int z) + void place_lc(ArchRWProxy &proxy, CellInfo *cell, int x, int y, int z) { auto &loc = logic_bels.at(x).at(y).at(z); NPNR_ASSERT(!loc.second); -- cgit v1.2.3 From 77878f5af7c3d1ca001ec610dbedda85ce9b9174 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:50:42 +0100 Subject: Revert "Fix description in Nix derivation" This reverts commit 9365bf297c3e1a47d97dbc92e9f2df5aea590126. --- nextpnr.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nextpnr.nix b/nextpnr.nix index bbd2c127..97097749 100644 --- a/nextpnr.nix +++ b/nextpnr.nix @@ -43,8 +43,8 @@ in enableParallelBuilding = true; meta = with stdenv.lib; { - description = "Next Generation Place-and-Route tool for FPGAs"; - homepage = "https://gitlab.com/symbioticeda/nextpnr"; + description = "A computer-aided design (CAD) tool from a parallel universe"; + homepage = "https://github.com/mkeeter/antimony"; license = licenses.bsd0; platforms = platforms.linux; }; -- cgit v1.2.3 From 836d8c1ef3295a34c591324ef4c8ec48687279ee Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:50:46 +0100 Subject: Revert "Add Nix(OS) support" This reverts commit 7db6817a0b5afcf89e3c7eafc031a7eec59ee24e. --- README.md | 15 --------------- default.nix | 28 ---------------------------- nextpnr.nix | 53 ----------------------------------------------------- 3 files changed, 96 deletions(-) delete mode 100644 default.nix delete mode 100644 nextpnr.nix diff --git a/README.md b/README.md index eb96bd1c..da38500d 100644 --- a/README.md +++ b/README.md @@ -78,21 +78,6 @@ Running `./nextpnr-ecp5 --json ecp5/synth/blinky.json --basecfg ecp5/synth/ulx3s_empty.config --bit ecp5/synth/ulx3s.bit` - Note that `ulx3s_empty.config` contains fixed/unknown bits to be copied to the output bitstream - You can also use `--textcfg out.config` to write a text file describing the bitstream for debugging - -Nix ---- - -As an alternative to getting the prerequisites yourself, you can use Nix/NixOS and run the following to get dropped into a shell with nextpnr built: - - nix-shell - -Or, you can add the `nextpnr.nix` file into your /etc/nixos/configuration.nix: - - environment.systemPackages = [ - ... - ( import /home/q3k/Software/nextpnr/nextpnr.nix ) - ... - ]; Notes ------- diff --git a/default.nix b/default.nix deleted file mode 100644 index 664e3669..00000000 --- a/default.nix +++ /dev/null @@ -1,28 +0,0 @@ -# -# nextpnr -- Next Generation Place and Route -# -# Copyright (C) 2018 Serge Bazanski -# -# 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. -# - - -with import {}; - -stdenv.mkDerivation rec { - name = "env"; - env = buildEnv { name = name; paths = buildInputs; }; - buildInputs = [ - ( import ./nextpnr.nix ) - ]; -} diff --git a/nextpnr.nix b/nextpnr.nix deleted file mode 100644 index 97097749..00000000 --- a/nextpnr.nix +++ /dev/null @@ -1,53 +0,0 @@ -# -# nextpnr -- Next Generation Place and Route -# -# Copyright (C) 2018 Serge Bazanski -# -# 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. -# - -with import {}; - -let - gitRev = "a8c84e90a39c54174dd24b5b76bd17aed8311481"; - gitBranch = "master"; -in - stdenv.mkDerivation rec { - name = "nextpnr-${version}"; - version = "1.0.0"; - - src = ./.; - - buildInputs = [ - python3 (boost.override { python = python3; }) - qt5.qtbase - ]; - - nativeBuildInputs = [ cmake icestorm ]; - - cmakeFlags= [ - "-DARCH=ice40" - "-DICEBOX_ROOT=${icestorm}/share/icebox" - ]; - - enableParallelBuilding = true; - - meta = with stdenv.lib; { - description = "A computer-aided design (CAD) tool from a parallel universe"; - homepage = "https://github.com/mkeeter/antimony"; - license = licenses.bsd0; - platforms = platforms.linux; - }; - } - - -- cgit v1.2.3 From 36b4e3382dc552fcd1b078bdd246dc14379394a1 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:50:50 +0100 Subject: Revert "Make GUI nice and smooth." This reverts commit a8c84e90a39c54174dd24b5b76bd17aed8311481. --- common/nextpnr.h | 31 ---------- gui/fpgaviewwidget.cc | 154 +++++++++++++++++++++++++++++++++----------------- gui/fpgaviewwidget.h | 99 +++++++------------------------- ice40/arch.cc | 10 +--- ice40/arch.h | 8 +-- ice40/main.cc | 3 +- 6 files changed, 127 insertions(+), 178 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index efcab9fc..50465869 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -238,16 +238,6 @@ struct CellInfo std::unordered_map pins; }; -struct UIUpdatesRequired -{ - bool allUIReload; - bool frameUIReload; - std::unordered_set belUIReload; - std::unordered_set wireUIReload; - std::unordered_set pipUIReload; - std::unordered_set groupUIReload; -}; - struct BaseCtx { // -------------------------------------------------------------- @@ -270,8 +260,6 @@ struct BaseCtx idstring_idx_to_str = new std::vector; IdString::initialize_add(this, "", 0); IdString::initialize_arch(this); - - allUiReload = true; } ~BaseCtx() @@ -304,25 +292,6 @@ struct BaseCtx void refreshUiPip(PipId pip) { pipUiReload.insert(pip); } void refreshUiGroup(GroupId group) { groupUiReload.insert(group); } - - UIUpdatesRequired getUIUpdatesRequired(void) - { - UIUpdatesRequired req; - req.allUIReload = allUiReload; - req.frameUIReload = frameUiReload; - req.belUIReload = belUiReload; - req.wireUIReload = wireUiReload; - req.pipUIReload = pipUiReload; - req.groupUIReload = groupUiReload; - - allUiReload = false; - frameUiReload = false; - belUiReload.clear(); - wireUiReload.clear(); - pipUiReload.clear(); - groupUiReload.clear(); - return req; - } }; NEXTPNR_NAMESPACE_END diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 21ce5b67..6b6a2617 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -23,7 +23,6 @@ #include #include #include -#include #include #include "fpgaviewwidget.h" @@ -196,7 +195,7 @@ bool LineShader::compile(void) return true; } -void LineShader::draw(const LineShaderData &line, const QColor &color, const float thickness, const QMatrix4x4 &projection) +void LineShader::draw(const LineShaderData &line, const QMatrix4x4 &projection) { auto gl = QOpenGLContext::currentContext()->functions(); vao_.bind(); @@ -215,8 +214,8 @@ void LineShader::draw(const LineShaderData &line, const QColor &color, const flo buffers_.index.allocate(&line.indices[0], sizeof(GLuint) * line.indices.size()); program_->setUniformValue(uniforms_.projection, projection); - program_->setUniformValue(uniforms_.thickness, thickness); - program_->setUniformValue(uniforms_.color, color.redF(), color.greenF(), color.blueF(), color.alphaF()); + program_->setUniformValue(uniforms_.thickness, line.thickness); + program_->setUniformValue(uniforms_.color, line.color.r, line.color.g, line.color.b, line.color.a); buffers_.position.bind(); program_->enableAttributeArray("position"); @@ -265,10 +264,6 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineSha if (fmt.minorVersion() < 1) { printf("Could not get OpenGL 3.1 context - trying anyway...\n "); } - - QTimer *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(update())); - timer->start(5000); } FPGAViewWidget::~FPGAViewWidget() {} @@ -292,6 +287,73 @@ void FPGAViewWidget::initializeGL() glClearColor(backgroundColor_.red() / 255, backgroundColor_.green() / 255, backgroundColor_.blue() / 255, 0.0); } +void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal) +{ + const float scale = 1.0; + float offsetX = 0.0, offsetY = 0.0; + + for (auto &el : ctx_->getDecalGraphics(decal.decal)) { + offsetX = decal.x; + offsetY = decal.y; + + if (el.type == GraphicElement::G_BOX) { + auto line = PolyLine(true); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); + line.build(out); + } + + if (el.type == GraphicElement::G_LINE) { + PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, offsetY + scale * el.y2) + .build(out); + } + } +} + +void FPGAViewWidget::drawDecal(LineShaderData out[], const DecalXY &decal) +{ + const float scale = 1.0; + float offsetX = 0.0, offsetY = 0.0; + + for (auto &el : ctx_->getDecalGraphics(decal.decal)) { + offsetX = decal.x; + offsetY = decal.y; + + if (el.type == GraphicElement::G_BOX) { + auto line = PolyLine(true); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); + line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); + line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); + switch (el.style) { + case GraphicElement::G_FRAME: + case GraphicElement::G_INACTIVE: + case GraphicElement::G_ACTIVE: + line.build(out[el.style]); + break; + default: + break; + } + } + + if (el.type == GraphicElement::G_LINE) { + auto line = PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, + offsetY + scale * el.y2); + switch (el.style) { + case GraphicElement::G_FRAME: + case GraphicElement::G_INACTIVE: + case GraphicElement::G_ACTIVE: + line.build(out[el.style]); + break; + default: + break; + } + } + } +} + QMatrix4x4 FPGAViewWidget::getProjection(void) { QMatrix4x4 matrix; @@ -318,59 +380,47 @@ void FPGAViewWidget::paintGL() float thick11Px = mouseToWorldCoordinates(1.1, 0).x(); // Draw grid. - auto grid = LineShaderData(); + auto grid = LineShaderData(thick1Px, gridColor_); for (float i = -100.0f; i < 100.0f; i += 1.0f) { PolyLine(-100.0f, i, 100.0f, i).build(grid); PolyLine(i, -100.0f, i, 100.0f).build(grid); } - lineShader_.draw(grid, gridColor_, thick1Px, matrix); + lineShader_.draw(grid, matrix); + + LineShaderData shaders[4] = {[GraphicElement::G_FRAME] = LineShaderData(thick11Px, gFrameColor_), + [GraphicElement::G_HIDDEN] = LineShaderData(thick11Px, gHiddenColor_), + [GraphicElement::G_INACTIVE] = LineShaderData(thick11Px, gInactiveColor_), + [GraphicElement::G_ACTIVE] = LineShaderData(thick11Px, gActiveColor_)}; if (ctx_) { - auto &&proxy = ctx_->rwproxy(); - auto updates = proxy.getUIUpdatesRequired(); - - // Collapse all updates to a full redraw. - // TODO(q3k) fix this. - - bool redraw = (updates.allUIReload - || !updates.belUIReload.empty() - || !updates.wireUIReload.empty() - || !updates.pipUIReload.empty() - || !updates.groupUIReload.empty() - || updates.frameUIReload); - - if (redraw) { - shaders_[0].clear(); - shaders_[1].clear(); - shaders_[2].clear(); - shaders_[3].clear(); - - // Draw Bels. - for (auto bel : ctx_->getBels()) { - drawDecal(proxy, shaders_, ctx_->getBelDecal(bel)); - } - // Draw Wires. - for (auto wire : ctx_->getWires()) { - drawDecal(proxy, shaders_, ctx_->getWireDecal(wire)); - } - // Draw Pips. - for (auto pip : ctx_->getPips()) { - drawDecal(proxy, shaders_, ctx_->getPipDecal(pip)); - } - // Draw Groups. - for (auto group : ctx_->getGroups()) { - drawDecal(proxy, shaders_, ctx_->getGroupDecal(group)); - } - // Draw Frame Graphics. - drawDecal(proxy, shaders_, ctx_->getFrameDecal()); + // Draw Bels. + for (auto bel : ctx_->getBels()) { + drawDecal(shaders, ctx_->getBelDecal(bel)); + } + // Draw Wires. + for (auto wire : ctx_->getWires()) { + drawDecal(shaders, ctx_->getWireDecal(wire)); + } + // Draw Pips. + for (auto pip : ctx_->getPips()) { + drawDecal(shaders, ctx_->getPipDecal(pip)); + } + // Draw Groups. + for (auto group : ctx_->getGroups()) { + drawDecal(shaders, ctx_->getGroupDecal(group)); } } + lineShader_.draw(shaders[0], matrix); + lineShader_.draw(shaders[1], matrix); + lineShader_.draw(shaders[2], matrix); + lineShader_.draw(shaders[3], matrix); - lineShader_.draw(shaders_[0], gFrameColor_, thick11Px, matrix); - lineShader_.draw(shaders_[1], gHiddenColor_, thick11Px, matrix); - lineShader_.draw(shaders_[2], gInactiveColor_, thick11Px, matrix); - lineShader_.draw(shaders_[3], gActiveColor_, thick11Px, matrix); - //lineShader_.draw(frame, matrix); + // Draw Frame Graphics. + auto frames = LineShaderData(thick11Px, frameColor_); + if (ctx_) { + drawDecal(frames, ctx_->getFrameDecal()); + lineShader_.draw(frames, matrix); + } } void FPGAViewWidget::resizeGL(int width, int height) {} diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 3652e82e..410b0582 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -41,6 +41,18 @@ NPNR_PACKED_STRUCT(struct Vertex2DPOD { Vertex2DPOD(GLfloat X, GLfloat Y) : x(X), y(Y) {} }); +// Vertex2DPOD is a structure of R, G, B, A values that can be passed to OpenGL +// directly. +NPNR_PACKED_STRUCT(struct ColorPOD { + GLfloat r; + GLfloat g; + GLfloat b; + GLfloat a; + + ColorPOD(GLfloat R, GLfloat G, GLfloat B, GLfloat A) : r(R), g(G), b(B), a(A) {} + ColorPOD(const QColor &color) : r(color.redF()), g(color.greenF()), b(color.blueF()), a(color.alphaF()) {} +}); + // LineShaderData is a built set of vertices that can be rendered by the // LineShader. // Each LineShaderData can have its' own color and thickness. @@ -51,13 +63,10 @@ struct LineShaderData std::vector miters; std::vector indices; - void clear(void) - { - vertices.clear(); - normals.clear(); - miters.clear(); - indices.clear(); - } + GLfloat thickness; + ColorPOD color; + + LineShaderData(GLfloat Thickness, QColor Color) : thickness(Thickness), color(Color) {} }; // PolyLine is a set of segments defined by points, that can be built to a @@ -201,7 +210,7 @@ class LineShader bool compile(void); // Render a LineShaderData with a given M/V/P transformation. - void draw(const LineShaderData &data, const QColor &color, const float thickness, const QMatrix4x4 &projection); + void draw(const LineShaderData &data, const QMatrix4x4 &projection); }; class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions @@ -237,76 +246,8 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; - - template - void drawDecal(const T &proxy, LineShaderData &out, const DecalXY &decal) - { - const float scale = 1.0; - float offsetX = 0.0, offsetY = 0.0; - - for (auto &el : proxy.getDecalGraphics(decal.decal)) { - offsetX = decal.x; - offsetY = decal.y; - - if (el.type == GraphicElement::G_BOX) { - auto line = PolyLine(true); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); - line.build(out); - } - - if (el.type == GraphicElement::G_LINE) { - PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, offsetY + scale * el.y2) - .build(out); - } - } - } - - template - void drawDecal(const T &proxy, LineShaderData out[], const DecalXY &decal) - { - const float scale = 1.0; - float offsetX = 0.0, offsetY = 0.0; - - for (auto &el : proxy.getDecalGraphics(decal.decal)) { - offsetX = decal.x; - offsetY = decal.y; - - if (el.type == GraphicElement::G_BOX) { - auto line = PolyLine(true); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y1); - line.point(offsetX + scale * el.x2, offsetY + scale * el.y2); - line.point(offsetX + scale * el.x1, offsetY + scale * el.y2); - switch (el.style) { - case GraphicElement::G_FRAME: - case GraphicElement::G_INACTIVE: - case GraphicElement::G_ACTIVE: - line.build(out[el.style]); - break; - default: - break; - } - } - - if (el.type == GraphicElement::G_LINE) { - auto line = PolyLine(offsetX + scale * el.x1, offsetY + scale * el.y1, offsetX + scale * el.x2, - offsetY + scale * el.y2); - switch (el.style) { - case GraphicElement::G_FRAME: - case GraphicElement::G_INACTIVE: - case GraphicElement::G_ACTIVE: - line.build(out[el.style]); - break; - default: - break; - } - } - } - } - + void drawDecal(LineShaderData &data, const DecalXY &decal); + void drawDecal(LineShaderData out[], const DecalXY &decal); public Q_SLOTS: void newContext(Context *ctx); @@ -333,8 +274,6 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions QColor gInactiveColor_; QColor gActiveColor_; QColor frameColor_; - - LineShaderData shaders_[4]; }; NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.cc b/ice40/arch.cc index 547dbcd6..af6e922c 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -534,8 +534,9 @@ DecalXY Arch::getGroupDecal(GroupId group) const return decalxy; }; -std::vector ArchRProxyMethods::getDecalGraphics(DecalId decal) const +std::vector Arch::getDecalGraphics(DecalId decal) const { + boost::shared_lock_guard lock(mtx_); std::vector ret; if (decal.type == DecalId::TYPE_FRAME) { @@ -567,7 +568,7 @@ std::vector ArchRProxyMethods::getDecalGraphics(DecalId decal) c BelId bel; bel.index = decal.index; - auto bel_type = parent_->getBelType(bel); + auto bel_type = getBelType(bel); if (bel_type == TYPE_ICESTORM_LC) { GraphicElement el; @@ -953,9 +954,4 @@ CellInfo *ArchRWProxyMethods::getCell(IdString cell) return parent_->cells.at(cell).get(); } -UIUpdatesRequired ArchRWProxyMethods::getUIUpdatesRequired(void) -{ - return parent_->getUIUpdatesRequired(); -} - NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index 4311f4a5..da1e583a 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -604,6 +604,8 @@ public: // ------------------------------------------------- + std::vector getDecalGraphics(DecalId decal) const; + DecalXY getFrameDecal() const; DecalXY getBelDecal(BelId bel) const; DecalXY getWireDecal(WireId wire) const; @@ -689,8 +691,6 @@ public: IdString getBoundBelCell(BelId bel) const; BelId getBelByName(IdString name) const; - - std::vector getDecalGraphics(DecalId decal) const; }; // A proxy object that keeps an Arch shared/readonly lock until it goes out @@ -750,10 +750,6 @@ public: void bindBel(BelId bel, IdString cell, PlaceStrength strength); // Returned pointer is valid as long as Proxy object exists. CellInfo *getCell(IdString cell); - - - // Methods to be used by UI for detecting whether we need to redraw. - UIUpdatesRequired getUIUpdatesRequired(void); }; // A proxy object that keeps an Arch readwrite lock until it goes out of scope. diff --git a/ice40/main.cc b/ice40/main.cc index d38c786c..e77bdd34 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -51,8 +51,7 @@ void svg_dump_decal(const Context *ctx, const DecalXY &decal) const float scale = 10.0, offset = 10.0; const std::string style = "stroke=\"black\" stroke-width=\"0.1\" fill=\"none\""; - auto &&proxy = ctx->rproxy(); - for (auto &el : proxy.getDecalGraphics(decal.decal)) { + for (auto &el : ctx->getDecalGraphics(decal.decal)) { if (el.type == GraphicElement::G_BOX) { std::cout << " Date: Sat, 14 Jul 2018 18:50:54 +0100 Subject: Revert "Slight simplification of proxy code" This reverts commit a71b576de6c404572439e30a56c4ff19497523a2. --- ice40/arch.cc | 108 +++++++++++++++++++++++++++++----------------------------- ice40/arch.h | 53 ++++++++-------------------- 2 files changed, 68 insertions(+), 93 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index af6e922c..af31e147 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -736,19 +736,19 @@ bool Arch::isGlobalNet(const NetInfo *net) const bool ArchRProxyMethods::checkBelAvail(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index] == IdString(); + return parent_->bel_to_cell[bel.index] == IdString(); } IdString ArchRProxyMethods::getBoundBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index]; + return parent_->bel_to_cell[bel.index]; } IdString ArchRProxyMethods::getConflictingBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index]; + return parent_->bel_to_cell[bel.index]; } WireId ArchRProxyMethods::getWireBelPin(BelId bel, PortPin pin) const @@ -757,8 +757,8 @@ WireId ArchRProxyMethods::getWireBelPin(BelId bel, PortPin pin) const NPNR_ASSERT(bel != BelId()); - int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); + int num_bel_wires = parent_->chip_info->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = parent_->chip_info->bel_data[bel.index].bel_wires.get(); for (int i = 0; i < num_bel_wires; i++) if (bel_wires[i].port == pin) { @@ -773,13 +773,13 @@ WireId ArchRProxyMethods::getWireByName(IdString name) const { WireId ret; - if (wire_by_name.empty()) { - for (int i = 0; i < chip_info->num_wires; i++) - wire_by_name[parent_->id(chip_info->wire_data[i].name.get())] = i; + if (parent_->wire_by_name.empty()) { + for (int i = 0; i < parent_->chip_info->num_wires; i++) + parent_->wire_by_name[parent_->id(parent_->chip_info->wire_data[i].name.get())] = i; } - auto it = wire_by_name.find(name); - if (it != wire_by_name.end()) + auto it = parent_->wire_by_name.find(name); + if (it != parent_->wire_by_name.end()) ret.index = it->second; return ret; @@ -788,35 +788,35 @@ WireId ArchRProxyMethods::getWireByName(IdString name) const bool ArchRProxyMethods::checkWireAvail(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index] == IdString(); + return parent_->wire_to_net[wire.index] == IdString(); } IdString ArchRProxyMethods::getBoundWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; + return parent_->wire_to_net[wire.index]; } IdString ArchRProxyMethods::getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; + return parent_->wire_to_net[wire.index]; } PipId ArchRProxyMethods::getPipByName(IdString name) const { PipId ret; - if (pip_by_name.empty()) { - for (int i = 0; i < chip_info->num_pips; i++) { + if (parent_->pip_by_name.empty()) { + for (int i = 0; i < parent_->chip_info->num_pips; i++) { PipId pip; pip.index = i; - pip_by_name[parent_->getPipName(pip)] = i; + parent_->pip_by_name[parent_->getPipName(pip)] = i; } } - auto it = pip_by_name.find(name); - if (it != pip_by_name.end()) + auto it = parent_->pip_by_name.find(name); + if (it != parent_->pip_by_name.end()) ret.index = it->second; return ret; @@ -825,32 +825,32 @@ PipId ArchRProxyMethods::getPipByName(IdString name) const bool ArchRProxyMethods::checkPipAvail(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); + return parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] == IdString(); } IdString ArchRProxyMethods::getBoundPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return pip_to_net[pip.index]; + return parent_->pip_to_net[pip.index]; } IdString ArchRProxyMethods::getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index]; + return parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index]; } BelId ArchRProxyMethods::getBelByName(IdString name) const { BelId ret; - if (bel_by_name.empty()) { - for (int i = 0; i < chip_info->num_bels; i++) - bel_by_name[parent_->id(chip_info->bel_data[i].name.get())] = i; + if (parent_->bel_by_name.empty()) { + for (int i = 0; i < parent_->chip_info->num_bels; i++) + parent_->bel_by_name[parent_->id(parent_->chip_info->bel_data[i].name.get())] = i; } - auto it = bel_by_name.find(name); - if (it != bel_by_name.end()) + auto it = parent_->bel_by_name.find(name); + if (it != parent_->bel_by_name.end()) ret.index = it->second; return ret; @@ -861,8 +861,8 @@ BelId ArchRProxyMethods::getBelByName(IdString name) const void ArchRWProxyMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) { NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); - bel_to_cell[bel.index] = cell; + NPNR_ASSERT(parent_->bel_to_cell[bel.index] == IdString()); + parent_->bel_to_cell[bel.index] = cell; parent_->cells[cell]->bel = bel; parent_->cells[cell]->belStrength = strength; parent_->refreshUiBel(bel); @@ -871,19 +871,19 @@ void ArchRWProxyMethods::bindBel(BelId bel, IdString cell, PlaceStrength strengt void ArchRWProxyMethods::unbindBel(BelId bel) { NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); - parent_->cells[bel_to_cell[bel.index]]->bel = BelId(); - parent_->cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; - bel_to_cell[bel.index] = IdString(); + NPNR_ASSERT(parent_->bel_to_cell[bel.index] != IdString()); + parent_->cells[parent_->bel_to_cell[bel.index]]->bel = BelId(); + parent_->cells[parent_->bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; + parent_->bel_to_cell[bel.index] = IdString(); parent_->refreshUiBel(bel); } void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) { NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] == IdString()); + NPNR_ASSERT(parent_->wire_to_net[wire.index] == IdString()); - wire_to_net[wire.index] = net; + parent_->wire_to_net[wire.index] = net; parent_->nets[net]->wires[wire].pip = PipId(); parent_->nets[net]->wires[wire].strength = strength; parent_->refreshUiWire(wire); @@ -892,37 +892,37 @@ void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength stren void ArchRWProxyMethods::unbindWire(WireId wire) { NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] != IdString()); + NPNR_ASSERT(parent_->wire_to_net[wire.index] != IdString()); - auto &net_wires = parent_->nets[wire_to_net[wire.index]]->wires; + auto &net_wires = parent_->nets[parent_->wire_to_net[wire.index]]->wires; auto it = net_wires.find(wire); NPNR_ASSERT(it != net_wires.end()); auto pip = it->second.pip; if (pip != PipId()) { - pip_to_net[pip.index] = IdString(); - switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + parent_->pip_to_net[pip.index] = IdString(); + parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString(); parent_->refreshUiPip(pip); } net_wires.erase(it); - wire_to_net[wire.index] = IdString(); + parent_->wire_to_net[wire.index] = IdString(); parent_->refreshUiWire(wire); } void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) { NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip.index] == IdString()); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); + NPNR_ASSERT(parent_->pip_to_net[pip.index] == IdString()); + NPNR_ASSERT(parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] == IdString()); - pip_to_net[pip.index] = net; - switches_locked[chip_info->pip_data[pip.index].switch_index] = net; + parent_->pip_to_net[pip.index] = net; + parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = net; WireId dst; - dst.index = chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst.index] == IdString()); - wire_to_net[dst.index] = net; + dst.index = parent_->chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(parent_->wire_to_net[dst.index] == IdString()); + parent_->wire_to_net[dst.index] = net; parent_->nets[net]->wires[dst].pip = pip; parent_->nets[net]->wires[dst].strength = strength; @@ -933,17 +933,17 @@ void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength void ArchRWProxyMethods::unbindPip(PipId pip) { NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip.index] != IdString()); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); + NPNR_ASSERT(parent_->pip_to_net[pip.index] != IdString()); + NPNR_ASSERT(parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] != IdString()); WireId dst; - dst.index = chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst.index] != IdString()); - wire_to_net[dst.index] = IdString(); - parent_->nets[pip_to_net[pip.index]]->wires.erase(dst); + dst.index = parent_->chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(parent_->wire_to_net[dst.index] != IdString()); + parent_->wire_to_net[dst.index] = IdString(); + parent_->nets[parent_->pip_to_net[pip.index]]->wires.erase(dst); - pip_to_net[pip.index] = IdString(); - switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + parent_->pip_to_net[pip.index] = IdString(); + parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString(); parent_->refreshUiPip(pip); parent_->refreshUiWire(dst); diff --git a/ice40/arch.h b/ice40/arch.h index da1e583a..8428dc29 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -339,7 +339,7 @@ class ArchRProxy; /// Arch/Context // Arch is the main state class of the PnR algorithms. It keeps note of mapped // cells/nets, locked switches, etc. -// +// // In order to mutate state in Arch, you can do one of two things: // - directly call one of the wrapper methods to mutate state // - get a read or readwrite proxy to the Arch, and call methods on it @@ -419,7 +419,7 @@ public: IdString getBoundPipNet(PipId pip) const; IdString getBoundBelCell(BelId bel) const; BelId getBelByName(IdString name) const; - + // ------------------------------------------------- /// Methods to get chip info - don't need to use a wrapper, as these are @@ -506,7 +506,7 @@ public: range.e.cursor = chip_info->num_pips; return range; } - + IdString getPipName(PipId pip) const; uint32_t getPipChecksum(PipId pip) const { return pip.index; } @@ -640,27 +640,13 @@ class ArchRProxyMethods { friend class ArchRWProxy; private: const Arch *parent_; - ArchRProxyMethods(const Arch *parent) : parent_(parent), chip_info(parent->chip_info), - bel_to_cell(parent->bel_to_cell), wire_to_net(parent->wire_to_net), - pip_to_net(parent->pip_to_net), switches_locked(parent->switches_locked), - bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), - pip_by_name(parent->pip_by_name) {} - ArchRProxyMethods(ArchRProxyMethods &&other) noexcept : ArchRProxyMethods(other.parent_) {} - ArchRProxyMethods(const ArchRProxyMethods &other) : ArchRProxyMethods(other.parent_) {} - - // Let methods access hot members directly without having to go through - // parent_. - const ChipInfoPOD *chip_info; - const std::vector &bel_to_cell; - const std::vector &wire_to_net; - const std::vector &pip_to_net; - const std::vector &switches_locked; - std::unordered_map &bel_by_name; - std::unordered_map &wire_by_name; - std::unordered_map &pip_by_name; + ArchRProxyMethods(const Arch *parent) : parent_(parent) {} + ArchRProxyMethods(ArchRProxyMethods &&other) noexcept : parent_(other.parent_) {} + ArchRProxyMethods(const ArchRProxyMethods &other) : parent_(other.parent_) {} + public: ~ArchRProxyMethods() noexcept { } - + /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) // Whether or not a given cell can be placed at a given Bel @@ -681,7 +667,7 @@ public: WireId getWireByName(IdString name) const; WireId getWireBelPin(BelId bel, PortPin pin) const; PipId getPipByName(IdString name) const; - + IdString getConflictingWireNet(WireId wire) const; IdString getConflictingPipNet(PipId pip) const; IdString getConflictingBelCell(BelId bel) const; @@ -723,22 +709,9 @@ class ArchRWProxyMethods { friend class ArchRWProxy; private: Arch *parent_; - ArchRWProxyMethods(Arch *parent) : parent_(parent), chip_info(parent->chip_info), - bel_to_cell(parent->bel_to_cell), wire_to_net(parent->wire_to_net), - pip_to_net(parent->pip_to_net), switches_locked(parent->switches_locked), - bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name), - pip_by_name(parent->pip_by_name) {} - ArchRWProxyMethods(ArchRWProxyMethods &&other) : ArchRWProxyMethods(other.parent_) {} - ArchRWProxyMethods(const ArchRWProxyMethods &other) : ArchRWProxyMethods(other.parent_) {} - - const ChipInfoPOD *chip_info; - std::vector &bel_to_cell; - std::vector &wire_to_net; - std::vector &pip_to_net; - std::vector &switches_locked; - std::unordered_map &bel_by_name; - std::unordered_map &wire_by_name; - std::unordered_map &pip_by_name; + ArchRWProxyMethods(Arch *parent) : parent_(parent) {} + ArchRWProxyMethods(ArchRWProxyMethods &&other) : parent_(other.parent_) {} + ArchRWProxyMethods(const ArchRWProxyMethods &other) : parent_(other.parent_) {} public: ~ArchRWProxyMethods() {} @@ -773,6 +746,8 @@ public: lock_->unlock(); } } + + }; NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From 09ca9ea39edbb33bfb23119786a3fa2792785e87 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:50:58 +0100 Subject: Revert "Comment arch.h" This reverts commit dc3256e62fce923a3dc703c521bea5a13cef4443. --- ice40/arch.h | 35 +---------------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/ice40/arch.h b/ice40/arch.h index 8428dc29..36e34d7b 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -328,28 +328,15 @@ struct ArchArgs std::string package; }; -/// Forward declare proxy classes for Arch. - class ArchRWProxyMethods; class ArchRProxyMethods; class ArchRWProxy; class ArchRProxy; - -/// Arch/Context -// Arch is the main state class of the PnR algorithms. It keeps note of mapped -// cells/nets, locked switches, etc. -// -// In order to mutate state in Arch, you can do one of two things: -// - directly call one of the wrapper methods to mutate state -// - get a read or readwrite proxy to the Arch, and call methods on it - class Arch : public BaseCtx { - // We let proxy methods access our state. friend class ArchRWProxyMethods; friend class ArchRProxyMethods; - // We let proxy objects access our mutex. friend class ArchRWProxy; friend class ArchRProxy; private: @@ -372,13 +359,7 @@ public: ArchArgs args; Arch(ArchArgs args); - // Get a readwrite proxy to arch - this will keep a readwrite lock on the - // entire architecture until the proxy object goes out of scope. ArchRWProxy rwproxy(void); - // Get a read-only proxy to arch - this will keep a read lock on the - // entire architecture until the proxy object goes out of scope. Other read - // locks can be taken while this one still exists. Ie., the UI can draw - // elements while the PnR is going a RO operation. ArchRProxy rproxy(void) const; std::string getChipName(); @@ -397,9 +378,6 @@ public: /// Wrappers around getting a r(w)proxy and calling a single method. // Deprecated: please acquire a proxy yourself and call the methods // you want on it. - // Warning: these will content with locks taken by the r(w)proxies, and - // thus can cause difficult to debug deadlocks - we'll be getting rid of - // them because of that. void unbindWire(WireId wire); void unbindPip(PipId pip); void unbindBel(BelId bel); @@ -576,7 +554,6 @@ public: // ------------------------------------------------- - // TODO(q3k) move this to archproxies? GroupId getGroupByName(IdString name) const; IdString getGroupName(GroupId group) const; std::vector getGroups() const; @@ -587,8 +564,6 @@ public: // ------------------------------------------------- - // These are also specific to the chip and not state, so they're available - // on arch directly. void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; delay_t estimateDelay(WireId src, WireId dst) const; delay_t getDelayEpsilon() const { return 20; } @@ -633,9 +608,7 @@ public: IdString id_dff_en, id_neg_clk; }; -// Read-only methods on Arch that require state access. class ArchRProxyMethods { - // We let proxy objects access our private constructors. friend class ArchRProxy; friend class ArchRWProxy; private: @@ -668,6 +641,7 @@ public: WireId getWireBelPin(BelId bel, PortPin pin) const; PipId getPipByName(IdString name) const; + IdString getConflictingWireNet(WireId wire) const; IdString getConflictingPipNet(PipId pip) const; IdString getConflictingBelCell(BelId bel) const; @@ -679,8 +653,6 @@ public: BelId getBelByName(IdString name) const; }; -// A proxy object that keeps an Arch shared/readonly lock until it goes out -// of scope. All const/read-only ArchRProxyMethods are available on it. class ArchRProxy : public ArchRProxyMethods { friend class Arch; friend class ArchRWProxy; @@ -703,9 +675,7 @@ public: } }; -// State mutating methods on Arch. class ArchRWProxyMethods { - // We let proxy objects access our private constructors. friend class ArchRWProxy; private: Arch *parent_; @@ -721,12 +691,9 @@ public: void bindWire(WireId wire, IdString net, PlaceStrength strength); void bindPip(PipId pip, IdString net, PlaceStrength strength); void bindBel(BelId bel, IdString cell, PlaceStrength strength); - // Returned pointer is valid as long as Proxy object exists. CellInfo *getCell(IdString cell); }; -// A proxy object that keeps an Arch readwrite lock until it goes out of scope. -// All ArchRProxyMethods and ArchRWProxyMethods are available on it. class ArchRWProxy : public ArchRProxyMethods, public ArchRWProxyMethods { friend class Arch; private: -- cgit v1.2.3 From 447ed83638ef35967adae801430f24e92acb6010 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:52:56 +0100 Subject: Revert "Introduce proxies for locked access to ctx" This reverts commit 89809a8b810dd57f50f365d70a0ce547705f8dbb. --- common/place_common.cc | 95 +++++++++-- common/place_common.h | 83 +--------- common/placer1.cc | 181 ++++++++++----------- common/router1.cc | 108 ++++++------- ice40/arch.cc | 368 ++++++++----------------------------------- ice40/arch.h | 402 ++++++++++++++++++++++++++++++----------------- ice40/arch_place.cc | 75 +++++---- ice40/place_legaliser.cc | 73 ++++----- 8 files changed, 607 insertions(+), 778 deletions(-) diff --git a/common/place_common.cc b/common/place_common.cc index 48416370..281e40a2 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -2,7 +2,6 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 David Shah - * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,8 +24,84 @@ NEXTPNR_NAMESPACE_BEGIN +// Get the total estimated wirelength for a net +wirelen_t get_net_wirelength(const Context *ctx, const NetInfo *net, float &tns) +{ + wirelen_t wirelength = 0; + int driver_x, driver_y; + bool driver_gb; + CellInfo *driver_cell = net->driver.cell; + if (!driver_cell) + return 0; + if (driver_cell->bel == BelId()) + return 0; + ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb); + WireId drv_wire = ctx->getWireBelPinUnlocked(driver_cell->bel, ctx->portPinFromId(net->driver.port)); + if (driver_gb) + return 0; + float worst_slack = 1000; + int xmin = driver_x, xmax = driver_x, ymin = driver_y, ymax = driver_y; + for (auto load : net->users) { + if (load.cell == nullptr) + continue; + CellInfo *load_cell = load.cell; + if (load_cell->bel == BelId()) + continue; + if (ctx->timing_driven) { + WireId user_wire = ctx->getWireBelPinUnlocked(load_cell->bel, ctx->portPinFromId(load.port)); + delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); + float slack = ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl); + if (slack < 0) + tns += slack; + worst_slack = std::min(slack, worst_slack); + } + + int load_x, load_y; + bool load_gb; + ctx->estimatePosition(load_cell->bel, load_x, load_y, load_gb); + if (load_gb) + continue; + xmin = std::min(xmin, load_x); + ymin = std::min(ymin, load_y); + xmax = std::max(xmax, load_x); + ymax = std::max(ymax, load_y); + } + if (ctx->timing_driven) { + wirelength = wirelen_t((((ymax - ymin) + (xmax - xmin)) * std::min(5.0, (1.0 + std::exp(-worst_slack / 5))))); + } else { + wirelength = wirelen_t((ymax - ymin) + (xmax - xmin)); + } + + return wirelength; +} + +// Get the total wirelength for a cell +wirelen_t get_cell_wirelength(const Context *ctx, const CellInfo *cell) +{ + std::set nets; + for (auto p : cell->ports) { + if (p.second.net) + nets.insert(p.second.net->name); + } + wirelen_t wirelength = 0; + float tns = 0; + for (auto n : nets) { + wirelength += get_net_wirelength(ctx, ctx->nets.at(n).get(), tns); + } + return wirelength; +} + +wirelen_t get_cell_wirelength_at_bel(const Context *ctx, CellInfo *cell, BelId bel) +{ + BelId oldBel = cell->bel; + cell->bel = bel; + wirelen_t wirelen = get_cell_wirelength(ctx, cell); + cell->bel = oldBel; + return wirelen; +} + // Placing a single cell -bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool require_legality) +bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality) { bool all_placed = false; int iters = 25; @@ -37,13 +112,13 @@ bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool re CellInfo *ripup_target = nullptr; BelId ripup_bel = BelId(); if (cell->bel != BelId()) { - proxy.unbindBel(cell->bel); + ctx->unbindBelUnlocked(cell->bel); } BelType targetType = ctx->belTypeFromId(cell->type); for (auto bel : ctx->getBels()) { - if (ctx->getBelType(bel) == targetType && (!require_legality || proxy.isValidBelForCell(cell, bel))) { - if (proxy.checkBelAvail(bel)) { - wirelen_t wirelen = get_cell_wirelength_at_bel(proxy, ctx, cell, bel); + if (ctx->getBelType(bel) == targetType && (!require_legality || ctx->isValidBelForCell(cell, bel))) { + if (ctx->checkBelAvailUnlocked(bel)) { + wirelen_t wirelen = get_cell_wirelength_at_bel(ctx, cell, bel); if (iters >= 4) wirelen += ctx->rng(25); if (wirelen <= best_wirelen) { @@ -51,11 +126,11 @@ bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool re best_bel = bel; } } else { - wirelen_t wirelen = get_cell_wirelength_at_bel(proxy, ctx, cell, bel); + wirelen_t wirelen = get_cell_wirelength_at_bel(ctx, cell, bel); if (iters >= 4) wirelen += ctx->rng(25); if (wirelen <= best_ripup_wirelen) { - ripup_target = proxy.getCell(proxy.getBoundBelCell(bel)); + ripup_target = ctx->cells.at(ctx->getBoundBelCellUnlocked(bel)).get(); if (ripup_target->belStrength < STRENGTH_STRONG) { best_ripup_wirelen = wirelen; ripup_bel = bel; @@ -73,12 +148,12 @@ bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool re log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx)); } --iters; - proxy.unbindBel(ripup_target->bel); + ctx->unbindBelUnlocked(ripup_target->bel); best_bel = ripup_bel; } else { all_placed = true; } - proxy.bindBel(best_bel, cell->name, STRENGTH_WEAK); + ctx->bindBelUnlocked(best_bel, cell->name, STRENGTH_WEAK); cell = ripup_target; } diff --git a/common/place_common.h b/common/place_common.h index 57e82510..67956072 100644 --- a/common/place_common.h +++ b/common/place_common.h @@ -22,94 +22,21 @@ #include "nextpnr.h" -#include - NEXTPNR_NAMESPACE_BEGIN typedef int64_t wirelen_t; -// Get the total estimated wirelength for a net -template -wirelen_t get_net_wirelength(const T &proxy, const Context *ctx, const NetInfo *net, float &tns) -{ - wirelen_t wirelength = 0; - int driver_x, driver_y; - bool driver_gb; - CellInfo *driver_cell = net->driver.cell; - if (!driver_cell) - return 0; - if (driver_cell->bel == BelId()) - return 0; - ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb); - WireId drv_wire = proxy.getWireBelPin(driver_cell->bel, ctx->portPinFromId(net->driver.port)); - if (driver_gb) - return 0; - float worst_slack = 1000; - int xmin = driver_x, xmax = driver_x, ymin = driver_y, ymax = driver_y; - for (auto load : net->users) { - if (load.cell == nullptr) - continue; - CellInfo *load_cell = load.cell; - if (load_cell->bel == BelId()) - continue; - if (ctx->timing_driven) { - WireId user_wire = proxy.getWireBelPin(load_cell->bel, ctx->portPinFromId(load.port)); - delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); - float slack = ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl); - if (slack < 0) - tns += slack; - worst_slack = std::min(slack, worst_slack); - } - - int load_x, load_y; - bool load_gb; - ctx->estimatePosition(load_cell->bel, load_x, load_y, load_gb); - if (load_gb) - continue; - xmin = std::min(xmin, load_x); - ymin = std::min(ymin, load_y); - xmax = std::max(xmax, load_x); - ymax = std::max(ymax, load_y); - } - if (ctx->timing_driven) { - wirelength = wirelen_t((((ymax - ymin) + (xmax - xmin)) * std::min(5.0, (1.0 + std::exp(-worst_slack / 5))))); - } else { - wirelength = wirelen_t((ymax - ymin) + (xmax - xmin)); - } - - return wirelength; -} +// Return the wirelength of a net +wirelen_t get_net_wirelength(const Context *ctx, const NetInfo *net, float &tns); // Return the wirelength of all nets connected to a cell -template -wirelen_t get_cell_wirelength(const T &proxy, const Context *ctx, const CellInfo *cell) -{ - std::set nets; - for (auto p : cell->ports) { - if (p.second.net) - nets.insert(p.second.net->name); - } - wirelen_t wirelength = 0; - float tns = 0; - for (auto n : nets) { - wirelength += get_net_wirelength(proxy, ctx, ctx->nets.at(n).get(), tns); - } - return wirelength; -} +wirelen_t get_cell_wirelength(const Context *ctx, const CellInfo *cell); // Return the wirelength of all nets connected to a cell, when the cell is at a given bel -template -wirelen_t get_cell_wirelength_at_bel(const T &proxy, const Context *ctx, CellInfo *cell, BelId bel) -{ - BelId oldBel = cell->bel; - cell->bel = bel; - wirelen_t wirelen = get_cell_wirelength(proxy, ctx, cell); - cell->bel = oldBel; - return wirelen; -} +wirelen_t get_cell_wirelength_at_bel(const Context *ctx, CellInfo *cell, BelId bel); // Place a single cell in the lowest wirelength Bel available, optionally requiring validity check -bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool require_legality); +bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality); NEXTPNR_NAMESPACE_END diff --git a/common/placer1.cc b/common/placer1.cc index 0e3a84f7..05f760a3 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -3,7 +3,6 @@ * * Copyright (C) 2018 Clifford Wolf * Copyright (C) 2018 David Shah - * Copyright (C) 2018 Serge Bazanski * * Simulated annealing implementation based on arachne-pnr * Copyright (C) 2015-2018 Cotton Seed @@ -80,33 +79,30 @@ class SAPlacer log_break(); size_t placed_cells = 0; - { - auto &&proxy = ctx->rwproxy(); - // Initial constraints placer - for (auto &cell_entry : ctx->cells) { - CellInfo *cell = cell_entry.second.get(); - auto loc = cell->attrs.find(ctx->id("BEL")); - if (loc != cell->attrs.end()) { - std::string loc_name = loc->second; - BelId bel = proxy.getBelByName(ctx->id(loc_name)); - if (bel == BelId()) { - log_error("No Bel named \'%s\' located for " - "this chip (processing BEL attribute on \'%s\')\n", - loc_name.c_str(), cell->name.c_str(ctx)); - } - - BelType bel_type = ctx->getBelType(bel); - if (bel_type != ctx->belTypeFromId(cell->type)) { - log_error("Bel \'%s\' of type \'%s\' does not match cell " - "\'%s\' of type \'%s\'", - loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(ctx), cell->name.c_str(ctx), - cell->type.c_str(ctx)); - } + // Initial constraints placer + for (auto &cell_entry : ctx->cells) { + CellInfo *cell = cell_entry.second.get(); + auto loc = cell->attrs.find(ctx->id("BEL")); + if (loc != cell->attrs.end()) { + std::string loc_name = loc->second; + BelId bel = ctx->getBelByNameUnlocked(ctx->id(loc_name)); + if (bel == BelId()) { + log_error("No Bel named \'%s\' located for " + "this chip (processing BEL attribute on \'%s\')\n", + loc_name.c_str(), cell->name.c_str(ctx)); + } - proxy.bindBel(bel, cell->name, STRENGTH_USER); - locked_bels.insert(bel); - placed_cells++; + BelType bel_type = ctx->getBelType(bel); + if (bel_type != ctx->belTypeFromId(cell->type)) { + log_error("Bel \'%s\' of type \'%s\' does not match cell " + "\'%s\' of type \'%s\'", + loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(ctx), cell->name.c_str(ctx), + cell->type.c_str(ctx)); } + + ctx->bindBelUnlocked(bel, cell->name, STRENGTH_USER); + locked_bels.insert(bel); + placed_cells++; } } int constr_placed_cells = placed_cells; @@ -126,15 +122,12 @@ class SAPlacer // Place cells randomly initially log_info("Creating initial placement for remaining %d cells.\n", int(autoplaced.size())); - { - auto &&proxy = ctx->rwproxy(); - for (auto cell : autoplaced) { - place_initial(proxy, cell); - placed_cells++; - if ((placed_cells - constr_placed_cells) % 500 == 0) - log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells), - int(autoplaced.size())); - } + for (auto cell : autoplaced) { + place_initial(cell); + placed_cells++; + if ((placed_cells - constr_placed_cells) % 500 == 0) + log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells), + int(autoplaced.size())); } if ((placed_cells - constr_placed_cells) % 500 != 0) log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells), @@ -145,13 +138,10 @@ class SAPlacer // Calculate wirelength after initial placement curr_wirelength = 0; curr_tns = 0; - { - auto &&proxy = ctx->rproxy(); - for (auto &net : ctx->nets) { - wirelen_t wl = get_net_wirelength(proxy, ctx, net.second.get(), curr_tns); - wirelengths[net.first] = wl; - curr_wirelength += wl; - } + for (auto &net : ctx->nets) { + wirelen_t wl = get_net_wirelength(ctx, net.second.get(), curr_tns); + wirelengths[net.first] = wl; + curr_wirelength += wl; } int n_no_progress = 0; @@ -168,18 +158,15 @@ class SAPlacer "%.0f, est tns = %.02fns\n", iter, temp, double(curr_wirelength), curr_tns); - { - auto &&proxy = ctx->rwproxy(); - for (int m = 0; m < 15; ++m) { - // Loop through all automatically placed cells - for (auto cell : autoplaced) { - // Find another random Bel for this cell - BelId try_bel = random_bel_for_cell(cell); - // If valid, try and swap to a new position and see if - // the new position is valid/worthwhile - if (try_bel != BelId() && try_bel != cell->bel) - try_swap_position(proxy, cell, try_bel); - } + for (int m = 0; m < 15; ++m) { + // Loop through all automatically placed cells + for (auto cell : autoplaced) { + // Find another random Bel for this cell + BelId try_bel = random_bel_for_cell(cell); + // If valid, try and swap to a new position and see if + // the new position is valid/worthwhile + if (try_bel != BelId() && try_bel != cell->bel) + try_swap_position(cell, try_bel); } } // Heuristic to improve placement on the 8k @@ -240,33 +227,27 @@ class SAPlacer // accumulating over time curr_wirelength = 0; curr_tns = 0; - { - auto &&proxy = ctx->rproxy(); - for (auto &net : ctx->nets) { - wirelen_t wl = get_net_wirelength(proxy, ctx, net.second.get(), curr_tns); - wirelengths[net.first] = wl; - curr_wirelength += wl; - } + for (auto &net : ctx->nets) { + wirelen_t wl = get_net_wirelength(ctx, net.second.get(), curr_tns); + wirelengths[net.first] = wl; + curr_wirelength += wl; } } - { - // Final post-pacement validitiy check - auto &&proxy = ctx->rproxy(); - for (auto bel : ctx->getBels()) { - IdString cell = proxy.getBoundBelCell(bel); - if (!proxy.isBelLocationValid(bel)) { - std::string cell_text = "no cell"; - if (cell != IdString()) - cell_text = std::string("cell '") + cell.str(ctx) + "'"; - if (ctx->force) { - log_warning("post-placement validity check failed for Bel '%s' " - "(%s)\n", - ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); - } else { - log_error("post-placement validity check failed for Bel '%s' " - "(%s)\n", - ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); - } + // Final post-pacement validitiy check + for (auto bel : ctx->getBels()) { + IdString cell = ctx->getBoundBelCellUnlocked(bel); + if (!ctx->isBelLocationValid(bel)) { + std::string cell_text = "no cell"; + if (cell != IdString()) + cell_text = std::string("cell '") + cell.str(ctx) + "'"; + if (ctx->force) { + log_warning("post-placement validity check failed for Bel '%s' " + "(%s)\n", + ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); + } else { + log_error("post-placement validity check failed for Bel '%s' " + "(%s)\n", + ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); } } } @@ -275,7 +256,7 @@ class SAPlacer private: // Initial random placement - void place_initial(ArchRWProxy &proxy, CellInfo *cell) + void place_initial(CellInfo *cell) { bool all_placed = false; int iters = 25; @@ -286,12 +267,12 @@ class SAPlacer CellInfo *ripup_target = nullptr; BelId ripup_bel = BelId(); if (cell->bel != BelId()) { - proxy.unbindBel(cell->bel); + ctx->unbindBelUnlocked(cell->bel); } BelType targetType = ctx->belTypeFromId(cell->type); for (auto bel : ctx->getBels()) { - if (ctx->getBelType(bel) == targetType && (proxy.isValidBelForCell(cell, bel) || !require_legal)) { - if (proxy.checkBelAvail(bel)) { + if (ctx->getBelType(bel) == targetType && (ctx->isValidBelForCell(cell, bel) || !require_legal)) { + if (ctx->checkBelAvailUnlocked(bel)) { uint64_t score = ctx->rng64(); if (score <= best_score) { best_score = score; @@ -301,7 +282,7 @@ class SAPlacer uint64_t score = ctx->rng64(); if (score <= best_ripup_score) { best_ripup_score = score; - ripup_target = ctx->cells.at(proxy.getBoundBelCell(bel)).get(); + ripup_target = ctx->cells.at(ctx->getBoundBelCellUnlocked(bel)).get(); ripup_bel = bel; } } @@ -311,12 +292,12 @@ class SAPlacer if (iters == 0 || ripup_bel == BelId()) log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx)); --iters; - proxy.unbindBel(ripup_target->bel); + ctx->unbindBelUnlocked(ripup_target->bel); best_bel = ripup_bel; } else { all_placed = true; } - proxy.bindBel(best_bel, cell->name, STRENGTH_WEAK); + ctx->bindBelUnlocked(best_bel, cell->name, STRENGTH_WEAK); // Back annotate location cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx); @@ -325,14 +306,14 @@ class SAPlacer } // Attempt a SA position swap, return true on success or false on failure - bool try_swap_position(ArchRWProxy &proxy, CellInfo *cell, BelId newBel) + bool try_swap_position(CellInfo *cell, BelId newBel) { static std::unordered_set update; static std::vector> new_lengths; new_lengths.clear(); update.clear(); BelId oldBel = cell->bel; - IdString other = proxy.getBoundBelCell(newBel); + IdString other = ctx->getBoundBelCellUnlocked(newBel); CellInfo *other_cell = nullptr; if (other != IdString()) { other_cell = ctx->cells[other].get(); @@ -340,9 +321,9 @@ class SAPlacer return false; } wirelen_t new_wirelength = 0, delta; - proxy.unbindBel(oldBel); + ctx->unbindBelUnlocked(oldBel); if (other != IdString()) { - proxy.unbindBel(newBel); + ctx->unbindBelUnlocked(newBel); } for (const auto &port : cell->ports) @@ -355,16 +336,16 @@ class SAPlacer update.insert(port.second.net); } - proxy.bindBel(newBel, cell->name, STRENGTH_WEAK); + ctx->bindBelUnlocked(newBel, cell->name, STRENGTH_WEAK); if (other != IdString()) { - proxy.bindBel(oldBel, other_cell->name, STRENGTH_WEAK); + ctx->bindBelUnlocked(oldBel, other_cell->name, STRENGTH_WEAK); } if (require_legal) { - if (!proxy.isBelLocationValid(newBel) || ((other != IdString() && !proxy.isBelLocationValid(oldBel)))) { - proxy.unbindBel(newBel); + if (!ctx->isBelLocationValid(newBel) || ((other != IdString() && !ctx->isBelLocationValid(oldBel)))) { + ctx->unbindBelUnlocked(newBel); if (other != IdString()) - proxy.unbindBel(oldBel); + ctx->unbindBelUnlocked(oldBel); goto swap_fail; } } @@ -375,7 +356,7 @@ class SAPlacer for (auto net : update) { new_wirelength -= wirelengths.at(net->name); float temp_tns = 0; - wirelen_t net_new_wl = get_net_wirelength<>(proxy, ctx, net, temp_tns); + wirelen_t net_new_wl = get_net_wirelength(ctx, net, temp_tns); new_wirelength += net_new_wl; new_lengths.push_back(std::make_pair(net->name, net_new_wl)); } @@ -388,8 +369,8 @@ class SAPlacer improved = true; } else { if (other != IdString()) - proxy.unbindBel(oldBel); - proxy.unbindBel(newBel); + ctx->unbindBelUnlocked(oldBel); + ctx->unbindBelUnlocked(newBel); goto swap_fail; } curr_wirelength = new_wirelength; @@ -398,9 +379,9 @@ class SAPlacer return true; swap_fail: - proxy.bindBel(oldBel, cell->name, STRENGTH_WEAK); + ctx->bindBelUnlocked(oldBel, cell->name, STRENGTH_WEAK); if (other != IdString()) { - proxy.bindBel(newBel, other, STRENGTH_WEAK); + ctx->bindBelUnlocked(newBel, other, STRENGTH_WEAK); } return false; } diff --git a/common/router1.cc b/common/router1.cc index 0d26a36d..cbaf773d 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -2,7 +2,6 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf - * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -74,7 +73,7 @@ struct RipupScoreboard std::unordered_map, int, hash_id_pip> netPipScores; }; -void ripup_net(ArchRWProxy &proxy, Context *ctx, IdString net_name) +void ripup_net(Context *ctx, IdString net_name) { auto net_info = ctx->nets.at(net_name).get(); std::vector pips; @@ -91,10 +90,10 @@ void ripup_net(ArchRWProxy &proxy, Context *ctx, IdString net_name) } for (auto pip : pips) - proxy.unbindPip(pip); + ctx->unbindPipUnlocked(pip); for (auto wire : wires) - proxy.unbindWire(wire); + ctx->unbindWireUnlocked(wire); NPNR_ASSERT(net_info->wires.empty()); } @@ -115,7 +114,7 @@ struct Router delay_t maxDelay = 0.0; WireId failedDest; - void route(ArchRWProxy &proxy, const std::unordered_map &src_wires, WireId dst_wire) + void route(const std::unordered_map &src_wires, WireId dst_wire) { std::priority_queue, QueuedWire::Greater> queue; @@ -136,7 +135,6 @@ struct Router int thisVisitCnt = 0; int thisVisitCntLimit = 0; - while (!queue.empty() && (thisVisitCntLimit == 0 || thisVisitCnt < thisVisitCntLimit)) { QueuedWire qw = queue.top(); queue.pop(); @@ -150,10 +148,10 @@ struct Router bool foundRipupNet = false; thisVisitCnt++; - if (!proxy.checkWireAvail(next_wire)) { + if (!ctx->checkWireAvailUnlocked(next_wire)) { if (!ripup) continue; - IdString ripupWireNet = proxy.getConflictingWireNet(next_wire); + IdString ripupWireNet = ctx->getConflictingWireNetUnlocked(next_wire); if (ripupWireNet == net_name || ripupWireNet == IdString()) continue; @@ -168,10 +166,10 @@ struct Router foundRipupNet = true; } - if (!proxy.checkPipAvail(pip)) { + if (!ctx->checkPipAvailUnlocked(pip)) { if (!ripup) continue; - IdString ripupPipNet = proxy.getConflictingPipNet(pip); + IdString ripupPipNet = ctx->getConflictingPipNetUnlocked(pip); if (ripupPipNet == net_name || ripupPipNet == IdString()) continue; @@ -229,10 +227,7 @@ struct Router { std::unordered_map src_wires; src_wires[src_wire] = 0; - { - auto &&proxy = ctx->rwproxy(); - route(proxy, src_wires, dst_wire); - } + route(src_wires, dst_wire); routedOkay = visited.count(dst_wire); if (ctx->debug) { @@ -277,7 +272,7 @@ struct Router if (driver_port_it != net_info->driver.cell->pins.end()) driver_port = driver_port_it->second; - auto src_wire = ctx->rproxy().getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getWireBelPinUnlocked(src_bel, ctx->portPinFromId(driver_port)); if (src_wire == WireId()) log_error("No wire found for port %s (pin %s) on source cell %s " @@ -291,10 +286,8 @@ struct Router std::unordered_map src_wires; src_wires[src_wire] = 0; - auto &&proxy = ctx->rwproxy(); - - ripup_net(proxy, ctx, net_name); - proxy.bindWire(src_wire, net_name, STRENGTH_WEAK); + ripup_net(ctx, net_name); + ctx->bindWireUnlocked(src_wire, net_name, STRENGTH_WEAK); std::vector users_array = net_info->users; ctx->shuffle(users_array); @@ -319,7 +312,7 @@ struct Router if (user_port_it != user_it.cell->pins.end()) user_port = user_port_it->second; - auto dst_wire = proxy.getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getWireBelPinUnlocked(dst_bel, ctx->portPinFromId(user_port)); if (dst_wire == WireId()) log_error("No wire found for port %s (pin %s) on destination " @@ -332,7 +325,7 @@ struct Router log(" Path delay estimate: %.2f\n", float(ctx->estimateDelay(src_wire, dst_wire))); } - route(proxy, src_wires, dst_wire); + route(src_wires, dst_wire); if (visited.count(dst_wire) == 0) { if (ctx->debug) @@ -341,7 +334,7 @@ struct Router else if (ripup) log_info("Failed to route %s -> %s.\n", ctx->getWireName(src_wire).c_str(ctx), ctx->getWireName(dst_wire).c_str(ctx)); - ripup_net(proxy, ctx, net_name); + ripup_net(ctx, net_name); failedDest = dst_wire; return; } @@ -362,15 +355,15 @@ struct Router if (src_wires.count(cursor)) break; - IdString conflicting_wire_net = proxy.getConflictingWireNet(cursor); + IdString conflicting_wire_net = ctx->getConflictingWireNetUnlocked(cursor); if (conflicting_wire_net != IdString()) { NPNR_ASSERT(ripup); NPNR_ASSERT(conflicting_wire_net != net_name); - proxy.unbindWire(cursor); - if (!proxy.checkWireAvail(cursor)) - ripup_net(proxy, ctx, conflicting_wire_net); + ctx->unbindWireUnlocked(cursor); + if (!ctx->checkWireAvailUnlocked(cursor)) + ripup_net(ctx, conflicting_wire_net); rippedNets.insert(conflicting_wire_net); scores.wireScores[cursor]++; @@ -379,15 +372,15 @@ struct Router } PipId pip = visited[cursor].pip; - IdString conflicting_pip_net = proxy.getConflictingPipNet(pip); + IdString conflicting_pip_net = ctx->getConflictingPipNetUnlocked(pip); if (conflicting_pip_net != IdString()) { NPNR_ASSERT(ripup); NPNR_ASSERT(conflicting_pip_net != net_name); - proxy.unbindPip(pip); - if (!proxy.checkPipAvail(pip)) - ripup_net(proxy, ctx, conflicting_pip_net); + ctx->unbindPipUnlocked(pip); + if (!ctx->checkPipAvailUnlocked(pip)) + ripup_net(ctx, conflicting_pip_net); rippedNets.insert(conflicting_pip_net); scores.pipScores[visited[cursor].pip]++; @@ -395,7 +388,7 @@ struct Router scores.netPipScores[std::make_pair(conflicting_pip_net, visited[cursor].pip)]++; } - proxy.bindPip(visited[cursor].pip, net_name, STRENGTH_WEAK); + ctx->bindPipUnlocked(visited[cursor].pip, net_name, STRENGTH_WEAK); src_wires[cursor] = visited[cursor].delay; cursor = ctx->getPipSrcWire(visited[cursor].pip); } @@ -444,48 +437,45 @@ bool router1(Context *ctx) delay_t estimatedTotalDelay = 0.0; int estimatedTotalDelayCnt = 0; - { - auto &&proxy = ctx->rproxy(); - for (auto net_name : netsQueue) { - auto net_info = ctx->nets.at(net_name).get(); + for (auto net_name : netsQueue) { + auto net_info = ctx->nets.at(net_name).get(); - auto src_bel = net_info->driver.cell->bel; + auto src_bel = net_info->driver.cell->bel; - if (src_bel == BelId()) - continue; + if (src_bel == BelId()) + continue; - IdString driver_port = net_info->driver.port; + IdString driver_port = net_info->driver.port; - auto driver_port_it = net_info->driver.cell->pins.find(driver_port); - if (driver_port_it != net_info->driver.cell->pins.end()) - driver_port = driver_port_it->second; + auto driver_port_it = net_info->driver.cell->pins.find(driver_port); + if (driver_port_it != net_info->driver.cell->pins.end()) + driver_port = driver_port_it->second; - auto src_wire = proxy.getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getWireBelPinUnlocked(src_bel, ctx->portPinFromId(driver_port)); - if (src_wire == WireId()) - continue; + if (src_wire == WireId()) + continue; - for (auto &user_it : net_info->users) { - auto dst_bel = user_it.cell->bel; + for (auto &user_it : net_info->users) { + auto dst_bel = user_it.cell->bel; - if (dst_bel == BelId()) - continue; + if (dst_bel == BelId()) + continue; - IdString user_port = user_it.port; + IdString user_port = user_it.port; - auto user_port_it = user_it.cell->pins.find(user_port); + auto user_port_it = user_it.cell->pins.find(user_port); - if (user_port_it != user_it.cell->pins.end()) - user_port = user_port_it->second; + if (user_port_it != user_it.cell->pins.end()) + user_port = user_port_it->second; - auto dst_wire = proxy.getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getWireBelPinUnlocked(dst_bel, ctx->portPinFromId(user_port)); - if (dst_wire == WireId()) - continue; + if (dst_wire == WireId()) + continue; - estimatedTotalDelay += ctx->estimateDelay(src_wire, dst_wire); - estimatedTotalDelayCnt++; - } + estimatedTotalDelay += ctx->estimateDelay(src_wire, dst_wire); + estimatedTotalDelayCnt++; } } diff --git a/ice40/arch.cc b/ice40/arch.cc index af31e147..30eea776 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -2,7 +2,6 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf - * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -29,16 +28,6 @@ NEXTPNR_NAMESPACE_BEGIN -ArchRWProxy Arch::rwproxy(void) { - ArchRWProxy res(this); - return res; -} - -ArchRProxy Arch::rproxy(void) const { - ArchRProxy res(this); - return res; -} - // ----------------------------------------------------------------------- IdString Arch::belTypeToId(BelType type) const @@ -250,6 +239,28 @@ IdString Arch::archArgsToId(ArchArgs args) const // ----------------------------------------------------------------------- +BelId Arch::getBelByName(IdString name) const +{ + boost::lock_guard lock(mtx_); + return getBelByNameUnlocked(name); +} + +BelId Arch::getBelByNameUnlocked(IdString name) const +{ + BelId ret; + + if (bel_by_name.empty()) { + for (int i = 0; i < chip_info->num_bels; i++) + bel_by_name[id(chip_info->bel_data[i].name.get())] = i; + } + + auto it = bel_by_name.find(name); + if (it != bel_by_name.end()) + ret.index = it->second; + + return ret; +} + BelRange Arch::getBelsAtSameTile(BelId bel) const { BelRange br; @@ -268,105 +279,81 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const return br; } -// ----------------------------------------------------------------------- -// Shorthands to ArchProxy - -BelId Arch::getBelByName(IdString name) const -{ - return rproxy().getBelByName(name); -} - -void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength) +WireId Arch::getWireBelPin(BelId bel, PortPin pin) const { - rwproxy().bindWire(wire, net, strength); + boost::shared_lock_guard lock(mtx_); + return getWireBelPinUnlocked(bel, pin); } -void Arch::unbindWire(WireId wire) +WireId Arch::getWireBelPinUnlocked(BelId bel, PortPin pin) const { - rwproxy().unbindWire(wire); -} + WireId ret; -void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength) { - rwproxy().bindBel(bel, cell, strength); -} + NPNR_ASSERT(bel != BelId()); -void Arch::unbindBel(BelId bel) -{ - rwproxy().unbindBel(bel); -} + int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); -bool Arch::checkBelAvail(BelId bel) const -{ - return rproxy().checkBelAvail(bel); -} + for (int i = 0; i < num_bel_wires; i++) + if (bel_wires[i].port == pin) { + ret.index = bel_wires[i].wire_index; + break; + } -IdString Arch::getBoundBelCell(BelId bel) const -{ - return rproxy().getBoundBelCell(bel); + return ret; } -IdString Arch::getConflictingBelCell(BelId bel) const -{ - return rproxy().getConflictingBelCell(bel); -} +// ----------------------------------------------------------------------- WireId Arch::getWireByName(IdString name) const { - return rproxy().getWireByName(name); + boost::shared_lock_guard lock(mtx_); + return getWireByNameUnlocked(name); } -WireId Arch::getWireBelPin(BelId bel, PortPin pin) const +WireId Arch::getWireByNameUnlocked(IdString name) const { - return rproxy().getWireBelPin(bel, pin); -} + WireId ret; -bool Arch::checkWireAvail(WireId wire) const -{ - return rproxy().checkWireAvail(wire); -} + if (wire_by_name.empty()) { + for (int i = 0; i < chip_info->num_wires; i++) + wire_by_name[id(chip_info->wire_data[i].name.get())] = i; + } -IdString Arch::getBoundWireNet(WireId wire) const -{ - return rproxy().getBoundWireNet(wire); -} + auto it = wire_by_name.find(name); + if (it != wire_by_name.end()) + ret.index = it->second; -IdString Arch::getConflictingWireNet(WireId wire) const -{ - return rproxy().getConflictingWireNet(wire); + return ret; } -PipId Arch::getPipByName(IdString name) const -{ - return rproxy().getPipByName(name); -} +// ----------------------------------------------------------------------- -void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength) +PipId Arch::getPipByName(IdString name) const { - return rwproxy().bindPip(pip, net, strength); + boost::shared_lock_guard lock(mtx_); + return getPipByNameUnlocked(name); } -void Arch::unbindPip(PipId pip) +PipId Arch::getPipByNameUnlocked(IdString name) const { - return rwproxy().unbindPip(pip); -} + PipId ret; -bool Arch::checkPipAvail(PipId pip) const -{ - return rproxy().checkPipAvail(pip); -} + if (pip_by_name.empty()) { + for (int i = 0; i < chip_info->num_pips; i++) { + PipId pip; + pip.index = i; + pip_by_name[getPipName(pip)] = i; + } + } -IdString Arch::getBoundPipNet(PipId pip) const -{ - return rproxy().getBoundPipNet(pip); -} + auto it = pip_by_name.find(name); + if (it != pip_by_name.end()) + ret.index = it->second; -IdString Arch::getConflictingPipNet(PipId pip) const -{ - return rproxy().getConflictingPipNet(pip); + return ret; } -// ----------------------------------------------------------------------- - IdString Arch::getPipName(PipId pip) const { NPNR_ASSERT(pip != PipId()); @@ -731,227 +718,4 @@ bool Arch::isGlobalNet(const NetInfo *net) const return net->driver.cell != nullptr && net->driver.port == id_glb_buf_out; } -// ----------------------------------------------------------------------- - -bool ArchRProxyMethods::checkBelAvail(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - return parent_->bel_to_cell[bel.index] == IdString(); -} - -IdString ArchRProxyMethods::getBoundBelCell(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - return parent_->bel_to_cell[bel.index]; -} - -IdString ArchRProxyMethods::getConflictingBelCell(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - return parent_->bel_to_cell[bel.index]; -} - -WireId ArchRProxyMethods::getWireBelPin(BelId bel, PortPin pin) const -{ - WireId ret; - - NPNR_ASSERT(bel != BelId()); - - int num_bel_wires = parent_->chip_info->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = parent_->chip_info->bel_data[bel.index].bel_wires.get(); - - for (int i = 0; i < num_bel_wires; i++) - if (bel_wires[i].port == pin) { - ret.index = bel_wires[i].wire_index; - break; - } - - return ret; -} - -WireId ArchRProxyMethods::getWireByName(IdString name) const -{ - WireId ret; - - if (parent_->wire_by_name.empty()) { - for (int i = 0; i < parent_->chip_info->num_wires; i++) - parent_->wire_by_name[parent_->id(parent_->chip_info->wire_data[i].name.get())] = i; - } - - auto it = parent_->wire_by_name.find(name); - if (it != parent_->wire_by_name.end()) - ret.index = it->second; - - return ret; -} - -bool ArchRProxyMethods::checkWireAvail(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - return parent_->wire_to_net[wire.index] == IdString(); -} - -IdString ArchRProxyMethods::getBoundWireNet(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - return parent_->wire_to_net[wire.index]; -} - -IdString ArchRProxyMethods::getConflictingWireNet(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - return parent_->wire_to_net[wire.index]; -} - -PipId ArchRProxyMethods::getPipByName(IdString name) const -{ - PipId ret; - - if (parent_->pip_by_name.empty()) { - for (int i = 0; i < parent_->chip_info->num_pips; i++) { - PipId pip; - pip.index = i; - parent_->pip_by_name[parent_->getPipName(pip)] = i; - } - } - - auto it = parent_->pip_by_name.find(name); - if (it != parent_->pip_by_name.end()) - ret.index = it->second; - - return ret; -} - -bool ArchRProxyMethods::checkPipAvail(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - return parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] == IdString(); -} - -IdString ArchRProxyMethods::getBoundPipNet(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - return parent_->pip_to_net[pip.index]; -} - -IdString ArchRProxyMethods::getConflictingPipNet(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - return parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index]; -} - -BelId ArchRProxyMethods::getBelByName(IdString name) const -{ - BelId ret; - - if (parent_->bel_by_name.empty()) { - for (int i = 0; i < parent_->chip_info->num_bels; i++) - parent_->bel_by_name[parent_->id(parent_->chip_info->bel_data[i].name.get())] = i; - } - - auto it = parent_->bel_by_name.find(name); - if (it != parent_->bel_by_name.end()) - ret.index = it->second; - - return ret; -} - -// ----------------------------------------------------------------------- - -void ArchRWProxyMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) -{ - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(parent_->bel_to_cell[bel.index] == IdString()); - parent_->bel_to_cell[bel.index] = cell; - parent_->cells[cell]->bel = bel; - parent_->cells[cell]->belStrength = strength; - parent_->refreshUiBel(bel); -} - -void ArchRWProxyMethods::unbindBel(BelId bel) -{ - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(parent_->bel_to_cell[bel.index] != IdString()); - parent_->cells[parent_->bel_to_cell[bel.index]]->bel = BelId(); - parent_->cells[parent_->bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; - parent_->bel_to_cell[bel.index] = IdString(); - parent_->refreshUiBel(bel); -} - -void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) -{ - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(parent_->wire_to_net[wire.index] == IdString()); - - parent_->wire_to_net[wire.index] = net; - parent_->nets[net]->wires[wire].pip = PipId(); - parent_->nets[net]->wires[wire].strength = strength; - parent_->refreshUiWire(wire); -} - -void ArchRWProxyMethods::unbindWire(WireId wire) -{ - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(parent_->wire_to_net[wire.index] != IdString()); - - auto &net_wires = parent_->nets[parent_->wire_to_net[wire.index]]->wires; - auto it = net_wires.find(wire); - NPNR_ASSERT(it != net_wires.end()); - - auto pip = it->second.pip; - if (pip != PipId()) { - parent_->pip_to_net[pip.index] = IdString(); - parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString(); - parent_->refreshUiPip(pip); - } - - net_wires.erase(it); - parent_->wire_to_net[wire.index] = IdString(); - parent_->refreshUiWire(wire); -} - -void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) -{ - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(parent_->pip_to_net[pip.index] == IdString()); - NPNR_ASSERT(parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] == IdString()); - - parent_->pip_to_net[pip.index] = net; - parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = net; - - WireId dst; - dst.index = parent_->chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(parent_->wire_to_net[dst.index] == IdString()); - parent_->wire_to_net[dst.index] = net; - parent_->nets[net]->wires[dst].pip = pip; - parent_->nets[net]->wires[dst].strength = strength; - - parent_->refreshUiPip(pip); - parent_->refreshUiWire(dst); -} - -void ArchRWProxyMethods::unbindPip(PipId pip) -{ - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(parent_->pip_to_net[pip.index] != IdString()); - NPNR_ASSERT(parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] != IdString()); - - WireId dst; - dst.index = parent_->chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(parent_->wire_to_net[dst.index] != IdString()); - parent_->wire_to_net[dst.index] = IdString(); - parent_->nets[parent_->pip_to_net[pip.index]]->wires.erase(dst); - - parent_->pip_to_net[pip.index] = IdString(); - parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString(); - - parent_->refreshUiPip(pip); - parent_->refreshUiWire(dst); -} - -CellInfo *ArchRWProxyMethods::getCell(IdString cell) -{ - return parent_->cells.at(cell).get(); -} - NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index 36e34d7b..6f281d4a 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -2,7 +2,6 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf - * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -328,40 +327,27 @@ struct ArchArgs std::string package; }; -class ArchRWProxyMethods; -class ArchRProxyMethods; -class ArchRWProxy; -class ArchRProxy; - class Arch : public BaseCtx { - friend class ArchRWProxyMethods; - friend class ArchRProxyMethods; - friend class ArchRWProxy; - friend class ArchRProxy; private: // All of the following... std::vector bel_to_cell; std::vector wire_to_net; std::vector pip_to_net; std::vector switches_locked; - mutable std::unordered_map bel_by_name; - mutable std::unordered_map wire_by_name; - mutable std::unordered_map pip_by_name; - // ... are guarded by the following lock: mutable boost::shared_mutex mtx_; - public: const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; + mutable std::unordered_map bel_by_name; + mutable std::unordered_map wire_by_name; + mutable std::unordered_map pip_by_name; + ArchArgs args; Arch(ArchArgs args); - ArchRWProxy rwproxy(void); - ArchRProxy rproxy(void) const; - std::string getChipName(); IdString archId() const { return id("ice40"); } @@ -375,33 +361,8 @@ public: // ------------------------------------------------- - /// Wrappers around getting a r(w)proxy and calling a single method. - // Deprecated: please acquire a proxy yourself and call the methods - // you want on it. - void unbindWire(WireId wire); - void unbindPip(PipId pip); - void unbindBel(BelId bel); - void bindWire(WireId wire, IdString net, PlaceStrength strength); - void bindPip(PipId pip, IdString net, PlaceStrength strength); - void bindBel(BelId bel, IdString cell, PlaceStrength strength); - bool checkWireAvail(WireId wire) const; - bool checkPipAvail(PipId pip) const; - bool checkBelAvail(BelId bel) const; - WireId getWireByName(IdString name) const; - WireId getWireBelPin(BelId bel, PortPin pin) const; - PipId getPipByName(IdString name) const; - IdString getConflictingWireNet(WireId wire) const; - IdString getConflictingPipNet(PipId pip) const; - IdString getConflictingBelCell(BelId bel) const; - IdString getBoundWireNet(WireId wire) const; - IdString getBoundPipNet(PipId pip) const; - IdString getBoundBelCell(BelId bel) const; BelId getBelByName(IdString name) const; - - // ------------------------------------------------- - - /// Methods to get chip info - don't need to use a wrapper, as these are - /// static per lifetime of object. + BelId getBelByNameUnlocked(IdString name) const; IdString getBelName(BelId bel) const { @@ -409,9 +370,71 @@ public: return id(chip_info->bel_data[bel.index].name.get()); } - uint32_t getBelChecksum(BelId bel) const + uint32_t getBelChecksum(BelId bel) const { return bel.index; } + + void bindBel(BelId bel, IdString cell, PlaceStrength strength) { + boost::lock_guard lock(mtx_); + bindBelUnlocked(bel, cell, strength); + } + + void bindBelUnlocked(BelId bel, IdString cell, PlaceStrength strength) { - return bel.index; + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); + bel_to_cell[bel.index] = cell; + cells[cell]->bel = bel; + cells[cell]->belStrength = strength; + } + + void unbindBel(BelId bel) + { + boost::lock_guard lock(mtx_); + unbindBelUnlocked(bel); + } + + void unbindBelUnlocked(BelId bel) + { + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); + cells[bel_to_cell[bel.index]]->bel = BelId(); + cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; + bel_to_cell[bel.index] = IdString(); + } + + bool checkBelAvail(BelId bel) const + { + boost::shared_lock_guard lock(mtx_); + return checkBelAvailUnlocked(bel); + } + + bool checkBelAvailUnlocked(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index] == IdString(); + } + + IdString getBoundBelCell(BelId bel) const + { + boost::shared_lock_guard lock(mtx_); + return getBoundBelCellUnlocked(bel); + } + + IdString getBoundBelCellUnlocked(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index]; + } + + IdString getConflictingBelCell(BelId bel) const + { + boost::shared_lock_guard lock(mtx_); + return getConflictingBelCellUnlocked(bel); + } + + IdString getConflictingBelCellUnlocked(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index]; } BelRange getBels() const @@ -444,6 +467,8 @@ public: return chip_info->bel_data[bel.index].type; } + WireId getWireBelPin(BelId bel, PortPin pin) const; + WireId getWireBelPinUnlocked(BelId bel, PortPin pin) const; BelPin getBelPinUphill(WireId wire) const { @@ -469,6 +494,9 @@ public: // ------------------------------------------------- + WireId getWireByName(IdString name) const; + WireId getWireByNameUnlocked(IdString name) const; + IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); @@ -477,6 +505,180 @@ public: uint32_t getWireChecksum(WireId wire) const { return wire.index; } + void bindWire(WireId wire, IdString net, PlaceStrength strength) + { + boost::lock_guard lock(mtx_); + bindWireUnlocked(wire, net, strength); + } + + void bindWireUnlocked(WireId wire, IdString net, PlaceStrength strength) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire.index] == IdString()); + + wire_to_net[wire.index] = net; + nets[net]->wires[wire].pip = PipId(); + nets[net]->wires[wire].strength = strength; + } + + void unbindWire(WireId wire) + { + boost::lock_guard lock(mtx_); + unbindWireUnlocked(wire); + } + + void unbindWireUnlocked(WireId wire) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire.index] != IdString()); + + auto &net_wires = nets[wire_to_net[wire.index]]->wires; + auto it = net_wires.find(wire); + NPNR_ASSERT(it != net_wires.end()); + + auto pip = it->second.pip; + if (pip != PipId()) { + pip_to_net[pip.index] = IdString(); + switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + } + + net_wires.erase(it); + wire_to_net[wire.index] = IdString(); + } + + bool checkWireAvail(WireId wire) const + { + boost::shared_lock_guard lock(mtx_); + return checkWireAvailUnlocked(wire); + } + + bool checkWireAvailUnlocked(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index] == IdString(); + } + + IdString getBoundWireNet(WireId wire) const + { + boost::shared_lock_guard lock(mtx_); + return getBoundWireNetUnlocked(wire); + } + + IdString getBoundWireNetUnlocked(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index]; + } + + IdString getConflictingWireNet(WireId wire) const + { + boost::shared_lock_guard lock(mtx_); + return getConflictingWireNetUnlocked(wire); + } + + IdString getConflictingWireNetUnlocked(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index]; + } + + WireRange getWires() const + { + WireRange range; + range.b.cursor = 0; + range.e.cursor = chip_info->num_wires; + return range; + } + + // ------------------------------------------------- + + PipId getPipByName(IdString name) const; + PipId getPipByNameUnlocked(IdString name) const; + IdString getPipName(PipId pip) const; + + uint32_t getPipChecksum(PipId pip) const { return pip.index; } + + void bindPip(PipId pip, IdString net, PlaceStrength strength) + { + boost::lock_guard lock(mtx_); + bindPipUnlocked(pip, net, strength); + } + + void bindPipUnlocked(PipId pip, IdString net, PlaceStrength strength) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip.index] == IdString()); + NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); + + pip_to_net[pip.index] = net; + switches_locked[chip_info->pip_data[pip.index].switch_index] = net; + + WireId dst; + dst.index = chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(wire_to_net[dst.index] == IdString()); + wire_to_net[dst.index] = net; + nets[net]->wires[dst].pip = pip; + nets[net]->wires[dst].strength = strength; + } + + void unbindPip(PipId pip) + { + boost::lock_guard lock(mtx_); + unbindPipUnlocked(pip); + } + + void unbindPipUnlocked(PipId pip) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip.index] != IdString()); + NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); + + WireId dst; + dst.index = chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(wire_to_net[dst.index] != IdString()); + wire_to_net[dst.index] = IdString(); + nets[pip_to_net[pip.index]]->wires.erase(dst); + + pip_to_net[pip.index] = IdString(); + switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + } + + bool checkPipAvail(PipId pip) const + { + boost::shared_lock_guard lock(mtx_); + return checkPipAvailUnlocked(pip); + } + + bool checkPipAvailUnlocked(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); + } + + IdString getBoundPipNet(PipId pip) const + { + boost::shared_lock_guard lock(mtx_); + return getBoundPipNetUnlocked(pip); + } + + IdString getBoundPipNetUnlocked(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return pip_to_net[pip.index]; + } + + IdString getConflictingPipNet(PipId pip) const + { + boost::shared_lock_guard lock(mtx_); + return getConflictingPipNetUnlocked(pip); + } + + IdString getConflictingPipNetUnlocked(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return switches_locked[chip_info->pip_data[pip.index].switch_index]; + } + AllPipRange getPips() const { AllPipRange range; @@ -601,26 +803,7 @@ public: // ------------------------------------------------- - IdString id_glb_buf_out; - IdString id_icestorm_lc, id_sb_io, id_sb_gb; - IdString id_cen, id_clk, id_sr; - IdString id_i0, id_i1, id_i2, id_i3; - IdString id_dff_en, id_neg_clk; -}; - -class ArchRProxyMethods { - friend class ArchRProxy; - friend class ArchRWProxy; -private: - const Arch *parent_; - ArchRProxyMethods(const Arch *parent) : parent_(parent) {} - ArchRProxyMethods(ArchRProxyMethods &&other) noexcept : parent_(other.parent_) {} - ArchRProxyMethods(const ArchRProxyMethods &other) : parent_(other.parent_) {} - -public: - ~ArchRProxyMethods() noexcept { } - - /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) + // Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) // Whether or not a given cell can be placed at a given Bel // This is not intended for Bel type checks, but finer-grained constraints @@ -633,88 +816,11 @@ public: // Helper function for above bool logicCellsCompatible(const std::vector &cells) const; - bool checkWireAvail(WireId wire) const; - bool checkPipAvail(PipId pip) const; - bool checkBelAvail(BelId bel) const; - - WireId getWireByName(IdString name) const; - WireId getWireBelPin(BelId bel, PortPin pin) const; - PipId getPipByName(IdString name) const; - - - IdString getConflictingWireNet(WireId wire) const; - IdString getConflictingPipNet(PipId pip) const; - IdString getConflictingBelCell(BelId bel) const; - - IdString getBoundWireNet(WireId wire) const; - IdString getBoundPipNet(PipId pip) const; - IdString getBoundBelCell(BelId bel) const; - - BelId getBelByName(IdString name) const; -}; - -class ArchRProxy : public ArchRProxyMethods { - friend class Arch; - friend class ArchRWProxy; -private: - boost::shared_mutex *lock_; - ArchRProxy(const Arch *parent) : ArchRProxyMethods(parent), lock_(&parent->mtx_) - { - lock_->lock_shared(); - } - -public: - ~ArchRProxy() { - if (lock_ != nullptr) { - lock_->unlock_shared(); - } - } - ArchRProxy(ArchRProxy &&other) : ArchRProxyMethods(other), lock_(other.lock_) - { - other.lock_ = nullptr; - } -}; - -class ArchRWProxyMethods { - friend class ArchRWProxy; -private: - Arch *parent_; - ArchRWProxyMethods(Arch *parent) : parent_(parent) {} - ArchRWProxyMethods(ArchRWProxyMethods &&other) : parent_(other.parent_) {} - ArchRWProxyMethods(const ArchRWProxyMethods &other) : parent_(other.parent_) {} -public: - ~ArchRWProxyMethods() {} - - void unbindWire(WireId wire); - void unbindPip(PipId pip); - void unbindBel(BelId bel); - void bindWire(WireId wire, IdString net, PlaceStrength strength); - void bindPip(PipId pip, IdString net, PlaceStrength strength); - void bindBel(BelId bel, IdString cell, PlaceStrength strength); - CellInfo *getCell(IdString cell); -}; - -class ArchRWProxy : public ArchRProxyMethods, public ArchRWProxyMethods { - friend class Arch; -private: - boost::shared_mutex *lock_; - ArchRWProxy(Arch *parent) : ArchRProxyMethods(parent), ArchRWProxyMethods(parent), lock_(&parent->mtx_) { - lock_->lock(); - } - -public: - ArchRWProxy(ArchRWProxy &&other) : ArchRProxyMethods(other), ArchRWProxyMethods(other), lock_(other.lock_) - { - other.lock_ = nullptr; - } - ~ArchRWProxy() - { - if (lock_ != nullptr) { - lock_->unlock(); - } - } - - + IdString id_glb_buf_out; + IdString id_icestorm_lc, id_sb_io, id_sb_gb; + IdString id_cen, id_clk, id_sr; + IdString id_i0, id_i1, id_i2, id_i3; + IdString id_dff_en, id_neg_clk; }; NEXTPNR_NAMESPACE_END diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index cb7c44b8..c9dd26c5 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -3,7 +3,6 @@ * * Copyright (C) 2018 Clifford Wolf * Copyright (C) 2018 David Shah - * Copyright (C) 2018 Serge Bazanski * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,44 +24,44 @@ NEXTPNR_NAMESPACE_BEGIN -bool ArchRProxyMethods::logicCellsCompatible(const std::vector &cells) const +bool Arch::logicCellsCompatible(const std::vector &cells) const { bool dffs_exist = false, dffs_neg = false; const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; int locals_count = 0; for (auto cell : cells) { - if (bool_or_default(cell->params, parent_->id_dff_en)) { + if (bool_or_default(cell->params, id_dff_en)) { if (!dffs_exist) { dffs_exist = true; - cen = get_net_or_empty(cell, parent_->id_cen); - clk = get_net_or_empty(cell, parent_->id_clk); - sr = get_net_or_empty(cell, parent_->id_sr); + cen = get_net_or_empty(cell, id_cen); + clk = get_net_or_empty(cell, id_clk); + sr = get_net_or_empty(cell, id_sr); - if (!parent_->isGlobalNet(cen) && cen != nullptr) + if (!isGlobalNet(cen) && cen != nullptr) locals_count++; - if (!parent_->isGlobalNet(clk) && clk != nullptr) + if (!isGlobalNet(clk) && clk != nullptr) locals_count++; - if (!parent_->isGlobalNet(sr) && sr != nullptr) + if (!isGlobalNet(sr) && sr != nullptr) locals_count++; - if (bool_or_default(cell->params, parent_->id_neg_clk)) { + if (bool_or_default(cell->params, id_neg_clk)) { dffs_neg = true; } } else { - if (cen != get_net_or_empty(cell, parent_->id_cen)) + if (cen != get_net_or_empty(cell, id_cen)) return false; - if (clk != get_net_or_empty(cell, parent_->id_clk)) + if (clk != get_net_or_empty(cell, id_clk)) return false; - if (sr != get_net_or_empty(cell, parent_->id_sr)) + if (sr != get_net_or_empty(cell, id_sr)) return false; - if (dffs_neg != bool_or_default(cell->params, parent_->id_neg_clk)) + if (dffs_neg != bool_or_default(cell->params, id_neg_clk)) return false; } } - const NetInfo *i0 = get_net_or_empty(cell, parent_->id_i0), *i1 = get_net_or_empty(cell, parent_->id_i1), - *i2 = get_net_or_empty(cell, parent_->id_i2), *i3 = get_net_or_empty(cell, parent_->id_i3); + const NetInfo *i0 = get_net_or_empty(cell, id_i0), *i1 = get_net_or_empty(cell, id_i1), + *i2 = get_net_or_empty(cell, id_i2), *i3 = get_net_or_empty(cell, id_i3); if (i0 != nullptr) locals_count++; if (i1 != nullptr) @@ -76,57 +75,57 @@ bool ArchRProxyMethods::logicCellsCompatible(const std::vector return locals_count <= 32; } -bool ArchRProxyMethods::isBelLocationValid(BelId bel) const +bool Arch::isBelLocationValid(BelId bel) const { - if (parent_->getBelType(bel) == TYPE_ICESTORM_LC) { + if (getBelType(bel) == TYPE_ICESTORM_LC) { std::vector bel_cells; - for (auto bel_other : parent_->getBelsAtSameTile(bel)) { - IdString cell_other = getBoundBelCell(bel_other); + for (auto bel_other : getBelsAtSameTile(bel)) { + IdString cell_other = getBoundBelCellUnlocked(bel_other); if (cell_other != IdString()) { - const CellInfo *ci_other = parent_->cells.at(cell_other).get(); + const CellInfo *ci_other = cells.at(cell_other).get(); bel_cells.push_back(ci_other); } } return logicCellsCompatible(bel_cells); } else { - IdString cellId = getBoundBelCell(bel); + IdString cellId = getBoundBelCellUnlocked(bel); if (cellId == IdString()) return true; else - return isValidBelForCell(parent_->cells.at(cellId).get(), bel); + return isValidBelForCell(cells.at(cellId).get(), bel); } } -bool ArchRProxyMethods::isValidBelForCell(CellInfo *cell, BelId bel) const +bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { - if (cell->type == parent_->id_icestorm_lc) { - NPNR_ASSERT(parent_->getBelType(bel) == TYPE_ICESTORM_LC); + if (cell->type == id_icestorm_lc) { + NPNR_ASSERT(getBelType(bel) == TYPE_ICESTORM_LC); std::vector bel_cells; - for (auto bel_other : parent_->getBelsAtSameTile(bel)) { - IdString cell_other = getBoundBelCell(bel_other); + for (auto bel_other : getBelsAtSameTile(bel)) { + IdString cell_other = getBoundBelCellUnlocked(bel_other); if (cell_other != IdString() && bel_other != bel) { - const CellInfo *ci_other = parent_->cells.at(cell_other).get(); + const CellInfo *ci_other = cells.at(cell_other).get(); bel_cells.push_back(ci_other); } } bel_cells.push_back(cell); return logicCellsCompatible(bel_cells); - } else if (cell->type == parent_->id_sb_io) { - return parent_->getBelPackagePin(bel) != ""; - } else if (cell->type == parent_->id_sb_gb) { + } else if (cell->type == id_sb_io) { + return getBelPackagePin(bel) != ""; + } else if (cell->type == id_sb_gb) { bool is_reset = false, is_cen = false; - NPNR_ASSERT(cell->ports.at(parent_->id_glb_buf_out).net != nullptr); - for (auto user : cell->ports.at(parent_->id_glb_buf_out).net->users) { - if (is_reset_port(parent_, user)) + NPNR_ASSERT(cell->ports.at(id_glb_buf_out).net != nullptr); + for (auto user : cell->ports.at(id_glb_buf_out).net->users) { + if (is_reset_port(this, user)) is_reset = true; - if (is_enable_port(parent_, user)) + if (is_enable_port(this, user)) is_cen = true; } - IdString glb_net = parent_->getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT)); - int glb_id = std::stoi(std::string("") + glb_net.str(parent_).back()); + IdString glb_net = getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT)); + int glb_id = std::stoi(std::string("") + glb_net.str(this).back()); if (is_reset && is_cen) return false; else if (is_reset) diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index 10a6f3ff..d42188f0 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -119,17 +119,13 @@ class PlacementLegaliser bool legalise() { - log_info("Legalising logic cells...\n"); + log_info("Legalising design..\n"); init_logic_cells(); - log_info("Legalising carries...\n"); bool legalised_carries = legalise_carries(); if (!legalised_carries && !ctx->force) return false; - log_info("Legalising others...\n"); legalise_others(); - log_info("Legalising logic tiles...\n"); legalise_logic_tiles(); - log_info("Replacing cells...\n"); bool replaced_cells = replace_cells(); return legalised_carries && replaced_cells; } @@ -137,7 +133,6 @@ class PlacementLegaliser private: void init_logic_cells() { - auto &&proxy = ctx->rproxy(); for (auto bel : ctx->getBels()) { // Initialise the logic bels vector with unavailable invalid bels, dimensions [0..width][0..height[0..7] logic_bels.resize(ctx->chip_info->width + 1, @@ -148,7 +143,7 @@ class PlacementLegaliser // Using the non-standard API here to get (x, y, z) rather than just (x, y) auto bi = ctx->chip_info->bel_data[bel.index]; int x = bi.x, y = bi.y, z = bi.z; - IdString cell = proxy.getBoundBelCell(bel); + IdString cell = ctx->getBoundBelCellUnlocked(bel); if (cell != IdString() && ctx->cells.at(cell)->belStrength >= STRENGTH_FIXED) logic_bels.at(x).at(y).at(z) = std::make_pair(bel, true); // locked out of use else @@ -200,33 +195,28 @@ class PlacementLegaliser } } bool success = true; - // Find midpoints for all chains, before we start tearing them up std::vector all_chains; - { - auto &&proxy = ctx->rproxy(); - for (auto &base_chain : carry_chains) { - if (ctx->verbose) { - log_info("Found carry chain: \n"); - for (auto entry : base_chain.cells) - log_info(" %s\n", entry->name.c_str(ctx)); - log_info("\n"); - } - std::vector split_chains = split_carry_chain(proxy, base_chain); - for (auto &chain : split_chains) { - get_chain_midpoint(ctx, chain, chain.mid_x, chain.mid_y); - all_chains.push_back(chain); - } + for (auto &base_chain : carry_chains) { + if (ctx->verbose) { + log_info("Found carry chain: \n"); + for (auto entry : base_chain.cells) + log_info(" %s\n", entry->name.c_str(ctx)); + log_info("\n"); + } + std::vector split_chains = split_carry_chain(base_chain); + for (auto &chain : split_chains) { + get_chain_midpoint(ctx, chain, chain.mid_x, chain.mid_y); + all_chains.push_back(chain); } } // Actual chain placement - auto &&proxy = ctx->rwproxy(); for (auto &chain : all_chains) { if (ctx->verbose) log_info("Placing carry chain starting at '%s'\n", chain.cells.front()->name.c_str(ctx)); float base_x = chain.mid_x, base_y = chain.mid_y - (chain.cells.size() / 16.0f); // Find Bel meeting requirements closest to the target base, returning location as - auto chain_origin_bel = find_closest_bel(proxy, base_x, base_y, chain); + auto chain_origin_bel = find_closest_bel(base_x, base_y, chain); int place_x = std::get<0>(chain_origin_bel), place_y = std::get<1>(chain_origin_bel), place_z = std::get<2>(chain_origin_bel); if (place_x == -1) { @@ -243,7 +233,7 @@ class PlacementLegaliser // Place carry chain for (int i = 0; i < int(chain.cells.size()); i++) { int target_z = place_y * 8 + place_z + i; - place_lc(proxy, chain.cells.at(i), place_x, target_z / 8, target_z % 8); + place_lc(chain.cells.at(i), place_x, target_z / 8, target_z % 8); if (ctx->verbose) log_info(" Cell '%s' placed at (%d, %d, %d)\n", chain.cells.at(i)->name.c_str(ctx), place_x, target_z / 8, target_z % 8); @@ -253,7 +243,7 @@ class PlacementLegaliser } // Find Bel closest to a location, meeting chain requirements - std::tuple find_closest_bel(ArchRWProxy &proxy, float target_x, float target_y, CellChain &chain) + std::tuple find_closest_bel(float target_x, float target_y, CellChain &chain) { std::tuple best_origin = std::make_tuple(-1, -1, -1); wirelen_t best_wirelength = std::numeric_limits::max(); @@ -270,7 +260,7 @@ class PlacementLegaliser valid = false; break; } else { - wirelen += get_cell_wirelength_at_bel(proxy, ctx, chain.cells.at(k), lb.first); + wirelen += get_cell_wirelength_at_bel(ctx, chain.cells.at(k), lb.first); } } if (valid && wirelen < best_wirelength) { @@ -283,7 +273,7 @@ class PlacementLegaliser } // Split a carry chain into multiple legal chains - std::vector split_carry_chain(const ArchRProxy &proxy, CellChain &carryc) + std::vector split_carry_chain(CellChain &carryc) { bool start_of_chain = true; std::vector chains; @@ -308,7 +298,7 @@ class PlacementLegaliser } tile.push_back(cell); chains.back().cells.push_back(cell); - bool split_chain = (!proxy.logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length); + bool split_chain = (!ctx->logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length); if (split_chain) { CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT"))); tile.pop_back(); @@ -335,22 +325,22 @@ class PlacementLegaliser } // Place a logic cell at a given grid location, handling rip-up etc - void place_lc(ArchRWProxy &proxy, CellInfo *cell, int x, int y, int z) + void place_lc(CellInfo *cell, int x, int y, int z) { auto &loc = logic_bels.at(x).at(y).at(z); NPNR_ASSERT(!loc.second); BelId bel = loc.first; // Check if there is a cell presently at the location, which we will need to rip up - IdString existing = proxy.getBoundBelCell(bel); + IdString existing = ctx->getBoundBelCellUnlocked(bel); if (existing != IdString()) { // TODO: keep track of the previous position of the ripped up cell, as a hint rippedCells.insert(existing); - proxy.unbindBel(bel); + ctx->unbindBelUnlocked(bel); } if (cell->bel != BelId()) { - proxy.unbindBel(cell->bel); + ctx->unbindBelUnlocked(cell->bel); } - proxy.bindBel(bel, cell->name, STRENGTH_LOCKED); + ctx->bindBelUnlocked(bel, cell->name, STRENGTH_LOCKED); rippedCells.erase(cell->name); // If cell was ripped up previously, no need to re-place loc.second = true; // Bel is now unavailable for further use } @@ -433,20 +423,19 @@ class PlacementLegaliser // Legalise logic tiles void legalise_logic_tiles() { - auto &&proxy = ctx->rwproxy(); int width = ctx->chip_info->width, height = ctx->chip_info->height; for (int x = 1; x < width; x++) { for (int y = 1; y < height; y++) { BelId tileBel = logic_bels.at(x).at(y).at(0).first; if (tileBel != BelId()) { bool changed = true; - while (!proxy.isBelLocationValid(tileBel) && changed) { + while (!ctx->isBelLocationValid(tileBel) && changed) { changed = false; int max_score = 0; CellInfo *target = nullptr; for (int z = 0; z < 8; z++) { BelId bel = logic_bels.at(x).at(y).at(z).first; - IdString cell = proxy.getBoundBelCell(bel); + IdString cell = ctx->getBoundBelCellUnlocked(bel); if (cell != IdString()) { CellInfo *ci = ctx->cells.at(cell).get(); if (ci->belStrength >= STRENGTH_STRONG) @@ -459,7 +448,7 @@ class PlacementLegaliser } } if (target != nullptr) { - proxy.unbindBel(target->bel); + ctx->unbindBelUnlocked(target->bel); rippedCells.insert(target->name); changed = true; } @@ -472,14 +461,13 @@ class PlacementLegaliser // Legalise other tiles void legalise_others() { - auto &&proxy = ctx->rwproxy(); std::vector legalised_others; for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (!is_lc(ctx, ci)) { if (ci->belStrength < STRENGTH_STRONG && ci->bel != BelId()) { - if (!proxy.isValidBelForCell(ci, ci->bel)) { - place_single_cell(proxy, ctx, ci, true); + if (!ctx->isValidBelForCell(ci, ci->bel)) { + place_single_cell(ctx, ci, true); } legalised_others.push_back(ci); } @@ -494,11 +482,10 @@ class PlacementLegaliser // Replace ripped-up cells bool replace_cells() { - auto &&proxy = ctx->rwproxy(); bool success = true; for (auto cell : sorted(rippedCells)) { CellInfo *ci = ctx->cells.at(cell).get(); - bool placed = place_single_cell(proxy, ctx, ci, true); + bool placed = place_single_cell(ctx, ci, true); if (!placed) { if (ctx->force) { log_warning("failed to place cell '%s' of type '%s'\n", cell.c_str(ctx), ci->type.c_str(ctx)); -- cgit v1.2.3 From 57f75385b0960d6e1e30112a395a89ee4df07056 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:53:08 +0100 Subject: Revert "Make PnR use Unlocked methods" This reverts commit 9e4f97290a50fc5d9dc0cbe6ead945840b9811b1. --- common/place_common.cc | 14 +++--- common/placer1.cc | 38 +++++++-------- common/router1.cc | 36 +++++++-------- ice40/arch.cc | 26 ++--------- ice40/arch.h | 117 +++++++++-------------------------------------- ice40/arch_place.cc | 6 +-- ice40/place_legaliser.cc | 14 +++--- 7 files changed, 78 insertions(+), 173 deletions(-) diff --git a/common/place_common.cc b/common/place_common.cc index 281e40a2..60735890 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -36,7 +36,7 @@ wirelen_t get_net_wirelength(const Context *ctx, const NetInfo *net, float &tns) if (driver_cell->bel == BelId()) return 0; ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb); - WireId drv_wire = ctx->getWireBelPinUnlocked(driver_cell->bel, ctx->portPinFromId(net->driver.port)); + WireId drv_wire = ctx->getWireBelPin(driver_cell->bel, ctx->portPinFromId(net->driver.port)); if (driver_gb) return 0; float worst_slack = 1000; @@ -48,7 +48,7 @@ wirelen_t get_net_wirelength(const Context *ctx, const NetInfo *net, float &tns) if (load_cell->bel == BelId()) continue; if (ctx->timing_driven) { - WireId user_wire = ctx->getWireBelPinUnlocked(load_cell->bel, ctx->portPinFromId(load.port)); + WireId user_wire = ctx->getWireBelPin(load_cell->bel, ctx->portPinFromId(load.port)); delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); float slack = ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl); if (slack < 0) @@ -112,12 +112,12 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality) CellInfo *ripup_target = nullptr; BelId ripup_bel = BelId(); if (cell->bel != BelId()) { - ctx->unbindBelUnlocked(cell->bel); + ctx->unbindBel(cell->bel); } BelType targetType = ctx->belTypeFromId(cell->type); for (auto bel : ctx->getBels()) { if (ctx->getBelType(bel) == targetType && (!require_legality || ctx->isValidBelForCell(cell, bel))) { - if (ctx->checkBelAvailUnlocked(bel)) { + if (ctx->checkBelAvail(bel)) { wirelen_t wirelen = get_cell_wirelength_at_bel(ctx, cell, bel); if (iters >= 4) wirelen += ctx->rng(25); @@ -130,7 +130,7 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality) if (iters >= 4) wirelen += ctx->rng(25); if (wirelen <= best_ripup_wirelen) { - ripup_target = ctx->cells.at(ctx->getBoundBelCellUnlocked(bel)).get(); + ripup_target = ctx->cells.at(ctx->getBoundBelCell(bel)).get(); if (ripup_target->belStrength < STRENGTH_STRONG) { best_ripup_wirelen = wirelen; ripup_bel = bel; @@ -148,12 +148,12 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality) log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx)); } --iters; - ctx->unbindBelUnlocked(ripup_target->bel); + ctx->unbindBel(ripup_target->bel); best_bel = ripup_bel; } else { all_placed = true; } - ctx->bindBelUnlocked(best_bel, cell->name, STRENGTH_WEAK); + ctx->bindBel(best_bel, cell->name, STRENGTH_WEAK); cell = ripup_target; } diff --git a/common/placer1.cc b/common/placer1.cc index 05f760a3..53295a91 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -85,7 +85,7 @@ class SAPlacer auto loc = cell->attrs.find(ctx->id("BEL")); if (loc != cell->attrs.end()) { std::string loc_name = loc->second; - BelId bel = ctx->getBelByNameUnlocked(ctx->id(loc_name)); + BelId bel = ctx->getBelByName(ctx->id(loc_name)); if (bel == BelId()) { log_error("No Bel named \'%s\' located for " "this chip (processing BEL attribute on \'%s\')\n", @@ -100,7 +100,7 @@ class SAPlacer cell->type.c_str(ctx)); } - ctx->bindBelUnlocked(bel, cell->name, STRENGTH_USER); + ctx->bindBel(bel, cell->name, STRENGTH_USER); locked_bels.insert(bel); placed_cells++; } @@ -235,7 +235,7 @@ class SAPlacer } // Final post-pacement validitiy check for (auto bel : ctx->getBels()) { - IdString cell = ctx->getBoundBelCellUnlocked(bel); + IdString cell = ctx->getBoundBelCell(bel); if (!ctx->isBelLocationValid(bel)) { std::string cell_text = "no cell"; if (cell != IdString()) @@ -267,12 +267,12 @@ class SAPlacer CellInfo *ripup_target = nullptr; BelId ripup_bel = BelId(); if (cell->bel != BelId()) { - ctx->unbindBelUnlocked(cell->bel); + ctx->unbindBel(cell->bel); } BelType targetType = ctx->belTypeFromId(cell->type); for (auto bel : ctx->getBels()) { if (ctx->getBelType(bel) == targetType && (ctx->isValidBelForCell(cell, bel) || !require_legal)) { - if (ctx->checkBelAvailUnlocked(bel)) { + if (ctx->checkBelAvail(bel)) { uint64_t score = ctx->rng64(); if (score <= best_score) { best_score = score; @@ -282,7 +282,7 @@ class SAPlacer uint64_t score = ctx->rng64(); if (score <= best_ripup_score) { best_ripup_score = score; - ripup_target = ctx->cells.at(ctx->getBoundBelCellUnlocked(bel)).get(); + ripup_target = ctx->cells.at(ctx->getBoundBelCell(bel)).get(); ripup_bel = bel; } } @@ -292,12 +292,12 @@ class SAPlacer if (iters == 0 || ripup_bel == BelId()) log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx)); --iters; - ctx->unbindBelUnlocked(ripup_target->bel); + ctx->unbindBel(ripup_target->bel); best_bel = ripup_bel; } else { all_placed = true; } - ctx->bindBelUnlocked(best_bel, cell->name, STRENGTH_WEAK); + ctx->bindBel(best_bel, cell->name, STRENGTH_WEAK); // Back annotate location cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx); @@ -313,7 +313,7 @@ class SAPlacer new_lengths.clear(); update.clear(); BelId oldBel = cell->bel; - IdString other = ctx->getBoundBelCellUnlocked(newBel); + IdString other = ctx->getBoundBelCell(newBel); CellInfo *other_cell = nullptr; if (other != IdString()) { other_cell = ctx->cells[other].get(); @@ -321,9 +321,9 @@ class SAPlacer return false; } wirelen_t new_wirelength = 0, delta; - ctx->unbindBelUnlocked(oldBel); + ctx->unbindBel(oldBel); if (other != IdString()) { - ctx->unbindBelUnlocked(newBel); + ctx->unbindBel(newBel); } for (const auto &port : cell->ports) @@ -336,16 +336,16 @@ class SAPlacer update.insert(port.second.net); } - ctx->bindBelUnlocked(newBel, cell->name, STRENGTH_WEAK); + ctx->bindBel(newBel, cell->name, STRENGTH_WEAK); if (other != IdString()) { - ctx->bindBelUnlocked(oldBel, other_cell->name, STRENGTH_WEAK); + ctx->bindBel(oldBel, other_cell->name, STRENGTH_WEAK); } if (require_legal) { if (!ctx->isBelLocationValid(newBel) || ((other != IdString() && !ctx->isBelLocationValid(oldBel)))) { - ctx->unbindBelUnlocked(newBel); + ctx->unbindBel(newBel); if (other != IdString()) - ctx->unbindBelUnlocked(oldBel); + ctx->unbindBel(oldBel); goto swap_fail; } } @@ -369,8 +369,8 @@ class SAPlacer improved = true; } else { if (other != IdString()) - ctx->unbindBelUnlocked(oldBel); - ctx->unbindBelUnlocked(newBel); + ctx->unbindBel(oldBel); + ctx->unbindBel(newBel); goto swap_fail; } curr_wirelength = new_wirelength; @@ -379,9 +379,9 @@ class SAPlacer return true; swap_fail: - ctx->bindBelUnlocked(oldBel, cell->name, STRENGTH_WEAK); + ctx->bindBel(oldBel, cell->name, STRENGTH_WEAK); if (other != IdString()) { - ctx->bindBelUnlocked(newBel, other, STRENGTH_WEAK); + ctx->bindBel(newBel, other, STRENGTH_WEAK); } return false; } diff --git a/common/router1.cc b/common/router1.cc index cbaf773d..94c7070e 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -90,10 +90,10 @@ void ripup_net(Context *ctx, IdString net_name) } for (auto pip : pips) - ctx->unbindPipUnlocked(pip); + ctx->unbindPip(pip); for (auto wire : wires) - ctx->unbindWireUnlocked(wire); + ctx->unbindWire(wire); NPNR_ASSERT(net_info->wires.empty()); } @@ -148,10 +148,10 @@ struct Router bool foundRipupNet = false; thisVisitCnt++; - if (!ctx->checkWireAvailUnlocked(next_wire)) { + if (!ctx->checkWireAvail(next_wire)) { if (!ripup) continue; - IdString ripupWireNet = ctx->getConflictingWireNetUnlocked(next_wire); + IdString ripupWireNet = ctx->getConflictingWireNet(next_wire); if (ripupWireNet == net_name || ripupWireNet == IdString()) continue; @@ -166,10 +166,10 @@ struct Router foundRipupNet = true; } - if (!ctx->checkPipAvailUnlocked(pip)) { + if (!ctx->checkPipAvail(pip)) { if (!ripup) continue; - IdString ripupPipNet = ctx->getConflictingPipNetUnlocked(pip); + IdString ripupPipNet = ctx->getConflictingPipNet(pip); if (ripupPipNet == net_name || ripupPipNet == IdString()) continue; @@ -272,7 +272,7 @@ struct Router if (driver_port_it != net_info->driver.cell->pins.end()) driver_port = driver_port_it->second; - auto src_wire = ctx->getWireBelPinUnlocked(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); if (src_wire == WireId()) log_error("No wire found for port %s (pin %s) on source cell %s " @@ -287,7 +287,7 @@ struct Router src_wires[src_wire] = 0; ripup_net(ctx, net_name); - ctx->bindWireUnlocked(src_wire, net_name, STRENGTH_WEAK); + ctx->bindWire(src_wire, net_name, STRENGTH_WEAK); std::vector users_array = net_info->users; ctx->shuffle(users_array); @@ -312,7 +312,7 @@ struct Router if (user_port_it != user_it.cell->pins.end()) user_port = user_port_it->second; - auto dst_wire = ctx->getWireBelPinUnlocked(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); if (dst_wire == WireId()) log_error("No wire found for port %s (pin %s) on destination " @@ -355,14 +355,14 @@ struct Router if (src_wires.count(cursor)) break; - IdString conflicting_wire_net = ctx->getConflictingWireNetUnlocked(cursor); + IdString conflicting_wire_net = ctx->getConflictingWireNet(cursor); if (conflicting_wire_net != IdString()) { NPNR_ASSERT(ripup); NPNR_ASSERT(conflicting_wire_net != net_name); - ctx->unbindWireUnlocked(cursor); - if (!ctx->checkWireAvailUnlocked(cursor)) + ctx->unbindWire(cursor); + if (!ctx->checkWireAvail(cursor)) ripup_net(ctx, conflicting_wire_net); rippedNets.insert(conflicting_wire_net); @@ -372,14 +372,14 @@ struct Router } PipId pip = visited[cursor].pip; - IdString conflicting_pip_net = ctx->getConflictingPipNetUnlocked(pip); + IdString conflicting_pip_net = ctx->getConflictingPipNet(pip); if (conflicting_pip_net != IdString()) { NPNR_ASSERT(ripup); NPNR_ASSERT(conflicting_pip_net != net_name); - ctx->unbindPipUnlocked(pip); - if (!ctx->checkPipAvailUnlocked(pip)) + ctx->unbindPip(pip); + if (!ctx->checkPipAvail(pip)) ripup_net(ctx, conflicting_pip_net); rippedNets.insert(conflicting_pip_net); @@ -388,7 +388,7 @@ struct Router scores.netPipScores[std::make_pair(conflicting_pip_net, visited[cursor].pip)]++; } - ctx->bindPipUnlocked(visited[cursor].pip, net_name, STRENGTH_WEAK); + ctx->bindPip(visited[cursor].pip, net_name, STRENGTH_WEAK); src_wires[cursor] = visited[cursor].delay; cursor = ctx->getPipSrcWire(visited[cursor].pip); } @@ -451,7 +451,7 @@ bool router1(Context *ctx) if (driver_port_it != net_info->driver.cell->pins.end()) driver_port = driver_port_it->second; - auto src_wire = ctx->getWireBelPinUnlocked(src_bel, ctx->portPinFromId(driver_port)); + auto src_wire = ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); if (src_wire == WireId()) continue; @@ -469,7 +469,7 @@ bool router1(Context *ctx) if (user_port_it != user_it.cell->pins.end()) user_port = user_port_it->second; - auto dst_wire = ctx->getWireBelPinUnlocked(dst_bel, ctx->portPinFromId(user_port)); + auto dst_wire = ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); if (dst_wire == WireId()) continue; diff --git a/ice40/arch.cc b/ice40/arch.cc index 30eea776..74353fe6 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -242,11 +242,6 @@ IdString Arch::archArgsToId(ArchArgs args) const BelId Arch::getBelByName(IdString name) const { boost::lock_guard lock(mtx_); - return getBelByNameUnlocked(name); -} - -BelId Arch::getBelByNameUnlocked(IdString name) const -{ BelId ret; if (bel_by_name.empty()) { @@ -280,14 +275,9 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const } WireId Arch::getWireBelPin(BelId bel, PortPin pin) const -{ - boost::shared_lock_guard lock(mtx_); - return getWireBelPinUnlocked(bel, pin); -} - -WireId Arch::getWireBelPinUnlocked(BelId bel, PortPin pin) const { WireId ret; + boost::shared_lock_guard lock(mtx_); NPNR_ASSERT(bel != BelId()); @@ -306,14 +296,9 @@ WireId Arch::getWireBelPinUnlocked(BelId bel, PortPin pin) const // ----------------------------------------------------------------------- WireId Arch::getWireByName(IdString name) const -{ - boost::shared_lock_guard lock(mtx_); - return getWireByNameUnlocked(name); -} - -WireId Arch::getWireByNameUnlocked(IdString name) const { WireId ret; + boost::shared_lock_guard lock(mtx_); if (wire_by_name.empty()) { for (int i = 0; i < chip_info->num_wires; i++) @@ -330,14 +315,9 @@ WireId Arch::getWireByNameUnlocked(IdString name) const // ----------------------------------------------------------------------- PipId Arch::getPipByName(IdString name) const -{ - boost::shared_lock_guard lock(mtx_); - return getPipByNameUnlocked(name); -} - -PipId Arch::getPipByNameUnlocked(IdString name) const { PipId ret; + boost::shared_lock_guard lock(mtx_); if (pip_by_name.empty()) { for (int i = 0; i < chip_info->num_pips; i++) { diff --git a/ice40/arch.h b/ice40/arch.h index 6f281d4a..a7af3269 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -362,7 +362,6 @@ public: // ------------------------------------------------- BelId getBelByName(IdString name) const; - BelId getBelByNameUnlocked(IdString name) const; IdString getBelName(BelId bel) const { @@ -372,68 +371,44 @@ public: uint32_t getBelChecksum(BelId bel) const { return bel.index; } - void bindBel(BelId bel, IdString cell, PlaceStrength strength) { - boost::lock_guard lock(mtx_); - bindBelUnlocked(bel, cell, strength); - } - - void bindBelUnlocked(BelId bel, IdString cell, PlaceStrength strength) + void bindBel(BelId bel, IdString cell, PlaceStrength strength) { NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); + boost::lock_guard lock(mtx_); bel_to_cell[bel.index] = cell; cells[cell]->bel = bel; cells[cell]->belStrength = strength; } void unbindBel(BelId bel) - { - boost::lock_guard lock(mtx_); - unbindBelUnlocked(bel); - } - - void unbindBelUnlocked(BelId bel) { NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); + boost::lock_guard lock(mtx_); cells[bel_to_cell[bel.index]]->bel = BelId(); cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; bel_to_cell[bel.index] = IdString(); } bool checkBelAvail(BelId bel) const - { - boost::shared_lock_guard lock(mtx_); - return checkBelAvailUnlocked(bel); - } - - bool checkBelAvailUnlocked(BelId bel) const { NPNR_ASSERT(bel != BelId()); + boost::shared_lock_guard lock(mtx_); return bel_to_cell[bel.index] == IdString(); } IdString getBoundBelCell(BelId bel) const - { - boost::shared_lock_guard lock(mtx_); - return getBoundBelCellUnlocked(bel); - } - - IdString getBoundBelCellUnlocked(BelId bel) const { NPNR_ASSERT(bel != BelId()); + boost::shared_lock_guard lock(mtx_); return bel_to_cell[bel.index]; } IdString getConflictingBelCell(BelId bel) const - { - boost::shared_lock_guard lock(mtx_); - return getConflictingBelCellUnlocked(bel); - } - - IdString getConflictingBelCellUnlocked(BelId bel) const { NPNR_ASSERT(bel != BelId()); + boost::shared_lock_guard lock(mtx_); return bel_to_cell[bel.index]; } @@ -450,11 +425,11 @@ public: BelRange range; // FIXME #if 0 - if (type == "TYPE_A") { - range.b.cursor = bels_type_a_begin; - range.e.cursor = bels_type_a_end; - } - ... + if (type == "TYPE_A") { + range.b.cursor = bels_type_a_begin; + range.e.cursor = bels_type_a_end; + } + ... #endif return range; } @@ -468,7 +443,6 @@ public: } WireId getWireBelPin(BelId bel, PortPin pin) const; - WireId getWireBelPinUnlocked(BelId bel, PortPin pin) const; BelPin getBelPinUphill(WireId wire) const { @@ -495,7 +469,6 @@ public: // ------------------------------------------------- WireId getWireByName(IdString name) const; - WireId getWireByNameUnlocked(IdString name) const; IdString getWireName(WireId wire) const { @@ -506,15 +479,10 @@ public: uint32_t getWireChecksum(WireId wire) const { return wire.index; } void bindWire(WireId wire, IdString net, PlaceStrength strength) - { - boost::lock_guard lock(mtx_); - bindWireUnlocked(wire, net, strength); - } - - void bindWireUnlocked(WireId wire, IdString net, PlaceStrength strength) { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire.index] == IdString()); + boost::lock_guard lock(mtx_); wire_to_net[wire.index] = net; nets[net]->wires[wire].pip = PipId(); @@ -522,15 +490,10 @@ public: } void unbindWire(WireId wire) - { - boost::lock_guard lock(mtx_); - unbindWireUnlocked(wire); - } - - void unbindWireUnlocked(WireId wire) { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire.index] != IdString()); + boost::lock_guard lock(mtx_); auto &net_wires = nets[wire_to_net[wire.index]]->wires; auto it = net_wires.find(wire); @@ -548,37 +511,25 @@ public: bool checkWireAvail(WireId wire) const { + NPNR_ASSERT(wire != WireId()); boost::shared_lock_guard lock(mtx_); - return checkWireAvailUnlocked(wire); - } - bool checkWireAvailUnlocked(WireId wire) const - { - NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index] == IdString(); } IdString getBoundWireNet(WireId wire) const { + NPNR_ASSERT(wire != WireId()); boost::shared_lock_guard lock(mtx_); - return getBoundWireNetUnlocked(wire); - } - IdString getBoundWireNetUnlocked(WireId wire) const - { - NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index]; } IdString getConflictingWireNet(WireId wire) const { + NPNR_ASSERT(wire != WireId()); boost::shared_lock_guard lock(mtx_); - return getConflictingWireNetUnlocked(wire); - } - IdString getConflictingWireNetUnlocked(WireId wire) const - { - NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index]; } @@ -593,22 +544,16 @@ public: // ------------------------------------------------- PipId getPipByName(IdString name) const; - PipId getPipByNameUnlocked(IdString name) const; IdString getPipName(PipId pip) const; uint32_t getPipChecksum(PipId pip) const { return pip.index; } void bindPip(PipId pip, IdString net, PlaceStrength strength) - { - boost::lock_guard lock(mtx_); - bindPipUnlocked(pip, net, strength); - } - - void bindPipUnlocked(PipId pip, IdString net, PlaceStrength strength) { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] == IdString()); NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); + boost::lock_guard lock(mtx_); pip_to_net[pip.index] = net; switches_locked[chip_info->pip_data[pip.index].switch_index] = net; @@ -622,16 +567,11 @@ public: } void unbindPip(PipId pip) - { - boost::lock_guard lock(mtx_); - unbindPipUnlocked(pip); - } - - void unbindPipUnlocked(PipId pip) { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] != IdString()); NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); + boost::lock_guard lock(mtx_); WireId dst; dst.index = chip_info->pip_data[pip.index].dst; @@ -644,38 +584,23 @@ public: } bool checkPipAvail(PipId pip) const - { - boost::shared_lock_guard lock(mtx_); - return checkPipAvailUnlocked(pip); - } - - bool checkPipAvailUnlocked(PipId pip) const { NPNR_ASSERT(pip != PipId()); + boost::shared_lock_guard lock(mtx_); return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); } IdString getBoundPipNet(PipId pip) const - { - boost::shared_lock_guard lock(mtx_); - return getBoundPipNetUnlocked(pip); - } - - IdString getBoundPipNetUnlocked(PipId pip) const { NPNR_ASSERT(pip != PipId()); + boost::shared_lock_guard lock(mtx_); return pip_to_net[pip.index]; } IdString getConflictingPipNet(PipId pip) const - { - boost::shared_lock_guard lock(mtx_); - return getConflictingPipNetUnlocked(pip); - } - - IdString getConflictingPipNetUnlocked(PipId pip) const { NPNR_ASSERT(pip != PipId()); + boost::shared_lock_guard lock(mtx_); return switches_locked[chip_info->pip_data[pip.index].switch_index]; } diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index c9dd26c5..dc1bc3eb 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -80,7 +80,7 @@ bool Arch::isBelLocationValid(BelId bel) const if (getBelType(bel) == TYPE_ICESTORM_LC) { std::vector bel_cells; for (auto bel_other : getBelsAtSameTile(bel)) { - IdString cell_other = getBoundBelCellUnlocked(bel_other); + IdString cell_other = getBoundBelCell(bel_other); if (cell_other != IdString()) { const CellInfo *ci_other = cells.at(cell_other).get(); bel_cells.push_back(ci_other); @@ -88,7 +88,7 @@ bool Arch::isBelLocationValid(BelId bel) const } return logicCellsCompatible(bel_cells); } else { - IdString cellId = getBoundBelCellUnlocked(bel); + IdString cellId = getBoundBelCell(bel); if (cellId == IdString()) return true; else @@ -104,7 +104,7 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const std::vector bel_cells; for (auto bel_other : getBelsAtSameTile(bel)) { - IdString cell_other = getBoundBelCellUnlocked(bel_other); + IdString cell_other = getBoundBelCell(bel_other); if (cell_other != IdString() && bel_other != bel) { const CellInfo *ci_other = cells.at(cell_other).get(); bel_cells.push_back(ci_other); diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index d42188f0..559358c7 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -143,7 +143,7 @@ class PlacementLegaliser // Using the non-standard API here to get (x, y, z) rather than just (x, y) auto bi = ctx->chip_info->bel_data[bel.index]; int x = bi.x, y = bi.y, z = bi.z; - IdString cell = ctx->getBoundBelCellUnlocked(bel); + IdString cell = ctx->getBoundBelCell(bel); if (cell != IdString() && ctx->cells.at(cell)->belStrength >= STRENGTH_FIXED) logic_bels.at(x).at(y).at(z) = std::make_pair(bel, true); // locked out of use else @@ -331,16 +331,16 @@ class PlacementLegaliser NPNR_ASSERT(!loc.second); BelId bel = loc.first; // Check if there is a cell presently at the location, which we will need to rip up - IdString existing = ctx->getBoundBelCellUnlocked(bel); + IdString existing = ctx->getBoundBelCell(bel); if (existing != IdString()) { // TODO: keep track of the previous position of the ripped up cell, as a hint rippedCells.insert(existing); - ctx->unbindBelUnlocked(bel); + ctx->unbindBel(bel); } if (cell->bel != BelId()) { - ctx->unbindBelUnlocked(cell->bel); + ctx->unbindBel(cell->bel); } - ctx->bindBelUnlocked(bel, cell->name, STRENGTH_LOCKED); + ctx->bindBel(bel, cell->name, STRENGTH_LOCKED); rippedCells.erase(cell->name); // If cell was ripped up previously, no need to re-place loc.second = true; // Bel is now unavailable for further use } @@ -435,7 +435,7 @@ class PlacementLegaliser CellInfo *target = nullptr; for (int z = 0; z < 8; z++) { BelId bel = logic_bels.at(x).at(y).at(z).first; - IdString cell = ctx->getBoundBelCellUnlocked(bel); + IdString cell = ctx->getBoundBelCell(bel); if (cell != IdString()) { CellInfo *ci = ctx->cells.at(cell).get(); if (ci->belStrength >= STRENGTH_STRONG) @@ -448,7 +448,7 @@ class PlacementLegaliser } } if (target != nullptr) { - ctx->unbindBelUnlocked(target->bel); + ctx->unbindBel(target->bel); rippedCells.insert(target->name); changed = true; } -- cgit v1.2.3 From d327a0afbb6a92553647444c0baaeb4971a0847b Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 19:01:33 +0100 Subject: Revert "Make ice40::Arch thread-safe" This reverts commit 0816f447b768ebe0632f419e9b696714dda4e860. --- ice40/arch.cc | 7 ------- ice40/arch.h | 38 ++++++-------------------------------- ice40/bitstream.cc | 10 +++++----- 3 files changed, 11 insertions(+), 44 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 74353fe6..adc37dbd 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -241,7 +241,6 @@ IdString Arch::archArgsToId(ArchArgs args) const BelId Arch::getBelByName(IdString name) const { - boost::lock_guard lock(mtx_); BelId ret; if (bel_by_name.empty()) { @@ -277,7 +276,6 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const WireId Arch::getWireBelPin(BelId bel, PortPin pin) const { WireId ret; - boost::shared_lock_guard lock(mtx_); NPNR_ASSERT(bel != BelId()); @@ -298,7 +296,6 @@ WireId Arch::getWireBelPin(BelId bel, PortPin pin) const WireId Arch::getWireByName(IdString name) const { WireId ret; - boost::shared_lock_guard lock(mtx_); if (wire_by_name.empty()) { for (int i = 0; i < chip_info->num_wires; i++) @@ -317,7 +314,6 @@ WireId Arch::getWireByName(IdString name) const PipId Arch::getPipByName(IdString name) const { PipId ret; - boost::shared_lock_guard lock(mtx_); if (pip_by_name.empty()) { for (int i = 0; i < chip_info->num_pips; i++) { @@ -376,8 +372,6 @@ std::string Arch::getBelPackagePin(BelId bel) const // ----------------------------------------------------------------------- -// TODO(cliffordvienna): lock all of this - GroupId Arch::getGroupByName(IdString name) const { for (auto g : getGroups()) @@ -503,7 +497,6 @@ DecalXY Arch::getGroupDecal(GroupId group) const std::vector Arch::getDecalGraphics(DecalId decal) const { - boost::shared_lock_guard lock(mtx_); std::vector ret; if (decal.type == DecalId::TYPE_FRAME) { diff --git a/ice40/arch.h b/ice40/arch.h index a7af3269..e42da422 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -21,9 +21,6 @@ #error Include "arch.h" via "nextpnr.h" only. #endif -#include -#include - NEXTPNR_NAMESPACE_BEGIN /**** Everything in this section must be kept in sync with chipdb.py ****/ @@ -327,17 +324,8 @@ struct ArchArgs std::string package; }; -class Arch : public BaseCtx +struct Arch : BaseCtx { -private: - // All of the following... - std::vector bel_to_cell; - std::vector wire_to_net; - std::vector pip_to_net; - std::vector switches_locked; - // ... are guarded by the following lock: - mutable boost::shared_mutex mtx_; -public: const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; @@ -345,6 +333,11 @@ public: mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; + std::vector bel_to_cell; + std::vector wire_to_net; + std::vector pip_to_net; + std::vector switches_locked; + ArchArgs args; Arch(ArchArgs args); @@ -375,7 +368,6 @@ public: { NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); - boost::lock_guard lock(mtx_); bel_to_cell[bel.index] = cell; cells[cell]->bel = bel; cells[cell]->belStrength = strength; @@ -385,7 +377,6 @@ public: { NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); - boost::lock_guard lock(mtx_); cells[bel_to_cell[bel.index]]->bel = BelId(); cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; bel_to_cell[bel.index] = IdString(); @@ -394,21 +385,18 @@ public: bool checkBelAvail(BelId bel) const { NPNR_ASSERT(bel != BelId()); - boost::shared_lock_guard lock(mtx_); return bel_to_cell[bel.index] == IdString(); } IdString getBoundBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); - boost::shared_lock_guard lock(mtx_); return bel_to_cell[bel.index]; } IdString getConflictingBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); - boost::shared_lock_guard lock(mtx_); return bel_to_cell[bel.index]; } @@ -482,8 +470,6 @@ public: { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire.index] == IdString()); - boost::lock_guard lock(mtx_); - wire_to_net[wire.index] = net; nets[net]->wires[wire].pip = PipId(); nets[net]->wires[wire].strength = strength; @@ -493,7 +479,6 @@ public: { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire.index] != IdString()); - boost::lock_guard lock(mtx_); auto &net_wires = nets[wire_to_net[wire.index]]->wires; auto it = net_wires.find(wire); @@ -512,24 +497,18 @@ public: bool checkWireAvail(WireId wire) const { NPNR_ASSERT(wire != WireId()); - boost::shared_lock_guard lock(mtx_); - return wire_to_net[wire.index] == IdString(); } IdString getBoundWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); - boost::shared_lock_guard lock(mtx_); - return wire_to_net[wire.index]; } IdString getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); - boost::shared_lock_guard lock(mtx_); - return wire_to_net[wire.index]; } @@ -553,7 +532,6 @@ public: NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] == IdString()); NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); - boost::lock_guard lock(mtx_); pip_to_net[pip.index] = net; switches_locked[chip_info->pip_data[pip.index].switch_index] = net; @@ -571,7 +549,6 @@ public: NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] != IdString()); NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); - boost::lock_guard lock(mtx_); WireId dst; dst.index = chip_info->pip_data[pip.index].dst; @@ -586,21 +563,18 @@ public: bool checkPipAvail(PipId pip) const { NPNR_ASSERT(pip != PipId()); - boost::shared_lock_guard lock(mtx_); return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); } IdString getBoundPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); - boost::shared_lock_guard lock(mtx_); return pip_to_net[pip.index]; } IdString getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); - boost::shared_lock_guard lock(mtx_); return switches_locked[chip_info->pip_data[pip.index].switch_index]; } diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 58a59366..a62c6c09 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -128,7 +128,7 @@ void write_asc(const Context *ctx, std::ostream &out) } // Set pips for (auto pip : ctx->getPips()) { - if (ctx->getBoundPipNet(pip) != IdString()) { + if (ctx->pip_to_net[pip.index] != IdString()) { const PipInfoPOD &pi = ci.pip_data[pip.index]; const SwitchInfoPOD &swi = bi.switches[pi.switch_index]; for (int i = 0; i < swi.num_bits; i++) { @@ -199,8 +199,8 @@ void write_asc(const Context *ctx, std::ostream &out) NPNR_ASSERT(iez != -1); bool input_en = false; - if (!ctx->checkWireAvail(ctx->getWireBelPin(bel, PIN_D_IN_0)) || - !ctx->checkWireAvail(ctx->getWireBelPin(bel, PIN_D_IN_1))) { + if ((ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_0).index] != IdString()) || + (ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_1).index] != IdString())) { input_en = true; } @@ -271,7 +271,7 @@ void write_asc(const Context *ctx, std::ostream &out) } // Set config bits in unused IO and RAM for (auto bel : ctx->getBels()) { - if (ctx->checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_SB_IO) { + if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_SB_IO) { const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y, z = beli.z; @@ -284,7 +284,7 @@ void write_asc(const Context *ctx, std::ostream &out) set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); } } - } else if (ctx->checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) { + } else if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) { const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB]; -- cgit v1.2.3 From eafb9b4281db82b7f5b2cfcab4dfcfd1dcb038aa Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 19:02:52 +0100 Subject: Fix revert issues. --- ice40/arch.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/ice40/arch.h b/ice40/arch.h index e42da422..a02e0ced 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -523,9 +523,6 @@ struct Arch : BaseCtx // ------------------------------------------------- PipId getPipByName(IdString name) const; - IdString getPipName(PipId pip) const; - - uint32_t getPipChecksum(PipId pip) const { return pip.index; } void bindPip(PipId pip, IdString net, PlaceStrength strength) { @@ -641,15 +638,6 @@ struct Arch : BaseCtx return range; } - WireRange getWires() const - { - WireRange range; - range.b.cursor = 0; - range.e.cursor = chip_info->num_wires; - return range; - } - - BelId getPackagePinBel(const std::string &pin) const; std::string getBelPackagePin(BelId bel) const; -- cgit v1.2.3 From fcba866b632bff903cc2d8797047075eab623693 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sat, 14 Jul 2018 20:19:39 +0200 Subject: remove selected on context change --- gui/fpgaviewwidget.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 1d0e8b57..ad62d38f 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -272,6 +272,7 @@ FPGAViewWidget::~FPGAViewWidget() {} void FPGAViewWidget::newContext(Context *ctx) { ctx_ = ctx; + selectedItems_.clear(); update(); } -- cgit v1.2.3 From bce235fad582dbb727354a7917e4d25a6529c650 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 15 Jul 2018 09:49:19 +0200 Subject: show selected item from property window as well, cleanup --- gui/designwidget.cc | 437 ++++++++++++++++++++++------------------------------ gui/designwidget.h | 20 ++- 2 files changed, 201 insertions(+), 256 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index edf9f1ec..553171ab 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -29,16 +29,6 @@ NEXTPNR_NAMESPACE_BEGIN -enum class ElementType -{ - NONE, - BEL, - WIRE, - PIP, - NET, - CELL -}; - class ElementTreeItem : public QTreeWidgetItem { public: @@ -87,27 +77,28 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net propertyEditor = new QtTreePropertyBrowser(this); propertyEditor->setFactoryForManager(variantManager, variantFactory); propertyEditor->setPropertiesWithoutValueMarked(true); - + connect(propertyEditor, SIGNAL(currentItemChanged(QtBrowserItem *)), this, + SLOT(onCurrentPropertyChanged(QtBrowserItem *))); propertyEditor->show(); - + QLineEdit *lineEdit = new QLineEdit(); lineEdit->setClearButtonEnabled(true); lineEdit->addAction(QIcon(":/icons/resources/zoom.png"), QLineEdit::LeadingPosition); lineEdit->setPlaceholderText("Search..."); - actionFirst = new QAction("", this); + actionFirst = new QAction("", this); actionFirst->setIcon(QIcon(":/icons/resources/resultset_first.png")); actionFirst->setEnabled(false); - actionPrev = new QAction("", this); + actionPrev = new QAction("", this); actionPrev->setIcon(QIcon(":/icons/resources/resultset_previous.png")); actionPrev->setEnabled(false); - actionNext = new QAction("", this); + actionNext = new QAction("", this); actionNext->setIcon(QIcon(":/icons/resources/resultset_next.png")); actionNext->setEnabled(false); - actionLast = new QAction("", this); + actionLast = new QAction("", this); actionLast->setIcon(QIcon(":/icons/resources/resultset_last.png")); actionLast->setEnabled(false); @@ -301,12 +292,13 @@ void DesignWidget::updateTree() cells_root->addChild(item.second); } } - -void DesignWidget::addProperty(QtProperty *property, const QString &id) +QtProperty *DesignWidget::addTopLevelProperty(const QString &id) { - propertyToId[property] = id; - idToProperty[id] = property; - propertyEditor->addProperty(property); + QtProperty *topItem = groupManager->addProperty(id); + propertyToId[topItem] = id; + idToProperty[id] = topItem; + propertyEditor->addProperty(topItem); + return topItem; } void DesignWidget::clearProperties() @@ -320,10 +312,90 @@ void DesignWidget::clearProperties() idToProperty.clear(); } +void DesignWidget::onCurrentPropertyChanged(QtBrowserItem *_item) +{ + if (_item) { + QtProperty *selectedProperty = _item->property(); + QString type = selectedProperty->propertyId(); + IdString value = ctx->id(selectedProperty->valueText().toStdString()); + std::vector decals; + if (type == "BEL") { + BelId bel = ctx->getBelByName(value); + if (bel != BelId()) { + decals.push_back(ctx->getBelDecal(bel)); + Q_EMIT selected(decals); + } + } else if (type == "WIRE") { + WireId wire = ctx->getWireByName(value); + if (wire != WireId()) { + decals.push_back(ctx->getWireDecal(wire)); + Q_EMIT selected(decals); + } + } else if (type == "PIP") { + PipId pip = ctx->getPipByName(value); + if (pip != PipId()) { + decals.push_back(ctx->getPipDecal(pip)); + Q_EMIT selected(decals); + } + } else if (type == "NET") { + } else if (type == "CELL") { + } + } +} + +QString DesignWidget::getElementTypeName(ElementType type) +{ + if (type == ElementType::NONE) + return ""; + if (type == ElementType::BEL) + return "BEL"; + if (type == ElementType::WIRE) + return "WIRE"; + if (type == ElementType::PIP) + return "PIP"; + if (type == ElementType::NET) + return "NET"; + if (type == ElementType::CELL) + return "CELL"; + return ""; +} + +ElementType DesignWidget::getElementTypeByName(QString type) +{ + if (type == "BEL") + return ElementType::BEL; + if (type == "WIRE") + return ElementType::WIRE; + if (type == "PIP") + return ElementType::PIP; + if (type == "NET") + return ElementType::NET; + if (type == "CELL") + return ElementType::CELL; + return ElementType::NONE; +} + +void DesignWidget::addProperty(QtProperty *topItem, int propertyType, const QString &name, QVariant value, + const ElementType &type) +{ + QtVariantProperty *item = readOnlyManager->addProperty(propertyType, name); + item->setValue(value); + item->setPropertyId(getElementTypeName(type)); + topItem->addSubProperty(item); +} + +QtProperty *DesignWidget::addSubGroup(QtProperty *topItem, const QString &name) +{ + QtProperty *item = groupManager->addProperty(name); + topItem->addSubProperty(item); + return item; +} + void DesignWidget::onItemSelectionChanged() { - if (treeWidget->selectedItems().size()== 0) return; - + if (treeWidget->selectedItems().size() == 0) + return; + QTreeWidgetItem *clickItem = treeWidget->selectedItems().at(0); if (!clickItem->parent()) @@ -340,32 +412,18 @@ void DesignWidget::onItemSelectionChanged() if (type == ElementType::BEL) { IdString c = static_cast(clickItem)->getData(); BelId bel = ctx->getBelByName(c); - - decals.push_back(ctx->getBelDecal(bel)); - Q_EMIT selected(decals); - - QtProperty *topItem = groupManager->addProperty("Bel"); - addProperty(topItem, "Bel"); - - QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name"); - nameItem->setValue(c.c_str(ctx)); - topItem->addSubProperty(nameItem); - QtVariantProperty *typeItem = readOnlyManager->addProperty(QVariant::String, "Type"); - typeItem->setValue(ctx->belTypeToId(ctx->getBelType(bel)).c_str(ctx)); - topItem->addSubProperty(typeItem); - - QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available"); - availItem->setValue(ctx->checkBelAvail(bel)); - topItem->addSubProperty(availItem); + decals.push_back(ctx->getBelDecal(bel)); + Q_EMIT selected(decals); - QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Cell"); - cellItem->setValue(ctx->getBoundBelCell(bel).c_str(ctx)); - topItem->addSubProperty(cellItem); + QtProperty *topItem = addTopLevelProperty("Bel"); - QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Cell"); - conflictItem->setValue(ctx->getConflictingBelCell(bel).c_str(ctx)); - topItem->addSubProperty(conflictItem); + addProperty(topItem, QVariant::String, "Name", c.c_str(ctx)); + addProperty(topItem, QVariant::String, "Type", ctx->belTypeToId(ctx->getBelType(bel)).c_str(ctx)); + addProperty(topItem, QVariant::Bool, "Available", ctx->checkBelAvail(bel)); + addProperty(topItem, QVariant::String, "Bound Cell", ctx->getBoundBelCell(bel).c_str(ctx), ElementType::CELL); + addProperty(topItem, QVariant::String, "Conflicting Cell", ctx->getConflictingBelCell(bel).c_str(ctx), + ElementType::CELL); } else if (type == ElementType::WIRE) { IdString c = static_cast(clickItem)->getData(); @@ -374,76 +432,45 @@ void DesignWidget::onItemSelectionChanged() decals.push_back(ctx->getWireDecal(wire)); Q_EMIT selected(decals); - QtProperty *topItem = groupManager->addProperty("Wire"); - addProperty(topItem, "Wire"); - - QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name"); - nameItem->setValue(c.c_str(ctx)); - topItem->addSubProperty(nameItem); - - QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available"); - availItem->setValue(ctx->checkWireAvail(wire)); - topItem->addSubProperty(availItem); + QtProperty *topItem = addTopLevelProperty("Wire"); - QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Net"); - cellItem->setValue(ctx->getBoundWireNet(wire).c_str(ctx)); - topItem->addSubProperty(cellItem); - - QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Net"); - conflictItem->setValue(ctx->getConflictingWireNet(wire).c_str(ctx)); - topItem->addSubProperty(conflictItem); + addProperty(topItem, QVariant::String, "Name", c.c_str(ctx)); + addProperty(topItem, QVariant::Bool, "Available", ctx->checkWireAvail(wire)); + addProperty(topItem, QVariant::String, "Bound Net", ctx->getBoundWireNet(wire).c_str(ctx), ElementType::NET); + addProperty(topItem, QVariant::String, "Conflicting Net", ctx->getConflictingWireNet(wire).c_str(ctx), + ElementType::NET); + QtProperty *belpinItem = addSubGroup(topItem, "BelPin Uphill"); BelPin uphill = ctx->getBelPinUphill(wire); - QtProperty *belpinItem = groupManager->addProperty("BelPin Uphill"); - topItem->addSubProperty(belpinItem); - - QtVariantProperty *belUphillItem = readOnlyManager->addProperty(QVariant::String, "Bel"); if (uphill.bel != BelId()) - belUphillItem->setValue(ctx->getBelName(uphill.bel).c_str(ctx)); + addProperty(belpinItem, QVariant::String, "Bel", ctx->getBelName(uphill.bel).c_str(ctx), ElementType::BEL); else - belUphillItem->setValue(""); - belpinItem->addSubProperty(belUphillItem); + addProperty(belpinItem, QVariant::String, "Bel", "", ElementType::BEL); - QtVariantProperty *portUphillItem = readOnlyManager->addProperty(QVariant::String, "PortPin"); - portUphillItem->setValue(ctx->portPinToId(uphill.pin).c_str(ctx)); - belpinItem->addSubProperty(portUphillItem); + addProperty(belpinItem, QVariant::String, "PortPin", ctx->portPinToId(uphill.pin).c_str(ctx), ElementType::BEL); - QtProperty *downhillItem = groupManager->addProperty("BelPins Downhill"); - topItem->addSubProperty(downhillItem); + QtProperty *downhillItem = addSubGroup(topItem, "BelPin Downhill"); for (const auto &item : ctx->getBelPinsDownhill(wire)) { QString belname = ""; if (item.bel != BelId()) belname = ctx->getBelName(item.bel).c_str(ctx); QString pinname = ctx->portPinToId(item.pin).c_str(ctx); - QtProperty *dhItem = groupManager->addProperty(belname + "-" + pinname); - downhillItem->addSubProperty(dhItem); - - QtVariantProperty *belItem = readOnlyManager->addProperty(QVariant::String, "Bel"); - belItem->setValue(belname); - dhItem->addSubProperty(belItem); - - QtVariantProperty *portItem = readOnlyManager->addProperty(QVariant::String, "PortPin"); - portItem->setValue(pinname); - dhItem->addSubProperty(portItem); - } -/* - QtProperty *pipsDownItem = groupManager->addProperty("Pips Downhill"); - topItem->addSubProperty(pipsDownItem); - for (const auto &item : ctx->getPipsDownhill(wire)) { - QtVariantProperty *pipItem = readOnlyManager->addProperty(QVariant::String, ""); - pipItem->setValue(ctx->getPipName(item).c_str(ctx)); - pipsDownItem->addSubProperty(pipItem); + QtProperty *dhItem = addSubGroup(downhillItem, belname + "-" + pinname); + addProperty(dhItem, QVariant::String, "Bel", belname, ElementType::BEL); + addProperty(dhItem, QVariant::String, "PortPin", pinname); } + /* + QtProperty *pipsDownItem = addSubGroup(downhillItem, "Pips Downhill"); + for (const auto &item : ctx->getPipsDownhill(wire)) { + addProperty(pipsDownItem, QVariant::String, "", ctx->getPipName(item).c_str(ctx), ElementType::PIP); + } - QtProperty *pipsUpItem = groupManager->addProperty("Pips Uphill"); - topItem->addSubProperty(pipsUpItem); - for (const auto &item : ctx->getPipsUphill(wire)) { - QtVariantProperty *pipItem = readOnlyManager->addProperty(QVariant::String, ""); - pipItem->setValue(ctx->getPipName(item).c_str(ctx)); - pipsUpItem->addSubProperty(pipItem); - } -*/ + QtProperty *pipsUpItem = addSubGroup(downhillItem, "Pips Uphill"); + for (const auto &item : ctx->getPipsUphill(wire)) { + addProperty(pipsUpItem, QVariant::String, "", ctx->getPipName(item).c_str(ctx), ElementType::PIP); + } + */ } else if (type == ElementType::PIP) { IdString c = static_cast(clickItem)->getData(); PipId pip = ctx->getPipByName(c); @@ -451,199 +478,108 @@ void DesignWidget::onItemSelectionChanged() decals.push_back(ctx->getPipDecal(pip)); Q_EMIT selected(decals); - QtProperty *topItem = groupManager->addProperty("Pip"); - addProperty(topItem, "Pip"); + QtProperty *topItem = addTopLevelProperty("Pip"); - QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name"); - nameItem->setValue(c.c_str(ctx)); - topItem->addSubProperty(nameItem); - - QtVariantProperty *availItem = readOnlyManager->addProperty(QVariant::Bool, "Available"); - availItem->setValue(ctx->checkPipAvail(pip)); - topItem->addSubProperty(availItem); - - QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Bound Net"); - cellItem->setValue(ctx->getBoundPipNet(pip).c_str(ctx)); - topItem->addSubProperty(cellItem); - - QtVariantProperty *conflictItem = readOnlyManager->addProperty(QVariant::String, "Conflicting Net"); - conflictItem->setValue(ctx->getConflictingPipNet(pip).c_str(ctx)); - topItem->addSubProperty(conflictItem); - - QtVariantProperty *srcWireItem = readOnlyManager->addProperty(QVariant::String, "Src Wire"); - srcWireItem->setValue(ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx)); - topItem->addSubProperty(srcWireItem); - - QtVariantProperty *destWireItem = readOnlyManager->addProperty(QVariant::String, "Dest Wire"); - destWireItem->setValue(ctx->getWireName(ctx->getPipDstWire(pip)).c_str(ctx)); - topItem->addSubProperty(destWireItem); + addProperty(topItem, QVariant::String, "Name", c.c_str(ctx)); + addProperty(topItem, QVariant::Bool, "Available", ctx->checkPipAvail(pip)); + addProperty(topItem, QVariant::String, "Bound Net", ctx->getBoundPipNet(pip).c_str(ctx), ElementType::NET); + addProperty(topItem, QVariant::String, "Conflicting Net", ctx->getConflictingPipNet(pip).c_str(ctx), + ElementType::NET); + addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx), + ElementType::WIRE); + addProperty(topItem, QVariant::String, "Dest Wire", ctx->getWireName(ctx->getPipDstWire(pip)).c_str(ctx), + ElementType::WIRE); DelayInfo delay = ctx->getPipDelay(pip); - QtProperty *delayItem = groupManager->addProperty("Delay"); - topItem->addSubProperty(delayItem); - - QtVariantProperty *raiseDelayItem = readOnlyManager->addProperty(QVariant::Double, "Raise"); - raiseDelayItem->setValue(delay.raiseDelay()); - delayItem->addSubProperty(raiseDelayItem); - - QtVariantProperty *fallDelayItem = readOnlyManager->addProperty(QVariant::Double, "Fall"); - fallDelayItem->setValue(delay.fallDelay()); - delayItem->addSubProperty(fallDelayItem); - - QtVariantProperty *avgDelayItem = readOnlyManager->addProperty(QVariant::Double, "Average"); - avgDelayItem->setValue(delay.avgDelay()); - delayItem->addSubProperty(avgDelayItem); + QtProperty *delayItem = addSubGroup(topItem, "Delay"); + addProperty(delayItem, QVariant::Double, "Raise", delay.raiseDelay()); + addProperty(delayItem, QVariant::Double, "Fall", delay.fallDelay()); + addProperty(delayItem, QVariant::Double, "Average", delay.avgDelay()); } else if (type == ElementType::NET) { IdString c = static_cast(clickItem)->getData(); NetInfo *net = ctx->nets.at(c).get(); - QtProperty *topItem = groupManager->addProperty("Net"); - addProperty(topItem, "Net"); + QtProperty *topItem = addTopLevelProperty("Net"); - QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name"); - nameItem->setValue(net->name.c_str(ctx)); - topItem->addSubProperty(nameItem); + addProperty(topItem, QVariant::String, "Name", net->name.c_str(ctx)); - QtProperty *driverItem = groupManager->addProperty("Driver"); - topItem->addSubProperty(driverItem); - - QtVariantProperty *portItem = readOnlyManager->addProperty(QVariant::String, "Port"); - portItem->setValue(net->driver.port.c_str(ctx)); - driverItem->addSubProperty(portItem); - - QtVariantProperty *budgetItem = readOnlyManager->addProperty(QVariant::Double, "Budget"); - budgetItem->setValue(net->driver.budget); - driverItem->addSubProperty(budgetItem); - - QtVariantProperty *cellNameItem = readOnlyManager->addProperty(QVariant::String, "Cell"); + QtProperty *driverItem = addSubGroup(topItem, "Driver"); + addProperty(driverItem, QVariant::String, "Port", net->driver.port.c_str(ctx)); + addProperty(driverItem, QVariant::Double, "Budget", net->driver.budget); if (net->driver.cell) - cellNameItem->setValue(net->driver.cell->name.c_str(ctx)); + addProperty(driverItem, QVariant::String, "Cell", net->driver.cell->name.c_str(ctx), ElementType::CELL); else - cellNameItem->setValue(""); - driverItem->addSubProperty(cellNameItem); + addProperty(driverItem, QVariant::String, "Cell", "", ElementType::CELL); - QtProperty *usersItem = groupManager->addProperty("Users"); - topItem->addSubProperty(usersItem); + QtProperty *usersItem = addSubGroup(topItem, "Users"); for (auto &item : net->users) { - QtProperty *portItem = groupManager->addProperty(item.port.c_str(ctx)); - usersItem->addSubProperty(portItem); - - QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Port"); - nameItem->setValue(item.port.c_str(ctx)); - portItem->addSubProperty(nameItem); - - QtVariantProperty *budgetItem = readOnlyManager->addProperty(QVariant::Double, "Budget"); - budgetItem->setValue(item.budget); - portItem->addSubProperty(budgetItem); + QtProperty *portItem = addSubGroup(usersItem, item.port.c_str(ctx)); - QtVariantProperty *userItem = readOnlyManager->addProperty(QVariant::String, "Cell"); + addProperty(portItem, QVariant::String, "Port", item.port.c_str(ctx)); + addProperty(portItem, QVariant::Double, "Budget", item.budget); if (item.cell) - userItem->setValue(item.cell->name.c_str(ctx)); + addProperty(portItem, QVariant::String, "Cell", item.cell->name.c_str(ctx), ElementType::CELL); else - userItem->setValue(""); - portItem->addSubProperty(userItem); + addProperty(portItem, QVariant::String, "Cell", "", ElementType::CELL); } - QtProperty *attrsItem = groupManager->addProperty("Attributes"); - topItem->addSubProperty(attrsItem); + QtProperty *attrsItem = addSubGroup(topItem, "Attributes"); for (auto &item : net->attrs) { - QtVariantProperty *attrItem = readOnlyManager->addProperty(QVariant::String, item.first.c_str(ctx)); - attrItem->setValue(item.second.c_str()); - attrsItem->addSubProperty(attrItem); + addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str()); } - QtProperty *wiresItem = groupManager->addProperty("Wires"); - topItem->addSubProperty(wiresItem); + QtProperty *wiresItem = addSubGroup(topItem, "Wires"); for (auto &item : net->wires) { auto name = ctx->getWireName(item.first).c_str(ctx); - QtProperty *wireItem = groupManager->addProperty(name); - - QtVariantProperty *nameItem = readOnlyManager->addProperty(QVariant::String, "Name"); - nameItem->setValue(name); - wireItem->addSubProperty(nameItem); - - QtVariantProperty *pipItem = readOnlyManager->addProperty(QVariant::String, "Pip"); + QtProperty *wireItem = addSubGroup(wiresItem, name); + addProperty(wireItem, QVariant::String, "Name", name); if (item.second.pip != PipId()) - pipItem->setValue(ctx->getPipName(item.second.pip).c_str(ctx)); + addProperty(wireItem, QVariant::String, "Pip", ctx->getPipName(item.second.pip).c_str(ctx), + ElementType::PIP); else - pipItem->setValue(""); - wireItem->addSubProperty(pipItem); + addProperty(wireItem, QVariant::String, "Pip", "", ElementType::PIP); - QtVariantProperty *strengthItem = readOnlyManager->addProperty(QVariant::Int, "Strength"); - strengthItem->setValue((int)item.second.strength); - wireItem->addSubProperty(strengthItem); - - wiresItem->addSubProperty(wireItem); + addProperty(wireItem, QVariant::Int, "Strength", (int)item.second.strength); } } else if (type == ElementType::CELL) { IdString c = static_cast(clickItem)->getData(); CellInfo *cell = ctx->cells.at(c).get(); - QtProperty *topItem = groupManager->addProperty("Cell"); - addProperty(topItem, "Cell"); - - QtVariantProperty *cellNameItem = readOnlyManager->addProperty(QVariant::String, "Name"); - cellNameItem->setValue(cell->name.c_str(ctx)); - topItem->addSubProperty(cellNameItem); + QtProperty *topItem = addTopLevelProperty("Cell"); - QtVariantProperty *cellTypeItem = readOnlyManager->addProperty(QVariant::String, "Type"); - cellTypeItem->setValue(cell->type.c_str(ctx)); - topItem->addSubProperty(cellTypeItem); - - QtVariantProperty *cellBelItem = readOnlyManager->addProperty(QVariant::String, "Bel"); + addProperty(topItem, QVariant::String, "Name", cell->name.c_str(ctx)); + addProperty(topItem, QVariant::String, "Type", cell->type.c_str(ctx)); if (cell->bel != BelId()) - cellBelItem->setValue(ctx->getBelName(cell->bel).c_str(ctx)); + addProperty(topItem, QVariant::String, "Bel", ctx->getBelName(cell->bel).c_str(ctx), ElementType::BEL); else - cellBelItem->setValue(""); - topItem->addSubProperty(cellBelItem); - - QtVariantProperty *cellBelStrItem = readOnlyManager->addProperty(QVariant::Int, "Bel strength"); - cellBelStrItem->setValue(int(cell->belStrength)); - topItem->addSubProperty(cellBelStrItem); + addProperty(topItem, QVariant::String, "Bel", "", ElementType::BEL); + addProperty(topItem, QVariant::Int, "Bel strength", int(cell->belStrength)); - QtProperty *cellPortsItem = groupManager->addProperty("Ports"); - topItem->addSubProperty(cellPortsItem); + QtProperty *cellPortsItem = addSubGroup(topItem, "Ports"); for (auto &item : cell->ports) { PortInfo p = item.second; - QtProperty *portInfoItem = groupManager->addProperty(p.name.c_str(ctx)); - - QtVariantProperty *portInfoNameItem = readOnlyManager->addProperty(QVariant::String, "Name"); - portInfoNameItem->setValue(p.name.c_str(ctx)); - portInfoItem->addSubProperty(portInfoNameItem); - - QtVariantProperty *portInfoTypeItem = readOnlyManager->addProperty(QVariant::Int, "Type"); - portInfoTypeItem->setValue(int(p.type)); - portInfoItem->addSubProperty(portInfoTypeItem); - - QtVariantProperty *portInfoNetItem = readOnlyManager->addProperty(QVariant::String, "Net"); + QtProperty *portInfoItem = addSubGroup(cellPortsItem, p.name.c_str(ctx)); + addProperty(portInfoItem, QVariant::String, "Name", p.name.c_str(ctx)); + addProperty(portInfoItem, QVariant::Int, "Type", int(p.type)); if (p.net) - portInfoNetItem->setValue(p.net->name.c_str(ctx)); + addProperty(portInfoItem, QVariant::String, "Net", p.net->name.c_str(ctx), ElementType::NET); else - portInfoNetItem->setValue(""); - portInfoItem->addSubProperty(portInfoNetItem); - - cellPortsItem->addSubProperty(portInfoItem); + addProperty(portInfoItem, QVariant::String, "Net", "", ElementType::NET); } - QtProperty *cellAttrItem = groupManager->addProperty("Attributes"); - topItem->addSubProperty(cellAttrItem); + QtProperty *cellAttrItem = addSubGroup(topItem, "Attributes"); for (auto &item : cell->attrs) { - QtVariantProperty *attrItem = readOnlyManager->addProperty(QVariant::String, item.first.c_str(ctx)); - attrItem->setValue(item.second.c_str()); - cellAttrItem->addSubProperty(attrItem); + addProperty(cellAttrItem, QVariant::String, item.first.c_str(ctx), item.second.c_str()); } - QtProperty *cellParamsItem = groupManager->addProperty("Parameters"); - topItem->addSubProperty(cellParamsItem); + QtProperty *cellParamsItem = addSubGroup(topItem, "Parameters"); for (auto &item : cell->params) { - QtVariantProperty *paramItem = readOnlyManager->addProperty(QVariant::String, item.first.c_str(ctx)); - paramItem->setValue(item.second.c_str()); - cellParamsItem->addSubProperty(paramItem); + addProperty(cellParamsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str()); } QtProperty *cellPinsItem = groupManager->addProperty("Pins"); @@ -652,17 +588,10 @@ void DesignWidget::onItemSelectionChanged() std::string cell_port = item.first.c_str(ctx); std::string bel_pin = item.second.c_str(ctx); - QtProperty *pinGroupItem = groupManager->addProperty((cell_port + " -> " + bel_pin).c_str()); - - QtVariantProperty *cellItem = readOnlyManager->addProperty(QVariant::String, "Cell"); - cellItem->setValue(cell_port.c_str()); - pinGroupItem->addSubProperty(cellItem); - - QtVariantProperty *belItem = readOnlyManager->addProperty(QVariant::String, "Bel"); - belItem->setValue(bel_pin.c_str()); - pinGroupItem->addSubProperty(belItem); + QtProperty *pinGroupItem = addSubGroup(cellPortsItem, (cell_port + " -> " + bel_pin).c_str()); - cellPinsItem->addSubProperty(pinGroupItem); + addProperty(pinGroupItem, QVariant::String, "Cell", cell_port.c_str(), ElementType::CELL); + addProperty(pinGroupItem, QVariant::String, "Bel", bel_pin.c_str(), ElementType::BEL); } } } diff --git a/gui/designwidget.h b/gui/designwidget.h index 618c7bbf..a4940213 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -21,6 +21,7 @@ #define DESIGNWIDGET_H #include +#include #include "nextpnr.h" #include "qtgroupboxpropertybrowser.h" #include "qtpropertymanager.h" @@ -29,6 +30,16 @@ NEXTPNR_NAMESPACE_BEGIN +enum class ElementType +{ + NONE, + BEL, + WIRE, + PIP, + NET, + CELL +}; + class DesignWidget : public QWidget { Q_OBJECT @@ -38,9 +49,13 @@ class DesignWidget : public QWidget ~DesignWidget(); private: - void addProperty(QtProperty *property, const QString &id); void clearProperties(); - + QtProperty *addTopLevelProperty(const QString &id); + QtProperty *addSubGroup(QtProperty *topItem, const QString &name); + void addProperty(QtProperty *topItem, int propertyType, const QString &name, QVariant value, + const ElementType &type = ElementType::NONE); + QString getElementTypeName(ElementType type); + ElementType getElementTypeByName(QString type); Q_SIGNALS: void info(std::string text); void selected(std::vector decal); @@ -49,6 +64,7 @@ class DesignWidget : public QWidget void prepareMenu(const QPoint &pos); void onItemSelectionChanged(); void selectObject(); + void onCurrentPropertyChanged(QtBrowserItem *_item); public Q_SLOTS: void newContext(Context *ctx); void updateTree(); -- cgit v1.2.3 From bf0b1d2db3e071f5606e117d5fc5f2213b948997 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 15 Jul 2018 12:39:19 +0200 Subject: add select on property pane, and action to double click --- .../src/qttreepropertybrowser.cpp | 11 ++++ .../QtPropertyBrowser/src/qttreepropertybrowser.h | 4 ++ gui/basewindow.cc | 11 ++-- gui/designwidget.cc | 58 +++++++++++++++------- gui/designwidget.h | 6 +-- gui/fpgaviewwidget.cc | 6 +-- gui/fpgaviewwidget.h | 1 + 7 files changed, 69 insertions(+), 28 deletions(-) diff --git a/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.cpp b/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.cpp index a92ab537..673252d2 100644 --- a/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.cpp +++ b/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.cpp @@ -74,6 +74,7 @@ public: QtProperty *indexToProperty(const QModelIndex &index) const; QTreeWidgetItem *indexToItem(const QModelIndex &index) const; QtBrowserItem *indexToBrowserItem(const QModelIndex &index) const; + QtBrowserItem *itemToBrowserItem(QTreeWidgetItem *item) const { return m_itemToIndex.value(item); }; bool lastColumn(int column) const; void disableItem(QTreeWidgetItem *item) const; void enableItem(QTreeWidgetItem *item) const; @@ -1068,6 +1069,16 @@ void QtTreePropertyBrowser::editItem(QtBrowserItem *item) d_ptr->editItem(item); } +QTreeWidget *QtTreePropertyBrowser::treeWidget() const +{ + return d_ptr->treeWidget(); +} + +QtBrowserItem *QtTreePropertyBrowser::itemToBrowserItem(QTreeWidgetItem *item) +{ + return d_ptr->itemToBrowserItem(item); +} + #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif diff --git a/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.h b/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.h index c5f7fa88..7bc96b69 100644 --- a/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.h +++ b/3rdparty/QtPropertyBrowser/src/qttreepropertybrowser.h @@ -47,6 +47,7 @@ QT_BEGIN_NAMESPACE #endif +class QTreeWidget; class QTreeWidgetItem; class QtTreePropertyBrowserPrivate; @@ -107,6 +108,9 @@ public: void editItem(QtBrowserItem *item); + //ADDED:miodrag + QTreeWidget *treeWidget() const; + QtBrowserItem *itemToBrowserItem(QTreeWidgetItem *item); Q_SIGNALS: void collapsed(QtBrowserItem *item); diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 0c7632ee..a57d3ef1 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -81,7 +81,8 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent centralTabWidget->addTab(fpgaView, "Graphics"); connect(this, SIGNAL(contextChanged(Context *)), fpgaView, SLOT(newContext(Context *))); - connect(designview, SIGNAL(selected(std::vector)), fpgaView, SLOT(onSelectedArchItem(std::vector))); + connect(designview, SIGNAL(selected(std::vector)), fpgaView, + SLOT(onSelectedArchItem(std::vector))); splitter_v->addWidget(centralTabWidget); splitter_v->addWidget(tabWidget); @@ -93,26 +94,26 @@ void BaseMainWindow::writeInfo(std::string text) { console->info(text); } void BaseMainWindow::createMenusAndBars() { - actionNew = new QAction("New", this); + actionNew = new QAction("New", this); actionNew->setIcon(QIcon(":/icons/resources/new.png")); actionNew->setShortcuts(QKeySequence::New); actionNew->setStatusTip("New project file"); connect(actionNew, SIGNAL(triggered()), this, SLOT(new_proj())); - actionOpen = new QAction("Open", this); + actionOpen = new QAction("Open", this); actionOpen->setIcon(QIcon(":/icons/resources/open.png")); actionOpen->setShortcuts(QKeySequence::Open); actionOpen->setStatusTip("Open an existing project file"); connect(actionOpen, SIGNAL(triggered()), this, SLOT(open_proj())); - QAction *actionSave = new QAction("Save", this); + QAction *actionSave = new QAction("Save", this); actionSave->setIcon(QIcon(":/icons/resources/save.png")); actionSave->setShortcuts(QKeySequence::Save); actionSave->setStatusTip("Save existing project to disk"); actionSave->setEnabled(false); connect(actionSave, SIGNAL(triggered()), this, SLOT(save_proj())); - QAction *actionExit = new QAction("Exit", this); + QAction *actionExit = new QAction("Exit", this); actionExit->setIcon(QIcon(":/icons/resources/exit.png")); actionExit->setShortcuts(QKeySequence::Quit); actionExit->setStatusTip("Exit the application"); diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 553171ab..cfcdc9fc 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -77,9 +77,8 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net propertyEditor = new QtTreePropertyBrowser(this); propertyEditor->setFactoryForManager(variantManager, variantFactory); propertyEditor->setPropertiesWithoutValueMarked(true); - connect(propertyEditor, SIGNAL(currentItemChanged(QtBrowserItem *)), this, - SLOT(onCurrentPropertyChanged(QtBrowserItem *))); propertyEditor->show(); + propertyEditor->treeWidget()->setContextMenuPolicy(Qt::CustomContextMenu); QLineEdit *lineEdit = new QLineEdit(); lineEdit->setClearButtonEnabled(true); @@ -144,7 +143,9 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net setLayout(mainLayout); // Connection - connect(treeWidget, &QTreeWidget::customContextMenuRequested, this, &DesignWidget::prepareMenu); + connect(propertyEditor->treeWidget(), &QTreeWidget::customContextMenuRequested, this, + &DesignWidget::prepareMenuProperty); + connect(propertyEditor->treeWidget(), &QTreeWidget::itemDoubleClicked, this, &DesignWidget::onItemDoubleClicked); connect(treeWidget, SIGNAL(itemSelectionChanged()), SLOT(onItemSelectionChanged())); } @@ -312,33 +313,41 @@ void DesignWidget::clearProperties() idToProperty.clear(); } -void DesignWidget::onCurrentPropertyChanged(QtBrowserItem *_item) +void DesignWidget::onCurrentPropertySelected(QtBrowserItem *_item) { if (_item) { QtProperty *selectedProperty = _item->property(); - QString type = selectedProperty->propertyId(); + ElementType type = getElementTypeByName(selectedProperty->propertyId()); IdString value = ctx->id(selectedProperty->valueText().toStdString()); std::vector decals; - if (type == "BEL") { + switch (type) { + case ElementType::BEL: { BelId bel = ctx->getBelByName(value); if (bel != BelId()) { decals.push_back(ctx->getBelDecal(bel)); Q_EMIT selected(decals); } - } else if (type == "WIRE") { + } break; + case ElementType::WIRE: { WireId wire = ctx->getWireByName(value); if (wire != WireId()) { decals.push_back(ctx->getWireDecal(wire)); Q_EMIT selected(decals); } - } else if (type == "PIP") { + } break; + case ElementType::PIP: { PipId pip = ctx->getPipByName(value); if (pip != PipId()) { decals.push_back(ctx->getPipDecal(pip)); Q_EMIT selected(decals); } - } else if (type == "NET") { - } else if (type == "CELL") { + } break; + case ElementType::NET: { + } break; + case ElementType::CELL: { + } break; + default: + break; } } } @@ -596,23 +605,38 @@ void DesignWidget::onItemSelectionChanged() } } -void DesignWidget::prepareMenu(const QPoint &pos) +void DesignWidget::prepareMenuProperty(const QPoint &pos) { - QTreeWidget *tree = treeWidget; + QTreeWidget *tree = propertyEditor->treeWidget(); itemContextMenu = tree->itemAt(pos); + if (itemContextMenu->parent() == nullptr) + return; - QAction *selectAction = new QAction("&Select", this); - selectAction->setStatusTip("Select item on view"); - - connect(selectAction, SIGNAL(triggered()), this, SLOT(selectObject())); + QtBrowserItem *browserItem = propertyEditor->itemToBrowserItem(itemContextMenu); + // if (((ElementTreeItem*)itemContextMenu)->getType() == ElementType::NONE) return; QMenu menu(this); + QAction *selectAction = new QAction("&Select", this); + connect(selectAction, &QAction::triggered, this, [this, browserItem] { onCurrentPropertySelected(browserItem); }); + menu.addAction(selectAction); menu.exec(tree->mapToGlobal(pos)); } -void DesignWidget::selectObject() { Q_EMIT info("selected " + itemContextMenu->text(0).toStdString() + "\n"); } +void DesignWidget::onItemDoubleClicked(QTreeWidgetItem *item, int column) +{ + QtProperty *selectedProperty = propertyEditor->itemToBrowserItem(item)->property(); + ElementType type = getElementTypeByName(selectedProperty->propertyId()); + IdString value = ctx->id(selectedProperty->valueText().toStdString()); + switch (type) { + case ElementType::NONE: + return; + default: + Q_EMIT info("double clicked " + std::string(value.c_str(ctx)) + "\n"); + break; + } +} NEXTPNR_NAMESPACE_END diff --git a/gui/designwidget.h b/gui/designwidget.h index a4940213..50f00bbe 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -61,10 +61,10 @@ class DesignWidget : public QWidget void selected(std::vector decal); private Q_SLOTS: - void prepareMenu(const QPoint &pos); + void prepareMenuProperty(const QPoint &pos); void onItemSelectionChanged(); - void selectObject(); - void onCurrentPropertyChanged(QtBrowserItem *_item); + void onItemDoubleClicked(QTreeWidgetItem *item, int column); + void onCurrentPropertySelected(QtBrowserItem *_item); public Q_SLOTS: void newContext(Context *ctx); void updateTree(); diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index ad62d38f..cb60bc76 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -240,7 +240,8 @@ void LineShader::draw(const LineShaderData &line, const QColor &color, float thi vao_.release(); } -FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), selectedItemsChanged(false) +FPGAViewWidget::FPGAViewWidget(QWidget *parent) + : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), selectedItemsChanged(false) { backgroundColor_ = QColor("#000000"); gridColor_ = QColor("#333"); @@ -412,8 +413,7 @@ void FPGAViewWidget::paintGL() drawDecal(shaders, ctx_->getGroupDecal(group)); } - if (selectedItemsChanged) - { + if (selectedItemsChanged) { selectedItemsChanged = false; selectedShader_.clear(); for (auto decal : selectedItems_) { diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index dd86277e..ea4a17cf 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -245,6 +245,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions public Q_SLOTS: void newContext(Context *ctx); void onSelectedArchItem(std::vector decals); + private: QPoint lastPos_; LineShader lineShader_; -- cgit v1.2.3 From 3eb34bf38b8e2da66b3852bf35927a0b540a3cff Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 15 Jul 2018 15:12:31 +0200 Subject: make linked items clickable --- gui/designwidget.cc | 58 ++++++++++++++++++++++++++++++++++++------------- gui/designwidget.h | 4 ++++ gui/ice40/mainwindow.cc | 20 ++++++++--------- 3 files changed, 57 insertions(+), 25 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index cfcdc9fc..2b0c43c0 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -155,6 +155,9 @@ DesignWidget::~DesignWidget() {} void DesignWidget::newContext(Context *ctx) { treeWidget->clear(); + for (int i = 0; i < 6; i++) + nameToItem[i].clear(); + this->ctx = ctx; // Add bels to tree @@ -174,7 +177,7 @@ void DesignWidget::newContext(Context *ctx) name += items.at(i); if (!bel_items.contains(name)) { if (i == items.size() - 1) - bel_items.insert(name, new IdStringTreeItem(id, ElementType::BEL, items.at(i), parent)); + nameToItem[0].insert(name, new IdStringTreeItem(id, ElementType::BEL, items.at(i), parent)); else bel_items.insert(name, new ElementTreeItem(ElementType::NONE, items.at(i), parent)); } @@ -185,6 +188,9 @@ void DesignWidget::newContext(Context *ctx) for (auto bel : bel_items.toStdMap()) { bel_root->addChild(bel.second); } + for (auto bel : nameToItem[0].toStdMap()) { + bel_root->addChild(bel.second); + } // Add wires to tree QTreeWidgetItem *wire_root = new QTreeWidgetItem(treeWidget); @@ -203,7 +209,7 @@ void DesignWidget::newContext(Context *ctx) name += items.at(i); if (!wire_items.contains(name)) { if (i == items.size() - 1) - wire_items.insert(name, new IdStringTreeItem(id, ElementType::WIRE, items.at(i), parent)); + nameToItem[1].insert(name, new IdStringTreeItem(id, ElementType::WIRE, items.at(i), parent)); else wire_items.insert(name, new ElementTreeItem(ElementType::NONE, items.at(i), parent)); } @@ -214,7 +220,9 @@ void DesignWidget::newContext(Context *ctx) for (auto wire : wire_items.toStdMap()) { wire_root->addChild(wire.second); } - + for (auto wire : nameToItem[1].toStdMap()) { + wire_root->addChild(wire.second); + } // Add pips to tree QTreeWidgetItem *pip_root = new QTreeWidgetItem(treeWidget); QMap pip_items; @@ -232,7 +240,7 @@ void DesignWidget::newContext(Context *ctx) name += items.at(i); if (!pip_items.contains(name)) { if (i == items.size() - 1) - pip_items.insert(name, new IdStringTreeItem(id, ElementType::PIP, items.at(i), parent)); + nameToItem[2].insert(name, new IdStringTreeItem(id, ElementType::PIP, items.at(i), parent)); else pip_items.insert(name, new ElementTreeItem(ElementType::NONE, items.at(i), parent)); } @@ -243,6 +251,9 @@ void DesignWidget::newContext(Context *ctx) for (auto pip : pip_items.toStdMap()) { pip_root->addChild(pip.second); } + for (auto pip : nameToItem[2].toStdMap()) { + pip_root->addChild(pip.second); + } // Add nets to tree nets_root = new QTreeWidgetItem(treeWidget); @@ -260,36 +271,38 @@ void DesignWidget::updateTree() clearProperties(); delete nets_root; delete cells_root; + nameToItem[3].clear(); + nameToItem[4].clear(); // Add nets to tree nets_root = new QTreeWidgetItem(treeWidget); - QMap nets_items; nets_root->setText(0, "Nets"); treeWidget->insertTopLevelItem(0, nets_root); if (ctx) { for (auto &item : ctx->nets) { auto id = item.first; QString name = QString(id.c_str(ctx)); - nets_items.insert(name, new IdStringTreeItem(id, ElementType::NET, name, nullptr)); + IdStringTreeItem *newItem = new IdStringTreeItem(id, ElementType::NET, name, nullptr); + nameToItem[3].insert(name, newItem); } } - for (auto item : nets_items.toStdMap()) { + for (auto item : nameToItem[3].toStdMap()) { nets_root->addChild(item.second); } // Add cells to tree cells_root = new QTreeWidgetItem(treeWidget); - QMap cells_items; cells_root->setText(0, "Cells"); treeWidget->insertTopLevelItem(0, cells_root); if (ctx) { for (auto &item : ctx->cells) { auto id = item.first; QString name = QString(id.c_str(ctx)); - cells_items.insert(name, new IdStringTreeItem(id, ElementType::CELL, name, nullptr)); + IdStringTreeItem *newItem = new IdStringTreeItem(id, ElementType::CELL, name, nullptr); + nameToItem[4].insert(name, newItem); } } - for (auto item : cells_items.toStdMap()) { + for (auto item : nameToItem[4].toStdMap()) { cells_root->addChild(item.second); } } @@ -368,6 +381,20 @@ QString DesignWidget::getElementTypeName(ElementType type) return "CELL"; return ""; } +int DesignWidget::getElementIndex(ElementType type) +{ + if (type == ElementType::BEL) + return 0; + if (type == ElementType::WIRE) + return 1; + if (type == ElementType::PIP) + return 2; + if (type == ElementType::NET) + return 3; + if (type == ElementType::CELL) + return 4; + return -1; +} ElementType DesignWidget::getElementTypeByName(QString type) { @@ -615,7 +642,6 @@ void DesignWidget::prepareMenuProperty(const QPoint &pos) QtBrowserItem *browserItem = propertyEditor->itemToBrowserItem(itemContextMenu); - // if (((ElementTreeItem*)itemContextMenu)->getType() == ElementType::NONE) return; QMenu menu(this); QAction *selectAction = new QAction("&Select", this); connect(selectAction, &QAction::triggered, this, [this, browserItem] { onCurrentPropertySelected(browserItem); }); @@ -629,13 +655,15 @@ void DesignWidget::onItemDoubleClicked(QTreeWidgetItem *item, int column) { QtProperty *selectedProperty = propertyEditor->itemToBrowserItem(item)->property(); ElementType type = getElementTypeByName(selectedProperty->propertyId()); - IdString value = ctx->id(selectedProperty->valueText().toStdString()); + QString value = selectedProperty->valueText(); + int index = getElementIndex(type); switch (type) { case ElementType::NONE: return; - default: - Q_EMIT info("double clicked " + std::string(value.c_str(ctx)) + "\n"); - break; + default: { + if (nameToItem[index].contains(value)) + treeWidget->setCurrentItem(nameToItem[index].value(value)); + } break; } } diff --git a/gui/designwidget.h b/gui/designwidget.h index 50f00bbe..8f2fa375 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -56,6 +56,7 @@ class DesignWidget : public QWidget const ElementType &type = ElementType::NONE); QString getElementTypeName(ElementType type); ElementType getElementTypeByName(QString type); + int getElementIndex(ElementType type); Q_SIGNALS: void info(std::string text); void selected(std::vector decal); @@ -83,6 +84,9 @@ class DesignWidget : public QWidget QMap propertyToId; QMap idToProperty; + + QMap nameToItem[6]; + QTreeWidgetItem *nets_root; QTreeWidgetItem *cells_root; diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index 772ca6ac..28792ed3 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -71,43 +71,43 @@ void MainWindow::createMenu() QMenu *menu_Design = new QMenu("&Design", menuBar); menuBar->addAction(menu_Design->menuAction()); - actionLoadJSON = new QAction("Open JSON", this); + actionLoadJSON = new QAction("Open JSON", this); actionLoadJSON->setIcon(QIcon(":/icons/resources/open_json.png")); actionLoadJSON->setStatusTip("Open an existing JSON file"); actionLoadJSON->setEnabled(true); connect(actionLoadJSON, SIGNAL(triggered()), this, SLOT(open_json())); - actionLoadPCF = new QAction("Open PCF", this); + actionLoadPCF = new QAction("Open PCF", this); actionLoadPCF->setIcon(QIcon(":/icons/resources/open_pcf.png")); actionLoadPCF->setStatusTip("Open PCF file"); actionLoadPCF->setEnabled(false); connect(actionLoadPCF, SIGNAL(triggered()), this, SLOT(open_pcf())); - actionPack = new QAction("Pack", this); + actionPack = new QAction("Pack", this); actionPack->setIcon(QIcon(":/icons/resources/pack.png")); actionPack->setStatusTip("Pack current design"); actionPack->setEnabled(false); connect(actionPack, SIGNAL(triggered()), task, SIGNAL(pack())); - actionAssignBudget = new QAction("Assign Budget", this); + actionAssignBudget = new QAction("Assign Budget", this); actionAssignBudget->setIcon(QIcon(":/icons/resources/time_add.png")); actionAssignBudget->setStatusTip("Assign time budget for current design"); actionAssignBudget->setEnabled(false); connect(actionAssignBudget, SIGNAL(triggered()), this, SLOT(budget())); - actionPlace = new QAction("Place", this); + actionPlace = new QAction("Place", this); actionPlace->setIcon(QIcon(":/icons/resources/place.png")); actionPlace->setStatusTip("Place current design"); actionPlace->setEnabled(false); connect(actionPlace, SIGNAL(triggered()), this, SLOT(place())); - actionRoute = new QAction("Route", this); + actionRoute = new QAction("Route", this); actionRoute->setIcon(QIcon(":/icons/resources/route.png")); actionRoute->setStatusTip("Route current design"); actionRoute->setEnabled(false); connect(actionRoute, SIGNAL(triggered()), task, SIGNAL(route())); - actionSaveAsc = new QAction("Save ASC", this); + actionSaveAsc = new QAction("Save ASC", this); actionSaveAsc->setIcon(QIcon(":/icons/resources/save_asc.png")); actionSaveAsc->setStatusTip("Save ASC file"); actionSaveAsc->setEnabled(false); @@ -132,19 +132,19 @@ void MainWindow::createMenu() menu_Design->addAction(actionRoute); menu_Design->addAction(actionSaveAsc); - actionPlay = new QAction("Play", this); + actionPlay = new QAction("Play", this); actionPlay->setIcon(QIcon(":/icons/resources/control_play.png")); actionPlay->setStatusTip("Continue running task"); actionPlay->setEnabled(false); connect(actionPlay, SIGNAL(triggered()), task, SLOT(continue_thread())); - actionPause = new QAction("Pause", this); + actionPause = new QAction("Pause", this); actionPause->setIcon(QIcon(":/icons/resources/control_pause.png")); actionPause->setStatusTip("Pause running task"); actionPause->setEnabled(false); connect(actionPause, SIGNAL(triggered()), task, SLOT(pause_thread())); - actionStop = new QAction("Stop", this); + actionStop = new QAction("Stop", this); actionStop->setIcon(QIcon(":/icons/resources/control_stop.png")); actionStop->setStatusTip("Stop running task"); actionStop->setEnabled(false); -- cgit v1.2.3 From 82c9fef3de1017d39a15b5c23be84a8f3c8bebc0 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 15 Jul 2018 16:20:35 +0200 Subject: added browsing history --- gui/designwidget.cc | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ gui/designwidget.h | 5 +++++ 2 files changed, 61 insertions(+) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 2b0c43c0..698e4ca8 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -88,18 +88,42 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net actionFirst = new QAction("", this); actionFirst->setIcon(QIcon(":/icons/resources/resultset_first.png")); actionFirst->setEnabled(false); + connect(actionFirst, &QAction::triggered, this, [this] { + history_ignore = true; + history_index = 0; + treeWidget->setCurrentItem(history.at(history_index)); + updateButtons(); + }); actionPrev = new QAction("", this); actionPrev->setIcon(QIcon(":/icons/resources/resultset_previous.png")); actionPrev->setEnabled(false); + connect(actionPrev, &QAction::triggered, this, [this] { + history_ignore = true; + history_index--; + treeWidget->setCurrentItem(history.at(history_index)); + updateButtons(); + }); actionNext = new QAction("", this); actionNext->setIcon(QIcon(":/icons/resources/resultset_next.png")); actionNext->setEnabled(false); + connect(actionNext, &QAction::triggered, this, [this] { + history_ignore = true; + history_index++; + treeWidget->setCurrentItem(history.at(history_index)); + updateButtons(); + }); actionLast = new QAction("", this); actionLast->setIcon(QIcon(":/icons/resources/resultset_last.png")); actionLast->setEnabled(false); + connect(actionLast, &QAction::triggered, this, [this] { + history_ignore = true; + history_index = int(history.size() - 1); + treeWidget->setCurrentItem(history.at(history_index)); + updateButtons(); + }); QToolBar *toolbar = new QToolBar(); toolbar->addAction(actionFirst); @@ -148,13 +172,43 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net connect(propertyEditor->treeWidget(), &QTreeWidget::itemDoubleClicked, this, &DesignWidget::onItemDoubleClicked); connect(treeWidget, SIGNAL(itemSelectionChanged()), SLOT(onItemSelectionChanged())); + + history_index = -1; + history_ignore = false; } DesignWidget::~DesignWidget() {} +void DesignWidget::updateButtons() +{ + int count = int(history.size()); + actionFirst->setEnabled(history_index > 0); + actionPrev->setEnabled(history_index > 0); + actionNext->setEnabled(history_index < (count - 1)); + actionLast->setEnabled(history_index < (count - 1)); +} + +void DesignWidget::addToHistory(QTreeWidgetItem *item) +{ + if (!history_ignore) { + int count = int(history.size()); + for (int i = count - 1; i > history_index; i--) + history.pop_back(); + history.push_back(item); + history_index++; + } + history_ignore = false; + updateButtons(); +} + void DesignWidget::newContext(Context *ctx) { treeWidget->clear(); + history_ignore = false; + history_index = -1; + history.clear(); + updateButtons(); + for (int i = 0; i < 6; i++) nameToItem[i].clear(); @@ -444,6 +498,8 @@ void DesignWidget::onItemSelectionChanged() std::vector decals; + addToHistory(clickItem); + clearProperties(); if (type == ElementType::BEL) { IdString c = static_cast(clickItem)->getData(); diff --git a/gui/designwidget.h b/gui/designwidget.h index 8f2fa375..2733e6cf 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -57,6 +57,8 @@ class DesignWidget : public QWidget QString getElementTypeName(ElementType type); ElementType getElementTypeByName(QString type); int getElementIndex(ElementType type); + void updateButtons(); + void addToHistory(QTreeWidgetItem *item); Q_SIGNALS: void info(std::string text); void selected(std::vector decal); @@ -86,6 +88,9 @@ class DesignWidget : public QWidget QMap idToProperty; QMap nameToItem[6]; + std::vector history; + int history_index; + bool history_ignore; QTreeWidgetItem *nets_root; QTreeWidgetItem *cells_root; -- cgit v1.2.3 From ecc4c3fa7bdf1726377cd5cf2199b3cabd233427 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 15 Jul 2018 17:50:58 +0200 Subject: added highlight groups --- gui/basewindow.cc | 3 + gui/designwidget.cc | 165 +++++++++++++++++++++++++++++++++++++------------- gui/designwidget.h | 8 ++- gui/fpgaviewwidget.cc | 36 +++++++++-- gui/fpgaviewwidget.h | 8 ++- 5 files changed, 173 insertions(+), 47 deletions(-) diff --git a/gui/basewindow.cc b/gui/basewindow.cc index a57d3ef1..22e47295 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -84,6 +84,9 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent connect(designview, SIGNAL(selected(std::vector)), fpgaView, SLOT(onSelectedArchItem(std::vector))); + connect(designview, SIGNAL(highlight(std::vector, int)), fpgaView, + SLOT(onHighlightGroupChanged(std::vector, int))); + splitter_v->addWidget(centralTabWidget); splitter_v->addWidget(tabWidget); } diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 698e4ca8..1f039c60 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -172,9 +172,19 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net connect(propertyEditor->treeWidget(), &QTreeWidget::itemDoubleClicked, this, &DesignWidget::onItemDoubleClicked); connect(treeWidget, SIGNAL(itemSelectionChanged()), SLOT(onItemSelectionChanged())); + connect(treeWidget, &QTreeWidget::customContextMenuRequested, this, &DesignWidget::prepareMenuTree); history_index = -1; history_ignore = false; + + highlightColors[0] = QColor("#6495ed"); + highlightColors[1] = QColor("#7fffd4"); + highlightColors[2] = QColor("#98fb98"); + highlightColors[3] = QColor("#ffd700"); + highlightColors[4] = QColor("#cd5c5c"); + highlightColors[5] = QColor("#fa8072"); + highlightColors[6] = QColor("#ff69b4"); + highlightColors[7] = QColor("#da70d6"); } DesignWidget::~DesignWidget() {} @@ -380,45 +390,6 @@ void DesignWidget::clearProperties() idToProperty.clear(); } -void DesignWidget::onCurrentPropertySelected(QtBrowserItem *_item) -{ - if (_item) { - QtProperty *selectedProperty = _item->property(); - ElementType type = getElementTypeByName(selectedProperty->propertyId()); - IdString value = ctx->id(selectedProperty->valueText().toStdString()); - std::vector decals; - switch (type) { - case ElementType::BEL: { - BelId bel = ctx->getBelByName(value); - if (bel != BelId()) { - decals.push_back(ctx->getBelDecal(bel)); - Q_EMIT selected(decals); - } - } break; - case ElementType::WIRE: { - WireId wire = ctx->getWireByName(value); - if (wire != WireId()) { - decals.push_back(ctx->getWireDecal(wire)); - Q_EMIT selected(decals); - } - } break; - case ElementType::PIP: { - PipId pip = ctx->getPipByName(value); - if (pip != PipId()) { - decals.push_back(ctx->getPipDecal(pip)); - Q_EMIT selected(decals); - } - } break; - case ElementType::NET: { - } break; - case ElementType::CELL: { - } break; - default: - break; - } - } -} - QString DesignWidget::getElementTypeName(ElementType type) { if (type == ElementType::NONE) @@ -688,6 +659,64 @@ void DesignWidget::onItemSelectionChanged() } } +std::vector DesignWidget::getDecals(ElementType type, IdString value) +{ + std::vector decals; + switch (type) { + case ElementType::BEL: { + BelId bel = ctx->getBelByName(value); + if (bel != BelId()) { + decals.push_back(ctx->getBelDecal(bel)); + } + } break; + case ElementType::WIRE: { + WireId wire = ctx->getWireByName(value); + if (wire != WireId()) { + decals.push_back(ctx->getWireDecal(wire)); + Q_EMIT selected(decals); + } + } break; + case ElementType::PIP: { + PipId pip = ctx->getPipByName(value); + if (pip != PipId()) { + decals.push_back(ctx->getPipDecal(pip)); + Q_EMIT selected(decals); + } + } break; + case ElementType::NET: { + } break; + case ElementType::CELL: { + } break; + default: + break; + } + return decals; +} + +void DesignWidget::updateHighlightGroup(QTreeWidgetItem *item, int group) +{ + if (highlightSelected.contains(item)) { + if (highlightSelected[item] == group) { + highlightSelected.remove(item); + } else + highlightSelected[item] = group; + } else + highlightSelected.insert(item, group); + + std::vector decals; + + for (auto it : highlightSelected.toStdMap()) { + if (it.second == group) { + ElementType type = static_cast(it.first)->getType(); + IdString value = static_cast(it.first)->getData(); + std::vector d = getDecals(type, value); + std::move(d.begin(), d.end(), std::back_inserter(decals)); + } + } + + Q_EMIT highlight(decals, group); +} + void DesignWidget::prepareMenuProperty(const QPoint &pos) { QTreeWidget *tree = propertyEditor->treeWidget(); @@ -697,13 +726,67 @@ void DesignWidget::prepareMenuProperty(const QPoint &pos) return; QtBrowserItem *browserItem = propertyEditor->itemToBrowserItem(itemContextMenu); + if (!browserItem) + return; + QtProperty *selectedProperty = browserItem->property(); + ElementType type = getElementTypeByName(selectedProperty->propertyId()); + if (type == ElementType::NONE) + return; + IdString value = ctx->id(selectedProperty->valueText().toStdString()); + + QTreeWidgetItem *item = nameToItem[getElementIndex(type)].value(value.c_str(ctx)); QMenu menu(this); QAction *selectAction = new QAction("&Select", this); - connect(selectAction, &QAction::triggered, this, [this, browserItem] { onCurrentPropertySelected(browserItem); }); - + connect(selectAction, &QAction::triggered, this, [this, type, value] { Q_EMIT selected(getDecals(type, value)); }); menu.addAction(selectAction); + QMenu *subMenu = menu.addMenu("Highlight"); + QActionGroup *group = new QActionGroup(this); + group->setExclusive(true); + for (int i = 0; i < 8; i++) { + QPixmap pixmap(32, 32); + pixmap.fill(QColor(highlightColors[i])); + QAction *action = new QAction(QIcon(pixmap), ("Group " + std::to_string(i)).c_str(), this); + action->setCheckable(true); + subMenu->addAction(action); + group->addAction(action); + if (highlightSelected.contains(item) && highlightSelected[item] == i) + action->setChecked(true); + connect(action, &QAction::triggered, this, [this, i, item] { updateHighlightGroup(item, i); }); + } + menu.exec(tree->mapToGlobal(pos)); +} + +void DesignWidget::prepareMenuTree(const QPoint &pos) +{ + QTreeWidget *tree = treeWidget; + + itemContextMenu = tree->itemAt(pos); + + ElementType type = static_cast(itemContextMenu)->getType(); + IdString value = static_cast(itemContextMenu)->getData(); + + if (type == ElementType::NONE) + return; + + QTreeWidgetItem *item = nameToItem[getElementIndex(type)].value(value.c_str(ctx)); + + QMenu menu(this); + QMenu *subMenu = menu.addMenu("Highlight"); + QActionGroup *group = new QActionGroup(this); + group->setExclusive(true); + for (int i = 0; i < 8; i++) { + QPixmap pixmap(32, 32); + pixmap.fill(QColor(highlightColors[i])); + QAction *action = new QAction(QIcon(pixmap), ("Group " + std::to_string(i)).c_str(), this); + action->setCheckable(true); + subMenu->addAction(action); + group->addAction(action); + if (highlightSelected.contains(item) && highlightSelected[item] == i) + action->setChecked(true); + connect(action, &QAction::triggered, this, [this, i, item] { updateHighlightGroup(item, i); }); + } menu.exec(tree->mapToGlobal(pos)); } diff --git a/gui/designwidget.h b/gui/designwidget.h index 2733e6cf..269e32fa 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -59,15 +59,18 @@ class DesignWidget : public QWidget int getElementIndex(ElementType type); void updateButtons(); void addToHistory(QTreeWidgetItem *item); + std::vector getDecals(ElementType type, IdString value); + void updateHighlightGroup(QTreeWidgetItem *item, int group); Q_SIGNALS: void info(std::string text); void selected(std::vector decal); + void highlight(std::vector decal, int group); private Q_SLOTS: void prepareMenuProperty(const QPoint &pos); + void prepareMenuTree(const QPoint &pos); void onItemSelectionChanged(); void onItemDoubleClicked(QTreeWidgetItem *item, int column); - void onCurrentPropertySelected(QtBrowserItem *_item); public Q_SLOTS: void newContext(Context *ctx); void updateTree(); @@ -99,6 +102,9 @@ class DesignWidget : public QWidget QAction *actionPrev; QAction *actionNext; QAction *actionLast; + + QColor highlightColors[8]; + QMap highlightSelected; }; NEXTPNR_NAMESPACE_END diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index cb60bc76..2d8d4cef 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -241,7 +241,7 @@ void LineShader::draw(const LineShaderData &line, const QColor &color, float thi } FPGAViewWidget::FPGAViewWidget(QWidget *parent) - : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), selectedItemsChanged(false) + : QOpenGLWidget(parent), lineShader_(this), zoom_(500.f), ctx_(nullptr), selectedItemsChanged_(false) { backgroundColor_ = QColor("#000000"); gridColor_ = QColor("#333"); @@ -251,6 +251,16 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) gActiveColor_ = QColor("#f0f0f0"); gSelectedColor_ = QColor("#ff6600"); frameColor_ = QColor("#0066ba"); + highlightColors[0] = QColor("#6495ed"); + highlightColors[1] = QColor("#7fffd4"); + highlightColors[2] = QColor("#98fb98"); + highlightColors[3] = QColor("#ffd700"); + highlightColors[4] = QColor("#cd5c5c"); + highlightColors[5] = QColor("#fa8072"); + highlightColors[6] = QColor("#ff69b4"); + highlightColors[7] = QColor("#da70d6"); + for (int i = 0; i < 8; i++) + highlightItemsChanged_[i] = false; auto fmt = format(); fmt.setMajorVersion(3); @@ -413,26 +423,44 @@ void FPGAViewWidget::paintGL() drawDecal(shaders, ctx_->getGroupDecal(group)); } - if (selectedItemsChanged) { - selectedItemsChanged = false; + if (selectedItemsChanged_) { + selectedItemsChanged_ = false; selectedShader_.clear(); for (auto decal : selectedItems_) { drawDecal(selectedShader_, decal); } } + for (int i = 0; i < 8; i++) { + if (highlightItemsChanged_[i]) { + highlightItemsChanged_[i] = false; + highlightShader_[i].clear(); + for (auto decal : highlightItems_[i]) { + drawDecal(highlightShader_[i], decal); + } + } + } } lineShader_.draw(shaders[0], gFrameColor_, thick11Px, matrix); lineShader_.draw(shaders[1], gHiddenColor_, thick11Px, matrix); lineShader_.draw(shaders[2], gInactiveColor_, thick11Px, matrix); lineShader_.draw(shaders[3], gActiveColor_, thick11Px, matrix); + for (int i = 0; i < 8; i++) + lineShader_.draw(highlightShader_[i], highlightColors[i], thick11Px, matrix); lineShader_.draw(selectedShader_, gSelectedColor_, thick11Px, matrix); } void FPGAViewWidget::onSelectedArchItem(std::vector decals) { selectedItems_ = decals; - selectedItemsChanged = true; + selectedItemsChanged_ = true; + update(); +} + +void FPGAViewWidget::onHighlightGroupChanged(std::vector decals, int group) +{ + highlightItems_[group] = decals; + highlightItemsChanged_[group] = true; update(); } diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index ea4a17cf..33eb2800 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -245,6 +245,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions public Q_SLOTS: void newContext(Context *ctx); void onSelectedArchItem(std::vector decals); + void onHighlightGroupChanged(std::vector decals, int group); private: QPoint lastPos_; @@ -273,7 +274,12 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions LineShaderData selectedShader_; std::vector selectedItems_; - bool selectedItemsChanged; + bool selectedItemsChanged_; + + LineShaderData highlightShader_[8]; + std::vector highlightItems_[8]; + bool highlightItemsChanged_[8]; + QColor highlightColors[8]; }; NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From 8e12ae2cfed728ee1ecab4e5f60f0435bf2d58b8 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 15 Jul 2018 20:31:42 +0200 Subject: Added splash screen info while loading --- gui/base.qrc | 1 + gui/basewindow.cc | 30 ++++++++++++++++++++++++------ gui/basewindow.h | 6 ++++++ gui/designwidget.cc | 5 +++++ gui/designwidget.h | 2 ++ gui/ice40/mainwindow.cc | 1 + gui/resources/splash.png | Bin 0 -> 4651 bytes 7 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 gui/resources/splash.png diff --git a/gui/base.qrc b/gui/base.qrc index 8f07aabe..bf21986b 100644 --- a/gui/base.qrc +++ b/gui/base.qrc @@ -9,5 +9,6 @@ resources/resultset_previous.png resources/resultset_next.png resources/resultset_last.png + resources/splash.png diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 22e47295..07b71105 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -61,15 +62,10 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent setCentralWidget(centralWidget); - DesignWidget *designview = new DesignWidget(); + designview = new DesignWidget(); designview->setMinimumWidth(300); splitter_h->addWidget(designview); - connect(this, SIGNAL(contextChanged(Context *)), designview, SLOT(newContext(Context *))); - connect(this, SIGNAL(updateTreeView()), designview, SLOT(updateTree())); - - connect(designview, SIGNAL(info(std::string)), this, SLOT(writeInfo(std::string))); - tabWidget = new QTabWidget(); console = new PythonTab(); @@ -87,12 +83,34 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent connect(designview, SIGNAL(highlight(std::vector, int)), fpgaView, SLOT(onHighlightGroupChanged(std::vector, int))); + connect(this, SIGNAL(contextChanged(Context *)), designview, SLOT(newContext(Context *))); + connect(this, SIGNAL(updateTreeView()), designview, SLOT(updateTree())); + + connect(designview, SIGNAL(info(std::string)), this, SLOT(writeInfo(std::string))); + splitter_v->addWidget(centralTabWidget); splitter_v->addWidget(tabWidget); + displaySplash(); } BaseMainWindow::~BaseMainWindow() {} +void BaseMainWindow::displaySplash() +{ + splash = new QSplashScreen(); + splash->setPixmap(QPixmap(":/icons/resources/splash.png")); + splash->show(); + connect(designview, SIGNAL(finishContextLoad()), splash, SLOT(close())); + connect(designview, SIGNAL(contextLoadStatus(std::string)), this, SLOT(displaySplashMessage(std::string))); + QCoreApplication::instance()->processEvents(); +} + +void BaseMainWindow::displaySplashMessage(std::string msg) +{ + splash->showMessage(msg.c_str(), Qt::AlignCenter | Qt::AlignBottom, Qt::white); + QCoreApplication::instance()->processEvents(); +} + void BaseMainWindow::writeInfo(std::string text) { console->info(text); } void BaseMainWindow::createMenusAndBars() diff --git a/gui/basewindow.h b/gui/basewindow.h index 4d3d80a1..18b5339e 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ Q_DECLARE_METATYPE(NEXTPNR_NAMESPACE_PREFIX DecalXY) NEXTPNR_NAMESPACE_BEGIN class PythonTab; +class DesignWidget; class BaseMainWindow : public QMainWindow { @@ -48,9 +50,11 @@ class BaseMainWindow : public QMainWindow protected: void createMenusAndBars(); + void displaySplash(); protected Q_SLOTS: void writeInfo(std::string text); + void displaySplashMessage(std::string msg); virtual void new_proj() = 0; virtual void open_proj() = 0; @@ -72,6 +76,8 @@ class BaseMainWindow : public QMainWindow QAction *actionNew; QAction *actionOpen; QProgressBar *progressBar; + QSplashScreen *splash; + DesignWidget *designview; }; NEXTPNR_NAMESPACE_END diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 1f039c60..8b9e9d22 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -230,6 +230,7 @@ void DesignWidget::newContext(Context *ctx) bel_root->setText(0, "Bels"); treeWidget->insertTopLevelItem(0, bel_root); if (ctx) { + Q_EMIT contextLoadStatus("Configuring bels..."); for (auto bel : ctx->getBels()) { auto id = ctx->getBelName(bel); QStringList items = QString(id.c_str(ctx)).split("/"); @@ -262,6 +263,7 @@ void DesignWidget::newContext(Context *ctx) wire_root->setText(0, "Wires"); treeWidget->insertTopLevelItem(0, wire_root); if (ctx) { + Q_EMIT contextLoadStatus("Configuring wires..."); for (auto wire : ctx->getWires()) { auto id = ctx->getWireName(wire); QStringList items = QString(id.c_str(ctx)).split("/"); @@ -293,6 +295,7 @@ void DesignWidget::newContext(Context *ctx) pip_root->setText(0, "Pips"); treeWidget->insertTopLevelItem(0, pip_root); if (ctx) { + Q_EMIT contextLoadStatus("Configuring pips..."); for (auto pip : ctx->getPips()) { auto id = ctx->getPipName(pip); QStringList items = QString(id.c_str(ctx)).split("/"); @@ -328,6 +331,8 @@ void DesignWidget::newContext(Context *ctx) cells_root = new QTreeWidgetItem(treeWidget); cells_root->setText(0, "Cells"); treeWidget->insertTopLevelItem(0, cells_root); + + Q_EMIT finishContextLoad(); } void DesignWidget::updateTree() diff --git a/gui/designwidget.h b/gui/designwidget.h index 269e32fa..1afe817d 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -65,6 +65,8 @@ class DesignWidget : public QWidget void info(std::string text); void selected(std::vector decal); void highlight(std::vector decal, int group); + void finishContextLoad(); + void contextLoadStatus(std::string text); private Q_SLOTS: void prepareMenuProperty(const QPoint &pos); diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index 28792ed3..4b1f2c57 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -226,6 +226,7 @@ void MainWindow::new_proj() ctx = std::unique_ptr(new Context(chipArgs)); actionLoadJSON->setEnabled(true); + Q_EMIT displaySplash(); Q_EMIT contextChanged(ctx.get()); } } diff --git a/gui/resources/splash.png b/gui/resources/splash.png new file mode 100644 index 00000000..14d2842b Binary files /dev/null and b/gui/resources/splash.png differ -- cgit v1.2.3 From 21bf78dae9ef95e65b549c60061bce9790b1b611 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 15 Jul 2018 21:06:04 +0200 Subject: Make at least 50 of pips available in uphill/downhill --- gui/designwidget.cc | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 8b9e9d22..335ed929 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -528,17 +528,28 @@ void DesignWidget::onItemSelectionChanged() addProperty(dhItem, QVariant::String, "Bel", belname, ElementType::BEL); addProperty(dhItem, QVariant::String, "PortPin", pinname); } - /* - QtProperty *pipsDownItem = addSubGroup(downhillItem, "Pips Downhill"); - for (const auto &item : ctx->getPipsDownhill(wire)) { - addProperty(pipsDownItem, QVariant::String, "", ctx->getPipName(item).c_str(ctx), ElementType::PIP); - } - QtProperty *pipsUpItem = addSubGroup(downhillItem, "Pips Uphill"); - for (const auto &item : ctx->getPipsUphill(wire)) { - addProperty(pipsUpItem, QVariant::String, "", ctx->getPipName(item).c_str(ctx), ElementType::PIP); - } - */ + int counter = 0; + QtProperty *pipsDownItem = addSubGroup(downhillItem, "Pips Downhill"); + for (const auto &item : ctx->getPipsDownhill(wire)) { + addProperty(pipsDownItem, QVariant::String, "", ctx->getPipName(item).c_str(ctx), ElementType::PIP); + counter++; + if (counter == 50) { + addProperty(pipsDownItem, QVariant::String, "Warning", "Too many items...", ElementType::NONE); + break; + } + } + + counter = 0; + QtProperty *pipsUpItem = addSubGroup(downhillItem, "Pips Uphill"); + for (const auto &item : ctx->getPipsUphill(wire)) { + addProperty(pipsUpItem, QVariant::String, "", ctx->getPipName(item).c_str(ctx), ElementType::PIP); + counter++; + if (counter == 50) { + addProperty(pipsUpItem, QVariant::String, "Warning", "Too many items...", ElementType::NONE); + break; + } + } } else if (type == ElementType::PIP) { IdString c = static_cast(clickItem)->getData(); PipId pip = ctx->getPipByName(c); -- cgit v1.2.3