[memutils] Add support for > 32b memories

Pack > 32bit memory loads into wider RAM instances. Fixes #790

Signed-off-by: Tom Roberts <tomroberts@lowrisc.org>
This commit is contained in:
Tom Roberts 2020-04-17 11:21:19 +01:00 committed by Tom Roberts
parent b4e5d91842
commit dc8ba83de4
3 changed files with 46 additions and 16 deletions

View file

@ -31,12 +31,22 @@ extern void simutil_verilator_memload(const char *file);
*
* @return 1 if successful, 0 otherwise
*/
extern int simutil_verilator_set_mem(int index, const svLogicVecVal *val);
extern int simutil_verilator_set_mem(int index, const svBitVecVal *val);
}
bool VerilatorMemUtil::RegisterMemoryArea(const std::string name,
const std::string location) {
MemArea mem = {.name = name, .location = location};
// Default to 32bit width
return RegisterMemoryArea(name, location, 32);
}
bool VerilatorMemUtil::RegisterMemoryArea(const std::string name,
const std::string location,
size_t width_bit) {
MemArea mem = {.name = name, .location = location, .width_bit = width_bit};
assert((width_bit == 32 || width_bit == 64) &&
"TODO: Check if width other than 32 and 64 works as expected.");
auto ret = mem_register_.emplace(name, mem);
if (ret.second == false) {
@ -130,8 +140,9 @@ bool VerilatorMemUtil::ParseCLIArguments(int argc, char **argv,
void VerilatorMemUtil::PrintMemRegions() const {
std::cout << "Registered memory regions:" << std::endl;
for (const auto &m : mem_register_) {
std::cout << "\t'" << m.second.name << "' at location: '"
<< m.second.location << "'" << std::endl;
std::cout << "\t'" << m.second.name << "' (" << m.second.width_bit
<< "bits) at location: '" << m.second.location << "'"
<< std::endl;
}
}
@ -386,9 +397,17 @@ bool VerilatorMemUtil::MemWrite(const MemArea &m, const std::string &filepath,
return false;
}
if ((m.width_bit % 32) != 0) {
std::cerr << "ERROR: width for: " << m.name
<< "must be a multiple of 32 (was : " << m.width_bit << ")"
<< std::endl;
return false;
}
size_t size_byte = m.width_bit / 8;
switch (type) {
case kMemImageElf:
if (!WriteElfToMem(scope, filepath)) {
if (!WriteElfToMem(scope, filepath, size_byte)) {
std::cerr << "ERROR: Writing ELF file to memory \"" << m.name << "\" ("
<< m.location << ") failed." << std::endl;
return false;
@ -410,7 +429,8 @@ bool VerilatorMemUtil::MemWrite(const MemArea &m, const std::string &filepath,
}
bool VerilatorMemUtil::WriteElfToMem(const svScope &scope,
const std::string &filepath) {
const std::string &filepath,
size_t size_byte) {
bool retcode;
svScope prev_scope = svSetScope(scope);
@ -422,9 +442,9 @@ bool VerilatorMemUtil::WriteElfToMem(const svScope &scope,
retcode = false;
goto ret;
}
for (int i = 0; i < (len_bytes + 3) / 4; ++i) {
if (!simutil_verilator_set_mem(i, (svLogicVecVal *)&buf[4 * i])) {
std::cerr << "ERROR: Could not set memory byte: " << i * 4 << "/"
for (int i = 0; i < (len_bytes + size_byte - 1) / size_byte; ++i) {
if (!simutil_verilator_set_mem(i, (svBitVecVal *)&buf[size_byte * i])) {
std::cerr << "ERROR: Could not set memory byte: " << i * size_byte << "/"
<< len_bytes << "" << std::endl;
retcode = false;

View file

@ -21,6 +21,7 @@ enum MemImageType {
struct MemArea {
std::string name; // Unique identifier
std::string location; // Design scope location
size_t width_bit; // Memory width
};
/**
@ -41,10 +42,18 @@ class VerilatorMemUtil : public SimCtrlExtension {
* instantiated memory, which needs to support the DPI-C interfaces
* 'simutil_verilator_memload' and 'simutil_verilator_set_mem' used for
* 'vmem' and 'elf' files, respectively.
* The |width_bit| argument specifies the with in bits of the target memory
* instance (used for packing data).
*
* Memories must be registered before command arguments are parsed by
* ParseCommandArgs() in order for them to be known.
*/
bool RegisterMemoryArea(const std::string name, const std::string location,
size_t width_bit);
/**
* Register a memory with default width (32bits)
*/
bool RegisterMemoryArea(const std::string name, const std::string location);
/**
@ -98,7 +107,8 @@ class VerilatorMemUtil : public SimCtrlExtension {
MemImageType type);
bool MemWrite(const MemArea &m, const std::string &filepath,
MemImageType type);
bool WriteElfToMem(const svScope &scope, const std::string &filepath);
bool WriteElfToMem(const svScope &scope, const std::string &filepath,
size_t size_byte);
bool WriteVmemToMem(const svScope &scope, const std::string &filepath);
};

View file

@ -71,16 +71,16 @@ module prim_generic_ram_1p #(
$readmemh(file, mem);
endtask
// TODO: Allow 'val' to have other widths than 32 bit
// Width must be a multiple of 32bit for this function to work
// Note that the DPI export and function definition must both be in the same generate
// context to get the correct name.
if (Width == 32) begin : gen_32bit
// Function for setting a specific 32 bit element in |mem|
if ((Width % 32) == 0) begin : gen_set_mem
// Function for setting a specific element in |mem|
// Returns 1 (true) for success, 0 (false) for errors.
export "DPI-C" function simutil_verilator_set_mem;
function int simutil_verilator_set_mem(input int index,
input logic[31:0] val);
input bit [Width-1:0] val);
if (index >= Depth) begin
return 0;
end
@ -89,11 +89,11 @@ module prim_generic_ram_1p #(
return 1;
endfunction
end else begin : gen_other
// Function doesn't work for Width != 32 so just return 0
// Function doesn't work unless Width % 32 so just return 0
export "DPI-C" function simutil_verilator_set_mem;
function int simutil_verilator_set_mem(input int index,
input logic[31:0] val);
input bit [Width-1:0] val);
return 0;
endfunction
end