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 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 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