Skip to content

khadiwala/Spim-Hacking

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

/* Spim Modifcations for CS296 fa10
   By: Ravi Khadiwala, Netid: khadiwa1 */

MODIFICATIONS:
    f_start/f_end:
    Checks at runtime whether a function violates calling conventions
    Exits the program with error message if it does.

    k_start/k_end:
    Checks at runtime whether the kernel section violates calling conventions
    Exits the program with error message if it does.

    assert statements:
    Checks a boolean register-register or register-constant expression
    If it is false, the program exits, otherwise execution continues
    
    C functions (ccall):
    Allows MIPS programs to execute arbitrary C functions, uses $a0-3 as parameters
    The (integer) return value of the function is written to $v0
    
USAGE:
    f_start/f_end:
    Put #@ f_start on its own line at either the beginning of a function 
    or before a function call, put #@ f_end at the end of function (before
    the return) or after a function call. NOTE: because memory must be allocated
    for every f_start, using f_start on recursive functions is slow/limited.
    
    k_start/k_end:
    Put #@ k_start on its own line at the beginning of the kernel segment, and put
    #@ k_end on its own line at the end of the kernel segment.

    assert statements:
    The left operand should be a register and the right can be a register or an int. 
    Prepend the expression with #@, supported operators are ==, !=, <, <=, >, >=
    Ex: 
        li  $t0, 3
        #@  $t0 == 3

    C functions (ccall):
    The functions are defined with the following syntax: #@ cfunc "function name"
    "string containing C function". Note these are actual string literals. As
    a result, any double quotes you'd like to use must be escaped with a '\'. 
    The opening quote of the C function must be on the same line as #@ cfunc. The 
    function can then be called with the line #@ ccall "function name". The C
    functions must be defined before they are ccall-ed in the code. The C function
    prototype must return an integer and take 4 integer arguments.
    Ex:
        #@ cfunc "my_func" "
        int my_func(int a0, int a1, int a2, int a3){
            int x = a1 - a3;
            printf(\"string within string \");
            //do some work
            return x;
        } "
        main:
            li  $a0, 3
            li  $a1, 5
            #@ ccall "my_func"
            #do stuff with $v0
            jr  $ra

IMPLEMENTATION DETAILS/LIMITS:
    All changes are marked with "CS296", changes are in parser.y, scanner.l,
    run.c, op.h

    f_start/f_end:
    Parser inserts a 'fstart instruction' into run file, code is in run.c,
    this instruction is mapped to f_start in op.h, likewise with f_end. Every 
    f_start mallocs 10 integers, and a corresponding f_end frees them. As a result
    an arbitrary limit of 500 nested function calls is placed on f_start to prevent
    heap overflow.

    k_start/k_end:
    Parser inserts a 'kstart instruction' into run file, code is in run.c,
    this instruction is mapped to k_start in op.h, likewise with k_end.

    assert statements:
    These are implemented in the parsing stage by inserting instructions into the
    run file. There is some sort of weird variable length branching bug which is 
    resolved by overshooting the branch and an additional no-op instruction.

    C functions (ccall):
    When the parser catches the cfunc macro, it writes a full C program with
    the user written function to a temporary file. The C program writes the result
    of the function call to a different temporary file. The C program file is
    compiled into an executable named cfunc#, where # is an index for user written
    c functions. The file is compiled with a fork/exec/block gcc call.
    The function name is stored in an array of function names. When ccall is called 
    we search the array of function names and then insert an i-type instruction 
    into the run file that passes the index of the function so we know what 
    executable to call. Then we do another fork/exec/block to run the function, and
    read the file the program writes to for the return value. Then the return value
    is written to $v0.

About

Modifications to SPIM for debugging and prototyping

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published