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:
ADDRL
exception though I actually used a store instruction -- not load?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.
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.