XADC and DNA for Xilinx FPGA (#407)
* xilinx: add XADC and DNA args, see https://github.com/cfib/openFPGALoaderXADC/tree/XADC_3 parts: add xcku060 * doc: add xcku060
This commit is contained in:
parent
b119a955a6
commit
234f7f5a35
|
|
@ -229,6 +229,7 @@ Xilinx:
|
||||||
Model:
|
Model:
|
||||||
- xcku035
|
- xcku035
|
||||||
- xcku040
|
- xcku040
|
||||||
|
- xcku060
|
||||||
- xcku115
|
- xcku115
|
||||||
URL: https://www.xilinx.com/products/silicon-devices/fpga/kintex-ultrascale.html#productTable
|
URL: https://www.xilinx.com/products/silicon-devices/fpga/kintex-ultrascale.html#productTable
|
||||||
Memory: OK
|
Memory: OK
|
||||||
|
|
|
||||||
16
src/main.cpp
16
src/main.cpp
|
|
@ -92,6 +92,8 @@ struct arguments {
|
||||||
string mcufw;
|
string mcufw;
|
||||||
bool conmcu;
|
bool conmcu;
|
||||||
std::map<uint32_t, misc_device> user_misc_devs;
|
std::map<uint32_t, misc_device> user_misc_devs;
|
||||||
|
bool read_dna;
|
||||||
|
bool read_xadc;
|
||||||
};
|
};
|
||||||
|
|
||||||
int run_xvc_server(const struct arguments &args, const cable_t &cable,
|
int run_xvc_server(const struct arguments &args, const cable_t &cable,
|
||||||
|
|
@ -120,7 +122,8 @@ int main(int argc, char **argv)
|
||||||
"127.0.0.1", 0, false, false, "", false, false,
|
"127.0.0.1", 0, false, false, "", false, false,
|
||||||
/* xvc server */
|
/* xvc server */
|
||||||
false, 3721, "-",
|
false, 3721, "-",
|
||||||
"", false, {} // mcufw conmcu, user_misc_dev_list
|
"", false, {}, // mcufw conmcu, user_misc_dev_list
|
||||||
|
false, false // read_dna, read_xadc
|
||||||
};
|
};
|
||||||
/* parse arguments */
|
/* parse arguments */
|
||||||
try {
|
try {
|
||||||
|
|
@ -557,7 +560,8 @@ int main(int argc, char **argv)
|
||||||
if (fab == "xilinx") {
|
if (fab == "xilinx") {
|
||||||
fpga = new Xilinx(jtag, args.bit_file, args.secondary_bit_file,
|
fpga = new Xilinx(jtag, args.bit_file, args.secondary_bit_file,
|
||||||
args.file_type, args.prg_type, args.fpga_part, args.bridge_path,
|
args.file_type, args.prg_type, args.fpga_part, args.bridge_path,
|
||||||
args.target_flash, args.verify, args.verbose, args.skip_load_bridge, args.skip_reset);
|
args.target_flash, args.verify, args.verbose, args.skip_load_bridge, args.skip_reset,
|
||||||
|
args.read_dna, args.read_xadc);
|
||||||
} else if (fab == "altera") {
|
} else if (fab == "altera") {
|
||||||
fpga = new Altera(jtag, args.bit_file, args.file_type,
|
fpga = new Altera(jtag, args.bit_file, args.file_type,
|
||||||
args.prg_type, args.fpga_part, args.bridge_path, args.verify,
|
args.prg_type, args.fpga_part, args.bridge_path, args.verify,
|
||||||
|
|
@ -822,6 +826,10 @@ int parse_opt(int argc, char **argv, struct arguments *args,
|
||||||
cxxopts::value<std::string>(args->mcufw))
|
cxxopts::value<std::string>(args->mcufw))
|
||||||
("conmcu", "Connect JTAG to MCU",
|
("conmcu", "Connect JTAG to MCU",
|
||||||
cxxopts::value<bool>(args->conmcu))
|
cxxopts::value<bool>(args->conmcu))
|
||||||
|
("D,read_dna", "Read DNA (Xilinx FPGA only)",
|
||||||
|
cxxopts::value<bool>(args->read_dna))
|
||||||
|
("X,read_xadc", "Read XADC (Xilinx FPGA only)",
|
||||||
|
cxxopts::value<bool>(args->read_xadc))
|
||||||
("V,Version", "Print program version");
|
("V,Version", "Print program version");
|
||||||
|
|
||||||
options.parse_positional({"bitstream"});
|
options.parse_positional({"bitstream"});
|
||||||
|
|
@ -1012,7 +1020,9 @@ int parse_opt(int argc, char **argv, struct arguments *args,
|
||||||
!args->bulk_erase_flash &&
|
!args->bulk_erase_flash &&
|
||||||
!args->xvc &&
|
!args->xvc &&
|
||||||
!args->reset &&
|
!args->reset &&
|
||||||
!args->conmcu) {
|
!args->conmcu &&
|
||||||
|
!args->read_dna &&
|
||||||
|
!args->read_xadc) {
|
||||||
printError("Error: bitfile not specified");
|
printError("Error: bitfile not specified");
|
||||||
cout << options.help() << endl;
|
cout << options.help() << endl;
|
||||||
throw std::exception();
|
throw std::exception();
|
||||||
|
|
|
||||||
|
|
@ -86,8 +86,9 @@ static std::map <uint32_t, fpga_model> fpga_list = {
|
||||||
{0x03736093, {"xilinx", "zynq", "xc7z100", 6}},
|
{0x03736093, {"xilinx", "zynq", "xc7z100", 6}},
|
||||||
|
|
||||||
/* Xilinx Ultrascale / Kintex */
|
/* Xilinx Ultrascale / Kintex */
|
||||||
{0x13822093, {"xilinx", "kintexus", "xcku040", 6}},
|
|
||||||
{0x13823093, {"xilinx", "kintexus", "xcku035", 6}},
|
{0x13823093, {"xilinx", "kintexus", "xcku035", 6}},
|
||||||
|
{0x13822093, {"xilinx", "kintexus", "xcku040", 6}},
|
||||||
|
{0x13919093, {"xilinx", "kintexus", "xcku060", 6}},
|
||||||
{0x1390d093, {"xilinx", "kintexus", "xcku115", 6}},
|
{0x1390d093, {"xilinx", "kintexus", "xcku115", 6}},
|
||||||
|
|
||||||
/* Xilinx Ultrascale+ / Artix */
|
/* Xilinx Ultrascale+ / Artix */
|
||||||
|
|
|
||||||
184
src/xilinx.cpp
184
src/xilinx.cpp
|
|
@ -53,6 +53,74 @@
|
||||||
#define XC95_ISC_PROGRAM 0xea
|
#define XC95_ISC_PROGRAM 0xea
|
||||||
#define XC95_ISC_READ 0xee
|
#define XC95_ISC_READ 0xee
|
||||||
|
|
||||||
|
/* DRP instructions set */
|
||||||
|
#define XADC_DRP 0x37
|
||||||
|
|
||||||
|
/* XADC Addresses */
|
||||||
|
#define XADC_TEMP 0x00
|
||||||
|
#define XADC_LOCK 0x00
|
||||||
|
#define XADC_VCCINT 0x01
|
||||||
|
#define XADC_VCCAUX 0x02
|
||||||
|
#define XADC_VAUXEN 0x02
|
||||||
|
#define XADC_VPVN 0x03
|
||||||
|
#define XADC_RESET 0x03
|
||||||
|
#define XADC_VREFP 0x04
|
||||||
|
#define XADC_VREFN 0x05
|
||||||
|
#define XADC_VCCBRAM 0x06
|
||||||
|
#define XADC_SUPAOFFS 0x08
|
||||||
|
#define XADC_ADCAOFFS 0x09
|
||||||
|
#define XADC_ADCAGAIN 0x0a
|
||||||
|
#define XADC_VCCPINT 0x0d
|
||||||
|
#define XADC_VCCPAUX 0x0e
|
||||||
|
#define XADC_VCCODDR 0x0f
|
||||||
|
#define XADC_VAUX0 0x10
|
||||||
|
#define XADC_VAUX1 0x11
|
||||||
|
#define XADC_VAUX2 0x12
|
||||||
|
#define XADC_VAUX3 0x13
|
||||||
|
#define XADC_VAUX4 0x14
|
||||||
|
#define XADC_VAUX5 0x15
|
||||||
|
#define XADC_VAUX6 0x16
|
||||||
|
#define XADC_VAUX7 0x17
|
||||||
|
#define XADC_VAUX8 0x18
|
||||||
|
#define XADC_VAUX9 0x19
|
||||||
|
#define XADC_VAUX10 0x1a
|
||||||
|
#define XADC_VAUX11 0x1b
|
||||||
|
#define XADC_VAUX12 0x1c
|
||||||
|
#define XADC_VAUX13 0x1d
|
||||||
|
#define XADC_VAUX14 0x1e
|
||||||
|
#define XADC_VAUX15 0x1f
|
||||||
|
#define XADC_SUPBOFFS 0x30
|
||||||
|
#define XADC_ADCBOFFS 0x31
|
||||||
|
#define XADC_ADCBGAIN 0x32
|
||||||
|
#define XADC_FLAG 0x3f
|
||||||
|
#define XADC_CFG0 0x40
|
||||||
|
#define XADC_CFG1 0x41
|
||||||
|
#define XADC_CFG2 0x42
|
||||||
|
#define XADC_SEQ0 0x48
|
||||||
|
#define XADC_SEQ1 0x49
|
||||||
|
#define XADC_SEQ2 0x4a
|
||||||
|
#define XADC_SEQ3 0x4b
|
||||||
|
#define XADC_SEQ4 0x4c
|
||||||
|
#define XADC_SEQ5 0x4d
|
||||||
|
#define XADC_SEQ6 0x4e
|
||||||
|
#define XADC_SEQ7 0x4f
|
||||||
|
#define XADC_ALARM0 0x50
|
||||||
|
#define XADC_ALARM1 0x51
|
||||||
|
#define XADC_ALARM2 0x52
|
||||||
|
#define XADC_ALARM3 0x53
|
||||||
|
#define XADC_ALARM4 0x54
|
||||||
|
#define XADC_ALARM5 0x55
|
||||||
|
#define XADC_ALARM6 0x56
|
||||||
|
#define XADC_ALARM7 0x57
|
||||||
|
#define XADC_ALARM8 0x58
|
||||||
|
#define XADC_ALARM9 0x59
|
||||||
|
#define XADC_ALARM10 0x5a
|
||||||
|
#define XADC_ALARM11 0x5b
|
||||||
|
#define XADC_ALARM12 0x5c
|
||||||
|
#define XADC_ALARM13 0x5d
|
||||||
|
#define XADC_ALARM14 0x5e
|
||||||
|
#define XADC_ALARM15 0x5f
|
||||||
|
|
||||||
/* Boundary-scan instruction set based on the FPGA model */
|
/* Boundary-scan instruction set based on the FPGA model */
|
||||||
static std::map<std::string, std::map<std::string, std::vector<uint8_t>>>
|
static std::map<std::string, std::map<std::string, std::vector<uint8_t>>>
|
||||||
ircode_mapping {
|
ircode_mapping {
|
||||||
|
|
@ -125,6 +193,69 @@ static void open_bitfile(
|
||||||
printSuccess("DONE");
|
printSuccess("DONE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FUSE_DNA 0x32
|
||||||
|
|
||||||
|
unsigned long long Xilinx::fuse_dna_read(void)
|
||||||
|
{
|
||||||
|
unsigned char tx_data[8] = {0,0,0,0,0,0,0,0};
|
||||||
|
unsigned char rx_data[8];
|
||||||
|
|
||||||
|
_jtag->go_test_logic_reset();
|
||||||
|
_jtag->shiftIR(FUSE_DNA, 6);
|
||||||
|
_jtag->shiftDR((unsigned char *)&tx_data, (unsigned char *)&rx_data, 64);
|
||||||
|
|
||||||
|
unsigned long long dna = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < 8; i++) {
|
||||||
|
unsigned char rev = 0;
|
||||||
|
for (int j = 0; j < 8; j++) {
|
||||||
|
rev |= ((rx_data[i]>>j)&1)<<(7-j);
|
||||||
|
}
|
||||||
|
dna = (dna << 8ULL) | rev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dna & 0x1ffffffffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Xilinx::xadc_read(unsigned short addr)
|
||||||
|
{
|
||||||
|
unsigned int tx_data = (1 << 26) | (addr << 16);
|
||||||
|
unsigned int rx_data = 0;
|
||||||
|
|
||||||
|
_jtag->go_test_logic_reset();
|
||||||
|
_jtag->shiftIR(XADC_DRP, 6);
|
||||||
|
_jtag->shiftDR((unsigned char *)&tx_data, (unsigned char *)&rx_data, 32);
|
||||||
|
usleep(1000);
|
||||||
|
_jtag->shiftIR(XADC_DRP, 6);
|
||||||
|
_jtag->shiftDR((unsigned char *)&tx_data, (unsigned char *)&rx_data, 32);
|
||||||
|
|
||||||
|
return rx_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Xilinx::xadc_write(unsigned short addr, unsigned short data)
|
||||||
|
{
|
||||||
|
unsigned int tx_data = (1 << 26) | (addr << 16) | data;
|
||||||
|
unsigned int rx_data = 0;
|
||||||
|
|
||||||
|
_jtag->go_test_logic_reset();
|
||||||
|
_jtag->shiftIR(XADC_DRP, 6);
|
||||||
|
_jtag->shiftDR((unsigned char *)&tx_data, (unsigned char *)&rx_data, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Xilinx::xadc_single(unsigned short ch)
|
||||||
|
{
|
||||||
|
_jtag->go_test_logic_reset();
|
||||||
|
// single channel, disable the sequencer
|
||||||
|
xadc_write(XADC_CFG1,0x3000);
|
||||||
|
// set channel, no averaging, additional settling time
|
||||||
|
xadc_write(XADC_CFG0,(1<<15) | (1<<8) | ch);
|
||||||
|
// leave some time (1ms) for the conversion
|
||||||
|
usleep(1000);
|
||||||
|
unsigned int ret = xadc_read(ch);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
Xilinx::Xilinx(Jtag *jtag, const std::string &filename,
|
Xilinx::Xilinx(Jtag *jtag, const std::string &filename,
|
||||||
const std::string &secondary_filename,
|
const std::string &secondary_filename,
|
||||||
const std::string &file_type,
|
const std::string &file_type,
|
||||||
|
|
@ -132,7 +263,7 @@ Xilinx::Xilinx(Jtag *jtag, const std::string &filename,
|
||||||
const std::string &device_package, const std::string &spiOverJtagPath,
|
const std::string &device_package, const std::string &spiOverJtagPath,
|
||||||
const std::string &target_flash,
|
const std::string &target_flash,
|
||||||
bool verify, int8_t verbose,
|
bool verify, int8_t verbose,
|
||||||
bool skip_load_bridge, bool skip_reset):
|
bool skip_load_bridge, bool skip_reset, bool read_dna, bool read_xadc):
|
||||||
Device(jtag, filename, file_type, verify, verbose),
|
Device(jtag, filename, file_type, verify, verbose),
|
||||||
SPIInterface(filename, verbose, 256, verify, skip_load_bridge,
|
SPIInterface(filename, verbose, 256, verify, skip_load_bridge,
|
||||||
skip_reset),
|
skip_reset),
|
||||||
|
|
@ -251,6 +382,57 @@ Xilinx::Xilinx(Jtag *jtag, const std::string &filename,
|
||||||
} else {
|
} else {
|
||||||
_fpga_family = UNKNOWN_FAMILY;
|
_fpga_family = UNKNOWN_FAMILY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (read_dna) {
|
||||||
|
if (_fpga_family == ARTIX_FAMILY || _fpga_family == KINTEXUS_FAMILY) {
|
||||||
|
unsigned long long dna = Xilinx::fuse_dna_read();
|
||||||
|
printf("{\"dna\": \"0x%016lx\"}\n", dna);
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Error: read_xadc only supported for Artix 7");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read_xadc) {
|
||||||
|
if (_fpga_family == ARTIX_FAMILY || _fpga_family == KINTEXUS_FAMILY) {
|
||||||
|
// calibrate XADC
|
||||||
|
Xilinx::xadc_single(8);
|
||||||
|
|
||||||
|
const int MAX_CHANNEL = 8;
|
||||||
|
const int TEMP_MEAS = 4;
|
||||||
|
|
||||||
|
unsigned int v = 0;
|
||||||
|
for (int i = 0; i < TEMP_MEAS; i++) {
|
||||||
|
v += Xilinx::xadc_single(0);
|
||||||
|
}
|
||||||
|
double temp = ((v/(double)TEMP_MEAS) * 503.975)/(1 << 16) - 273.15;
|
||||||
|
|
||||||
|
unsigned int channel_values[32];
|
||||||
|
for (int ch = 0; ch < MAX_CHANNEL; ch++) {
|
||||||
|
if (ch < 7 || ch > 12) {
|
||||||
|
v = Xilinx::xadc_single(ch);
|
||||||
|
} else {
|
||||||
|
// 7 = Invalid channel selection
|
||||||
|
// 8 = Carry out XADC calibration
|
||||||
|
// 9...12 = Invalid channel selection
|
||||||
|
v = 0;
|
||||||
|
}
|
||||||
|
channel_values[ch] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* output as JSON dict */
|
||||||
|
std::cout << "{";
|
||||||
|
std::cout << "\"temp\": " << temp << ", ";
|
||||||
|
std::cout << "\"raw\": {";
|
||||||
|
for (int ch = 0; ch < MAX_CHANNEL; ch++) {
|
||||||
|
std::cout << "\"" << ch << "\": " << channel_values[ch]
|
||||||
|
<< ((ch==MAX_CHANNEL-1)? "}" : ", ");
|
||||||
|
}
|
||||||
|
std::cout << "}" << std::endl;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Error: read_xadc only supported for Artix 7");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Xilinx::~Xilinx() {}
|
Xilinx::~Xilinx() {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ class Xilinx: public Device, SPIInterface {
|
||||||
const std::string &spiOverJtagPath,
|
const std::string &spiOverJtagPath,
|
||||||
const std::string &target_flash,
|
const std::string &target_flash,
|
||||||
bool verify, int8_t verbose,
|
bool verify, int8_t verbose,
|
||||||
bool skip_load_bridge, bool skip_reset);
|
bool skip_load_bridge, bool skip_reset,
|
||||||
|
bool read_dna, bool read_xadc);
|
||||||
~Xilinx();
|
~Xilinx();
|
||||||
|
|
||||||
void program(unsigned int offset, bool unprotect_flash) override;
|
void program(unsigned int offset, bool unprotect_flash) override;
|
||||||
|
|
@ -191,6 +192,14 @@ class Xilinx: public Device, SPIInterface {
|
||||||
SECONDARY_FLASH = 0x2
|
SECONDARY_FLASH = 0x2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* XADC */
|
||||||
|
unsigned int xadc_read(unsigned short addr);
|
||||||
|
void xadc_write(unsigned short addr, unsigned short data);
|
||||||
|
unsigned int xadc_single(unsigned short ch);
|
||||||
|
|
||||||
|
/* DNA */
|
||||||
|
unsigned long long fuse_dna_read(void);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Starting from UltraScale, Xilinx devices can support dual
|
* \brief Starting from UltraScale, Xilinx devices can support dual
|
||||||
* QSPI flash configuration, with two different flash chips
|
* QSPI flash configuration, with two different flash chips
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue