From 3ef85b30b461972d264d7e259eca25762356c16e Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 17 Jul 2018 17:24:01 +0200 Subject: [PATCH 01/28] proper fix --- gui/yosystab.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gui/yosystab.cc b/gui/yosystab.cc index d83b969e..9bbd9c12 100644 --- a/gui/yosystab.cc +++ b/gui/yosystab.cc @@ -61,9 +61,9 @@ YosysTab::YosysTab(QString folder, QWidget *parent) : QWidget(parent) connect(process, SIGNAL(readyReadStandardError()), this, SLOT(onReadyReadStandardError())); connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadyReadStandardOutput())); connect(process, &QProcess::started, this, [this] { lineEdit->setEnabled(true); }); -/* + #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0) - connect(process, &QProcess::error, this, [this](QProcess::ProcessError error) { + connect(process, static_cast(&QProcess::error), this, [this](QProcess::ProcessError error) { #else connect(process, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) { #endif @@ -74,7 +74,6 @@ YosysTab::YosysTab(QString folder, QWidget *parent) : QWidget(parent) Q_EMIT deleteLater(); } }); -*/ process->setWorkingDirectory(folder); process->start("yosys"); } From ddfc535df766a8d6091e6c043b74bb6a40c8d2b7 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 17 Jul 2018 20:04:49 +0200 Subject: [PATCH 02/28] Add ArchNetInfo and ArchCellInfo Signed-off-by: Clifford Wolf --- common/nextpnr.h | 4 ++-- ecp5/archdefs.h | 3 +++ generic/archdefs.h | 3 +++ ice40/archdefs.h | 4 +++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 50465869..3d0cc955 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -200,7 +200,7 @@ struct PipMap PlaceStrength strength = STRENGTH_NONE; }; -struct NetInfo +struct NetInfo : ArchNetInfo { IdString name; PortRef driver; @@ -225,7 +225,7 @@ struct PortInfo PortType type; }; -struct CellInfo +struct CellInfo : ArchCellInfo { IdString name, type; std::unordered_map ports; diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index 84a431fd..df1add44 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -129,6 +129,9 @@ struct DecalId } }; +struct ArchNetInfo { }; +struct ArchCellInfo { }; + NEXTPNR_NAMESPACE_END namespace std { diff --git a/generic/archdefs.h b/generic/archdefs.h index 9969014b..f5999776 100644 --- a/generic/archdefs.h +++ b/generic/archdefs.h @@ -52,4 +52,7 @@ typedef IdString PipId; typedef IdString GroupId; typedef IdString DecalId; +struct ArchNetInfo { }; +struct ArchCellInfo { }; + NEXTPNR_NAMESPACE_END diff --git a/ice40/archdefs.h b/ice40/archdefs.h index 75df678a..ce7d3f52 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -150,6 +150,9 @@ struct DecalId bool operator!=(const DecalId &other) const { return (type != other.type) || (index != other.index); } }; +struct ArchNetInfo { }; +struct ArchCellInfo { }; + NEXTPNR_NAMESPACE_END namespace std { @@ -201,5 +204,4 @@ template <> struct hash return seed; } }; - } // namespace std From edf7bd09cf2a27fa1ada1a1e34cbe47c4bf0d48a Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 17 Jul 2018 21:51:24 +0200 Subject: [PATCH 03/28] ecp5: Function to handle constant LUT inputs Signed-off-by: David Shah --- ecp5/pack.cc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 1900eded..c0427d46 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -359,6 +359,32 @@ class Ecp5Packer flush_cells(); } + void set_lut_input_constant(CellInfo *cell, IdString input, bool value) + { + int index = std::string("ABCD").find(input.str(ctx)); + int init = int_or_default(cell->params, ctx->id("INIT")); + int new_init = 0; + for (int i = 0; i < 16; i++) { + if (((i >> index) & 0x1) != value) { + int other_i = (i & (~(1 << index))) | (value << index); + if ((init >> other_i) & 0x1) + new_init |= (1 << i); + } else { + if ((init >> i) & 0x1) + new_init |= (1 << i); + } + } + cell->params[ctx->id("INIT")] = std::to_string(init); + NetInfo *innet = cell->ports.at(input).net; + if (innet != nullptr) { + innet->users.erase( + std::remove_if(innet->users.begin(), innet->users.end(), + [cell, input](PortRef port) { return port.cell == cell && port.port == input; }), + innet->users.end()); + } + cell->ports.at(input).net = nullptr; + } + public: void pack() { From f138368e343d0d69b6e1f74d44e13d7097999de6 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 18 Jul 2018 09:35:40 +0200 Subject: [PATCH 04/28] ecp5: Add simple constant packer Signed-off-by: David Shah --- ecp5/archdefs.h | 8 +++-- ecp5/cells.cc | 8 +++++ ecp5/pack.cc | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 2 deletions(-) diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index df1add44..941607ba 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -129,8 +129,12 @@ struct DecalId } }; -struct ArchNetInfo { }; -struct ArchCellInfo { }; +struct ArchNetInfo +{ +}; +struct ArchCellInfo +{ +}; NEXTPNR_NAMESPACE_END diff --git a/ecp5/cells.cc b/ecp5/cells.cc index 59504735..22e6a8dc 100644 --- a/ecp5/cells.cc +++ b/ecp5/cells.cc @@ -116,6 +116,14 @@ std::unique_ptr create_ecp5_cell(Context *ctx, IdString type, std::str add_port(ctx, new_cell.get(), "I", PORT_IN); add_port(ctx, new_cell.get(), "T", PORT_IN); add_port(ctx, new_cell.get(), "O", PORT_OUT); + } else if (type == ctx->id("LUT4")) { + new_cell->params[ctx->id("INIT")] = "0"; + + add_port(ctx, new_cell.get(), "A", PORT_IN); + add_port(ctx, new_cell.get(), "B", PORT_IN); + add_port(ctx, new_cell.get(), "C", PORT_IN); + add_port(ctx, new_cell.get(), "D", PORT_IN); + add_port(ctx, new_cell.get(), "Z", PORT_OUT); } else { log_error("unable to create ECP5 cell of type %s", type.c_str(ctx)); } diff --git a/ecp5/pack.cc b/ecp5/pack.cc index c0427d46..47f22e55 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -385,10 +385,94 @@ class Ecp5Packer cell->ports.at(input).net = nullptr; } + // Merge a net into a constant net + void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval) + { + orig->driver.cell = nullptr; + for (auto user : orig->users) { + if (user.cell != nullptr) { + CellInfo *uc = user.cell; + if (ctx->verbose) + log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx)); + if (is_lut(ctx, uc)) { + set_lut_input_constant(uc, user.port, constval); + } else if (is_ff(ctx, uc) && user.port == ctx->id("CE")) { + uc->params[ctx->id("CEMUX")] = constval ? "1" : "0"; + uc->ports[user.port].net = nullptr; + } else if (is_ff(ctx, uc) && user.port == ctx->id("LSR") && + ((!constval && str_or_default(uc->params, ctx->id("LSRMUX"), "LSR") == "LSR") || + (constval && str_or_default(uc->params, ctx->id("LSRMUX"), "LSR") == "INV"))) { + uc->ports[user.port].net = nullptr; + } else { + uc->ports[user.port].net = constnet; + constnet->users.push_back(user); + } + } + } + orig->users.clear(); + } + + // Pack constants (simple implementation) + void pack_constants() + { + log_info("Packing constants..\n"); + + std::unique_ptr gnd_cell = create_ecp5_cell(ctx, ctx->id("LUT4"), "$PACKER_GND"); + gnd_cell->params[ctx->id("LUT_INIT")] = "0"; + std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); + gnd_net->name = ctx->id("$PACKER_GND_NET"); + gnd_net->driver.cell = gnd_cell.get(); + gnd_net->driver.port = ctx->id("Z"); + gnd_cell->ports.at(ctx->id("Z")).net = gnd_net.get(); + + std::unique_ptr vcc_cell = create_ecp5_cell(ctx, ctx->id("LUT4"), "$PACKER_VCC"); + vcc_cell->params[ctx->id("LUT_INIT")] = "65535"; + std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); + vcc_net->name = ctx->id("$PACKER_VCC_NET"); + vcc_net->driver.cell = vcc_cell.get(); + vcc_net->driver.port = ctx->id("Z"); + vcc_cell->ports.at(ctx->id("Z")).net = vcc_net.get(); + + std::vector dead_nets; + + bool gnd_used = false, vcc_used = false; + + for (auto net : sorted(ctx->nets)) { + NetInfo *ni = net.second; + if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) { + IdString drv_cell = ni->driver.cell->name; + set_net_constant(ctx, ni, gnd_net.get(), false); + gnd_used = true; + dead_nets.push_back(net.first); + ctx->cells.erase(drv_cell); + } else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) { + IdString drv_cell = ni->driver.cell->name; + set_net_constant(ctx, ni, vcc_net.get(), true); + vcc_used = true; + dead_nets.push_back(net.first); + ctx->cells.erase(drv_cell); + } + } + + if (gnd_used) { + ctx->cells[gnd_cell->name] = std::move(gnd_cell); + ctx->nets[gnd_net->name] = std::move(gnd_net); + } + if (vcc_used) { + ctx->cells[vcc_cell->name] = std::move(vcc_cell); + ctx->nets[vcc_net->name] = std::move(vcc_net); + } + + for (auto dn : dead_nets) { + ctx->nets.erase(dn); + } + } + public: void pack() { pack_io(); + pack_constants(); find_lutff_pairs(); pack_lut5s(); pair_luts(); From 74cbaa5b83518d1743ae0a8fd335e7be1afb4f54 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 18 Jul 2018 09:52:53 +0200 Subject: [PATCH 05/28] ecp5: Simple packer working Signed-off-by: David Shah --- ecp5/cells.cc | 2 +- ecp5/pack.cc | 36 +++++++++++++++++++----------- ecp5/synth/blinky.v | 4 ++-- ecp5/synth/counter.v | 52 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 16 deletions(-) create mode 100644 ecp5/synth/counter.v diff --git a/ecp5/cells.cc b/ecp5/cells.cc index 22e6a8dc..e3532f36 100644 --- a/ecp5/cells.cc +++ b/ecp5/cells.cc @@ -177,7 +177,7 @@ void ff_to_slice(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool drive void lut_to_slice(Context *ctx, CellInfo *lut, CellInfo *lc, int index) { - lc->params[ctx->id("LUT" + std::to_string(index) + "_INITVAL")] = str_or_default(lc->params, ctx->id("INIT"), "0"); + lc->params[ctx->id("LUT" + std::to_string(index) + "_INITVAL")] = str_or_default(lut->params, ctx->id("INIT"), "0"); replace_port(lut, ctx->id("A"), lc, ctx->id("A" + std::to_string(index))); replace_port(lut, ctx->id("B"), lc, ctx->id("B" + std::to_string(index))); replace_port(lut, ctx->id("C"), lc, ctx->id("C" + std::to_string(index))); diff --git a/ecp5/pack.cc b/ecp5/pack.cc index 47f22e55..da5b3ec5 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -71,6 +71,15 @@ class Ecp5Packer } } + const NetInfo *net_or_nullptr(CellInfo *cell, IdString port) + { + auto fnd = cell->ports.find(port); + if (fnd == cell->ports.end()) + return nullptr; + else + return fnd->second.net; + } + // Return whether two FFs can be packed together in the same slice bool can_pack_ffs(CellInfo *ff0, CellInfo *ff1) { @@ -88,11 +97,11 @@ class Ecp5Packer if (str_or_default(ff0->params, ctx->id("CLKMUX"), "CLK") != str_or_default(ff1->params, ctx->id("CLKMUX"), "CLK")) return false; - if (ff0->ports.at(ctx->id("CLK")).net != ff1->ports.at(ctx->id("CLK")).net) + if (net_or_nullptr(ff0, ctx->id("CLK")) != net_or_nullptr(ff1, ctx->id("CLK"))) return false; - if (ff0->ports.at(ctx->id("CE")).net != ff1->ports.at(ctx->id("CE")).net) + if (net_or_nullptr(ff0, ctx->id("CE")) != net_or_nullptr(ff1, ctx->id("CE"))) return false; - if (ff0->ports.at(ctx->id("LSR")).net != ff1->ports.at(ctx->id("LSR")).net) + if (net_or_nullptr(ff0, ctx->id("LSR")) != net_or_nullptr(ff1, ctx->id("LSR"))) return false; return true; } @@ -275,6 +284,8 @@ class Ecp5Packer ff_to_slice(ctx, ff, packed.get(), 0, true); packed_cells.insert(ff->name); sliceUsage[packed->name].ff0_used = true; + lutffPairs.erase(ci->name); + fflutPairs.erase(ff->name); } new_cells.push_back(std::move(packed)); @@ -304,10 +315,14 @@ class Ecp5Packer if (ff0 != lutffPairs.end()) { ff_to_slice(ctx, ctx->cells.at(ff0->second).get(), slice.get(), 0, true); packed_cells.insert(ff0->second); + lutffPairs.erase(lut0->name); + fflutPairs.erase(ff0->second); } if (ff1 != lutffPairs.end()) { ff_to_slice(ctx, ctx->cells.at(ff1->second).get(), slice.get(), 1, true); packed_cells.insert(ff1->second); + lutffPairs.erase(lut1->name); + fflutPairs.erase(ff1->second); } new_cells.push_back(std::move(slice)); @@ -333,6 +348,8 @@ class Ecp5Packer if (ff != lutffPairs.end()) { ff_to_slice(ctx, ctx->cells.at(ff->second).get(), slice.get(), 0, true); packed_cells.insert(ff->second); + lutffPairs.erase(ci->name); + fflutPairs.erase(ff->second); } new_cells.push_back(std::move(slice)); @@ -374,14 +391,7 @@ class Ecp5Packer new_init |= (1 << i); } } - cell->params[ctx->id("INIT")] = std::to_string(init); - NetInfo *innet = cell->ports.at(input).net; - if (innet != nullptr) { - innet->users.erase( - std::remove_if(innet->users.begin(), innet->users.end(), - [cell, input](PortRef port) { return port.cell == cell && port.port == input; }), - innet->users.end()); - } + cell->params[ctx->id("INIT")] = std::to_string(new_init); cell->ports.at(input).net = nullptr; } @@ -418,7 +428,7 @@ class Ecp5Packer log_info("Packing constants..\n"); std::unique_ptr gnd_cell = create_ecp5_cell(ctx, ctx->id("LUT4"), "$PACKER_GND"); - gnd_cell->params[ctx->id("LUT_INIT")] = "0"; + gnd_cell->params[ctx->id("INIT")] = "0"; std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); gnd_net->name = ctx->id("$PACKER_GND_NET"); gnd_net->driver.cell = gnd_cell.get(); @@ -426,7 +436,7 @@ class Ecp5Packer gnd_cell->ports.at(ctx->id("Z")).net = gnd_net.get(); std::unique_ptr vcc_cell = create_ecp5_cell(ctx, ctx->id("LUT4"), "$PACKER_VCC"); - vcc_cell->params[ctx->id("LUT_INIT")] = "65535"; + vcc_cell->params[ctx->id("INIT")] = "65535"; std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); vcc_net->name = ctx->id("$PACKER_VCC_NET"); vcc_net->driver.cell = vcc_cell.get(); diff --git a/ecp5/synth/blinky.v b/ecp5/synth/blinky.v index ac7c6ea3..a8f556b2 100644 --- a/ecp5/synth/blinky.v +++ b/ecp5/synth/blinky.v @@ -1,4 +1,4 @@ -module top(input clk_pin, input btn_pin, output [3:0] led_pin, output gpio0_pin); +module top(input clk_pin, input btn_pin, output [7:0] led_pin, output gpio0_pin); wire clk; wire [7:0] led; @@ -72,6 +72,6 @@ module top(input clk_pin, input btn_pin, output [3:0] led_pin, output gpio0_pin) assign led = led_reg; // Tie GPIO0, keep board from rebooting - TRELLIS_SLICE #(.MODE("LOGIC"), .LUT0_INITVAL(16'hFFFF)) vcc (.F0(gpio0)); + assign gpio0 = 1'b1; endmodule diff --git a/ecp5/synth/counter.v b/ecp5/synth/counter.v new file mode 100644 index 00000000..f2a4b812 --- /dev/null +++ b/ecp5/synth/counter.v @@ -0,0 +1,52 @@ +module top(input clk_pin, input btn_pin, output [7: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" *) (* keep *) + 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" *) + 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/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)); + + localparam ctr_width = 30; + 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) begin + ctr <= ctr + 1'b1; + end + + + assign led = ctr[ctr_width-1:ctr_width-8]; + + // Tie GPIO0, keep board from rebooting + assign gpio0 = 1'b1; + +endmodule From c75a924c3f9dba4fd7d5c4e9674b29f7869a4e52 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 18 Jul 2018 12:12:05 +0200 Subject: [PATCH 06/28] ice40: Assign ArchArgs after packing Signed-off-by: David Shah --- ice40/arch.cc | 5 ++--- ice40/arch.h | 2 +- ice40/archdefs.h | 22 ++++++++++++++++++++-- ice40/bitstream.cc | 5 +++-- ice40/gfx.cc | 9 ++++----- ice40/gfx.h | 3 ++- ice40/pack.cc | 31 +++++++++++++++++++++++++++++++ 7 files changed, 63 insertions(+), 14 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 69848aff..1c6dd6a5 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -610,8 +610,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const } 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; @@ -621,7 +620,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const 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); diff --git a/ice40/arch.h b/ice40/arch.h index 5dab414b..1c47e958 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -584,7 +584,7 @@ struct Arch : BaseCtx range.e.cursor = chip_info->num_pips; return range; } - + IdString getPipName(PipId pip) const; uint32_t getPipChecksum(PipId pip) const { return pip.index; } diff --git a/ice40/archdefs.h b/ice40/archdefs.h index ce7d3f52..cf8a78f4 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -150,8 +150,26 @@ struct DecalId bool operator!=(const DecalId &other) const { return (type != other.type) || (index != other.index); } }; -struct ArchNetInfo { }; -struct ArchCellInfo { }; +struct ArchNetInfo +{ + bool is_global = false; +}; + +struct NetInfo; + +struct ArchCellInfo +{ + BelType belType = TYPE_NONE; + union + { + struct + { + bool dffEnable, negClk; + int inputCount; + const NetInfo *clk, *cen, *sr; + } lcInfo; + }; +}; NEXTPNR_NAMESPACE_END diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index a62c6c09..98a7a0e4 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -341,8 +341,9 @@ 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/gfx.cc b/ice40/gfx.cc index aa2fc9ce..f6ed789f 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -640,10 +640,8 @@ static bool getWireXY_local(GfxTileWireId id, float &x, float &y) return false; } -void pipGfx(std::vector &g, int x, int y, - float x1, float y1, float x2, float y2, - float swx1, float swy1, float swx2, float swy2, - GraphicElement::style_t style) +void pipGfx(std::vector &g, int x, int y, float x1, float y1, float x2, float y2, float swx1, + float swy1, float swx2, float swy2, GraphicElement::style_t style) { float tx = 0.5 * (x1 + x2); float ty = 0.5 * (y1 + y2); @@ -693,7 +691,8 @@ edge_pip: g.push_back(el); } -void gfxTilePip(std::vector &g, int x, int y, GfxTileWireId src, GfxTileWireId dst, GraphicElement::style_t style) +void gfxTilePip(std::vector &g, int x, int y, GfxTileWireId src, GfxTileWireId dst, + GraphicElement::style_t style) { float x1, y1, x2, y2; diff --git a/ice40/gfx.h b/ice40/gfx.h index a1cbd65b..8a55407d 100644 --- a/ice40/gfx.h +++ b/ice40/gfx.h @@ -468,7 +468,8 @@ enum GfxTileWireId }; void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, GraphicElement::style_t style); -void gfxTilePip(std::vector &g, int x, int y, GfxTileWireId src, GfxTileWireId dst, GraphicElement::style_t style); +void gfxTilePip(std::vector &g, int x, int y, GfxTileWireId src, GfxTileWireId dst, + GraphicElement::style_t style); NEXTPNR_NAMESPACE_END diff --git a/ice40/pack.cc b/ice40/pack.cc index 76a52be0..e656e596 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -575,6 +575,36 @@ static void pack_special(Context *ctx) } } +// Assign arch arg info +static void assign_archargs(Context *ctx) +{ + for (auto &net : ctx->nets) { + NetInfo *ni = net.second.get(); + if (ctx->isGlobalNet(ni)) + ni->is_global = true; + } + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); + ci->belType = ctx->belTypeFromId(ci->type); + if (is_lc(ctx, ci)) { + ci->lcInfo.dffEnable = bool_or_default(ci->params, ctx->id("DFF_ENABLE")); + ci->lcInfo.negClk = bool_or_default(ci->params, ctx->id("NEG_CLK")); + ci->lcInfo.clk = get_net_or_empty(ci, ctx->id("CLK")); + ci->lcInfo.cen = get_net_or_empty(ci, ctx->id("CEN")); + ci->lcInfo.sr = get_net_or_empty(ci, ctx->id("SR")); + ci->lcInfo.inputCount = 0; + if (get_net_or_empty(ci, ctx->id("I0"))) + ci->lcInfo.inputCount++; + if (get_net_or_empty(ci, ctx->id("I1"))) + ci->lcInfo.inputCount++; + if (get_net_or_empty(ci, ctx->id("I2"))) + ci->lcInfo.inputCount++; + if (get_net_or_empty(ci, ctx->id("I3"))) + ci->lcInfo.inputCount++; + } + } +} + // Main pack function bool Arch::pack() { @@ -589,6 +619,7 @@ bool Arch::pack() pack_carries(ctx); pack_ram(ctx); pack_special(ctx); + assign_archargs(ctx); log_info("Checksum: 0x%08x\n", ctx->checksum()); return true; } catch (log_execution_error_exception) { From 70cfa7a6a4bbc796f1ddf23f53a932538eb3b84d Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 18 Jul 2018 12:21:02 +0200 Subject: [PATCH 07/28] ice40: Make assignArchArgs a Arch method; call also after legaliser Signed-off-by: David Shah --- ice40/arch.cc | 30 ++++++++++++++++++++++++++++++ ice40/arch.h | 5 +++++ ice40/pack.cc | 32 +------------------------------- ice40/place_legaliser.cc | 1 + 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 1c6dd6a5..a5c920bb 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -697,4 +697,34 @@ bool Arch::isGlobalNet(const NetInfo *net) const return net->driver.cell != nullptr && net->driver.port == id_glb_buf_out; } +// Assign arch arg info +void Arch::assignArchArgs() +{ + for (auto &net : getCtx()->nets) { + NetInfo *ni = net.second.get(); + if (isGlobalNet(ni)) + ni->is_global = true; + } + for (auto &cell : getCtx()->cells) { + CellInfo *ci = cell.second.get(); + ci->belType = belTypeFromId(ci->type); + if (ci->type == id_icestorm_lc) { + ci->lcInfo.dffEnable = bool_or_default(ci->params, id_dff_en); + ci->lcInfo.negClk = bool_or_default(ci->params, id_neg_clk); + ci->lcInfo.clk = get_net_or_empty(ci, id_clk); + ci->lcInfo.cen = get_net_or_empty(ci, id_cen); + ci->lcInfo.sr = get_net_or_empty(ci, id_sr); + ci->lcInfo.inputCount = 0; + if (get_net_or_empty(ci, id_i0)) + ci->lcInfo.inputCount++; + if (get_net_or_empty(ci, id_i1)) + ci->lcInfo.inputCount++; + if (get_net_or_empty(ci, id_i2)) + ci->lcInfo.inputCount++; + if (get_net_or_empty(ci, id_i3)) + ci->lcInfo.inputCount++; + } + } +} + NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index 1c47e958..8821ded2 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -705,6 +705,11 @@ struct Arch : BaseCtx // Helper function for above bool logicCellsCompatible(const std::vector &cells) const; + // ------------------------------------------------- + // Assign architecure-specific arguments to nets and cells, which must be called between packing or further + // netlist modifications, and validity checks + void assignArchArgs(); + IdString id_glb_buf_out; IdString id_icestorm_lc, id_sb_io, id_sb_gb; IdString id_cen, id_clk, id_sr; diff --git a/ice40/pack.cc b/ice40/pack.cc index e656e596..6a6bdfaf 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -575,36 +575,6 @@ static void pack_special(Context *ctx) } } -// Assign arch arg info -static void assign_archargs(Context *ctx) -{ - for (auto &net : ctx->nets) { - NetInfo *ni = net.second.get(); - if (ctx->isGlobalNet(ni)) - ni->is_global = true; - } - for (auto &cell : ctx->cells) { - CellInfo *ci = cell.second.get(); - ci->belType = ctx->belTypeFromId(ci->type); - if (is_lc(ctx, ci)) { - ci->lcInfo.dffEnable = bool_or_default(ci->params, ctx->id("DFF_ENABLE")); - ci->lcInfo.negClk = bool_or_default(ci->params, ctx->id("NEG_CLK")); - ci->lcInfo.clk = get_net_or_empty(ci, ctx->id("CLK")); - ci->lcInfo.cen = get_net_or_empty(ci, ctx->id("CEN")); - ci->lcInfo.sr = get_net_or_empty(ci, ctx->id("SR")); - ci->lcInfo.inputCount = 0; - if (get_net_or_empty(ci, ctx->id("I0"))) - ci->lcInfo.inputCount++; - if (get_net_or_empty(ci, ctx->id("I1"))) - ci->lcInfo.inputCount++; - if (get_net_or_empty(ci, ctx->id("I2"))) - ci->lcInfo.inputCount++; - if (get_net_or_empty(ci, ctx->id("I3"))) - ci->lcInfo.inputCount++; - } - } -} - // Main pack function bool Arch::pack() { @@ -619,7 +589,7 @@ bool Arch::pack() pack_carries(ctx); pack_ram(ctx); pack_special(ctx); - assign_archargs(ctx); + ctx->assignArchArgs(); log_info("Checksum: 0x%08x\n", ctx->checksum()); return true; } catch (log_execution_error_exception) { diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index 5fffb4fb..ebcc0da7 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -127,6 +127,7 @@ class PlacementLegaliser legalise_others(); legalise_logic_tiles(); bool replaced_cells = replace_cells(); + ctx->assignArchArgs(); return legalised_carries && replaced_cells; } From d392b5f63587339c27a30c247f4a045f923edc4b Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 18 Jul 2018 12:51:07 +0200 Subject: [PATCH 08/28] ice40: Use xArchArgs in validity check Signed-off-by: David Shah --- ice40/arch.cc | 39 ++++++++++++++++++++++----------------- ice40/arch.h | 1 + ice40/arch_place.cc | 36 ++++++++++++++---------------------- ice40/place_legaliser.cc | 2 ++ 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index a5c920bb..1825c142 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -707,23 +707,28 @@ void Arch::assignArchArgs() } for (auto &cell : getCtx()->cells) { CellInfo *ci = cell.second.get(); - ci->belType = belTypeFromId(ci->type); - if (ci->type == id_icestorm_lc) { - ci->lcInfo.dffEnable = bool_or_default(ci->params, id_dff_en); - ci->lcInfo.negClk = bool_or_default(ci->params, id_neg_clk); - ci->lcInfo.clk = get_net_or_empty(ci, id_clk); - ci->lcInfo.cen = get_net_or_empty(ci, id_cen); - ci->lcInfo.sr = get_net_or_empty(ci, id_sr); - ci->lcInfo.inputCount = 0; - if (get_net_or_empty(ci, id_i0)) - ci->lcInfo.inputCount++; - if (get_net_or_empty(ci, id_i1)) - ci->lcInfo.inputCount++; - if (get_net_or_empty(ci, id_i2)) - ci->lcInfo.inputCount++; - if (get_net_or_empty(ci, id_i3)) - ci->lcInfo.inputCount++; - } + assignCellArgs(ci); + } +} + +void Arch::assignCellArgs(CellInfo *cell) +{ + cell->belType = belTypeFromId(cell->type); + if (cell->type == id_icestorm_lc) { + cell->lcInfo.dffEnable = bool_or_default(cell->params, id_dff_en); + cell->lcInfo.negClk = bool_or_default(cell->params, id_neg_clk); + cell->lcInfo.clk = get_net_or_empty(cell, id_clk); + cell->lcInfo.cen = get_net_or_empty(cell, id_cen); + cell->lcInfo.sr = get_net_or_empty(cell, id_sr); + cell->lcInfo.inputCount = 0; + if (get_net_or_empty(cell, id_i0)) + cell->lcInfo.inputCount++; + if (get_net_or_empty(cell, id_i1)) + cell->lcInfo.inputCount++; + if (get_net_or_empty(cell, id_i2)) + cell->lcInfo.inputCount++; + if (get_net_or_empty(cell, id_i3)) + cell->lcInfo.inputCount++; } } diff --git a/ice40/arch.h b/ice40/arch.h index 8821ded2..8c1a3d41 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -709,6 +709,7 @@ struct Arch : BaseCtx // Assign architecure-specific arguments to nets and cells, which must be called between packing or further // netlist modifications, and validity checks void assignArchArgs(); + void assignCellArgs(CellInfo *cell); IdString id_glb_buf_out; IdString id_icestorm_lc, id_sb_io, id_sb_gb; diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index dc1bc3eb..1f2943a0 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -31,45 +31,37 @@ bool Arch::logicCellsCompatible(const std::vector &cells) cons int locals_count = 0; for (auto cell : cells) { - if (bool_or_default(cell->params, id_dff_en)) { + NPNR_ASSERT(cell->belType == TYPE_ICESTORM_LC); + if (cell->lcInfo.dffEnable) { 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 = cell->lcInfo.cen; + clk = cell->lcInfo.clk; + sr = cell->lcInfo.sr; - if (!isGlobalNet(cen) && cen != nullptr) + if (cen != nullptr && !cen->is_global) locals_count++; - if (!isGlobalNet(clk) && clk != nullptr) + if (clk != nullptr && !clk->is_global) locals_count++; - if (!isGlobalNet(sr) && sr != nullptr) + if (sr != nullptr && !sr->is_global) locals_count++; - if (bool_or_default(cell->params, id_neg_clk)) { + if (cell->lcInfo.negClk) { dffs_neg = true; } } else { - if (cen != get_net_or_empty(cell, id_cen)) + if (cen != cell->lcInfo.cen) return false; - if (clk != get_net_or_empty(cell, id_clk)) + if (clk != cell->lcInfo.clk) return false; - if (sr != get_net_or_empty(cell, id_sr)) + if (sr != cell->lcInfo.sr) return false; - if (dffs_neg != bool_or_default(cell->params, id_neg_clk)) + if (dffs_neg != cell->lcInfo.negClk) 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); - if (i0 != nullptr) - locals_count++; - if (i1 != nullptr) - locals_count++; - if (i2 != nullptr) - locals_count++; - if (i3 != nullptr) - locals_count++; + locals_count += cell->lcInfo.inputCount; } return locals_count <= 32; diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index ebcc0da7..3c82a1bd 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -372,6 +372,7 @@ class PlacementLegaliser NPNR_ASSERT(ctx->nets.find(co_i3_name) == ctx->nets.end()); ctx->nets[co_i3_name] = std::move(co_i3_net); IdString name = lc->name; + ctx->assignCellArgs(lc.get()); ctx->cells[lc->name] = std::move(lc); createdCells.insert(name); return ctx->cells[name].get(); @@ -416,6 +417,7 @@ class PlacementLegaliser ctx->nets[out_net_name] = std::move(out_net); IdString name = lc->name; + ctx->assignCellArgs(lc.get()); ctx->cells[lc->name] = std::move(lc); createdCells.insert(name); return ctx->cells[name].get(); From 609794f9e6561fec1324ee554d85742e13e3d513 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 18 Jul 2018 13:29:58 +0200 Subject: [PATCH 09/28] Add Net/Cell "udata" field Signed-off-by: Clifford Wolf --- common/nextpnr.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/nextpnr.h b/common/nextpnr.h index 3d0cc955..f808faf8 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -203,6 +203,8 @@ struct PipMap struct NetInfo : ArchNetInfo { IdString name; + int32_t udata; + PortRef driver; std::vector users; std::unordered_map attrs; @@ -228,6 +230,8 @@ struct PortInfo struct CellInfo : ArchCellInfo { IdString name, type; + int32_t udata; + std::unordered_map ports; std::unordered_map attrs, params; From acdaec249ad9b6288cc053e4d504ca8f14e41ec6 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 18 Jul 2018 13:46:00 +0200 Subject: [PATCH 10/28] Cleanups in iCE40 blinky and picorv32 tests Signed-off-by: Clifford Wolf --- ice40/blinky.ys | 2 +- ice40/picorv32.sh | 2 +- ice40/picorv32_arachne.sh | 9 --------- ice40/transform_arachne_loc.py | 24 ------------------------ 4 files changed, 2 insertions(+), 35 deletions(-) delete mode 100755 ice40/picorv32_arachne.sh delete mode 100755 ice40/transform_arachne_loc.py diff --git a/ice40/blinky.ys b/ice40/blinky.ys index bad0a8b4..a5dd2c85 100644 --- a/ice40/blinky.ys +++ b/ice40/blinky.ys @@ -1,3 +1,3 @@ read_verilog blinky.v -synth_ice40 -top blinky -nocarry +synth_ice40 -top blinky write_json blinky.json diff --git a/ice40/picorv32.sh b/ice40/picorv32.sh index 2c67f641..87426cde 100755 --- a/ice40/picorv32.sh +++ b/ice40/picorv32.sh @@ -2,5 +2,5 @@ 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 +yosys -p 'synth_ice40 -json picorv32.json -top top' picorv32.v picorv32_top.v ../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json diff --git a/ice40/picorv32_arachne.sh b/ice40/picorv32_arachne.sh deleted file mode 100755 index b3960fdc..00000000 --- a/ice40/picorv32_arachne.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -ex -rm -f picorv32.v -wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v -yosys -p 'synth_ice40 -nocarry -blif picorv32.blif -top top' picorv32.v picorv32_top.v -arachne-pnr -d 8k --post-place-blif picorv32_place.blif picorv32.blif -o picorv32_arachne_all.asc -yosys -p "read_blif -wideports picorv32_place.blif; read_verilog -lib +/ice40/cells_sim.v; write_json picorv32_place.json" -./transform_arachne_loc.py picorv32_place.json > picorv32_place_nx.json -../nextpnr-ice40 --hx8k --asc picorv32_ar_placed.asc --json picorv32_place_nx.json --force diff --git a/ice40/transform_arachne_loc.py b/ice40/transform_arachne_loc.py deleted file mode 100755 index 14792845..00000000 --- a/ice40/transform_arachne_loc.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 -import json -import sys -import re - -with open(sys.argv[1]) as f: - data = json.load(f) - -for mod, moddata in data["modules"].items(): - if "cells" in moddata: - for cell, celldata in moddata["cells"].items(): - pos = re.split('[,/]', celldata["attributes"]["loc"]) - pos = [int(_) for _ in pos] - if celldata["type"] == "ICESTORM_LC": - celldata["attributes"]["BEL"] = "X%d/Y%d/lc%d" % (pos[0], pos[1], pos[2]) - elif celldata["type"] == "SB_IO": - celldata["attributes"]["BEL"] = "X%d/Y%d/io%d" % (pos[0], pos[1], pos[2]) - elif "RAM" in celldata["type"]: - celldata["attributes"]["BEL"] = "X%d/Y%d/ram" % (pos[0], pos[1]) - elif celldata["type"] == "SB_GB": - celldata["attributes"]["BEL"] = "X%d/Y%d/gb" % (pos[0], pos[1]) - else: - assert False -print(json.dumps(data, sort_keys=True, indent=4)) \ No newline at end of file From ddd94edfe0af32a33e5b71b9768c706f8b37d61b Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 18 Jul 2018 14:01:19 +0200 Subject: [PATCH 11/28] ice40: Fixes for inverted clocks Signed-off-by: David Shah --- ice40/bitstream.cc | 2 +- ice40/cells.cc | 3 ++- ice40/pack.cc | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 98a7a0e4..35a460f9 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -192,7 +192,7 @@ void write_asc(const Context *ctx, std::ostream &out) bool val = (pin_type >> i) & 0x01; set_config(ti, config.at(y).at(x), "IOB_" + std::to_string(z) + ".PINTYPE_" + std::to_string(i), val); } - + set_config(ti, config.at(y).at(x), "NegClk", neg_trigger); auto ieren = get_ieren(bi, x, y, z); int iex, iey, iez; std::tie(iex, iey, iez) = ieren; diff --git a/ice40/cells.cc b/ice40/cells.cc index 1ba40970..8e8679ee 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -256,7 +256,8 @@ bool is_clock_port(const BaseCtx *ctx, const PortRef &port) if (port.cell->type == ctx->id("ICESTORM_LC")) return port.port == ctx->id("CLK"); if (is_ram(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_RAM")) - return port.port == ctx->id("RCLK") || port.port == ctx->id("WCLK"); + return port.port == ctx->id("RCLK") || port.port == ctx->id("WCLK") || port.port == ctx->id("RCLKN") || + port.port == ctx->id("WCLKN"); return false; } diff --git a/ice40/pack.cc b/ice40/pack.cc index 6a6bdfaf..76e36151 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -277,6 +277,10 @@ static void pack_ram(Context *ctx) if (bpos != std::string::npos) { newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2); } + if (pi.name == ctx->id("RCLKN")) + newname = "RCLK"; + else if (pi.name == ctx->id("WCLKN")) + newname = "WCLK"; replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); } new_cells.push_back(std::move(packed)); From 08ceb8a059d96a0546c02eb3ee75e46093e2ee44 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 18 Jul 2018 14:34:32 +0200 Subject: [PATCH 12/28] ice40: Renaming Signed-off-by: David Shah --- ice40/arch.cc | 6 +++--- ice40/arch.h | 4 ++-- ice40/pack.cc | 2 +- ice40/place_legaliser.cc | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 1825c142..0decc513 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -698,7 +698,7 @@ bool Arch::isGlobalNet(const NetInfo *net) const } // Assign arch arg info -void Arch::assignArchArgs() +void Arch::assignArchInfo() { for (auto &net : getCtx()->nets) { NetInfo *ni = net.second.get(); @@ -707,11 +707,11 @@ void Arch::assignArchArgs() } for (auto &cell : getCtx()->cells) { CellInfo *ci = cell.second.get(); - assignCellArgs(ci); + assignCellInfo(ci); } } -void Arch::assignCellArgs(CellInfo *cell) +void Arch::assignCellInfo(CellInfo *cell) { cell->belType = belTypeFromId(cell->type); if (cell->type == id_icestorm_lc) { diff --git a/ice40/arch.h b/ice40/arch.h index 8c1a3d41..f0f734ce 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -708,8 +708,8 @@ struct Arch : BaseCtx // ------------------------------------------------- // Assign architecure-specific arguments to nets and cells, which must be called between packing or further // netlist modifications, and validity checks - void assignArchArgs(); - void assignCellArgs(CellInfo *cell); + void assignArchInfo(); + void assignCellInfo(CellInfo *cell); IdString id_glb_buf_out; IdString id_icestorm_lc, id_sb_io, id_sb_gb; diff --git a/ice40/pack.cc b/ice40/pack.cc index 76e36151..5f7e95f3 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -593,7 +593,7 @@ bool Arch::pack() pack_carries(ctx); pack_ram(ctx); pack_special(ctx); - ctx->assignArchArgs(); + ctx->assignArchInfo(); log_info("Checksum: 0x%08x\n", ctx->checksum()); return true; } catch (log_execution_error_exception) { diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index 3c82a1bd..2aefb839 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -127,7 +127,7 @@ class PlacementLegaliser legalise_others(); legalise_logic_tiles(); bool replaced_cells = replace_cells(); - ctx->assignArchArgs(); + ctx->assignArchInfo(); return legalised_carries && replaced_cells; } @@ -372,7 +372,7 @@ class PlacementLegaliser NPNR_ASSERT(ctx->nets.find(co_i3_name) == ctx->nets.end()); ctx->nets[co_i3_name] = std::move(co_i3_net); IdString name = lc->name; - ctx->assignCellArgs(lc.get()); + ctx->assignCellInfo(lc.get()); ctx->cells[lc->name] = std::move(lc); createdCells.insert(name); return ctx->cells[name].get(); @@ -417,7 +417,7 @@ class PlacementLegaliser ctx->nets[out_net_name] = std::move(out_net); IdString name = lc->name; - ctx->assignCellArgs(lc.get()); + ctx->assignCellInfo(lc.get()); ctx->cells[lc->name] = std::move(lc); createdCells.insert(name); return ctx->cells[name].get(); From 5393841c669775eab5a5e5fde9be2bab3ec67879 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 18 Jul 2018 15:34:22 +0200 Subject: [PATCH 13/28] ecp5: Adding PIO data to chipdb Signed-off-by: David Shah --- ecp5/arch.h | 23 +++++++++++++ ecp5/trellis_import.py | 78 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/ecp5/arch.h b/ecp5/arch.h index 4bb71b47..5158fe5c 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -96,13 +96,36 @@ NPNR_PACKED_STRUCT(struct LocationTypePOD { RelPtr pip_data; }); +NPNR_PACKED_STRUCT(struct PIOInfoPOD { + Location abs_loc; + int32_t bel_index; + RelPtr function_name; + int16_t bank; + int16_t padding; +}); + +NPNR_PACKED_STRUCT(struct PackagePinPOD { + RelPtr name; + Location abs_loc; + int32_t bel_index; +}); + +NPNR_PACKED_STRUCT(struct PackageInfoPOD { + RelPtr name; + int32_t num_pins; + RelPtr pin_data; +}); + NPNR_PACKED_STRUCT(struct ChipInfoPOD { int32_t width, height; int32_t num_tiles; int32_t num_location_types; + int32_t num_packages, num_pios; RelPtr locations; RelPtr location_type; RelPtr> tiletype_names; + RelPtr package_info; + RelPtr pio_info; }); #if defined(_MSC_VER) diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py index 2bc32169..af5386e7 100755 --- a/ecp5/trellis_import.py +++ b/ecp5/trellis_import.py @@ -2,6 +2,8 @@ import pytrellis import database import argparse +import json +from os import path location_types = dict() type_at_location = dict() @@ -319,6 +321,49 @@ bel_types = { "PIO": 2 } +def get_bel_index(ddrg, loc, name): + loctype = ddrg.locationTypes[ddrg.typeAtLocation[loc]] + idx = 0 + for bel in loctype.bels: + if ddrg.to_str(bel.name) == name: + return idx + idx += 1 + assert loc.y == max_row # Only missing IO should be special pins at bottom of device + return None + + +packages = {} +pindata = [] + +def process_pio_db(ddrg, device): + piofile = path.join(database.get_db_root(), "ECP5", dev_names[device], "iodb.json") + with open(piofile, 'r') as f: + piodb = json.load(f) + for pkgname, pkgdata in sorted(piodb["packages"].items()): + pins = [] + for name, pinloc in sorted(pkgdata.items()): + x = pinloc["col"] + y = pinloc["row"] + loc = pytrellis.Location(x, y) + pio = "PIO" + pinloc["pio"] + bel_idx = get_bel_index(ddrg, loc, pio) + if bel_idx is not None: + pins.append((name, loc, bel_idx)) + packages[pkgname] = pins + for metaitem in piodb["pio_metadata"]: + x = metaitem["col"] + y = metaitem["row"] + loc = pytrellis.Location(x, y) + pio = "PIO" + metaitem["pio"] + bank = metaitem["bank"] + if "function" in metaitem: + pinfunc = metaitem["function"] + else: + pinfunc = None + bel_idx = get_bel_index(ddrg, loc, pio) + if bel_idx is not None: + pindata.append((loc, bel_idx, bank, pinfunc)) + def write_database(dev_name, ddrg, endianness): def write_loc(loc, sym_name): @@ -409,6 +454,32 @@ def write_database(dev_name, ddrg, endianness): for y in range(0, max_row+1): for x in range(0, max_col+1): bba.u32(loctypes.index(ddrg.typeAtLocation[pytrellis.Location(x, y)]), "loctype") + for package, pkgdata in sorted(packages.items()): + bba.l("package_data_%s" % package, "PackagePinPOD") + for pin in pkgdata: + name, loc, bel_idx = pin + bba.s(name, "name") + write_loc(loc, "abs_loc") + bba.u32(bel_idx, "bel_index") + + bba.l("package_data", "PackageInfoPOD") + for package, pkgdata in sorted(packages.items()): + bba.s(package, "name") + bba.u32(len(pkgdata), "num_pins") + bba.r("package_data_%s" % package, "pin_data") + + bba.l("pio_info", "PIOInfoPOD") + for pin in pindata: + loc, bel_idx, bank, func = pin + write_loc(loc, "abs_loc") + bba.u32(bel_idx, "bel_index") + if func is not None: + bba.s(func, "function_name") + else: + bba.r(None, "function_name") + bba.u16(bank, "bank") + bba.u16(0, "padding") + bba.l("tiletype_names", "RelPtr") for tt in tiletype_names: @@ -419,9 +490,15 @@ def write_database(dev_name, ddrg, endianness): 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.u32(len(packages), "num_packages") + bba.u32(len(pindata), "num_pios") + bba.r("locations", "locations") bba.r("location_types", "location_type") bba.r("tiletype_names", "tiletype_names") + bba.r("package_data", "package_info") + bba.r("pio_info", "pio_info") + bba.finalize() return bba @@ -451,6 +528,7 @@ def main(): ddrg = pytrellis.make_dedup_chipdb(chip) max_row = chip.get_max_row() max_col = chip.get_max_col() + process_pio_db(ddrg, args.device) print("{} unique location types".format(len(ddrg.locationTypes))) bba = write_database(args.device, ddrg, "le") From c80934f953a9aa185aec0f3e9b9a23296c6e682b Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 18 Jul 2018 16:01:53 +0200 Subject: [PATCH 14/28] ecp5: Add support for pin name constraints using 'LOC' attributes Signed-off-by: David Shah --- ecp5/arch.cc | 33 +++++++++++++++++++++++++++++++-- ecp5/arch.h | 1 + ecp5/main.cc | 8 ++++++-- ecp5/pack.cc | 15 +++++++++++++++ ecp5/synth/blinky.v | 22 +++++++++++----------- 5 files changed, 64 insertions(+), 15 deletions(-) diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 0ffede3b..1510a27f 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -118,6 +118,16 @@ Arch::Arch(ArchArgs args) : args(args) log_error("Unsupported ECP5 chip type.\n"); } #endif + package_info = nullptr; + for (int i = 0; i < chip_info->num_packages; i++) { + if (args.package == chip_info->package_info[i].name.get()) { + package_info = &(chip_info->package_info[i]); + break; + } + } + + if (!package_info) + log_error("Unsupported package '%s' for '%s'.\n", args.package.c_str(), getChipName().c_str()); id_trellis_slice = id("TRELLIS_SLICE"); id_clk = id("CLK"); @@ -282,9 +292,28 @@ IdString Arch::getPipName(PipId pip) const // ----------------------------------------------------------------------- -BelId Arch::getPackagePinBel(const std::string &pin) const { return BelId(); } +BelId Arch::getPackagePinBel(const std::string &pin) const +{ + for (int i = 0; i < package_info->num_pins; i++) { + if (package_info->pin_data[i].name.get() == pin) { + BelId bel; + bel.location = package_info->pin_data[i].abs_loc; + bel.index = package_info->pin_data[i].bel_index; + return bel; + } + } + return BelId(); +} -std::string Arch::getBelPackagePin(BelId bel) const { return ""; } +std::string Arch::getBelPackagePin(BelId bel) const +{ + for (int i = 0; i < package_info->num_pins; i++) { + if (package_info->pin_data[i].abs_loc == bel.location && package_info->pin_data[i].bel_index == bel.index) { + return package_info->pin_data[i].name.get(); + } + } + return ""; +} // ----------------------------------------------------------------------- void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const diff --git a/ecp5/arch.h b/ecp5/arch.h index 5158fe5c..944aedea 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -363,6 +363,7 @@ 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; diff --git a/ecp5/main.cc b/ecp5/main.cc index 7521b88c..5a4a900a 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -68,6 +68,8 @@ int main(int argc, char *argv[]) options.add_options()("45k", "set device type to LFE5U-45F"); options.add_options()("85k", "set device type to LFE5U-85F"); + options.add_options()("package", po::value(), "select device package (defaults to CABGA381)"); + options.add_options()("json", po::value(), "JSON design file to ingest"); options.add_options()("seed", po::value(), "seed value for random number generator"); @@ -123,8 +125,10 @@ int main(int argc, char *argv[]) args.type = ArchArgs::LFE5U_45F; if (vm.count("85k")) args.type = ArchArgs::LFE5U_85F; - - args.package = "CABGA381"; + if (vm.count("package")) + args.package = vm["package"].as(); + else + args.package = "CABGA381"; args.speed = 6; std::unique_ptr ctx = std::unique_ptr(new Context(args)); diff --git a/ecp5/pack.cc b/ecp5/pack.cc index da5b3ec5..11cc2647 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -232,8 +232,23 @@ class Ecp5Packer } 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())); + + auto loc_attr = trio->attrs.find(ctx->id("LOC")); + if (loc_attr != trio->attrs.end()) { + std::string pin = loc_attr->second; + BelId pinBel = ctx->getPackagePinBel(pin); + if (pinBel == BelId()) { + log_error("IO pin '%s' constrained to pin '%s', which does not exist for package '%s'.\n", + trio->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str()); + } else { + log_info("pin '%s' constrained to Bel '%s'.\n", trio->name.c_str(ctx), + ctx->getBelName(pinBel).c_str(ctx)); + } + trio->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx); + } } } flush_cells(); diff --git a/ecp5/synth/blinky.v b/ecp5/synth/blinky.v index a8f556b2..36ec7ae3 100644 --- a/ecp5/synth/blinky.v +++ b/ecp5/synth/blinky.v @@ -5,32 +5,32 @@ module top(input clk_pin, input btn_pin, output [7:0] led_pin, output gpio0_pin) wire btn; wire gpio0; - (* BEL="X0/Y35/PIOA" *) (* IO_TYPE="LVCMOS33" *) + (* LOC="G2" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("INPUT")) clk_buf (.B(clk_pin), .O(clk)); - (* BEL="X4/Y71/PIOA" *) (* IO_TYPE="LVCMOS33" *) + (* LOC="R1" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("INPUT")) btn_buf (.B(btn_pin), .O(btn)); - (* BEL="X0/Y23/PIOC" *) (* IO_TYPE="LVCMOS33" *) + (* LOC="B2" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) led_buf_0 (.B(led_pin[0]), .I(led[0])); - (* BEL="X0/Y23/PIOD" *) (* IO_TYPE="LVCMOS33" *) + (* LOC="C2" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) led_buf_1 (.B(led_pin[1]), .I(led[1])); - (* BEL="X0/Y26/PIOA" *) (* IO_TYPE="LVCMOS33" *) + (* LOC="C1" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) led_buf_2 (.B(led_pin[2]), .I(led[2])); - (* BEL="X0/Y26/PIOC" *) (* IO_TYPE="LVCMOS33" *) + (* LOC="D2" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) led_buf_3 (.B(led_pin[3]), .I(led[3])); - (* BEL="X0/Y26/PIOB" *) (* IO_TYPE="LVCMOS33" *) + (* LOC="D1" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) led_buf_4 (.B(led_pin[4]), .I(led[4])); - (* BEL="X0/Y32/PIOD" *) (* IO_TYPE="LVCMOS33" *) + (* LOC="E2" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) led_buf_5 (.B(led_pin[5]), .I(led[5])); - (* BEL="X0/Y26/PIOD" *) (* IO_TYPE="LVCMOS33" *) + (* LOC="E1" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) led_buf_6 (.B(led_pin[6]), .I(led[6])); - (* BEL="X0/Y29/PIOD" *) (* IO_TYPE="LVCMOS33" *) + (* LOC="H3" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) led_buf_7 (.B(led_pin[7]), .I(led[7])); - (* BEL="X0/Y62/PIOD" *) (* IO_TYPE="LVCMOS33" *) + (* LOC="L2" *) (* IO_TYPE="LVCMOS33" *) TRELLIS_IO #(.DIR("OUTPUT")) gpio0_buf (.B(gpio0_pin), .I(gpio0)); localparam ctr_width = 24; From 50bf32665d0d7b7054df3ce1f36aad783eaaaa83 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 18 Jul 2018 16:31:55 +0200 Subject: [PATCH 15/28] ecp5: Tidying up examples Signed-off-by: David Shah --- ecp5/synth/blinky.v | 78 ++++++++++++++++++------------------- ecp5/synth/blinky.ys | 9 +---- ecp5/synth/blinky_nopack.ys | 2 - ecp5/synth/cells.v | 49 ----------------------- ecp5/synth/counter.v | 52 ------------------------- ecp5/synth/simple_map.v | 68 -------------------------------- ecp5/synth/ulx3s.v | 18 --------- ecp5/synth/ulx3s.ys | 9 ----- ecp5/synth/wire.v | 11 ------ ecp5/synth/wire.ys | 9 ----- 10 files changed, 40 insertions(+), 265 deletions(-) delete mode 100644 ecp5/synth/blinky_nopack.ys delete mode 100644 ecp5/synth/cells.v delete mode 100644 ecp5/synth/counter.v delete mode 100644 ecp5/synth/simple_map.v delete mode 100644 ecp5/synth/ulx3s.v delete mode 100644 ecp5/synth/ulx3s.ys delete mode 100644 ecp5/synth/wire.v delete mode 100644 ecp5/synth/wire.ys diff --git a/ecp5/synth/blinky.v b/ecp5/synth/blinky.v index 36ec7ae3..9c6b187b 100644 --- a/ecp5/synth/blinky.v +++ b/ecp5/synth/blinky.v @@ -1,46 +1,46 @@ module top(input clk_pin, input btn_pin, output [7:0] led_pin, output gpio0_pin); - wire clk; - wire [7:0] led; + wire clk; + wire [7:0] led; wire btn; wire gpio0; - (* LOC="G2" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("INPUT")) clk_buf (.B(clk_pin), .O(clk)); + (* LOC="G2" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("INPUT")) clk_buf (.B(clk_pin), .O(clk)); - (* LOC="R1" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("INPUT")) btn_buf (.B(btn_pin), .O(btn)); + (* LOC="R1" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("INPUT")) btn_buf (.B(btn_pin), .O(btn)); - (* LOC="B2" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("OUTPUT")) led_buf_0 (.B(led_pin[0]), .I(led[0])); - (* LOC="C2" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("OUTPUT")) led_buf_1 (.B(led_pin[1]), .I(led[1])); - (* LOC="C1" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("OUTPUT")) led_buf_2 (.B(led_pin[2]), .I(led[2])); + (* LOC="B2" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_0 (.B(led_pin[0]), .I(led[0])); + (* LOC="C2" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_1 (.B(led_pin[1]), .I(led[1])); + (* LOC="C1" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_2 (.B(led_pin[2]), .I(led[2])); (* LOC="D2" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("OUTPUT")) led_buf_3 (.B(led_pin[3]), .I(led[3])); + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_3 (.B(led_pin[3]), .I(led[3])); - (* LOC="D1" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("OUTPUT")) led_buf_4 (.B(led_pin[4]), .I(led[4])); - (* LOC="E2" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("OUTPUT")) led_buf_5 (.B(led_pin[5]), .I(led[5])); - (* LOC="E1" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("OUTPUT")) led_buf_6 (.B(led_pin[6]), .I(led[6])); + (* LOC="D1" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_4 (.B(led_pin[4]), .I(led[4])); + (* LOC="E2" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_5 (.B(led_pin[5]), .I(led[5])); + (* LOC="E1" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_6 (.B(led_pin[6]), .I(led[6])); (* LOC="H3" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("OUTPUT")) led_buf_7 (.B(led_pin[7]), .I(led[7])); + TRELLIS_IO #(.DIR("OUTPUT")) led_buf_7 (.B(led_pin[7]), .I(led[7])); - (* LOC="L2" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("OUTPUT")) gpio0_buf (.B(gpio0_pin), .I(gpio0)); + (* LOC="L2" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("OUTPUT")) gpio0_buf (.B(gpio0_pin), .I(gpio0)); 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 [ctr_width-1:0] ctr = 0; + reg [9:0] pwm_ctr = 0; reg dir = 0; - always@(posedge clk) begin - ctr <= btn ? ctr : (dir ? ctr - 1'b1 : 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) @@ -54,19 +54,19 @@ module top(input clk_pin, input btn_pin, output [7:0] led_pin, output gpio0_pin) 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] <= 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] <= pwm_ctr < brightness[i]; - end - end + for (i = 0; i < 8; i=i+1) begin + always @ (posedge clk) begin + 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] <= pwm_ctr < brightness[i]; + end + end endgenerate assign led = led_reg; diff --git a/ecp5/synth/blinky.ys b/ecp5/synth/blinky.ys index c0b74636..fb359380 100644 --- a/ecp5/synth/blinky.ys +++ b/ecp5/synth/blinky.ys @@ -1,9 +1,2 @@ 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 +synth_ecp5 -noccu2 -nomux -nodram -json blinky.json diff --git a/ecp5/synth/blinky_nopack.ys b/ecp5/synth/blinky_nopack.ys deleted file mode 100644 index fb359380..00000000 --- a/ecp5/synth/blinky_nopack.ys +++ /dev/null @@ -1,2 +0,0 @@ -read_verilog blinky.v -synth_ecp5 -noccu2 -nomux -nodram -json blinky.json diff --git a/ecp5/synth/cells.v b/ecp5/synth/cells.v deleted file mode 100644 index 353b8ada..00000000 --- a/ecp5/synth/cells.v +++ /dev/null @@ -1,49 +0,0 @@ -(* 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, - 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 WDO0, WDO1, WDO2, WDO3, - output WADO0, WADO1, WADO2, WADO3 -); - -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 *) (* keep *) -module TRELLIS_IO( - inout B, - input I, - input T, - output O, -); -parameter DIR = "INPUT"; - -endmodule diff --git a/ecp5/synth/counter.v b/ecp5/synth/counter.v deleted file mode 100644 index f2a4b812..00000000 --- a/ecp5/synth/counter.v +++ /dev/null @@ -1,52 +0,0 @@ -module top(input clk_pin, input btn_pin, output [7: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" *) (* keep *) - 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" *) - 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/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)); - - localparam ctr_width = 30; - 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) begin - ctr <= ctr + 1'b1; - end - - - assign led = ctr[ctr_width-1:ctr_width-8]; - - // Tie GPIO0, keep board from rebooting - assign gpio0 = 1'b1; - -endmodule diff --git a/ecp5/synth/simple_map.v b/ecp5/synth/simple_map.v deleted file mode 100644 index 550fa92c..00000000 --- a/ecp5/synth/simple_map.v +++ /dev/null @@ -1,68 +0,0 @@ -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({8{LUT[1:0]}}) - ) _TECHMAP_REPLACE_ ( - .A0(A[0]), - .F0(Y) - ); - end - if (WIDTH == 2) begin - TRELLIS_SLICE #( - .MODE("LOGIC"), - .LUT0_INITVAL({4{LUT[3:0]}}) - ) _TECHMAP_REPLACE_ ( - .A0(A[0]), - .B0(A[1]), - .F0(Y) - ); - end - if (WIDTH == 3) begin - TRELLIS_SLICE #( - .MODE("LOGIC"), - .LUT0_INITVAL({2{LUT[7:0]}}) - ) _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 diff --git a/ecp5/synth/ulx3s.v b/ecp5/synth/ulx3s.v deleted file mode 100644 index 08f6e65b..00000000 --- a/ecp5/synth/ulx3s.v +++ /dev/null @@ -1,18 +0,0 @@ -module top(input a_pin, output led_pin, output led2_pin, output gpio0_pin); - - wire a; - wire led, led2; - wire gpio0; - (* 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)); - (* 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 led2 = !a; - - TRELLIS_SLICE #(.MODE("LOGIC"), .LUT0_INITVAL(16'hFFFF)) vcc (.F0(gpio0)); -endmodule diff --git a/ecp5/synth/ulx3s.ys b/ecp5/synth/ulx3s.ys deleted file mode 100644 index d741c985..00000000 --- a/ecp5/synth/ulx3s.ys +++ /dev/null @@ -1,9 +0,0 @@ -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/wire.v b/ecp5/synth/wire.v deleted file mode 100644 index 2af68ed2..00000000 --- a/ecp5/synth/wire.v +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index f916588b..00000000 --- a/ecp5/synth/wire.ys +++ /dev/null @@ -1,9 +0,0 @@ -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 From 34772634317972aa4f816b6010a273bd7f3d17f3 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 18 Jul 2018 17:18:44 +0200 Subject: [PATCH 16/28] removed not used and buggy features --- gui/base.qrc | 1 - gui/basewindow.cc | 35 ------------- gui/basewindow.h | 5 -- gui/designwidget.cc | 5 -- gui/designwidget.h | 2 - gui/ice40/mainwindow.cc | 1 - gui/infotab.cc | 58 --------------------- gui/infotab.h | 48 ------------------ gui/resources/splash.png | Bin 4651 -> 0 bytes gui/yosys_edit.cc | 96 ----------------------------------- gui/yosys_edit.h | 57 --------------------- gui/yosystab.cc | 107 --------------------------------------- gui/yosystab.h | 59 --------------------- 13 files changed, 474 deletions(-) delete mode 100644 gui/infotab.cc delete mode 100644 gui/infotab.h delete mode 100644 gui/resources/splash.png delete mode 100644 gui/yosys_edit.cc delete mode 100644 gui/yosys_edit.h delete mode 100644 gui/yosystab.cc delete mode 100644 gui/yosystab.h diff --git a/gui/base.qrc b/gui/base.qrc index bf21986b..8f07aabe 100644 --- a/gui/base.qrc +++ b/gui/base.qrc @@ -9,6 +9,5 @@ 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 81c89e45..4a225bd6 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -29,7 +29,6 @@ #include "log.h" #include "mainwindow.h" #include "pythontab.h" -#include "yosystab.h" static void initBasenameResource() { Q_INIT_RESOURCE(base); } @@ -95,29 +94,12 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent splitter_v->addWidget(centralTabWidget); splitter_v->addWidget(tabWidget); - displaySplash(); } BaseMainWindow::~BaseMainWindow() {} void BaseMainWindow::closeTab(int index) { delete centralTabWidget->widget(index); } -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() @@ -147,10 +129,6 @@ void BaseMainWindow::createMenusAndBars() actionExit->setStatusTip("Exit the application"); connect(actionExit, SIGNAL(triggered()), this, SLOT(close())); - QAction *actionYosys = new QAction("Yosys", this); - actionYosys->setStatusTip("Run Yosys"); - connect(actionYosys, SIGNAL(triggered()), this, SLOT(yosys())); - QAction *actionAbout = new QAction("About", this); menuBar = new QMenuBar(); @@ -183,19 +161,6 @@ void BaseMainWindow::createMenusAndBars() mainToolBar->addAction(actionNew); mainToolBar->addAction(actionOpen); mainToolBar->addAction(actionSave); - mainToolBar->addAction(actionYosys); } -void BaseMainWindow::yosys() -{ - QString folder = QFileDialog::getExistingDirectory(0, ("Select Work Folder"), QDir::currentPath(), - QFileDialog::ShowDirsOnly); - if (!folder.isEmpty() && !folder.isNull()) { - YosysTab *yosysTab = new YosysTab(folder); - yosysTab->setAttribute(Qt::WA_DeleteOnClose); - centralTabWidget->addTab(yosysTab, "Yosys"); - centralTabWidget->setCurrentWidget(yosysTab); - centralTabWidget->setTabToolTip(centralTabWidget->indexOf(yosysTab), folder); - } -} NEXTPNR_NAMESPACE_END diff --git a/gui/basewindow.h b/gui/basewindow.h index 087880ed..eee426c7 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -50,17 +49,14 @@ class BaseMainWindow : public QMainWindow protected: void createMenusAndBars(); - void displaySplash(); protected Q_SLOTS: void writeInfo(std::string text); - void displaySplashMessage(std::string msg); void closeTab(int index); virtual void new_proj() = 0; virtual void open_proj() = 0; virtual bool save_proj() = 0; - void yosys(); Q_SIGNALS: void contextChanged(Context *ctx); @@ -78,7 +74,6 @@ class BaseMainWindow : public QMainWindow QAction *actionNew; QAction *actionOpen; QProgressBar *progressBar; - QSplashScreen *splash; DesignWidget *designview; }; diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 335ed929..5181cd23 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -230,7 +230,6 @@ 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("/"); @@ -263,7 +262,6 @@ 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("/"); @@ -295,7 +293,6 @@ 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("/"); @@ -331,8 +328,6 @@ 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 1afe817d..269e32fa 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -65,8 +65,6 @@ 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 4b1f2c57..28792ed3 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -226,7 +226,6 @@ 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/infotab.cc b/gui/infotab.cc deleted file mode 100644 index dd44b806..00000000 --- a/gui/infotab.cc +++ /dev/null @@ -1,58 +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 "infotab.h" -#include - -NEXTPNR_NAMESPACE_BEGIN - -InfoTab::InfoTab(QWidget *parent) : QWidget(parent) -{ - plainTextEdit = new QPlainTextEdit(); - plainTextEdit->setReadOnly(true); - QFont f("unexistent"); - f.setStyleHint(QFont::Monospace); - plainTextEdit->setFont(f); - - plainTextEdit->setContextMenuPolicy(Qt::CustomContextMenu); - QAction *clearAction = new QAction("Clear &buffer", this); - clearAction->setStatusTip("Clears display buffer"); - connect(clearAction, SIGNAL(triggered()), this, SLOT(clearBuffer())); - contextMenu = plainTextEdit->createStandardContextMenu(); - contextMenu->addSeparator(); - contextMenu->addAction(clearAction); - connect(plainTextEdit, SIGNAL(customContextMenuRequested(const QPoint)), this, SLOT(showContextMenu(const QPoint))); - - QGridLayout *mainLayout = new QGridLayout(); - mainLayout->addWidget(plainTextEdit); - setLayout(mainLayout); -} - -void InfoTab::info(std::string str) -{ - plainTextEdit->moveCursor(QTextCursor::End); - plainTextEdit->insertPlainText(str.c_str()); - plainTextEdit->moveCursor(QTextCursor::End); -} - -void InfoTab::showContextMenu(const QPoint &pt) { contextMenu->exec(mapToGlobal(pt)); } - -void InfoTab::clearBuffer() { plainTextEdit->clear(); } - -NEXTPNR_NAMESPACE_END diff --git a/gui/infotab.h b/gui/infotab.h deleted file mode 100644 index 41529973..00000000 --- a/gui/infotab.h +++ /dev/null @@ -1,48 +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. - * - */ - -#ifndef INFOTAB_H -#define INFOTAB_H - -#include -#include -#include "nextpnr.h" - -NEXTPNR_NAMESPACE_BEGIN - -class InfoTab : public QWidget -{ - Q_OBJECT - - public: - explicit InfoTab(QWidget *parent = 0); - void info(std::string str); - public Q_SLOTS: - void clearBuffer(); - private Q_SLOTS: - void showContextMenu(const QPoint &pt); - - private: - QPlainTextEdit *plainTextEdit; - QMenu *contextMenu; -}; - -NEXTPNR_NAMESPACE_END - -#endif // INFOTAB_H diff --git a/gui/resources/splash.png b/gui/resources/splash.png deleted file mode 100644 index 14d2842b95f853cf0947a5edb2fd398625d3c552..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4651 zcmc&&XH(OQ)BS}O5HKcmX)z)JsTMj?gMjoBkd8tGm1ZI+(gLUiL?8)OLb31{LltSE zD+-BT=|zgvAkqb-&x%`LlaDfdVHR#U0N@w;&q2U5iuh3yeAm*(3_J&hz$A4A z6KQS$0By8H89Uz}U!z22IuB=cwa0{n55kR61J^P>sefD$7wyzeC2>iJoSyUWIX~E2eFw)1-wui`sYo@=^H*EUmpB0 zuT%9`U;wqjDYVnd@cR?YpMWY<*59(-g|$M00`u^AD3!1a;M zXP#rR^_v+Zw$=ELd~UEjWglxL@U%vt`FPWW`c4u@dM-{HMTKvj$H(6f3KRsaW8Zj9 zSiG`h`p@r?8)Bpas@$=GO295AOM~_KcF3i9D<|*HZ)(S)XD9hi#5_lK)p|u?;eYtS5bBrZEFVm*e8Ixn1+~)1&c_|GamJFI+IG01 z52{f4&Z)f$!oR2Z05+2{(Fj={mp0M^B!JsyC>-;5raux2VkA;<8b0$TR}~QpHvjNv z98T&q47aO+!~BW3vx2@JirZJvP6#X)UKn42*ou6Manf-rprq1uw0Euk5vTCgwwlWg z7+@1Jg)+?&wk-M(X98y{ssU9~TMJI1IeiHce+nFC%w+4uv(*+(c=P$%@Ch0cnby#y zIVAFs8F*NvWP@4i^6~u6H+whe&Y^a$`sGs0v!eTxuNbMSa z9Jrt6KVffq52v>EDuzt2+t2Cn1VW?A8Zka9n#Qut`oVdp5OH9*3gTej|GGQ_O8a4a z%FJ3d;;Z7ypf0h+1=RzOEGItplij8fUZGcVolENoBf2Idk^ah>ao_3?CS1;LqQ{pg7cR@rhrtS9*9hXPq><`@D|23k#>5K>J| zu5~5zmoD;8r~m$3&(X)Amk0wJI&a_5H5(s?u>~Sp+TdBk|4uKqk0o18??+Yc&l?W0*IPG=a&U^C!_OE0R5}0c z%`91qJa}Pxzwa6N2TKVddDJ$M zX;*a8{=fBd0n}w5&PahR5%P{0x_~JbfB6YIp~cQ3%|_vJct(2^yj_w}BDeB{24<*P z+HR9Yn zv7%K%gct$Nb(a`wiM7P9W0GeoHWvt!CfZuZwUqN8=a)%tdr#e4>E@6sIy2R)U|&^k z6~LPOZ|)T1Y=`ccHiMUkmf4e3E(;^$a72KCX8F#1>x^pFNpy@6YKo=gYe&ktc+MyX z(Ec13efs!WVzh9F8Q`wfon`k5okD*Kgs40Z${msDa3+a~@a}&S^^;(bL9bG1V0^ut zIhistxxbJfN*$N%Z~~e%Oue0=mO2x5RKv3Q4cXWQ((=f9ET)TY}2JViW_=! zc)}8Q3+1_8Vo20_)irTGpfYAj7`1-p6#_1DiJ;IVC6spi;u6k#<*LIE=Fcq)O~KVV zjBDTZ&rS9A+<)JVhOCeGiZ!gbj7D;l?)+{5?R9$|h;H19GpZ?&E%h_=S7B(%wF^TRG5;WG!bV=|8H=3S zV?J@pl?|^=P&^OJ5(q&s;zqY_#h7SPG*+ET?T=C4WVw~U3A~wXTgPc(Q6t(7OOr=MjTd48#8zG5IdjQu;sY7hd zBYt2!NIpDU?PB%aqg5uTsbAeuCx}rf=JI_#&Y4Sq*I`Vk5YfYGkhGGW+Qm{6YG^UB zj?QZIW4&zLW_>7|t`!{hTi#f?Gb+g{b&rbK+7jG`7+jxxH~stHEhJ>l4Chf;4>spi zB*|VJMW1oA+A2rAHWcwJDpUi6=u!Hm<_!-Ima&-yu*_Bka}W2jTdQ5MB~(@Wna0UJ z#Qv+>_Bn=&*yrfFB)eur#-&!e+4f+uv@~ot7MU@sX!qNWq-k-Ph z8?HcOWyXaxJ|+2wd`EZC#J^~lBHMtvfcB-z&QbM@4f)Jh`p*^aaqjiStqQ^;+>(f^ zYv6fPU^f%HZ6ey(=g+_yj76tYH?KPc=`=uk`s?0o&%<~VT?%$k_P7Zp#HGYLUmkWx z$fXMtzrd!t1)zC0SWWzxTmYG(f_N$P$Dpne)V}pdcqS$U2JhSKZV#Ae%fQPrhTqU{ zq?^j~m+t34G%hH2ejztp3COE-MZ7Gb`Tf0$G{ZKyR@Q1ipxDJ9CUU!eN|Z;SV>cW` z1eo_XZe#_~p52VU$D{Q7oZ006TnjBJWd_&u($3xp1sC7$OM7*AH>1Jt!hVVTBz5%+ zcdXjaL697{^i~;@Lf^(liVi0%IM-!S3jtqu_3Ra)#qa3%Bc}%+D#^CbaaTeZIFjHW zk59BvUmn-5aWE#~;Rg<9{Be65(}jpqkK_He#Z$*#9H?@;6lpp8w@FX^7?N;kw$4sm zes>tQ5E!Cpe99J74X<^aZ9APOYA7{RHOd?hO{T+0Y9xItlrAaS3U%G}0JC_7jV5kh zi@$Mo#*m98Yg41g_)3%cvFY%WoKO?0PyzO;G%fIh+cFQ<|J?8vQR#?`z~?%! zP+m~#=eLh^p7{s2)x^Mb9{N+S`A$iBml{B75Oqi&2rmXg@wOB zRL0?Y5HaSH9vvia&KbEl+mlM6&zQqee!XLv+_w5Jb}!<8$wl1{UHXXlvMx+y*eGo3 zlD0ttn;5&)g(UKY-$O)0(WWy=EfU_)0>WMSNK5;j=Nup^805L^^*xh75uMV?`S5&p zsl(*hAvePTkP#!MXlsiX?Fl|s8O(eA5d*HO35SG%jq~zr)};ISvC~~9^;o>)xWG2$+Kaz()*2OirQ~X zgbR`s_66SjyfrzZ#cp^U`>T1x-U}EOYT@<Ze>p>Nk^l34E6$!S%7{n&nef?n0H z{NK$ls1g~|rf9Yr$HFD4j$^Q3v#|Z!e$~rHYrJf)p>M%cqOr5@)sH(rV*_R`MI8T1 zXu~jSoMtNLb%+2k*b^%=w(2_+5P=}aaJWfJDTVruX*u@w sW{w`URgLO#LyAAX_Wy$}tpqk$g}SJOKM8qw^wt3^&1_MXCcX*(2V~@~b^rhX diff --git a/gui/yosys_edit.cc b/gui/yosys_edit.cc deleted file mode 100644 index 72d2430d..00000000 --- a/gui/yosys_edit.cc +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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. - * - */ - -#include "yosys_edit.h" -#include -#include - -NEXTPNR_NAMESPACE_BEGIN - -YosysLineEditor::YosysLineEditor(QWidget *parent) : QLineEdit(parent), index(0) -{ - setContextMenuPolicy(Qt::CustomContextMenu); - QAction *clearAction = new QAction("Clear &history", this); - clearAction->setStatusTip("Clears line edit history"); - connect(clearAction, SIGNAL(triggered()), this, SLOT(clearHistory())); - contextMenu = createStandardContextMenu(); - contextMenu->addSeparator(); - contextMenu->addAction(clearAction); - - connect(this, SIGNAL(returnPressed()), SLOT(textInserted())); - connect(this, SIGNAL(customContextMenuRequested(const QPoint)), this, SLOT(showContextMenu(const QPoint))); -} - -void YosysLineEditor::keyPressEvent(QKeyEvent *ev) -{ - - if (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) { - QToolTip::hideText(); - if (lines.empty()) - return; - if (ev->key() == Qt::Key_Up) - index--; - if (ev->key() == Qt::Key_Down) - index++; - - if (index < 0) - index = 0; - if (index >= lines.size()) { - index = lines.size(); - clear(); - return; - } - setText(lines[index]); - } else if (ev->key() == Qt::Key_Escape) { - QToolTip::hideText(); - clear(); - return; - } else if (ev->key() == Qt::Key_Tab) { - return; - } - QToolTip::hideText(); - - QLineEdit::keyPressEvent(ev); -} - -// This makes TAB work -bool YosysLineEditor::focusNextPrevChild(bool next) { return false; } - -void YosysLineEditor::textInserted() -{ - if (lines.empty() || lines.back() != text()) - lines += text(); - if (lines.size() > 100) - lines.removeFirst(); - index = lines.size(); - clear(); - Q_EMIT textLineInserted(lines.back()); -} - -void YosysLineEditor::showContextMenu(const QPoint &pt) { contextMenu->exec(mapToGlobal(pt)); } - -void YosysLineEditor::clearHistory() -{ - lines.clear(); - index = 0; - clear(); -} - -NEXTPNR_NAMESPACE_END diff --git a/gui/yosys_edit.h b/gui/yosys_edit.h deleted file mode 100644 index 05e4ae36..00000000 --- a/gui/yosys_edit.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 YOSYS_EDIT_H -#define YOSYS_EDIT_H - -#include -#include -#include "nextpnr.h" - -NEXTPNR_NAMESPACE_BEGIN - -class YosysLineEditor : public QLineEdit -{ - Q_OBJECT - - public: - explicit YosysLineEditor(QWidget *parent = 0); - - private Q_SLOTS: - void textInserted(); - void showContextMenu(const QPoint &pt); - void clearHistory(); - - Q_SIGNALS: - void textLineInserted(QString); - - protected: - void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE; - bool focusNextPrevChild(bool next) Q_DECL_OVERRIDE; - - private: - int index; - QStringList lines; - QMenu *contextMenu; -}; - -NEXTPNR_NAMESPACE_END - -#endif // YOSYS_EDIT_H diff --git a/gui/yosystab.cc b/gui/yosystab.cc deleted file mode 100644 index 9bbd9c12..00000000 --- a/gui/yosystab.cc +++ /dev/null @@ -1,107 +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 "yosystab.h" -#include -#include - -NEXTPNR_NAMESPACE_BEGIN - -YosysTab::YosysTab(QString folder, QWidget *parent) : QWidget(parent) -{ - QFont f("unexistent"); - f.setStyleHint(QFont::Monospace); - - console = new QPlainTextEdit(); - console->setMinimumHeight(100); - console->setReadOnly(true); - console->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); - console->setFont(f); - - console->setContextMenuPolicy(Qt::CustomContextMenu); - QAction *clearAction = new QAction("Clear &buffer", this); - clearAction->setStatusTip("Clears display buffer"); - connect(clearAction, SIGNAL(triggered()), this, SLOT(clearBuffer())); - contextMenu = console->createStandardContextMenu(); - contextMenu->addSeparator(); - contextMenu->addAction(clearAction); - connect(console, SIGNAL(customContextMenuRequested(const QPoint)), this, SLOT(showContextMenu(const QPoint))); - - lineEdit = new YosysLineEditor(); - lineEdit->setMinimumHeight(30); - lineEdit->setMaximumHeight(30); - lineEdit->setFont(f); - lineEdit->setFocus(); - lineEdit->setEnabled(false); - lineEdit->setPlaceholderText("yosys>"); - 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); - - process = new QProcess(); - connect(process, SIGNAL(readyReadStandardError()), this, SLOT(onReadyReadStandardError())); - connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadyReadStandardOutput())); - connect(process, &QProcess::started, this, [this] { lineEdit->setEnabled(true); }); - -#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0) - connect(process, static_cast(&QProcess::error), this, [this](QProcess::ProcessError error) { -#else - connect(process, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) { -#endif - if (error == QProcess::FailedToStart) { - QMessageBox::critical( - this, QString::fromUtf8("Yosys cannot be started!"), - QString::fromUtf8("

Please make sure you have Yosys installed and available in path

")); - Q_EMIT deleteLater(); - } - }); - process->setWorkingDirectory(folder); - process->start("yosys"); -} - -YosysTab::~YosysTab() -{ - process->terminate(); - process->waitForFinished(1000); // in ms - process->kill(); - process->close(); -} - -void YosysTab::displayString(QString text) -{ - QTextCursor cursor = console->textCursor(); - cursor.movePosition(QTextCursor::End); - cursor.insertText(text); - cursor.movePosition(QTextCursor::End); - console->setTextCursor(cursor); -} - -void YosysTab::onReadyReadStandardOutput() { displayString(process->readAllStandardOutput()); } -void YosysTab::onReadyReadStandardError() { displayString(process->readAllStandardError()); } - -void YosysTab::editLineReturnPressed(QString text) { process->write(text.toLatin1() + "\n"); } - -void YosysTab::showContextMenu(const QPoint &pt) { contextMenu->exec(mapToGlobal(pt)); } - -void YosysTab::clearBuffer() { console->clear(); } - -NEXTPNR_NAMESPACE_END diff --git a/gui/yosystab.h b/gui/yosystab.h deleted file mode 100644 index 1c668d15..00000000 --- a/gui/yosystab.h +++ /dev/null @@ -1,59 +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. - * - */ - -#ifndef YOSYSTAB_H -#define YOSYSTAB_H - -#include -#include -#include -#include -#include "nextpnr.h" -#include "yosys_edit.h" - -NEXTPNR_NAMESPACE_BEGIN - -class YosysTab : public QWidget -{ - Q_OBJECT - - public: - explicit YosysTab(QString folder, QWidget *parent = 0); - ~YosysTab(); - - private: - void displayString(QString text); - private Q_SLOTS: - void showContextMenu(const QPoint &pt); - void editLineReturnPressed(QString text); - void onReadyReadStandardOutput(); - void onReadyReadStandardError(); - public Q_SLOTS: - void clearBuffer(); - - private: - QPlainTextEdit *console; - YosysLineEditor *lineEdit; - QMenu *contextMenu; - QProcess *process; -}; - -NEXTPNR_NAMESPACE_END - -#endif // YOSYSTAB_H From 19828bdf455d9e7d554cab639a2cd045c897b671 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 18 Jul 2018 17:33:04 +0200 Subject: [PATCH 17/28] added clear action for browsing history --- gui/base.qrc | 1 + gui/designwidget.cc | 16 ++++++++++++++++ gui/designwidget.h | 1 + gui/resources/cross.png | Bin 0 -> 655 bytes 4 files changed, 18 insertions(+) create mode 100644 gui/resources/cross.png diff --git a/gui/base.qrc b/gui/base.qrc index 8f07aabe..1a848f54 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/cross.png diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 5181cd23..93f71355 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -125,11 +125,27 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net updateButtons(); }); + actionClear = new QAction("", this); + actionClear->setIcon(QIcon(":/icons/resources/cross.png")); + actionClear->setEnabled(true); + connect(actionClear, &QAction::triggered, this, [this] { + history_index = -1; + history.clear(); + QTreeWidgetItem *clickItem = treeWidget->selectedItems().at(0); + if (clickItem->parent()) { + ElementType type = static_cast(clickItem)->getType(); + if (type != ElementType::NONE) + addToHistory(treeWidget->selectedItems().at(0)); + } + updateButtons(); + }); + QToolBar *toolbar = new QToolBar(); toolbar->addAction(actionFirst); toolbar->addAction(actionPrev); toolbar->addAction(actionNext); toolbar->addAction(actionLast); + toolbar->addAction(actionClear); QWidget *topWidget = new QWidget(); QVBoxLayout *vbox1 = new QVBoxLayout(); diff --git a/gui/designwidget.h b/gui/designwidget.h index 269e32fa..b5877f60 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -102,6 +102,7 @@ class DesignWidget : public QWidget QAction *actionPrev; QAction *actionNext; QAction *actionLast; + QAction *actionClear; QColor highlightColors[8]; QMap highlightSelected; diff --git a/gui/resources/cross.png b/gui/resources/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..1514d51a3cf1b67e1c5b9ada36f1fd474e2d214a GIT binary patch literal 655 zcmV;A0&x9_P)uEoyT++I zn$b9r%cFfhHe2K68PkBu*@^<$y+7xQ$wJ~;c5aBx$R=xq*41Wo zhwQus_VOgm0hughj}MhOvs#{>Vg09Y8WxjWUJY5YW zJ?&8eG!59Cz=|E%Ns@013KLWOLV)CObIIj_5{>{#k%TEAMs_GbdDV`x-iYsGH z#=Z{USAQA>NY(}X7=3{K8# Date: Wed, 18 Jul 2018 18:06:47 +0200 Subject: [PATCH 18/28] cell and net now can be selected, fixed issue with highlight --- gui/designwidget.cc | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 93f71355..898ff0c6 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -488,13 +488,12 @@ void DesignWidget::onItemSelectionChanged() addToHistory(clickItem); clearProperties(); + + IdString c = static_cast(clickItem)->getData(); + Q_EMIT selected(getDecals(type, c)); + 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 = addTopLevelProperty("Bel"); addProperty(topItem, QVariant::String, "Name", c.c_str(ctx)); @@ -505,12 +504,7 @@ void DesignWidget::onItemSelectionChanged() ElementType::CELL); } else if (type == ElementType::WIRE) { - IdString c = static_cast(clickItem)->getData(); WireId wire = ctx->getWireByName(c); - - decals.push_back(ctx->getWireDecal(wire)); - Q_EMIT selected(decals); - QtProperty *topItem = addTopLevelProperty("Wire"); addProperty(topItem, QVariant::String, "Name", c.c_str(ctx)); @@ -562,12 +556,7 @@ void DesignWidget::onItemSelectionChanged() } } } else if (type == ElementType::PIP) { - IdString c = static_cast(clickItem)->getData(); PipId pip = ctx->getPipByName(c); - - decals.push_back(ctx->getPipDecal(pip)); - Q_EMIT selected(decals); - QtProperty *topItem = addTopLevelProperty("Pip"); addProperty(topItem, QVariant::String, "Name", c.c_str(ctx)); @@ -587,7 +576,6 @@ void DesignWidget::onItemSelectionChanged() 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 = addTopLevelProperty("Net"); @@ -636,7 +624,6 @@ void DesignWidget::onItemSelectionChanged() } } else if (type == ElementType::CELL) { - IdString c = static_cast(clickItem)->getData(); CellInfo *cell = ctx->cells.at(c).get(); QtProperty *topItem = addTopLevelProperty("Cell"); @@ -700,19 +687,28 @@ std::vector DesignWidget::getDecals(ElementType type, IdString value) 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: { + NetInfo *net = ctx->nets.at(value).get(); + for (auto &item : net->wires) { + decals.push_back(ctx->getWireDecal(item.first)); + if (item.second.pip != PipId()) { + decals.push_back(ctx->getPipDecal(item.second.pip)); + } + } } break; case ElementType::CELL: { + CellInfo *cell = ctx->cells.at(value).get(); + if (cell->bel != BelId()) { + decals.push_back(ctx->getBelDecal(cell->bel)); + } } break; default: break; From 2df7e130fbc18c81840a841b16f4780fbcfda34a Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 18 Jul 2018 18:37:54 +0200 Subject: [PATCH 19/28] Fix click on wire in net section --- gui/designwidget.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 898ff0c6..4123bf30 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -612,7 +612,7 @@ void DesignWidget::onItemSelectionChanged() auto name = ctx->getWireName(item.first).c_str(ctx); QtProperty *wireItem = addSubGroup(wiresItem, name); - addProperty(wireItem, QVariant::String, "Name", name); + addProperty(wireItem, QVariant::String, "Wire", name, ElementType::WIRE); if (item.second.pip != PipId()) addProperty(wireItem, QVariant::String, "Pip", ctx->getPipName(item.second.pip).c_str(ctx), From b0d9b994eb211f4c4060f6b9802ea5692512e08c Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 19 Jul 2018 11:14:43 +0200 Subject: [PATCH 20/28] ice40: Adding data for extra cell configuration Signed-off-by: David Shah --- ice40/arch.h | 18 +++++++++++++++++- ice40/chipdb.py | 25 ++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/ice40/arch.h b/ice40/arch.h index f0f734ce..3b6d23dc 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -153,15 +153,31 @@ NPNR_PACKED_STRUCT(struct BitstreamInfoPOD { RelPtr ierens; }); +NPNR_PACKED_STRUCT(struct BelConfigEntryPOD { + RelPtr entry_name; + RelPtr cbit_name; + int8_t x, y; + int16_t padding; +}); + +// Stores mapping between bel parameters and config bits, +// for extra cells where this mapping is non-trivial +NPNR_PACKED_STRUCT(struct BelConfigPOD { + int32_t bel_index; + int32_t num_entries; + RelPtr entries; +}); + NPNR_PACKED_STRUCT(struct ChipInfoPOD { int32_t width, height; int32_t num_bels, num_wires, num_pips; - int32_t num_switches, num_packages; + int32_t num_switches, num_belcfgs, num_packages; RelPtr bel_data; RelPtr wire_data; RelPtr pip_data; RelPtr tile_grid; RelPtr bits_info; + RelPtr bel_config; RelPtr packages_data; }); diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 698cd173..55ca1c1f 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -38,7 +38,7 @@ switches = list() ierens = list() extra_cells = dict() - +extra_cell_config = dict() packages = list() wire_uphill_belport = dict() @@ -567,6 +567,7 @@ def is_ec_output(ec_entry): def add_bel_ec(ec): ectype, x, y, z = ec bel = len(bel_name) + extra_cell_config[bel] = [] bel_name.append("X%d/Y%d/%s_%d" % (x, y, ectype.lower(), z)) bel_type.append(ectype) bel_pos.append((x, y, z)) @@ -578,8 +579,7 @@ def add_bel_ec(ec): else: add_bel_input(bel, wire_names[entry[1]], entry[0]) else: - # Configuration bit, need to create a structure for these - pass + extra_cell_config[bel].append(entry) for tile_xy, tile_type in sorted(tiles.items()): if tile_type == "logic": @@ -1175,6 +1175,23 @@ bba.l("tile_grid_%s" % dev_name, "TileType") for t in tilegrid: bba.u32(tiletypes[t], "tiletype") +for bel_idx, entries in sorted(extra_cell_config.items()): + if len(entries) > 0: + bba.l("bel%d_config_entries" % bel_idx, "BelConfigEntryPOD") + for entry in entries: + bba.s(entry[0], "entry_name") + bba.s(entry[1][2], "cbit_name") + bba.u8(entry[1][0], "x") + bba.u8(entry[1][1], "y") + bba.u16(0, "padding") + +if len(extra_cell_config) > 0: + bba.l("bel_config_%s" % dev_name, "BelConfigPOD") + for bel_idx, entries in sorted(extra_cell_config.items()): + bba.u32(bel_idx, "bel_index") + bba.u32(len(entries), "num_entries") + bba.r("bel%d_config_entries" % bel_idx if len(entries) > 0 else None, "entries") + bba.l("package_info_%s" % dev_name, "PackageInfoPOD") for info in packageinfo: bba.s(info[0], "name") @@ -1188,12 +1205,14 @@ bba.u32(len(bel_name), "num_bels") bba.u32(num_wires, "num_wires") bba.u32(len(pipinfo), "num_pips") bba.u32(len(switchinfo), "num_switches") +bba.u32(len(extra_cell_config), "num_belcfgs") bba.u32(len(packageinfo), "num_packages") bba.r("bel_data_%s" % dev_name, "bel_data") bba.r("wire_data_%s" % dev_name, "wire_data") bba.r("pip_data_%s" % dev_name, "pip_data") bba.r("tile_grid_%s" % dev_name, "tile_grid") bba.r("bits_info_%s" % dev_name, "bits_info") +bba.r("bel_config_%s" % dev_name if len(extra_cell_config) > 0 else None, "bel_config") bba.r("package_info_%s" % dev_name, "packages_data") bba.finalize() From d221e90706915c8ba540805167c8e9e07d4c3d6f Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 19 Jul 2018 11:43:10 +0200 Subject: [PATCH 21/28] Reducing performance cost of asserts Signed-off-by: David Shah --- common/nextpnr.h | 18 ++++++++++-------- ice40/bitstream.cc | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index f808faf8..7aadfae4 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -72,21 +72,23 @@ class assertion_failure : public std::runtime_error int line; }; -inline void except_assert_impl(bool expr, const char *message, const char *expr_str, const char *filename, int line) +NPNR_NORETURN +inline bool assert_fail_impl(const char *message, const char *expr_str, const char *filename, int line) { - if (!expr) - throw assertion_failure(message, expr_str, filename, line); + throw assertion_failure(message, expr_str, filename, line); } NPNR_NORETURN -inline void assert_false_impl(std::string message, std::string filename, int line) +inline bool assert_fail_impl_str(std::string message, const char *expr_str, const char *filename, int line) { - throw assertion_failure(message, "false", filename, line); + throw assertion_failure(message, expr_str, filename, line); } -#define NPNR_ASSERT(cond) except_assert_impl((cond), #cond, #cond, __FILE__, __LINE__) -#define NPNR_ASSERT_MSG(cond, msg) except_assert_impl((cond), msg, #cond, __FILE__, __LINE__) -#define NPNR_ASSERT_FALSE(msg) assert_false_impl(msg, __FILE__, __LINE__) + +#define NPNR_ASSERT(cond) ((void)((cond) || (assert_fail_impl(#cond, #cond, __FILE__, __LINE__)))) +#define NPNR_ASSERT_MSG(cond, msg) ((void)((cond) || (assert_fail_impl(msg, #cond, __FILE__, __LINE__)))) +#define NPNR_ASSERT_FALSE(msg) (assert_fail_impl(msg, "false", __FILE__, __LINE__)) +#define NPNR_ASSERT_FALSE_STR(msg) (assert_fail_impl_str(msg, "false", __FILE__, __LINE__)) struct BaseCtx; struct Context; diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 35a460f9..09312b07 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -36,7 +36,7 @@ const ConfigEntryPOD &find_config(const TileInfoPOD &tile, const std::string &na return tile.entries[i]; } } - NPNR_ASSERT_FALSE("unable to find config bit " + name); + NPNR_ASSERT_FALSE_STR("unable to find config bit " + name); } std::tuple get_ieren(const BitstreamInfoPOD &bi, int8_t x, int8_t y, int8_t z) From 0cb9ec0757c635982e0bd64f3e314786762c7483 Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 19 Jul 2018 12:04:35 +0200 Subject: [PATCH 22/28] ice40: Add virtual padin wires for intoscs and GB_IOs Signed-off-by: David Shah --- ice40/chipdb.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 55ca1c1f..329fef56 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -159,7 +159,7 @@ def wire_type(name): name = name.split('/')[-1] wt = None - if name.startswith("glb_netwk_"): + if name.startswith("glb_netwk_") or name.startswith("padin_"): wt = "GLOBAL" elif name.startswith("D_IN_") or name.startswith("D_OUT_"): wt = "LOCAL" @@ -432,6 +432,19 @@ with open(args.filename, "r") as f: extra_cells[mode[1]].append((line[0], (int(line[1]), int(line[2]), line[3]))) continue +def add_wire(x, y, name): + global num_wires + wire_idx = num_wires + num_wires = num_wires + 1 + wname = (x, y, name) + wire_names[wname] = wire_idx + wire_names_r[wire_idx] = wname + wire_segments[wire_idx] = dict() + +# Add virtual padin wires +for i in range(8): + add_wire(0, 0, "padin_%d" % i) + def add_bel_input(bel, wire, port): if wire not in wire_downhill_belports: wire_downhill_belports[wire] = set() From 6c38df7295747ddd37a751ea5de2a73e95a021d1 Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 19 Jul 2018 13:22:46 +0200 Subject: [PATCH 23/28] ice40: Adding cell definition for DSPs Signed-off-by: David Shah --- common/nextpnr.h | 3 +- ice40/arch.cc | 8 +++--- ice40/archdefs.h | 2 +- ice40/cells.cc | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ ice40/cells.h | 2 ++ 5 files changed, 80 insertions(+), 7 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 7aadfae4..bc64adb5 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -84,9 +84,8 @@ inline bool assert_fail_impl_str(std::string message, const char *expr_str, cons throw assertion_failure(message, expr_str, filename, line); } - #define NPNR_ASSERT(cond) ((void)((cond) || (assert_fail_impl(#cond, #cond, __FILE__, __LINE__)))) -#define NPNR_ASSERT_MSG(cond, msg) ((void)((cond) || (assert_fail_impl(msg, #cond, __FILE__, __LINE__)))) +#define NPNR_ASSERT_MSG(cond, msg) ((void)((cond) || (assert_fail_impl(msg, #cond, __FILE__, __LINE__)))) #define NPNR_ASSERT_FALSE(msg) (assert_fail_impl(msg, "false", __FILE__, __LINE__)) #define NPNR_ASSERT_FALSE_STR(msg) (assert_fail_impl_str(msg, "false", __FILE__, __LINE__)) diff --git a/ice40/arch.cc b/ice40/arch.cc index 0decc513..1aa02294 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -44,8 +44,8 @@ IdString Arch::belTypeToId(BelType type) const 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_DSP) + return id("ICESTORM_DSP"); if (type == TYPE_ICESTORM_HFOSC) return id("ICESTORM_HFOSC"); if (type == TYPE_ICESTORM_LFOSC) @@ -79,8 +79,8 @@ BelType Arch::belTypeFromId(IdString type) const 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_DSP")) + return TYPE_ICESTORM_DSP; if (type == id("ICESTORM_HFOSC")) return TYPE_ICESTORM_HFOSC; if (type == id("ICESTORM_LFOSC")) diff --git a/ice40/archdefs.h b/ice40/archdefs.h index cf8a78f4..55e2c2fb 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -54,7 +54,7 @@ enum BelType : int32_t TYPE_SB_GB, TYPE_ICESTORM_PLL, TYPE_SB_WARMBOOT, - TYPE_SB_MAC16, + TYPE_ICESTORM_DSP, TYPE_ICESTORM_HFOSC, TYPE_ICESTORM_LFOSC, TYPE_SB_I2C, diff --git a/ice40/cells.cc b/ice40/cells.cc index 8e8679ee..f07e0d22 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -142,6 +142,71 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri for (int i = 0; i < 4; i++) { add_port(ctx, new_cell.get(), "MASKWREN_" + std::to_string(i), PORT_IN); } + } else if (type == ctx->id("ICESTORM_DSP")) { + new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; + + new_cell->params[ctx->id("C_REG")] = "0"; + new_cell->params[ctx->id("A_REG")] = "0"; + new_cell->params[ctx->id("B_REG")] = "0"; + new_cell->params[ctx->id("D_REG")] = "0"; + new_cell->params[ctx->id("TOP_8x8_MULT_REG")] = "0"; + new_cell->params[ctx->id("BOT_8x8_MULT_REG")] = "0"; + new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG1")] = "0"; + new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG2")] = "0"; + + new_cell->params[ctx->id("TOPOUTPUT_SELECT")] = "0"; + new_cell->params[ctx->id("TOPADDSUB_LOWERINPUT")] = "0"; + new_cell->params[ctx->id("TOPADDSUB_UPPERINPUT")] = "0"; + new_cell->params[ctx->id("TOPADDSUB_CARRYSELECT")] = "0"; + + new_cell->params[ctx->id("BOTOUTPUT_SELECT")] = "0"; + new_cell->params[ctx->id("BOTADDSUB_LOWERINPUT")] = "0"; + new_cell->params[ctx->id("BOTADDSUB_UPPERINPUT")] = "0"; + new_cell->params[ctx->id("BOTADDSUB_CARRYSELECT")] = "0"; + + new_cell->params[ctx->id("MODE_8x8")] = "0"; + new_cell->params[ctx->id("A_SIGNED")] = "0"; + new_cell->params[ctx->id("B_SIGNED")] = "0"; + + add_port(ctx, new_cell.get(), "CLK", PORT_IN); + add_port(ctx, new_cell.get(), "CE", PORT_IN); + for (int i = 0; i < 16; i++) { + add_port(ctx, new_cell.get(), "C_" + std::to_string(i), PORT_IN); + add_port(ctx, new_cell.get(), "A_" + std::to_string(i), PORT_IN); + add_port(ctx, new_cell.get(), "B_" + std::to_string(i), PORT_IN); + add_port(ctx, new_cell.get(), "D_" + std::to_string(i), PORT_IN); + } + add_port(ctx, new_cell.get(), "AHOLD", PORT_IN); + add_port(ctx, new_cell.get(), "BHOLD", PORT_IN); + add_port(ctx, new_cell.get(), "CHOLD", PORT_IN); + add_port(ctx, new_cell.get(), "DHOLD", PORT_IN); + + add_port(ctx, new_cell.get(), "IRSTTOP", PORT_IN); + add_port(ctx, new_cell.get(), "IRSTBOT", PORT_IN); + add_port(ctx, new_cell.get(), "ORSTTOP", PORT_IN); + add_port(ctx, new_cell.get(), "ORSTBOT", PORT_IN); + + add_port(ctx, new_cell.get(), "OLOADTOP", PORT_IN); + add_port(ctx, new_cell.get(), "OLOADBOT", PORT_IN); + + add_port(ctx, new_cell.get(), "ADDSUBTOP", PORT_IN); + add_port(ctx, new_cell.get(), "ADDSUBBOT", PORT_IN); + + add_port(ctx, new_cell.get(), "OHOLDTOP", PORT_IN); + add_port(ctx, new_cell.get(), "OHOLDBOT", PORT_IN); + + add_port(ctx, new_cell.get(), "CI", PORT_IN); + add_port(ctx, new_cell.get(), "ACCUMCI", PORT_IN); + add_port(ctx, new_cell.get(), "SIGNEXTIN", PORT_IN); + + for (int i = 0; i < 32; i++) { + add_port(ctx, new_cell.get(), "O_" + std::to_string(i), PORT_OUT); + } + + add_port(ctx, new_cell.get(), "CO", PORT_OUT); + add_port(ctx, new_cell.get(), "ACCUMCO", PORT_OUT); + add_port(ctx, new_cell.get(), "SIGNEXTOUT", PORT_OUT); + } else { log_error("unable to create iCE40 cell of type %s", type.c_str(ctx)); } @@ -258,6 +323,8 @@ bool is_clock_port(const BaseCtx *ctx, const PortRef &port) if (is_ram(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_RAM")) return port.port == ctx->id("RCLK") || port.port == ctx->id("WCLK") || port.port == ctx->id("RCLKN") || port.port == ctx->id("WCLKN"); + if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) + return port.port == ctx->id("CLK"); return false; } @@ -269,6 +336,9 @@ bool is_reset_port(const BaseCtx *ctx, const PortRef &port) return port.port == ctx->id("R") || port.port == ctx->id("S"); if (port.cell->type == ctx->id("ICESTORM_LC")) return port.port == ctx->id("SR"); + if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) + return port.port == ctx->id("IRSTTOP") || port.port == ctx->id("IRSTBOT") || port.port == ctx->id("ORSTTOP") || + port.port == ctx->id("ORSTBOT"); return false; } @@ -280,6 +350,8 @@ bool is_enable_port(const BaseCtx *ctx, const PortRef &port) return port.port == ctx->id("E"); if (port.cell->type == ctx->id("ICESTORM_LC")) return port.port == ctx->id("CEN"); + if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) + return port.port == ctx->id("CE"); return false; } diff --git a/ice40/cells.h b/ice40/cells.h index 9f99835d..2f9c77e8 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -69,6 +69,8 @@ inline bool is_sb_hfosc(const BaseCtx *ctx, const CellInfo *cell) { return cell- inline bool is_sb_spram(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_SPRAM256KA"); } +inline bool is_sb_mac16(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_MAC16"); } + // Convert a SB_LUT primitive to (part of) an ICESTORM_LC, swapping ports // as needed. Set no_dff if a DFF is not being used, so that the output // can be reconnected From bff7d673eda60f1ff8a59fd49a9e57a9ba8fa393 Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 19 Jul 2018 14:03:48 +0200 Subject: [PATCH 24/28] ice40: Packer and bitstream gen support for MAC16s Signed-off-by: David Shah --- ice40/bitstream.cc | 90 +++++++++++++++++++++++++++++++++++++++++++++- ice40/cells.cc | 5 +-- ice40/pack.cc | 19 ++++++++++ 3 files changed, 111 insertions(+), 3 deletions(-) diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 09312b07..c12fa90e 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -90,12 +90,79 @@ std::string get_param_str_or_def(const CellInfo *cell, const IdString param, std char get_hexdigit(int i) { return std::string("0123456789ABCDEF").at(i); } +static const BelConfigPOD &get_ec_config(const ChipInfoPOD *chip, BelId bel) +{ + for (int i = 0; i < chip->num_belcfgs; i++) { + if (chip->bel_config[i].bel_index == bel.index) + return chip->bel_config[i]; + } + NPNR_ASSERT_FALSE("failed to find bel config"); +} + +typedef std::vector>>> chipconfig_t; + +static void set_ec_cbit(chipconfig_t &config, const Context *ctx, const BelConfigPOD &cell_cbits, std::string name, + bool value) +{ + const ChipInfoPOD *chip = ctx->chip_info; + + for (int i = 0; i < cell_cbits.num_entries; i++) { + const auto &cbit = cell_cbits.entries[i]; + if (cbit.entry_name.get() == name) { + const auto &ti = chip->bits_info->tiles_nonrouting[tile_at(ctx, cbit.x, cbit.y)]; + set_config(ti, config.at(cbit.y).at(cbit.x), std::string("IpConfig.") + cbit.cbit_name.get(), value); + return; + } + } + NPNR_ASSERT_FALSE_STR("failed to config extra cell config bit " + name); +} + +void configure_extra_cell(chipconfig_t &config, const Context *ctx, CellInfo *cell, + const std::vector> ¶ms, bool string_style) +{ + const ChipInfoPOD *chip = ctx->chip_info; + const auto &bc = get_ec_config(chip, cell->bel); + for (auto p : params) { + std::vector value; + if (string_style) { + // Lattice's weird string style params, not sure if + // prefixes other than 0b should be supported, only 0b features in docs + std::string raw = get_param_str_or_def(cell, ctx->id(p.first), "0b0"); + assert(raw.substr(0, 2) == "0b"); + raw = raw.substr(2); + value.resize(raw.length()); + for (int i = 0; i < (int)raw.length(); i++) { + if (raw[i] == '1') { + value[(raw.length() - 1) - i] = 1; + } else { + assert(raw[i] == '0'); + value[(raw.length() - 1) - i] = 0; + } + } + } else { + int ival = get_param_or_def(cell, ctx->id(p.first), 0); + + for (int i = 0; i < p.second; i++) + value.push_back((ival >> i) & 0x1); + } + + value.resize(p.second); + if (p.second == 1) { + set_ec_cbit(config, ctx, bc, p.first, value.at(0)); + } else { + for (int i = 0; i < p.second; i++) { + set_ec_cbit(config, ctx, bc, p.first + "_" + std::to_string(i), value.at(i)); + } + } + } +} + void write_asc(const Context *ctx, std::ostream &out) { // [y][x][row][col] const ChipInfoPOD &ci = *ctx->chip_info; const BitstreamInfoPOD &bi = *ci.bits_info; - std::vector>>> config; + chipconfig_t config; config.resize(ci.height); for (int y = 0; y < ci.height; y++) { config.at(y).resize(ci.width); @@ -265,6 +332,27 @@ void write_asc(const Context *ctx, std::ostream &out) NPNR_ASSERT(false); } } + } else if (cell.second->type == ctx->id("ICESTORM_DSP")) { + const std::vector> mac16_params = {{"C_REG", 1}, + {"A_REG", 1}, + {"B_REG", 1}, + {"D_REG", 1}, + {"TOP_8x8_MULT_REG", 1}, + {"BOT_8x8_MULT_REG", 1}, + {"PIPELINE_16x16_MULT_REG1", 1}, + {"PIPELINE_16x16_MULT_REG2", 1}, + {"TOPOUTPUT_SELECT", 2}, + {"TOPADDSUB_LOWERINPUT", 2}, + {"TOPADDSUB_UPPERINPUT", 1}, + {"TOPADDSUB_CARRYSELECT", 2}, + {"BOTOUTPUT_SELECT", 2}, + {"BOTADDSUB_LOWERINPUT", 2}, + {"BOTADDSUB_UPPERINPUT", 1}, + {"BOTADDSUB_CARRYSELECT", 2}, + {"MODE_8x8", 1}, + {"A_SIGNED", 1}, + {"B_SIGNED", 1}}; + configure_extra_cell(config, ctx, cell.second.get(), mac16_params, false); } else { NPNR_ASSERT(false); } diff --git a/ice40/cells.cc b/ice40/cells.cc index f07e0d22..71a65d44 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -350,8 +350,9 @@ bool is_enable_port(const BaseCtx *ctx, const PortRef &port) return port.port == ctx->id("E"); if (port.cell->type == ctx->id("ICESTORM_LC")) return port.port == ctx->id("CEN"); - if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) - return port.port == ctx->id("CE"); + // FIXME + // if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) + // return port.port == ctx->id("CE"); return false; } diff --git a/ice40/pack.cc b/ice40/pack.cc index 5f7e95f3..78df00f6 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -568,6 +568,25 @@ static void pack_special(Context *ctx) replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); } new_cells.push_back(std::move(packed)); + } else if (is_sb_mac16(ctx, ci)) { + std::unique_ptr packed = + create_ice_cell(ctx, ctx->id("ICESTORM_DSP"), ci->name.str(ctx) + "_DSP"); + packed_cells.insert(ci->name); + for (auto attr : ci->attrs) + packed->attrs[attr.first] = attr.second; + for (auto param : ci->params) + packed->params[param.first] = param.second; + + for (auto port : ci->ports) { + PortInfo &pi = port.second; + std::string newname = pi.name.str(ctx); + size_t bpos = newname.find('['); + if (bpos != std::string::npos) { + newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2); + } + replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); + } + new_cells.push_back(std::move(packed)); } } From 79dc910b40b082c9d74d010557b7939fb18535fe Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 19 Jul 2018 14:32:30 +0200 Subject: [PATCH 25/28] ice40: Trim DSP inputs that are constant where appropriate Signed-off-by: David Shah --- generic/archdefs.h | 8 ++++++-- ice40/pack.cc | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/generic/archdefs.h b/generic/archdefs.h index f5999776..06d4ec6e 100644 --- a/generic/archdefs.h +++ b/generic/archdefs.h @@ -52,7 +52,11 @@ typedef IdString PipId; typedef IdString GroupId; typedef IdString DecalId; -struct ArchNetInfo { }; -struct ArchCellInfo { }; +struct ArchNetInfo +{ +}; +struct ArchCellInfo +{ +}; NEXTPNR_NAMESPACE_END diff --git a/ice40/pack.cc b/ice40/pack.cc index 78df00f6..7e2e389c 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -307,6 +307,10 @@ static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constne if ((is_lut(ctx, uc) || is_lc(ctx, uc) || is_carry(ctx, uc)) && (user.port.str(ctx).at(0) == 'I') && !constval) { uc->ports[user.port].net = nullptr; + } else if ((is_sb_mac16(ctx, uc) || uc->type == ctx->id("ICESTORM_DSP")) && + (user.port != ctx->id("CLK") && + ((constval && user.port == ctx->id("CE")) || (!constval && user.port != ctx->id("CE"))))) { + uc->ports[user.port].net = nullptr; } else { uc->ports[user.port].net = constnet; constnet->users.push_back(user); From 3bad9c26cff1ba2da7f1810e5915246874780744 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 20 Jul 2018 11:36:32 +0200 Subject: [PATCH 26/28] ice40: Optimise reset/enable net checking Signed-off-by: David Shah --- ice40/arch.cc | 10 +++++++++- ice40/arch_place.cc | 14 ++++---------- ice40/archdefs.h | 1 + 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/ice40/arch.cc b/ice40/arch.cc index 1aa02294..786d8ba1 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -25,7 +25,7 @@ #include "placer1.h" #include "router1.h" #include "util.h" - +#include "cells.h" NEXTPNR_NAMESPACE_BEGIN // ----------------------------------------------------------------------- @@ -704,6 +704,14 @@ void Arch::assignArchInfo() NetInfo *ni = net.second.get(); if (isGlobalNet(ni)) ni->is_global = true; + ni->is_enable = false; + ni->is_reset = false; + for (auto usr : ni->users) { + if (is_enable_port(this, usr)) + ni->is_enable = true; + if (is_reset_port(this, usr)) + ni->is_reset = true; + } } for (auto &cell : getCtx()->cells) { CellInfo *ci = cell.second.get(); diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 1f2943a0..116ab7d3 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -108,21 +108,15 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const } 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(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(this, user)) - is_cen = true; - } + const NetInfo *net = cell->ports.at(id_glb_buf_out).net; 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) + if (net->is_reset && net->is_enable) return false; - else if (is_reset) + else if (net->is_reset) return (glb_id % 2) == 0; - else if (is_cen) + else if (net->is_enable) return (glb_id % 2) == 1; else return true; diff --git a/ice40/archdefs.h b/ice40/archdefs.h index 55e2c2fb..14b0d2be 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -153,6 +153,7 @@ struct DecalId struct ArchNetInfo { bool is_global = false; + bool is_reset = false, is_enable = false; }; struct NetInfo; From 53034959f338c952f4cf905890e44aad2ba202ae Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 20 Jul 2018 13:27:21 +0200 Subject: [PATCH 27/28] Start adding bitstream reading for ice40 --- gui/designwidget.cc | 11 +-- ice40/bitstream.cc | 166 +++++++++++++++++++++++++++++++++++--------- ice40/bitstream.h | 1 + ice40/main.cc | 8 +++ 4 files changed, 143 insertions(+), 43 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 4123bf30..d28b843b 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -334,16 +334,7 @@ void DesignWidget::newContext(Context *ctx) for (auto pip : nameToItem[2].toStdMap()) { pip_root->addChild(pip.second); } - - // Add nets to tree - nets_root = new QTreeWidgetItem(treeWidget); - nets_root->setText(0, "Nets"); - treeWidget->insertTopLevelItem(0, nets_root); - - // Add cells to tree - cells_root = new QTreeWidgetItem(treeWidget); - cells_root->setText(0, "Cells"); - treeWidget->insertTopLevelItem(0, cells_root); + updateTree(); } void DesignWidget::updateTree() diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index c12fa90e..b0f6260d 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -157,6 +157,42 @@ void configure_extra_cell(chipconfig_t &config, const Context *ctx, CellInfo *ce } } +std::string tagTileType(TileType &tile) +{ + if (tile == TILE_NONE) + return ""; + switch (tile) { + case TILE_LOGIC: + return ".logic_tile"; + break; + case TILE_IO: + return ".io_tile"; + break; + case TILE_RAMB: + return ".ramb_tile"; + break; + case TILE_RAMT: + return ".ramt_tile"; + break; + case TILE_DSP0: + return ".dsp0_tile"; + break; + case TILE_DSP1: + return ".dsp1_tile"; + break; + case TILE_DSP2: + return ".dsp2_tile"; + break; + case TILE_DSP3: + return ".dsp3_tile"; + break; + case TILE_IPCON: + return ".ipcon_tile"; + break; + default: + NPNR_ASSERT(false); + } +} void write_asc(const Context *ctx, std::ostream &out) { // [y][x][row][col] @@ -443,39 +479,7 @@ void write_asc(const Context *ctx, std::ostream &out) for (int y = 0; y < ci.height; y++) { for (int x = 0; x < ci.width; x++) { TileType tile = tile_at(ctx, x, y); - if (tile == TILE_NONE) - continue; - switch (tile) { - case TILE_LOGIC: - out << ".logic_tile"; - break; - case TILE_IO: - out << ".io_tile"; - break; - case TILE_RAMB: - out << ".ramb_tile"; - break; - case TILE_RAMT: - out << ".ramt_tile"; - break; - case TILE_DSP0: - out << ".dsp0_tile"; - break; - case TILE_DSP1: - out << ".dsp1_tile"; - break; - case TILE_DSP2: - out << ".dsp2_tile"; - break; - case TILE_DSP3: - out << ".dsp3_tile"; - break; - case TILE_IPCON: - out << ".ipcon_tile"; - break; - default: - NPNR_ASSERT(false); - } + out << tagTileType(tile); out << " " << x << " " << y << std::endl; for (auto row : config.at(y).at(x)) { for (auto col : row) { @@ -526,4 +530,100 @@ void write_asc(const Context *ctx, std::ostream &out) } } +void read_config(Context *ctx, std::istream &in, chipconfig_t &config) +{ + constexpr size_t line_buf_size = 65536; + char buffer[line_buf_size]; + int tile_x = -1, tile_y = -1, line_nr = -1; + + while (1) { + in.getline(buffer, line_buf_size); + if (buffer[0] == '.') { + line_nr = -1; + const char *tok = strtok(buffer, " \t\r\n"); + + if (!strcmp(tok, ".device")) { + std::string config_device = strtok(nullptr, " \t\r\n"); + std::string expected; + switch (ctx->args.type) { + case ArchArgs::LP384: + expected = "384"; + break; + case ArchArgs::HX1K: + case ArchArgs::LP1K: + expected = "1k"; + break; + case ArchArgs::HX8K: + case ArchArgs::LP8K: + expected = "8k"; + break; + case ArchArgs::UP5K: + expected = "5k"; + break; + default: + log_error("unsupported device type"); + } + if (expected != config_device) + log_error("device type does not match"); + } else if (!strcmp(tok, ".io_tile") || !strcmp(tok, ".logic_tile") || !strcmp(tok, ".ramb_tile") || + !strcmp(tok, ".ramt_tile") || !strcmp(tok, ".ipcon_tile") || !strcmp(tok, ".dsp0_tile") || + !strcmp(tok, ".dsp1_tile") || !strcmp(tok, ".dsp2_tile") || !strcmp(tok, ".dsp3_tile")) { + line_nr = 0; + tile_x = atoi(strtok(nullptr, " \t\r\n")); + tile_y = atoi(strtok(nullptr, " \t\r\n")); + + TileType tile = tile_at(ctx, tile_x, tile_y); + if (tok != tagTileType(tile)) + log_error("Wrong tile type for specified position"); + + } else if (!strcmp(tok, ".extra_bit")) { + /* + int b = atoi(strtok(nullptr, " \t\r\n")); + int x = atoi(strtok(nullptr, " \t\r\n")); + int y = atoi(strtok(nullptr, " \t\r\n")); + std::tuple key(b, x, y); + extra_bits.insert(key); + */ + } else if (!strcmp(tok, ".sym")) { + int net = atoi(strtok(nullptr, " \t\r\n")); (void)net; + const char *name = strtok(nullptr, " \t\r\n"); + std::unique_ptr created_net = std::unique_ptr(new NetInfo); + created_net->name = ctx->id(name); + ctx->nets[created_net->name] = std::move(created_net); + } + } else if (line_nr >= 0 && strlen(buffer) > 0) { + if (line_nr > int(config.at(tile_y).at(tile_x).size() - 1)) + log_error("Invalid data in input asc file"); + for (int i = 0; buffer[i] == '0' || buffer[i] == '1'; i++) + config.at(tile_y).at(tile_x).at(line_nr).at(i) = (buffer[i] == '1') ? 1 : 0; + line_nr++; + } + if (in.eof()) + break; + } +} + +bool read_asc(Context *ctx, std::istream &in) +{ + try { + // [y][x][row][col] + const ChipInfoPOD &ci = *ctx->chip_info; + const BitstreamInfoPOD &bi = *ci.bits_info; + chipconfig_t config; + config.resize(ci.height); + for (int y = 0; y < ci.height; y++) { + config.at(y).resize(ci.width); + for (int x = 0; x < ci.width; x++) { + TileType tile = tile_at(ctx, x, y); + int rows = bi.tiles_nonrouting[tile].rows; + int cols = bi.tiles_nonrouting[tile].cols; + config.at(y).at(x).resize(rows, std::vector(cols)); + } + } + read_config(ctx, in, config); + return true; + } catch (log_execution_error_exception) { + return false; + } +} NEXTPNR_NAMESPACE_END diff --git a/ice40/bitstream.h b/ice40/bitstream.h index 2b6cda1d..41a2ae68 100644 --- a/ice40/bitstream.h +++ b/ice40/bitstream.h @@ -27,6 +27,7 @@ NEXTPNR_NAMESPACE_BEGIN void write_asc(const Context *ctx, std::ostream &out); +bool read_asc(Context *ctx, std::istream &in); NEXTPNR_NAMESPACE_END diff --git a/ice40/main.cc b/ice40/main.cc index e77bdd34..c14b6086 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -95,6 +95,7 @@ int main(int argc, char *argv[]) options.add_options()("json", po::value(), "JSON design file to ingest"); options.add_options()("pcf", po::value(), "PCF constraints file to ingest"); options.add_options()("asc", po::value(), "asc bitstream file to write"); + options.add_options()("read", po::value(), "asc bitstream file to read"); 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"); @@ -353,6 +354,13 @@ int main(int argc, char *argv[]) if (vm.count("no-tmdriv")) ctx->timing_driven = false; + if (vm.count("read")) { + std::string filename = vm["read"].as(); + std::ifstream f(filename); + if (!read_asc(ctx.get(), f)) + log_error("Loading ASC failed.\n"); + } + #ifndef NO_GUI if (vm.count("gui")) { Application a(argc, argv); From 6c835d76f27af79813299419780c039eb2a8b02e Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 20 Jul 2018 14:06:53 +0200 Subject: [PATCH 28/28] Few more checks on parameters and error eol --- ice40/bitstream.cc | 8 ++++---- ice40/main.cc | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index b0f6260d..1b6a9425 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -227,7 +227,7 @@ void write_asc(const Context *ctx, std::ostream &out) out << ".device 5k" << std::endl; break; default: - NPNR_ASSERT_FALSE("unsupported device type"); + NPNR_ASSERT_FALSE("unsupported device type\n"); } // Set pips for (auto pip : ctx->getPips()) { @@ -561,10 +561,10 @@ void read_config(Context *ctx, std::istream &in, chipconfig_t &config) expected = "5k"; break; default: - log_error("unsupported device type"); + log_error("unsupported device type\n"); } if (expected != config_device) - log_error("device type does not match"); + log_error("device type does not match\n"); } else if (!strcmp(tok, ".io_tile") || !strcmp(tok, ".logic_tile") || !strcmp(tok, ".ramb_tile") || !strcmp(tok, ".ramt_tile") || !strcmp(tok, ".ipcon_tile") || !strcmp(tok, ".dsp0_tile") || !strcmp(tok, ".dsp1_tile") || !strcmp(tok, ".dsp2_tile") || !strcmp(tok, ".dsp3_tile")) { @@ -574,7 +574,7 @@ void read_config(Context *ctx, std::istream &in, chipconfig_t &config) TileType tile = tile_at(ctx, tile_x, tile_y); if (tok != tagTileType(tile)) - log_error("Wrong tile type for specified position"); + log_error("Wrong tile type for specified position\n"); } else if (!strcmp(tok, ".extra_bit")) { /* diff --git a/ice40/main.cc b/ice40/main.cc index c14b6086..652196a1 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -66,6 +66,12 @@ void svg_dump_decal(const Context *ctx, const DecalXY &decal) } } +void conflicting_options(const boost::program_options::variables_map &vm, const char *opt1, const char *opt2) +{ + if (vm.count(opt1) && !vm[opt1].defaulted() && vm.count(opt2) && !vm[opt2].defaulted()) + log_error((std::string("Conflicting options '") + opt1 + "' and '" + opt2 + "'.").c_str()); +} + int main(int argc, char *argv[]) { try { @@ -122,13 +128,17 @@ int main(int argc, char *argv[]) po::store(parsed, vm); po::notify(vm); - } - - catch (std::exception &e) { + } catch (std::exception &e) { std::cout << e.what() << "\n"; return 1; } + conflicting_options(vm, "read", "json"); +#ifndef ICE40_HX1K_ONLY + if ((vm.count("lp384") + vm.count("lp1k") + vm.count("lp8k") + vm.count("hx1k") + vm.count("hx8k") + + vm.count("up5k")) > 1) + log_error("Only one device type can be set\n"); +#endif if (vm.count("help") || argc == 1) { help: std::cout << boost::filesystem::basename(argv[0])