* H316 SAFE SOFTWARE STACK, REV. 0.1 * * * AUTHOR: * * PHILIPP HACHTMANN, 2007 * * VERSIONS: * * 0.1 - INITIAL REVISION (22.12.2007) * * PURPOSE: * * TO PROVIDE A MULTI-PURPOSE STACK MECHANISM * TO PROVIDE A SPECIAL-PURPOSE STACK MECHANISM FOR RECURSIVE * PROGRAM CALLS * * THEORY OF OPERATION: * * THE STACK ROUTINES MAINTAIN AN UPWARDS GROWING STACK. * EVERY USAGE CONTEXT OF THE STACK NEEDS TO RESERVE THE SPACE FOR * ITS STACK'S DATA. THIS ENABLES THE PROGRAMMER TO CHOOSE THE STACK * SIZE AND USE MULTIPLE STACKS IN MULTIPLE PLACES INDEPENDENTLY. * ALL STACK RELATED ROUTINES TAKE A POINTER TO THE STACK'S INTERNAL * DATA AS FIRST ARGUMENT. * * THE DATA LAYOUT OF THE STACK DATA IS AS FOLLOWING: * * SIZE OCT '1000 SIZE OF THE STACK IN MACHINE WORDS * PTR DAC ** THE STACK POINTER * FILL DAC ** THE FILL COUNTER * OVER DAC OFL OPTIONAL POINTER TO OVERFLOW ERROR ROUTINE * UNDR DAC UFL OPTIONAL POINTER TO UNDERFLOW ERROR ROUTINE * STCK BSS '1000 THE STACK DATA * * IF CUSTOM ERROR HANDLING ROUTINES ARE NOT TO BE USED, SET THE TWO * POINTER LOCATIONS TO ZERO. THEN, INTERNAL ERROR ROUTINES WILL BE * USED. SIZE AND THE FUNCTION POINTERS HAVE TO BE INITIALISED. THE * OTHER LOCATIONS ARE INITIALISED BY THE STACK ROUTINES. * * USAGE: * * INITIALISING STACK POINTER: * * CALL S$INIT * DAC SDATA STACK DATA * OCT SSIZ DATA SIZE (NOT STACK DEPTH!!!) * * PUSHING AND POPPING THE A-REGISTER FROM AND TO THE STACK: * * CALL S$PUSH VALUE IN A REGISTER IS PUSHED. * DAC SDATA * * CALL $$POP VALUE FROM STACK IS POPPED INTO A-REGISTER. * DAC SDATA * * PUSHING AND POPPING ARBITRARY DATA FROM AND TO THE STACK: * * CALL S$PUSM * DAC SDATA * DAC ADDRESS * OCT SIZE * * CALL S$POPM * DAC SDATA * DAC ADDRESS * OCT SIZE * * * MAKING A RECURSIVE CALL FROM FORTRAN IV TO A FORTRAN IV OR OTHER ROUTINE: * * THE ROUTINE S$CALL SAVES A SET OF LOCAL VARIABLES ONTO THE STACK. * IT ALSO SAVES THE RETURN ADDRESS AND ITS OWN PARAMETERS. * S$LLAC DOES EVERYTHING IN REVERSE ORDER. * * HERE IS AN EXAMPLE HOW TO USE THE TWO ROUTINES IN FORTRAN IV: * * C LOCAL VARIABLES I(3),A,Z TO SAVE * * CALL S$CALL(3,I,3,A,2,Z,2) * RETURN <-- FOR THE RETURN ADDRESS OF THE CURRENT ROUTINE * CALL MYROUTINE(...) * CALL S$LLAC * * ASSEMBLER CALLING SEQUENCE: * * JST S$CALL * DAC VARNO NO OF LOCAL VARIABLES TO SAVE ON THE STACK * DAC VAR1 POINTER TO FIRST VARIABLE * DAC SIZE1 WORD SIZE OF VARIABLE * ... * DAC VARN POINTER TO LAST VARIABLE * DAC SIZEN WORD SIZE OF LAST VARIABLE * DAC 0 FORTRAN IV COMPILER GENERATED * * JMP* PROC RETURN JUMP, GENERATED BY THE "RETURN" STATEMENT * * JST MYROUTINE * ... * * JST S$LLAC * * ******************************************************************************** * * **** SYMBOL DECLARATIONS * SUBR STACK,SBUF JUST A LABEL FOR THE OBJECT TAPE SUBR S$INIT,INIT INITITALISATION SUBR S$PUSH,PUSH SINGLE WORD PUSH SUBR S$POP,POP SINGLE WORD POP SUBR S$PUSM,PUSM MEMORY RANGE PUSH SUBR S$POPM,POPM MEMORY RANGE POP SUBR S$PTR,SPTR STACK POINTER ACCESS SUBR S$CALL,CALL SUBR S$LLAC,LLAC * * ******************************************************************************** * * REL RELOCATEABLE OBJECT * * ******************************************************************************** * * *** PUSH MEMORY RANGE TO STACK * PUSM DAC ** ENTRY POINT TO PUSH ROUTINE STA ATM1 SAVE A-REGISTER * LDA* PUSM LOAD DATA BASE IRS PUSM STA DPT SAVE FOR LATER USE * LDA* PUSM LOAD POINTER STA PTR STORE TO TRANSFER POINTER IRS PUSM GO TO NEXT ARGUMENT LDA* PUSM LOAD TRANSFER SIZE IRS PUSM CORRECT RETURN ADDRESS * TCA NEGATE WORD COUNT STA CNT STORE TO COUNTER * PULP LDA* PTR GET DATA JST PUSH PUSH IT! DPT DAC ** * IRS PTR INCREMENT POINTER IRS CNT INCREMENT BYTE COUNTER JMP PULP DO IT AGAIN! * LDA ATM1 RESTORE A-REG JMP* PUSM RETURN * * ******************************************************************************** * * **** POP MEMORY RANGE FROM STACK * POPM DAC ** ENTRY POINT TO PUSH ROUTINE STA ATM1 SAVE A-REGISTER * LDA* POPM GET DATA POINTER IRS POPM STA DPTR STORE FOR LATER USE * LDA* POPM LOAD POINTER IRS POPM GO TO NEXT ARGUMENT ADD* POPM ADD TRANSFER SIZE SUB =1 SUBSTRACT 1 TO GET HIGH ADDRESS STA PTR STORE TO TRANSFER POINTER LDA* POPM LOAD TRANSFER SIZE IRS POPM CORRECT RETURN ADDRESS * TCA NEGATE WORD COUNT STA CNT STORE TO COUNTER * POLP JST POP POP DATA FROM THE STACK DPTR DAC ** * STA* PTR STORE IT. LDA PTR SUB =1 DECREMENT STA PTR WRITE BACK IRS CNT INCREMENT BYTE COUNTER JMP POLP DO IT AGAIN! * LDA ATM1 RESTORE A-REG JMP* POPM RETURN * * ******************************************************************************** * * **** PUSH SINGLE WORD ONTO STACK * SUBR PUSH PUSH DAC ** REAL PUSH ROUTINE - PUSH AC TO STACK. * STX XTM SAVE X REGISTER STA ATM2 SAVE A REGISTER * LDX* PUSH LOAD INDEX REGISTER WITH DATA BASE IRS PUSH * LDA FILL,1 LOAD FILL SIZE CAS SSIZ,1 COMPARE STACK SIZE NOP JST OFLO OVERFLOW! * LDA ATM2 STA* SPTR,1 NO OVERFLOW, PUT DATA ONTO STACK IRS SPTR,1 INCREMENT STACK POINTER IRS FILL,1 INCREMENT FILL SIZE * LDX XTM RESTORE X REGISTER LDA ATM2 JMP* PUSH RETURN WITH A-REG UNALTERED. * * ******************************************************************************** * * **** POP SINGLE WORD FROM STACK * POP DAC ** REAL POP ROUTINE - POP AC FROM STACK. * STX XTM SAVE X REGISTER LDX* POP LOAD INDEX REGISTER WITH DATA BASE IRS POP * LDA FILL,1 FILL SIZE SNZ JST UFLO NOTHING INSIDE? SKIP! * LDA SPTR,1 LOAD STACK POINTER SUB =1 DECREMENT IT TO LAST USED LOCATION STA SPTR,1 SAVE IT BACK LDA FILL,1 SUB =1 STA FILL,1 DECREMENT FILL SIZE * LDA* SPTR,1 LOAD VALUE FROM THE STACK LDX XTM RESTORE INDEX REGISTER JMP* POP RETURN. * * ******************************************************************************** * * **** INITIALIZATION * INIT DAC ** INITIALIZE STACK STA ATM1 STX XTM * LDX* INIT * LDA VARS SIZE OF MANAGEMENT VARIABLES ADD* INIT BASE ADDRESS STA SPTR,1 SAVE TO STACK POINTER IRS INIT * LDA* INIT LOAD DATA POOL SIZE SUB VARS VARIABLE SIZE STA SSIZ,1 SAVE TO STACK DEPTH * CRA STA FILL,1 * LDA ATM1 LDX XTM IRS INIT JMP* INIT * * ******************************************************************************** * * **** ERROR HANDLING ROUTINES * SUBR OFLO OFLO DAC ** STACK OVERFLOW ROUTINE LDA OMSP LOAD OVERFLOW MESSAGE POINTER JST TYPE TYPE IT OUT. * HLT WHAT WE DO: HALT THE MACHINE. JMP *-1 YOU CANNOT SIMPLY LEAVE THIS, IT'S SERIOUS! * * **************************************** * * SUBR UFLO UFLO DAC ** STACK OVERFLOW ROUTINE LDA UMSP LOAD OVERFLOW MESSAGE POINTER JST TYPE TYPE IT OUT. * HLT WHAT WE DO: HALT THE MACHINE. JMP *-1 YOU CANNOT SIMPLY LEAVE THIS, IT'S SERIOUS! * * **************************************** * * SUBR TYPE TYPE DAC ** SKS '104 TEST ASR READY JMP *-1 WAIT TO BECOME READY OCP '104 SET TO OUTPUT MODE * STA PTR STORE POINTER * TLOP LDA* PTR TYPE LOOP SNZ TEST FOR END JMP* TYPE RETURN ICA OTA '4 JMP *-1 ICA OTA '4 JMP *-1 SKS '104 ADDITIONAL TEST FOR READY JMP *-1 IRS PTR NEXT WORD. JMP TLOP * * ******************************************************************************** * * ***** VARIABLES * * PTR DEC 0 TRANSFER POINTER TO USER BUFFERS CNT DEC 0 TRANSFER COUNTER * ATM1 DEC 0 A-REGISTER BACKUP ATM2 DEC 0 A-REGISTER BACKUP XTM DEC 0 X-REGISTER BACKUP * * ***** CONSTANTS * VARS DEC 3 SIZE OF VARIABLES AT BEGINNING OF DATA * SSIZ EQU 0 SPTR EQU 1 FILL EQU 2 * OMSP DAC OMSG POINTER TO MESSAGE UMSP DAC UMSG POINTER TO MESSAGE OMSG OCT '006412 CR/LF CHARACTERS BCI 16,STACK OVERFLOW, YOUR'RE SCREWED! DEC 0 TERMINATION CHARACTER UMSG OCT '006412 CR/LF CHARACTERS BCI 17,STACK UNDERFLOW, YOUR'RE SCREWED! DEC 0 TERMINATION CHARACTER * * ******************************************************************************** * * END THAT'S IT.