Close

Further Compiler Enhancements

A project log for SPAM-1 - 8 Bit CPU

8 Bit CPU with simulator and toolchain and a hardware build to follow

John LonerganJohn Lonergan 12/05/2020 at 06:230 Comments

I need to be able to return values from functions. So I had to make a change.

I could have used a "return" statement, but decided instead to extend the function arguments to include "inout" parameters instead.

This allows me to return zero or more value from a function call by marking the relevant params as "out". Technically are "inout" when marked in this manner.

Below I pass 'A' into the call tree and the value is incremented in the function 'depth2' changing it to a 'B'; which we expect to be printed once control returns to the main function.

fun depth2(b1 out) {
 var b1 = b1 + 1;
}

fun depth1(a1 out) {
 depth2(a1)
}

fun main() {
 var arg1 = 'A';
 depth1(arg1)
 putchar(arg1)
}


The Assembler is shown below. 

Everything wth a ';' is a comment so there are 36 instructions to implement the above program.

The "EQU" block defined constants for the addresses in RAM for temporary values and for function arguments and also variables used in the program.

The names of these constants map to the static path in the program where the variable can be found.

No stack is used at the moment so all calls and return addresses are recorded in RAM variables allocated to each function. What this aproach means is that the execution is fast at the expense of not being able to safely have functions called recursuvely; ie no "reentrant" functions. 

If I retain this calling convention as the default and call it the "variable" calling conventions, then I can introduce a second calling convention called "stack" for those few cases where reentrant functions are needed. The function declaration would signal when it wants one or the other.     

       root_function_depth2___VAR_RETURN_HI: EQU 0
       root_function_depth2___VAR_RETURN_LO: EQU 1
       root_function_depth2___VAR_b1: EQU 2
       root_function_depth1___VAR_RETURN_HI: EQU 3
       root_function_depth1___VAR_RETURN_LO: EQU 4
       root_function_depth1___VAR_a1: EQU 5
       root_function_depth1___VAR_blkExprs2: EQU 6
       root_function_main___VAR_RETURN_HI: EQU 7
       root_function_main___VAR_RETURN_LO: EQU 8
       root_function_main___VAR_arg1: EQU 9
       root_function_main___VAR_blkExprs2: EQU 10
    0  PCHITMP = < :ROOT________main_start
    1  PC = > :ROOT________main_start
       ; (0) ENTER root_function_depth2 @ function
             root_function_depth2___LABEL_START:
             ; (1)  ENTER root_function_depth2 @ statementEqVarOpConst
    2               REGA = [:root_function_depth2___VAR_b1]
    3               REGA = REGA + 1
    4               [:root_function_depth2___VAR_b1] = REGA
             ; (1)  EXIT  root_function_depth2 @ statementEqVarOpConst
    5        PCHITMP = [:root_function_depth2___VAR_RETURN_HI]
    6        PC = [:root_function_depth2___VAR_RETURN_LO]
       ; (0) EXIT  root_function_depth2 @ function
       ; (0) ENTER root_function_depth1 @ function
             root_function_depth1___LABEL_START:
             ; (1)  ENTER root_function_depth1 @ functionCall
                    ; (2)   ENTER root_function_depth1 @ blkExprs
                            ; (3)    ENTER root_function_depth1 @ blkVar
    7                                REGA = [:root_function_depth1___VAR_a1]
                            ; (3)    EXIT  root_function_depth1 @ blkVar
                            ; assign clause 1 result to [:root_function_depth1___VAR_blkExprs2] = a1 
    8                       [:root_function_depth1___VAR_blkExprs2] = REGA
                            ; assigning result back to REGA
    9                       REGA = [:root_function_depth1___VAR_blkExprs2]
                    ; (2)   EXIT  root_function_depth1 @ blkExprs
   10               [:root_function_depth2___VAR_b1] = REGA
                    ; set return address variables
   11               [:root_function_depth2___VAR_RETURN_HI] = < :root_function_depth1___LABEL_RETURN_1
   12               [:root_function_depth2___VAR_RETURN_LO] = > :root_function_depth1___LABEL_RETURN_1
                    ; do jump to function 'depth2''
   13               PCHITMP = < :root_function_depth2___LABEL_START
   14               PC = > :root_function_depth2___LABEL_START
                    ; return location
                    root_function_depth1___LABEL_RETURN_1:
   15               REGA = [:root_function_depth2___VAR_b1]
   16               [:root_function_depth1___VAR_a1] = REGA
             ; (1)  EXIT  root_function_depth1 @ functionCall
   17        PCHITMP = [:root_function_depth1___VAR_RETURN_HI]
   18        PC = [:root_function_depth1___VAR_RETURN_LO]
       ; (0) EXIT  root_function_depth1 @ function
       ; (0) ENTER root_function_main @ function
             ROOT________main_start:
             root_function_main___LABEL_START:
             ; (1)  ENTER root_function_main @ statementVar
   19               [:root_function_main___VAR_arg1] = 65
             ; (1)  EXIT  root_function_main @ statementVar
             ; (1)  ENTER root_function_main @ functionCall
                    ; (2)   ENTER root_function_main @ blkExprs
                            ; (3)    ENTER root_function_main @ blkVar
   20                                REGA = [:root_function_main___VAR_arg1]
                            ; (3)    EXIT  root_function_main @ blkVar
                            ; assign clause 1 result to [:root_function_main___VAR_blkExprs2] = arg1 
   21                       [:root_function_main___VAR_blkExprs2] = REGA
                            ; assigning result back to REGA
   22                       REGA = [:root_function_main___VAR_blkExprs2]
                    ; (2)   EXIT  root_function_main @ blkExprs
   23               [:root_function_depth1___VAR_a1] = REGA
                    ; set return address variables
   24               [:root_function_depth1___VAR_RETURN_HI] = < :root_function_main___LABEL_RETURN_2
   25               [:root_function_depth1___VAR_RETURN_LO] = > :root_function_main___LABEL_RETURN_2
                    ; do jump to function 'depth1''
   26               PCHITMP = < :root_function_depth1___LABEL_START
   27               PC = > :root_function_depth1___LABEL_START
                    ; return location
                    root_function_main___LABEL_RETURN_2:
   28               REGA = [:root_function_depth1___VAR_a1]
   29               [:root_function_main___VAR_arg1] = REGA
             ; (1)  EXIT  root_function_main @ functionCall
             ; (1)  ENTER root_function_main_putcharN_arg1_ @ statementPutcharName
                    root_function_main_putcharN_arg1____LABEL_wait_3:
   30               PCHITMP = <:root_function_main_putcharN_arg1____LABEL_transmit_4
   31               PC = >:root_function_main_putcharN_arg1____LABEL_transmit_4 _DO
   32               PCHITMP = <:root_function_main_putcharN_arg1____LABEL_wait_3
   33               PC = <:root_function_main_putcharN_arg1____LABEL_wait_3
                    root_function_main_putcharN_arg1____LABEL_transmit_4:
   34               UART = [:root_function_main___VAR_arg1]
             ; (1)  EXIT  root_function_main_putcharN_arg1_ @ statementPutcharName
   35        PCHITMP = <:root_end
   36        PC = >:root_end
       ; (0) EXIT  root_function_main @ function
       ; (0) ENTER root @ comment
             ; // END  COMMAND
       ; (0) EXIT  root @ comment
       root_end:
   37  END

Discussions