ice40: Add support for SB_I2C and SB_SPI
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
This commit is contained in:
parent
c2d87846d8
commit
d401e3e1a0
@ -1053,6 +1053,16 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
|
|||||||
if (port == id_CLK || port == id_CLOCK)
|
if (port == id_CLK || port == id_CLOCK)
|
||||||
return TMG_CLOCK_INPUT;
|
return TMG_CLOCK_INPUT;
|
||||||
return TMG_IGNORE;
|
return TMG_IGNORE;
|
||||||
|
} else if (cell->type == id_SB_I2C || cell->type == id_SB_SPI) {
|
||||||
|
if (port == this->id("SBCLKI"))
|
||||||
|
return TMG_CLOCK_INPUT;
|
||||||
|
|
||||||
|
clockInfoCount = 1;
|
||||||
|
|
||||||
|
if (cell->ports.at(port).type == PORT_OUT)
|
||||||
|
return TMG_REGISTER_OUTPUT;
|
||||||
|
else
|
||||||
|
return TMG_REGISTER_INPUT;
|
||||||
}
|
}
|
||||||
log_error("cell type '%s' is unsupported (instantiated as '%s')\n", cell->type.c_str(this), cell->name.c_str(this));
|
log_error("cell type '%s' is unsupported (instantiated as '%s')\n", cell->type.c_str(this), cell->name.c_str(this));
|
||||||
}
|
}
|
||||||
@ -1144,6 +1154,17 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
|
|||||||
info.setup.delay = 100;
|
info.setup.delay = 100;
|
||||||
info.hold.delay = 0;
|
info.hold.delay = 0;
|
||||||
}
|
}
|
||||||
|
} else if (cell->type == id_SB_I2C || cell->type == id_SB_SPI) {
|
||||||
|
info.clock_port = this->id("SBCLKI");
|
||||||
|
info.edge = RISING_EDGE;
|
||||||
|
if (cell->ports.at(port).type == PORT_OUT) {
|
||||||
|
/* Dummy number */
|
||||||
|
info.clockToQ.delay = 1500;
|
||||||
|
} else {
|
||||||
|
/* Dummy number */
|
||||||
|
info.setup.delay = 1500;
|
||||||
|
info.hold.delay = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
NPNR_ASSERT_FALSE("unhandled cell type in getPortClockingInfo");
|
NPNR_ASSERT_FALSE("unhandled cell type in getPortClockingInfo");
|
||||||
}
|
}
|
||||||
|
@ -618,6 +618,28 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
} else if (cell.second->type == ctx->id("SB_WARMBOOT") || cell.second->type == ctx->id("ICESTORM_LFOSC") ||
|
} else if (cell.second->type == ctx->id("SB_WARMBOOT") || cell.second->type == ctx->id("ICESTORM_LFOSC") ||
|
||||||
cell.second->type == ctx->id("SB_LEDDA_IP")) {
|
cell.second->type == ctx->id("SB_LEDDA_IP")) {
|
||||||
// No config needed
|
// No config needed
|
||||||
|
} else if (cell.second->type == ctx->id("SB_I2C")) {
|
||||||
|
bool sda_in_dly = !cell.second->attrs.count(ctx->id("SDA_INPUT_DELAYED")) ||
|
||||||
|
std::stoi(cell.second->attrs[ctx->id("SDA_INPUT_DELAYED")]);
|
||||||
|
bool sda_out_dly = !cell.second->attrs.count(ctx->id("SDA_OUTPUT_DELAYED")) ||
|
||||||
|
std::stoi(cell.second->attrs[ctx->id("SDA_OUTPUT_DELAYED")]);
|
||||||
|
set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "SDA_INPUT_DELAYED", sda_in_dly,
|
||||||
|
"IpConfig.");
|
||||||
|
set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "SDA_OUTPUT_DELAYED", sda_out_dly,
|
||||||
|
"IpConfig.");
|
||||||
|
set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "I2C_ENABLE_0", true,
|
||||||
|
"IpConfig.");
|
||||||
|
set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "I2C_ENABLE_1", true,
|
||||||
|
"IpConfig.");
|
||||||
|
} else if (cell.second->type == ctx->id("SB_SPI")) {
|
||||||
|
set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "SPI_ENABLE_0", true,
|
||||||
|
"IpConfig.");
|
||||||
|
set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "SPI_ENABLE_1", true,
|
||||||
|
"IpConfig.");
|
||||||
|
set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "SPI_ENABLE_2", true,
|
||||||
|
"IpConfig.");
|
||||||
|
set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "SPI_ENABLE_3", true,
|
||||||
|
"IpConfig.");
|
||||||
} else if (cell.second->type == ctx->id("ICESTORM_SPRAM")) {
|
} else if (cell.second->type == ctx->id("ICESTORM_SPRAM")) {
|
||||||
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
||||||
int x = beli.x, y = beli.y, z = beli.z;
|
int x = beli.x, y = beli.y, z = beli.z;
|
||||||
|
@ -275,6 +275,53 @@ std::unique_ptr<CellInfo> create_ice_cell(Context *ctx, IdString type, std::stri
|
|||||||
add_port(ctx, new_cell.get(), "PWMOUT1", PORT_OUT);
|
add_port(ctx, new_cell.get(), "PWMOUT1", PORT_OUT);
|
||||||
add_port(ctx, new_cell.get(), "PWMOUT2", PORT_OUT);
|
add_port(ctx, new_cell.get(), "PWMOUT2", PORT_OUT);
|
||||||
add_port(ctx, new_cell.get(), "LEDDON", PORT_OUT);
|
add_port(ctx, new_cell.get(), "LEDDON", PORT_OUT);
|
||||||
|
} else if (type == ctx->id("SB_I2C")) {
|
||||||
|
new_cell->params[ctx->id("I2C_SLAVE_INIT_ADDR")] = "0b1111100001";
|
||||||
|
new_cell->params[ctx->id("BUS_ADDR74")] = "0b0001";
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
add_port(ctx, new_cell.get(), "SBADRI" + std::to_string(i), PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SBDATI" + std::to_string(i), PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SBDATO" + std::to_string(i), PORT_OUT);
|
||||||
|
}
|
||||||
|
add_port(ctx, new_cell.get(), "SBCLKI", PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SBRWI", PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SBSTBI", PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SCLI", PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SDAI", PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SBACKO", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "I2CIRQ", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "I2CWKUP", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "SCLO", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "SCLOE", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "SDAO", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "SDAOE", PORT_OUT);
|
||||||
|
} else if (type == ctx->id("SB_SPI")) {
|
||||||
|
new_cell->params[ctx->id("BUS_ADDR74")] = "0b0000";
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
add_port(ctx, new_cell.get(), "SBADRI" + std::to_string(i), PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SBDATI" + std::to_string(i), PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SBDATO" + std::to_string(i), PORT_OUT);
|
||||||
|
}
|
||||||
|
add_port(ctx, new_cell.get(), "SBCLKI", PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SBRWI", PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SBSTBI", PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "MI", PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SI", PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SCKI", PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SCSNI", PORT_IN);
|
||||||
|
add_port(ctx, new_cell.get(), "SBACKO", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "SPIIRQ", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "SPIWKUP", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "SO", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "SOE", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "MO", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "MOE", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "SCKO", PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "SCKOE", PORT_OUT);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
add_port(ctx, new_cell.get(), "MCSNO" + std::to_string(i), PORT_OUT);
|
||||||
|
add_port(ctx, new_cell.get(), "MCSNOE" + std::to_string(i), PORT_OUT);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log_error("unable to create iCE40 cell of type %s", type.c_str(ctx));
|
log_error("unable to create iCE40 cell of type %s", type.c_str(ctx));
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,10 @@ inline bool is_sb_rgba_drv(const BaseCtx *ctx, const CellInfo *cell) { return ce
|
|||||||
|
|
||||||
inline bool is_sb_ledda_ip(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LEDDA_IP"); }
|
inline bool is_sb_ledda_ip(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LEDDA_IP"); }
|
||||||
|
|
||||||
|
inline bool is_sb_i2c(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_I2C"); }
|
||||||
|
|
||||||
|
inline bool is_sb_spi(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_SPI"); }
|
||||||
|
|
||||||
inline bool is_sb_pll40(const BaseCtx *ctx, const CellInfo *cell)
|
inline bool is_sb_pll40(const BaseCtx *ctx, const CellInfo *cell)
|
||||||
{
|
{
|
||||||
return cell->type == ctx->id("SB_PLL40_PAD") || cell->type == ctx->id("SB_PLL40_2_PAD") ||
|
return cell->type == ctx->id("SB_PLL40_PAD") || cell->type == ctx->id("SB_PLL40_2_PAD") ||
|
||||||
|
@ -1056,7 +1056,24 @@ static void pack_special(Context *ctx)
|
|||||||
} else if (is_sb_ledda_ip(ctx, ci)) {
|
} else if (is_sb_ledda_ip(ctx, ci)) {
|
||||||
/* Force placement (no choices anyway) */
|
/* Force placement (no choices anyway) */
|
||||||
cell_place_unique(ctx, ci);
|
cell_place_unique(ctx, ci);
|
||||||
|
} else if (is_sb_i2c(ctx, ci) || is_sb_spi(ctx, ci)) {
|
||||||
|
const std::map<std::tuple<IdString, std::string>, Loc> map_ba74 = {
|
||||||
|
{std::make_tuple(id_SB_SPI, "0b0000"), Loc(0, 0, 0)},
|
||||||
|
{std::make_tuple(id_SB_I2C, "0b0001"), Loc(0, 31, 0)},
|
||||||
|
{std::make_tuple(id_SB_SPI, "0b0010"), Loc(25, 0, 1)},
|
||||||
|
{std::make_tuple(id_SB_I2C, "0b0011"), Loc(25, 31, 0)},
|
||||||
|
};
|
||||||
|
if (map_ba74.find(std::make_tuple(ci->type, ci->params[ctx->id("BUS_ADDR74")])) == map_ba74.end())
|
||||||
|
log_error("Invalid value for BUS_ADDR74 for cell '%s' of type '%s'\n", ci->name.c_str(ctx),
|
||||||
|
ci->type.c_str(ctx));
|
||||||
|
Loc bel_loc = map_ba74.at(std::make_tuple(ci->type, ci->params[ctx->id("BUS_ADDR74")]));
|
||||||
|
BelId bel = ctx->getBelByLocation(bel_loc);
|
||||||
|
if (bel == BelId() || ctx->getBelType(bel) != ci->type)
|
||||||
|
log_error("Unable to find placement for cell '%s' of type '%s'\n", ci->name.c_str(ctx),
|
||||||
|
ci->type.c_str(ctx));
|
||||||
|
IdString bel_name = ctx->getBelName(bel);
|
||||||
|
ci->attrs[ctx->id("BEL")] = bel_name.str(ctx);
|
||||||
|
log_info(" constrained %s '%s' to %s\n", ci->type.c_str(ctx), ci->name.c_str(ctx), bel_name.c_str(ctx));
|
||||||
} else if (is_sb_pll40(ctx, ci)) {
|
} else if (is_sb_pll40(ctx, ci)) {
|
||||||
bool is_pad = is_sb_pll40_pad(ctx, ci);
|
bool is_pad = is_sb_pll40_pad(ctx, ci);
|
||||||
bool is_core = !is_pad;
|
bool is_core = !is_pad;
|
||||||
|
Loading…
Reference in New Issue
Block a user