Skip to content

Commit

Permalink
Improve robustness of ecppack JED file generator. Allow NOTEs to be g…
Browse files Browse the repository at this point in the history
…enerated.
  • Loading branch information
cr1901 committed Sep 8, 2023
1 parent c84aae2 commit 839f9f5
Showing 1 changed file with 56 additions and 12 deletions.
68 changes: 56 additions & 12 deletions libtrellis/tools/ecppack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,33 @@ uint16_t calc_checksum(std::string bytes)
}

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

int num_digits(uint32_t num) {
int count = 0;
do {
num /= 10;
count++;
} while(num != 0);

return count;
}

int main(int argc, char *argv[])
{
using namespace Trellis;
Expand All @@ -68,6 +86,7 @@ int main(int argc, char *argv[])
options.add_options()("svf", po::value<std::string>(), "output SVF file");
options.add_options()("svf-rowsize", po::value<int>(), "SVF row size in bits (default 8000)");
options.add_options()("jed", po::value<std::string>(), "output JED file");
options.add_options()("jed-note", po::value<vector<std::string>>(), "emit NOTE field in JED file");
options.add_options()("compress", "compress bitstream to reduce size");
options.add_options()("spimode", po::value<std::string>(), "SPI Mode to use (fast-read, dual-spi, qspi)");
options.add_options()("background", "enable background reconfiguration in bitstream");
Expand Down Expand Up @@ -377,8 +396,15 @@ int main(int argc, char *argv[])

jed_file << "\x02*" << endl; // STX plus "design specification" (not filled in).
full_checksum += calc_checksum("\x02*\n");
// jed_file << "\x03" << hex << uppercase << setw(4) << full_checksum << endl;
// return 0;

if (vm.count("jed-note")) {
ostringstream note_field;
for(auto &n: vm["jed-note"].as<vector<string>>()) {
note_field << "NOTE " << n << "*" << endl;
full_checksum += calc_checksum(note_field.str());
jed_file << note_field.str();
}
}

ostringstream fusecnt_field;
uint32_t fusecnt;
Expand All @@ -389,6 +415,7 @@ int main(int argc, char *argv[])
return 1;
}

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

// The JEDEC spec says leading 0s are optional. My own experience is
// that some programmers require leading 0s.
ostringstream list_field;
list_field << "L" << setw(num_digits(fusecnt)) << setfill('0') << 0 << endl;
full_checksum += calc_checksum(list_field.str());
jed_file << list_field.str();

// Strip the leading comment- it wastes precious fuse space and
// some programmers (e.g STEP-MXO2) even rely on the preamble being
// the first bytes.
vector<uint8_t> preamble = {0xFF, 0xFF, 0xBD, 0xB3, 0xFF, 0xFF };
auto start_iter = search(begin(bitstream), end(bitstream), begin(preamble), end(preamble));

if(start_iter == end(bitstream)) {
cerr << "Could not extract preamble from bitstream" << endl;
return 1;
}

auto start_offs = start_iter - bitstream.begin();

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

for (unsigned int j = 0; j < len; j++) {
uint8_t byte = uint8_t(bitstream[j + i]);
uint8_t byte = uint8_t(bitstream[j + i + start_offs]);
checksum += reverse_byte(byte);
full_checksum += calc_checksum(std::bitset<8>{byte}.to_string());
full_checksum += calc_checksum(bitset<8>{byte}.to_string());
jed_file << std::bitset<8>{byte};
}

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

ostringstream oss;
oss << "C" << hex << uppercase << setfill('0') << setw(4) << checksum << '*' << endl;
full_checksum += calc_checksum(oss.str());
jed_file << oss.str();
ostringstream checksum_field;
checksum_field << "C" << hex << uppercase << setfill('0') << setw(4) << checksum << '*' << endl;
full_checksum += calc_checksum(checksum_field.str());
jed_file << checksum_field.str();

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

0 comments on commit 839f9f5

Please sign in to comment.