Skip to content

Commit 839f9f5

Browse files
committed
Improve robustness of ecppack JED file generator. Allow NOTEs to be generated.
1 parent c84aae2 commit 839f9f5

File tree

1 file changed

+56
-12
lines changed

1 file changed

+56
-12
lines changed

libtrellis/tools/ecppack.cpp

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,33 @@ uint16_t calc_checksum(std::string bytes)
4242
}
4343

4444
uint32_t get_num_config_fuses(Trellis::ChipInfo &ci) {
45-
if(ci.name == "LCMXO2-4000") {
45+
if(ci.name == "LCMXO2-256") {
46+
return (575 + 0 + 1)*128; // No UFM, 1 dummy page at end.
47+
} else if(ci.name == "LCMXO2-640") {
48+
return (1151 + 191 + 1)*128; // UFM is 0 bytes after end of CFG, 1 dummy page at end.
49+
} else if(ci.name == "LCMXO2-1200" || ci.name == "LCMXO2-640U") {
50+
return (2175 + 511 + 1)*128; // UFM is 0 bytes after end of CFG, 1 dummy page at end.
51+
} else if(ci.name == "LCMXO2-2000" || ci.name == "LCMXO2-1200U") {
52+
return (3198 + 639 + 1)*128; // UFM is 0 bytes after end of CFG, 1 dummy page at end.
53+
} else if(ci.name == "LCMXO2-4000" || ci.name == "LCMXO2-2000U") {
4654
return (5758 + 767 + 1)*128; // UFM is 0 bytes after end of CFG, 1 dummy page at end.
47-
} if(ci.name == "LCMXO2-7000") {
55+
} else if(ci.name == "LCMXO2-7000") {
4856
return (9211 + 1 + 2046 + 2)*128; // UFM is 16 bytes after end of CFG, 2 dummy pages at end.
4957
} else {
5058
throw runtime_error(fmt("Can not extract number of config fuses from FPGA family " << ci.name));
5159
}
5260
}
5361

62+
int num_digits(uint32_t num) {
63+
int count = 0;
64+
do {
65+
num /= 10;
66+
count++;
67+
} while(num != 0);
68+
69+
return count;
70+
}
71+
5472
int main(int argc, char *argv[])
5573
{
5674
using namespace Trellis;
@@ -68,6 +86,7 @@ int main(int argc, char *argv[])
6886
options.add_options()("svf", po::value<std::string>(), "output SVF file");
6987
options.add_options()("svf-rowsize", po::value<int>(), "SVF row size in bits (default 8000)");
7088
options.add_options()("jed", po::value<std::string>(), "output JED file");
89+
options.add_options()("jed-note", po::value<vector<std::string>>(), "emit NOTE field in JED file");
7190
options.add_options()("compress", "compress bitstream to reduce size");
7291
options.add_options()("spimode", po::value<std::string>(), "SPI Mode to use (fast-read, dual-spi, qspi)");
7392
options.add_options()("background", "enable background reconfiguration in bitstream");
@@ -377,8 +396,15 @@ int main(int argc, char *argv[])
377396

378397
jed_file << "\x02*" << endl; // STX plus "design specification" (not filled in).
379398
full_checksum += calc_checksum("\x02*\n");
380-
// jed_file << "\x03" << hex << uppercase << setw(4) << full_checksum << endl;
381-
// return 0;
399+
400+
if (vm.count("jed-note")) {
401+
ostringstream note_field;
402+
for(auto &n: vm["jed-note"].as<vector<string>>()) {
403+
note_field << "NOTE " << n << "*" << endl;
404+
full_checksum += calc_checksum(note_field.str());
405+
jed_file << note_field.str();
406+
}
407+
}
382408

383409
ostringstream fusecnt_field;
384410
uint32_t fusecnt;
@@ -389,6 +415,7 @@ int main(int argc, char *argv[])
389415
return 1;
390416
}
391417

418+
// TODO: QP (package information not implied in textual representation).
392419
fusecnt_field << "QF" << fusecnt << '*' << endl;
393420
full_checksum += calc_checksum(fusecnt_field.str());
394421
jed_file << fusecnt_field.str();
@@ -397,19 +424,36 @@ int main(int argc, char *argv[])
397424
full_checksum += calc_checksum("G0*\n");
398425
jed_file << "F0*" << endl; // Default fuse value.
399426
full_checksum += calc_checksum("F0*\n");
400-
jed_file << "L0" << endl;
401-
full_checksum += calc_checksum("L0\n");
402427

428+
// The JEDEC spec says leading 0s are optional. My own experience is
429+
// that some programmers require leading 0s.
430+
ostringstream list_field;
431+
list_field << "L" << setw(num_digits(fusecnt)) << setfill('0') << 0 << endl;
432+
full_checksum += calc_checksum(list_field.str());
433+
jed_file << list_field.str();
434+
435+
// Strip the leading comment- it wastes precious fuse space and
436+
// some programmers (e.g STEP-MXO2) even rely on the preamble being
437+
// the first bytes.
438+
vector<uint8_t> preamble = {0xFF, 0xFF, 0xBD, 0xB3, 0xFF, 0xFF };
439+
auto start_iter = search(begin(bitstream), end(bitstream), begin(preamble), end(preamble));
440+
441+
if(start_iter == end(bitstream)) {
442+
cerr << "Could not extract preamble from bitstream" << endl;
443+
return 1;
444+
}
445+
446+
auto start_offs = start_iter - bitstream.begin();
403447

404448
size_t i = 0;
405449
while(i < fusecnt/8) {
406450
if(i < bitstream.size()) {
407451
size_t len = min(size_t(16), bitstream.size() - i);
408452

409453
for (unsigned int j = 0; j < len; j++) {
410-
uint8_t byte = uint8_t(bitstream[j + i]);
454+
uint8_t byte = uint8_t(bitstream[j + i + start_offs]);
411455
checksum += reverse_byte(byte);
412-
full_checksum += calc_checksum(std::bitset<8>{byte}.to_string());
456+
full_checksum += calc_checksum(bitset<8>{byte}.to_string());
413457
jed_file << std::bitset<8>{byte};
414458
}
415459

@@ -442,10 +486,10 @@ int main(int argc, char *argv[])
442486
jed_file << "*" << endl;
443487
full_checksum += calc_checksum("*\n");
444488

445-
ostringstream oss;
446-
oss << "C" << hex << uppercase << setfill('0') << setw(4) << checksum << '*' << endl;
447-
full_checksum += calc_checksum(oss.str());
448-
jed_file << oss.str();
489+
ostringstream checksum_field;
490+
checksum_field << "C" << hex << uppercase << setfill('0') << setw(4) << checksum << '*' << endl;
491+
full_checksum += calc_checksum(checksum_field.str());
492+
jed_file << checksum_field.str();
449493

450494
full_checksum += calc_checksum("\x03");
451495
jed_file << "\x03" << hex << uppercase << setw(4) << setfill('0') << full_checksum << endl;

0 commit comments

Comments
 (0)