blob: 74f4eb3db19664a7c17fad44c766eae78110b1b6 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "otbn_trace_entry.h"
#include <algorithm>
#include <cassert>
#include <iostream>
#include <regex>
#include <sstream>
void OtbnTraceEntry::from_rtl_trace(const std::string &trace) {
size_t eol = trace.find('\n');
hdr_ = trace.substr(0, eol);
while (eol != std::string::npos) {
size_t bol = eol + 1;
eol = trace.find('\n', bol);
size_t line_len =
(eol == std::string::npos) ? std::string::npos : eol - bol;
std::string line = trace.substr(bol, line_len);
if (line.size() > 0 && line[0] == '>')
writes_.push_back(line);
}
std::sort(writes_.begin(), writes_.end());
}
bool OtbnTraceEntry::operator==(const OtbnTraceEntry &other) const {
return hdr_ == other.hdr_ && writes_ == other.writes_;
}
void OtbnTraceEntry::print(const std::string &indent, std::ostream &os) const {
os << indent << hdr_ << "\n";
for (const std::string &write : writes_) {
os << indent << write << "\n";
}
}
void OtbnTraceEntry::take_writes(const OtbnTraceEntry &other) {
if (!other.writes_.empty()) {
for (const std::string &write : other.writes_) {
writes_.push_back(write);
}
std::sort(writes_.begin(), writes_.end());
}
}
bool OtbnTraceEntry::empty() const { return hdr_.empty(); }
bool OtbnTraceEntry::is_stall() const { return !empty() && hdr_[0] == 'S'; }
bool OtbnTraceEntry::is_exec() const { return !empty() && hdr_[0] == 'E'; }
bool OtbnTraceEntry::is_compatible(const OtbnTraceEntry &prev) const {
return 0 ==
hdr_.compare(1, std::string::npos, prev.hdr_, 1, std::string::npos);
}
bool OtbnIssTraceEntry::from_iss_trace(const std::vector<std::string> &lines) {
// Read FSM. state 0 = read header; state 1 = read mnemonic (for E
// lines); state 2 = read writes
int state = 0;
std::regex re("# @0x([0-9a-f]{8}): (.*)");
std::smatch match;
for (const std::string &line : lines) {
switch (state) {
case 0:
hdr_ = line;
state = (!line.empty() && line[0] == 'E') ? 1 : 2;
break;
case 1:
// This some "special" extra data from the ISS that we use for
// functional coverage calculations. The line should be of the form
//
// # @ADDR: MNEMONIC
//
// where ADDR is an 8-digit instruction address (in hex) and mnemonic
// is the string mnemonic.
if (!std::regex_match(line, match, re)) {
std::cerr << "Bad 'special' line for ISS trace with header `" << hdr_
<< "': `" << line << "'.\n";
return false;
}
assert(match.size() == 3);
data_.insn_addr =
(uint32_t)strtoul(match[1].str().c_str(), nullptr, 16);
data_.mnemonic = match[2].str();
state = 2;
break;
default: {
assert(state == 2);
// Ignore '!' lines (which are used to tell the simulation about
// external register changes, not tracked by the RTL core simulation)
bool is_bang = (line.size() > 0 && line[0] == '!');
if (!is_bang) {
writes_.push_back(line);
}
break;
}
}
}
// We shouldn't be in state 1 here: that would mean an E line with no
// follow-up '#' line.
if (state == 1) {
std::cerr << "No 'special' line for ISS trace with header `" << hdr_
<< "'.\n";
return false;
}
std::sort(writes_.begin(), writes_.end());
return true;
}