ice40: add RGB_DRV/LED_DRV_CUR support for u4k

This commit is contained in:
Simon Schubert 2019-06-10 11:30:01 +02:00
parent 187db92b05
commit 88eeafae12
8 changed files with 77 additions and 4 deletions

View File

@ -1045,6 +1045,14 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
return TMG_COMB_INPUT; return TMG_COMB_INPUT;
} else if (cell->type == id_SB_WARMBOOT) { } else if (cell->type == id_SB_WARMBOOT) {
return TMG_ENDPOINT; return TMG_ENDPOINT;
} else if (cell->type == id_SB_LED_DRV_CUR) {
if (port == id_LEDPU)
return TMG_IGNORE;
return TMG_ENDPOINT;
} else if (cell->type == id_SB_RGB_DRV) {
if (port == id_RGB0 || port == id_RGB1 || port == id_RGB2 || port == id_RGBPU)
return TMG_IGNORE;
return TMG_ENDPOINT;
} else if (cell->type == id_SB_RGBA_DRV) { } else if (cell->type == id_SB_RGBA_DRV) {
if (port == id_RGB0 || port == id_RGB1 || port == id_RGB2) if (port == id_RGB0 || port == id_RGB1 || port == id_RGB2)
return TMG_IGNORE; return TMG_IGNORE;

View File

@ -159,6 +159,10 @@ struct ArchCellInfo
{ {
bool forPadIn; bool forPadIn;
} gbInfo; } gbInfo;
struct
{
bool ledCurConnected;
} ledInfo;
}; };
}; };

View File

@ -610,6 +610,13 @@ void write_asc(const Context *ctx, std::ostream &out)
set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_1", write_mode & 0x2); set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_1", write_mode & 0x2);
set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_2", read_mode & 0x1); set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_2", read_mode & 0x1);
set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_3", read_mode & 0x2); set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_3", read_mode & 0x2);
} else if (cell.second->type == ctx->id("SB_LED_DRV_CUR")) {
set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "LED_DRV_CUR_EN", true, "IpConfig.");
} else if (cell.second->type == ctx->id("SB_RGB_DRV")) {
const std::vector<std::pair<std::string, int>> rgb_params = {
{"RGB0_CURRENT", 6}, {"RGB1_CURRENT", 6}, {"RGB2_CURRENT", 6}};
configure_extra_cell(config, ctx, cell.second.get(), rgb_params, true, std::string("IpConfig."));
set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "RGB_DRV_EN", true, "IpConfig.");
} else if (cell.second->type == ctx->id("SB_RGBA_DRV")) { } else if (cell.second->type == ctx->id("SB_RGBA_DRV")) {
const std::vector<std::pair<std::string, int>> rgba_params = { const std::vector<std::pair<std::string, int>> rgba_params = {
{"CURRENT_MODE", 1}, {"RGB0_CURRENT", 6}, {"RGB1_CURRENT", 6}, {"RGB2_CURRENT", 6}}; {"CURRENT_MODE", 1}, {"RGB0_CURRENT", 6}, {"RGB1_CURRENT", 6}, {"RGB2_CURRENT", 6}};

View File

@ -260,6 +260,22 @@ std::unique_ptr<CellInfo> create_ice_cell(Context *ctx, IdString type, std::stri
add_port(ctx, new_cell.get(), "RGB0", PORT_OUT); add_port(ctx, new_cell.get(), "RGB0", PORT_OUT);
add_port(ctx, new_cell.get(), "RGB1", PORT_OUT); add_port(ctx, new_cell.get(), "RGB1", PORT_OUT);
add_port(ctx, new_cell.get(), "RGB2", PORT_OUT); add_port(ctx, new_cell.get(), "RGB2", PORT_OUT);
} else if (type == ctx->id("SB_LED_DRV_CUR")) {
add_port(ctx, new_cell.get(), "EN", PORT_IN);
add_port(ctx, new_cell.get(), "LEDPU", PORT_OUT);
} else if (type == ctx->id("SB_RGB_DRV")) {
new_cell->params[ctx->id("RGB0_CURRENT")] = "0b000000";
new_cell->params[ctx->id("RGB1_CURRENT")] = "0b000000";
new_cell->params[ctx->id("RGB2_CURRENT")] = "0b000000";
add_port(ctx, new_cell.get(), "RGBPU", PORT_IN);
add_port(ctx, new_cell.get(), "RGBLEDEN", PORT_IN);
add_port(ctx, new_cell.get(), "RGB0PWM", PORT_IN);
add_port(ctx, new_cell.get(), "RGB1PWM", PORT_IN);
add_port(ctx, new_cell.get(), "RGB2PWM", PORT_IN);
add_port(ctx, new_cell.get(), "RGB0", PORT_OUT);
add_port(ctx, new_cell.get(), "RGB1", PORT_OUT);
add_port(ctx, new_cell.get(), "RGB2", PORT_OUT);
} else if (type == ctx->id("SB_LEDDA_IP")) { } else if (type == ctx->id("SB_LEDDA_IP")) {
add_port(ctx, new_cell.get(), "LEDDCS", PORT_IN); add_port(ctx, new_cell.get(), "LEDDCS", PORT_IN);
add_port(ctx, new_cell.get(), "LEDDCLK", PORT_IN); add_port(ctx, new_cell.get(), "LEDDCLK", PORT_IN);

View File

@ -76,6 +76,10 @@ inline bool is_sb_mac16(const BaseCtx *ctx, const CellInfo *cell) { return cell-
inline bool is_sb_rgba_drv(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_RGBA_DRV"); } inline bool is_sb_rgba_drv(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_RGBA_DRV"); }
inline bool is_sb_rgb_drv(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_RGB_DRV"); }
inline bool is_sb_led_drv_cur(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LED_DRV_CUR"); }
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_i2c(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_I2C"); }

View File

@ -81,6 +81,8 @@ constids["SPI"] = constids["SB_SPI"]
constids["LEDDA_IP"] = constids["SB_LEDDA_IP"] constids["LEDDA_IP"] = constids["SB_LEDDA_IP"]
constids["RGBA_DRV"] = constids["SB_RGBA_DRV"] constids["RGBA_DRV"] = constids["SB_RGBA_DRV"]
constids["SPRAM"] = constids["ICESTORM_SPRAM"] constids["SPRAM"] = constids["ICESTORM_SPRAM"]
constids["LED_DRV_CUR"] = constids["SB_LED_DRV_CUR"]
constids["RGB_DRV"] = constids["SB_RGB_DRV"]
with open(args.gfxh) as f: with open(args.gfxh) as f:
state = 0 state = 0

View File

@ -355,6 +355,9 @@ X(PWMOUT0)
X(PWMOUT1) X(PWMOUT1)
X(PWMOUT2) X(PWMOUT2)
X(LEDPU)
X(EN)
X(RGBPU)
X(CURREN) X(CURREN)
X(RGB0PWM) X(RGB0PWM)
X(RGB1PWM) X(RGB1PWM)
@ -438,6 +441,8 @@ X(IO_I3C)
X(SB_LEDDA_IP) X(SB_LEDDA_IP)
X(SB_RGBA_DRV) X(SB_RGBA_DRV)
X(ICESTORM_SPRAM) X(ICESTORM_SPRAM)
X(SB_LED_DRV_CUR)
X(SB_RGB_DRV)
// cell parameters // cell parameters
X(DFF_ENABLE) X(DFF_ENABLE)

View File

@ -450,7 +450,7 @@ static void pack_io(Context *ctx)
} else if (ci->type == ctx->id("$nextpnr_obuf")) { } else if (ci->type == ctx->id("$nextpnr_obuf")) {
NetInfo *net = ci->ports.at(ctx->id("I")).net; NetInfo *net = ci->ports.at(ctx->id("I")).net;
sb = net_only_drives(ctx, net, is_ice_iob, ctx->id("PACKAGE_PIN"), true, ci); sb = net_only_drives(ctx, net, is_ice_iob, ctx->id("PACKAGE_PIN"), true, ci);
if (net && net->driver.cell && is_sb_rgba_drv(ctx, net->driver.cell)) if (net && net->driver.cell && (is_sb_rgba_drv(ctx, net->driver.cell) || is_sb_rgb_drv(ctx, net->driver.cell)))
rgb = net->driver.cell; rgb = net->driver.cell;
} }
if (sb != nullptr) { if (sb != nullptr) {
@ -476,7 +476,7 @@ static void pack_io(Context *ctx)
} }
} }
} else if (rgb != nullptr) { } else if (rgb != nullptr) {
log_info("%s use by SB_RGBA_DRV %s, not creating SB_IO\n", ci->name.c_str(ctx), rgb->name.c_str(ctx)); log_info("%s use by SB_RGBA_DRV/SB_RGB_DRV %s, not creating SB_IO\n", ci->name.c_str(ctx), rgb->name.c_str(ctx));
disconnect_port(ctx, ci, ctx->id("I")); disconnect_port(ctx, ci, ctx->id("I"));
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
continue; continue;
@ -1038,6 +1038,27 @@ static void pack_special(Context *ctx)
std::unordered_set<IdString> packed_cells; std::unordered_set<IdString> packed_cells;
std::vector<std::unique_ptr<CellInfo>> new_cells; std::vector<std::unique_ptr<CellInfo>> new_cells;
// Handle LED_DRV_CUR first to set the ledCurConnected flag before RGB_DRV is handled below.
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (is_sb_led_drv_cur(ctx, ci)) {
/* Force placement (no choices anyway) */
cell_place_unique(ctx, ci);
NetInfo *ledpu_net = ci->ports.at(ctx->id("LEDPU")).net;
for (auto &user : ledpu_net->users) {
if (!is_sb_rgb_drv(ctx, user.cell)) {
log_error("SB_LED_DRV_CUR LEDPU port can only be connected to SB_RGB_DRV!\n");
} else {
user.cell->ledInfo.ledCurConnected = true;
user.cell->ports.at(user.port).net = nullptr;
}
}
ci->ports.erase(ctx->id("LEDPU"));
ctx->nets.erase(ledpu_net->name);
}
}
for (auto cell : sorted(ctx->cells)) { for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second;
if (is_sb_lfosc(ctx, ci)) { if (is_sb_lfosc(ctx, ci)) {
@ -1113,7 +1134,7 @@ static void pack_special(Context *ctx)
replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname));
} }
new_cells.push_back(std::move(packed)); new_cells.push_back(std::move(packed));
} else if (is_sb_rgba_drv(ctx, ci)) { } else if (is_sb_rgba_drv(ctx, ci) || is_sb_rgb_drv(ctx, ci)) {
/* Force placement (no choices anyway) */ /* Force placement (no choices anyway) */
cell_place_unique(ctx, ci); cell_place_unique(ctx, ci);
@ -1125,14 +1146,20 @@ static void pack_special(Context *ctx)
if (net == nullptr) if (net == nullptr)
continue; continue;
if ((pi.name != ctx->id("RGB0")) && (pi.name != ctx->id("RGB1")) && (pi.name != ctx->id("RGB2"))) if ((pi.name != ctx->id("RGB0")) && (pi.name != ctx->id("RGB1")) && (pi.name != ctx->id("RGB2")))
continue; continue;
if (net->users.size() > 0) if (net->users.size() > 0)
log_error("SB_RGBA_DRV port connected to more than just package pin !\n"); log_error("SB_RGB_DRV/SB_RGBA_DRV port connected to more than just package pin !\n");
ctx->nets.erase(net->name); ctx->nets.erase(net->name);
} }
if (is_sb_rgb_drv(ctx, ci) && !ci->ledInfo.ledCurConnected)
log_error("Port RGBPU of SB_RGB_DRV should be driven by port LEDPU of SB_LED_DRV_CUR!\n");
ci->ports.erase(ctx->id("RGBPU"));
ci->ports.erase(ctx->id("RGB0")); ci->ports.erase(ctx->id("RGB0"));
ci->ports.erase(ctx->id("RGB1")); ci->ports.erase(ctx->id("RGB1"));
ci->ports.erase(ctx->id("RGB2")); ci->ports.erase(ctx->id("RGB2"));