assemblymipsmars-simulator

Why did the MARS MIPS Simulator throws a "Load from an Illegal Address" exception?


I created a simple, recursive factorial() function which calls a recursive multiplication function called mul_alt() whenever it evaluates n * factorial(n-1). So instead of return n * factorial(n-1) (in C notation), the factorial() function executes return mul_alt(n, factorial(n-1)), where the called function would add n + n + ... factorial(n-1) times. I made this convoluted program since my class demands so.

The program works fine for n <= 9, but when I tried n > 9, the program would return an exception at n = 10 with the following values of the coprocessor 0:

$8 (vaddr) = 0x7fbffffc
$12 (status) = 0x0000ff13
$13 (cause) = 0x00000014
$14 (epc) = 0x0040008c

From the first two bits of the status register, I learned that the exception handler returned an ADDRL exception which means loading from an illegal address. And the epc register shows the address of the instruction which caused the error, which is

0x0040008c: sw $s1, 4($sp)

and the value of my $sp register is 0x7fbffff8. So 0x7fbffff8 + 0x4 = 0x7fbffffc (which is the value stored in vaddr) is where store instruction tried to store the contents of $s1. I have a few questions regarding this situation:

  1. Why did I get an ADDRL exception though I actually used a store instruction -- not load?
  2. 0x7fbffffc is divisible by 4, so why am I not allowed to store word-sized data in there?

I hope I have stated my point clear. Thank you in advance.


Solution

  • MIPS cause 0x14 is an ADDRS not an ADDRL. ExcCode = 0x14/4 = 5: ADDRS

    This is a simple stack overflow.  The MARS stack can go to 0x7fc00000, so allows for about 4M bytes.


    // from the default memory configuration menu selection
    public static int stackPointer = MemoryConfigurations.getDefaultStackPointer(); //0x7fffeffc;
    public static int stackBaseAddress = MemoryConfigurations.getDefaultStackBaseAddress(); //0x7ffffffc;
    public static int stackLimitAddress = stackBaseAddress - BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES;
    //                          where these constants are 1024, 1024, and 4 respectively
    

    The default values (from the default memory configuration) are 0x7ffffffc (stackBase), 0x7fffeffc (stackPointer), 0x7fc00000 (stackLimitAddress).

    There is no menu option to increase the stack space beyond 4MB.

    There is a menu for memory configuration, but it incorrectly reports stack limit as the same value as heap base for all available configurations.  This isn't the case: the stack limit is always stack base - 4MB, according to the source code.

    The memory addresses between heap base address and stack limit address are protected unless you expand the heap using sbrk system call.  There is no expanding the stack further.


    SPIM on the other hand, appears to expand the stack space as needed, but only when you modify the stack pointer register, rather than when storing into memory below the stack pointer.  Thus in SPIM, if you modify the stack pointer register to a random value, it will immediately fail to expand the stack space (without doing a store or load) even if you put the stack pointer back where it was before loading or storing relative to that register — odd behavior indeed but it seems they treat the $sp register specially rather than how the hardware would do it.