An alternative for $readmemh

I have a RISC-V based system that has separate instruction and data memory. The firmware calls an objcopy on the .elf to generate a .vh which is ready to be parsed by $readmemh.

If I have a single memory I could have simply used the following:

// NOTE: the buffer size is twice as big as the memory
// as we need to hold both instruction and data
bit [DW-1:0] buf [2*MEM_SIZE-1:0];
$readmemh("myfile", buf);
for (int i=0; i<2*MEM_SIZE; i++) begin
  mem.write(buf[i]); // where mem is a uvm_mem object
end

I have two issues though:

  1. the file might only have few bytes that are necessary, the .text and .data sections plus some other ones are not going to cover the full memory. So loading irrespective of what is useful is a waste of resources (especially if doing front door access)
  2. As I have two such memories, I would need somehow to divvy up the buffer and only go through half of it for the instruction memory and the other half for the data memory.

Both problems are very annoying. Ideally I only want to load what’s necessary and leave the rest of the memory unitialized or randomly initialized. And secondly I’d like to write in the two memories separately, also because it is not uncommon to have different access type for data and instruction, which makes things complicated when you have your ECC working on different widths.

I thought about parsing the file myself but wondered if there was no better idea than through time at the problem.
Thanks a lot for any pointer.

I think I’ve found a solution to my original problems, and it’s not about a different $readmemh implementation.

The main idea behind my solution is that I first create a memory buffer, apply an encoding scheme of some sort (to avoid random matches) and then store a copy of it.

When the buf then gets filled with the $readmem() only a portion of it will be overwritten, while the rest of the locations will match with my second copy. At that point I can use the difference between the buf and the copy as an indicator for a change and I know I only need to write those ones in memory.

So something like this:

class myseq extends uvm_sequence;
// boiler-plate code
  rand bit [CODEWORD-1:0] membuf[MEMSIZE-1:0];
  rand bit [CODEWORD-1:0] refbuf[MEMSIZE-1:0];

virtual task body();
  
  // here *codec* is a class that performs some encoding algo
  foreach(refbuf[i]) begin
    refbuf[i] = codec.encode(refbuf[i]);
    membuf[i] = refbuf[i];
  end

  // here only locations specified in the file will be modified
  $readmemh(myfile, membuf);

  // write to mem only locations that are different then our ref.
  foreach(membuf[i]) begin
    if (membuf[i] != refbuf[i]) begin
      mem.write(membuf[i]);
    end
  end

endtask

Some may argue that an encoding scheme may not be necessary, but I believe it drastically reduces the chances of one of the content from the file to match with one of the initially randomized content of refbuf.

Feel free to comment.