.title six_macros ;------------------------------------------------------------------------ ; Macro to reset the length of a fake variable-length string. ; ; By my convention, the maximum length of a string is stored in the ; word preceeding the string descriptor quadword. ; .macro _RESLEN addr movw addr-4, addr .endm ;------------------------------------------------------------------------ ; Macro to get a value-string from the command line, ; and optionally call an action-routine to use it. ; ; If there is a list of values, the action routine is called with each. ; .macro _GET_VALUE, entity, routine, desc=six_xstr, ?x, ?y x: _reslen desc ; Call get_value to get string pushaw desc pushaq desc pushaq entity calls #3, g^cli$get_value .if not_blank blbc r0, y ; Save get_value status movl r0, -(sp) movaq desc, r0 jsb routine ; Pass string to action routine movl (sp)+, r1 _if_err <> ; Test for error _if_eql r1, #cli$_comma, <> ; Loop if get_value status y: ; indicates there's another string .endc .endm ;------------------------------------------------------------------------- ; Macro to output a record to the open output file (if there is one). ; ; There are three formats: ; _output [desc=]dx-adr -- prints the string from a string descriptor ; _output nam=nam-adr -- prints the file name from a NAM block ; _output rab=rab-adr -- prints the buffer from an RAB block ; Optionally specify alternate output rab with "outrab=rab-adr". ; .macro _OUTPUT desc, nam, rab, outrab=six_out_rab, ?x _if_eql six_out_file, <>, type=W .if not_blank movw , movl , .endc .if not_blank movzbw , movl , .endc .if not_blank movw , movl , .endc $put _if_err <> x: .endm ;------------------------------------------------------------------------ ; Macro to push address of a descriptor pointing to ; 1) a string described by a string-descriptor (_PUSH_STR desc ), or ; 2) a filename extracted from a FAB/NAM block (_PUSH_STR FAB=nam), or ; 3) a text record extracted from a RAB block (_PUSH_STR RAB=rab) ; .macro _PUSH_STR str, fab, rab, desc=six_xdx _get_str , , , pushaq desc .endm ;-------------------------------------------------------------------------- ; Macro to fill in a descriptor with: ; 1) a string described by a string-descriptor (_GET_STR desc ), or ; 2) a filename extracted from a FAB/NAM block (_GET_STR FAB=nam), or ; 3) a text record extracted from a RAB block (_GET_STR RAB=rab) ; This macro uses r1 to store the address of the FAB's NAM block. ; Also note that this destroys previous contents of the descriptor, ; so use scratch quadword. ; .macro _GET_STR str, fab, rab, desc=six_xdx, ?x .if not_blank ; if from a descriptor movq str, desc .endc .if not_blank ; if from a RAB movzwl , desc movl , desc+4 .endc .if not_blank ; if from a FAB movl fab+fab$l_nam, r1 _if_neq nam$b_rsl(r1), type=b, - ; if searched <, - , - > _if_neq nam$b_esl(r1), type=b, - ; if parsed <, - , - > movzbw , desc ; if not even movl , desc+4 ; that x: .endc .endm ;-------------------------------------------------------------------------- ; Macros to allocate and initialize text strings. ; ; _ASCII and _ASCID both produce a string. ; _ASCID preceeds it with a descriptor. ; ; macro parameters: ; Len = The number of characters in the string. ; If blank, the length of the Str parameter is used. ; Str = The initial value of the text string. i.e. str=. ; Fil = The fill character used to pad out the allocated length. ; By default this is a blank (" "). ; Jst = Either LEFT or RIGHT, specifying how the initialization ; string should be positioned in the allocated space. ; Addr = Label to be equated with the address of the beginning of the ; text string. If you want to equate a symbol with the address ; of the descriptor, use the format "label: _ASCID p1,...". ; Scope = Either GBL or LCL, declaring the string address label ; to be either a global or a local symbol. Default is LCL. ; .macro _ASCID len, str, fil=< >, jst=left, addr, scope=LCL .if blank .iif blank , .error .long %length( str ) .address . + 4 .if not_blank .iif idn , , addr: .iif idn , , addr:: .endc .ascii `str` .if_false .long len .address . + 4 .if not_blank .iif idn , , addr: .iif idn , , addr:: .endc .if blank .byte ^a`fil` [len] .if_false _strd.xlen = len - %length( str ) .iif le _strd.xlen, .error .if identical jst left .ascii `str` .iff .iif different jst right, .error .endc .byte ^a`fil` [_strd.xlen] .iif identical jst right, .ascii `str` .endc .endc .endm ;--------------------------- .macro _ASCII len, str, fil=< >, jst=left, addr, scope=LCL .if not_blank .iif idn , , addr: .iif idn , , addr:: .endc .if blank .iif blank , .error .ascii `str` .if_false .if blank .byte ^a`fil` [len] .if_false _strd.xlen = len - %length( str ) .iif le _strd.xlen, .error .if identical jst left .ascii `str` .iff .iif different jst right, .error .endc .byte ^a`fil` [_strd.xlen] .iif identical jst right, .ascii `str` .endc .endc .endm ;---------------------------------------------------------------------------- ; macros to implement conditionals. ; ; a series of macros that can take three different formats: ; _IF_ dest ; will jump if the current state matches the test condition. ; _IF_ var, dest ; will compare the variable to zero, then jump if the test condtion is met. ; _IF_ var1, var2, dest ; will compare the two variables, then jump if the test condition is met. ; ; the suggested style for the block-if is as follows: ; _IF_EQL var1, var2, < - ; , - ; , - ; > ;---------------------------------------------------------------------------- ; Macro to invert a branch condition. ; .macro _INV_BR cond, dst, ?y x'y = . .iif idn , , bleq dst .iif idn , , bgtr dst .iif idn , , beql dst .iif idn , , beqlu dst .iif idn , , bneq dst .iif idn , , bnequ dst .iif idn , , blss dst .iif idn , , bgeq dst .iif idn , , blequ dst .iif idn , , bgtru dst .iif idn , , bvs dst .iif idn , , bvc dst .iif idn , , blssu dst .iif idn , , bgequ dst .iif idn , , bcs dst .iif idn , , bcc dst .iif eq .-x'y, .error ; no valid test condition for _INV_BR .endm ;---------------------------------------------------------------------------- .macro _IF cond, p1, p2, p3, type=l, ?label .if not_blank ; _IF cond, var1, var2, stmts cmp'type p1, p2 _inv_br cond, label .irp stmt, stmt .endr label: .mexit .endc .if not_blank ; _IF cond, var, stmts tst'type p1 _inv_br cond, label .irp stmt, stmt .endr label: .mexit .endc .if not_blank ; _IF cond, stmts _inv_br cond, label .irp stmt, stmt .endr label: .mexit .endc .error ; too few arguments to _IF .endm ;--------------------------------------- ; .irp test, - ; ; .macro _IF_'test p1, p2, p3, type=l ; _IF , , , , ; .endm ; .endr ; .macro _IF_GTR, p1, p2, p3, type=l _IF gtr, , , , .endm .macro _IF_LEQ, p1, p2, p3, type=l _IF leq, , , , .endm .macro _IF_NEQ, p1, p2, p3, type=l _IF neq, , , , .endm .macro _IF_NEQU, p1, p2, p3, type=l _IF nequ, , , , .endm .macro _IF_EQL, p1, p2, p3, type=l _IF eql, , , , .endm .macro _IF_EQLU, p1, p2, p3, type=l _IF eqlu, , , , .endm .macro _IF_GEQ, p1, p2, p3, type=l _IF geq, , , , .endm .macro _IF_LSS, p1, p2, p3, type=l _IF lss, , , , .endm .macro _IF_GTRU, p1, p2, p3, type=l _IF gtru, , , , .endm .macro _IF_LEQU, p1, p2, p3, type=l _IF lequ, , , , .endm .macro _IF_VC, p1, p2, p3, type=l _IF vc, , , , .endm .macro _IF_VS, p1, p2, p3, type=l _IF vs, , , , .endm .macro _IF_GEQU, p1, p2, p3, type=l _IF gequ, , , , .endm .macro _IF_LSSU, p1, p2, p3, type=l _IF lssu, , , , .endm .macro _IF_CC, p1, p2, p3, type=l _IF cc, , , , .endm .macro _IF_CS, p1, p2, p3, type=l _IF cs, , , , .endm ;------------------------------------------------------------------------- ; Macro to handle multiple commands on an error status. ; .macro _IF_ERR stmts, ?x blbs r0, x .irp stmt, stmt .endr x: .endm ;------------------------------------------------------------------------- ; Macro to handle multiple commands on a success status. ; .macro _IF_SUCC stmts, ?x blbc r0, x .irp stmt, stmt .endr x: .endm ;------------------------------------------------------------------------ ; Macro to exit the program, suppressing DCL status messages. ; ; Actually we just load r0 and jsb to SIX_ERR_FADE. ; .macro _FADE status .iif dif , , movl status, r0 jsb six_err_fade ; and hopefully never return! .endm ;------------------------------------------------------------------------ ; Macros for setting up psects ; author: ; Gordon O. Davisson ; modifications: ; Names changed to conform to SIX standards, GCL. ; .macro _ESECT name=_code ; executable code psect .psect name, pic, con, rel, lcl, shr, exe, rd, nowrt, long .endm _ESECT ; ; .macro _WESECT name=_wcode ; writable executable code psect .psect name, pic, con, rel, lcl, shr, exe, rd, wrt, long .endm _WESECT ; ; .macro _CSECT name=_blank ; fortran common block psect .psect name, pic, ovr, rel, gbl, shr, noexe, rd, wrt, long .endm _CSECT ; ; .macro _PSECT name=_pdata ; constant data psect .psect name, pic, con, rel, lcl, shr, noexe, rd, nowrt, long .endm _PSECT ; ; .macro _LSECT name=_local ; local variables psect .psect name, pic, con, rel, lcl, noshr, noexe, rd, wrt, long .endm _LSECT ; ;---------------------------------------------------------------------------