diff options
Diffstat (limited to 'ecp5')
-rw-r--r-- | ecp5/arch.cc | 33 | ||||
-rw-r--r-- | ecp5/arch.h | 24 | ||||
-rw-r--r-- | ecp5/archdefs.h | 8 | ||||
-rw-r--r-- | ecp5/cells.cc | 10 | ||||
-rw-r--r-- | ecp5/main.cc | 8 | ||||
-rw-r--r-- | ecp5/pack.cc | 131 | ||||
-rw-r--r-- | ecp5/synth/blinky.v | 86 | ||||
-rw-r--r-- | ecp5/synth/blinky.ys | 9 | ||||
-rw-r--r-- | ecp5/synth/blinky_nopack.ys | 2 | ||||
-rw-r--r-- | ecp5/synth/cells.v | 49 | ||||
-rw-r--r-- | ecp5/synth/simple_map.v | 68 | ||||
-rw-r--r-- | ecp5/synth/ulx3s.v | 18 | ||||
-rw-r--r-- | ecp5/synth/ulx3s.ys | 9 | ||||
-rw-r--r-- | ecp5/synth/wire.v | 11 | ||||
-rw-r--r-- | ecp5/synth/wire.ys | 9 | ||||
-rwxr-xr-x | ecp5/trellis_import.py | 78 |
16 files changed, 318 insertions, 235 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 4bb71b47..944aedea 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -96,13 +96,36 @@ NPNR_PACKED_STRUCT(struct LocationTypePOD { RelPtr<PipInfoPOD> pip_data; }); +NPNR_PACKED_STRUCT(struct PIOInfoPOD { + Location abs_loc; + int32_t bel_index; + RelPtr<char> function_name; + int16_t bank; + int16_t padding; +}); + +NPNR_PACKED_STRUCT(struct PackagePinPOD { + RelPtr<char> name; + Location abs_loc; + int32_t bel_index; +}); + +NPNR_PACKED_STRUCT(struct PackageInfoPOD { + RelPtr<char> name; + int32_t num_pins; + RelPtr<PackagePinPOD> 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<LocationTypePOD> locations; RelPtr<int32_t> location_type; RelPtr<RelPtr<char>> tiletype_names; + RelPtr<PackageInfoPOD> package_info; + RelPtr<PIOInfoPOD> pio_info; }); #if defined(_MSC_VER) @@ -340,6 +363,7 @@ struct ArchArgs struct Arch : BaseCtx { const ChipInfoPOD *chip_info; + const PackageInfoPOD *package_info; mutable std::unordered_map<IdString, BelId> bel_by_name; mutable std::unordered_map<IdString, WireId> wire_by_name; 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..e3532f36 100644 --- a/ecp5/cells.cc +++ b/ecp5/cells.cc @@ -116,6 +116,14 @@ std::unique_ptr<CellInfo> 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)); } @@ -169,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/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<std::string>(), "select device package (defaults to CABGA381)"); + options.add_options()("json", po::value<std::string>(), "JSON design file to ingest"); options.add_options()("seed", po::value<int>(), "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<std::string>(); + else + args.package = "CABGA381"; args.speed = 6; std::unique_ptr<Context> ctx = std::unique_ptr<Context>(new Context(args)); diff --git a/ecp5/pack.cc b/ecp5/pack.cc index c0427d46..11cc2647 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; } @@ -223,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(); @@ -275,6 +299,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 +330,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 +363,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,21 +406,98 @@ 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; } + // 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<CellInfo> gnd_cell = create_ecp5_cell(ctx, ctx->id("LUT4"), "$PACKER_GND"); + gnd_cell->params[ctx->id("INIT")] = "0"; + std::unique_ptr<NetInfo> gnd_net = std::unique_ptr<NetInfo>(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<CellInfo> vcc_cell = create_ecp5_cell(ctx, ctx->id("LUT4"), "$PACKER_VCC"); + vcc_cell->params[ctx->id("INIT")] = "65535"; + std::unique_ptr<NetInfo> vcc_net = std::unique_ptr<NetInfo>(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<IdString> 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(); diff --git a/ecp5/synth/blinky.v b/ecp5/synth/blinky.v index ac7c6ea3..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 [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; + 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)); + (* LOC="G2" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("INPUT")) clk_buf (.B(clk_pin), .O(clk)); - (* BEL="X4/Y71/PIOA" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("INPUT")) btn_buf (.B(btn_pin), .O(btn)); + (* LOC="R1" *) (* IO_TYPE="LVCMOS33" *) + TRELLIS_IO #(.DIR("INPUT")) btn_buf (.B(btn_pin), .O(btn)); - (* BEL="X0/Y23/PIOC" *) (* IO_TYPE="LVCMOS33" *) - TRELLIS_IO #(.DIR("OUTPUT")) led_buf_0 (.B(led_pin[0]), .I(led[0])); - (* BEL="X0/Y23/PIOD" *) (* IO_TYPE="LVCMOS33" *) - 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])); + (* 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])); - (* 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])); + (* 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])); - (* BEL="X0/Y62/PIOD" *) (* 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,24 +54,24 @@ module top(input clk_pin, input btn_pin, output [3: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; // 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/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/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 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<char>") 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") |