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);