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)
|
||||
return TMG_CLOCK_INPUT;
|
||||
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));
|
||||
}
|
||||
@ -1144,6 +1154,17 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
|
||||
info.setup.delay = 100;
|
||||
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 {
|
||||
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") ||
|
||||
cell.second->type == ctx->id("SB_LEDDA_IP")) {
|
||||
// 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")) {
|
||||
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
||||
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(), "PWMOUT2", 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 {
|
||||
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_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)
|
||||
{
|
||||
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)) {
|
||||
/* Force placement (no choices anyway) */
|
||||
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)) {
|
||||
bool is_pad = is_sb_pll40_pad(ctx, ci);
|
||||
bool is_core = !is_pad;
|
||||
|
Loading…
Reference in New Issue
Block a user