! ! ! ! ! %TITLE 'LIBEXT - Extensions to LIB.REQ' !++ ! ! FACILITY: LIBEXT ! ! ABSTRACT: Extensions to the VMS library LIB.REQ; i.e. macros which appear in LIB.MAR but not in LIB.REQ. ! ! ENVIRONMENT: ! ! RESTRICTIONS: The following macros have been incorporated into other macros: ! Old macro Has been incorporated into ! _DPT_STORE _DPTAB ! _FUNCTAB _DDTAB ! ! Macros not currently planned for implementation are: ! CASE CPUDISP ! PFN_DISP_ELSE PFN_DISP_ENDIF PFN_DISP_IF_BIGPFN_THEN ! ! AUTHOR: James A. Gray ! ! CREATION DATE: 4 September 1984 ! ! MODIFICATION HISTORY: ! ! V001 James A. Gray, 4-SEP-1984 00:01:31.16 ! Original version. ! V002 James A. Gray, 9-NOV-1988 00:30:42.58 ! Updated to VMS version 5.0 compatibility. !-- %SBTTL 'Include files' LIBRARY 'SYS$LIBRARY:LIB'; %SBTTL '_ACCEPT' !+ ! FUNCTIONAL DESCRIPTION: ! ?? ! ! INPUTS: ! cdt Address of listening CDT. ! ! msgadr Input address. ! ! dgadr Datagram input address. ! ! erradr Error address. ! ! initcr Initial credit value. ! ! minscr Minimum send credit value. ! ! initdg Initial DG credit value. ! ! blkpri Block transfer priority. ! ! condat Address of connect data. ! ! auxstr Address of auxilary structure. ! ! badrsp Bad response packet address. ! ! retadr Return address. ! ! OUTPUTS: ! cdt Address of listening CDT. ! ! cdtadr Address of CDT allocated. ! ! pdt Address of PDT for listening. ! ! VALUE: ! Status returned from SCS$ACCEPT. !- KEYWORDMACRO _accept ( cdt, msgadr = 0, dgadr = 0, erradr, initcr = 0, minscr = 0, initdg = 0, blkpri = 0, condat = 0, auxstr = 0, badrsp = 0, retadr, cdtadr, pdt) = BEGIN LINKAGE call_accept_linkage = CALL (; REGISTER = 2, REGISTER = 3, REGISTER = 4); ROUTINE call_accept ( ; cdt, cdtadr, pdt) : call_accept_linkage = BEGIN BUILTIN FP; LINKAGE accept_linkage = JSB (REGISTER = 3; REGISTER = 2, REGISTER = 3, REGISTER = 4) : NOPRESERVE (0, 1) PRESERVE (5); EXTERNAL ROUTINE scs$accept : accept_linkage ADDRESSING_MODE (GENERAL); LOCAL al_params : VECTOR [2, LONG]; BIND r_stack_frame = .FP : BLOCK [, BYTE], aw_params = al_params [0] : VECTOR [, WORD], w_initcr = aw_params [0] : WORD, w_minscr = aw_params [1] : WORD, w_initdg = aw_params [2] : WORD, w_blkpri = aw_params [3] : WORD; w_initcr = initcr; w_minscr = minscr; w_initdg = initdg; w_blkpri = blkpri; %IF %NULL (erradr) %THEN %ERROR ('Error address (ERRADR) is required') %FI scs$accept (cdt, msgadr, dgadr, erradr, .al_params [0], .al_params [1], condat, auxstr, badrsp %IF %NULL (retadr) %THEN , .r_stack_frame [sf$l_save_pc] %ELSE , retadr %FI ; cdt, cdtadr, pdt) END; call_accept (; cdt, cdtadr, pdt) END %; %SBTTL '_ALLOC_DG_BUF' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _alloc_dg_buf ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (.ref_pdt [pdt$l_allocdg]) END %; %SBTTL '_ALLOC_MSG_BUF' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _alloc_msg_buf ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (.ref_pdt [pdt$l_allocmsg]) END %; %SBTTL '_ALLOC_RSPID' !+ ! FUNCTIONAL DESCRIPTION: ! ?? ! ! INPUTS: ! cdrp Pointer to context block (usually CDRP). ! ! OUTPUTS: ! rspid RSPID. ! ! rdte Pointer to RDTE. ! ! VALUE: ! None. !- KEYWORDMACRO _alloc_rspid ( cdrp, rspid, rdte) = BEGIN LINKAGE alloc_rspid_linkage = JSB (REGISTER = 5; REGISTER = 1, REGISTER = 2) : PRESERVE (0, 3, 4); EXTERNAL ROUTINE scs$alloc_rspid : alloc_rspid_linkage ADDRESSING_MODE (GENERAL); scs$alloc_rspid (cdrp; rspid, rdte) END %; %SBTTL '_BT_TIMEWAIT' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! rpb ! ! time ! ! tst_field ! ! sense ! ! units ! ! VALUE: ! !- KEYWORDMACRO _bt_timewait ( rpb, time, tst_field, sense = 1, units = sec ) = NOT BEGIN BIND r_rpb = rpb : BLOCK [, BYTE], al_iovec = .r_rpb [rpb$l_iovec] : BLOCK [, BYTE]; DECR i FROM (time %IF %IDENTICAL (units, 'USEC') %THEN /10 %ELSE %IF %IDENTICAL (units, 'MSEC') %THEN *100 %ELSE %IF %IDENTICAL (units, 'SEC') %THEN *1000*100 %FI %FI %FI )*.al_iovec [bqo$l_tenusec] - 1 TO 1 DO BEGIN IF sense XOR tst_field THEN EXITLOOP NOT ss$_normal; DECR j FROM .al_iovec [bqo$l_ubdelay] - 1 TO 1 DO __nothing; END END %; %SBTTL '_BT_TIMEDWAIT' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! rpb ! ! time ! ! codblk ! ! units ! ! VALUE: ! !- KEYWORDMACRO _bt_timedwait ( rpb, time, codblk, units = sec ) = NOT BEGIN BIND r_rpb = rpb : BLOCK [, BYTE], al_iovec = .r_rpb [rpb$l_iovec] : BLOCK [, BYTE]; DECR i FROM (time %IF %IDENTICAL (units, 'USEC') %THEN /10 %ELSE %IF %IDENTICAL (units, 'MSEC') %THEN *100 %ELSE %IF %IDENTICAL (units, 'SEC') %THEN *1000*100 %FI %FI %FI )*.al_iovec [bqo$l_tenusec] - 1 TO 1 DO BEGIN %IF NOT %NULL (codblk) %THEN IF codblk THEN EXITLOOP NOT ss$_normal; %FI DECR j FROM .al_iovec [bqo$l_ubdelay] - 1 TO 1 DO __nothing; END END %; %SBTTL '_BUGCHK - Generate operating bug check' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! subsystem ! ! error ! ! type ! ! callop ! ! mode ! ! VALUE: ! !- KEYWORDMACRO _bugchk ( subsystem, error, type = cont, callop = op$_bsbw, mode = WORD_RELATIVE ) = BEGIN COMPILETIME string_size = %CHARCOUNT (subsystem) + 1 + %CHARCOUNT (error) + 1; MACRO __asciz (fld_off, str_text) = __ascii (fld_off, %EXPLODE (str_text)), [fld_off + string_size - 1, 0, 8, 0] = 0 %QUOTE %; MACRO __ascii (fld_off) [character] = [fld_off + %COUNT, 0, 8, 0] = character %QUOTE %; LINKAGE bugchk_linkage = JSB; %IF %IDENTICAL (type, 'FATAL') %THEN EXTERNAL ROUTINE exe$bugchkfatal; %ELSE EXTERNAL ROUTINE exe$bugchkcont; %FI OWN call_code : BLOCK [16 + string_size, BYTE] PRESET ( [0, 0, 8, 0] = op$_movl, [1, 0, 8, 0] = %X'8E' , ! (SP)+ [2, 0, 8, 0] = %X'AF', ! B^ [3, 0, 8, 0] = call_code [11 + string_size, 0, 32, 0] - call_code [4, 0, 0, 0], ! D [4, 0, 8, 0] = callop, %IF %IDENTICAL (type, 'FATAL') %THEN [5, 0, 32, 0] = exe$bugchkfatal, %ELSE [5, 0, 32, 0] = exe$bugchkcont, %FI ! [9, 0, 16, 0] = ! BUGCHECK string (ASCIZ); handled below __asciz (9, %STRING (subsystem, '_', error)), ! BUGCHECK string (ASCIZ) [9 + string_size, 0, 8, 0] = op$_jmp, [10 + string_size, 0, 8, 0] = %X'9F', ! @# [11 + string_size, 0, 32, 0] = 0); ! location JSB (call_code [0, 0, 0, 0]); END %; %SBTTL '_BUG_CHECK - Generate system internal bug check' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! error One to six character error name. ! ! type "FATAL" or anything else. ! ! VALUE: ! !- KEYWORDMACRO _bug_check ( error, type = cont ) = BEGIN BUILTIN BUGW; EXTERNAL LITERAL %NAME ('BUG$_', error); %IF %IDENTICAL (type, fatal) %THEN BUGW (%NAME ('BUG$_', error) OR sts$k_severe) %ELSE BUGW(%NAME ('BUG$_', error)) %FI END %; %SBTTL '_CONFIG_PTH' !+ ! FUNCTIONAL DESCRIPTION: ! Searches the path blocks on all systems blocks for one with a matching station ! address and local port name. If none is found, then error is returned. Otherwise, ! most of the path block information is returned in the caller's output array plus ! the system ID of the remote system on this path and the station address of the ! next path to this remote system. If there are no more paths, the remote station ! ID returned is -1. ! ! A fork process interested in discovering all paths to a particular system first ! issues a _CONFIG_SYS call to learn the station address/local port name of the ! first path to the system. The fork process then calls this macro repeatedly ! until a next station address of -1 is returned. ! ! INPUTS: ! staadr Address of station address followed by local port name: ! ! +--------+---------+--------+--------+ ! | Remote station addr, l.o. | ! +--------+---------+--------+--------+ ! | unused | Rstation, h.o. | ! +--------+---------+--------+--------+ ! | Local port name, e.g. PAA0 | ! +--------+---------+--------+--------+ ! ! outbuf Address of output buffer to return path information ! ! OUTPUTS: ! pthblk Address of path block found. Only valid if successful. ! ! VALUE: ! Status of routine call to SCS$CONFIG_PTH. !- KEYWORDMACRO _config_pth ( staadr = 0, outbuf = 0, pthblk) = BEGIN LINKAGE scs_linkage = JSB (REGISTER = 1, REGISTER = 2; REGISTER = 1) : PRESERVE (2, 3, 4, 5); EXTERNAL ROUTINE scs$config_pth : scs_linkage ADDRESSING_MODE (GENERAL); scs$config_pth (staadr, outbuf; pthblk) END %; %SBTTL '_CONFIG_SYS' !+ ! FUNCTIONAL DESCRIPTION: ! Searches the list of system blocks until it finds one with a system ID matching ! the specified ID. If no match is found, error is returned. Otherwise, most of ! the system block is returned to the caller together ith the ID of the next system ! in the list. ! ! A fork process interested in finding out about all the systems in the configuration ! simply issues successive calls to this macro on the next system ID until the ! returned next system ID is 0. To get information about the first system, specify ! system id of 0. There is a possibility that the configuration will chage between ! calls unless the entire configuration scan is conducted at SCS IPL or higher. ! ! INPUTS: ! sysadr Address of system ID to search for. ! ! outbuf Address of output buffer to return system information. ! ! OUTPUTS: ! sysblk Address of system block found. Only valid if successful. ! ! VALUE: ! !- KEYWORDMACRO _config_sys ( sysadr = 0, outbuf = 0, sysblk) = BEGIN LINKAGE scs_linkage = JSB (REGISTER = 1, REGISTER = 2; REGISTER = 1) : PRESERVE (2, 3, 4, 5); EXTERNAL ROUTINE scs$config_sys : scs_linkage ADDRESSING_MODE (GENERAL); scs$config_sys (sysadr, outbuf; sysblk) END %; %SBTTL '_CONNECT' !+ ! FUNCTIONAL DESCRIPTION: ! ?? ! ! INPUTS: ! msgadr Input address. ! ! dgadr Datagram input address. ! ! erradr Error address. ! ! rsysid Address of remote system ID. ! ! rstadr Address of remote station address. ! ! rprnam Address of remote process name. ! ! lprnam Address of local process name. ! ! initcr Initial credit value. ! ! minscr Minimum send credit value. ! ! initdg Initial datagram credit value. ! ! blkpri Block transfer priority. ! ! condat Address of connect data. ! ! auxstr Address of auxilary structure. ! ! badrsp Bad response packet address. ! ! retadr Return address. ! ! OUTPUTS: ! cdtblk Address of CDT allocated. Only valid if successful. ! ! pdt Address of PDT for this station address. ! ! VALUE: ! Status of routine call to SCS$CONNECT. !- KEYWORDMACRO _connect ( msgadr = 0, dgadr = 0, erradr, rsysid = 0, rstadr = 0, rprnam = 0, lprnam = 0, initcr = 0, minscr = 0, initdg = 0, blkpri = 0, condat = 0, auxstr = 0, badrsp = 0, retadr, cdtblk, pdt) = BEGIN LINKAGE call_connect_linkage = CALL (; REGISTER = 3, REGISTER = 4); ROUTINE call_connect ( ; cdtblk, pdt) : call_connect_linkage = BEGIN BUILTIN FP; LINKAGE connect_linkage = JSB (; REGISTER = 3, REGISTER = 4) : NOPRESERVE (1, 2) PRESERVE (5); EXTERNAL ROUTINE scs$connect : connect_linkage ADDRESSING_MODE (GENERAL); LOCAL al_params : VECTOR [2, LONG], l_status; BIND r_stack_frame = .FP : BLOCK [, BYTE], aw_params = al_params [0] : VECTOR [, WORD], w_initcr = aw_params [0] : WORD, w_minscr = aw_params [1] : WORD, w_initdg = aw_params [2] : WORD, w_blkpri = aw_params [3] : WORD; w_initcr = initcr; w_minscr = minscr; w_initdg = initdg; w_blkpri = blkpri; %IF %NULL (erradr) %THEN %ERROR ('Error address (ERRADR) is required') %FI l_status = scs$connect (msgadr, dgadr, erradr, rsysid, rstadr, rprnam, lprnam, .al_params [0], .al_params [1], condat, auxstr, badrsp, %IF %NULL (retadr) %THEN , .r_stack_frame [sf$l_save_pc] %ELSE , retadr %FI ; cdtblk, pdt) END; call_connect (; cdtblk, pdt) END %; %SBTTL '_DDTAB' !+ ! FUNCTIONAL DESCRIPTION: ! This macro generates a driver-dispatch table labeled devnam$DDT. ! ! INPUTS: ! devnam Generic name of the device. ! ! start Address of the start-I/O routine. 0 => IOC$RETURN. ! ! unsolic Address of the unsolicited-interrupt-servicing routine. 0 => IOC$RETURN. ! ! functb Address of the function-decision table. ! ! cancel Address of the cancel-I/O routine. 0 => IOC$RETURN. ! ! regdmp Address of the register-dumping routine. 0 => IOC$RETURN. ! ! diagbf Length, in bytes, of the diagnostic buffer. ! ! erlgbf Length, in bytes, of the error-logging buffer. ! ! unitinit Address of the unit-initialization routine. 0 => IOC$RETURN. ! ! altstart Address of the alternate start-I/O routine. 0 => IOC$RETURN. ! ! mntver Address of the mount-verification routine; the default is suitable ! for all single-stream disk drives. ! ! cloneducb Address of the routine called when a UCB is cloned by the $ASSIGN ! system service. 0 => IOC$RETURN. ! ! mntv_sssc 0 => IOC$RETURN. ! ! mntv_for 0 => IOC$RETURN. ! ! mntv_sqd 0 => IOC$RETURN. ! ! aux_storage Address of auxiliary storage area. ! ! aux_routine Address of auxiliary routine. ! ! legal List of legal I/O function codes without the leading IO$_. ! ! buffered List of buffered I/O function codes without the leading IO$_. ! ! actions Action/function code list tuple for each FDT action to be taken. ! ! VALUE: ! !- KEYWORDMACRO _ddtab ( devnam, start = 0, unsolic = 0, functb, cancel = 0, regdmp = 0, diagbf = 0, erlgbf = 0, unitinit = 0, altstart = 0, mntver = 'IOC$MNTVER', cloneducb = 0, mntv_sssc = 0, mntv_for = 0, mntv_sqd = 0, aux_storage = 0, aux_routine = 0, legal, buffered, actions) = !+ ! FUNCTIONAL DESCRIPTION: ! Used to count the number of tuples passed as a single argument. ! ! INPUTS: ! tuple_size The size (in arguments) of each tuple to follow. ! ! %REMAINING The tuples to be counted. ! ! EXPANSION: ! The number of tuples of specified size (in arguments). Partial tuples are ! not counted. !- MACRO __tuple_count (tuple_size) = (%LENGTH - 1) %QUOTE %; !+ ! FUNCTIONAL DESCRIPTION: ! This macro generates an entry for a function descision table. ! ! INPUTS: ! action Routine to call when the function code specified in the I/O request ! matches the code argument to this macro; if this is to be the first or ! second entry in the table, this argument must not be supplied. ! ! codes Code or codes for which the routine specified in the first argument ! to this macro is to be called; the codes are specified as the I/O-function ! codes of the form, IO$_xxx, but without the IO$_ prefix; if more than one ! code is specified then they must be enclosed within angle brackets (<>). ! ! EXPANSION: ! !- MACRO __functab_1 (action, codes) = OWN functable : ALIGN (0) BITVECTOR [64] PSECT ($$$115_driver) %IF NOT %NULL (codes) %THEN PRESET (__setbit (%REMOVE (codes))) %FI ; %IF NOT %NULL (action) %THEN OWN actaddr : ALIGN (0) PSECT ($$$115_driver) INITIAL (_genraddr (action, actaddr + 8)); UNDECLARE actaddr; %FI UNDECLARE functable; %QUOTE %; !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! ! ! EXAPNSION: ! !- MACRO __functab [tuple] = __functab_1 (%REMOVE (tuple)) %QUOTE %; !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! ! ! EXAPNSION: ! !- MACRO __genraddr (address) = _genraddr (address, %NAME (devnam, '$DDT')) %QUOTE %; !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! ! ! EXAPNSION: ! !- MACRO __setbit [CODE] = [%quotename ('IO$_', CODE)] = 1 %QUOTE %; FORWARD functb : VECTOR [0, BYTE] PSECT ($$$115_driver); GLOBAL %NAME (devnam, '$DDT') : BLOCK [ddt$k_length, BYTE] PSECT ($$$115_driver) ! PRESET ( ! [ddt$l_start] = __genraddr (start), ! Address of driver start I/O routine [ddt$l_unsolint] = __genraddr (unsolic), ! Address of unsolicited interrupt routine [ddt$l_fdt] = __genraddr (functb), ! Address of function decision table [ddt$l_cancel] = __genraddr (cancel), ! Address of cancel I/O entry point [ddt$l_regdump] = __genraddr (regdmp), ! Address of device register dump routine [ddt$w_diagbuf] = diagbf, ! Size of diagnostic buffer in bytes [ddt$w_errorbuf] = erlgbf, ! Size of error log buffer in bytes [ddt$l_unitinit] = __genraddr (unitinit), ! Unit initialization entry point [ddt$l_altstart] = __genraddr (altstart), ! Alternate start I/O entry point [ddt$l_mntver] = __genraddr (mntver), ! Address of mount verification routine [ddt$w_fdtsize] = 16 + (__tuple_count (2, %REMOVE (actions))*12), ! Size of FDT in bytes [ddt$l_cloneducb] = __genraddr (cloneducb), ! Address of cloned UCB entry point [ddt$l_mntv_sssc] = __genraddr (mntv_sssc), ! Address of shadow set state change MV entry [ddt$l_mntv_for] = __genraddr (mntv_for), ! Address of foreign device MV entry [ddt$l_mntv_sqd] = __genraddr (mntv_sqd) ! Address of sequential device MV entry %IF %DECLARED (%NAME (ddt$l_aux_storage)) %THEN , [ddt$l_aux_storage] = __genraddr (aux_storage), ! Address of auxiliary storage area [ddt$l_aux_routine] = __genraddr (aux_routine) ! Address of auxiliary routine %FI ); OWN functb : ALIGN (0) VECTOR [0, BYTE] PSECT ($$$115_driver); __functab_1 (, legal); __functab_1 (, buffered); __functab (%REMOVE (actions)); UNDECLARE %QUOTE %QUOTE __genraddr, %QUOTE %QUOTE __tuple_count, %QUOTE %QUOTE __setbit; %; %SBTTL '_DEALLOC_DG_BUF' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _dealloc_dg_buf ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (.ref_pdt [pdt$l_deallocdg]) END %; %SBTTL '_DEALLOC_MSG_BUF' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _dealloc_msg_buf ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (.ref_pdt [pdt$l_deallomsg]) END %; %SBTTL '_DEALLOC_MSG_BUF_REG' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _dealloc_msg_buf_reg ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (.ref_pdt [pdt$l_dealrgmsg]) END %; %SBTTL '_DEALLOC_RSPID' !+ ! FUNCTIONAL DESCRIPTION: ! Check validity of the value in the CDRP$L_RSPID field. Increment the RDTE ! sequence number. ! ! Dequeue next waiter for an RDTE and start it up. If no waiter to dequeue, ! set the RDTE state to unallocated, link RDTE as first entry in the free list ! and return. ! ! INPUTS: ! cdrp Address of CDRP. ! ! VALUE: ! None. !- KEYWORDMACRO _dealloc_rspid ( cdrp) = BEGIN LINKAGE deall_rspid_linkage = JSB (REGISTER = 5) : NOPRESERVE (0, 1, 2) PRESERVE (3, 4, 5); EXTERNAL ROUTINE scs$deall_rspid : deall_rspid_linkage ADDRESSING_MODE (GENERAL); scs$deall_rspid (cdrp); END %; %SBTTL '_DECREF - Decrement page reference count' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pfn Address of PFN. ! ! mode Addressing mode, default is word displacement. ! ! call Mode to use when calling MMG$REFCNTNEG. ! ! VALUE: ! !- KEYWORDMACRO _decref ( pfn, mode = WORD_RELATIVE, CALL = WORD_RELATIVE ) = BEGIN EXTERNAL pfn$aw_refcnt : REF VECTOR [, WORD] ADDRESSING_MODE (mode); EXTERNAL ROUTINE mmg$refcntneg : ADDRESSING_MODE (CALL); IF (pfn$aw_refcnt [pfn] = .pfn$aw_refcnt [pfn] - 1) LSS 0 THEN mmg$refcntneg (); .pfn$aw_refcnt [pfn] END %; %SBTTL '_DECSHR - Decrement page share count' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pfn PFN whose share count is to be decremented. ! ! mode Addressingh mode to be used. ! ! image Set to SYS_NONPAGED if INIT does fixup. ! ! VALUE: ! !- KEYWORDMACRO _decshr ( pfn, mode = GENERAL, image = nosys ) = BEGIN LOCAL pfn_l_shrcnt; EXTERNAL ROUTINE mmg$shrcntneg : ADDRESSING_MODE (mode); pfn_l_shrcnt = _pfn_reference (pfn$ax_shrcnt, 'pfn$ax_shrcnt [pfn] = .pfn$ax_shrcnt [pfn] - 1', mode, image); IF (.pfn_l_shrcnt) LSS 0 THEN mmg$shrcntneg (); .pfn_l_shrcnt END %; %SBTTL '_DISCONNECT' !+ ! FUNCTIONAL DESCRIPTION: ! ?? ! ! If state was listen then directory entry removed and CDT deallocated. ! ! INPUTS: ! distyp ?? ! ! VALUE: ! Status of routine call to SCS$DISCONNECT. !- KEYWORDMACRO _disconnect ( distyp) = BEGIN LINKAGE disconnect_linkage = JSB (REGISTER = 0); EXTERNAL ROUTINE scs$disconnect : disconnect_linkage ADDRESSING_MODE (GENERAL); scs$disconnect (distyp) END %; %SBTTL '_DPTAB' !+ ! FUNCTIONAL DESCRIPTION: ! This macro generates a driver-prologue table in a program section called $$$105_PROLOGUE. ! ! INPUTS: ! devnam Generic name of the device. ! ! adapter Type of adapter, e.g. UBA, MBA, DR, NULL. ! ! flags Flags used in loading the driver. ! ! ucbsize Size, in bytes, of the unit-control block required by each ! device that this driver will drive. ! ! unload Address of the routine in the driver that SYSGEN is to call ! before unloading the driver and loading a new version of the driver. ! ! maxunits Maximum number of device units that can be connected to the ! controller. ! ! defunits Maximum number of UCBs to be created by SYSGEN's AUTOCONFIGURE ! command (one for each device unit to be configured). ! ! deliver Address of the routine in the driver that determines whether a ! unit should be configured automatically, the unit-delivery routine. ! ! vec Reserved to DIGITAL; the address of a driver-specific transfer vector. ! ! name Name of the device driver. ! ! dpt_psect ! ! smp ! ! decode ! ! VALUE: ! !- KEYWORDMACRO _dptab ( devnam, adapter, flags = 0, ucbsize, unload, maxunits = 8, defunits = 1, deliver, vec, name, dpt_psect = $$$105_prologue, smp = no, decode, init, reinit) = !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! ! ! EXAPNSION: ! !- MACRO __ascic (fld_off, fld_pos, fld_siz, fld_ext, str_siz, str_text) = %IF fld_pos NEQ 0 %THEN %ERROR ('String does not begin on a BYTE boundary') %FI %IF str_siz LSS (1 + %CHARCOUNT (str_text)) %THEN %ERROR ('Insufficient space for string') %FI [fld_off, 0, 8, 0] = %CHARCOUNT (str_text), __ascii (fld_off + 1, %EXPLODE (str_text)) %QUOTE %; !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! ! ! EXAPNSION: ! !- MACRO __ascii (fld_off) [character] = [fld_off + %COUNT, 0, 8, 0] = character %QUOTE %; !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! ! ! EXAPNSION: ! !- MACRO __byte = 0, 8, 0 %QUOTE %; !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! ! ! EXAPNSION: ! !- MACRO __convert_op (char) [] = %IF %IDENTICAL (char, '@') %THEN %ASSIGN ($$op, %X'80') %ELSE %IF %IDENTICAL (char, 'W') %THEN %ASSIGN ($$op, $$op OR 1) %ELSE %IF %IDENTICAL (char, 'D') %THEN %ASSIGN ($$op, $$op OR 2) %ELSE %IF %IDENTICAL (char, 'L') %THEN %ASSIGN ($$op, $$op OR 3) %ELSE %IF %IDENTICAL (char, 'V') %THEN %ASSIGN ($$op, $$op OR 4) %FI %FI %FI %FI %FI %QUOTE __convert_op (%REMAINING) %QUOTE %; !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! ! ! EXAPNSION: ! !- MACRO __dpt_store [tuple] = __dpt_store_1 (%REMOVE (tuple)) %QUOTE %; !+ ! FUNCTIONAL DESCRIPTION: ! This macro, used within _DPTAB, builds the table which instructs the system's driver-loading ! procedure to store value(s) in device driver data structure(s). ! ! INPUTS: ! str_type The type of control block into which the data is to be stored (DDB, ! UCB, ORB, CRB or IDB). ! ! str_off The offset, in bytes, from the begining of the data structure at ! which the data is to be stored. ! ! str_pos The offset, in bits, from the position specified by STR_OFF at ! which the data is to be stored. Not used; only present so field ! macros may be used. ! ! str_siz The size, in bits, of the field at which the data is to be stored. ! Only used if OPER='V'. ! ! str_ext The sign extension flag of the field at which the data is to be ! stored. Only used if OPER='V'. ! ! oper The type of storage operation, one of the following: ! 'B' Byte ! 'W' Word ! 'L' Longword ! 'D' Address relative to the begining of the driver ! 'V' Bit field ! If an at-sign character (@) precedes the OPER argument, then the ! EXP argument describes the address of the data with which to ! initialize the field, e.g. '@B'. ! ! exp The value with which to initialize the field; if OPER is preceded ! by an at-sign (@), then the address at which to find the value ! with which to initialize the field. ! ! EXPANSION: ! !- MACRO __dpt_store_1 [str_type, str_off, str_pos, str_siz, str_ext, oper, exp] = COMPILETIME $$op = 0; __convert_op (oper); %IF str_off LSSU 255 %THEN OWN dpt : ALIGN (0) VECTOR [2, BYTE] PSECT ($$$105_prologue) ! INITIAL (BYTE (%NAME ('DPT$K_STRUC_', str_type), str_off)); %ELSE OWN dpt : ALIGN (0)BYTE PSECT ($$$105_prologue) ! INITIAL (BYTE (%NAME ('DPT$K_STRUC_', str_type) OR dpt$m_struc_wrd)); UNDECLARE dpt; OWN dpt : ALIGN (0)WORD PSECT ($$$105_prologue) ! INITIAL (WORD (str_off)); %FI UNDECLARE dpt; OWN dpt : ALIGN (0)BYTE PSECT ($$$105_prologue) INITIAL (BYTE ($$op)); UNDECLARE dpt; %IF $$op EQLU 0 %THEN OWN dpt : ALIGN (0)BYTE PSECT ($$$105_prologue) INITIAL (BYTE (exp)); %ELSE %IF $$op EQLU 1 %THEN OWN dpt : ALIGN (0)WORD PSECT ($$$105_prologue) INITIAL (WORD (exp)); %ELSE %IF $$op EQLU 2 %THEN OWN dpt : ALIGN (0)WORD PSECT ($$$105_prologue) INITIAL (WORD (exp - dpt_tab)); %ELSE OWN dpt : ALIGN (0)LONG PSECT ($$$105_prologue) INITIAL (LONG (exp)); %IF ($$op AND ( NOT %X'80')) EQLU 4 %THEN OWN dpt_v : ALIGN (0)BYTE PSECT ($$$105_prologue) INITIAL (BYTE (str_pos, str_siz)); UNDECLARE dpt_v; %FI %FI %FI %FI UNDECLARE dpt, $$op; %QUOTE %; !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! ! ! EXAPNSION: ! !- MACRO __long = 0, 32, 0 %QUOTE %; !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! ! ! EXAPNSION: ! !- MACRO __reladdr (address) = %IF NOT %NULL (address) %THEN address - dpt_tab %ELSE 0 %FI %QUOTE %; MACRO __word = 0, 16, 0 %QUOTE %; !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! ! ! EXAPNSION: ! !- MACRO __zero (fld_off, fld_pos, fld_siz, fld_ext, siz) [] = %IF fld_pos NEQ 0 %THEN %ERROR ('Field does not begin on a BYTE boundary') %FI [fld_off + %COUNT, 0, 8, 0] = 0 %IF (%COUNT + 1) LSSU siz %THEN , __zero (fld_off, fld_pos, fld_siz, fld_ext, siz) %FI %QUOTE %; FORWARD dpt_initab : VECTOR [0, BYTE] PSECT (dpt_psect), dpt_reinitab : VECTOR [0, BYTE] PSECT (dpt_psect); OWN %NAME (devnam, '_B_END') : VECTOR [0, BYTE] PSECT ($$$125_epilogue); OWN dpt_tab : BLOCK [dpt$k_length, BYTE] PSECT (dpt_psect) ! PRESET ( ! [dpt$w_size] = %NAME (devnam, '_B_END') - dpt_tab, ! Size of driver [dpt$b_type] = dyn$c_dpt, ! Structure type [dpt$b_refc] = 0, ! Count of DDB's that reference driver [dpt$b_adptype] = %NAME ('AT$_', adapter), ! Adapter type code [dpt$w_ucbsize] = ucbsize, ! Size of UCB [dpt$l_flags] = flags OR ! Driver loader flags %IF %IDENTICAL (smp, yes) %THEN dpt$m_smpmod %ELSE 0 %FI , [dpt$w_inittab] = dpt_initab - dpt_tab, ! Offset to init table [dpt$w_reinittab] = dpt_reinitab - dpt_tab, ! Offset to re-init table [dpt$w_unload] = __reladdr (unload), ! Offset to unload action routine [dpt$w_maxunits] = maxunits, ! Maximum units that can be connected [dpt$w_version] = dpt$c_version, ! Driver prologue version number [dpt$w_defunits] = defunits, ! Default number of units [dpt$w_deliver] = __reladdr (deliver), ! Offset to driver unit delivery routine [dpt$w_vector] = __reladdr (vec), ! Offset to vector table (in TTDRIVER) __ascic (dpt$t_name, dpt$s_name, name), ! Driver name (counted string) __zero (dpt$q_linktime, dpt$s_linktime), ! Link date and time from image header [dpt$l_ecolevel] = 0 ! ECO level from image header %IF %DECLARED (%NAME (dpt$q_lmf_1)) %THEN , __zero (dpt$q_lmf_1, dpt$s_lmf_1), ! Reserved space for LMF __zero (dpt$q_lmf_2, dpt$s_lmf_2), ! Reserved space for LMF __zero (dpt$q_lmf_3, dpt$s_lmf_3), ! Reserved space for LMF __zero (dpt$q_lmf_4, dpt$s_lmf_4), ! Reserved space for LMF __zero (dpt$q_lmf_5, dpt$s_lmf_5), ! Reserved space for LMF __zero (dpt$q_lmf_6, dpt$s_lmf_6), ! Reserved space for LMF __zero (dpt$q_lmf_7, dpt$s_lmf_7), ! Reserved space for LMF __zero (dpt$q_lmf_8, dpt$s_lmf_8), ! Reserved space for LMF [dpt$w_decw_sname] = __reladdr (decode) ! Offset to counted ASCII string %FI ); OWN dpt_initab : ALIGN (0) VECTOR [0, BYTE] PSECT ($$$105_prologue); __dpt_store (%REMOVE (init)); OWN dpt_reinitab : ALIGN (0) VECTOR [0, BYTE] PSECT ($$$105_prologue); __dpt_store (%REMOVE (reinit)); OWN dpt : ALIGN (0)BYTE PSECT ($$$105_prologue) INITIAL (BYTE (0)); UNDECLARE %QUOTE %QUOTE __ascic, %QUOTE %QUOTE __byte, %QUOTE %QUOTE __convert_op, dpt, %QUOTE %QUOTE __long, %QUOTE %QUOTE __reladdr, %QUOTE %QUOTE __word; %; %SBTTL '_DSBINT - Disable interrupts' !+ ! FUNCTIONAL DESCRIPTION: ! Disables interrupts occurring at or below the specified IPL and saves the current IPL ! in the specified longword. ! ! INPUTS: ! ipl IPL at which to block interrupts. If no IPL is specified, the default is ! IPL$_POWER which blocks all interrupts. ! ! dst Location in which to save the current IPL. If no destination is specified, ! the current IPL is pushed on the stack. ! ! VALUE: ! !- KEYWORDMACRO _dsbint ( ipl = %REF ( ipl$_power ), dst) = BEGIN BUILTIN MFPR, MTPR; %IF %NULL (dst) %THEN BEGIN BUILTIN SP; SP = .SP - 4; MFPR (pr$_ipl, .SP); END; %ELSE MFPR (pr$_ipl, dst); %FI MTPR (ipl, pr$_ipl); END; %; %SBTTL '_ENBINT - Enable interrupts' !+ ! FUNCTIONAL DESCRIPTION: ! Enables interrupts at a specified IPL or at the IPL stored on the stack. ! ! INPUTS: ! src Address of IPL at which to enable interrupts. If no address is specified, ! the IPL is popped from the top of the current stack. ! ! VALUE: ! !- KEYWORDMACRO _enbint ( src) = BEGIN BUILTIN MTPR; %IF %NULL (src) %THEN BEGIN BUILTIN SP; MTPR (.SP, pr$_ipl); SP = .SP + 4; END; %ELSE MTPR (src, pr$_ipl); %FI END; %; %SBTTL '_FORK - Create fork process' !+ ! FUNCTIONAL DESCRIPTION: ! Drivers use this macros to create, by calling EXE$FORK, a fork process, in which context ! the code following the macro invocation executes. ! ! NOTE: The stack pointer must point to a longword containing the address of the ! caller's caller when the macro is invoked. ! ! INPUTS: ! fbk Address of the fork block. ! ! fr3 Content's of the fork's R3. ! ! fr4 Content's of the fork's R4. ! ! VALUE: ! !- KEYWORDMACRO _fork ( fbk, fr3 = 0, fr4 = 0 ) = BEGIN LINKAGE exe$fork_linkage = JSB (REGISTER = 5; REGISTER = 4) : NOPRESERVE (3, 4) PRESERVE (0, 1, 2, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE exe$fork : exe$fork_linkage ADDRESSING_MODE (GENERAL); exe$fork (fr3, fr4, fbk) END %; %SBTTL '_FORK_WAIT - Fork and wait' !+ ! FUNCTIONAL DESCRIPTION: ! Folds a fork context into a fork block and places that block on the fork-and-wait ! work queue, EXE$GL_FKWAITFL. From zero to one second later, EXE$TIMEOUT will ! remove all entries in the fork-and-wait work queue and restart the fork thread ! saved here. ! ! NOTE: The stack pointer must point to a longword containing the address of the ! caller's caller when the macro is invoked. ! ! INPUTS: ! fbk Address of the fork block. ! ! fr3 Content's of the fork's R3. ! ! fr4 Content's of the fork's R4. ! ! VALUE: ! !- KEYWORDMACRO _fork_wait ( fbk, fr3 = 0, fr4 = 0 ) = BEGIN LINKAGE fork_linkage = JSB (REGISTER = 3, REGISTER = 4, REGISTER = 5) : PRESERVE (3, 4, 5); EXTERNAL ROUTINE exe$fork_wait : fork_linkage ADDRESSING_MODE (GENERAL); exe$fork_wait (fr3, fr4, fbk) END %; %SBTTL '_GENRADDR - Generate relative address' !+ ! FUNCTIONAL DESCRIPTION: ! This is an internal macro which generates relocatable (relative) addresses. ! ! INPUTS: ! address If zero then IOC$RETURN is result. If a string then string is result. ! Otherwise ADDRESS - BASE is result. ! ! base Base address to use in generating offset if ADDRESS is not zero or ! a string. ! ! VALUE: ! !- MACRO _genraddr (address, base) = %IF %IDENTICAL (address, 0) %THEN BEGIN LINKAGE ioc$return_linkage = JSB : NOTUSED (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$return : ioc$return_linkage NOVALUE ADDRESSING_MODE (GENERAL); ioc$return END %ELSE %IF %ISSTRING (address) %THEN BEGIN %IF NOT %DECLARED (%NAME (address)) %THEN EXTERNAL ROUTINE %NAME (address) : ADDRESSING_MODE (GENERAL); %FI %NAME (address) !!ERROR!! Incorrect block ending. END %ELSE address - base %FI %FI %; %SBTTL '_IFNORD - Test if range of addresses is not readable' !+ ! FUNCTIONAL DESCRIPTION: ! Uses the PROBER instruction to check the accessibility of the specified range of memory ! by checking the accessibility of the first and last bytes in that range. ! ! NOTE: This macro is slightly different from the MACRO version in that it returns a value ! rather than dispatching to a destination address. ! ! INPUTS: ! siz Offset to the last byte to check from the first byte to check, a number ! less than or equal to 512. ! ! adr Address of the first byte to check. ! ! mode Mode in which access is to be checked; zero, the default, causes the check ! to be performed in the mode contained in the previous mode field of the ! current PSL. ! ! VALUE: ! If both of the specified bytes can be read in the specified access mode, the macro ! returns a true value otherwise a false value. !- KEYWORDMACRO _ifnord ( siz, adr, mode = %REF ( 0 )) = BEGIN BUILTIN PROBER; NOT PROBER (mode, siz, adr) END %; %SBTTL '_IFNOWRT - Test if range of addresses is not writable' !+ ! FUNCTIONAL DESCRIPTION: ! Uses the PROBEW instruction to check the accessibility of the specified range of memory ! by checking the accessibility of the first and last bytes in that range. ! ! NOTE: This macro is slightly different from the MACRO version in that it returns a value ! rather than dispatching to a destination address. ! ! INPUTS: ! siz Offset to the last byte to check from the first byte to check, a number ! less than or equal to 512. ! ! adr Address of the first byte to check. ! ! mode Mode in which access is to be checked; zero, the default, causes the check ! to be performed in the mode contained in the previous mode field of the ! current PSL. ! ! VALUE: ! If both of the specified bytes can be written in the specified access mode, the macro ! returns a true value otherwise a false value. !- KEYWORDMACRO _ifnowrt ( siz, adr, mode = %REF ( 0 )) = BEGIN BUILTIN PROBEW; NOT PROBEW (mode, siz, adr) END %; %SBTTL '_IFNPRIV - Test if process does not have privilege' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! priv Privilege to be tested. ! ! pcb Address of PCB. ! ! VALUE: ! !- KEYWORDMACRO _ifnpriv ( priv, pcb) = BEGIN LOCAL privmsk : REF BLOCK [, BYTE], ref_pcb : REF BLOCK [, BYTE], ref_phd : REF BLOCK [, BYTE]; ref_pcb = pcb; ref_phd = .ref_pcb [pcb$l_phd]; privmsk = ref_phd [phd$q_privmsk]; NOT .privmsk [%NAME ('PRV$V_', priv)] END %; %SBTTL '_IFPRIV - Test if process has specified privilege' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! priv Needed privilege. ! ! pcb Address of PCB. ! ! VALUE: ! !- KEYWORDMACRO _ifpriv ( priv, pcb) = BEGIN LOCAL privmsk : REF BLOCK [, BYTE], ref_pcb : REF BLOCK [, BYTE], ref_phd : REF BLOCK [, BYTE]; ref_pcb = pcb; ref_phd = .ref_pcb [pcb$l_phd]; privmsk = ref_phd [phd$q_privmsk]; .privmsk [%NAME ('PRV$V_', priv)] END %; %SBTTL '_IFRD - Test if range of addresses is readable' !+ ! FUNCTIONAL DESCRIPTION: ! Uses the PROBER instruction to check the accessibility of the specified range of memory ! by checking the accessibility of the first and last bytes in that range. ! ! NOTE: This macro is slightly different from the MACRO version in that it returns a value ! rather than dispatching to a destination address. ! ! INPUTS: ! siz Offset to the last byte to check from the first byte to check, a number ! less than or equal to 512. ! ! adr Address of the first byte to check. ! ! mode Mode in which access is to be checked; zero, the default, causes the check ! to be performed in the mode contained in the previous mode field of the ! current PSL. ! ! VALUE: ! If either of the specified bytes cannot be read in the specified access mode, the macro ! returns a true value otherwise a false value. !- KEYWORDMACRO _ifrd ( siz, adr, mode = %REF ( 0 )) = BEGIN BUILTIN PROBER; PROBER (mode, siz, adr) END %; %SBTTL '_IFWRT - Test if range of addresses is writable' !+ ! FUNCTIONAL DESCRIPTION: ! Uses the PROBEW instruction to check the accessibility of the specified range of memory ! by checking the accessibility of the first and last bytes in that range. ! ! NOTE: This macro is slightly different from the MACRO version in that it returns a value ! rather than dispatching to a destination address. ! ! INPUTS: ! siz Offset to the last byte to check from the first byte to check, a number ! less than or equal to 512. ! ! adr Address of the first byte to check. ! ! mode Mode in which access is to be checked; zero, the default, causes the check ! to be performed in the mode contained in the previous mode field of the ! current PSL. ! ! VALUE: ! If either of the specified bytes cannot be written in the specified access mode, the macro ! returns a true value otherwise a false value. !- KEYWORDMACRO _ifwrt ( siz, adr, mode = %REF ( 0 )) = BEGIN BUILTIN PROBEW; PROBEW (mode, siz, adr) END %; %SBTTL '_INVALID - Invalidate translation buffer' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! addr ! ! reg ! ! VALUE: ! !- KEYWORDMACRO _invalid ( addr, reg) = BEGIN BUILTIN MTPR; %IF %NULL (addr) %THEN MTPR (%REF (0), pr$_tbia); %ELSE %IF %NULL (reg) %THEN MTPR (addr, pr$_tbis); %ELSE reg = addr; MTPR (reg, pr$_tbis); %FI %FI END %; %SBTTL '_IOFORK - Create I/O driver fork process' !+ ! FUNCTIONAL DESCRIPTION: ! Calls EXE$IOFORK to create a fork process for a device driver. Clears the bit ! UCB$V_TIM in the field UCB$L_STS, whereas the FORK macro does not. ! ! INPUTS: ! fbk Address of UCB that will be used as a fork block for the fork ! process to be created. ! ! fr3 Contents of fork's R3. ! ! fr4 Contents of fork's R4. ! ! VALUE: ! !- KEYWORDMACRO _iofork ( fbk, fr3 = 0, fr4 = 0 ) = BEGIN LINKAGE exe$iofork_linkage = JSB (REGISTER = 5; REGISTER = 4) : NOPRESERVE (3, 4) PRESERVE (0, 1, 2, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE exe$iofork : exe$fork_linkage ADDRESSING_MODE (GENERAL); exe$iofork (fr3, fr4, fbk) END %; %SBTTL '_LDP0LR - Load P0 space length register' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! src ! ! VALUE: ! !- KEYWORDMACRO _ldp0lr ( src) = BEGIN BUILTIN MTPR; MTPR (src, pr$_p0lr); END %; %SBTTL '_LDP1LR - Load P1 space length register' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! src ! ! VALUE: ! !- KEYWORDMACRO _ldp1lr ( src) = BEGIN BUILTIN MTPR; MTPR (src, pr$_p1lr); END %; %SBTTL '_LISTEN' !+ ! FUNCTIONAL DESCRIPTION: ! ?? ! ! Directory entry made if successful, CDT state set to listen. ! ! INPUTS: ! msgadr Address to call with CONNECT_REQ message. ! ! erradr Address to call with error in VC. ! ! lprnam Address of listening process name. ! ! prinfo Address of listening process information. ! ! retadr Return address. ! ! OUTPUTS: ! cdt Address of CDT. Only valid if successful. ! ! VALUE: ! Status of routine call to SCS$LISTEN. !- KEYWORDMACRO _listen ( msgadr = 0, erradr, lprnam = 0, prinfo = 0, retadr, cdt) = BEGIN LINKAGE call_listen_linkage = CALL (; REGISTER = 3); ROUTINE call_listen ( ; cdt) : call_listen_linkage = BEGIN BUILTIN FP; LINKAGE listen_linkage = JSB (; REGISTER = 3) : NOPRESERVE (1, 2) PRESERVE (4, 5); EXTERNAL ROUTINE scs$listen : listen_linkage ADDRESSING_MODE (GENERAL); LOCAL l_status; BIND r_stack_frame = .FP : BLOCK [, BYTE]; %IF %NULL (erradr) %THEN %ERROR ('Error address (ERRADR) is required') %FI l_status = scs$listen (msgadr, erradr, lprnam, prinfo %IF %NULL (retadr) %THEN , .r_stack_frame [sf$l_save_pc] %ELSE , retadr %FI ; cdt) END; call_listen (; cdt) END %; %SBTTL '_LOADMBA - Load MBA map registers' !+ ! FUNCTIONAL DESCRIPTION: ! Calls IOC$LOADMBAMAP to load MASSBUS mapping registers. The driver must own the MASSBUS adapter, ! and thus the mapping registers, before it can invoke this macro. ! ! INPUTS: ! ucb Address of UCB. ! ! csr Address of MBA's CSR. ! ! VALUE: ! !- KEYWORDMACRO _loadmba ( ucb, csr) = BEGIN LINKAGE ioc$loadmbamap_linkage = JSB (REGISTER = 4, REGISTER = 5) : NOPRESERVE (0, 1, 2) PRESERVE (3, 4, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$loadmbamap : ioc$loadmba_linkage NOVALUE ADDRESSING_MODE (GENERAL); ioc$loadmbamap (csr, ucb); END %; %SBTTL '_LOADUBA - Load UBA map registers' !+ ! FUNCTIONAL DESCRIPTION: ! Calls IOC$LOADUBAMAP to load the UNIBUS adapter's registers. The registers must already be allocated ! before this macro is invoked. ! ! INPUTS: ! ucb Address of the UCB. ! ! VALUE: ! !- KEYWORDMACRO _loaduba ( ucb) = BEGIN LINKAGE ioc$loadubamap_linkage = JSB (REGISTER = 5) : NOPRESERVE (0, 1, 2) PRESERVE (3, 4, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$loadubamap : ioc$loadubamap_linkage NOVALUE ADDRESSING_MODE (GENERAL); ioc$loadubamap (ucb); END %; %SBTTL '_LOADUBAA - Load UBA map registers, alternate entry point' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! ucb ! ! VALUE: ! !- KEYWORDMACRO _loadubaa ( ucb) = BEGIN LINKAGE ioc$loadubamapa_linkage = JSB (REGISTER = 5) : NOPRESERVE (0, 1, 2) PRESERVE (3, 4, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$loadubamapa : ioc$loadubamapa_linkage NOVALUE ADDRESSING_MODE (GENERAL); ioc$loadubamapa (ucb); END %; %SBTTL '_LOCK - Set a lock bit and retry if failure' !+ ! FUNCTIONAL DESCRIPTION: ! Interrupts are disabled and the bit tested. If the bit was already set ! then exit with error. If the bit was not set then loop testing the bit ! for EXE$GL_LOCKRTRY times. Exit with the bit set at IPL$_POWER unless ! timeout. If timeout then lower IPL to saved IPL. ! ! INPUTS: ! bit_field Field refence of bit to be set. ! ! VALUE: ! Success if flag set within timeout. Failure otherwise. !- KEYWORDMACRO _lock ( bit_field, dst) = NOT BEGIN EXTERNAL exe$gl_locktry : ADDRESSING_MODE (GENERAL); DECR i FROM .exe$gl_locktry TO 1 DO BEGIN BUILTIN TESTBITSSI; _dsbint (dst = dst, ipl = %REF (ipl$_power)); IF NOT TESTBITSSI (bit_field) THEN EXITLOOP 0; _enbint (src = dst); END END %; %SBTTL '_MAP' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _map ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (.ref_pdt [pdt$l_map]) END %; %SBTTL '_MAP_BYPASS' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _map_bypass ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (.ref_pdt [pdt$l_mapbypass]) END %; %SBTTL '_MAP_IRP' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _map_irp ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (.ref_pdt [pdt$l_mapirp]) END %; %SBTTL '_MAP_IRP_BYPASS' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _map_irp_bypass ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (.ref_pdt [pdt$l_mapirpbyp]) END %; %SBTTL '_MRESET' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! rstadr ! ! flag ! ! start ! ! VALUE: ! !- KEYWORDMACRO _mreset ( pdt, rstadr, flag = 1, start = 0 ) = BEGIN LINKAGE pdt_linkage = JSB (REGISTER = 0, REGISTER = 1, REGISTER = 2); LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; pdt_linkage (.ref_pdt [pdt$l_mreset], flag, rstadr, start) END %; %SBTTL '_MSTART' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! rstadr ! ! flag ! ! start ! ! VALUE: ! !- KEYWORDMACRO _mstart ( pdt, rstadr, flag = 1, start = 0 ) = BEGIN LINKAGE pdt_linkage = JSB (REGISTER = 0, REGISTER = 1, REGISTER = 2); LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; pdt_linkage (.ref_pdt [pdt$l_mstart], flag, rstadr, start) END %; %SBTTL '_PFN_REFERENCE - Reference a PFN array' !+ ! FUNCTIONAL DESCRIPTION: ! Executes a specified operation on either a word or longword PFN array. ! ! INPUTS: ! pfn_array PFN array to be referenced. ! ! operation Operation to be performed enclosed within ! quote marks. ! ! mode Addressing mode to use. ! ! image Set to SYS_NONPAGED if INIT does fixup. ! ! VALUE: ! Result of 'operation'. !- MACRO _pfn_reference (pfn_array, operation, mode, image) = %IF %IDENTICAL (image, 'SYS_NONPAGED') %THEN %ERRORMACRO ('SYS_NONPAGED image flag not currently supported') %FI BEGIN EXTERNAL mmg$gw_bigpfn : WORD ADDRESSING_MODE (mode); IF .mmg$gw_bigpfn EQLU 0 THEN BEGIN EXTERNAL pfn_array : REF VECTOR [, WORD] ADDRESSING_MODE (mode); operation END ELSE BEGIN EXTERNAL pfn_array : REF VECTOR [, LONG] ADDRESSING_MODE (mode); operation END END %; %SBTTL '_PURDPR - Purge data path' !+ ! FUNCTIONAL DESCRIPTION: ! Calls IOC$PURGDATAP to purge a data path. ! ! INPUTS: ! ucb Address of the UCB. ! ! dpr Set to the status of the purge (success or failure). ! ! mapreg Set to the contents of the data-path register, provided ! for the use of the driver's register-dumping routine. ! ! crb Set to the address of the first mapping register, provided ! for the use of the driver's register dumping routine. ! ! VALUE: ! !- KEYWORDMACRO _purdpr ( ucb, dpr, mapreg, crb) = BEGIN LINKAGE ioc$purgdatap_linkage = JSB (REGISTER = 5; REGISTER = 1, REGISTER = 2, REGISTER = 3) : NOPRESERVE (0, 1, 2, 3) PRESERVE (4, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$purgdatap : ioc$purgdatap_linkage ADDRESSING_MODE (GENERAL); %IF NOT %NULL (dpr) %THEN dpr = %ELSE ioc$purgdatap (ucb; mapreg, crb) %FI END %; %SBTTL '_QRETRY - Execute interlocked queue instruction and retry if failure' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! setclr ! ! tst_field ! ! VALUE: ! !- KEYWORDMACRO _qretry ( setclr, tst_field) = NOT BEGIN BUILTIN TESTBITSSI, TESTBITCCI; EXTERNAL ROUTINE exe$gl_lockrtry : ADDRESSING_MODE (GENERAL); INCR i FROM 0 TO .exe$gl_lockrtry - 1 DO %IF setclr EQLU 'S' %THEN IF TESTBITSSI (tst_field) THEN EXITLOOP 0 %FI ! separator %IF setclr EQLU 'C' %THEN IF TESTBITCCI (tst_field) THEN EXITLOOP 0 %FI END %; %SBTTL '_QUEUE_DG_BUF' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _queue_dg_buf ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (ref_pdt [pdt$l_queuedg]) END %; %SBTTL '_QUEUE_MULT_DGS' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! numbuf ! ! VALUE: ! !- KEYWORDMACRO _queue_mult_dgs ( pdt, numbuf) = BEGIN LINKAGE pdt_linkage = JSB (REGISTER = 1); LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; pdt_linkage (.ref_pdt [pdt$l_queuemdgs], numbuf) END %; %SBTTL '_READ_COUNTERS' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! rstadr ! ! lprnam ! ! VALUE: ! !- KEYWORDMACRO _read_counters ( pdt, rstadr = 0, lprnam) = BEGIN LINKAGE pdt_linkage = JSB (REGISTER = 0, REGISTER = 1); LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; pdt_linkage (.ref_pdt [pdt$l_readcount], rstadr, lprnam) END %; %SBTTL '_RECYCH_MSG_BUF' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _recych_msg_buf ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (ref_pdt [pdt$l_rchmsgbuf]) END %; %SBTTL '_RECYCL_MSG_BUF' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _recycl_msg_buf ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (ref_pdt [pdt$l_rclmsgbuf]) END %; %SBTTL '_REJECT' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! rejtyp ! ! VALUE: ! !- KEYWORDMACRO _reject ( pdt, rejtyp) = BEGIN LINKAGE pdt_linkage = JSB (REGISTER = 0); LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; pdt_linkage (.ref_pdt [pdt$l_reject], rejtyp) END %; %SBTTL '_RELCHAN' !+ ! FUNCTIONAL DESCRIPTION: ! Calls IOC$RELCHAN to release all data channels (controllers) allocated to the device. ! ! INPUTS: ! ucb Address of the UCB. ! ! VALUE: ! !- KEYWORDMACRO _relchan ( ucb) = BEGIN LINKAGE ioc$relchan_linkage = JSB (REGISTER = 5) : NOPRESERVE (0, 1, 2) PRESERVE (3, 4, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$relchan : ioc$relchan_linkage NOVALUE ADDRESSING_MODE (GENERAL); ioc$relchan (ucb); END %; %SBTTL '_RELDPR' !+ ! FUNCTIONAL DESCRIPTION: ! Calls IOC$RELDATAP to release a UNIBUS data path register allocated to the driver. ! ! INPUTS: ! ucb Address of the UCB. ! ! VALUE: ! !- KEYWORDMACRO _reldpr ( ucb) = BEGIN LINKAGE ioc$reldatap_linkage = JSB (REGISTER = 5) : NOPRESERVE (0, 1, 2) PRESERVE (3, 4, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$reldatap : ioc$reldatap_linkage NOVALUE ADDRESSING_MODE (GENERAL); ioc$reldatap (ucb); END %; %SBTTL '_RELMPR' !+ ! FUNCTIONAL DESCRIPTION: ! Calls IOC$RELMAPREG to release a set of UNIBUS or MicroVAX II Q22 bus mapping registers ! allocated to the device. ! ! INPUTS: ! ucb Address of the UCB. ! ! VALUE: ! !- KEYWORDMACRO _relmpr ( ucb) = BEGIN LINKAGE ioc$relmapreg_linkage = JSB (REGISTER = 5) : NOPRESERVE (0, 1, 2) PRESERVE (3, 4, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$relmapreg : ioc$relmapreg_linkage NOVALUE ADDRESSING_MODE (GENERAL); ioc$relmapreg (ucb); END %; %SBTTL '_RELSCHAN' !+ ! FUNCTIONAL DESCRIPTION: ! Calls IOC$RELSCHAN to release all secondary data channels allocated by the driver. ! ! INPUTS: ! ucb Address of the UCB. ! ! VALUE: ! !- KEYWORDMACRO _relschan ( ucb) = BEGIN LINKAGE ioc$relschan_linkage = JSB (REGISTER = 5) : NOPRESERVE (0, 1, 2) PRESERVE (3, 4, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$relschan : ioc$relschan_linkage NOVALUE ADDRESSING_MODE (GENERAL); ioc$relschan (ucb); END %; %SBTTL '_REQCOM' !+ ! FUNCTIONAL DESCRIPTION: ! Calls IOC$REQCOM to complete the processing of an I/O request after the driver has finished ! its portion of the processing. ! ! INPUTS: ! ucb Address of the UCB. ! ! sts1 First I/O status longword. ! ! sts2 Second I/O status longword. ! ! VALUE: ! !- KEYWORDMACRO _reqcom ( ucb, sts1, sts2 = 0 ) = BEGIN LINKAGE ioc$reqcom_linkage = JSB (REGISTER = 0, REGISTER = 1, REGISTER = 5) : NOPRESERVE (0, 1, 2, 3) PRESERVE (4, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$reqcom : ioc$reqcom_linkage NOVALUE ADDRESSING_MODE (GENERAL); ioc$reqcom (sts1, sts2, ucb); END %; %SBTTL '_REQDPR' !+ ! FUNCTIONAL DESCRIPTION: ! Calls IOC$REQDATAP to request a data path in a UNIBUS adapter. ! ! NOTE: The stack pointer must point to a longword containing the address of the ! caller's caller when the macro is invoked. ! ! INPUTS: ! ucb Address of UCB. ! ! VALUE: ! !- KEYWORDMACRO _reqdpr ( ucb) = BEGIN LINKAGE ioc$reqdatap_linkage = JSB (REGISTER = 5) : NOPRESERVE (0) PRESERVE (1, 2, 3, 4, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$reqdatap : ioc$reqdatap_linkage ADDRESSING_MODE (GENERAL); ioc$reqdatap (ucb) END %; %SBTTL '_REQMPR' !+ ! FUNCTIONAL DESCRIPTION: ! Calls IOC$REQMAPREG to obtain UNIBUS or MicroVAX II Q22 bus mapping registers. ! ! NOTE: The stack pointer must point to a longword containing the address of the ! caller's caller when the macro is invoked. ! ! INPUTS: ! ucb Address of UCB. ! ! VALUE: ! !- KEYWORDMACRO _reqmpr ( ucb) = BEGIN LINKAGE ioc$reqmapreq_linkage = JSB (REGISTER = 5; REGISTER = 2) : NOPRESERVE (0, 1, 2) PRESERVE (3, 4, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$reqmapreg : ioc$reqmapreg_linkage ADDRESSING_MODE (GENERAL); ioc$reqmapreg (ucb) END %; %SBTTL '_REQPCHAN' !+ ! FUNCTIONAL DESCRIPTION: ! Calls IOC$REQPCHANH or IOC$REQPCHANL, depending on the priority specified, to ! obtain a controller data channel. ! ! NOTE: The stack pointer must point to a longword containing the address of the ! caller's caller when the macro is invoked. ! ! INPUTS: ! ucb Address of UCB. ! ! pri Priority of request. If the priority is HIGH, IOC$REQPCHANH is ! called otherwise IOC$REQPCHANL is called. ! ! csr ! ! VALUE: ! !- KEYWORDMACRO _reqpchan ( ucb, pri, csr) = BEGIN %IF ( NOT %NULL (pri)) AND (%IDENTICAL (pri, 'HIGH')) %THEN LINKAGE ioc$reqpchanh_linkage = JSB (REGISTER = 5; REGISTER = 4) : NOPRESERVE (0, 1, 2, 4) PRESERVE (3, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$reqpchanh : ioc$reqpchan_linkage NOVALUE ADDRESSING_MODE (GENERAL); ioc$reqpchanh (ucb; csr); %ELSE LINKAGE ioc$reqpchanl_linkage = JSB (REGISTER = 5; REGISTER = 4) : NOPRESERVE (0, 1, 2, 4) PRESERVE (3, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$reqpchanl : ioc$reqpchan_linkage NOVALUE ADDRESSING_MODE (GENERAL); ioc$reqpchanl (ucb; csr); %FI END %; %SBTTL '_REQSCHAN' !+ ! FUNCTIONAL DESCRIPTION: ! Calls IOC$REQSCHANH or IOC$REQSCHANL, depending on the priority specified, to obatin ! a secondary MASSBUS data channel. ! ! NOTE: The stack pointer must point to a longword containing the address of the ! caller's caller when the macro is invoked. ! ! INPUTS: ! ucb Address of UCB. ! ! pri Priority of request. If the priority is HIGH, IOC$REQPCHANH is ! called otherwise IOC$REQPCHANL is called. ! ! csr ! ! VALUE: ! !- KEYWORDMACRO _reqschan ( ucb, pri, csr) = BEGIN %IF ( NOT %NULL (pri)) AND (%IDENTICAL (pri, 'HIGH')) %THEN LINKAGE ioc$reqschanh_linkage = JSB (REGISTER = 5; REGISTER = 4) : NOPRESERVE (0, 1, 2, 4) PRESERVE (3, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$reqschanh : ioc$reqschan_linkage NOVALUE ADDRESSING_MODE (GENERAL); ioc$reqschanh (ucb; csr); %ELSE LINKAGE ioc$reqschanl_linkage = JSB (REGISTER = 5; REGISTER = 4) : NOPRESERVE (0, 1, 2, 4) PRESERVE (3, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$reqschanl : ioc$reqschan_linkage NOVALUE ADDRESSING_MODE (GENERAL); ioc$reqschanl (ucb; csr); %FI END %; %SBTTL '_REQUEST_DATA' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _request_data ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; _alloc_rspid; ref_pdt = pdt; JSB (ref_pdt [pdt$l_allocmsg]); JSB (ref_pdt [pdt$l_reqdata]) END %; %SBTTL '_RLS_COUNTERS' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _rls_counters ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (ref_pdt [pdt$l_rlscount]) END %; %SBTTL '_RPTEVT' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! name ! ! mode ! ! VALUE: ! !- KEYWORDMACRO _rptevt ( name, mode = GENERAL ) = BEGIN LINKAGE rse_linkage = JSB; EXTERNAL ROUTINE sch$rse : rse_linkage ADDRESSING_MODE (mode); OWN call_code : BLOCK [16, BYTE] PRESET ( [0, 0, 8, 0] = op$_movl, [1, 0, 8, 0] = %X'8E', ! (SP)+ [2, 0, 8, 0] = %X'AF', ! B^ [3, 0, 8, 0] = call_code [12, 0, 32, 0] - call_code [4, 0, 0, 0], ! D [4, 0, 8, 0] = op$_jsb, [5, 0, 32, 0] = sch$rse, [9, 0, 8, 0] = %NAME ('EVT$_', name), [10, 0, 8, 0] = op$_jmp, [11, 0, 8, 0] = %X'9F', ! @# [12, 0, 32, 0] = 0); ! location JSB (call_code [0, 0, 0, 0]); END %; %SBTTL '_SAVIPL' !+ ! FUNCTIONAL DESCRIPTION: ! Saves the current IPL, as recorded in the processor IPL register (PR$_IPL), in the ! specified location or on the stack. ! ! INPUTS: ! dst Address of longword in which to save the current IPL; the default ! is to push the IPL on the stack. ! ! VALUE: ! !- KEYWORDMACRO _savipl ( dst) = BEGIN BUILTIN MFPR; %IF %NULL (dst) %THEN BEGIN BUILTIN SP; SP = .SP - 4; MFPR (pr$_ipl, .SP); END; %ELSE MFPR (pr$_ipl, dst); %FI END %; %SBTTL '_SCAN_RDT' !+ ! FUNCTIONAL DESCRIPTION: ! Search RDT for CDRPs with CDT address matching the specified CDT address. ! For each CDRP found, call user supplied action routine. ! ! INPUTS: ! action Address of action routine. ! ! cdt Address of CDT. ! ! blk User defined usage. ! ! VALUE: ! Status from routine call to SCS$LKP_RDTCDRP. !- KEYWORDMACRO _scan_rdt ( action, cdt, blk) = BEGIN LINKAGE lkp_rdtcdrp_linkage = JSB (REGISTER = 0, REGISTER = 1, REGISTER = 3; REGISTER = 1) : PRESERVE (2, 3, 4, 5); EXTERNAL ROUTINE scs$lkp_rdtcdrp : lkp_rdtcdrp_linkage ADDRESSING_MODE (GENERAL); scs$lkp_rdtcdrp (action, blk, cdt) END %; %SBTTL '_SCAN_RSPID_WAIT' !+ ! FUNCTIONAL DESCRIPTION: ! Search RSPID wait queue for next CDRP with CDRP$L_CDT that matches CDT specified. ! For each CDRP found, call user supplied action routine. ! ! INPUTS: ! action Address of action routine. ! ! cdt Address of CDT. ! ! blk User defined usage. ! ! VALUE: ! Status from routine call to SCS$LKP_RDTWAIT. !- KEYWORDMACRO _scan_rspid_wait ( action, cdt, blk) = BEGIN LINKAGE lkp_rdtwait_linkage = JSB (REGISTER = 0, REGISTER = 1, REGISTER = 3; REGISTER = 1) : PRESERVE (2, 3, 4, 5); EXTERNAL ROUTINE scs$lkp_rdtwait : lkp_rdtwait_linkage ( REGISTER = 0) ADDRESSING_MODE (GENERAL); scs$lkp_rdtwait (action, blk, cdt) END %; %SBTTL '_SEND_CNT_MSG_BUF' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _send_cnt_msg_buf ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (ref_pdt [pdt$l_sndcntmsg]) END %; %SBTTL '_SEND_DATA' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _send_data ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; _alloc_rspid; ref_pdt = pdt; JSB (.ref_pdt [pdt$l_allocmsg]); JSB (.ref_pdt [pdt$l_senddata]) END %; %SBTTL '_SEND_DG_BUF' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! flag ! ! VALUE: ! !- KEYWORDMACRO _send_dg_buf ( pdt, flag) = BEGIN LINKAGE pdt_linkage = JSB (REGISTER = 0); LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; pdt_linkage (.ref_pdt [pdt$l_senddg], flag) END %; %SBTTL '_SEND_MSG_BUF' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _send_msg_buf ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (.ref_pdt [pdt$l_sendmsg]) END %; %SBTTL '_SETIPL' !+ ! FUNCTIONAL DESCRIPTION: ! This macro sets the current IPL by moving the specified value into the processor register PR$_IPL. ! ! INPUTS: ! ipl Level at which to set the current IPL. ! ! VALUE: ! !- KEYWORDMACRO _setipl ( ipl = ipl$_power ) = BEGIN BUILTIN MTPR; MTPR (ipl, pr$_ipl); END; %; %SBTTL '_SOFTINT' !+ ! FUNCTIONAL DESCRIPTION: ! Moves the specified IPL into the processor software-interrupt-request register (PR$_SIR), ! thus requesting a software interrupt at that IPL. ! ! INPUTS: ! ipl IPL at which interrupt is to occur. ! ! VALUE: ! !- KEYWORDMACRO _softint ( ipl) = BEGIN BUILTIN MTPR; MTPR (ipl, pr$_sirr); END %; %SBTTL '_TIMEWAIT' !+ ! FUNCTIONAL DESCRIPTION: ! Checks for a specific state by testing bits for a specified length of time. Use of ! the TIMEDWAIT macro instead of this macro is recommended. ! ! INPUTS: ! time Number of intervals of units (see below) to wait. The value specified ! will be converted into 10-microsecond intervals which will then be ! multipled by the processor specific value in order to compute the ! interval to wait. The processor specific value is inversely ! proportional to the speed of the processor but is never less than 1. ! ! tst_field Field reference to test. Normally the dot is part of this reference, ! e.g. .w_csr[csr$v_done]. More than one field may be tested, e.g. ! (.w_csr[csr$v_done] OR .w_csr[csr$v_error]). ! ! sense If true (low bit set), test for one or more of the specified bits set; ! otherwise test for all bits cleared. ! ! units Units with which to interpret the time parameter. May be one of USEC, ! MSEC or SEC. ! ! VALUE: ! ! If the state comes into existence during the specified interval, this macro returns ! a success code. ! ! If the state does not occur during the specified interval, this macro returns ! a success code. !- KEYWORDMACRO _timewait ( time, tst_field, sense = 1, units = sec ) = NOT BEGIN EXTERNAL exe$gl_tenusec : ADDRESSING_MODE (GENERAL), exe$gl_ubdelay : ADDRESSING_MODE (GENERAL); DECR i FROM (time %IF %IDENTICAL (units, 'USEC') %THEN /10 %ELSE %IF %IDENTICAL (units, 'MSEC') %THEN *100 %ELSE %IF %IDENTICAL (units, 'SEC') %THEN *1000*100 %FI %FI %FI )*.exe$gl_tenusec - 1 TO 1 DO BEGIN IF sense XOR tst_field THEN EXITLOOP NOT ss$_normal; DECR j FROM .exe$gl_ubdelay - 1 TO 1 DO __nothing; END END %; %SBTTL '_TIMEDWAIT' !+ ! FUNCTIONAL DESCRIPTION: ! Waits for a period of time for an event or condition to occur. You can specify any ! ammount of code for this macro to execute in a loop to determine whether the event ! has occurred or not. ! ! This macro does not read the processor's clock. The interval it waits is appoximate ! and depends upon the processor and the set of code you choose for testing to see if ! the condition exists. ! ! INPUTS: ! time Number of intervals of units (see below) to wait. The value specified ! will be converted into 10-microsecond intervals which will then be ! multipled by the processor specific value in order to compute the ! interval to wait. The processor specific value is inversely ! proportional to the speed of the processor but is never less than 1. ! ! If you do not specify any code for testing, increase the value of ! time by 25 percent. ! ! If you specify code that takes longer to execute than average then ! this macro will wait proportionally longer. ! ! codblk Expression to be evaluated in each iteration of the loop. When using ! more than one expression, enclose them within a BEGIN-END block. ! ! units Units with which to interpret the time parameter. May be one of USEC, ! MSEC or SEC. ! ! VALUE: ! !- KEYWORDMACRO _timedwait ( time, codblk, units = sec ) = NOT BEGIN EXTERNAL exe$gl_tenusec : ADDRESSING_MODE (GENERAL), exe$gl_ubdelay : ADDRESSING_MODE (GENERAL); DECR i FROM (time %IF %IDENTICAL (units, 'USEC') %THEN /10 %ELSE %IF %IDENTICAL (units, 'MSEC') %THEN *100 %ELSE %IF %IDENTICAL (units, 'SEC') %THEN *1000*100 %FI %FI %FI )*.exe$gl_tenusec - 1 TO 1 DO BEGIN %IF NOT %NULL (codblk) %THEN IF codblk THEN EXITLOOP NOT ss$_normal; %FI DECR j FROM .exe$gl_ubdelay - 1 TO 1 DO __nothing; END END %; %SBTTL '_UNLOCK' !+ ! FUNCTIONAL DESCRIPTION: ! Clear the specified bit and reenable interrupts. ! ! INPUTS: ! bit_field Field refence of bit to be cleared. ! ! src Address of the IPL to be restored. ! ! VALUE: ! None. !- KEYWORDMACRO _unlock ( flag, lock_field) = BEGIN BUILTIN TESTBITCCI; TESTBITCCI (lock_field); enbint (); END %; %SBTTL '_UNMAP' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! pdt ! ! VALUE: ! !- KEYWORDMACRO _unmap ( pdt) = BEGIN LINKAGE JSB = JSB; LOCAL ref_pdt : REF BLOCK [, BYTE]; ref_pdt = pdt; JSB (.ref_pdt [pdt$l_unmap]) END %; %SBTTL '_WFIKPCH' !+ ! FUNCTIONAL DESCRIPTION: ! Causes a process to wait for an interrupt from a device by calling IOC$WFIKPCH. The process ! retains ownership of the channel (the controller) while waiting. ! ! The waiting can be ended by the successful completion of a device operation, a device ! failure, or a timeout. When an interrupt occurrs, control returns to the code which follows ! this macro. ! ! INPUTS: ! excpt LTCE address of a device timeout handling routine; the address of this ! routine must be within 65535 bytes of the address of the call_code ! block. ! ! ipl IPL at which control is passed to the caller's caller (may be placed ! on the stack by a prior invocation of the _DSBINT macro). ! ! time Number of seconds to wait for an interrupt before a device timeout is ! considered to exist. ! ! ucb Address of UCB. ! ! VALUE: ! !- KEYWORDMACRO _wfikpch ( excpt, ipl, time, ucb) = BEGIN LINKAGE ioc$wfikpch_linkage = JSB (REGISTER = 5) : PRESERVE (0, 1, 2, 3, 4, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$wfikpch : ioc$wfikpch_linkage ADDRESSING_MODE (GENERAL); !+ ! The following OWN generates the equivalent of the code sequence: ! ! MOVL (SP)+,B^RETADR ! JSB G^IOC$WFIKPCH ! .WORD excpt-. ! JMP (PC)+ ! RETADR: .LONG 0 !- OWN call_code : BLOCK [17, BYTE] PRESET ( ! [0, 0, 8, 0] = op$_movl, ! [1, 0, 8, 0] = %X'8E', ! (SP)+ [2, 0, 8, 0] = %X'AF', ! B^ [3, 0, 8, 0] = call_code [13, 0, 32, 0] - call_code [4, 0, 0, 0], ! D [4, 0, 8, 0] = op$_jsb, ! [5, 0, 32, 0] = ioc$wfikpch, ! [9, 0, 16, 0] = excpt - call_code [9, 0, 16, 0], ! [11, 0, 8, 0] = op$_jmp, ! [12, 0, 8, 0] = %X'9F', ! @# [13, 0, 32, 0] = 0); ! location %IF %NULL (time) %THEN wfikpch_linkage (call_code [0, 0, 0, 0], 1^16 %IF NOT %NULL (ipl) %THEN , ipl %FI ); %ELSE wfikpch_linkage (call_code [0, 0, 0, 0], time %IF NOT %NULL (ipl) %THEN , ipl %FI ); %FI END %; %SBTTL '_WFIRLCH' !+ ! FUNCTIONAL DESCRIPTION: ! Causes a process to wait for an interrupt from a device by calling IOC$WFIRLCH. The process ! releases ownership of the channel (the controller) while waiting. ! ! The waiting can be ended by the successful completion of a device operation, a device ! failure, or a timeout. When an interrupt occurrs, control returns to the code which follows ! this macro. ! ! INPUTS: ! excpt LTCE address of a device timeout handling routine; the address of this ! routine must be within 65535 bytes of the address of the call_code ! block. ! ! ipl IPL at which control is passed to the caller's caller (may be placed ! on the stack by a prior invocation of the _DSBINT macro). ! ! time Number of seconds to wait for an interrupt before a device timeout is ! considered to exist. ! ! ucb Address of UCB. ! ! VALUE: ! !- KEYWORDMACRO _wfirlch ( excpt, ipl, time, ucb) = BEGIN LINKAGE ioc$wfirlch_linkage = JSB (REGISTER = 5) : PRESERVE (0, 1, 2, 3, 4, 5) NOTUSED (6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ioc$wfirlch : ioc$wfirlch_linkage ADDRESSING_MODE (GENERAL); !+ ! The following OWN generates the equivalent of the code sequence: ! ! MOVL (SP)+,B^RETADR ! JSB G^IOC$WFIRLCH ! .WORD excpt-. ! JMP (PC)+ ! RETADR: .LONG 0 !- OWN call_code : BLOCK [17, BYTE] PRESET ( ! [0, 0, 8, 0] = op$_movl, ! [1, 0, 8, 0] = %X'8E', ! (SP)+ [2, 0, 8, 0] = %X'AF', ! B^ [3, 0, 8, 0] = call_code [13, 0, 32, 0] - call_code [4, 0, 0, 0], ! D [4, 0, 8, 0] = op$_jsb, ! [5, 0, 32, 0] = ioc$wfirlch, ! [9, 0, 16, 0] = excpt - call_code [9, 0, 16, 0], ! [11, 0, 8, 0] = op$_jmp, ! [12, 0, 8, 0] = %X'9F', ! @# [13, 0, 32, 0] = 0); ! location %IF %NULL (time) %THEN wfirlch_linkage (call_code [0, 0, 0, 0], 1^16 %IF NOT %NULL (ipl) %THEN , ipl %FI ); %ELSE wfirlch_linkage (call_code [0, 0, 0, 0], time %IF NOT %NULL (ipl) %THEN , ipl %FI ); %FI END %; %SBTTL '_FIELD_OP' !+ ! FUNCTIONAL DESCRIPTION: ! This macro provides the ability perform some operation on two fields. The most common usage ! would be to add the offsets of two field references resulting in a field reference. ! ! INPUTS: ! fld1_off Offset, in bytes, to the first field. ! ! fld1_pos Offset, in bits, to the first field from the byte offset. ! ! fld1_siz Size, in bits, of the first field. Not used. ! ! fld1_ext Sign extension flag of the first field. Not used. ! ! oper Operation to be performed, e.g. +. ! ! fld2_off Offset, in bytes, to the second field. ! ! fld2_pos Offset, in bits, to the second field from the byte offset. ! ! fld2_siz Size, in bits, of the second field. ! ! fld2_ext Sign extension flag of the second field. ! ! VALUE: ! !- MACRO _field_op (fld1_off, fld1_pos, fld1_siz, fld1_ext, oper, fld2_off, fld2_pos, fld2_siz, fld2_ext) = fld1_off oper fld2_off, fld1_pos oper fld2_pos, fld2_siz, fld2_ext %; %SBTTL '_FIELD_TEST' !+ ! FUNCTIONAL DESCRIPTION: ! ! ! INPUTS: ! fld1_off Offset, in bytes, to the first field. ! ! fld1_pos Offset, in bits, to the first field from the byte offset. ! ! fld1_siz Size, in bits, of the first field. Not used. ! ! fld1_ext Sign extension flag of the first field. Not used. ! ! oper Operation to be performed, e.g. EQLU. ! ! fld2_off Offset, in bytes, to the second field. ! ! fld2_pos Offset, in bits, to the second field from the byte offset. ! ! fld2_siz Size, in bits, of the second field. ! ! fld2_ext Sign extension flag of the second field. ! ! VALUE: ! !- MACRO _field_test (fld1_off, fld1_pos, fld1_siz, fld1_ext, oper, fld2_off, fld2_pos, fld2_siz, fld2_ext) = (fld1_off oper fld2_off) AND (fld1_pos oper fld2_pos) AND (fld1_siz oper fld2_siz) AND (fld1_ext oper fld2_ext) %; %SBTTL '_SEVERITY_LEVEL' !+ ! FUNCTIONAL DESCRIPTION: ! Returns the severity level of a condition value modified so that a ! binary comparision yields the normal order of importance/severity. ! Undefined (as of the date of the writing of this macro) severity levels ! are included so as to maintain compatability with all future versions ! of VMS. ! ! INPUTS: ! status ! ! VALUE: ! Severity Original Value Returned Value ! ------------ -------------- -------------- ! success 1 0 ! infomational 3 1 ! (undefined) 5 2 ! (undefined) 7 3 ! warning 0 4 ! error 2 5 ! severe/fatal 4 6 ! (undefined) 6 7 !- MACRO _severity_level (status) = !+ ! Check (at compile time) that the definition of the severity field in ! a condition value is consistant with this macro. That is, that the ! success bit is the low order bit in the severity field. !- %IF ($byteoffset (sts$v_severity) NEQU $byteoffset (sts$v_success)) OR ($bitposition (sts$v_severity) NEQU $bitposition (sts$v_success)) OR ($fieldwidth (sts$v_success) NEQU 1) %THEN %ERROR ('Definition of either STS$V_SEVERITY or STS$V_SUCCESS not compatible with macro expansion' ) %FI BEGIN LOCAL condition_code; !+ ! Make a local copy of the condition value. This is done since in some ! cases the condition value passed will be a constant. !- condition_code = status; !+ ! Convert the passed value into the returned value by right justifying ! the severity field (less the success field) and subtracting the ! success bit (after shifting left by the size of the severity field. !- .condition_code<$bitposition (sts$v_success) + $fieldwidth (sts$v_success), $fieldwidth (sts$v_severity) - $fieldwidth (sts$v_success), 0> + ((1 - .condition_code< $bitposition (sts$v_success), $fieldwidth (sts$v_success), 0>)^($fieldwidth (sts$v_severity) - $fieldwidth (sts$v_success))) END %; %SBTTL '_XDELTA_BREAKPOINT' !+ ! FUNCTIONAL DESCRIPTION: ! Generates an XDELTA breakpoint. ! ! INPUTS: ! None. ! ! VALUE: ! !- MACRO _xdelta_breakpoint = BEGIN LINKAGE ini$brk_linkage = JSB : NOTUSED (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); EXTERNAL ROUTINE ini$brk : ! XDELTA breakpoint. NOVALUE ini$brk_linkage ADDRESSING_MODE (GENERAL); ini$brk (); END %; %SBTTL '__nothing' !+ ! FUNCTIONAL DESCRIPTION: ! Generates no code. Only included to provide better formatting by PRETTY and to more ! explicitly indicate that nothing is to be done in those cases where it is used. ! ! INPUTS: ! None. ! ! VALUE: ! None. !- MACRO __nothing = %;