gowin: Himbaechel. Add simplified IO
Add processing IO located on the sides of some chips. These are IOBUF, which are converted into IBUF and OBUF not by fuses, but by signaling to OE. Also added the creation of a Global Set / Reset for all chips, instead of a list of tile types, information from the apicula database is used, and minor fixes. Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
parent
df13104384
commit
03c413a27a
@ -52,7 +52,7 @@ struct GowinGlobalRouter
|
|||||||
bool src_valid = src_type.in(id_GLOBAL_CLK, id_IO_O, id_PLL_O);
|
bool src_valid = src_type.in(id_GLOBAL_CLK, id_IO_O, id_PLL_O);
|
||||||
bool dst_valid = dst_type.in(id_GLOBAL_CLK, id_TILE_CLK, id_PLL_I, id_IO_I);
|
bool dst_valid = dst_type.in(id_GLOBAL_CLK, id_TILE_CLK, id_PLL_I, id_IO_I);
|
||||||
|
|
||||||
if (ctx->debug) {
|
if (ctx->debug && false) {
|
||||||
log_info("%s <- %s [%s <- %s]\n", ctx->getWireName(ctx->getPipDstWire(pip)).str(ctx).c_str(),
|
log_info("%s <- %s [%s <- %s]\n", ctx->getWireName(ctx->getPipDstWire(pip)).str(ctx).c_str(),
|
||||||
ctx->getWireName(ctx->getPipSrcWire(pip)).str(ctx).c_str(), dst_type.c_str(ctx),
|
ctx->getWireName(ctx->getPipSrcWire(pip)).str(ctx).c_str(), dst_type.c_str(ctx),
|
||||||
src_type.c_str(ctx));
|
src_type.c_str(ctx));
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
namespace BelFlags {
|
||||||
|
static constexpr uint32_t FLAG_SIMPLE_IO = 0x100;
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Return true if a cell is a LUT
|
// Return true if a cell is a LUT
|
||||||
inline bool type_is_lut(IdString cell_type) { return cell_type.in(id_LUT1, id_LUT2, id_LUT3, id_LUT4); }
|
inline bool type_is_lut(IdString cell_type) { return cell_type.in(id_LUT1, id_LUT2, id_LUT3, id_LUT4); }
|
||||||
@ -39,6 +43,12 @@ NPNR_PACKED_STRUCT(struct Bottom_io_POD {
|
|||||||
|
|
||||||
NPNR_PACKED_STRUCT(struct Extra_chip_data_POD { Bottom_io_POD bottom_io; });
|
NPNR_PACKED_STRUCT(struct Extra_chip_data_POD { Bottom_io_POD bottom_io; });
|
||||||
|
|
||||||
|
inline bool have_bottom_io_cnds(const ChipInfoPOD *chip)
|
||||||
|
{
|
||||||
|
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(chip->extra_data.get());
|
||||||
|
return extra->bottom_io.conditions.size() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
inline IdString get_bottom_io_wire_a_net(const ChipInfoPOD *chip, int8_t condition)
|
inline IdString get_bottom_io_wire_a_net(const ChipInfoPOD *chip, int8_t condition)
|
||||||
{
|
{
|
||||||
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(chip->extra_data.get());
|
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(chip->extra_data.get());
|
||||||
@ -51,6 +61,10 @@ inline IdString get_bottom_io_wire_b_net(const ChipInfoPOD *chip, int8_t conditi
|
|||||||
return IdString(extra->bottom_io.conditions[condition].wire_b_net);
|
return IdString(extra->bottom_io.conditions[condition].wire_b_net);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool getBelSimpleIO(const ChipInfoPOD *chip, BelId bel)
|
||||||
|
{
|
||||||
|
return chip_bel_info(chip, bel).flags & BelFlags::FLAG_SIMPLE_IO;
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Bels Z ranges. It is desirable that these numbers be synchronized with the chipdb generator
|
// Bels Z ranges. It is desirable that these numbers be synchronized with the chipdb generator
|
||||||
|
@ -11,6 +11,9 @@ sys.path.append(path.join(path.dirname(__file__), "../.."))
|
|||||||
from himbaechel_dbgen.chip import *
|
from himbaechel_dbgen.chip import *
|
||||||
from apycula import chipdb
|
from apycula import chipdb
|
||||||
|
|
||||||
|
# Bel flags
|
||||||
|
BEL_FLAG_SIMPLE_IO = 0x100
|
||||||
|
|
||||||
# Z of the bels
|
# Z of the bels
|
||||||
# sync with C++ part!
|
# sync with C++ part!
|
||||||
LUT0_Z = 0 # z(DFFx) = z(LUTx) + 1
|
LUT0_Z = 0 # z(DFFx) = z(LUTx) + 1
|
||||||
@ -171,6 +174,9 @@ def create_nodes(chip: Chip, db: chipdb):
|
|||||||
wire_type, node = node_hdr
|
wire_type, node = node_hdr
|
||||||
for y, x, wire in node:
|
for y, x, wire in node:
|
||||||
if wire_type:
|
if wire_type:
|
||||||
|
if not chip.tile_type_at(x, y).has_wire(wire):
|
||||||
|
chip.tile_type_at(x, y).create_wire(wire, wire_type)
|
||||||
|
else:
|
||||||
chip.tile_type_at(x, y).set_wire_type(wire, wire_type)
|
chip.tile_type_at(x, y).set_wire_type(wire, wire_type)
|
||||||
new_node = NodeWire(x, y, wire)
|
new_node = NodeWire(x, y, wire)
|
||||||
gl_nodes = global_nodes.setdefault(node_name, [])
|
gl_nodes = global_nodes.setdefault(node_name, [])
|
||||||
@ -200,7 +206,7 @@ def create_switch_matrix(tt: TileType, db: chipdb, x: int, y: int):
|
|||||||
tt.create_wire(src, get_wire_type(src))
|
tt.create_wire(src, get_wire_type(src))
|
||||||
tt.create_pip(src, dst)
|
tt.create_pip(src, dst)
|
||||||
# clock wires
|
# clock wires
|
||||||
for dst, srcs in db.grid[y][x].clock_pips.items():
|
for dst, srcs in db.grid[y][x].pure_clock_pips.items():
|
||||||
if not tt.has_wire(dst):
|
if not tt.has_wire(dst):
|
||||||
tt.create_wire(dst, "GLOBAL_CLK")
|
tt.create_wire(dst, "GLOBAL_CLK")
|
||||||
for src in srcs.keys():
|
for src in srcs.keys():
|
||||||
@ -234,6 +240,12 @@ def create_corner_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
|
|||||||
tt.create_wire('VCC', 'VCC')
|
tt.create_wire('VCC', 'VCC')
|
||||||
gnd = tt.create_bel('VCC', 'VCC', z = VCC_Z)
|
gnd = tt.create_bel('VCC', 'VCC', z = VCC_Z)
|
||||||
tt.add_bel_pin(gnd, "V", "VCC", PinType.OUTPUT)
|
tt.add_bel_pin(gnd, "V", "VCC", PinType.OUTPUT)
|
||||||
|
# also here may be GSR
|
||||||
|
if 'GSR' in db.grid[y][x].bels.keys():
|
||||||
|
portmap = db.grid[y][x].bels['GSR'].portmap
|
||||||
|
tt.create_wire(portmap['GSRI'], "GSRI")
|
||||||
|
io = tt.create_bel("GSR", "GSR", z = GSR_Z)
|
||||||
|
tt.add_bel_pin(io, "GSRI", portmap['GSRI'], PinType.INPUT)
|
||||||
|
|
||||||
create_switch_matrix(tt, db, x, y)
|
create_switch_matrix(tt, db, x, y)
|
||||||
return (ttyp, tt)
|
return (ttyp, tt)
|
||||||
@ -262,15 +274,27 @@ def create_io_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
|
|||||||
tt = chip.create_tile_type(f"{typename}_{ttyp}")
|
tt = chip.create_tile_type(f"{typename}_{ttyp}")
|
||||||
tt.extra_data = TileExtraData(chip.strs.id(typename))
|
tt.extra_data = TileExtraData(chip.strs.id(typename))
|
||||||
|
|
||||||
for i in range(2):
|
simple_io = y in db.simplio_rows and chip.name in {'GW1N-1', 'GW1NZ-1'}
|
||||||
name = ['IOBA', 'IOBB'][i]
|
if simple_io:
|
||||||
|
rng = 10
|
||||||
|
else:
|
||||||
|
rng = 2
|
||||||
|
for i in range(rng):
|
||||||
|
name = 'IOB' + 'ABCDEFGHIJ'[i]
|
||||||
|
# XXX some IOBs excluded from generic chipdb for some reason
|
||||||
|
if name not in db.grid[y][x].bels.keys():
|
||||||
|
continue
|
||||||
# wires
|
# wires
|
||||||
portmap = db.grid[y][x].bels[name].portmap
|
portmap = db.grid[y][x].bels[name].portmap
|
||||||
tt.create_wire(portmap['I'], "IO_I")
|
tt.create_wire(portmap['I'], "IO_I")
|
||||||
tt.create_wire(portmap['O'], "IO_O")
|
tt.create_wire(portmap['O'], "IO_O")
|
||||||
|
tt.create_wire(portmap['OE'], "IO_OE")
|
||||||
# bels
|
# bels
|
||||||
io = tt.create_bel(name, "IOB", z = IOBA_Z + i)
|
io = tt.create_bel(name, "IOB", z = IOBA_Z + i)
|
||||||
|
if simple_io:
|
||||||
|
io.flags |= BEL_FLAG_SIMPLE_IO
|
||||||
tt.add_bel_pin(io, "I", portmap['I'], PinType.INPUT)
|
tt.add_bel_pin(io, "I", portmap['I'], PinType.INPUT)
|
||||||
|
tt.add_bel_pin(io, "OE", portmap['OE'], PinType.INPUT)
|
||||||
tt.add_bel_pin(io, "O", portmap['O'], PinType.OUTPUT)
|
tt.add_bel_pin(io, "O", portmap['O'], PinType.OUTPUT)
|
||||||
# bottom io
|
# bottom io
|
||||||
if 'BOTTOM_IO_PORT_A' in portmap.keys():
|
if 'BOTTOM_IO_PORT_A' in portmap.keys():
|
||||||
@ -510,11 +534,11 @@ def main():
|
|||||||
# The manufacturer distinguishes by externally identical tiles, so keep
|
# The manufacturer distinguishes by externally identical tiles, so keep
|
||||||
# these differences (in case it turns out later that there is a slightly
|
# these differences (in case it turns out later that there is a slightly
|
||||||
# different routing or something like that).
|
# different routing or something like that).
|
||||||
logic_tiletypes = {12, 13, 14, 15, 16}
|
logic_tiletypes = db.tile_types['C']
|
||||||
io_tiletypes = {52, 53, 54, 55, 58, 59, 64, 65, 66}
|
io_tiletypes = db.tile_types['I']
|
||||||
ssram_tiletypes = {17, 18, 19}
|
ssram_tiletypes = {17, 18, 19}
|
||||||
gsr_tiletypes = {1}
|
gsr_tiletypes = {1}
|
||||||
pll_tiletypes = {86, 87, 42, 45}
|
pll_tiletypes = db.tile_types['P']
|
||||||
# Setup tile grid
|
# Setup tile grid
|
||||||
for x in range(X):
|
for x in range(X):
|
||||||
for y in range(Y):
|
for y in range(Y):
|
||||||
|
@ -21,8 +21,26 @@ struct GowinPacker
|
|||||||
// ===================================
|
// ===================================
|
||||||
// IO
|
// IO
|
||||||
// ===================================
|
// ===================================
|
||||||
|
void config_simple_io(CellInfo &ci)
|
||||||
|
{
|
||||||
|
if (ci.type.in(id_TBUF, id_IOBUF)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log_info("simple:%s\n", ctx->nameOf(&ci));
|
||||||
|
ci.addInput(id_OE);
|
||||||
|
if (ci.type == id_OBUF) {
|
||||||
|
ci.connectPort(id_OE, ctx->nets[ctx->id("$PACKER_GND")].get());
|
||||||
|
} else {
|
||||||
|
NPNR_ASSERT(ci.type == id_IBUF);
|
||||||
|
ci.connectPort(id_OE, ctx->nets[ctx->id("$PACKER_VCC")].get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void config_bottom_row(CellInfo &ci, Loc loc, uint8_t cnd = Bottom_io_POD::NORMAL)
|
void config_bottom_row(CellInfo &ci, Loc loc, uint8_t cnd = Bottom_io_POD::NORMAL)
|
||||||
{
|
{
|
||||||
|
if (!have_bottom_io_cnds(ctx->chip_info)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!ci.type.in(id_OBUF, id_TBUF, id_IOBUF)) {
|
if (!ci.type.in(id_OBUF, id_TBUF, id_IOBUF)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -93,6 +111,7 @@ struct GowinPacker
|
|||||||
BelId bind_io(CellInfo &ci)
|
BelId bind_io(CellInfo &ci)
|
||||||
{
|
{
|
||||||
BelId bel = ctx->getBelByName(IdStringList::parse(ctx, ci.attrs.at(id_BEL).as_string()));
|
BelId bel = ctx->getBelByName(IdStringList::parse(ctx, ci.attrs.at(id_BEL).as_string()));
|
||||||
|
NPNR_ASSERT(bel != BelId());
|
||||||
ci.unsetAttr(id_BEL);
|
ci.unsetAttr(id_BEL);
|
||||||
ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_LOCKED);
|
ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_LOCKED);
|
||||||
return bel;
|
return bel;
|
||||||
@ -115,6 +134,9 @@ struct GowinPacker
|
|||||||
if (io_loc.y == ctx->getGridDimY() - 1) {
|
if (io_loc.y == ctx->getGridDimY() - 1) {
|
||||||
config_bottom_row(ci, io_loc);
|
config_bottom_row(ci, io_loc);
|
||||||
}
|
}
|
||||||
|
if (getBelSimpleIO(ctx->chip_info, io_bel)) {
|
||||||
|
config_simple_io(ci);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,10 +160,11 @@ struct GowinPacker
|
|||||||
NetInfo *constnet = net->second.get();
|
NetInfo *constnet = net->second.get();
|
||||||
for (auto user : constnet->users) {
|
for (auto user : constnet->users) {
|
||||||
CellInfo *uc = user.cell;
|
CellInfo *uc = user.cell;
|
||||||
if (ctx->debug)
|
|
||||||
log_info("%s user %s/%s\n", ctx->nameOf(constnet), ctx->nameOf(uc), user.port.c_str(ctx));
|
|
||||||
|
|
||||||
if (is_lut(uc) && (user.port.str(ctx).at(0) == 'I')) {
|
if (is_lut(uc) && (user.port.str(ctx).at(0) == 'I')) {
|
||||||
|
if (ctx->debug) {
|
||||||
|
log_info("%s user %s/%s\n", ctx->nameOf(constnet), ctx->nameOf(uc), user.port.c_str(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
auto it_param = uc->params.find(id_INIT);
|
auto it_param = uc->params.find(id_INIT);
|
||||||
if (it_param == uc->params.end())
|
if (it_param == uc->params.end())
|
||||||
log_error("No initialization for lut found.\n");
|
log_error("No initialization for lut found.\n");
|
||||||
@ -318,9 +341,9 @@ struct GowinPacker
|
|||||||
// CIN from logic
|
// CIN from logic
|
||||||
cin_ci->addInput(id_I1);
|
cin_ci->addInput(id_I1);
|
||||||
cin_ci->addInput(id_I3);
|
cin_ci->addInput(id_I3);
|
||||||
cin_ci->addInput(id_I2);
|
|
||||||
cin_ci->connectPort(id_I1, cin_net);
|
cin_ci->connectPort(id_I1, cin_net);
|
||||||
cin_ci->connectPort(id_I3, cin_net);
|
cin_ci->connectPort(id_I3, cin_net);
|
||||||
|
cin_ci->addInput(id_I2);
|
||||||
cin_ci->connectPort(id_I2, ctx->nets[ctx->id("$PACKER_VCC")].get());
|
cin_ci->connectPort(id_I2, ctx->nets[ctx->id("$PACKER_VCC")].get());
|
||||||
cin_ci->params[id_ALU_MODE] = std::string("0"); // ADD
|
cin_ci->params[id_ALU_MODE] = std::string("0"); // ADD
|
||||||
return cin_ci;
|
return cin_ci;
|
||||||
@ -342,6 +365,8 @@ struct GowinPacker
|
|||||||
cout_ci->connectPort(id_CIN, cin_net);
|
cout_ci->connectPort(id_CIN, cin_net);
|
||||||
cout_ci->addOutput(id_SUM);
|
cout_ci->addOutput(id_SUM);
|
||||||
cout_ci->connectPort(id_SUM, cout_net);
|
cout_ci->connectPort(id_SUM, cout_net);
|
||||||
|
cout_ci->addInput(id_I2);
|
||||||
|
cout_ci->connectPort(id_I2, ctx->nets[ctx->id("$PACKER_VCC")].get());
|
||||||
|
|
||||||
cout_ci->params[id_ALU_MODE] = std::string("C2L");
|
cout_ci->params[id_ALU_MODE] = std::string("C2L");
|
||||||
return cout_ci;
|
return cout_ci;
|
||||||
@ -425,8 +450,8 @@ struct GowinPacker
|
|||||||
cout_block_ci->constr_y = 0;
|
cout_block_ci->constr_y = 0;
|
||||||
cout_block_ci->constr_z = alu_chain_len % 6;
|
cout_block_ci->constr_z = alu_chain_len % 6;
|
||||||
if (ctx->debug) {
|
if (ctx->debug) {
|
||||||
log_info("Add ALU carry out to the chain (len:%d): %s\n", alu_chain_len,
|
log_info("Add ALU carry out to the chain (len:%d): %s COUT-net: %s\n", alu_chain_len,
|
||||||
ctx->nameOf(cout_block_ci));
|
ctx->nameOf(cout_block_ci), ctx->nameOf(cout_net));
|
||||||
}
|
}
|
||||||
|
|
||||||
++alu_chain_len;
|
++alu_chain_len;
|
||||||
@ -566,7 +591,7 @@ struct GowinPacker
|
|||||||
// ===================================
|
// ===================================
|
||||||
void pack_gsr(void)
|
void pack_gsr(void)
|
||||||
{
|
{
|
||||||
log_info("Packing GSR..\n");
|
log_info("Pack GSR..\n");
|
||||||
|
|
||||||
bool user_gsr = false;
|
bool user_gsr = false;
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
@ -603,7 +628,7 @@ struct GowinPacker
|
|||||||
// ===================================
|
// ===================================
|
||||||
void pack_pll(void)
|
void pack_pll(void)
|
||||||
{
|
{
|
||||||
log_info("Packing PLL..\n");
|
log_info("Pack PLL..\n");
|
||||||
|
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
auto &ci = *cell.second;
|
auto &ci = *cell.second;
|
||||||
|
Loading…
Reference in New Issue
Block a user