diff --git a/hwdb4cpp/hwdb4c.cpp b/hwdb4cpp/hwdb4c.cpp
index 583069e983860f050af06510dd2ba41ac6186508..6bb1b184347808544f2afffdfcd5466d718eb521 100644
--- a/hwdb4cpp/hwdb4c.cpp
+++ b/hwdb4cpp/hwdb4c.cpp
@@ -229,6 +229,13 @@ int _convert_hxcube_setup_entry(
} else {
fpga_entry_c->wing = NULL;
}
+ if (fpga_it.second.fuse_dna) {
+ fpga_entry_c->fuse_dna = fpga_it.second.fuse_dna.value();
+ fpga_entry_c->dna_port = fpga_it.second.get_dna_port();
+ } else {
+ fpga_entry_c->fuse_dna = 0;
+ fpga_entry_c->dna_port = 0;
+ }
hxcube_entry_c->fpgas[fpga_counter] = fpga_entry_c;
fpga_counter++;
}
@@ -237,6 +244,15 @@ int _convert_hxcube_setup_entry(
strncpy(hxcube_entry_c->usb_host, hxcube_entry_cpp.usb_host.c_str(), hxcube_entry_cpp.usb_host.length() + 1);
hxcube_entry_c->usb_serial = (char*)malloc((hxcube_entry_cpp.usb_serial.length() + 1) * sizeof(char));
strncpy(hxcube_entry_c->usb_serial, hxcube_entry_cpp.usb_serial.c_str(), hxcube_entry_cpp.usb_serial.length() + 1);
+ if (hxcube_entry_cpp.xilinx_hw_server) {
+ hxcube_entry_c->xilinx_hw_server =
+ (char*) malloc((hxcube_entry_cpp.xilinx_hw_server.value().length() + 1) * sizeof(char));
+ strncpy(
+ hxcube_entry_c->xilinx_hw_server, hxcube_entry_cpp.xilinx_hw_server.value().c_str(),
+ hxcube_entry_cpp.xilinx_hw_server.value().length() + 1);
+ } else {
+ hxcube_entry_c->xilinx_hw_server = NULL;
+ }
*ret = hxcube_entry_c;
return HWDB4C_SUCCESS;
@@ -646,6 +662,9 @@ void hwdb4c_free_hxcube_setup_entry(struct hwdb4c_hxcube_setup_entry* entry)
hwdb4c_free_hxcube_fpga_entry(entry->fpgas[i]);
}
free(entry->fpgas);
+ if (entry->xilinx_hw_server) {
+ free(entry->xilinx_hw_server);
+ }
free(entry);
}
diff --git a/hwdb4cpp/hwdb4c.h b/hwdb4cpp/hwdb4c.h
index 9a56157ddcadd13e0039175e2b83e9c855332ea5..24136102d10412de1e189a73161fdc2be4f7116d 100644
--- a/hwdb4cpp/hwdb4c.h
+++ b/hwdb4cpp/hwdb4c.h
@@ -127,6 +127,9 @@ struct SYMBOL_VISIBLE hwdb4c_hxcube_fpga_entry
size_t fpga_id;
struct in_addr ip;
struct hwdb4c_hxcube_wing_entry* wing;
+ uint64_t fuse_dna;
+
+ uint64_t dna_port; // cpp get_dna_port member function
};
struct SYMBOL_VISIBLE hwdb4c_hxcube_setup_entry
@@ -139,6 +142,7 @@ struct SYMBOL_VISIBLE hwdb4c_hxcube_setup_entry
size_t num_fpgas;
char* usb_host;
char* usb_serial;
+ char* xilinx_hw_server;
};
diff --git a/hwdb4cpp/hwdb4cpp.cpp b/hwdb4cpp/hwdb4cpp.cpp
index 26a023db51677c279353f83b2741e8ac29c15c75..148fc1add2aa1071ec5ccc5d67befa5108ac7ad8 100644
--- a/hwdb4cpp/hwdb4cpp.cpp
+++ b/hwdb4cpp/hwdb4cpp.cpp
@@ -1,5 +1,6 @@
#include "hwdb4cpp.h"
+#include <bitset>
#include <sstream>
#include <string>
#include <vector>
@@ -223,6 +224,9 @@ struct convert<HXFPGAYAML>
Node node;
node["fpga"] = data.coordinate;
node["ip"] = data.ip.to_string();
+ if (data.fuse_dna) {
+ node["fuse_dna"] = data.fuse_dna.value();
+ }
if (data.wing) {
node["ldo_version"] = data.wing.value().ldo_version;
node["handwritten_chip_serial"] = data.wing.value().handwritten_chip_serial;
@@ -236,12 +240,16 @@ struct convert<HXFPGAYAML>
static bool decode(const Node& node, HXFPGAYAML& data)
{
- if (!node.IsMap() || node.size() > 6) {
- LOG4CXX_ERROR(logger, "Decoding failed of: '''\n" << node << "'''");
+ if (!node.IsMap() || node.size() > 7) {
+ LOG4CXX_ERROR(logger, "Decoding failed of: '''\n" << node << "'''")
return false;
}
data.coordinate = get_entry<size_t>(node, "fpga");
data.ip = IPv4::from_string(get_entry<std::string>(node, "ip"));
+ auto fuse_dna = node["fuse_dna"];
+ if (fuse_dna.IsDefined()) {
+ data.fuse_dna = fuse_dna.as<uint64_t>();
+ }
auto ldo = node["ldo_version"];
auto hand_serial = node["handwritten_chip_serial"];
auto chip_rev = node["chip_revision"];
@@ -263,10 +271,10 @@ struct convert<HXFPGAYAML>
}
data.wing = wing;
} else {
- if (eeprom.IsDefined()) {
+ if (eeprom.IsDefined() || fuse_dna.IsDefined()) {
LOG4CXX_ERROR(
- logger, "Decoding failed. eeprom cannot be defined alone. Node: '''\n"
- << node << "'''");
+ logger, "Decoding failed. Only optional entries found. Node: '''\n"
+ << node << "'''")
return false;
}
}
@@ -358,6 +366,19 @@ struct convert<HICANNYAML>
namespace hwdb4cpp {
+uint64_t HXCubeFPGAEntry::get_dna_port() const
+{
+ auto dna = std::bitset<64>(fuse_dna.value());
+
+ // see Xilinx UG470 (v1.13.1) Table 5-16
+ std::bitset<57> dna_port;
+ for (size_t i = 0; i < 57; ++i) {
+ dna_port[i] = dna[63 - i];
+ }
+
+ return dna_port.to_ullong();
+}
+
std::string HXCubeSetupEntry::get_unique_branch_identifier(size_t chip_serial) const
{
using namespace std::string_literals;
@@ -365,7 +386,7 @@ std::string HXCubeSetupEntry::get_unique_branch_identifier(size_t chip_serial) c
if (!fpga.second.wing) {
continue;
}
- if ((fpga.second.wing.value().handwritten_chip_serial == chip_serial) |
+ if ((fpga.second.wing.value().handwritten_chip_serial == chip_serial) ||
(fpga.second.wing.value().eeprom_chip_serial == chip_serial)) {
return "hxcube"s + std::to_string(hxcube_id) + "fpga"s + std::to_string(fpga.first) +
"chip"s + std::to_string(fpga.second.wing.value().handwritten_chip_serial) +
@@ -527,6 +548,13 @@ void database::load(std::string const path)
if (usb_serial_entry.IsDefined()) {
mHXCubeData.at(hxcube_id).usb_serial = usb_serial_entry.as<std::string>();
}
+
+ auto xilinx_hw_server_entry = config["xilinx_hw_server"];
+ if (xilinx_hw_server_entry.IsDefined()) {
+ mHXCubeData.at(hxcube_id).xilinx_hw_server =
+ xilinx_hw_server_entry.as<std::string>();
+ }
+
}
// yaml node does not contain wafer or dls setup or hxcube setup
else {
@@ -753,6 +781,12 @@ void database::dump(std::ostream& out) const
config["usb_serial"] = data.usb_serial;
out << config << '\n';
}
+
+ if (data.xilinx_hw_server) {
+ YAML::Node config;
+ config["xilinx_hw_server"] = data.xilinx_hw_server.value();
+ out << config << '\n';
+ }
}
}
diff --git a/hwdb4cpp/hwdb4cpp.h b/hwdb4cpp/hwdb4cpp.h
index f3bcbbebbe9fd426d831d03318638d8846d9aaf3..b20b15793ce6be55e0afe475d8f8b81631af1f30 100644
--- a/hwdb4cpp/hwdb4cpp.h
+++ b/hwdb4cpp/hwdb4cpp.h
@@ -90,12 +90,19 @@ namespace hwdb4cpp GENPYBIND_TAG_HWDB {
/// HX cube FPGA sequence entry:
/// - ip: FPGA Ethernet IP
/// - (optional)wing: HXCubeWingEntry corresponding to the FPGA
+/// - (optional)fuse_dna: FPGA FUSE_DNA as provided by Xilinx toolchains, is
+/// required to identify the device in JTAG chain
+/// HX cube FPGA member functions:
+/// - get_dna_port: calculates the FPGA-internal DNA_PORT sequence (which can be
+/// read out from the fabric logic) from the FUSE_DNA
///
/// HX cube setups have a map entry with the keys:
/// - hxcube_id: wafer id = hxcube_id + 60, defining FPGA IP range
/// - fpgas: map of HXCubeFPGAEntries
/// - usb_host: name of host that connects to MSP430 on cube-io
/// - usb_serial: serial code of MSP430 (as string)
+/// - (optional)xilinx_hw_server: hostname/IP and port of xilinx hardware server
+/// (e.g. "xilinx-smartlynq-0:3121")
/* HWDB Entry Types: Structs representing the data in the YAML database */
@@ -197,6 +204,9 @@ struct GENPYBIND(visible) HXCubeFPGAEntry
{
halco::common::IPv4 ip;
std::optional<HXCubeWingEntry> wing;
+ std::optional<uint64_t> fuse_dna;
+
+ uint64_t get_dna_port() const;
};
struct GENPYBIND(visible) HXCubeSetupEntry
@@ -205,6 +215,7 @@ struct GENPYBIND(visible) HXCubeSetupEntry
std::map<size_t, HXCubeFPGAEntry> fpgas;
std::string usb_host;
std::string usb_serial;
+ std::optional<std::string> xilinx_hw_server;
HXCubeSetupEntry()
{
diff --git a/test/test_hwdb4c.cpp b/test/test_hwdb4c.cpp
index 288a8919fad4921f0a746fb0da47810267d28ce9..f5d03d139a240d2f4d836fac46bee705664ec18b 100644
--- a/test/test_hwdb4c.cpp
+++ b/test/test_hwdb4c.cpp
@@ -123,6 +123,7 @@ fpgas:\n\
ldo_version: 2\n\
chip_revision: 42\n\
eeprom_chip_serial: 0x1234ABCD\n\
+ fuse_dna: 0x3A0E92C402882A33\n\
- fpga: 3\n\
ip: 192.168.66.4\n\
handwritten_chip_serial: 69\n\
@@ -132,6 +133,7 @@ fpgas:\n\
ip: 192.168.66.8\n\
usb_host: 'AMTHost11'\n\
usb_serial: 'AFEABC1230456789'\n\
+xilinx_hw_server: 'abc.de:1234'\n\
";
};
@@ -313,20 +315,28 @@ void get_entry_test_impl(hwdb4c_database_t* hwdb)
EXPECT_EQ(std::string(hxcube->usb_serial), "AFEABC1230456789");
EXPECT_EQ(std::string(hxcube->usb_host), "AMTHost11");
EXPECT_EQ(hxcube->num_fpgas, 3);
+ EXPECT_EQ(std::string(hxcube->xilinx_hw_server), "abc.de:1234");
+
EXPECT_EQ(std::string(inet_ntoa(hxcube->fpgas[0]->ip)), "192.168.66.1");
EXPECT_EQ(hxcube->fpgas[0]->fpga_id, 0);
+ EXPECT_EQ(hxcube->fpgas[0]->fuse_dna, 0x3A0E92C402882A33);
+ EXPECT_EQ(hxcube->fpgas[0]->dna_port, 0x5411402349705C);
EXPECT_EQ(hxcube->fpgas[0]->wing->ldo_version, 2);
EXPECT_EQ(hxcube->fpgas[0]->wing->handwritten_chip_serial, 12);
EXPECT_EQ(hxcube->fpgas[0]->wing->chip_revision, 42);
EXPECT_EQ(hxcube->fpgas[0]->wing->eeprom_chip_serial, 0x1234ABCD);
+
EXPECT_EQ(std::string(inet_ntoa(hxcube->fpgas[1]->ip)), "192.168.66.4");
EXPECT_EQ(hxcube->fpgas[1]->fpga_id, 3);
+ EXPECT_TRUE(hxcube->fpgas[1]->fuse_dna == 0); // optional value
EXPECT_EQ(hxcube->fpgas[1]->wing->ldo_version, 1);
EXPECT_EQ(hxcube->fpgas[1]->wing->handwritten_chip_serial, 69);
EXPECT_EQ(hxcube->fpgas[1]->wing->chip_revision, 1);
EXPECT_EQ(hxcube->fpgas[1]->wing->eeprom_chip_serial, 0); // default value
+
EXPECT_EQ(std::string(inet_ntoa(hxcube->fpgas[2]->ip)), "192.168.66.8");
EXPECT_EQ(hxcube->fpgas[2]->fpga_id, 7);
+ EXPECT_TRUE(hxcube->fpgas[2]->fuse_dna == 0); // optional value
EXPECT_TRUE(hxcube->fpgas[2]->wing == NULL); // optional value
hwdb4c_free_hxcube_setup_entry(hxcube);
@@ -439,6 +449,7 @@ TEST_F(HWDB4C_Test, get_yaml_entries)
" ldo_version: 2\n"
" chip_revision: 42\n"
" eeprom_chip_serial: 0x1234ABCD\n"
+ " fuse_dna: 0x3A0E92C402882A33\n"
" - fpga: 3\n"
" ip: 192.168.66.4\n"
" handwritten_chip_serial: 69\n"
@@ -447,7 +458,8 @@ TEST_F(HWDB4C_Test, get_yaml_entries)
" - fpga: 7\n"
" ip: 192.168.66.8\n"
"usb_host: AMTHost11\n"
- "usb_serial: AFEABC1230456789";
+ "usb_serial: AFEABC1230456789\n"
+ "xilinx_hw_server: abc.de:1234";
ASSERT_EQ(yaml_string, test_string);
free(ret);