diff --git a/himbaechel/arch.cc b/himbaechel/arch.cc index 4152e7aee3..9ae9225e00 100644 --- a/himbaechel/arch.cc +++ b/himbaechel/arch.cc @@ -33,7 +33,7 @@ NEXTPNR_NAMESPACE_BEGIN -static constexpr int database_version = 4; +static constexpr int database_version = 5; static const ChipInfoPOD *get_chip_info(const RelPtr *ptr) { return ptr->get(); } @@ -501,4 +501,63 @@ IdString Arch::get_tile_type(int tile) const return IdString(tile_data.type_name); } +std::vector Arch::getDecalGraphics(DecalId decal) const +{ + std::vector ret; + 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)); + } else if (decal.type == DecalId::TYPE_WIRE) { + WireId w(decal.tile, decal.index); + for (WireId wire: get_tile_wire_range(w)) { + auto wire_type = getWireType(wire); + GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; + Loc loc; + tile_xy(chip_info, wire.tile, loc.x, loc.y); + int32_t tilewire = chip_wire_info(chip_info, wire).tile_wire; + uarch->drawWire(ret, style, loc, wire_type, tilewire, get_tile_type(wire.tile)); + } + } else if (decal.type == DecalId::TYPE_PIP) { + PipId pip(decal.tile, decal.index); + WireId src_wire = getPipSrcWire(pip); + WireId dst_wire = getPipDstWire(pip); + Loc loc = getPipLocation(pip); + int32_t src_id = chip_wire_info(chip_info, src_wire).tile_wire; + int32_t dst_id = chip_wire_info(chip_info, dst_wire).tile_wire; + GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_HIDDEN; + uarch->drawPip(ret, style, loc, src_wire, getWireType(src_wire), src_id, dst_wire, getWireType(dst_wire), dst_id); + } + return ret; +} + +DecalXY Arch::getBelDecal(BelId bel) const +{ + DecalXY decalxy; + decalxy.decal = DecalId(bel.tile, bel.index, DecalId::TYPE_BEL); + decalxy.decal.active = getBoundBelCell(bel) != nullptr; + return decalxy; +} + +DecalXY Arch::getWireDecal(WireId wire) const +{ + DecalXY decalxy; + decalxy.decal = DecalId(wire.tile, wire.index, DecalId::TYPE_WIRE); + decalxy.decal.active = getBoundWireNet(wire) != nullptr; + return decalxy; +} + +DecalXY Arch::getPipDecal(PipId pip) const +{ + DecalXY decalxy; + decalxy.decal = DecalId(pip.tile, pip.index, DecalId::TYPE_PIP); + decalxy.decal.active = getBoundPipNet(pip) != nullptr; + return decalxy; +} + +DecalXY Arch::getGroupDecal(GroupId group) const +{ + return DecalXY(); +} + NEXTPNR_NAMESPACE_END diff --git a/himbaechel/arch.h b/himbaechel/arch.h index 80765da356..c1076d5a56 100644 --- a/himbaechel/arch.h +++ b/himbaechel/arch.h @@ -698,6 +698,15 @@ struct Arch : BaseArch { return uarch->getClusterPlacement(cluster, root_bel, placement); } + + // ------------------------------------------------- + // Decal methods + std::vector getDecalGraphics(DecalId decal) const override; + DecalXY getBelDecal(BelId bel) const override; + DecalXY getWireDecal(WireId wire) const override; + DecalXY getPipDecal(PipId pip) const override; + DecalXY getGroupDecal(GroupId group) const override; + // ------------------------------------------------ bool pack() override; diff --git a/himbaechel/archdefs.h b/himbaechel/archdefs.h index d4b8d62155..589dea9926 100644 --- a/himbaechel/archdefs.h +++ b/himbaechel/archdefs.h @@ -85,7 +85,28 @@ struct PipId unsigned int hash() const { return mkhash(tile, index); } }; -typedef IdString DecalId; +struct DecalId +{ + int32_t tile = -1; + int32_t index = -1; + enum DecalType + { + TYPE_NONE, + TYPE_BEL, + TYPE_WIRE, + TYPE_PIP, + TYPE_GROUP + } type = TYPE_NONE; + bool active = false; + + DecalId() = default; + DecalId(int32_t tile, int32_t index, DecalType type) : tile(tile), index(index), type(type) {}; + + bool operator==(const DecalId &other) const { return tile == other.tile && index == other.index && type == other.type; } + bool operator!=(const DecalId &other) const { return tile != other.tile || index != other.index || type != other.type; } + unsigned int hash() const { return mkhash(tile, mkhash(index, type)); } +}; + typedef IdString GroupId; typedef IdString BelBucketId; typedef IdString ClusterId; diff --git a/himbaechel/chipdb.h b/himbaechel/chipdb.h index 17430ac4c2..4f3241c781 100644 --- a/himbaechel/chipdb.h +++ b/himbaechel/chipdb.h @@ -62,6 +62,7 @@ NPNR_PACKED_STRUCT(struct BelPinRefPOD { NPNR_PACKED_STRUCT(struct TileWireDataPOD { int32_t name; int32_t wire_type; + int32_t tile_wire; int32_t const_value; int32_t flags; // 32 bits of arbitrary data int32_t timing_idx; // used only when the wire is not part of a node, otherwise node idx applies diff --git a/himbaechel/himbaechel_api.h b/himbaechel/himbaechel_api.h index e795e4d5df..f432921738 100644 --- a/himbaechel/himbaechel_api.h +++ b/himbaechel/himbaechel_api.h @@ -105,6 +105,15 @@ struct HimbaechelAPI virtual bool isClusterStrict(const CellInfo *cell) const; virtual bool getClusterPlacement(ClusterId cluster, BelId root_bel, std::vector> &placement) const; + + // Graphics + virtual void drawBel(std::vector &g, GraphicElement::style_t style, IdString bel_type, Loc loc) {}; + + virtual void drawWire(std::vector &g, GraphicElement::style_t style, Loc loc, IdString wire_type, int32_t tilewire, IdString tile_type) {}; + + virtual void drawPip(std::vector &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) {}; + // --- Flow hooks --- virtual void pack() {}; // replaces the pack function // Called before and after main placement and routing diff --git a/himbaechel/himbaechel_dbgen/chip.py b/himbaechel/himbaechel_dbgen/chip.py index a5ee2b4272..bedf0f28d4 100644 --- a/himbaechel/himbaechel_dbgen/chip.py +++ b/himbaechel/himbaechel_dbgen/chip.py @@ -144,6 +144,7 @@ class TileWireData: index: int name: IdString wire_type: IdString + gfx_wire_id: int const_value: IdString = field(default_factory=list) flags: int = 0 timing_idx: int = -1 @@ -166,6 +167,7 @@ def serialise_lists(self, context: str, bba: BBAWriter): def serialise(self, context: str, bba: BBAWriter): bba.u32(self.name.index) bba.u32(self.wire_type.index) + bba.u32(self.gfx_wire_id) bba.u32(self.const_value.index) bba.u32(self.flags) bba.u32(self.timing_idx) @@ -202,6 +204,7 @@ def serialise(self, context: str, bba: BBAWriter): @dataclass class TileType(BBAStruct): strs: StringPool + gfx_wire_ids: dict() tmg: "TimingPool" type_name: IdString bels: list[BelData] = field(default_factory=list) @@ -229,9 +232,13 @@ def add_bel_pin(self, bel: BelData, pin: str, wire: str, dir: PinType): def create_wire(self, name: str, type: str="", const_value: str=""): # Create a new tile wire of a given name and type (optional) in the tile type + gfx_wire_id = 0 + if name in self.gfx_wire_ids: + gfx_wire_id = self.gfx_wire_ids[name] wire = TileWireData(index=len(self.wires), name=self.strs.id(name), wire_type=self.strs.id(type), + gfx_wire_id=gfx_wire_id, const_value=self.strs.id(const_value)) self._wire2idx[wire.name] = wire.index self.wires.append(wire) @@ -700,8 +707,9 @@ def __init__(self, uarch: str, name: str, width: int, height: int): self.packages = [] self.extra_data = None self.timing = TimingPool(self.strs) + self.gfx_wire_ids = dict() def create_tile_type(self, name: str): - tt = TileType(self.strs, self.timing, self.strs.id(name)) + tt = TileType(self.strs, self.gfx_wire_ids, self.timing, self.strs.id(name)) self.tile_type_idx[name] = len(self.tile_types) self.tile_types.append(tt) return tt @@ -831,7 +839,7 @@ def serialise(self, bba: BBAWriter): bba.label("chip_info") bba.u32(0x00ca7ca7) # magic - bba.u32(4) # version + bba.u32(5) # version bba.u32(self.width) bba.u32(self.height) @@ -866,3 +874,16 @@ def write_bba(self, filename): bba.ref('chip_info') self.serialise(bba) bba.pop() + + def read_gfxids(self, filename): + idx = 1 + with open(filename) as f: + for line in f: + l = line.strip() + if not l.startswith("X("): + continue + l = l[2:] + assert l.endswith(")"), l + l = l[:-1].strip() + self.gfx_wire_ids[l] = idx + idx += 1 diff --git a/himbaechel/himbaechel_gfxids.h b/himbaechel/himbaechel_gfxids.h new file mode 100644 index 0000000000..8d954bb3f3 --- /dev/null +++ b/himbaechel/himbaechel_gfxids.h @@ -0,0 +1,53 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 gatecat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef HIMBAECHEL_GFXIDS_H +#define HIMBAECHEL_GFXIDS_H + +/* +This enables use of 'gfxids' similar to a 'constids' in a HIMBAECHEL uarch. +To use: + - create a 'gfxids.inc' file in your uarch folder containing one ID per line; inside X( ) + - set the HIMBAECHEL_UARCH macro to uarch namespace + - set the HIMBAECHEL_GFXIDS macro to the path to this file relative to the generic arch base + - include this file +*/ + +#include "nextpnr_namespaces.h" + +NEXTPNR_NAMESPACE_BEGIN + +namespace HIMBAECHEL_UARCH { +#ifndef Q_MOC_RUN +enum GfxTileWireId +{ + GFX_WIRE_NONE +#define X(t) , GFX_WIRE_##t +#include HIMBAECHEL_GFXIDS +#undef X + , +}; +#endif +}; + +NEXTPNR_NAMESPACE_END + +using namespace NEXTPNR_NAMESPACE_PREFIX HIMBAECHEL_UARCH; + +#endif diff --git a/himbaechel/uarch/example/CMakeLists.txt b/himbaechel/uarch/example/CMakeLists.txt index 046f01306a..26be2ea31b 100644 --- a/himbaechel/uarch/example/CMakeLists.txt +++ b/himbaechel/uarch/example/CMakeLists.txt @@ -22,6 +22,7 @@ foreach(device ${HIMBAECHEL_EXAMPLE_DEVICES}) bbasm ${CMAKE_CURRENT_SOURCE_DIR}/example_arch_gen.py ${CMAKE_CURRENT_SOURCE_DIR}/constids.inc + ${CMAKE_CURRENT_SOURCE_DIR}/gfxids.inc VERBATIM) list(APPEND chipdb_binaries ${device_bin}) endforeach() diff --git a/himbaechel/uarch/example/constids.inc b/himbaechel/uarch/example/constids.inc index 900577e46c..eca9b10827 100644 --- a/himbaechel/uarch/example/constids.inc +++ b/himbaechel/uarch/example/constids.inc @@ -13,7 +13,31 @@ X(IOB) X(PAD) X(INIT) +X(BRAM_512X16) + X(GND) X(GND_DRV) X(VCC) -X(VCC_DRV) \ No newline at end of file +X(VCC_DRV) + +X(LUT_INPUT) +X(FF_DATA) +X(LUT_OUT) +X(FF_OUT) +X(TILE_CLK) + +X(RAM_IN) +X(RAM_OUT) + +X(IO_I) +X(IO_O) +X(IO_T) +X(IO_PAD) +X(GCLK) + +X(CLK_ROUTE) + +X(LOGIC) +X(BRAM) +X(IO) +X(NULL) diff --git a/himbaechel/uarch/example/example.cc b/himbaechel/uarch/example/example.cc index 391a8ca441..42b7608668 100644 --- a/himbaechel/uarch/example/example.cc +++ b/himbaechel/uarch/example/example.cc @@ -26,7 +26,10 @@ #define GEN_INIT_CONSTIDS #define HIMBAECHEL_CONSTIDS "uarch/example/constids.inc" +#define HIMBAECHEL_GFXIDS "uarch/example/gfxids.inc" +#define HIMBAECHEL_UARCH example #include "himbaechel_constids.h" +#include "himbaechel_gfxids.h" NEXTPNR_NAMESPACE_BEGIN @@ -135,6 +138,182 @@ struct ExampleImpl : HimbaechelAPI return false; return true; } + + void drawBel(std::vector &g, GraphicElement::style_t style, IdString bel_type, Loc loc) override + { + GraphicElement el; + el.type = GraphicElement::TYPE_BOX; + el.style = style; + switch (bel_type.index) + { + case id_LUT4.index : + el.x1 = loc.x + 0.15; + el.x2 = el.x1 + 0.25; + el.y1 = loc.y + 0.85 - (loc.z / 2) * 0.1; + el.y2 = el.y1 - 0.05; + g.push_back(el); + break; + case id_DFF.index : + el.x1 = loc.x + 0.55; + el.x2 = el.x1 + 0.25; + el.y1 = loc.y + 0.85 - (loc.z / 2) * 0.1; + el.y2 = el.y1 - 0.05; + g.push_back(el); + break; + case id_GND_DRV.index : + case id_VCC_DRV.index : + case id_IOB.index : + el.x1 = loc.x + 0.25; + el.x2 = el.x1 + 0.50; + el.y1 = loc.y + 0.80 - loc.z * 0.40; + el.y2 = el.y1 - 0.25; + g.push_back(el); + break; + case id_BRAM_512X16.index : + el.x1 = loc.x + 0.25; + el.x2 = el.x1 + 0.50; + el.y1 = loc.y + 0.80; + el.y2 = el.y1 - 0.60; + g.push_back(el); + break; + } + } + + void drawWire(std::vector &g, GraphicElement::style_t style, Loc loc, IdString wire_type, int32_t tilewire, IdString tile_type) + { + GraphicElement el; + el.type = GraphicElement::TYPE_LINE; + el.style = style; + int z; + switch(tile_type.index) + { + case id_LOGIC.index: + switch (wire_type.index) + { + case id_LUT_INPUT.index: + z = (tilewire - GFX_WIRE_L0_I0) / 4; + el.x1 = loc.x + 0.10; + el.x2 = el.x1 + 0.05; + el.y1 = loc.y + 0.85 - z * 0.1 - ((tilewire - GFX_WIRE_L0_I0) % 4 + 1) * 0.01; + el.y2 = el.y1; + g.push_back(el); + break; + case id_LUT_OUT.index: + z = tilewire - GFX_WIRE_L0_O; + el.x1 = loc.x + 0.40; + el.x2 = el.x1 + 0.05; + el.y1 = loc.y + 0.85 - z * 0.1 - 0.025; + el.y2 = el.y1; + g.push_back(el); + break; + case id_FF_DATA.index: + z = tilewire - GFX_WIRE_L0_D; + el.x1 = loc.x + 0.50; + el.x2 = el.x1 + 0.05; + el.y1 = loc.y + 0.85 - z * 0.1 - 0.025; + el.y2 = el.y1; + g.push_back(el); + break; + case id_FF_OUT.index: + z = tilewire - GFX_WIRE_L0_Q; + el.x1 = loc.x + 0.80; + el.x2 = el.x1 + 0.05; + el.y1 = loc.y + 0.85 - z * 0.1 - 0.025; + el.y2 = el.y1; + g.push_back(el); + break; + case id_TILE_CLK.index: + for(int i=0;i<8; i++) { + GraphicElement el; + el.type = GraphicElement::TYPE_LINE; + el.style = style; + el.x1 = loc.x + 0.6; + el.x2 = el.x1; + el.y1 = loc.y + 0.85 - i * 0.1 - 0.05; + el.y2 = el.y1 - 0.05; + g.push_back(el); + } + break; + } + break; + case id_BRAM.index: + switch (wire_type.index) + { + case id_RAM_IN.index: + z = tilewire - GFX_WIRE_RAM_WA0; + el.x1 = loc.x + 0.20; + el.x2 = el.x1 + 0.05; + el.y1 = loc.y + 0.78 - z * 0.015; + el.y2 = el.y1; + g.push_back(el); + break; + case id_RAM_OUT.index: + z = tilewire - GFX_WIRE_RAM_DO0; + el.x1 = loc.x + 0.75; + el.x2 = el.x1 + 0.05; + el.y1 = loc.y + 0.78 - z * 0.015; + el.y2 = el.y1; + g.push_back(el); + break; + case id_TILE_CLK.index: + el.x1 = loc.x + 0.6; + el.x2 = el.x1; + el.y1 = loc.y + 0.20; + el.y2 = el.y1 - 0.05; + g.push_back(el); + break; + } + break; + case id_IO.index: + switch (wire_type.index) + { + case id_IO_I.index: + break; + case id_IO_O.index: + break; + case id_IO_T.index: + break; + case id_IO_PAD.index: + break; + case id_TILE_CLK.index: + break; + case id_GCLK.index: + break; + } + break; + case id_NULL.index: + switch (wire_type.index) + { + case id_CLK_ROUTE.index: + break; + case id_GND.index: + break; + case id_VCC.index: + break; + case id_TILE_CLK.index: + break; + } + break; + } + } + + void drawPip(std::vector &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) + { + GraphicElement el; + el.type = GraphicElement::TYPE_ARROW; + el.style = style; + int z; + if (src_type == id_LUT_OUT && dst_type == id_FF_DATA) { + z = src_id - GFX_WIRE_L0_O; + el.x1 = loc.x + 0.45; + el.y1 = loc.y + 0.85 - z * 0.1 - 0.025; + el.x2 = loc.x + 0.50; + el.y2 = el.y1; + g.push_back(el); + + } + } }; struct ExampleArch : HimbaechelArch diff --git a/himbaechel/uarch/example/example_arch_gen.py b/himbaechel/uarch/example/example_arch_gen.py index cbfefd61ef..d36ae22e63 100644 --- a/himbaechel/uarch/example/example_arch_gen.py +++ b/himbaechel/uarch/example/example_arch_gen.py @@ -237,6 +237,7 @@ def main(): ch = Chip("example", "EX1", X, Y) # Init constant ids ch.strs.read_constids(path.join(path.dirname(__file__), "constids.inc")) + ch.read_gfxids(path.join(path.dirname(__file__), "gfxids.inc")) logic = create_logic_tiletype(ch) io = create_io_tiletype(ch) bram = create_bram_tiletype(ch) diff --git a/himbaechel/uarch/example/gfxids.inc b/himbaechel/uarch/example/gfxids.inc new file mode 100644 index 0000000000..567480821e --- /dev/null +++ b/himbaechel/uarch/example/gfxids.inc @@ -0,0 +1,123 @@ +X(L0_O) +X(L1_O) +X(L2_O) +X(L3_O) +X(L4_O) +X(L5_O) +X(L6_O) +X(L7_O) + +X(L0_I0) +X(L0_I1) +X(L0_I2) +X(L0_I3) + +X(L1_I0) +X(L1_I1) +X(L1_I2) +X(L1_I3) + +X(L2_I0) +X(L2_I1) +X(L2_I2) +X(L2_I3) + +X(L3_I0) +X(L3_I1) +X(L3_I2) +X(L3_I3) + +X(L4_I0) +X(L4_I1) +X(L4_I2) +X(L4_I3) + +X(L5_I0) +X(L5_I1) +X(L5_I2) +X(L5_I3) + +X(L6_I0) +X(L6_I1) +X(L6_I2) +X(L6_I3) + +X(L7_I0) +X(L7_I1) +X(L7_I2) +X(L7_I3) + +X(L0_D) +X(L1_D) +X(L2_D) +X(L3_D) +X(L4_D) +X(L5_D) +X(L6_D) +X(L7_D) + +X(L0_Q) +X(L1_Q) +X(L2_Q) +X(L3_Q) +X(L4_Q) +X(L5_Q) +X(L6_Q) +X(L7_Q) + +X(RAM_WA0) +X(RAM_WA1) +X(RAM_WA2) +X(RAM_WA3) +X(RAM_WA4) +X(RAM_WA5) +X(RAM_WA6) +X(RAM_WA7) +X(RAM_WA8) + +X(RAM_RA0) +X(RAM_RA1) +X(RAM_RA2) +X(RAM_RA3) +X(RAM_RA4) +X(RAM_RA5) +X(RAM_RA6) +X(RAM_RA7) +X(RAM_RA8) + +X(RAM_WE0) +X(RAM_WE1) + +X(RAM_DI0) +X(RAM_DI1) +X(RAM_DI2) +X(RAM_DI3) +X(RAM_DI4) +X(RAM_DI5) +X(RAM_DI6) +X(RAM_DI7) +X(RAM_DI8) +X(RAM_DI9) +X(RAM_DI10) +X(RAM_DI11) +X(RAM_DI12) +X(RAM_DI13) +X(RAM_DI14) +X(RAM_DI15) + +X(RAM_DO0) +X(RAM_DO1) +X(RAM_DO2) +X(RAM_DO3) +X(RAM_DO4) +X(RAM_DO5) +X(RAM_DO6) +X(RAM_DO7) +X(RAM_DO8) +X(RAM_DO9) +X(RAM_DO10) +X(RAM_DO11) +X(RAM_DO12) +X(RAM_DO13) +X(RAM_DO14) +X(RAM_DO15)