| // 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_MEMUTIL_OTBN_MEMUTIL_H_ |
| #define OPENTITAN_HW_IP_OTBN_DV_MEMUTIL_OTBN_MEMUTIL_H_ |
| |
| #include <map> |
| #include <svdpi.h> |
| #include <vector> |
| |
| #include "dpi_memutil.h" |
| #include "scrambled_ecc32_mem_area.h" |
| |
| class OtbnMemUtil : public DpiMemUtil { |
| public: |
| typedef std::map<std::pair<uint32_t, uint32_t>, uint32_t> LoopWarps; |
| |
| // Constructor. top_scope is the SV scope that contains IMEM and |
| // DMEM memories as u_imem and u_dmem, respectively. |
| OtbnMemUtil(const std::string &top_scope); |
| |
| // Load an ELF file at the given path and backdoor load it into the |
| // attached memories. |
| // |
| // If something goes wrong, throws a std::exception. |
| void LoadElf(const std::string &elf_path); |
| |
| // Get access to the segments currently staged for imem/dmem |
| const StagedMem::SegMap &GetSegs(bool is_imem) const; |
| |
| // Get access to a memory area |
| const ScrambledEcc32MemArea &GetMemArea(bool is_imem) const { |
| return is_imem ? imem_ : dmem_; |
| } |
| |
| // Get the expected end address, if set. Otherwise returns -1. |
| int GetExpEndAddr() const { return expected_end_addr_; } |
| |
| // Get any loop warp defined at addr with an initial count of |
| // from_cnt. If there is no such warp defined, returns from_cnt. |
| uint32_t GetLoopWarp(uint32_t addr, uint32_t from_cnt) const; |
| |
| // Read-only access to the table of loop warps |
| const LoopWarps &GetLoopWarps() const { return loop_warp_; } |
| |
| private: |
| void OnElfLoaded(Elf *elf_file) override; |
| |
| // Called by OnElfLoaded for each symbol in the symbol table |
| void OnSymbol(const std::string &name, uint32_t value); |
| |
| // Add an entry to loop_warp_ |
| void AddLoopWarp(uint32_t addr, uint32_t from_cnt, uint32_t to_cnt); |
| |
| ScrambledEcc32MemArea imem_, dmem_; |
| int expected_end_addr_; |
| LoopWarps loop_warp_; |
| }; |
| |
| // DPI-accessible wrappers |
| extern "C" { |
| OtbnMemUtil *OtbnMemUtilMake(const char *top_scope); |
| void OtbnMemUtilFree(OtbnMemUtil *mem_util); |
| |
| // Loads an ELF file into memory via the backdoor. Returns 1'b1 on success. |
| // Prints a message to stderr and returns 1'b0 on failure. |
| svBit OtbnMemUtilLoadElf(OtbnMemUtil *mem_util, const char *elf_path); |
| |
| // Loads an ELF file into the OtbnMemUtil object, but doesn't touch the |
| // simulated memory. Returns 1'b1 on success. Prints a message to stderr and |
| // returns 1'b0 on failure. |
| svBit OtbnMemUtilStageElf(OtbnMemUtil *mem_util, const char *elf_path); |
| |
| // Returns the number of segments currently staged in imem/dmem. |
| int OtbnMemUtilGetSegCount(OtbnMemUtil *mem_util, svBit is_imem); |
| |
| // Gets offset and size (both in 32-bit words) for a segment currently staged |
| // in imem/dmem. Both are returned with output arguments. Returns 1'b1 on |
| // success. Prints a message to stderr and returns 1'b0 on failure. |
| svBit OtbnMemUtilGetSegInfo(OtbnMemUtil *mem_util, svBit is_imem, int seg_idx, |
| /* output bit[31:0] */ svBitVecVal *seg_off, |
| /* output bit[31:0] */ svBitVecVal *seg_size); |
| |
| // Gets a word of data from segments currently staged in imem/dmem. If there |
| // is a word at that address, the function writes its value to the output |
| // argument and then returns 1'b1. If there is no word at that address, the |
| // output argument is untouched and the function returns 1'b0. |
| // |
| // If word_off is invalid (negative or enormous), the function writes a |
| // message to stderr and returns 1'b0. |
| svBit OtbnMemUtilGetSegData(OtbnMemUtil *mem_util, svBit is_imem, int word_off, |
| /* output bit[31:0] */ svBitVecVal *data_value); |
| |
| // Get an "expected end address". This is a belt-and-braces check, where the |
| // producer of the ELF file knows what address they expect to finish at (either |
| // an ECALL or a known-bad faulting instruction). They can put this as a magic |
| // symbol in the ELF file and then we check at simulation time that we really |
| // did stop there. |
| // |
| // Note: This functionality doesn't provide any extra check of OTBN itself. |
| // Rather, it's helpful for debugging the random instruction generator, which |
| // is supposed to be able to predict (roughly) what its instruction streams |
| // will do. |
| // |
| // Returns the output address as an integer. A negative result means that no |
| // such address is present in the ELF file. |
| int OtbnMemUtilGetExpEndAddr(OtbnMemUtil *mem_util); |
| |
| // Get a loop warp entry, if there is one. |
| // |
| // Returns 1'b0 if there is no matching entry. On a matching entry, |
| // returns 1'b1 and writes the new count to to_cnt. |
| svBit OtbnMemUtilGetLoopWarp(OtbnMemUtil *mem_util, |
| /* bit [31:0] */ const svBitVecVal *addr, |
| /* bit [31:0] */ const svBitVecVal *from_cnt, |
| /* output bit [31:0] */ svBitVecVal *to_cnt); |
| |
| // Get the number of loop warps |
| int OtbnMemUtilGetNumLoopWarps(OtbnMemUtil *mem_util); |
| |
| // Get a loop warp by index (should be less than returned by |
| // OtbnMemUtilGetNumLoopWarps). |
| void OtbnMemUtilGetLoopWarpByIndex( |
| OtbnMemUtil *mem_util, int idx, |
| /* output bit [31:0] */ svBitVecVal *addr, |
| /* output bit [31:0] */ svBitVecVal *from_cnt, |
| /* output bit [31:0] */ svBitVecVal *to_cnt); |
| } |
| |
| #endif // OPENTITAN_HW_IP_OTBN_DV_MEMUTIL_OTBN_MEMUTIL_H_ |