; ; +-------------------------------------------------+ ; I I ; I S T R U C T U R E M A C R O S I ; I - - - - - - - - - - - - - - - - I ; I I ; +-------------------------------------------------+ ; ; FUNCTION: ; ; MACRO-11 STRUCTURED PROGRAMMING MACROS ; ; AUTHOR: ; ; BOB STEWART, DIGITAL EQUIPMENT CORPORATION, DISTRIBUTED SYSTEMS ; ; Reading and Using the Structured Programming Macros ; ; Introduction ; ; You will find that these macros make MACRO-11 code look quite different ; from the usual assembly language. At first, if you are used to assembly ; language, you will probably find them difficult to read or use. This ; difficulty can be overcome with an understanding of the basic structured ; programming control constructs and the particular (peculiar) way that ; conditionals are coded using these macros. ; ; Once the initial difficulty is overcome, probably about ten minutes to ; an hour, depending on the individual, the obvious structured nature of ; the code makes it much easier to trace and to modify the control flow ; than standard assembly language with branches and labels. ; ; Basically, these macros allow the programmer to use structured control ; constructs in a way that is more obvious to the code reader than the ; usual techniques of commenting and code blocking. They relieve the ; programmer of the responsibility of (1) remembering which labels belong ; to which blocks of code, and (2) ensuring that branches go to the right ; place. They relieve the code reader of the problem of tracing branching ; structures or wondering how control comes to a particular label. ; ; The constructs provided are PROCEDURE, IF-THEN-ELSE, WHILE, and ONCASE. ; There is also a system state switching capability. ; ; The control structures may be nested within one another to any practical ; depth. The amount of code within a structure is limited only by the ; range of a PDP-11 branch instruction. ; ; Contents: ; ; 1.0 PROCEDURES ; 2.0 IF-THEN-ELSE ; 3.0 WHILE ; 4.0 ONCASE ; 5.0 Conditional Macros ; 6.0 System State Switching ; ; 1.0 PROCEDURE ; ; There are three types of PROCEDURES: mainline, global, and local. A ; mainline procedure has a local symbol for an entry point and no return ; at the end. A global procedure has a globally defined symbol for an ; entry point and a return at the end. A local procedure has a local ; symbol for an entry point and a return at the end. A PROCEDURE, as is ; any block of structured code, is defined as being entered only at the ; beginning and exited only at the end. Within its range there are no labels ; directly defined or accessed by the programmer and no returns other than ; the one at the end. All labels are used only internally, by the macros. ; ; PROCEDURES are started with one of three macros and terminated with an ; ENDPROC macro. The starting macros are: ; ; PROCMN for a mainline procedure ; PROC for a global procedure ; PROCLC for a local procedure ; ; The PROCEDURE begin macros generate MCALLs for all of the other macros ; needed. The programmer need only MCALL the appropriate PROCEDURE macro. ; ; All of the PROCEDURE begin macros take one required argument and one ; optional argument. The required argument is the name of the procedure, ; which becomes its entry point symbol. The optional argument is the word ; SYSTEM, which indicates that the procedure will use the system state ; switching capability. For example: ; ; PROCMN SUPER ; . ; . procedure body ; . ; ENDPROC ; ; This defines a local symbol, SUPER, as the entry point of the procedure. ; Or: ; ; PROC RDSYST,SYSTEM ; . ; . procedure body ; . ; ENDPROC ; ; This defines a global symbol, RDSYST, as the entry point. It declares ; that system state switching will be used, which generates the necessary ; extra .MCALLs. It also generates a return (RTS PC) at the ENDPROC. ; ; For the rare case where a procedure does not return directly, but goes ; to another procedure, the macro JMPPROC may be used in place of the ; ENDPROC. It takes one argument, the name of the procedure to go to, ; and generates a JMP to that label. ; ; A single MACRO-11 source file may contain one or more procedures in ; any combination of types. The inclusion of a .END directive is the ; responsibility of the programmer. ; ; 2.0 IF-THEN-ELSE ; ; The IF-THEN-ELSE construct provides the same type of conditional ; capability as found in many high level languages. Its basic forms are: ; ; IF ; condition ; . ; . conditional macros (see section 5.0) ; . ; THEN ; . ; . true code (code to execute if condition is true) ; . ; ELSE ; . ; . false code (code to execute if condition is false) ; . ; ENDIF ; ; Or: ; ; IF ; condition ; . ; . conditional macros (see section 5.0) ; . ; THEN ; . ; . true code (code to execute if condition is true) ; . ; ENDIF ; ; In using this construct, it is recommended that the IF line include ; a comment describing the condition, that the IF, THEN, ELSE, and ENDIF ; control lines be indented the same number of spaces, and that the true ; code and false code be indented two characters deeper than the control ; lines. ; ; The IF macro generates no code. The conditional macros (see section 5.0) ; test the condition and determine whether the true code or false code ; will execute. The THEN macro generates a local label for the beginning ; of the true code. The ELSE macro generates a branch to the end label ; followed by a local label for the beginning of the false code. The ; ENDIF macro generates a local label for the end of the structure. ; ; 3.0 WHILE ; ; The WHILE construct provides the basic looping capability. Its basic ; form is: ; ; WHILE ; condition ; . ; . conditional macros (see section 5.0) ; . ; DO ; . ; . true code (code executed if condition is true) ; . ; ENDWHILE ; ; In using this construct it is recommended that the WHILE line include ; a comment describing the condition, that the WHILE, DO, and ENDWHILE ; control lines be indented the same number of spaces, and that the true ; code be indented two characters deeper than the control lines. ; ; The WHILE macro generates a local label for the beginning of the ; condition check. The conditional macros (see section 5.0) test the ; condition to see if the true code will be executed or the loop exited. ; The DO macro generates a local label for the beginning of the true code. ; The ENDWHILE macro generates a branch to the beginning of the condition ; check, followed by a local label for the end of the strucure. ; ; 4.0 ONCASE ; ; The ONCASE construct provides a pick-one type of control strucure ; similar to an IF-THEN-ELSE with more than two possibilities. Its basic ; form is: ; ; ONCASE ; case control ; . ; . code to set up case control (e.g. load a register) ; . ; CASE ; condition 1 ; . ; . conditional macros (see section 5.0) ; . ; DO ; . ; . true code (code to execute if case 1 matches) ; . ; CASE ; condition 2 ; . ; . conditional macros (see section 5.0) ; . ; DO ; . ; . true code (code to execute if case 2 matches) ; . ; ELSE ; . ; . false code (code to execute if no case matches) ; . ; ENDCASE ; ; The ELSE is optional. If it is omitted and no case matches, nothing ; is executed other than the conditional checking code. ; ; In using this construct it is recommended that the ONCASE line include ; a comment describing the basic test which controls case selection, that ; each CASE macro include a comment describing the specific case, that the ; ONCASE, CASE, DO, and ENDCASE control lines be indented the same number ; of spaces, and that the true code and false code be indented two ; characters deeper than the control lines. ; ; The ONCASE macro generates no code. The condition set up code is ; whatever is necessary to set up the condition to be tested by the cases. ; The first CASE macro in an ONCASE structure generates no code. ; Succeeding CASE macros in the ONCASE structure generate a branch to the ; end label, followed by a local label to be branched to if the preceeding ; condition check is false. The DO macro generates a local label for ; the true code for its associated CASE. The ELSE macro, if included, ; generates a branch to the end label, followed by a local label for the ; false code. The ENDCASE macro generates a local label for the end of ; the structure. ; ; 5.0 Conditional Macros ; ; In order to keep the macros internally as simple as possible while ; providing the programmer with easy control and predictability for the ; generated code, conditionals are handled in a manner that requires some ; explanation. The programmer needs to be able to transfer control to ; one place if the condition is true and another if it is false. In ; standard assembly language this would be accomplished with a branch to ; the appropriate label, but using the structure macros the programmer ; doesn't have access to the labels. The capability is therefore provided ; through macros which can be thought of as a branch-to-true or branch-to- ; false. The general format of these macros is: ; ; TRUE[B] condition [operand1 [operand2]] ; FALSE[B] condition [operand1 [operand2]] ; ; These branch to the true label or the false label, respectively. The ; rules for assigning labels to which to branch when the condition is ; true or false are as follows: ; ; Construct True label False label ; ; IF with ELSE THEN ELSE ; IF without ELSE THEN ENDIF ; WHILE DO past the ENDWHILE ; CASE before CASE DO next CASE ; CASE before ELSE DO ELSE ; CASE before ENDCASE DO ENDCASE ; ; The condition argument is either the appropriate last two characters for ; a MACRO-11 branch instruction (e.g. EQ, CS) or one of the words SET or ; CLEAR. SET and CLEAR generate the appropriate branch to follow a BIT ; or BITB instruction. If no arguments other than the condition are provided, ; only a branch instruction is generated. For example: ; ; TRUE CC ; ; This branches to the true label if the carry bit is clear. It generates ; a BCC instruction. ; ; BIT #401,R0 ; FALSE SET ; ; This branches to the false label if either bit 0 or bit 8 is set in R0. ; It generates a BNE instruction. ; ; The FALSE or TRUE macros will also generate the condition code setting ; instruction if desired. In this case the macros are FALSE and TRUE for ; instructions which reference word locations and FALSEB and TRUEB for ; instructions which reference byte locations. If a single ; operand is supplied, it is used as the operand for a TST or TSTB ; instruction. If two operands are supplied, they are used as operands ; for a CMP or CMPB unless the condition is equal to either SET or CLEAR. ; If the condition is equal to either SET or CLEAR, operand1 and operand2 ; are used as operands for a BIT or BITB instruction. The macros first ; generate the condition code setting instruction, then the branch. ; ; For example: ; ; FALSE LT R0,#MAX ; ; Generates: ; ; CMP R0,#MAX ; BLT false label ; ; Or: ; ; TRUEB CLEAR #,LIFE ; ; Generates: ; ; BITB #,LIFE ; BEQ true label ; ; Or: ; ; FALSEB NE R0 ; ; Generates: ; ; TSTB R0 ; BNE false label ; ; In summary: ; ; A. FALSE and FALSEB may be thought of as branch-to-false. TRUE and ; TRUEB may be thought of as branch-to-true. ; ; B. FALSE and TRUE generate instructions which reference word locations. ; FALSEB and TRUEB generate instructions which reference byte ; locations. ; ; C. All four conditional macros accept the same argument list. ; ; D. The first argument in the argument list determines the type of ; branch instruction. Any specific branch is generated by using ; the characters following the B in a MACRO-11 conditional branch ; instruction (e.g. R for a BR, or CS for a BCS). ; To automatically generate the correct test for BIT or BITB, or ; a zero or non-zero condition, the branch type can be SET or CLEAR. ; ; E. If no arguments follow the branch type, only a branch is generated. ; ; F. If one argument follows the branch type, the argument is used as the ; operand for a TST or TSTB instruction. ; ; G. If two arguments follow the branch type, they are used as the ; operands for a CMP or CMPB instruction, unless the branch type is ; SET or CLEAR. ; ; H. If the branch type is SET or CLEAR, and it is followed by two ; arguments, they are used as the operands for a BIT or BITB ; instruction. ; ; * * * Important Note * * * ; ; In a condition check, the final conditional macro must always generate ; a branch-to-false. This is because no branch around the true code is ; automatically generated. This leads to the initially odd looking ; characteristic of condition checks that they always end with a FALSE or ; FALSEB macro. Furthermore, this last condition check is always the ; logical opposite of the comment on the IF, WHILE or CASE line. For ; example the code to call a subroutine if a flag is set would read: ; ; IF ; FLAG IS SET ; FALSE CLEAR #FLAG,FLAGS(R5) ; THEN ; CALL START ;START THE PROCESS ; ENDIF ; ; For a check of a multiple condition: ; ; WHILE ; FLAG IS SET OR RETRY COUNT > 0 ; TRUE SET #FLAG,FLAGS(R5) ; FALSE LE RETCNT ; DO ; DEC RETCNT ;DECREMENT RETRY COUNT ; CALL START ;ATTEMPT TO START PROCESS ; ENDWHILE ; ; 6.0 System State Switching ; ; Due to the way system state switching is implemented in RSX-11M/S it ; is convenient to handle this within the structured macros. The macros ; hide the need to use a label and a return to exit system state when ; using the SWSTK$ macro. They also provide a compatible facility for ; RSX-11D/IAS. On both systems the SYSTATE and ENDSYSTATE macros provide ; the same behavior: (1) the task is made non-interruptable, and ; (2) all registers are saved and restored. If they are to be used, the ; SYSTEM option is specified on the PROCEDURE macro. For example: ; ; PROC RDSYST,SYSTEM ; . ; . ; . ; SYSTATE ; . ; . system state code ; . ; ENDSYSTATE ; . ; . ; . ; ENDPROC ; ; In using this construct it is recommended that the SYSTATE and ; ENDSYSTATE control lines be indented the same number of spaces, and that ; the system state code be indented two characters deeper than the control ; lines. ; ; On RSX11-M/S the SYSTEM option generates an MCALL for SWSTK$. The ; SYSTATE macro generates an invocation of SWSTK$ with an end label as ; its argument. The ENDSYSTATE macro generates a return (RTS PC) followed ; by the end label. The processing of the switch to system state, done within ; SWSTK$, provides the two functions named above. ; ; On RSX11-D/IAS the SYSTEM option generates an MCALL for .INH0 and ; .ENB0. The SYSTATE macro generates MOVs of R0-R5 to the stack followed ; by an invocation of .INH0. The ENDSYSTATE macro generates an ; invocation of .ENB0 followed by MOVs of R5-R0 from the stack. ; ; If this facility is used, the programmer must ensure that the proper ; control symbols (R$$11M, R$$11D, and/or I$$AS) and the necessary ; macros (SWSTK$ or .INH0 and .ENB0) are available at assembly time. ; ; THIS FILE CONTAINS THE FOLLOWING MACROS (IN THIS ORDER): ; ; EXTERNALLY CALLABLE: ; ; PROC - EXTERNAL SYMBOL DEFINITION AND INITIALIZATION FOR SUBROUTINE ; PROCLC - EXTERNAL SYMBOLS DEFINITION AND INITIALIZATION FOR LOCAL SUBROUTINE ; PROCMN - EXTERNAL SYMBOL DEFINITION AND INITIALIZATION FOR MAINLINE ; ENDPROC - END OF PROCEDURE, GENERATES RETURN FOR SUBROUTINE ; JMPPROC - END OF PROCEDURE, GENERATES A JMP TO NEXT PROCEDURE ; IF - BEGINNING OF IF STATEMENT ; ENDIF - END OF IF STATEMENT ; WHILE - BEGINNING OF WHILE STATEMENT ; ENDWHILE - END OF WHILE STATEMENT ; ONCASE - BEGINNING OF CASE STATEMENT ; CASE - BEGINNING OF INDIVIDUAL CASE ; ENDCASE - END OF CASE STATEMENT ; ; SYSTATE - ENTER SYSTEM STATE ; ENDSYSTATE - EXIT SYSTEM STATE ; ; DO - END OF CONDITION CHECK FOR CASE AND WHILE ; THEN - END OF CONDITION CHECK FOR IF ; ELSE - ELSE CLAUSE FOR IF AND ONCASE ; ; TRUE - TRUE BRANCH FOR WORD CONDITION CHECK ; FALSE - FALSE BRANCH FOR WORD CONDITION CHECK ; TRUEB - TRUE BRANCH FOR BYTE CONDITION CHECK ; FALSEB - FALSE BRANCH FOR BYTE CONDITION CHECK ; ; INTERNAL: ; ; $$INSY - SYMBOL INITIALIZATION FOR PROC MACROS ; $$INMC - MCALL INITIALIZATION FOR PROC MACROS ; $$PUSH - PUSH NUMBER ON STACK ; $$POP - POP NUMBER OFF STACK ; $$POPI - POP INTERNAL MACRO ; $$ELSE - ELSE INTERNAL MACRO ; $$BGND - GENERATE A BRANCH GIVEN TYPE AND DIFFERENCE ; $$BGNN - GENERATE A BRANCH GIVEN TYPE AND NUMBERS ; $$LAB - GENERATE A LABEL ; $$STSM - SET SYMBOL VALUE ; $$GEN1 - GENERATE CODE WITH 1 OPERAND ; $$GEN2 - GENERATE CODE WITH 2 OPERANDS ; $$GNCM - GENERATE COMPARE AND BRANCH INSTRUCTIONS ; $$GNBT - GENERATE TEST FOR SET AND CLEAR ; $$GNAB - GENERATE TEST FOR 0, 1 OR 2 ARGUMENT COMPARES ; ; ; PROC MACRO ; .MACRO PROC NAME,FLAG .MCALL $$INSY,$$INMC $$INSY $$INMC FLAG $$GEN1 NAME':: $$SUB=0 .ENDM ; ; PROCLC MACRO ; .MACRO PROCLC NAME,FLAG .MCALL $$INSY,$$INMC $$INSY $$INMC FLAG $$GEN1 NAME': $$SUB=0 .ENDM ; ; PROCMN MACRO ; .MACRO PROCMN NAME,FLAG .MCALL $$INSY,$$INMC $$INSY $$INMC FLAG $$GEN1 NAME':: $$SUB=1 .ENDM ; ; ENDPROC MACRO ; .MACRO ENDPROC .IF EQ $$SUB $$GEN1 ,RTS,PC .ENDC .ENDM ; ; JMPPROC MACRO ; .MACRO JMPPROC NAME $$GEN1 ,JMP,NAME .ENDM ; ; IF MACRO ; .MACRO IF $$PUSH $$STNM $$STNM=$$PRST+1 $$PRST=$$STNM $$PUSH $$TRNM $$TRNM=77 .ENDM ; ; ENDIF MACRO ; .MACRO ENDIF $$LAB \$$STNM,\$$TRNM-1 $$POP $$TRNM $$POP $$STNM .ENDM ; ; WHILE MACRO ; .MACRO WHILE IF $$LAB \$$STNM,10 .ENDM ; ; ENDWHILE MACRO ; .MACRO ENDWHILE $$BGNN R,\$$STNM,10 ENDIF .ENDM ; ; ONCASE MACRO ; .MACRO ONCASE IF $$PUSH $$CSTA $$CSTA=0 .ENDM ; ; CASE MACRO ; .MACRO CASE .IF GT $$CSTA ;MUST TERMINATE PREVIOUS STATE $$ELSE $$TRNM=$$TRNM-2 .IFF $$CSTA=1 .ENDC .ENDM ; ; ENDCASE MACRO ; .MACRO ENDCASE $$POP $$CSTA .IF NE $$TRNM-11 $$LAB \$$STNM,10 .ENDC ENDIF .ENDM ; ; SYSTATE MACRO ; .MACRO SYSTATE .IF DF,R$$11M IF $$SYS \$$STNM,10 .IFF MOV R0,-(SP) MOV R1,-(SP) MOV R2,-(SP) MOV R3,-(SP) MOV R4,-(SP) MOV R5,-(SP) .ENDC .IF DF,R$$11D!I$$AS .INH0 .ENDC .ENDM ; ; ENDSYSTATE MACRO ; .MACRO ENDSYSTATE .IF DF,R$$11D!I$$AS .ENB0 .ENDC .IF NDF,R$$11M MOV (SP)+,R5 MOV (SP)+,R4 MOV (SP)+,R3 MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 .IFF $$GEN1 ,RTS,PC $$LAB \$$STNM,10 ENDIF .ENDC .ENDM ; ; DO MACRO ; .MACRO DO THEN .ENDM ; ; THEN MACRO ; .MACRO THEN $$LAB \$$STNM,\$$TRNM .ENDM ; ; ELSE MACRO ; .MACRO ELSE $$ELSE $$TRNM=11 .ENDM ; ; TRUE MACRO ; .MACRO TRUE,COMP,OP1,OP2 $$GNCM COMP,,,0 .ENDM ; ; FALSE MACRO ; .MACRO FALSE,COMP,OP1,OP2 $$GNCM COMP,,,1 .ENDM ; ; TRUEB MACRO ; .MACRO TRUEB,COMP,OP1,OP2 $$GNCM COMP,,,0,B .ENDM ; ; FALSEB MACRO ; .MACRO FALSEB,COMP,OP1,OP2 $$GNCM COMP,,,1,B .ENDM ; ; $$INSY INTERNAL MACRO ; .MACRO $$INSY $$CSTA=0 $$PRST=7 $$STNM=0 $$TRNM=0 $$STIX=777 .ENDM ; ; $$INMC INTERNAL MACRO ; .MACRO $$INMC FLAG .MCALL ENDPROC,IF,ENDIF,WHILE,ENDWHILE,ONCASE,CASE,ENDCASE .MCALL PROCLC,JMPPROC,DO,THEN,ELSE,TRUE,FALSE,TRUEB,FALSEB .MCALL $$PUSH,$$POP,$$POPI,$$ELSE,$$BGNN,$$BGND,$$LAB,$$STSM .MCALL $$GEN1,$$GEN2,$$GNCM,$$GNBT,$$GNAB .IF IDN , .MCALL SYSTATE,ENDSYSTATE .IF DF,R$$11M .MCALL SWSTK$,$$SYS .ENDC .IF DF,R$$11D!I$$AS .MCALL .INH0,.ENB0 .ENDC .ENDC .ENDM ; ; $$PUSH INTERNAL MACRO ; .MACRO $$PUSH VAL $$STSM $$S,\$$STIX, $$STIX=$$STIX-1 .ENDM ; ; $$POP INTERNAL MACRO ; .MACRO $$POP VAR $$STIX=$$STIX+1 $$POPI ,\$$STIX .ENDM ; ; $$POPI INTERNAL MACRO ; .MACRO $$POPI VAR,NUM VAR'=$$S'NUM .ENDM ; ; $$ELSE INTERNAL MACRO ; .MACRO $$ELSE $$BGNN R,\$$STNM,10 $$LAB \$$STNM,\$$TRNM-1 .ENDM ; ; $$BGND INTERNAL MACRO ; .MACRO $$BGND,BRTYPE,DIF $$BGNN BRTYPE,\$$STNM,\$$TRNM-DIF .ENDM ; ; $$BGNN INTERNAL MACRO ; .MACRO $$BGNN BRTYPE,N1,N2 $$GEN1 ,B'BRTYPE,N1'N2'$ .ENDM ; ; $$LAB INTERNAL MACRO ; .MACRO $$LAB N1,N2 $$GEN1 N1'N2'$: .ENDM ; ; $$STSM INTERNAL MACRO ; .MACRO $$STSM NAME,NUMB,VAL NAME'NUMB'='VAL .ENDM ; ; $$SYS INTERNAL MACRO ; .MACRO $$SYS N1,N2 $$GEN1 ,SWSTK$,N1'N2'$ .ENDM ; ; $$GEN1 INTERNAL MACRO ; .MACRO $$GEN1,LAB,OPCODE,OP1 .IF DF $$SLST .LIST LAB OPCODE OP1 .NLIST .IFF LAB OPCODE OP1 .ENDC .ENDM ; ; $$GEN2 INTERNAL MACRO ; .MACRO $$GEN2,OPCODE,OP1,OP2 .IF DF $$SLST .LIST OPCODE OP1,OP2 .NLIST .IFF OPCODE OP1,OP2 .ENDC .ENDM ; ; $$GNCM INTERNAL MACRO ; .MACRO $$GNCM,COMP,OP1,OP2,DIF,BYTE .IF IDN , $$GNBT ,,BYTE $$BGND NE,DIF .IFF .IF IDN , $$GNBT ,,BYTE $$BGND EQ,DIF .IFF $$GNAB ,,BYTE $$BGND COMP,DIF .ENDC .ENDC .ENDM ; ; $$GNBT INTERNAL MACRO ; .MACRO $$GNBT,A,B,BYTE .IF NB B $$GEN2 BIT'BYTE,, .IFF .IF NB A $$GEN1 ,TST'BYTE, .ENDC .ENDC .ENDM ; ; $$GNAB INTERNAL MACRO ; .MACRO $$GNAB,A,B,BYTE .IF NB B $$GEN2 CMP'BYTE,, .IFF .IF NB A $$GEN1 ,TST'BYTE, .ENDC .ENDC .ENDM