more like ecp5
This commit is contained in:
parent
3624fe90b2
commit
6f85053b03
@ -18,14 +18,20 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "bitstream.h"
|
#include "bitstream.h"
|
||||||
|
|
||||||
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <queue>
|
||||||
|
#include <regex>
|
||||||
|
#include <streambuf>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "nextpnr.h"
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#define fmt_str(x) (static_cast<const std::ostringstream &>(std::ostringstream() << x).str())
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
// These seem simple enough to do inline for now.
|
// These seem simple enough to do inline for now.
|
||||||
@ -129,6 +135,54 @@ struct MachXO2Bitgen
|
|||||||
rel_prefix += "W" + std::to_string(loc.x - wire.location.x);
|
rel_prefix += "W" + std::to_string(loc.x - wire.location.x);
|
||||||
return rel_prefix + "_" + basename;
|
return rel_prefix + "_" + basename;
|
||||||
}
|
}
|
||||||
|
std::vector<bool> int_to_bitvector(int val, int size)
|
||||||
|
{
|
||||||
|
std::vector<bool> bv;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
bv.push_back((val & (1 << i)) != 0);
|
||||||
|
}
|
||||||
|
return bv;
|
||||||
|
}
|
||||||
|
std::vector<bool> str_to_bitvector(std::string str, int size)
|
||||||
|
{
|
||||||
|
std::vector<bool> bv;
|
||||||
|
bv.resize(size, 0);
|
||||||
|
if (str.substr(0, 2) != "0b")
|
||||||
|
log_error("error parsing value '%s', expected 0b prefix\n", str.c_str());
|
||||||
|
for (int i = 0; i < int(str.size()) - 2; i++) {
|
||||||
|
char c = str.at((str.size() - i) - 1);
|
||||||
|
NPNR_ASSERT(c == '0' || c == '1');
|
||||||
|
bv.at(i) = (c == '1');
|
||||||
|
}
|
||||||
|
return bv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the PIC tile corresponding to a PIO bel
|
||||||
|
std::string get_pic_tile(BelId bel)
|
||||||
|
{
|
||||||
|
static const std::set<std::string> pio_t = {"PIC_T0", "PIC_T0_256", "PIC_TS0"};
|
||||||
|
static const std::set<std::string> pio_b = {"PIC_B0", "PIC_B0_256", "PIC_BS0_256"};
|
||||||
|
static const std::set<std::string> pio_l = {"PIC_L0", "PIC_L1", "PIC_L2", "PIC_L3", "PIC_LS0",
|
||||||
|
"PIC_L0_VREF3", "PIC_L0_VREF4", "PIC_L0_VREF5",
|
||||||
|
"PIC_L1_VREF3", "PIC_L1_VREF4", "PIC_L1_VREF5",
|
||||||
|
"PIC_L2_VREF4", "PIC_L2_VREF5",
|
||||||
|
"PIC_L3_VREF4", "PIC_L3_VREF5"};
|
||||||
|
static const std::set<std::string> pio_r = {"PIC_R0", "PIC_R1", "PIC_RS0",
|
||||||
|
"PIC_R0_256", "PIC_R1_640", "PIC_RS0_256"};
|
||||||
|
|
||||||
|
std::string pio_name = ctx->tile_info(bel)->bel_data[bel.index].name.get();
|
||||||
|
if (bel.location.y == 0) {
|
||||||
|
return ctx->get_tile_by_type_loc(0, bel.location.x, pio_t);
|
||||||
|
} else if (bel.location.y == ctx->chip_info->height - 1) {
|
||||||
|
return ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, pio_b);
|
||||||
|
} else if (bel.location.x == 0) {
|
||||||
|
return ctx->get_tile_by_type_loc(bel.location.y, 0, pio_l);
|
||||||
|
} else if (bel.location.x == ctx->chip_info->width - 1) {
|
||||||
|
return ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, pio_r);
|
||||||
|
} else {
|
||||||
|
NPNR_ASSERT_FALSE("bad PIO location");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void set_pip(ChipConfig &cc, PipId pip)
|
void set_pip(ChipConfig &cc, PipId pip)
|
||||||
{
|
{
|
||||||
@ -199,15 +253,6 @@ struct MachXO2Bitgen
|
|||||||
return permuted_init;
|
return permuted_init;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<bool> int_to_bitvector(int val, int size)
|
|
||||||
{
|
|
||||||
std::vector<bool> bv;
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
bv.push_back((val & (1 << i)) != 0);
|
|
||||||
}
|
|
||||||
return bv;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string intstr_or_default(const dict<IdString, Property> &ct, const IdString &key, std::string def = "0")
|
std::string intstr_or_default(const dict<IdString, Property> &ct, const IdString &key, std::string def = "0")
|
||||||
{
|
{
|
||||||
auto found = ct.find(key);
|
auto found = ct.find(key);
|
||||||
@ -221,31 +266,78 @@ struct MachXO2Bitgen
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the PIC tile corresponding to a PIO bel
|
void write_comb(CellInfo *ci)
|
||||||
std::string get_pic_tile(BelId bel)
|
|
||||||
{
|
{
|
||||||
static const std::set<std::string> pio_t = {"PIC_T0", "PIC_T0_256", "PIC_TS0"};
|
pool<IdString> used_phys_pins;
|
||||||
static const std::set<std::string> pio_b = {"PIC_B0", "PIC_B0_256", "PIC_BS0_256"};
|
BelId bel = ci->bel;
|
||||||
static const std::set<std::string> pio_l = {"PIC_L0", "PIC_L1", "PIC_L2", "PIC_L3", "PIC_LS0",
|
std::string tname = ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, "PLC");
|
||||||
"PIC_L0_VREF3", "PIC_L0_VREF4", "PIC_L0_VREF5",
|
int z = ctx->tile_info(bel)->bel_data[bel.index].z >> Arch::lc_idx_shift;
|
||||||
"PIC_L1_VREF3", "PIC_L1_VREF4", "PIC_L1_VREF5",
|
std::string slice = std::string("SLICE") + "ABCD"[z / 2];
|
||||||
"PIC_L2_VREF4", "PIC_L2_VREF5",
|
std::string lc = std::to_string(z % 2);
|
||||||
"PIC_L3_VREF4", "PIC_L3_VREF5"};
|
std::string mode = str_or_default(ci->params, id_MODE, "LOGIC");
|
||||||
static const std::set<std::string> pio_r = {"PIC_R0", "PIC_R1", "PIC_RS0",
|
if (mode == "RAMW_BLOCK")
|
||||||
"PIC_R0_256", "PIC_R1_640", "PIC_RS0_256"};
|
return;
|
||||||
|
int lut_init = int_or_default(ci->params, id_INITVAL);
|
||||||
std::string pio_name = ctx->tile_info(bel)->bel_data[bel.index].name.get();
|
cc.tiles[tname].add_enum(slice + ".MODE", mode);
|
||||||
if (bel.location.y == 0) {
|
cc.tiles[tname].add_word(slice + ".K" + lc + ".INIT",
|
||||||
return ctx->get_tile_by_type_loc(0, bel.location.x, pio_t);
|
int_to_bitvector(permute_lut(ci, used_phys_pins, lut_init), 16));
|
||||||
} else if (bel.location.y == ctx->chip_info->height - 1) {
|
if (mode == "CCU2") {
|
||||||
return ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, pio_b);
|
cc.tiles[tname].add_enum(slice + ".CCU2.INJECT1_" + lc, str_or_default(ci->params, id_CCU2_INJECT1, "YES"));
|
||||||
} else if (bel.location.x == 0) {
|
|
||||||
return ctx->get_tile_by_type_loc(bel.location.y, 0, pio_l);
|
|
||||||
} else if (bel.location.x == ctx->chip_info->width - 1) {
|
|
||||||
return ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, pio_r);
|
|
||||||
} else {
|
} else {
|
||||||
NPNR_ASSERT_FALSE("bad PIO location");
|
// Don't interfere with cascade mux wiring
|
||||||
|
cc.tiles[tname].add_enum(slice + ".CCU2.INJECT1_" + lc, "_NONE_");
|
||||||
}
|
}
|
||||||
|
if (mode == "DPRAM" && slice == "SLICEA" && lc == "0") {
|
||||||
|
cc.tiles[tname].add_enum(slice + ".WREMUX", str_or_default(ci->params, id_WREMUX, "WRE"));
|
||||||
|
std::string wckmux = str_or_default(ci->params, id_WCKMUX, "WCK");
|
||||||
|
wckmux = (wckmux == "WCK") ? "CLK" : wckmux;
|
||||||
|
cc.tiles[tname].add_enum("CLK1.CLKMUX", wckmux);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_ff(CellInfo *ci)
|
||||||
|
{
|
||||||
|
BelId bel = ci->bel;
|
||||||
|
std::string tname = ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, "PLC");
|
||||||
|
int z = ctx->tile_info(bel)->bel_data[bel.index].z >> Arch::lc_idx_shift;
|
||||||
|
std::string slice = std::string("SLICE") + "ABCD"[z / 2];
|
||||||
|
std::string lc = std::to_string(z % 2);
|
||||||
|
|
||||||
|
cc.tiles[tname].add_enum(slice + ".MODE", str_or_default(ci->params, id_MODE, "LOGIC"));
|
||||||
|
cc.tiles[tname].add_enum(slice + ".GSR", str_or_default(ci->params, id_GSR, "ENABLED"));
|
||||||
|
cc.tiles[tname].add_enum(slice + ".REGMODE", str_or_default(ci->params, id_REGMODE, "FF"));
|
||||||
|
cc.tiles[tname].add_enum(slice + ".REG" + lc + ".SD", intstr_or_default(ci->params, id_SD, "0"));
|
||||||
|
cc.tiles[tname].add_enum(slice + ".REG" + lc + ".REGSET", str_or_default(ci->params, id_REGSET, "RESET"));
|
||||||
|
|
||||||
|
cc.tiles[tname].add_enum(slice + ".CEMUX", str_or_default(ci->params, id_CEMUX, "1"));
|
||||||
|
|
||||||
|
NetInfo *lsrnet = ci->getPort(id_LSR);
|
||||||
|
if (ctx->getBoundWireNet(ctx->get_wire_by_loc_basename(bel.location, "LSR0")) == lsrnet) {
|
||||||
|
cc.tiles[tname].add_enum("LSR0.LSRMUX", str_or_default(ci->params, id_LSRMUX, "LSR"));
|
||||||
|
cc.tiles[tname].add_enum("LSR0.LSRONMUX", str_or_default(ci->params, id_LSRONMUX, "LSRMUX"));
|
||||||
|
}
|
||||||
|
if (ctx->getBoundWireNet(ctx->get_wire_by_loc_basename(bel.location, "LSR1")) == lsrnet) {
|
||||||
|
cc.tiles[tname].add_enum("LSR1.LSRMUX", str_or_default(ci->params, id_LSRMUX, "LSR"));
|
||||||
|
cc.tiles[tname].add_enum("LSR1.LSRONMUX", str_or_default(ci->params, id_LSRONMUX, "LSRMUX"));
|
||||||
|
}
|
||||||
|
|
||||||
|
NetInfo *clknet = ci->getPort(id_CLK);
|
||||||
|
if (ctx->getBoundWireNet(ctx->get_wire_by_loc_basename(bel.location, "CLK0")) == clknet) {
|
||||||
|
cc.tiles[tname].add_enum("CLK0.CLKMUX", str_or_default(ci->params, id_CLKMUX, "0"));
|
||||||
|
}
|
||||||
|
if (ctx->getBoundWireNet(ctx->get_wire_by_loc_basename(bel.location, "CLK1")) == clknet) {
|
||||||
|
cc.tiles[tname].add_enum("CLK1.CLKMUX", str_or_default(ci->params, id_CLKMUX, "0"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_io(CellInfo *ci)
|
||||||
|
{
|
||||||
|
BelId bel = ci->bel;
|
||||||
|
std::string pio = ctx->tile_info(bel)->bel_data[bel.index].name.get();
|
||||||
|
std::string iotype = str_or_default(ci->attrs, id_IO_TYPE, "LVCMOS33");
|
||||||
|
std::string dir = str_or_default(ci->params, id_DIR, "INPUT");
|
||||||
|
std::string pic_tile = get_pic_tile(bel);
|
||||||
|
cc.tiles[pic_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
@ -312,72 +404,16 @@ struct MachXO2Bitgen
|
|||||||
BelId bel = ci->bel;
|
BelId bel = ci->bel;
|
||||||
|
|
||||||
if (ci->type == id_TRELLIS_COMB) {
|
if (ci->type == id_TRELLIS_COMB) {
|
||||||
pool<IdString> used_phys_pins;
|
write_comb(ci);
|
||||||
std::string tname = ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, "PLC");
|
|
||||||
int z = ctx->tile_info(bel)->bel_data[bel.index].z >> Arch::lc_idx_shift;
|
|
||||||
std::string slice = std::string("SLICE") + "ABCD"[z / 2];
|
|
||||||
std::string lc = std::to_string(z % 2);
|
|
||||||
std::string mode = str_or_default(ci->params, id_MODE, "LOGIC");
|
|
||||||
if (mode == "RAMW_BLOCK")
|
|
||||||
return;
|
|
||||||
int lut_init = int_or_default(ci->params, id_INITVAL);
|
|
||||||
cc.tiles[tname].add_enum(slice + ".MODE", mode);
|
|
||||||
cc.tiles[tname].add_word(slice + ".K" + lc + ".INIT",
|
|
||||||
int_to_bitvector(permute_lut(ci, used_phys_pins, lut_init), 16));
|
|
||||||
if (mode == "CCU2") {
|
|
||||||
cc.tiles[tname].add_enum(slice + ".CCU2.INJECT1_" + lc, str_or_default(ci->params, id_CCU2_INJECT1, "YES"));
|
|
||||||
} else {
|
|
||||||
// Don't interfere with cascade mux wiring
|
|
||||||
cc.tiles[tname].add_enum(slice + ".CCU2.INJECT1_" + lc, "_NONE_");
|
|
||||||
}
|
|
||||||
if (mode == "DPRAM" && slice == "SLICEA" && lc == "0") {
|
|
||||||
cc.tiles[tname].add_enum(slice + ".WREMUX", str_or_default(ci->params, id_WREMUX, "WRE"));
|
|
||||||
std::string wckmux = str_or_default(ci->params, id_WCKMUX, "WCK");
|
|
||||||
wckmux = (wckmux == "WCK") ? "CLK" : wckmux;
|
|
||||||
cc.tiles[tname].add_enum("CLK1.CLKMUX", wckmux);
|
|
||||||
}
|
|
||||||
} else if (ci->type == id_TRELLIS_FF) {
|
} else if (ci->type == id_TRELLIS_FF) {
|
||||||
std::string tname = ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, "PLC");
|
write_ff(ci);
|
||||||
int z = ctx->tile_info(bel)->bel_data[bel.index].z >> Arch::lc_idx_shift;
|
|
||||||
std::string slice = std::string("SLICE") + "ABCD"[z / 2];
|
|
||||||
std::string lc = std::to_string(z % 2);
|
|
||||||
|
|
||||||
cc.tiles[tname].add_enum(slice + ".MODE", str_or_default(ci->params, id_MODE, "LOGIC"));
|
|
||||||
cc.tiles[tname].add_enum(slice + ".GSR", str_or_default(ci->params, id_GSR, "ENABLED"));
|
|
||||||
cc.tiles[tname].add_enum(slice + ".REGMODE", str_or_default(ci->params, id_REGMODE, "FF"));
|
|
||||||
cc.tiles[tname].add_enum(slice + ".REG" + lc + ".SD", intstr_or_default(ci->params, id_SD, "0"));
|
|
||||||
cc.tiles[tname].add_enum(slice + ".REG" + lc + ".REGSET", str_or_default(ci->params, id_REGSET, "RESET"));
|
|
||||||
|
|
||||||
cc.tiles[tname].add_enum(slice + ".CEMUX", str_or_default(ci->params, id_CEMUX, "1"));
|
|
||||||
|
|
||||||
NetInfo *lsrnet = ci->getPort(id_LSR);
|
|
||||||
if (ctx->getBoundWireNet(ctx->get_wire_by_loc_basename(bel.location, "LSR0")) == lsrnet) {
|
|
||||||
cc.tiles[tname].add_enum("LSR0.LSRMUX", str_or_default(ci->params, id_LSRMUX, "LSR"));
|
|
||||||
cc.tiles[tname].add_enum("LSR0.LSRONMUX", str_or_default(ci->params, id_LSRONMUX, "LSRMUX"));
|
|
||||||
}
|
|
||||||
if (ctx->getBoundWireNet(ctx->get_wire_by_loc_basename(bel.location, "LSR1")) == lsrnet) {
|
|
||||||
cc.tiles[tname].add_enum("LSR1.LSRMUX", str_or_default(ci->params, id_LSRMUX, "LSR"));
|
|
||||||
cc.tiles[tname].add_enum("LSR1.LSRONMUX", str_or_default(ci->params, id_LSRONMUX, "LSRMUX"));
|
|
||||||
}
|
|
||||||
|
|
||||||
NetInfo *clknet = ci->getPort(id_CLK);
|
|
||||||
if (ctx->getBoundWireNet(ctx->get_wire_by_loc_basename(bel.location, "CLK0")) == clknet) {
|
|
||||||
cc.tiles[tname].add_enum("CLK0.CLKMUX", str_or_default(ci->params, id_CLKMUX, "0"));
|
|
||||||
}
|
|
||||||
if (ctx->getBoundWireNet(ctx->get_wire_by_loc_basename(bel.location, "CLK1")) == clknet) {
|
|
||||||
cc.tiles[tname].add_enum("CLK1.CLKMUX", str_or_default(ci->params, id_CLKMUX, "0"));
|
|
||||||
}
|
|
||||||
} else if (ci->type == id_TRELLIS_RAMW) {
|
} else if (ci->type == id_TRELLIS_RAMW) {
|
||||||
std::string tname = ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, "PLC");
|
std::string tname = ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, "PLC");
|
||||||
cc.tiles[tname].add_enum("SLICEC.MODE", "RAMW");
|
cc.tiles[tname].add_enum("SLICEC.MODE", "RAMW");
|
||||||
cc.tiles[tname].add_word("SLICEC.K0.INIT", std::vector<bool>(16, false));
|
cc.tiles[tname].add_word("SLICEC.K0.INIT", std::vector<bool>(16, false));
|
||||||
cc.tiles[tname].add_word("SLICEC.K1.INIT", std::vector<bool>(16, false));
|
cc.tiles[tname].add_word("SLICEC.K1.INIT", std::vector<bool>(16, false));
|
||||||
} else if (ci->type == id_TRELLIS_IO) {
|
} else if (ci->type == id_TRELLIS_IO) {
|
||||||
std::string pio = ctx->tile_info(bel)->bel_data[bel.index].name.get();
|
write_io(ci);
|
||||||
std::string iotype = str_or_default(ci->attrs, id_IO_TYPE, "LVCMOS33");
|
|
||||||
std::string dir = str_or_default(ci->params, id_DIR, "INPUT");
|
|
||||||
std::string pic_tile = get_pic_tile(bel);
|
|
||||||
cc.tiles[pic_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype);
|
|
||||||
} else if (ci->type == id_OSCH) {
|
} else if (ci->type == id_OSCH) {
|
||||||
std::string freq = str_or_default(ci->params, id_NOM_FREQ, "2.08");
|
std::string freq = str_or_default(ci->params, id_NOM_FREQ, "2.08");
|
||||||
cc.tiles[ctx->get_tile_by_type("CFG1")].add_enum("OSCH.MODE", "OSCH");
|
cc.tiles[ctx->get_tile_by_type("CFG1")].add_enum("OSCH.MODE", "OSCH");
|
||||||
@ -399,4 +435,5 @@ void write_bitstream(Context *ctx, std::string text_config_file)
|
|||||||
out_config << bitgen.cc;
|
out_config << bitgen.cc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
Loading…
Reference in New Issue
Block a user