diff --git a/src/svf_jtag.cpp b/src/svf_jtag.cpp index b7f84e8..da9e76c 100644 --- a/src/svf_jtag.cpp +++ b/src/svf_jtag.cpp @@ -2,12 +2,13 @@ /* * Copyright (C) 2019 Gwenhael Goavec-Merou */ - +#include #include #include #include #include #include +#include #include "jtag.hpp" @@ -18,8 +19,8 @@ using namespace std; void SVF_jtag::split_str(string const &str, vector &vparse) { string token; - std::istringstream tokenStream(str); - while (std::getline(tokenStream, token, ' ')) + istringstream tokenStream(str); + while (getline(tokenStream, token, ' ')) vparse.push_back(token); } @@ -32,21 +33,41 @@ void SVF_jtag::clear_XYR(svf_XYR &t) t.smask.clear(); } +static unsigned char *parse_hex(string const &in, size_t byte_length, bool default_value) +{ + unsigned char *txbuf = new unsigned char[byte_length]; + char c; + int last_iter = ((int)in.size() - (int)(2 * byte_length)); + for (int i = (in.size() - 1), pos = 0; i >= last_iter; i--, pos++) { + if (i < 0) + c = default_value ? 0x0f : 0x00; + else { + if (in[i] <= '9') + c = 0x0f & (in[i] - '0'); + else + c = 0x0f & (in[i] - 'A' + 10); + } + if (!(pos & 1)) + txbuf[pos / 2] = c; + else + txbuf[pos / 2] |= c << 4; + } + return txbuf; +} /* pas clair: - * si length = 0 : tout est remis a zero - * tdi, mask et smask sont memorises. Si pas present c'est la memoire - * qui est utilise - * tdo si absent on s'en fout - * TODO: faut prendre en compte smask, mask and tdo - * ameliorer l'analyse des chaines de caracteres - */ +* si length != previous length : tout est remis a zero +* tdi, mask et smask sont memorises. Si pas present c'est la memoire +* qui est utilise +* tdo si absent on s'en fout +* TODO: ameliorer l'analyse des chaines de caracteres +*/ void SVF_jtag::parse_XYR(vector const &vstr, svf_XYR &t) { - if (_verbose) cout << endl; + if (_verbose) + cout << endl; int mode = 0; string s; - //string tdi; string full_line; full_line.reserve(1276); int write_data = -1; @@ -54,13 +75,15 @@ void SVF_jtag::parse_XYR(vector const &vstr, svf_XYR &t) if (vstr[0][0] == 'S') write_data = ((vstr[0][1] == 'I') ? 0 : 1); - t.len = stoul(vstr[1]); - if (t.len == 0) { + uint32_t new_length = stoul(vstr[1]); + if (new_length != t.len) { clear_XYR(t); - return; } - - for (long unsigned int pos=2; pos < vstr.size(); pos++) { + t.len = new_length; + t.tdo.clear(); + if (t.len == 0) + return; + for (long unsigned int pos = 2; pos < vstr.size(); pos++) { s = vstr[pos]; if (!s.compare("TDO")) { @@ -82,7 +105,7 @@ void SVF_jtag::parse_XYR(vector const &vstr, svf_XYR &t) if (s.front() == '\t') s = s.substr(1); if (s.back() == ')') - s = s.substr(0, s.size()-1); + s = s.substr(0, s.size() - 1); /* faut analyser et convertir le string ici * quand s.back() == ')' @@ -102,77 +125,116 @@ void SVF_jtag::parse_XYR(vector const &vstr, svf_XYR &t) break; case 3: t.mask.clear(); - t.mask= full_line; + t.mask = full_line; break; case 4: t.smask.clear(); - t.smask= full_line; + t.smask = full_line; break; } full_line.clear(); } } if (write_data != -1) { - string txbuf; - int len = t.tdi.size() / 2 + ((t.tdi.size() % 2)? 1 : 0); - txbuf.resize(len); - char c; - for (int i = t.tdi.size()-1, pos = 0; i >= 0; i--, pos++) { - if (t.tdi[i] <= '9') - c = 0x0f & (t.tdi[i] - '0'); - else - c = 0x0f & (t.tdi[i] - 'A' + 10); - - txbuf[pos/2] |= ((0x0F & c) << ((4*(pos & 1)))); + size_t byte_len = (t.len + 7) / 8; + unsigned char *write_buffer = parse_hex(t.tdi, byte_len, 0); + if (!t.smask.empty()) { + unsigned char *smaskbuff = parse_hex(t.smask, byte_len, 0); + for (unsigned int b = 0; b < byte_len; b++) { + write_buffer[b] &= smaskbuff[b]; + } + delete smaskbuff; } - + unsigned char *read_buffer = NULL; + if (!t.tdo.empty()) { + read_buffer = new unsigned char[byte_len]; + read_buffer[byte_len - 1] = 0; // clear the last byte which may not be full; + } else + read_buffer = NULL; if (write_data == 0) - _jtag->shiftIR((unsigned char *)txbuf.c_str(), NULL, t.len, _endir); + _jtag->shiftIR(write_buffer, read_buffer, t.len, _endir); else - _jtag->shiftDR((unsigned char *)txbuf.c_str(), NULL, t.len, _enddr); + _jtag->shiftDR(write_buffer, read_buffer, t.len, _enddr); + if (!t.tdo.empty()) { + unsigned char *tdobuf = parse_hex(t.tdo, byte_len, 0); + unsigned char *maskbuf = parse_hex(t.mask, byte_len, t.mask.empty() ? 1 : 0); + for (size_t i = 0; i < byte_len; i++) { + if ((read_buffer[i] ^ tdobuf[i]) & maskbuf[i]) { + cerr << "TDO value "; + for (int j = byte_len - 1; j >= 0; j--) { + cerr << uppercase << hex << int(read_buffer[j]); + } + cerr << " isn't the one expected: " << uppercase << t.tdo << endl; + throw exception(); + } + } + delete tdobuf; + delete maskbuf; + } + delete write_buffer; + delete read_buffer; } } /* Implementation partielle de la spec */ void SVF_jtag::parse_runtest(vector const &vstr) { - int pos = 1; + unsigned int pos = 1; int nb_iter = 0; int run_state = -1; int end_state = -1; -// 0 => RUNTEST -// 1 => Ca depend - if (vstr[pos][0] > '9') { + double min_duration = -1; + // 0 => RUNTEST + // 1 => Ca depend + if (isalpha(vstr[pos][0])) { run_state = fsm_state[vstr[1]]; pos++; } - nb_iter = atoi(vstr[pos].c_str()); // duree mais attention ca peut etre un xxeyy - pos++; - pos++; // clk currently don't care - if (!vstr[pos].compare("ENDSTATE")) { + if (!vstr[pos + 1].compare("SEC")) { + min_duration = atof(vstr[pos].c_str()); pos++; - end_state = fsm_state[vstr[pos]]; + pos++; + } else { + nb_iter = atoi(vstr[pos].c_str()); + pos++; + pos++; // run_clk field, ignored. + if (((pos + 1) < vstr.size()) && + (!vstr[pos + 1].compare("SEC"))) { + min_duration = atof(vstr[pos].c_str()); + pos++; + pos++; + } } - - if (run_state != -1) { + auto res = find(begin(vstr) + pos, end(vstr), "ENDSTATE"); + if (res != end(vstr)) + { + res++; + end_state = fsm_state[*res]; + } + if (run_state != -1) + { _run_state = run_state; } - if (end_state != -1) { + if (end_state != -1) + { _end_state = end_state; } else if (run_state != -1) _end_state = run_state; _jtag->set_state(_run_state); _jtag->toggleClk(nb_iter); + if (min_duration > 0 ) { + usleep((useconds_t)(min_duration * 1.0E6)); + } _jtag->set_state(_end_state); -} + } void SVF_jtag::handle_instruction(vector const &vstr) { if (!vstr[0].compare("FREQUENCY")) { _freq_hz = atof(vstr[1].c_str()); if (_verbose) { - cout << "frequence valeur " << vstr[1] << " unite " << vstr[2]; + cout << "frequency value " << vstr[1] << " unit " << vstr[2]; cout << _freq_hz << endl; } _jtag->setClkFreq(_freq_hz); @@ -191,6 +253,9 @@ void SVF_jtag::handle_instruction(vector const &vstr) parse_runtest(vstr); } else if (!vstr[0].compare("HIR")) { parse_XYR(vstr, hir); + if (hir.len > 0) { + cerr << "HIR length supported is only 0 " << endl; + } if (_verbose) { cout << "HIR" << endl; cout << "\tlen : " << hir.len << endl; @@ -201,6 +266,9 @@ void SVF_jtag::handle_instruction(vector const &vstr) } } else if (!vstr[0].compare("HDR")) { parse_XYR(vstr, hdr); + if (hdr.len > 0 ) { + cerr << "HDR length supported is only 0" << endl; + } if (_verbose) { cout << "HDR" << endl; cout << "\tlen : " << hdr.len << endl; @@ -231,8 +299,35 @@ void SVF_jtag::handle_instruction(vector const &vstr) cout << "\tmask : " << sdr.mask.size()*4 << endl; cout << "\tsmask : " << sdr.smask.size()*4 << endl; } + } else if (!vstr[0].compare("TDR")) { + parse_XYR(vstr, tdr); + if (tdr.len > 0) { + cerr << "TDR length supported is only 0" << endl; + } + if (_verbose) { + cout << "TDR" << endl; + cout << "\tlen : " << tdr.len << endl; + cout << "\ttdo : " << tdr.tdo.size() * 4 << endl; + cout << "\ttdi : " << tdr.tdi.size() * 4 << endl; + cout << "\tmask : " << tdr.mask.size() * 4 << endl; + cout << "\tsmask : " << tdr.smask.size() * 4 << endl; + } + } else if (!vstr[0].compare("TIR")) { + parse_XYR(vstr, tir); + if (tir.len > 0) { + cerr << "TIR length supported is only 0" << endl; + } + if (_verbose) { + cout << "TIR" << endl; + cout << "\tlen : " << tir.len << endl; + cout << "\ttdo : " << tir.tdo.size() * 4 << endl; + cout << "\ttdi : " << tir.tdi.size() * 4 << endl; + cout << "\tmask : " << tir.mask.size() * 4 << endl; + cout << "\tsmask : " << tir.smask.size() * 4 << endl; + } } else { - cout << "error: unhandled instruction : " << vstr[0] << endl; + cout << "error: unhandled instruction " << vstr[0] << endl; + throw exception(); } } @@ -247,6 +342,9 @@ SVF_jtag::SVF_jtag(Jtag *jtag, bool verbose):_verbose(verbose), _freq_hz(0), SVF_jtag::~SVF_jtag() {} +bool is_space (char x) { + return !!isspace(x); +} /* Read SVF file line by line * concat continuous lines * and pass instruction to handle_instruction @@ -260,38 +358,45 @@ void SVF_jtag::parse(string filename) fs.open(filename); if (!fs.is_open()) { - cerr << "error to opening svf file " << filename << endl; + cerr << "Error opening svf file " << filename << endl; return; } - - while (getline(fs, str)) { - /* sanity check: DOS CR */ - if (str.back() == '\r') - str.pop_back(); - - is_complete = false; - if (str[0] == '!') // comment - continue; - if (str.back() == ';') { - str.pop_back(); - is_complete = true; - } - - split_str(str, vstr); - if (is_complete) { - if (_verbose) { - if (vstr[0].compare("HDR") && vstr[0].compare("HIR") - && vstr[0].compare("SDR") && vstr[0].compare("SIR")) { - for (auto &&word: vstr) - cout << word << " "; - cout << endl; - } + unsigned int lineno = 0; + try { + while (getline(fs, str)) { + /* sanity check: DOS CR */ + if (str.back() == '\r') + str.pop_back(); + lineno++; + is_complete = false; + if (str[0] == '!') // comment + continue; + if (str.back() == ';') { + str.pop_back(); + is_complete = true; + } + replace_if(begin(str), end(str), is_space, ' '); + split_str(str, vstr); + if (is_complete) { + if (_verbose) { + if (vstr[0].compare("HDR") && vstr[0].compare("HIR") + && vstr[0].compare("SDR") && vstr[0].compare("SIR")) { + for (auto &&word: vstr) + cout << word << " "; + cout << endl; + } + } + handle_instruction(vstr); + vstr.clear(); } - handle_instruction(vstr); - vstr.clear(); } } + catch (exception &e) + { + cerr << "Cannot proceed because of error(s) at line " << lineno << endl; + throw; + } - cout << "end of flash" << endl; + cout << "end of SVF file" << endl; }