	.TITLE QIO
	.IDENT /31JA89/



;	Version:
;	File:[22,320]QIO.MAC  	Last Edit: 19-JUL-1989 11:27:28 
;
;	Author: Philip Hannay 
;	History: 31-Jan-89 -- Philip Hannay.  Created from old QIO.MAC.
;
; 

.REM |


Procedure QIO(fnc: word; lun: word; efn: event_flag;
              var iosb: IO_status_block; var parm: QIO_param_list); EXTERNAL;

{*USER*

Pascal-3 Procedure to execute QIO "nowait" function.  

This procedure provides access to all functionality provided by
the QIO nowait directive.  

It is assumed that you will include the PAS$EXT:QIO.TYP include file
that contains various IO defintions for both normal and EIO type
QIOs.  A number of predefined function values are defined as constants.
However, you may need to supply your own.

NOTE: THE QIO NO WAIT works differently if your task is non-checkpointable.
If your task is non-checkpointable, the input buffer you supplied will
be used, and you can actually see the characters coming in before the
QIO completes.  On the other hand, if your task in checkpointable, the
driver will used an external buffer, and you will not see any input characters
until the QIO is complete.

NOTE: ERROR CODES are returned in your IOSB as byte integers.  That 
means Pascal sees the first two bytes of the IOSB as a positive integer
as the error code is in the low order byte (and thus the sign bit)
of the first IOSB word.
Take this into account when you examine the IOSB.  If the low order byte
exceeds 127 (177 octal), then you are looking at a negative
byte integer.  To extract the error code into an integer, MOD the first
IOSB word by 256 (to get low order byte), and if result exceeds 127,
subtract 256 from the result.  The final integer will
then the be correct positive or negative number.  To extract the high order
byte, DIV the first IOSB word by 256.  Since this is the terminating 
character (7 or 8 bit), it is unsigned, and may be taken as is.
The second IOSB word is always a two byte integer (character count), and is
unsigned.  You can treat it as signed, since no QIO character count
can exceed 8192.

Note that the IO_status_block definition in GENERAL.TYP also lets you
look at the status block as a 4 byte array.  This lets you access
the two bytes of the first word of the block directly.  Accessing the
bytes directly, you can get the IO status code using an
ORD(BYT[1]).  The resulting integer is unsigned from 0 thru 255.  So if
you want a signed integer, subtract 256 from the integer IF integer 
exceeds 127.

You can look directly at the high order byte (terminating character if any)
of the first status block word by doing an ORD(BYT[2]).  To look at
it as a character, use CHR(ORD(BYTE[2])).

BE CAREFUL, if you are not familiar with the "no wait"
action.  Your task will continue processing, even though the QIO is
not yet done.  You must determine its state by examining the event flag
and the IOSB.  These QIOs can pile up, and if you keep issuing new
ones, you may fill up pool.  Read more in Executive Reference manual,
and I/O Drivers Reference manual.

Your program execution will continue after calling QIO, however the
IO will not yet be complete.  When execution continues after the QIO call, 
must be sure to check the directive status first to make sure that
the QIO was accepted ($DSW=1), otherwise, you may be waiting for an
IO that will never complete.  Check the DSW IMMEDIATELY after calling
QIO.  Later in your program, you can check to see if the IO has
completed, by looking at the associated event flag (set if complete),
or the first word of the IO status block (non-zero if complete).
Use the associated event flag for a stop for event flag if you have
no more work to do.

IMPORTANT - if you post more that one QIO at a time, remember that the
associated event flag is cleared at every posting.  Thus, if you are
using the event flag to single that IO is complete, you need to use
different flags for each QIO.  On the other hand, if you use the
non-zero state of the IO status block to signal that IO is complete,
you can use the same event flag for multiple QIOs.  Note that if you
use the same flag, you should check for completed IO PRIOR to stopping
for the event flag, in case an IO completed before you issued your
last QIO.

QIOs are dequeued by the device driver in that same order as
posted by your program (FIFO).  Thus you can count on QIOs for
the SAME DEVICE to complete in the order you posted them.  Note that
this is for the SAME device only.  

An IO.KIL function will
complete all outstanding IO, at once, for the specified device
(ie. the device currently associated with the LUN to which you 
sent the QIO).  A file close operation (CLOSE) in a high level 
language will issue an IO.KIL to the device on which the file
was open.  This will complete any QIOs posted to that device
even if they were posted using different LUNs (which were pointed
to that device).  In particular, if you open a file for IO to 
a terminal port, when you close it, any QIOs posted to that terminal
port will be completed by the IO.KIL of the file close.

Note that you may
need to supply imbedded carriage return and line feed in your output
buffer, or use the VFC parameter (parameter 4) supplying a FORTRAN
style form control character like blank (LF buffer CR) or "1"
(LF buffer CR CR), etc.  Note that normal DEC convention is to output
a leading LF (linefeed) before any output, and then output a trailing
CR (carriage return) after outputting buffer.

FNC is the IO function code - a word value.  Use the predefined contants
in QIO.TYP, or supply your own code.

LUN is the logical unit number to be assigned to the appropriate device.  

EFN is the event flag to be set when the I/O is completed.  You must
supply an event flag (local or otherwise).  You cannot use f0.

IOSB is the two word IO status block.

PARM is the 6 word QIO parameter list.  Supply a zero for any parameters
that are null or not applicable.  Remember that a zero will have meaning
in many cases depending on the function code used.

If you supply a timeout value in the parameter list, remember that
a zero indicates a "zero timeout"
is to be done, and
a positive value indicates "timeout of value*10 seconds" to be done.

IMPORTANT NOTE:  Variables passed in the PARM parameter list cannot
be noted by the Pascal compiler, and it may make a mistake when it
optimizes code, based on the assumption that the QIOW call does not use
those variables.  To avoid a problem, be sure to make global any variable that
is passed in PARM (as an address) that is modified by the QIOW call.
In particular, the input buffer variable where the results of a read
operation will be placed.  By making the variable a global variable, 
the compiler will do no further optimization.

IOSB and IOSB2 represent the two words of the IO status block. 
IOSB contains the IO status word. For read functions, the high byte 
contains the terminating character. 
IOSB2 is the second word of the IO status block, for read functions,
it contains the byte count read in.

Directive status is available in $DSW on return.

} 
|

;
; Assemble with PASMAC.MAC as prefix file.
;

         .MCALL  QIO$S
	
	PROC QIO

	PARAM FNC, INTEGER
	PARAM LUN, INTEGER
	PARAM EFN, SCALAR
	PARAM ISB1, ADDRESS
	PARAM PARM, ADDRESS

	SAVE <R0, R1, R2 >

	BEGIN
	MOV SP,R0			;PRESERVE SP
	MOVB EFN(0),R1			;EFN PARAM IS A BYTE, MUST CLEAN IT UP
	BIC #^C^O377,R1			;MAKE IT AN UNSIGNED WORD
  	BNE 1$				
	MOV #IE.IEF, $DSW		;MUST SUPPLY EVENT FLAG
	BR 2$
1$:	MOV PARM(0),R2			;R2 IS ADDRESS OF PARAMETER LIST
	ADD #10.,R2			;R2 NOW POINTS TO LAST PARAMETER -
					; NOTE THAT WE DO THIS SINCE THE 
					; QIO$S WILL MOVE THE PARAMETERS
					; ONTO THE STACK STARTING WITH THE
					; LAST ONE.
        QIO$S FNC(0),LUN(0),R1,,ISB1(0),,<-(R2),-(R2),-(R2),-(R2),-(R2),(R2)>
2$:	ENDPR
	.END

