blob: a41aae996e99b9c728de23c1d8239232e6667178 [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_DV_VERILATOR_CPP_DPI_MEMUTIL_H_
#define OPENTITAN_HW_DV_VERILATOR_CPP_DPI_MEMUTIL_H_
#include <map>
#include <memory>
#include <string>
#include <svdpi.h>
#include <vector>
#include "mem_area.h"
#include "ranged_map.h"
// Forward declaration for the Elf type from libelf.
struct Elf;
enum MemImageType {
kMemImageUnknown = 0,
kMemImageElf,
kMemImageVmem,
};
// Staged data for a given memory area.
//
// This is represented as an ordered list of disjoint segments (as loaded from
// an ELF file).
//
// Once it is nonempty, the class maintains the invariant that min_addr_ /
// max_addr_ is the smallest / largest byte offset with valid data.
class StagedMem {
public:
StagedMem() : min_addr_(~(uint32_t)0), max_addr_(0) {}
// Add a segment to the tracked memory
void AddSegment(uint32_t offset, std::vector<uint8_t> &&seg);
// Glob together the tracked segments, interspersing them with
// zeros, and return as a single flat array.
std::vector<uint8_t> GetFlat() const;
typedef RangedMap<uint32_t, std::vector<uint8_t>> SegMap;
std::pair<uint32_t, uint32_t> GetBounds() const {
return std::make_pair(min_addr_, max_addr_);
}
const SegMap &GetSegs() const { return segs_; }
private:
uint32_t min_addr_, max_addr_;
SegMap segs_;
};
/**
* Provide various memory loading utilities for verilog simulations
*
* These utilities require the corresponding DPI functions:
* simutil_memload()
* simutil_set_mem()
* to be defined somewhere as SystemVerilog functions.
*/
class DpiMemUtil {
public:
virtual ~DpiMemUtil() {}
/**
* Register a memory as instantiated by generic ram
*
* The |name| must be a unique identifier. The constructor will
* throw a std::runtime_error if |name| is already used.
*
* |base| gives the base address of the memory in a logical address
* space that corresponds to LMAs in an ELF file. If this overlaps
* with some other registered memory, the constructor throws a
* std::runtime_error.
*
* The |mem_area| argument describes the memory area to be registered and
* must not be null. This function does not take ownership of the object,
* which must survive at least as long as the DpiMemutil object.
*
* Memories must be registered before command arguments are parsed by
* ParseCommandArgs() in order for them to be known.
*/
void RegisterMemoryArea(const std::string &name, uint32_t base,
const MemArea *mem_area);
/**
* Guess the type of the file at |path|.
*
* If |type| is non-null, it is the name of an image type and will be used.
* Otherwise, the check is based on |path|. If |type| is not a valid name or
* if the function can't guess from the path, throws a std::runtime_error
* with a message about what went wrong.
*
* Never returns kMemImageUnknown.
*/
static MemImageType GetMemImageType(const std::string &path,
const char *type);
/**
* Print a list of all registered memory regions
*
* @see RegisterMemoryArea()
*/
void PrintMemRegions() const;
/**
* Load the file at filepath into the named memory. If type is
* kMemImageUnknown, the file type is determined from the path.
*/
void LoadFileToNamedMem(bool verbose, const std::string &name,
const std::string &filepath, MemImageType type);
/**
* Load an ELF file, placing segments in memories by LMA.
*
* Replaces any data currently in the staging area.
*/
void LoadElfToMemories(bool verbose, const std::string &filepath);
/**
* Load an ELF file into a staging area in this object, which can then be
* accessed with GetMemoryData().
*
* If the load fails, raises a std::exception with information about what
* happened.
*/
void StageElf(bool verbose, const std::string &path);
/**
* Get the contents of the staging area by memory name
*/
const StagedMem &GetMemoryData(const std::string &mem_name) const;
protected:
/**
* A hook for subclasses to do extra computations with loaded ELF data. This
* runs as part of StageElf: after loading the ELF file, but before reading
* in the segments.
*/
virtual void OnElfLoaded(Elf *elf_file) {}
private:
// Memory area registry. The maps give indices pointing into the vectors
// (which all have the same number of elements). Note that mem_areas_ does
// not own the objects that it points to.
std::vector<const MemArea *> mem_areas_;
std::vector<uint32_t> base_addrs_;
std::vector<std::string> names_;
std::map<std::string, size_t> name_to_mem_;
RangedMap<uint32_t, size_t> addr_to_mem_;
// Staging area, loaded by StageElf. The map is keyed by names of memories
// stored in name_to_mem_. We also ensure that every segment in a StagedMem
// for a memory starts at an address that's aligned for the word width of
// that memory. Note: we don't also check segments' lengths are aligned.
std::map<std::string, StagedMem> staging_area_;
const StagedMem empty_;
/**
* Find the index of a memory area containing the given segment's addresses.
* Raises a std::exception if none is found.
*/
size_t GetRegionForSegment(const std::string &path, int seg_idx, uint32_t lma,
uint32_t mem_sz) const;
};
#endif // OPENTITAN_HW_DV_VERILATOR_CPP_DPI_MEMUTIL_H_