blob: 713863c1dda52858bc43e1220acf25eb9ab58cbe [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#ifndef OPENTITAN_HW_IP_OTBN_DV_MODEL_ISS_WRAPPER_H_
#define OPENTITAN_HW_IP_OTBN_DV_MODEL_ISS_WRAPPER_H_
#include <array>
#include <cstdint>
#include <cstdio>
#include <memory>
#include <string>
#include <unistd.h>
#include <vector>
// Forward declaration (the implementation is private in iss_wrapper.cc)
struct TmpDir;
// OTBN has some externally visible CSRs that can be updated by hardware
// (without explicit writes from software). The ISSWrapper mirrors the ISS's
// versions of these registers in this structure.
class MirroredRegs {
public:
MirroredRegs() : status(0), insn_cnt(0), err_bits(0), stop_pc(0) {}
uint32_t status;
uint32_t insn_cnt;
uint32_t err_bits;
// The final PC from the most recent run
uint32_t stop_pc;
};
// An object wrapping the ISS subprocess.
struct ISSWrapper {
// A 256-bit unsigned integer value, stored in "LSB order". Thus, words[0]
// contains the LSB and words[7] contains the MSB.
struct u256_t {
uint32_t words[256 / 32];
};
ISSWrapper();
~ISSWrapper();
// Load new contents of DMEM / IMEM
void load_d(const std::string &path);
void load_i(const std::string &path);
// Add a loop warp instruction to the simulation
void add_loop_warp(uint32_t addr, uint32_t from_cnt, uint32_t to_cnt);
// Clear any loop warp instructions from the simulation
void clear_loop_warps();
// Dump the contents of DMEM to a file
void dump_d(const std::string &path) const;
// Jump to address zero and start running
void start();
// Provide data for RND. ISS will stall when RND is read and RND data isn't
// available
void edn_rnd_data(uint32_t edn_rnd_data[8]);
// Signal URND reseed at beginning of execution is complete
void edn_urnd_reseed_complete();
// Run simulation for a single cycle.
//
// If gen_trace is true, pass trace data to the (singleton) OtbnTraceChecker
// object.
//
// The return code describes the state of the simulation. It is 1 if the
// simulation just stopped (on ECALL or an architectural error); it is 0 if
// the simulation is still running. It is -1 if something went wrong (such as
// a trace mismatch).
//
// Updates mirrored versions of STATUS and INSN_CNT registers. If execution
// finishes (so we return 1), also updates mirrored versions of ERR_BITS and
// the final PC (see get_stop_pc()).
int step(bool gen_trace);
// Reset simulation
//
// This doesn't actually send anything to the ISS, but instead tells the
// OtbnTraceChecker to clear out any partial instructions. It also resets
// mirrored registers to their initial states.
void reset(bool gen_trace);
const MirroredRegs &get_mirrored() const { return mirrored_; }
// Read contents of the register file
void get_regs(std::array<uint32_t, 32> *gprs, std::array<u256_t, 32> *wdrs);
// Read the contents of the call stack
std::vector<uint32_t> get_call_stack();
// Resolve a path relative to the convenience temporary directory.
// relative should be a relative path (it is just appended to the
// path of the temporary directory).
std::string make_tmp_path(const std::string &relative) const;
private:
// Read line by line from the child process until we get ".\n".
// Return true if we got the ".\n" terminator, false if EOF. If dst
// is not null, append to it each line that was read.
bool read_child_response(std::vector<std::string> *dst) const;
// Send a command to the child and wait for its response. If no
// response, raise a runtime_error.
void run_command(const std::string &cmd, std::vector<std::string> *dst) const;
pid_t child_pid;
FILE *child_write_file;
FILE *child_read_file;
// A temporary directory for communicating with the child process
std::unique_ptr<TmpDir> tmpdir;
// Mirrored copies of registers
MirroredRegs mirrored_;
};
#endif // OPENTITAN_HW_IP_OTBN_DV_MODEL_ISS_WRAPPER_H_