diff --git a/himbaechel/arch.cc b/himbaechel/arch.cc index 9ae9225e00..4590c66ac2 100644 --- a/himbaechel/arch.cc +++ b/himbaechel/arch.cc @@ -307,6 +307,24 @@ IdStringList Arch::getPipName(PipId pip) const IdString Arch::getPipType(PipId pip) const { return IdString(); } +GroupId Arch::getGroupByName(IdStringList name) const +{ + NPNR_ASSERT(name.size() == 2); + int tile = tile_name2idx.at(name[0]); + const auto &tdata = chip_tile_info(chip_info, tile); + for (int group = 0; group < tdata.groups.ssize(); group++) { + if (IdString(tdata.groups[group].name) == name[1]) + return GroupId(tile, group); + } + return GroupId(); + +} + +IdStringList Arch::getGroupName(GroupId group) const +{ + return IdStringList::concat(tile_name.at(group.tile), IdString(chip_group_info(chip_info, group).name)); +} + std::string Arch::getChipName() const { return chip_info->name.get(); } IdString Arch::archArgsToId(ArchArgs args) const @@ -504,7 +522,12 @@ IdString Arch::get_tile_type(int tile) const std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const { std::vector<GraphicElement> ret; - if (decal.type == DecalId::TYPE_BEL) { + if (decal.type == DecalId::TYPE_GROUP) { + GroupId group(decal.tile, decal.index); + Loc loc; + tile_xy(chip_info, decal.tile, loc.x, loc.y); + uarch->drawGroup(ret, getGroupType(group), loc); + } else if (decal.type == DecalId::TYPE_BEL) { BelId bel(decal.tile, decal.index); GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; uarch->drawBel(ret, style, getBelType(bel), getBelLocation(bel)); @@ -557,7 +580,10 @@ DecalXY Arch::getPipDecal(PipId pip) const DecalXY Arch::getGroupDecal(GroupId group) const { - return DecalXY(); + DecalXY decalxy; + decalxy.decal = DecalId(group.tile, group.index, DecalId::TYPE_GROUP); + decalxy.decal.active = true; + return decalxy; } NEXTPNR_NAMESPACE_END diff --git a/himbaechel/arch.h b/himbaechel/arch.h index ca965c8625..b419db55eb 100644 --- a/himbaechel/arch.h +++ b/himbaechel/arch.h @@ -49,6 +49,10 @@ inline const PipDataPOD &chip_pip_info(const ChipInfoPOD *chip, PipId pip) { return chip_tile_info(chip, pip.tile).pips[pip.index]; } +inline const GroupDataPOD &chip_group_info(const ChipInfoPOD *chip, GroupId group) +{ + return chip_tile_info(chip, group.tile).groups[group.index]; +} inline const TileRoutingShapePOD &chip_tile_shape(const ChipInfoPOD *chip, int tile) { return chip->tile_shapes[chip->tile_insts[tile].shape]; @@ -332,6 +336,48 @@ template <RelSlice<int32_t> TileWireDataPOD::*ptr> struct UpDownhillPipRange // ----------------------------------------------------------------------- +template <typename Tid, RelSlice<int32_t> GroupDataPOD::*ptr> struct GroupObjIterator +{ + const GroupDataPOD &group; + int tile = -1; + int cursor = -1; + + GroupObjIterator(const GroupDataPOD &group, int tile, int cursor) + : group(group), tile(tile), cursor(cursor) {}; + + void operator++() { cursor++; } + + bool operator!=(const GroupObjIterator<Tid, ptr> &other) const + { + return tile != other.tile || cursor != other.cursor; + } + + bool operator==(const GroupObjIterator<Tid, ptr> &other) const + { + return tile == other.tile && cursor == other.cursor; + } + + Tid operator*() const + { + return Tid(tile, (group.*ptr)[cursor]); + } +}; + +template <typename Tid, RelSlice<int32_t> GroupDataPOD::*ptr> struct GroupObjRange +{ + using iterator = GroupObjIterator<Tid, ptr>; + GroupObjRange(const GroupDataPOD &group, int tile) + : b(group, tile, 0), e(group, tile, (group.*ptr).ssize()) + { + } + + iterator b, e; + iterator begin() const { return b; } + iterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + struct BelPinIterator { const ChipInfoPOD *chip; @@ -393,10 +439,16 @@ struct ArchArgs typedef TileObjRange<BelId, BelDataPOD, &TileTypePOD::bels> BelRange; typedef TileObjRange<PipId, PipDataPOD, &TileTypePOD::pips> AllPipRange; +typedef TileObjRange<GroupId, GroupDataPOD, &TileTypePOD::groups> GroupRange; typedef UpDownhillPipRange<&TileWireDataPOD::pips_uphill> UphillPipRange; typedef UpDownhillPipRange<&TileWireDataPOD::pips_downhill> DownhillPipRange; +typedef GroupObjRange<BelId, &GroupDataPOD::group_bels> GroupBelRange; +typedef GroupObjRange<WireId, &GroupDataPOD::group_wires> GroupWireRange; +typedef GroupObjRange<PipId, &GroupDataPOD::group_pips> GroupPipRange; +typedef GroupObjRange<GroupId, &GroupDataPOD::group_groups> GroupGroupRange; + struct ArchRanges : BaseArchRanges { using ArchArgsT = ArchArgs; @@ -412,6 +464,12 @@ struct ArchRanges : BaseArchRanges using WireBelPinRangeT = BelPinRange; // Pips using AllPipsRangeT = AllPipRange; + // Groups + using AllGroupsRangeT = GroupRange; + using GroupBelsRangeT = GroupBelRange; + using GroupWiresRangeT = GroupWireRange; + using GroupPipsRangeT = GroupPipRange; + using GroupGroupsRangeT = GroupGroupRange; }; struct Arch : BaseArch<ArchRanges> @@ -699,6 +757,17 @@ struct Arch : BaseArch<ArchRanges> return uarch->getClusterPlacement(cluster, root_bel, placement); } + // ------------------------------------------------- + // Group methods + GroupId getGroupByName(IdStringList name) const override; + IdStringList getGroupName(GroupId group) const override; + GroupRange getGroups() const override { return GroupRange(chip_info); } + IdString getGroupType(GroupId group) const { return IdString(chip_group_info(chip_info, group).group_type); } + GroupBelRange getGroupBels(GroupId group) const override { return GroupBelRange(chip_group_info(chip_info, group), group.tile); } + GroupWireRange getGroupWires(GroupId group) const override { return GroupWireRange(chip_group_info(chip_info, group), group.tile); } + GroupPipRange getGroupPips(GroupId group) const override { return GroupPipRange(chip_group_info(chip_info, group), group.tile); } + GroupGroupRange getGroupGroups(GroupId group) const override { return GroupGroupRange(chip_group_info(chip_info, group), group.tile); } + // ------------------------------------------------- // Decal methods std::vector<GraphicElement> getDecalGraphics(DecalId decal) const override; diff --git a/himbaechel/archdefs.h b/himbaechel/archdefs.h index 589dea9926..be2fb5ebde 100644 --- a/himbaechel/archdefs.h +++ b/himbaechel/archdefs.h @@ -107,7 +107,23 @@ struct DecalId unsigned int hash() const { return mkhash(tile, mkhash(index, type)); } }; -typedef IdString GroupId; +struct GroupId +{ + int32_t tile = -1; + int32_t index = -1; + + GroupId() = default; + GroupId(int32_t tile, int32_t index) : tile(tile), index(index) {}; + + bool operator==(const GroupId &other) const { return tile == other.tile && index == other.index; } + bool operator!=(const GroupId &other) const { return tile != other.tile || index != other.index; } + bool operator<(const GroupId &other) const + { + return tile < other.tile || (tile == other.tile && index < other.index); + } + unsigned int hash() const { return mkhash(tile, index); } +}; + typedef IdString BelBucketId; typedef IdString ClusterId; diff --git a/himbaechel/chipdb.h b/himbaechel/chipdb.h index 4f3241c781..099a1112c7 100644 --- a/himbaechel/chipdb.h +++ b/himbaechel/chipdb.h @@ -93,11 +93,23 @@ NPNR_PACKED_STRUCT(struct NodeShapePOD { int32_t timing_idx; }); +NPNR_PACKED_STRUCT(struct GroupDataPOD { + int32_t name; + int32_t group_type; + RelSlice<int32_t> group_bels; + RelSlice<int32_t> group_wires; + RelSlice<int32_t> group_pips; + RelSlice<int32_t> group_groups; + + RelPtr<uint8_t> extra_data; +}); + NPNR_PACKED_STRUCT(struct TileTypePOD { int32_t type_name; RelSlice<BelDataPOD> bels; RelSlice<TileWireDataPOD> wires; RelSlice<PipDataPOD> pips; + RelSlice<GroupDataPOD> groups; RelPtr<uint8_t> extra_data; }); diff --git a/himbaechel/himbaechel_api.h b/himbaechel/himbaechel_api.h index fa75740139..8aa5ebd40c 100644 --- a/himbaechel/himbaechel_api.h +++ b/himbaechel/himbaechel_api.h @@ -114,6 +114,8 @@ struct HimbaechelAPI virtual void drawPip(std::vector<GraphicElement> &g,GraphicElement::style_t style, Loc loc, WireId src, IdString src_type, int32_t src_id, WireId dst, IdString dst_type, int32_t dst_id) {}; + virtual void drawGroup(std::vector<GraphicElement> &g, IdString group_type, Loc loc) {}; + // Routing methods virtual void expandBoundingBox(BoundingBox &bb) const; // --- Flow hooks --- diff --git a/himbaechel/himbaechel_dbgen/chip.py b/himbaechel/himbaechel_dbgen/chip.py index bedf0f28d4..b82c26174e 100644 --- a/himbaechel/himbaechel_dbgen/chip.py +++ b/himbaechel/himbaechel_dbgen/chip.py @@ -202,6 +202,47 @@ def serialise(self, context: str, bba: BBAWriter): else: bba.u32(0) @dataclass +class GroupData(BBAStruct): + index: int + name: IdString + group_type: IdString = field(default_factory=IdString) + group_bels: list[int] = field(default_factory=list) + group_wires: list[int] = field(default_factory=list) + group_pips: list[int] = field(default_factory=list) + group_groups: list[int] = field(default_factory=list) + extra_data: object = None + + def serialise_lists(self, context: str, bba: BBAWriter): + bba.label(f"{context}_group_bels") + for idx in self.group_bels: + bba.u32(idx) + bba.label(f"{context}_group_wires") + for idx in self.group_wires: + bba.u32(idx) + bba.label(f"{context}_group_pips") + for idx in self.group_pips: + bba.u32(idx) + bba.label(f"{context}_group_groups") + for idx in self.group_groups: + bba.u32(idx) + # extra data (optional) + if self.extra_data is not None: + self.extra_data.serialise_lists(f"{context}_extra_data", bba) + bba.label(f"{context}_extra_data") + self.extra_data.serialise(f"{context}_extra_data", bba) + def serialise(self, context: str, bba: BBAWriter): + bba.u32(self.name.index) + bba.u32(self.group_type.index) + bba.slice(f"{context}_group_bels", len(self.group_bels)) + bba.slice(f"{context}_group_wires", len(self.group_wires)) + bba.slice(f"{context}_group_pips", len(self.group_pips)) + bba.slice(f"{context}_group_groups", len(self.group_groups)) + if self.extra_data is not None: + bba.ref(f"{context}_extra_data") + else: + bba.u32(0) + +@dataclass class TileType(BBAStruct): strs: StringPool gfx_wire_ids: dict() @@ -210,8 +251,10 @@ class TileType(BBAStruct): bels: list[BelData] = field(default_factory=list) pips: list[PipData] = field(default_factory=list) wires: list[TileWireData] = field(default_factory=list) + groups: list[GroupData] = field(default_factory=list) _wire2idx: dict[IdString, int] = field(default_factory=dict) + _group2idx: dict[IdString, int] = field(default_factory=dict) extra_data: object = None @@ -253,6 +296,26 @@ def create_pip(self, src: str, dst: str, timing_class: str=""): self.wires[dst_idx].pips_uphill.append(pip.index) self.pips.append(pip) return pip + def create_group(self, name: str, type: str): + # Create a new group of a given name and type in the tile type + group = GroupData(index=len(self.groups), + name=self.strs.id(name), + group_type=self.strs.id(type)) + self._group2idx[group.name] = group.index + self.groups.append(group) + return group + def add_bel_to_group(self, bel: BelData, group: str): + group_idx = self._group2idx[self.strs.id(group)] + self.groups[group_idx].group_bels.append(bel.index) + def add_wire_to_group(self, wire: TileWireData, group: str): + group_idx = self._group2idx[self.strs.id(group)] + self.groups[group_idx].group_wires.append(wire.index) + def add_pip_to_group(self, pip: PipData, group: str): + group_idx = self._group2idx[self.strs.id(group)] + self.groups[group_idx].group_pips.append(pip.index) + def add_group_to_group(self, sub_group: GroupData, group: str): + group_idx = self._group2idx[self.strs.id(group)] + self.groups[group_idx].group_groups.append(sub_group.index) def has_wire(self, wire: str): # Check if a wire has already been created return self.strs.id(wire) in self._wire2idx @@ -267,6 +330,8 @@ def serialise_lists(self, context: str, bba: BBAWriter): wire.serialise_lists(f"{context}_wire{i}", bba) for i, pip in enumerate(self.pips): pip.serialise_lists(f"{context}_pip{i}", bba) + for i, group in enumerate(self.groups): + group.serialise_lists(f"{context}_group{i}", bba) # lists of members bba.label(f"{context}_bels") for i, bel in enumerate(self.bels): @@ -277,6 +342,9 @@ def serialise_lists(self, context: str, bba: BBAWriter): bba.label(f"{context}_pips") for i, pip in enumerate(self.pips): pip.serialise(f"{context}_pip{i}", bba) + bba.label(f"{context}_groups") + for i, group in enumerate(self.groups): + group.serialise(f"{context}_group{i}", bba) # extra data (optional) if self.extra_data is not None: self.extra_data.serialise_lists(f"{context}_extra_data", bba) @@ -287,6 +355,7 @@ def serialise(self, context: str, bba: BBAWriter): bba.slice(f"{context}_bels", len(self.bels)) bba.slice(f"{context}_wires", len(self.wires)) bba.slice(f"{context}_pips", len(self.pips)) + bba.slice(f"{context}_groups", len(self.groups)) if self.extra_data is not None: bba.ref(f"{context}_extra_data") else: