aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5
diff options
context:
space:
mode:
Diffstat (limited to 'ecp5')
-rw-r--r--ecp5/arch.cc33
-rw-r--r--ecp5/arch.h24
-rw-r--r--ecp5/archdefs.h7
-rw-r--r--ecp5/cells.cc10
-rw-r--r--ecp5/main.cc8
-rw-r--r--ecp5/pack.cc141
-rw-r--r--ecp5/synth/blinky.v86
-rw-r--r--ecp5/synth/blinky.ys9
-rw-r--r--ecp5/synth/blinky_nopack.ys2
-rw-r--r--ecp5/synth/cells.v49
-rw-r--r--ecp5/synth/simple_map.v68
-rw-r--r--ecp5/synth/ulx3s.v18
-rw-r--r--ecp5/synth/ulx3s.ys9
-rw-r--r--ecp5/synth/wire.v11
-rw-r--r--ecp5/synth/wire.ys9
-rwxr-xr-xecp5/trellis_import.py78
16 files changed, 337 insertions, 225 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 84a431fd..941607ba 100644
--- a/ecp5/archdefs.h
+++ b/ecp5/archdefs.h
@@ -129,6 +129,13 @@ struct DecalId
}
};
+struct ArchNetInfo
+{
+};
+struct ArchCellInfo
+{
+};
+
NEXTPNR_NAMESPACE_END
namespace std {
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 1900eded..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));
@@ -359,10 +391,113 @@ 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(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")