mirror of https://github.com/YosysHQ/nextpnr.git
Gowin. Add GW5AST-138C chip. (#1631)
* Gowin. Add GW5AST-138C chip.
The ability to perform P&R for the largest GW5A series chip currently
available has been added, which has its own characteristics:
- the need to invert pin function configuration signals - these
signals are not part of the design, but are nextpnr command line
keys for specifying the activation of alternative pin functions such as
I2C;
- some clock PIPs are encoded not by fuses, but by applying VCC/GND to
special inputs. This is also not part of the design and is not a
dynamic clock selection primitive - it is simply an addition to the
fuses.
- added check for DFF and SSRAM placement in upper slots - prior to
this chip, SSRAM was not supported and there was no need for this
check.
- since the chip is divided into two parts in terms of the global
clock network, a flag is introduced to indicate which part the wire
belongs to. This is only requested for clock wires.
Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
* Gowin. Fix style.
Use C++ type cast.
Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
---------
Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
parent
8c6278170b
commit
b4da86edce
|
|
@ -20,7 +20,7 @@ add_nextpnr_himbaechel_microarchitecture(${uarch}
|
|||
CORE_SOURCES ${SOURCES}
|
||||
)
|
||||
|
||||
set(ALL_HIMBAECHEL_GOWIN_DEVICES GW1N-1 GW1NZ-1 GW1N-4 GW1N-9 GW1N-9C GW1NS-4 GW2A-18 GW2A-18C GW5A-25A)
|
||||
set(ALL_HIMBAECHEL_GOWIN_DEVICES GW1N-1 GW1NZ-1 GW1N-4 GW1N-9 GW1N-9C GW1NS-4 GW2A-18 GW2A-18C GW5A-25A GW5AST-138C)
|
||||
set(HIMBAECHEL_GOWIN_DEVICES ${ALL_HIMBAECHEL_GOWIN_DEVICES} CACHE STRING
|
||||
"Include support for these Gowin devices (available: ${ALL_HIMBAECHEL_GOWIN_DEVICES})")
|
||||
if (HIMBAECHEL_GOWIN_DEVICES STREQUAL "all")
|
||||
|
|
|
|||
|
|
@ -1237,6 +1237,7 @@ X(FB_C)
|
|||
X(BOTTOM_IO_PORT_A)
|
||||
X(BOTTOM_IO_PORT_B)
|
||||
X(IOLOGIC_DUMMY)
|
||||
X(SPINE_SELECT)
|
||||
|
||||
// User Flash
|
||||
X(INUSEN)
|
||||
|
|
|
|||
|
|
@ -1187,6 +1187,76 @@ struct GowinGlobalRouter
|
|||
}
|
||||
}
|
||||
|
||||
// Enable clocked spines by connecting magic wires to VCC/GND if necessary.
|
||||
void enable_spines(void)
|
||||
{
|
||||
if (ctx->verbose) {
|
||||
log_info("Check for spine select wires.\n");
|
||||
}
|
||||
|
||||
NetInfo *vcc_net = ctx->nets.at(ctx->id("$PACKER_VCC")).get();
|
||||
NetInfo *vss_net = ctx->nets.at(ctx->id("$PACKER_GND")).get();
|
||||
|
||||
std::unique_ptr<CellInfo> top_ci = gwu.create_cell(ctx->id("spine_select$top"), id_SPINE_SELECT);
|
||||
top_ci->pseudo_cell = std::make_unique<RegionPlug>(Loc(0, 0, 0));
|
||||
std::unique_ptr<CellInfo> bottom_ci = gwu.create_cell(ctx->id("spine_select$bottom"), id_SPINE_SELECT);
|
||||
bottom_ci->pseudo_cell = std::make_unique<RegionPlug>(Loc(0, 0, 0));
|
||||
|
||||
pool<WireId> seen_spines;
|
||||
dict<IdString, int> top_connections;
|
||||
dict<IdString, int> bottom_connections;
|
||||
|
||||
for (auto &net : ctx->nets) {
|
||||
const NetInfo *ni = net.second.get();
|
||||
for (auto &wire : ni->wires) {
|
||||
WireId spine = wire.first;
|
||||
IdString spine_name = ctx->getWireName(spine)[1];
|
||||
if (spine_name.str(ctx).rfind("SPINE", 0) == 0 && seen_spines.count(spine) == 0) {
|
||||
seen_spines.insert(spine);
|
||||
std::vector<std::pair<WireId, int>> wires;
|
||||
if (gwu.get_spine_select_wire(spine, wires)) {
|
||||
int sfx = 0; // To activate a single spine, it may be necessary to connect an unknown number of
|
||||
// wires.
|
||||
CellInfo *select_cell = top_ci.get();
|
||||
auto connections = &top_connections;
|
||||
if (gwu.wire_in_bottom_half(spine)) {
|
||||
select_cell = bottom_ci.get();
|
||||
connections = &bottom_connections;
|
||||
}
|
||||
|
||||
for (auto gate : wires) {
|
||||
IdString port_name = ctx->idf("%s.%d", spine_name.c_str(ctx), sfx);
|
||||
|
||||
select_cell->addInput(port_name);
|
||||
|
||||
RegionPlug *rp = dynamic_cast<RegionPlug *>(select_cell->pseudo_cell.get());
|
||||
rp->port_wires[port_name] = gate.first;
|
||||
(*connections)[port_name] = gate.second;
|
||||
++sfx;
|
||||
if (ctx->verbose) {
|
||||
log_info(" %s->%s\n", port_name.c_str(ctx), ctx->nameOfWire(gate.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// realy connect nets
|
||||
if (!top_connections.empty()) {
|
||||
for (auto conn : top_connections) {
|
||||
top_ci->connectPort(conn.first, conn.second ? vcc_net : vss_net);
|
||||
}
|
||||
ctx->cells[top_ci->name] = std::move(top_ci);
|
||||
}
|
||||
if (!bottom_connections.empty()) {
|
||||
for (auto conn : bottom_connections) {
|
||||
bottom_ci->connectPort(conn.first, conn.second ? vcc_net : vss_net);
|
||||
}
|
||||
ctx->cells[bottom_ci->name] = std::move(bottom_ci);
|
||||
}
|
||||
}
|
||||
|
||||
// Route all
|
||||
void run(void)
|
||||
{
|
||||
|
|
@ -1295,6 +1365,14 @@ struct GowinGlobalRouter
|
|||
if (gwu.get_segments_count() != 0) {
|
||||
route_segmented(seg_nets);
|
||||
}
|
||||
|
||||
// In some GW5 series chips, in addition to the mechanism for
|
||||
// enabling/disabling individual clock spines using fuses, which is
|
||||
// invisible to nextpnr, it is necessary to enable them by connecting
|
||||
// some ports of the mysterious MUX to VSS/GND.
|
||||
if (gwu.has_spine_enable_nets()) {
|
||||
enable_spines();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -143,7 +143,8 @@ void GowinImpl::init_database(Arch *arch)
|
|||
std::regex devicere = std::regex("GW5A(T|ST)?-LV(25|60|138)[A-Z]*.*");
|
||||
std::smatch match;
|
||||
if (std::regex_match(args.device, match, devicere)) {
|
||||
family = stringf("GW5A%s-%sA", match[1].str().c_str(), match[2].str().c_str());
|
||||
family = stringf("GW5A%s-%s%s", match[1].str().c_str(), match[2].str().c_str(),
|
||||
match[2].str() == "25" ? "A" : "C");
|
||||
} else {
|
||||
std::regex devicere = std::regex("GW1N([SZ]?)[A-Z]*-(LV|UV|UX)([0-9])(C?).*");
|
||||
std::smatch match;
|
||||
|
|
@ -1012,6 +1013,12 @@ bool GowinImpl::slice_valid(int x, int y, int z) const
|
|||
ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, 5 * 2 + 1)))) {
|
||||
return false;
|
||||
}
|
||||
if (gwu.has_DFF67()) {
|
||||
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, 6 * 2 + 1))) ||
|
||||
ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, 7 * 2 + 1)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// ALU/LUTs in slices 4, 5, 6, 7 are not allowed
|
||||
for (int i = 4; i < 8; ++i) {
|
||||
if (ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, i * 2)))) {
|
||||
|
|
|
|||
|
|
@ -176,6 +176,14 @@ NPNR_PACKED_STRUCT(struct Segment_POD {
|
|||
RelSlice<uint32_t> bottom_gate_wire;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct SpineSelectWire_POD {
|
||||
uint32_t spine;
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
uint32_t wire;
|
||||
uint32_t vcc_gnd;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct Constraint_POD {
|
||||
int32_t net;
|
||||
int32_t row;
|
||||
|
|
@ -196,6 +204,9 @@ NPNR_PACKED_STRUCT(struct Extra_chip_data_POD {
|
|||
RelSlice<Wire_bel_POD> dhcen_bels;
|
||||
RelSlice<Io_dlldly_bel_POD> io_dlldly_bels;
|
||||
RelSlice<Segment_POD> segments;
|
||||
RelSlice<SpineSelectWire_POD> spine_select_wires_top;
|
||||
RelSlice<SpineSelectWire_POD> spine_select_wires_bottom;
|
||||
|
||||
// chip flags
|
||||
static constexpr int32_t HAS_SP32 = 1;
|
||||
static constexpr int32_t NEED_SP_FIX = 2;
|
||||
|
|
@ -209,6 +220,8 @@ NPNR_PACKED_STRUCT(struct Extra_chip_data_POD {
|
|||
static constexpr int32_t HAS_CIN_MUX = 512;
|
||||
static constexpr int32_t NEED_BSRAM_RESET_FIX = 1024;
|
||||
static constexpr int32_t NEED_SDP_FIX = 2048;
|
||||
static constexpr int32_t NEED_CFGPINS_INVERSION = 4096;
|
||||
static constexpr int32_t HAS_I2CCFG = 8192;
|
||||
});
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -15,21 +15,24 @@ from apycula import chipdb
|
|||
BEL_FLAG_SIMPLE_IO = 0x100
|
||||
|
||||
# Wire flags
|
||||
WIRE_FLAG_CLOCK_GATE = 0x1
|
||||
WIRE_FLAG_CLOCK_GATE = 0x1
|
||||
WIRE_FLAG_BOTTOM_HALF = 0x2 # the wire is located in the bottom half of the chip
|
||||
|
||||
# Chip flags
|
||||
CHIP_HAS_SP32 = 0x1
|
||||
CHIP_NEED_SP_FIX = 0x2
|
||||
CHIP_NEED_BSRAM_OUTREG_FIX = 0x4
|
||||
CHIP_NEED_BLKSEL_FIX = 0x8
|
||||
CHIP_HAS_BANDGAP = 0x10
|
||||
CHIP_HAS_PLL_HCLK = 0x20
|
||||
CHIP_HAS_CLKDIV_HCLK = 0x40
|
||||
CHIP_HAS_PINCFG = 0x80
|
||||
CHIP_HAS_DFF67 = 0x100
|
||||
CHIP_HAS_CIN_MUX = 0x200
|
||||
CHIP_NEED_BSRAM_RESET_FIX = 0x400
|
||||
CHIP_NEED_SDP_FIX = 0x800
|
||||
CHIP_HAS_SP32 = 0x1
|
||||
CHIP_NEED_SP_FIX = 0x2
|
||||
CHIP_NEED_BSRAM_OUTREG_FIX = 0x4
|
||||
CHIP_NEED_BLKSEL_FIX = 0x8
|
||||
CHIP_HAS_BANDGAP = 0x10
|
||||
CHIP_HAS_PLL_HCLK = 0x20
|
||||
CHIP_HAS_CLKDIV_HCLK = 0x40
|
||||
CHIP_HAS_PINCFG = 0x80
|
||||
CHIP_HAS_DFF67 = 0x100
|
||||
CHIP_HAS_CIN_MUX = 0x200
|
||||
CHIP_NEED_BSRAM_RESET_FIX = 0x400
|
||||
CHIP_NEED_SDP_FIX = 0x800
|
||||
CHIP_NEED_CFGPINS_INVERSION = 0x1000
|
||||
CHIP_HAS_I2CCFG = 0x2000
|
||||
|
||||
# Tile flags
|
||||
TILE_I3C_CAPABLE_IO = 0x1
|
||||
|
|
@ -265,6 +268,23 @@ class Segment(BBAStruct):
|
|||
bba.slice(f"{context}_top_gate_wire", len(self.top_gate_wire))
|
||||
bba.slice(f"{context}_bottom_gate_wire", len(self.bottom_gate_wire))
|
||||
|
||||
@dataclass
|
||||
class SpineSelectWire(BBAStruct):
|
||||
spine: IdString
|
||||
x: int
|
||||
y: int
|
||||
wire: IdString
|
||||
vcc_gnd: int
|
||||
|
||||
def serialise_lists(self, context: str, bba: BBAWriter):
|
||||
pass
|
||||
def serialise(self, context: str, bba: BBAWriter):
|
||||
bba.u32(self.spine.index)
|
||||
bba.u16(self.x)
|
||||
bba.u16(self.y)
|
||||
bba.u32(self.wire.index)
|
||||
bba.u32(self.vcc_gnd)
|
||||
|
||||
@dataclass
|
||||
class ChipExtraData(BBAStruct):
|
||||
strs: StringPool
|
||||
|
|
@ -277,6 +297,8 @@ class ChipExtraData(BBAStruct):
|
|||
dhcen_bels: list[WireBel] = field(default_factory = list)
|
||||
io_dlldly_bels: list[IoBel] = field(default_factory = list)
|
||||
segments: list[Segment] = field(default_factory = list)
|
||||
spine_select_wires_top: list[SpineSelectWire] = field(default_factory = list)
|
||||
spine_select_wires_bottom: list[SpineSelectWire] = field(default_factory = list)
|
||||
|
||||
def set_dcs_prefix(self, prefix: str):
|
||||
self.dcs_prefix = self.strs.id(prefix)
|
||||
|
|
@ -301,6 +323,7 @@ class ChipExtraData(BBAStruct):
|
|||
|
||||
def add_io_dlldly_bel(self, io: str, dlldly: str):
|
||||
self.io_dlldly_bels.append(IoBel(self.strs.id(io), self.strs.id(dlldly)))
|
||||
|
||||
def add_segment(self, x: int, seg_idx: int, min_x: int, min_y: int, max_x: int, max_y: int,
|
||||
top_row: int, bottom_row: int, top_wire: str, bottom_wire: str, top_gate_wire: list, bottom_gate_wire: list):
|
||||
new_seg = Segment(x, seg_idx, min_x, min_y, max_x, max_y, top_row, bottom_row,
|
||||
|
|
@ -316,6 +339,12 @@ class ChipExtraData(BBAStruct):
|
|||
new_seg.bottom_gate_wire.append(self.strs.id(''))
|
||||
self.segments.append(new_seg)
|
||||
|
||||
def add_spine_select_wire_top(self, spine: str, x: int, y: int, wire: str, vcc_gnd: int):
|
||||
self.spine_select_wires_top.append(SpineSelectWire(self.strs.id(spine), x, y, self.strs.id(wire), vcc_gnd))
|
||||
|
||||
def add_spine_select_wire_bottom(self, spine: str, x: int, y: int, wire: str, vcc_gnd: int):
|
||||
self.spine_select_wires_bottom.append(SpineSelectWire(self.strs.id(spine), x, y, self.strs.id(wire), vcc_gnd))
|
||||
|
||||
def serialise_lists(self, context: str, bba: BBAWriter):
|
||||
self.bottom_io.serialise_lists(f"{context}_bottom_io", bba)
|
||||
for i, t in enumerate(self.segments):
|
||||
|
|
@ -338,6 +367,12 @@ class ChipExtraData(BBAStruct):
|
|||
bba.label(f"{context}_segments")
|
||||
for i, t in enumerate(self.segments):
|
||||
t.serialise(f"{context}_segment{i}", bba)
|
||||
bba.label(f"{context}_spine_select_wires_top")
|
||||
for i, t in enumerate(self.spine_select_wires_top):
|
||||
t.serialise(f"{context}_spine_select_wire_top{i}", bba)
|
||||
bba.label(f"{context}_spine_select_wires_bottom")
|
||||
for i, t in enumerate(self.spine_select_wires_bottom):
|
||||
t.serialise(f"{context}_spine_select_wire_bottom{i}", bba)
|
||||
|
||||
def serialise(self, context: str, bba: BBAWriter):
|
||||
bba.u32(self.flags)
|
||||
|
|
@ -349,6 +384,8 @@ class ChipExtraData(BBAStruct):
|
|||
bba.slice(f"{context}_dhcen_bels", len(self.dhcen_bels))
|
||||
bba.slice(f"{context}_io_dlldly_bels", len(self.io_dlldly_bels))
|
||||
bba.slice(f"{context}_segments", len(self.segments))
|
||||
bba.slice(f"{context}_spine_select_wires_top", len(self.spine_select_wires_top))
|
||||
bba.slice(f"{context}_spine_select_wires_bottom", len(self.spine_select_wires_bottom))
|
||||
|
||||
@dataclass
|
||||
class PackageExtraData(BBAStruct):
|
||||
|
|
@ -527,12 +564,17 @@ def create_switch_matrix(tt: TileType, db: chipdb, x: int, y: int):
|
|||
tt.create_pip(src, dst, get_tm_class(db, src))
|
||||
|
||||
# clock wires
|
||||
# always mark clock wires with location flag
|
||||
for dst, srcs in db.grid[y][x].clock_pips.items():
|
||||
if not tt.has_wire(dst):
|
||||
tt.create_wire(dst, "GLOBAL_CLK")
|
||||
wire = tt.create_wire(dst, "GLOBAL_CLK")
|
||||
if hasattr(db, "last_top_row") and y > db.last_top_row:
|
||||
wire.flags |= WIRE_FLAG_BOTTOM_HALF
|
||||
for src in srcs.keys():
|
||||
if not tt.has_wire(src):
|
||||
tt.create_wire(src, "GLOBAL_CLK")
|
||||
wire = tt.create_wire(src, "GLOBAL_CLK")
|
||||
if hasattr(db, "last_top_row") and y > db.last_top_row:
|
||||
wire.flags |= WIRE_FLAG_BOTTOM_HALF
|
||||
src_tm_class = get_tm_class(db, src)
|
||||
tt.create_pip(src, dst, src_tm_class)
|
||||
|
||||
|
|
@ -1466,6 +1508,17 @@ def create_extra_data(chip: Chip, db: chipdb, chip_flags: int):
|
|||
node.append(NodeWire(col, row, f'LB{idx}1'))
|
||||
chip.add_node(node)
|
||||
chip.add_node(lt_node)
|
||||
# create spine select wires
|
||||
if hasattr(db, "spine_select_wires"):
|
||||
if 'top' in db.spine_select_wires:
|
||||
for spine, wire_desc in db.spine_select_wires['top'].items():
|
||||
for y, x, wire, vcc_gnd in wire_desc:
|
||||
chip.extra_data.add_spine_select_wire_top(spine, x, y, wire, vcc_gnd)
|
||||
|
||||
if 'bottom' in db.spine_select_wires:
|
||||
for spine, wire_desc in db.spine_select_wires['bottom'].items():
|
||||
for y, x, wire, vcc_gnd in wire_desc:
|
||||
chip.extra_data.add_spine_select_wire_bottom(spine, x, y, wire, vcc_gnd)
|
||||
|
||||
def create_timing_info(chip: Chip, db: chipdb.Device):
|
||||
def group_to_timingvalue(group):
|
||||
|
|
@ -1636,6 +1689,10 @@ def main():
|
|||
chip_flags |= CHIP_NEED_BSRAM_RESET_FIX;
|
||||
if "NEED_SDP_FIX" in db.chip_flags:
|
||||
chip_flags |= CHIP_NEED_SDP_FIX;
|
||||
if "NEED_CFGPINS_INVERSION" in db.chip_flags:
|
||||
chip_flags |= CHIP_NEED_CFGPINS_INVERSION;
|
||||
if "CHIP_HAS_I2CCFG" in db.chip_flags:
|
||||
chip_flags |= CHIP_HAS_I2CCFG;
|
||||
|
||||
X = db.cols;
|
||||
Y = db.rows;
|
||||
|
|
|
|||
|
|
@ -350,18 +350,51 @@ bool GowinUtils::has_BANDGAP(void)
|
|||
return extra->chip_flags & Extra_chip_data_POD::HAS_BANDGAP;
|
||||
}
|
||||
|
||||
bool GowinUtils::has_PINCFG(void)
|
||||
bool GowinUtils::has_PINCFG(void) const
|
||||
{
|
||||
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
|
||||
return extra->chip_flags & Extra_chip_data_POD::HAS_PINCFG;
|
||||
}
|
||||
|
||||
bool GowinUtils::need_CFGPINS_INVERSION(void) const
|
||||
{
|
||||
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
|
||||
return extra->chip_flags & Extra_chip_data_POD::NEED_CFGPINS_INVERSION;
|
||||
}
|
||||
|
||||
bool GowinUtils::has_I2CCFG(void) const
|
||||
{
|
||||
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
|
||||
return extra->chip_flags & Extra_chip_data_POD::HAS_I2CCFG;
|
||||
}
|
||||
|
||||
bool GowinUtils::has_DFF67(void) const
|
||||
{
|
||||
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
|
||||
return extra->chip_flags & Extra_chip_data_POD::HAS_DFF67;
|
||||
}
|
||||
|
||||
bool GowinUtils::has_spine_enable_nets(void) const
|
||||
{
|
||||
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
|
||||
return extra->spine_select_wires_top.ssize() || extra->spine_select_wires_bottom.ssize();
|
||||
}
|
||||
|
||||
bool GowinUtils::get_spine_select_wire(WireId spine, std::vector<std::pair<WireId, int>> &wires)
|
||||
{
|
||||
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
|
||||
|
||||
wires.clear();
|
||||
for (auto &rec : wire_in_bottom_half(spine) ? extra->spine_select_wires_bottom : extra->spine_select_wires_top) {
|
||||
if (IdString(rec.spine) == ctx->getWireName(spine)[1]) {
|
||||
IdString tile = ctx->idf("X%dY%d", rec.x, rec.y);
|
||||
IdStringList name = IdStringList::concat(tile, IdString(rec.wire));
|
||||
wires.push_back(std::make_pair(ctx->getWireByName(name), rec.vcc_gnd));
|
||||
}
|
||||
}
|
||||
return !wires.empty();
|
||||
}
|
||||
|
||||
bool GowinUtils::has_CIN_MUX(void) const
|
||||
{
|
||||
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ static constexpr uint32_t FLAG_SIMPLE_IO = 0x100;
|
|||
|
||||
namespace WireFlags {
|
||||
static constexpr uint32_t FLAG_CLOCK_GATE = 0x1;
|
||||
}
|
||||
static constexpr uint32_t FLAG_BOTTOM_HALF = 0x2;
|
||||
} // namespace WireFlags
|
||||
|
||||
struct GowinUtils
|
||||
{
|
||||
|
|
@ -96,6 +97,12 @@ struct GowinUtils
|
|||
return chip_wire_info(ctx->chip_info, wire).flags & WireFlags::FLAG_CLOCK_GATE;
|
||||
}
|
||||
|
||||
bool wire_in_bottom_half(WireId wire) const
|
||||
{
|
||||
return chip_wire_info(ctx->chip_info, wire).flags & WireFlags::FLAG_BOTTOM_HALF;
|
||||
}
|
||||
bool get_spine_select_wire(WireId spine, std::vector<std::pair<WireId, int>> &);
|
||||
|
||||
// BSRAM
|
||||
bool has_SP32(void);
|
||||
bool need_SP_fix(void);
|
||||
|
|
@ -110,7 +117,9 @@ struct GowinUtils
|
|||
bool has_BANDGAP(void);
|
||||
|
||||
// Pin function configuration via wires
|
||||
bool has_PINCFG(void);
|
||||
bool has_PINCFG(void) const;
|
||||
bool need_CFGPINS_INVERSION(void) const;
|
||||
bool has_I2CCFG(void) const;
|
||||
|
||||
// Logic cell structure
|
||||
bool has_DFF67(void) const;
|
||||
|
|
@ -118,6 +127,9 @@ struct GowinUtils
|
|||
// ALU
|
||||
bool has_CIN_MUX(void) const;
|
||||
|
||||
// Clock MUX
|
||||
bool has_spine_enable_nets(void) const;
|
||||
|
||||
// DSP
|
||||
inline int get_dsp_18_z(int z) const { return z & (~3); }
|
||||
inline int get_dsp_9_idx(int z) const { return z & 3; }
|
||||
|
|
|
|||
|
|
@ -3959,10 +3959,15 @@ struct GowinPacker
|
|||
|
||||
auto pincfg_cell = std::make_unique<CellInfo>(ctx, id_PINCFG, id_PINCFG);
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
const int pin_cnt = gwu.has_I2CCFG() ? 5 : 4;
|
||||
for (int i = 0; i < pin_cnt; ++i) {
|
||||
IdString port = ctx->idf("UNK%d_VCC", i);
|
||||
pincfg_cell->addInput(port);
|
||||
pincfg_cell->connectPort(port, ctx->nets.at(ctx->id("$PACKER_VCC")).get());
|
||||
if (i && gwu.need_CFGPINS_INVERSION()) {
|
||||
pincfg_cell->connectPort(port, ctx->nets.at(ctx->id("$PACKER_GND")).get());
|
||||
} else {
|
||||
pincfg_cell->connectPort(port, ctx->nets.at(ctx->id("$PACKER_VCC")).get());
|
||||
}
|
||||
}
|
||||
|
||||
const ArchArgs &args = ctx->args;
|
||||
|
|
@ -3975,12 +3980,14 @@ struct GowinPacker
|
|||
pincfg_cell->connectPort(id_SSPI, ctx->nets.at(ctx->id("$PACKER_GND")).get());
|
||||
}
|
||||
|
||||
pincfg_cell->addInput(id_I2C);
|
||||
if (args.options.count("i2c_as_gpio")) {
|
||||
pincfg_cell->connectPort(id_I2C, ctx->nets.at(ctx->id("$PACKER_VCC")).get());
|
||||
pincfg_cell->setParam(id_I2C, 1);
|
||||
} else {
|
||||
pincfg_cell->connectPort(id_I2C, ctx->nets.at(ctx->id("$PACKER_GND")).get());
|
||||
if (gwu.has_I2CCFG()) {
|
||||
pincfg_cell->addInput(id_I2C);
|
||||
if (args.options.count("i2c_as_gpio")) {
|
||||
pincfg_cell->connectPort(id_I2C, ctx->nets.at(ctx->id("$PACKER_VCC")).get());
|
||||
pincfg_cell->setParam(id_I2C, 1);
|
||||
} else {
|
||||
pincfg_cell->connectPort(id_I2C, ctx->nets.at(ctx->id("$PACKER_GND")).get());
|
||||
}
|
||||
}
|
||||
ctx->cells[pincfg_cell->name] = std::move(pincfg_cell);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue