Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

himbaechel: Adding a xilinx uarch for xc7 with prjxray #1235

Merged
merged 1 commit into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "fpga-interchange-schema"]
path = 3rdparty/fpga-interchange-schema
url = https://github.com/SymbiFlow/fpga-interchange-schema.git
[submodule "himbaechel/uarch/xilinx/meta"]
path = himbaechel/uarch/xilinx/meta
url = https://github.com/gatecat/nextpnr-xilinx-meta
2 changes: 1 addition & 1 deletion himbaechel/arch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ const std::string Arch::defaultPlacer = "heap";

const std::vector<std::string> Arch::availablePlacers = {"sa", "heap"};

const std::string Arch::defaultRouter = "router1";
const std::string Arch::defaultRouter = "router2";
const std::vector<std::string> Arch::availableRouters = {"router1", "router2"};

void Arch::set_fast_pip_delays(bool fast_mode)
Expand Down
9 changes: 9 additions & 0 deletions himbaechel/arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,15 @@ struct Arch : BaseArch<ArchRanges>
// Scale delay (fF * mOhm -> ps)
delay_t total_delay = (input_res * input_cap) / uint64_t(1e6);
total_delay += pip_tmg->int_delay.slow_max;

WireId dst = getPipDstWire(pip);
auto dst_tmg = get_node_timing(dst);
if (dst_tmg != nullptr) {
total_delay +=
((pip_tmg->out_res.slow_max + uint64_t(dst_tmg->res.slow_max) / 2) * dst_tmg->cap.slow_max) /
uint64_t(1e6);
}

return DelayQuad(total_delay);
} else {
// Pip with no specified delay. Return a notional value so the router still has something to work with.
Expand Down
2 changes: 1 addition & 1 deletion himbaechel/family.cmake
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
set(HIMBAECHEL_UARCHES "example;gowin")
set(HIMBAECHEL_UARCHES "example;gowin;xilinx")
foreach(uarch ${HIMBAECHEL_UARCHES})
add_subdirectory(${family}/uarch/${uarch})
aux_source_directory(${family}/uarch/${uarch} HM_UARCH_FILES)
Expand Down
13 changes: 9 additions & 4 deletions himbaechel/himbaechel_dbgen/chip.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ class NodeShape(BBAStruct):
def key(self):
m = hashlib.md5()
m.update(struct.pack("h"*len(self.wires), *self.wires))
m.update(struct.pack("i", self.timing_index))
return m.digest()

def serialise_lists(self, context: str, bba: BBAWriter):
Expand Down Expand Up @@ -644,7 +645,11 @@ def set_pip_class(self, grade: str, name: str, delay: TimingValue,
if idx >= len(sg.pip_classes):
sg.pip_classes += [None for i in range(1 + idx - len(sg.pip_classes))]
assert sg.pip_classes[idx] is None, f"attempting to set pip class {name} in speed grade {grade} twice"
sg.pip_classes[idx] = PipTiming(int_delay=delay, in_cap=in_cap, out_res=out_res, flags=(1 if is_buffered else 0))
sg.pip_classes[idx] = PipTiming(int_delay=delay,
in_cap=in_cap or TimingValue(),
out_res=out_res or TimingValue(),
flags=(1 if is_buffered else 0)
)

def set_bel_pin_class(self, grade: str, name: str, delay: TimingValue,
in_cap: Optional[TimingValue]=None, out_res: Optional[TimingValue]=None):
Expand All @@ -658,7 +663,7 @@ def set_node_class(self, grade: str, name: str, delay: TimingValue,
if idx >= len(sg.node_classes):
sg.node_classes += [None for i in range(1 + idx - len(sg.node_classes))]
assert sg.node_classes[idx] is None, f"attempting to set node class {name} in speed grade {grade} twice"
sg.node_classes[idx] = NodeTiming(delay=delay, res=res, cap=cap)
sg.node_classes[idx] = NodeTiming(delay=delay, res=res or TimingValue(), cap=cap or TimingValue())

def add_cell_variant(self, speed_grade: str, name: str):
cell = CellTiming(self.strs, name)
Expand Down Expand Up @@ -700,13 +705,13 @@ def tile_type_at(self, x: int, y: int):
def set_speed_grades(self, speed_grades: list):
self.timing.set_speed_grades(speed_grades)
return self.timing
def add_node(self, wires: list[NodeWire]):
def add_node(self, wires: list[NodeWire], timing_class=""):
# add a node - joining between multiple tile wires into a single connection (from nextpnr's point of view)
# all the tile wires must exist, and the tile types must be set, first
x0 = wires[0].x
y0 = wires[0].y
# compute node shape
shape = NodeShape()
shape = NodeShape(timing_index=self.timing.node_class_idx(timing_class))
for w in wires:
if isinstance(w.wire, int):
wire_index = w.wire
Expand Down
37 changes: 37 additions & 0 deletions himbaechel/uarch/xilinx/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
message(STATUS "Configuring Xilinx uarch")
cmake_minimum_required(VERSION 3.5)
project(himbaechel-xilinx-chipdb NONE)

set(HIMBAECHEL_XILINX_DEVICES "" CACHE STRING
"Include support for these Xilinx devices via himbaechel")
set(HIMBAECHEL_PRJXRAY_DB "" CACHE STRING
"Path to a project x-ray database")
message(STATUS "Enabled Himbaechel-Xilinx devices: ${HIMBAECHEL_XILINX_DEVICES}")


set(chipdb_binaries)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/share/himbaechel/xilinx)
foreach(device ${HIMBAECHEL_XILINX_DEVICES})
if("${HIMBAECHEL_PRJXRAY_DB}" STREQUAL "")
message(SEND_ERROR "HIMBAECHEL_PRJXRAY_DB must be set to a prjxray database checkout")
endif()

set(device_bba ${CMAKE_BINARY_DIR}/share/himbaechel/xilinx/chipdb-${device}.bba)
set(device_bin ${CMAKE_BINARY_DIR}/share/himbaechel/xilinx/chipdb-${device}.bin)
add_custom_command(
OUTPUT ${device_bin}
COMMAND pypy3 ${CMAKE_CURRENT_SOURCE_DIR}/gen/xilinx_gen.py --xray ${HIMBAECHEL_PRJXRAY_DB}/artix7 --device ${device} --bba ${device_bba}
COMMAND bbasm ${BBASM_ENDIAN_FLAG} ${device_bba} ${device_bin}.new
# atomically update
COMMAND ${CMAKE_COMMAND} -E rename ${device_bin}.new ${device_bin}
DEPENDS
bbasm
${CMAKE_CURRENT_SOURCE_DIR}/gen/xilinx_gen.py
${CMAKE_CURRENT_SOURCE_DIR}/constids.inc
VERBATIM)
list(APPEND chipdb_binaries ${device_bin})
endforeach()

add_custom_target(chipdb-himbaechel-xilinx ALL DEPENDS ${chipdb_binaries})
install(DIRECTORY ${CMAKE_BINARY_DIR}/share/himbaechel/xilinx/ DESTINATION share/nextpnr/himbaechel/xilinx
PATTERN "*.bba" EXCLUDE)
197 changes: 197 additions & 0 deletions himbaechel/uarch/xilinx/cells.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2023 Myrtle Shah <[email protected]>
*
* 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.
*
*/

#include "nextpnr.h"
#include "pack.h"
#include "pins.h"

#define HIMBAECHEL_CONSTIDS "uarch/xilinx/constids.inc"
#include "himbaechel_constids.h"

NEXTPNR_NAMESPACE_BEGIN

CellInfo *XilinxPacker::create_cell(IdString type, IdString name)
{
CellInfo *cell = ctx->createCell(name, type);

auto add_port = [&](const std::string &name, PortType dir) {
IdString id = ctx->id(name);
cell->ports[id].name = id;
cell->ports[id].type = dir;
};
if (type == id_SLICE_LUTX) {
for (int i = 1; i <= 6; i++)
add_port("A" + std::to_string(i), PORT_IN);
for (int i = 1; i <= 9; i++)
add_port("WA" + std::to_string(i), PORT_IN);
add_port("DI1", PORT_IN);
add_port("DI2", PORT_IN);
add_port("CLK", PORT_IN);
add_port("WE", PORT_IN);
add_port("SIN", PORT_IN);
add_port("O5", PORT_OUT);
add_port("O6", PORT_OUT);
add_port("MC31", PORT_OUT);
} else if (type == id_SLICE_FFX) {
add_port("D", PORT_IN);
add_port("SR", PORT_IN);
add_port("CE", PORT_IN);
add_port("CLK", PORT_IN);
add_port("Q", PORT_OUT);
} else if (type == id_RAMD64E) {
for (int i = 0; i < 6; i++)
add_port("RADR" + std::to_string(i), PORT_IN);
for (int i = 0; i < 8; i++)
add_port("WADR" + std::to_string(i), PORT_IN);
add_port("CLK", PORT_IN);
add_port("I", PORT_IN);
add_port("WE", PORT_IN);
add_port("O", PORT_OUT);
} else if (type == id_RAMD32) {
for (int i = 0; i < 5; i++)
add_port("RADR" + std::to_string(i), PORT_IN);
for (int i = 0; i < 5; i++)
add_port("WADR" + std::to_string(i), PORT_IN);
add_port("CLK", PORT_IN);
add_port("I", PORT_IN);
add_port("WE", PORT_IN);
add_port("O", PORT_OUT);
} else if (type.in(id_MUXF7, id_MUXF8, id_MUXF9)) {
add_port("I0", PORT_IN);
add_port("I1", PORT_IN);
add_port("S", PORT_IN);
add_port("O", PORT_OUT);
} else if (type == id_CARRY8) {
add_port("CI", PORT_IN);
add_port("CI_TOP", PORT_IN);

for (int i = 0; i < 8; i++) {
add_port("DI[" + std::to_string(i) + "]", PORT_IN);
add_port("S[" + std::to_string(i) + "]", PORT_IN);
add_port("CO[" + std::to_string(i) + "]", PORT_OUT);
add_port("O[" + std::to_string(i) + "]", PORT_OUT);
}
} else if (type == id_MUXCY) {
add_port("CI", PORT_IN);
add_port("DI", PORT_IN);
add_port("S", PORT_IN);
add_port("O", PORT_OUT);
} else if (type == id_XORCY) {
add_port("CI", PORT_IN);
add_port("LI", PORT_IN);
add_port("O", PORT_OUT);
} else if (type == id_PAD) {
add_port("PAD", PORT_INOUT);
} else if (type == id_INBUF) {
add_port("VREF", PORT_IN);
add_port("PAD", PORT_IN);
add_port("OSC_EN", PORT_IN);
for (int i = 0; i < 4; i++)
add_port("OSC[" + std::to_string(i) + "]", PORT_IN);
add_port("O", PORT_OUT);
} else if (type == id_IBUFCTRL) {
add_port("I", PORT_IN);
add_port("IBUFDISABLE", PORT_IN);
add_port("T", PORT_IN);
add_port("O", PORT_OUT);
} else if (type.in(id_OBUF, id_IBUF)) {
add_port("I", PORT_IN);
add_port("O", PORT_OUT);
} else if (type == id_OBUFT) {
add_port("I", PORT_IN);
add_port("T", PORT_IN);
add_port("O", PORT_OUT);
} else if (type == id_IOBUF) {
add_port("I", PORT_IN);
add_port("T", PORT_IN);
add_port("O", PORT_OUT);
add_port("IO", PORT_INOUT);
} else if (type == id_OBUFT_DCIEN) {
add_port("I", PORT_IN);
add_port("T", PORT_IN);
add_port("DCITERMDISABLE", PORT_IN);
add_port("O", PORT_OUT);
} else if (type == id_DIFFINBUF) {
add_port("DIFF_IN_P", PORT_IN);
add_port("DIFF_IN_N", PORT_IN);
add_port("OSC_EN[0]", PORT_IN);
add_port("OSC_EN[1]", PORT_IN);
for (int i = 0; i < 4; i++)
add_port("OSC[" + std::to_string(i) + "]", PORT_IN);
add_port("VREF", PORT_IN);
add_port("O", PORT_OUT);
add_port("O_B", PORT_OUT);
} else if (type == id_HPIO_VREF) {
for (int i = 0; i < 7; i++)
add_port("FABRIC_VREF_TUNE[" + std::to_string(i) + "]", PORT_IN);
add_port("VREF", PORT_OUT);
} else if (type == id_INV) {
add_port("I", PORT_IN);
add_port("O", PORT_OUT);
} else if (type == id_IDELAYCTRL) {
add_port("REFCLK", PORT_IN);
add_port("RST", PORT_IN);
add_port("RDY", PORT_OUT);
} else if (type == id_IBUF) {
add_port("I", PORT_IN);
add_port("O", PORT_OUT);
} else if (type == id_IBUF_INTERMDISABLE) {
add_port("I", PORT_IN);
add_port("IBUFDISABLE", PORT_IN);
add_port("INTERMDISABLE", PORT_IN);
add_port("O", PORT_OUT);
} else if (type == id_IBUFDS) {
add_port("I", PORT_IN);
add_port("IB", PORT_IN);
add_port("O", PORT_OUT);
} else if (type == id_IBUFDS_INTERMDISABLE_INT) {
add_port("I", PORT_IN);
add_port("IB", PORT_IN);
add_port("IBUFDISABLE", PORT_IN);
add_port("INTERMDISABLE", PORT_IN);
add_port("O", PORT_OUT);
} else if (type == id_CARRY4) {
add_port("CI", PORT_IN);
add_port("CYINIT", PORT_IN);
for (int i = 0; i < 4; i++) {
add_port("DI[" + std::to_string(i) + "]", PORT_IN);
add_port("S[" + std::to_string(i) + "]", PORT_IN);
add_port("CO[" + std::to_string(i) + "]", PORT_OUT);
add_port("O[" + std::to_string(i) + "]", PORT_OUT);
}
}
return cell;
}

CellInfo *XilinxPacker::create_lut(const std::string &name, const std::vector<NetInfo *> &inputs, NetInfo *output,
const Property &init)
{
CellInfo *cell = ctx->createCell(ctx->id(name), ctx->idf("LUT%d", int(inputs.size())));
for (size_t i = 0; i < inputs.size(); i++) {
IdString ip = ctx->idf("I%d", int(i));
cell->addInput(ip);
cell->connectPort(ip, inputs.at(i));
}
cell->addOutput(id_O);
cell->connectPort(id_O, output);
cell->params[id_INIT] = init;
return cell;
}

NEXTPNR_NAMESPACE_END
Loading