0

I am trying to declare a 1MB memory model using an array in Verilog in ModelSim using the code below. I also need to have the address 0x80020000 within the address space.

parameter MEM_START = 32'h7FFA_0000;
parameter MEM_END = 32'h800A_0000;
reg [7:0] MEMORY [MEM_START:MEM_END];

The above code compiles fine but it gives the following error when I try to simulate it:

# Loading project.memoryModule
# ** Fatal: (vsim-3419) Array with element size 2 and index range 2147090432 downto -2146828288 is too large.
#    Time: 0 ns  Iteration: 0  Instance: Project/memoryModule.v
# FATAL ERROR while loading design
# Error loading design

However, if I initialize the memory indices from 7FEF_FFFF to 7FFF_FFFF, which should also be 1 MB, everything is fine and I can see the allocated memory in the simulation. If I modify the range from 7FEF_FFFF to 8000_0000, I now get an internal data size overflow during compilation. Why does the end range of the memory appear as -2146828288 (FFFF FFFF 800A 0000) in the error (2's complement)?

All the examples I've seen online show smaller memories, i.e. 256 words so reg [7:0] MEMORY [0:255]) so I'm not sure if there is a problem in my logic or if the issue is related to the HW on my machine. I'm using the 32 bit version of Modelsim & have 4 GB of RAM.

Qiu
  • 5,651
  • 10
  • 49
  • 56
terfex
  • 1
  • 2
  • 3
  • 4
    Do you really want to generate 4GB of memory? You're probably overloading your simulator. Do you have 64 bit machine and 6+ gb of ram available? – Tim May 16 '12 at 04:39
  • I think VCS can use sparse memories via attributes. Not sure about Modelsim. –  May 16 '12 at 05:07

2 Answers2

3

Each entry in that array will be two bytes, as each bit can be 0, 1, Z or X. The array is 0x80020000 entries, which is 2147614720 entries in decimal.

2 * 2147614720 is 4295229440 which is 4 + a bit gigabytes on one array.

Believe me, you don't want to do this. Even just writing a single value to all those locations would take a huge amount of simulation time.

If you're in SystemVerilog then use a associative array with the address as the index. This will only use memory for the locations that have something stored in them. Otherwise I suggest you wrap your memory in something which moves a smaller array into the right part of your address space.

Paul S
  • 7,645
  • 2
  • 24
  • 36
  • Thanks for your response. I realized my mistake regarding the size of the memory. I've modified my code but still get an error when trying to have the specified address (0x8002000) inside a 1MB model of memory. Please see my updated question above. – terfex May 16 '12 at 15:45
  • @terfex: It's interpreting the 0x80.... value as a signed value, and saying it's negative because the top bit is set. Try `parameter unsigned` – Paul S May 17 '12 at 10:15
1

At first this looked like a bug, but maybe not. Array indices are treated as constant integer expressions.

The expressions that specify the indices of the array shall be constant integer expressions. The value of the constant expression can be a positive integer, a negative integer, or zero.

The spec is also very clear about constant integers, and that they are different than variable integers.

Simple decimal numbers without the size and the base format shall be treated as signed integers, whereas the numbers specified with the base format shall be treated as signed integers if the s designator is included or as unsigned integers if the base format only is used.

However that parameter is forced to be an integer type(even though it's constant), which are always signed. This is kind of implied in the spec.

A parameter declaration with no type or range specification shall default to the type and range of the final value assigned to the parameter, after any value overrides have been applied.

If you run a sim and print out some arithmetic results using MEM_END it will probably act as a 32-bit signed value. The message you see is certainly consistent with MEM_END being signed. Personally I would never use offset array indices in this way.


To fix this there are several things you could try:

  • Use the unsigned function:

    reg [7:0] MEMORY [$unsigned(MEM_START):$unsigned(MEM_END)];
  • If you need a 1MB range, you could use 0x8000_0000..0x8010_0000 and then ignore the MSBs in the index.

  • If you need to test across the MSB of the address, you could apply an offset inside your memory model.

  • Use a 64-bit version of Modelsim.

  • Use `define to avoid the parameter, although not ideal since defines are global and parameters are scoped.

    `define MEM_START 32'h7FFA_0000;
    `define MEM_END   32'h800A_0000; 
    reg [7:0] MEMORY [`MEM_START:`MEM_END];

It's hard to answer this without knowing exactly what you're trying to do.

Greg
  • 18,111
  • 5
  • 46
  • 68
  • Hi Adam, thanks for your response and help. As you said, during my debugging I've realized that MEM_END is being interpreted as a signed integer during the indexing which causes the error. However, can you perhaps recommend a better approach to this problem? For the requirements of my project, I need to have a 1 MB memory that contains the address 0x8002_0000 within the address space. – terfex May 16 '12 at 21:07