The subset contains the most important F$... type system calls, some I$... type I/O system calls, most of the EV$... event system calls, and some other general-purpose system services for simplified SHELL forking, etc. Also, other entry points like the random generator etc. are described. More calls could be added on demand in future releases of RTF.
The full system calls library, and more than that, are available in C language, as described in the "OS-9/68000 C Compiler User's Manual". They can, in a manner unusual to Fortran programmers, also be called from RTF - but why not learn C right away ? (This is a commercial of the OPAL Microprocessor team.)
Note that the letter case used in the entry point names has no effect in RTF, unlike C or assembler. RTF always converts the names to uppercase.
Another general point to mention is that whenever I/O channels are used as arguments, they are identified as Fortan logical unit numbers instead of OS-9 path numbers, unlike C or assembler. A function NUMPATH is provided which converts a Fortran logical unit number into an OS-9 path number if required for special purposes. Paths handed over to an RTF program have Fortran logical units opened automatically, i.e. unit 1 for standard input and output (paths 0 and 1), unit 2 for error output (path 2), and more from unit 3 upwards (unit equals path number) if provided.
In the description of the arguments, < denotes an input parameter and > an output result. <> denotes an updated argument.
subroutine f_exit(code)
| |||
---|---|---|---|
integer | code | < | exit code |
Function (TM 16.13): Terminates the process and returns to the calling process which is normally the SHELL command interpreter of OS-9. An exit code 0 indicates normal termination, while all other values report abnormal termination to the calling process. OS-9 error codes should be used. OS-9 automatically closes files, returns system memory, etc. when a process terminates. The link counts of linked modules or events are however not decremented.
integer function f_link(name,expnt,modpnt)
| |||
---|---|---|---|
character*(*) | name | < | module name |
integer | expnt | > | address of module execution entry point |
modpnt | > | module header address |
Function (TM 16.23): Tries to find a module identified by the module name in memory. If successful, returns the address of the module's execution entry point (i.e., the address where useful data start in a data module, or the primary entry point of an executable program) as well as the start address of the entire module (header address). Increases the link count of the module to prevent it from being removed from memory.
integer function f_unlnk(name)
| |||
---|---|---|---|
character*(*) | name | < | module name |
Function (TM 16.48): The inverse of f_link. Decreases the link count of the module and removes it from memory when the count reaches 0, unless it is a 'sticky' module or a module found during system boot.
integer function f_setpri(id,pri)
| |||
---|---|---|---|
integer | id, | < | process id number (0=calling process) |
pri | < | desired new priority (0=lowest, 65535=highest) |
Function (TM 16.34): Changes the execution priority of the process identified by the process id number. If the calling process is meant, use id=0. The priority of other processes can be changed only by the super user, or if the it has the same group/user id as the calling process.
integer function f_sigmask(level)
| |||
---|---|---|---|
integer | level | < | mask level (0=clear, 1=set/increment, -1=decrement) |
Function (TM 16.33.a): Sets or clears the signal mask which can be used to protect critical code from being interrupted by signals to its intercept routine. Signals are accepted only if the mask is clear, else they get queued. Note that intercept routines are executed with the mask set. Note also that the KILL signal (code 0) cannot be masked off, and that the WAKEUP signal (code 1) is never queued, i.e. it gets lost when the process is not sleeping.
integer function f_datmod(name,isiz,datpnt,modpnt,color)
| |||
---|---|---|---|
character*(*) | name | < | modules name |
integer | isiz, | < | module size (bytes) |
datpnt, | > | address of data inside module | |
modpnt, | > | module header address | |
color | < | (optional) color code (0 or omitted means any color) |
Function (TM 16.7): Creates a data module identified by the module name, with size in bytes specified by module size. If the module exists already, an error is returned, and f_link should be used instead. If successful, returns the address where data start within the module, as well as the start address of the entire module (header address). Data modules are an easy and efficient means to communicate large amounts of data (e.g. event buffers) among processes. The link count is set to 1 and the data portion of the module is set to 0.
Note: This RTF function forces the data pointer to a longword boundary, for efficiency reasons on the 68020/30. This is different from the OS-9 system entry point F$Datmod.
integer function f_sleep(ticks,rest)
| |||
---|---|---|---|
integer | ticks, | < | duration in 1/100 sec (0=indefinite, 1=give up time slice) |
rest | > | remaining wait time if the process gets woken up early |
Function (TM 16.33): Deactivates the calling process for the duration given, or until a signal is received, in order to allow other processes to proceed. A timed sleep (ticks > 1) can be used for timeout purposes. A timeout can be recognized by the remaining ticks being > 0. The sleep call is e.g used internally by I/O drivers to suspend the requestor until I/O completes. All signals wake up the sleeping process, but the wakeup signal is specifically made for this purpose.
integer function f_send(id,code)
| |||
---|---|---|---|
integer | id, | < | receiving process' id (0: all processes of group/user) |
code | < | signal code |
Function (TM 16.30): Sends a signal specified by the signal code to a process identified by process id. If the process id is 0, the signal is broadcast to all processes with the same group/user id as the calling process, except the calling process itself. Predefined signal codes are: 0 for kill, 1 for wakeup, 2 for keyboard abort (usually CTRL-E), 3 for keyboard interrupt (usually CTRL-C). Codes 256-65535 are free for user definition. All signals except wakeup will kill the receiving process unless it has an intercept routine. Wakeup is not given to the intercept routine, nor is kill, which will abort the receiving process even if an intercept routine exists. Signals other than kill and wakeup are queued to the receiving process. Wakeup is lost if the process is not sleeping.
integer function f_time(format,time,date,day,tick)
| |||
---|---|---|---|
integer | format, | < | format of resulting data (0=Gregorian, 1=Julian, 2=Gregorian with ticks, 3=Julian with ticks) |
time, | > | current time | |
date, | > | current date | |
day | > | day of week | |
integer*2 | tick(2) | > | (1) tick rate, (2) current tick |
Function (TM 16.43): Returns the current time and date in either Gregorian or Julian format. The ticks information is returned only for formats 2 and 3. In Julian format (the unusual one), the current time is the seconds since midnight, and the current date is the Julian day number. In Gregorian format, the current time and date should rather be declared: byte time(4),date(4). Then time(2) is hour 0..23, time(3) is minute 0..59, time(4) is second 0..59, date(1)*256+date(2) is year e.g. 1987, date(3) is month 1..12, and date(4) is day 1..31. For day of week, 0 means Sunday and 6 means Saturday. The tick rate is 100/sec in OPAL, such that ticks(2) provides 10 msec units. - Refer to subroutine DAYTIME in chapter IV below which is less complete but easier to use.
integer function f_perr(error_lu,error_code)
| |||
---|---|---|---|
integer | error_lu, | < | log.unit of error text file (0 means none) |
error_code | < | OS-9 or user defined error code |
Function (TM 16.26): This is OS-9's error reporting facility. It prints an error message with the given error code to the standard error output. Optionally, if a non-zero logical unit number of an error text file (format see TM) is given, the explanatory text for the given error code is also printed. Files with user-defined error texts can easily be generated with the text editor.
integer function f_fork(mod_type,mem_size,cmnd_size,nb_path,prior,name,cmnd,id)
| |||
---|---|---|---|
integer | mod_type, | < | desired module type/revision code (0 means any - usual case) |
mem_size, | < | additional memory for new process | |
cmnd_size, | < | size (bytes) of command given to new process (0 means no command) | |
nb_path, | < | number of I/O paths to be copied to new process (usually 3) | |
prior | < | desired execution priority on new process (0 = same as caller) | |
character*(*) | name, | < | module/file name of new process |
cmnd | < | command string to be given to new process | |
integer | id | > | process id number of new process |
Function (TM 16.15): This creates a new process as a child of the calling process. If a module identified by the module/file name is in memory, this one is executed. If not, the module/file name is taken as name of a file containing an executable module which is then loaded into memory and executed. If desired, a module of specific type and revision code may be requested. Additional memory (in kbytes) to what is specified in module's header may be passed to the new process. A command string, which is specified by cmds_size and cmnd, may be passed to the new process. The number of I/O channels open to the calling process and being handed over to the new process may be specified; this in usually 3 (standard input, standard output, and standard error output). The execution priority of the new process may be specified; if 0, the caller's priority is taken. The default priority in OPAL is 128. If successful, the process id number of the new process is returned for further reference to that process. Refer to the subroutine SHELL in chapter IV below which is less complete but easier to use.
integer function f_wait(id,code)
| |||
---|---|---|---|
integer | id, | > | id number of terminating child |
code | > | exit code of terminating child |
Function (TM 16.49): Deactivates the calling process until a child process created by the calling process terminates. The process id number and the exit code are returned to the caller. If the calling process has several child processes, it should make one f_wait call per child. When a child terminates before f_wait is issued, f_wait will then return immediately.
integer function f_id(id,g_u,prior)
| |||
---|---|---|---|
integer | id, | > | id number of calling process |
g_u, | > | group/user number of calling process | |
prior | > | execution priority of calling process |
Function (TM 16.20): Allows to determine the calling process' id number, group/user number, and priority. The id number can be used for further reference in other system calls.
integer function f_gprdsc(id,nb,descr)
| |||
---|---|---|---|
integer | id, | < | desired process id number (0=calling process) |
nb, | < | size (bytes) of buffer | |
descr | > | buffer to receive the information |
Function (TM 16.19): Issues a copy of the descriptor of the process identified with the id number. Id=0 means the calling process. All details about the process can be found in this descriptor information. See TM and /dd/defs/procs.a for the descriptor format.
integer function f_icpt(ent)
| |||
---|---|---|---|
integer | ent | < | entry point address of intercept subroutine |
Function (TM 16.21): Installs an intercept routine for the calling process which can catch signals which would otherwise terminate the process. The intercept routine executes asynchronously to the main process, and has access to the same global data. It receives the signal code in the lower half of register d1. The routine may be written in RTF (see manual) or assembler. Be sure to declare the intercept routine's name EXTERNAL in the routine which calls f_icpt. This is a usual Fortran requirement. Note that in OS-9 there is at most one intercept routine per process, which has to handle all signals. New signals are masked off during execution of the intercept routine.
integer function f_load(file,color)
| |||
---|---|---|---|
character*(*) | file, | < | name of file containing the module to be loaded |
integer | color | < | (optional) color code of target memory (0 or omitted means any color) |
Function (TM 16.24): Tries to load a memory from a file according to the path name. The search starts in the current execution directory unless a full pathname is given. The file must have the exec attribute.
integer function f_permit(addr,size,permit)
| |||
---|---|---|---|
integer | addr | < | starting address of area to grant access to (not a pointer, but a constant or variable holding the address) |
integer | size | < | size of area (bytes) |
integer | permit | < | permission code 0: read/execute only 1: read/execute/write |
Function (SSM manual): works only for systems which include the SSM (system security module). Grants access by the calling process to the address range described by the parameters. A process can make several f_permit calls. Most implemenations of the SSM require that the calling process runs in group 0 (super user group).
integer function f_protect(addr,size)
| |||
---|---|---|---|
integer | addr, | < | starting address of area to disallow access to (same note as above) |
integer | size | < | size of area (bytes) |
Function (SSM manual): Same remarks as above. Disallows access by the calling process to the address range described by the parameters. A process can make several f_protect calls. Most implemenations of the SSM require that the calling process runs in group 0 (super user group).
integer function i_write(lu,nbytes,buff,nwritten)
| |||
---|---|---|---|
integer | lu, | < | logical unit number to write to |
nbytes | < | number of bytes to be written | |
byte | buff(nbytes) | < | buffer containing the data |
integer | nwritten | > | number of bytes actually written |
Function (TM 17.29): Performs a binary write of the specified data to lu. Returns the number of bytes actually written, which should normally be equal to the number requested.
integer function i_writln(lu,nbytes,buff,nwritten)
| |||
---|---|---|---|
integer | lu, | < | logical unit number to write to |
nbytes | < | number of bytes to be written | |
byte | buff(nbytes) | < | buffer containing the data |
integer | nwritten | > | number of bytes actually written |
Function (TM 17.30): Performs an ASCII write of the specified data to lu. Bytes are written until a carrige-return is met, or nbytes are done. Returns the number of bytes actually written, excluding the carriage-return.
integer function i_read(lu,nbmax,buff,nread)
| |||
---|---|---|---|
integer | lu, | < | logical unit number to read from |
nbmax | < | maximum number of bytes to be read | |
byte | buff(nbmax) | > | buffer to hold the data |
integer | nread | > | number of bytes actually read |
Function (TM 17.16): Performs a binary read of the specified data from lu. At maximum nbmax bytes are read, which is the size of the buffer. The number of bytes actually read is returned in nread.
integer function i_readln(lu,nbmax,buff,nread)
| |||
---|---|---|---|
integer | lu, | < | logical unit number to read from |
nbmax | < | maximum number of bytes to be read | |
byte | buff(nbmax) | > | buffer to hold the data |
integer | nread | > | number of bytes actually read |
Function (TM 17.17): Performs an ASCII read of the specified data from lu. Bytes are read until a carriage-return is met,or the maximum of nbmax bytes are read, which is the size of the buffer. The number of bytes actually read, excluding the carriage-return, is returned in nread.
integer function i_ssig(lu,sig)
| |||
---|---|---|---|
integer | lu, | < | logical unit number to be monitored |
sig | < | signal code to be sent |
Function (TM 17.24): This is OS-9's means of asynchronous input from a terminal or pipe. It requests the system to send a signal to the calling process as soon as data become available on the unit, e.g. a character has been entered on the keyboard. Once the signal has been delivered, the i_ssig call has to be made again to prepare for receiving a new signal. When characters are already waiting in the buffer or pipe when the call is made, i_ssig returns their number in negative, and the request to the system is not made. As usual, a zero result means success and positive means an OS-9 error code. When using the wakeup signal (1), keep in mind that this signal will be lost when this signal arrives before the process calls f_sleep. It is better to use a different signal code, which requires then the existence of an intercept routine.
integer function i_gpos(lu,pos)
| |||
---|---|---|---|
integer | lu, | < | logical unit number |
pos | > | current file position (bytes; 0 means first byte in the file) |
Function (TM 17.11): Returns the current position in the file identified by the logical unit number.
integer function i_seek(lu,pos)
| |||
---|---|---|---|
integer | lu, | < | logical unit number |
pos | < | new file position (bytes; 0 means first byte in the file, -1 means current end of file) |
Function (TM 17.11): Sets a new position in the file identified by the logical unit number. Pos=-1 positions to the current end of file. Pos=0 rewinds the file. It is allowed to position beyond the current end of file. Subsequent reads eill then return an end of file error, while writes will expand the file. Note: i_seek may be used for random-access files with variable record length. It also has to be used for fixed record length because the syntax for random-access is omitted from RTF. If records of size lng (bytes) are used, i_seek(lu,lng*(nrec-1)) positions to record nrec.
integer function i_gsize(lu,size)
| |||
---|---|---|---|
integer | lu, | < | logical unit number |
size | > | current size of file (bytes) |
Function (TM 17.11): Returns the current size of the file identified by the logical unit number.
integer function i_ssize(lu,size)
| |||
---|---|---|---|
integer | lu, | < | logical unit number |
size | < | new size of file (bytes) |
Function (TM 17.11): Sets a new size of the file identified by the logical unit number. Size=0 shrinks the file to empty. i_ssize(lu,0) makes an existing file appear like a freshly created one.
integer function i_ready(lu,nbytes)
| |||
---|---|---|---|
integer | lu, | < | logical unit number |
nbytes | > | number of bytes present |
Function (TM 17.10): Determines the number of bytes currently present in a pipe or from a terminal. Nbytes=0 says there is no data present. May be used e.g. before writing to a pipe or reading from a terminal, in order to avoid blocking of the read or write call.
integer function i_chd(path)
| |||
---|---|---|---|
character*(*) | path | < | path name of new data directory |
Function (TM 17.2): Changes the current data directory to the one indicated by path.
integer function i_chx(path)
| |||
---|---|---|---|
character*(*) | path | < | path name of new execution directory |
Function (TM 17.2): Changes the current execution directory to the one indicated by path.
integer function ev_creat(value,wait_inc,signal_inc,name,id)
| |||
---|---|---|---|
integer | value, | < | initial value of event variable |
wait_inc, | < | auto-increment value after wait | |
signal_inc | < | auto-increment value after signal | |
character*(*) | name | < | name of event |
integer | id | > | identifier of event |
Function (TM 15.5): Creates a named OS-9 event-flag and associates it with a numerical identifier for further reference. The link count is set to 1. Events are normally used as counter variables. The initial value is set. Each time the event is signalled, the value is incremented by the signal auto increment (see ev_signl). Each time an event wait expires, the value is incremented by the wait auto-increment (see ev_wait). Usual values are 0 for the initial value, 1 for the signal increment, and -1 for the wait decrement.
integer function ev_delet(name)
| |||
---|---|---|---|
character*(*) | name | < | name of event |
Function (TM 15.5): Removes an event definition from the system. Successful only if the link count is zero.
integer function ev_link(name,id)
| |||
---|---|---|---|
character*(*) | name | < | name of event |
integer | id | > | identifier of event |
Function (TM 15.4): Connects the calling process to the named event flag, for further reference with the numerical identfier. The link count is incremented by 1.
integer function ev_unlnk(id)
| |||
---|---|---|---|
integer | id | < | identifier of event |
Function (TM 15.4): Disconnects the calling process from the event by decrementing the link count, to allow deletion of the event as soon as the link count reaches zero. Note that events are not automatically unlinked when a process using the event terminates.
integer function ev_read(id,value)
| |||
---|---|---|---|
integer | id, | < | identifier of event |
value | > | current value of event variable |
Function (TM 15.7): Returns the current value of the event variable without waiting or affecting the value.
integer function ev_wait(id,min,max,value)
| |||
---|---|---|---|
integer | id, | < | identifier of event |
imin, | < | lower bound of window | |
imax, | < | upper bound of window | |
value | < | actual value of event variable |
Function (TM 15.6): Waits until the value of the event variable is within the specified window. The actual value of the variable is returned. The wait auto-increment is then applied to the variable. Usual values are 1 for the lower bound and a big number for the upper bound. The wait condition also expires when a signal is received by the process. This case can be distinguished from the desired case by the actual event value being not within the window.
integer function ev_signl(id,ms)
| |||
---|---|---|---|
integer | id, | < | identifier of event |
ms | < | broadcast flag (0 to signal only the first process in the event wait queue, else signal all processes in the queue successively) |
Function (TM 15.9): Applies the signal auto-increment to the event value. The the queue of processes waiting for this event is inspected. The first in the queue is activated if the new value is within its window. The wait auto-increment is the applied to the value. This procedure commences through the entire queue if the broadcast flag is not zero. See also ev_set and ev_pulse, but ev_signl is the standard way to change event variables.
integer function ev_set(id,ms,new_value)
| |||
---|---|---|---|
integer | id, | < | identifier of event |
ms, | < | broadcast flag | |
new_value | < | new value of event variable |
Function (TM 15.10): Similar to ev_signl, but the new value of the event variable is set to a given value rather than being obtained from the old value plus the signal auto-increment.
integer function ev_pulse(id,ms,temp_value)
| |||
---|---|---|---|
integer | id, | < | identifier of event |
ms, | < | broadcast flag | |
temp_value | < | new temporary value of event variable |
Function (TM 15.10): Similar to ev_signl, but the new value of the event variable is set to a given value rather than being obtained from the old value plus the signal auto-increment. After looking through the wait queue and possibly activating processes, the old event value is restored.
integer function numpath(lu,io)
| |||
---|---|---|---|
integer | lu, | < | logical unit |
io | < | input/output flag (1=input, 2=output) |
Function: Returns the OS-9 path number associated with a given Fortran logical unit number. In principle, the input and output parts of a logical unit could be different, but normally this is not the case; io=1 or 2 give the same result. A -1 is returned for logical units which have no paths associated.
integer function memall(nb,color)
| |||
---|---|---|---|
integer | nb, | < | number of bytes requested |
color | < | (optional) color code of
desired memory (0 or omitted means any color) |
Function: Requests from the system a contiguous piece of memory with the given length (bytes). Returns the start address of the memory if successful, and -1 if not enough memory is available. E.g., the address can then be used to set a pointer variable which then provides access to the piece of memory by Fortran means.
integer function memrel(nb,adr)
| |||
---|---|---|---|
integer | nb, | < | size of block to be released (bytes) |
adr | < | start address of block |
Function: Releases a block of memory to the system obtained previously with memall. Both the size and the address must conform to those used in memall.
subroutine mapto(pnt,new)
| |||
---|---|---|---|
integer | pnt, | < | old address of a pointer-based COMMON |
new | < | new address |
Function: Released the memory which has previously been allocated to a pointer-based COMMON block automatically at program start. Then remaps the COMMON block to the new start address. Note that this differs from mere pointer assignment by releasing the old memory block.
subroutine outchr(lu,ch)
| |||
---|---|---|---|
integer | lu, | < | logical unit number |
ch | < | character to be output |
Function: Writes a single character to the logical unit. The character is taken from the least significant byte of ch.
integer function inchr(lu)
| |||
---|---|---|---|
integer | lu | < | logical unit number |
Function: Reads a single character from the logical unit without waiting. Zero is returned if no character is ready. Else the ASCII code is returned in the least significant byte of the result.
subroutine delete(file,ier)
| |||
---|---|---|---|
character*(*) | file | < | file name |
integer | ier | > | error code |
Function: Deletes a file. Wildcards are disallowed. Zero is returned in ier if successful, else the OS-9 error code.
subroutine rename(old_name,new_name,ier)
| |||
---|---|---|---|
character*(*) | old_name, | < | old name of file |
new_name | < | new name | |
integer | ier | > | error code |
Function: Renames a file. Zero is returned in ier if successful, else the OS-9 error code.
subroutine shell(cmnd,ier)
| |||
---|---|---|---|
character*(*) | cmnd | < | command string to be executed |
integer | ier | > | error code |
Function: Provides an easy to use means of executing shell commands. The command string may contain anything which is usually typed in interactively. It can be used to fork a process through the shell, exploiting the shell's command interpretation. A wait for completion of command execution is done implicitely. Zero is returned in ier if successful, else the OS-9 error code.
subroutine datime(id,it)
| |||
---|---|---|---|
integer | id, | > | current Gregorian date |
it | > | current Gregorian time |
Function: Returns the current date and time in decimal, such that they can be printed in integer format. E.g., for 15 January 1988, 12 hours 5 minutes 20 seconds, id=880115 and it=120520.
character*(*) function upshft(strng)
| |||
---|---|---|---|
character*(*) | strng | < | character string |
Function: returns the argument string, shifted to uppercase letters.
character*(*) function loshft(strng)
| |||
---|---|---|---|
character*(*) | strng | < | character string |
Function: returns the argument string, shifted to lowercase letters.
real function rndm(irnd)
| |||
---|---|---|---|
integer | irnd(2) | <> | 64-bit workspace |
Function: Rndm returns a real number in the interval (0,1). Rndm is a high quality uniform random generator with period length 2**64. It is essential to provide 64 bits as argument, e.g. an integer array of length 2. The complete status of the generator is contained in there and can be initialized, saved, and restored by setting/saving the argument. Calls to rndm with different workspaces which are initialized to different values provide independent generators.
real function rnorm(irnd)
| |||
---|---|---|---|
integer | irnd(2) | <> | 64-bit workspace |
Function: Rnorm returns a real number of quasi-normal distribution, i.e. mean 0, variance 1, but values only within (-6,6). It is generated from 12 successive calls to rndm. Argument as for rndm.
integer function icamad(b,c,n,a,f,t)
| |||
---|---|---|---|
integer | b, | < | CAMAC branch number (0...9) |
c, | < | crate number (1...7) | |
n, | < | station number (0...31) | |
a, | < | subaddress (0...15) | |
f, | < | function code (0...31) | |
t | < | word size (0=24 bit, 1=16 bit) |
Function: returns the VME address under which a CAMAC module can be accessed in the given way (f,t) through a CES or DataSud VME to CAMAC branch controller. When being used together with RTF pointer variables, this provides a high-speed but non-standard way to do CAMAC cycles. See examples in the RTF manual. Note that as seen from inside of some CPU modules, e.g. the CES FIC 8230, a given VME address appears with an additional address offset which has thus to be added to the result of icamad (F0000000 for the FIC).
Function: prints traceback information from the current subroutine level up to the main program to the standard error output. Returns to caller afterwards. Also called internally bt the RTF runtime system.
subroutine tbk(lu,ipc,iframe)
| |||
---|---|---|---|
integer | lu, | < | logical unit for output |
ipc | < | program address from where to start traceback | |
iframe | < | stackframe pointer from where to start traceback |
Function: prints traceback information from the subroutine level defined by the program counter ipc and the frame pointer iframe up to the main program to the output unit lu. Returns to caller afterwards. Also called internally bt the RTF runtime system. - Same effect as tback if lu=2 and ipc and iframe are the current values of the registers PC and A5.
subroutine activate(vect,ent,oldent)
| |||
---|---|---|---|
integer | vect, | < | interrupt vector number (2...255) |
ent, | < | entry point address of new interrupt handler | |
oldent | > | entry point address of previous handler |
Function: 'Steals' interrupt handling from OS-9 and routes an interrupt directly to an RTF of assembler routine. Beware! Be sure to know what you are doing, and that your handler is fully tested and does not disappear from memory once it is installed. No use of OS-9 services should be made inside of the handler. Your handler must be declared EXTERNAL in the routine calling activate. Re-install the old handler by calling activate again with call-by-value for oldent, because the value of oldent is the pointer to the old handler.
subroutine uzero(arr,start,end)
| |||
---|---|---|---|
integer | arr(*), | < | array |
start, | < | start index (relative to 1st element of arr) | |
end | < | end index (relative to 1st element of arr) |
Function: clears (part of) an array to zero. If arr is declared e.g. integer arr(100), and start=1, end=100, the entire array is cleared. In general, if arr is declared arr(i1:i2), then the end-start+1 elements arr(i1+start-1) to arr(i1+end) are cleared.
subroutine mvbits(source,os,length,dest,od)
| |||
---|---|---|---|
integer | source, | < | source bit string |
os, | < | start bit number in source (LSB has number 0) | |
length, | < | number of bits transferred | |
dest, | > | destination bit string | |
od | < | start bit number in destination |
Function: transfers a bit string of length consecutive bits from source to destination. Bit numbering starts with 0 for the least significant bit. Bits os to os+length-1 of the source are put into bits od to od+length-1 of the destination. Other bits of the destination remain unchanged.
The utilities package described here is about failure interrupts. It provides trap routines for these interrupts together with an RTF interface. The interface lets the user select what should happen after an interrupt: traceback printout or not; stop, generate signal, call a user subroutine, or jump to a program label. This is accomplished by setting up information in a global area. This area contains also error details from the interrupt (e.g. bus error address), available to the user.
The following interrupts are made available to user control: bus error, zero divide, and the FPU (floating point coprocessor MC68881/2) errors: zero divide, operand error (e.g. SQRT of a negative argument), overflow, not a number and unordered condition (e.g. from uninitialized variables).
Other interrupts (address error, illegal instruction, F line trap) are used by RTF for various emulations for the 68000. Wrong emulations and the remaining user-trapable interrupts (CHK, TRAPV, privilege violation, A line trap, floating point underflow and inexact result) in RTF typically result from "static" programming errors which are not worth a recovery. The package provides improved handling for all these errors by generating a traceback.
Before describing these entry points, recall how to write an intercept routine in RTF.
Example:
Subroutine Example_Icpt(idummy,#isignal) Eventflag * ! mark as intercept routine Integer*2 isignal ! 2nd argument carries the ! signal code, by value, 16-bit ... if(isignal.eq.2) then ! react to CTRL-E call cleanup stop endif ... endIntercept routines may be entered indirectly after a failure interrupt by using the "generate signal" mode of the package described now.
subroutine berr_jump(label,lu)
| |||
---|---|---|---|
integer | label, | < | address of Fortran label inside routine calling this one (e.g.*999); calling routine is usually the main program |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the bus error handling such that a bus error interrupt acts much like a GOTO label, possibly directly out of the depth of nested subroutine calls. Stack and frame pointers etc. are reset to the conditions at the time berr_jump was called.
This is the call the best suited for automatic recovery from bus errors when simple repetition of the access is not good enough. Extra information can be obtained with a call to err_detail (see paragraph 7 below) which returns the failure address (the address the access to which failed) and, less important, the approximate program counter of the instruction which made the bus error.
Example:
program doberr parameter (lower='ffa00000'x,upper='ffa01fff'x) call berr_jump(*99,0) call preparations 1 call setup_hardware do forever call use_hardware enddo 99 call err_detail(ipc,iaddr) if(iaddr.ge.lower .and. iaddr.le.upper) goto 1 type '(a,z9)','Fatal bus error - address:',iaddr endHere, bus errors in a given address range result in reinitialisation of the associated hardware. This works on 68000 systems as well as on 68020/30 systems.
subroutine berr_call(entry,lu)
| |||
---|---|---|---|
integer | entry, | < | address of Fortran subroutine (declared EXTERNAL in calling program) |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the bus error handling such that a bus error interrupt results in a call to entry, with no arguments. After execution of the subroutine, control returns to this program counter, which may be the address of the instruction trying the access, or of the instruction after that one. It may even point to the middle of an instruction on 68000 systems. Return from the user subroutine after error is of limited use on 68000 systems. On 68020/30 systems, the faulted bus cycle will be rerun automatically by the processor after return from the user routine.
Example:
program doberr1 common /berr_c/ icount external brout call berr_call(brout,0) call preparations call setup_hardware do forever icount=0 call use_hardware enddo end subroutine brout common /berr_c/ icount parameter (lower='ffa00000'x,upper='ffa01fff'x) call err_detail(ipc,iaddr) if(iaddr.ge.lower .and. iaddr.le.upper) then icount=icount+1 if(icount.gt.3) type *,'More than three failures in a row - abort' call f_exit(102) endif endif type '(a,z9)','Fatal bus error - address:',iaddr call f_exit(102) endHere bus errors in a certain address range result in automatic retry as long as they don't happen all the time. This does not work on 68000 systems.
subroutine berr_signal(isignal,lu)
| |||
---|---|---|---|
integer | isignal, | < | code of signal to be generated after bus error |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the bus error handling such that a bus error interrupt results in generating a signal. This either aborts the process or enters the optional intercept routine. After execution of the intercept routine, control returns to the program counter where the error happened, which may be the address of the instruction trying the access, or of the instruction after that one. It may even point to the middle of an instruction on 68000 systems. Return from the intercept routine after a bus error is of limited use on 68000 systems. On 68020/30 systems, the faulted bus cycle will be rerun automatically by the processor after return from the intercept routine.
subroutine berr_stop(lu)
| |||
---|---|---|---|
integer | lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the bus error handling such that a bus error stops the process after the optional traceback output. This mode with output to the standard error output path is the default used by the RTF library, by calling berr_stop(2) internally.
subroutine zdiv_jump(label,lu)
| |||
---|---|---|---|
integer | label, | < | address of Fortran label inside routine calling this one (e.g.*999); calling routine is usually the main program |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the zero divide handling such that a zero divide interrupt acts much like a GOTO label, possibly directly out of the depth of nested subroutine calls. Stack and frame pointers etc. are reset to the conditions at the time zdiv_jump was called.
subroutine zdiv_call(entry,lu)
| |||
---|---|---|---|
integer | entry, | < | address of Fortran subroutine (declared EXTERNAL in calling program) |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the zero divide handling such that a zero divide interrupt results in a call to entry, with no arguments. After execution of the subroutine, control returns to the instruction after the failing one, with unpredictable numerical result unless the subroutine takes corrective action (hard to do).
subroutine zdiv_signal(isignal,lu)
| |||
---|---|---|---|
integer | isignal, | < | code of signal to be generated after bus error |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the zero divide handling such that a zero divide interrupt results in generating a signal. This either aborts the process or enters the optional intercept routine. After execution of the intercept routine, control returns to the instruction after the failing one, with unpredictable numerical result unless the intercept routine takes corrective action (hard to do).
subroutine zdiv_stop(lu)
| |||
---|---|---|---|
integer | lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the zero divide handling such that a zero divide interrupt stops the process after the optional traceback output. This mode with output to the standard error output path is the default used by the RTF library, by calling zdiv_stop(2) internally.
subroutine fzdiv_jump(label,lu)
| |||
---|---|---|---|
integer | label, | < | address of Fortran label inside routine calling this one (e.g.*999); calling routine is usually the main program |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the zero divide handling such that a zero divide interrupt acts much like a GOTO label, possibly directly out of the depth of nested subroutine calls. Stack and frame pointers etc. are reset to the conditions at the time fzdiv_jump was called.
subroutine fzdiv_call(entry,lu)
| |||
---|---|---|---|
integer | entry, | < | address of Fortran subroutine (declared EXTERNAL in calling program) |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the zero divide handling such that a zero divide interrupt results in a call to entry, with no arguments. After execution of the subroutine, control returns to the instruction after the failing one, with unpredictable numerical result unless the subroutine takes corrective action (hard to do).
subroutine fzdiv_signal(isignal,lu)
| |||
---|---|---|---|
integer | isignal, | < | code of signal to be generated after bus error |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the zero divide handling such that a zero divide interrupt results in generating a signal. This either aborts the process or enters the optional intercept routine. After execution of the intercept routine, control returns to the instruction after the failing one, with unpredictable numerical result unless the intercept routine takes corrective action (hard to do).
subroutine fzdiv_stop(lu)
| |||
---|---|---|---|
integer | lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the zero divide handling such that a zero divide interrupt stops the process after the optional traceback output. This mode with output to the standard error output path is the default used by the RTF library, by calling fzdiv_stop(2) internally.
subroutine operr_jump(label,lu)
| |||
---|---|---|---|
integer | label, | < | address of Fortran label inside routine calling this one (e.g.*999); calling routine is usually the main program |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the operand error handling such that an operand error interrupt acts much like a GOTO label, possibly directly out of the depth of nested subroutine calls. Stack and frame pointers etc. are reset to the conditions at the time operr_jump was called.
subroutine operr_call(entry,lu)
| |||
---|---|---|---|
integer | entry, | < | address of Fortran subroutine (declared EXTERNAL in calling program) |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the operand error handling such that an operand error interrupt results in a call to entry, with no arguments. After execution of the subroutine, control returns to the instruction after the failing one, with unpredictable numerical result unless the subroutine takes corrective action (hard to do).
subroutine operr_signal(isignal,lu)
| |||
---|---|---|---|
integer | isignal, | < | code of signal to be generated after bus error |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the operand error handling such that an operand error interrupt results in generating a signal. This either aborts the process or enters the optional intercept routine. After execution of the intercept routine, control returns to the instruction after the failing one, with unpredictable numerical result unless the intercept routine takes corrective action (hard to do).
subroutine operr_stop(lu)
| |||
---|---|---|---|
integer | lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the operand error handling such that an operand error interrupt stops the process after the optional traceback output. This mode with output to the standard error output path is the default used by the RTF library, by calling operr_stop(2) internally.
Note that overflow from integer operations and floating point underflows cause no interrupts. I.e., integer overflows remain undetected and floating point underflows give the result 0.
subroutine fovfl_jump(label,lu)
| |||
---|---|---|---|
integer | label, | < | address of Fortran label inside routine calling this one (e.g.*999); calling routine is usually the main program |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the overflow handling such that an overflow interrupt acts much like a GOTO label, possibly directly out of the depth of nested subroutine calls. Stack and frame pointers etc. are reset to the conditions at the time fovfl_jump was called.
subroutine fovfl_call(entry,lu)
| |||
---|---|---|---|
integer | entry, | < | address of Fortran subroutine (declared EXTERNAL in calling program) |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the overflow handling such that an overflow interrupt results in a call to entry, with no arguments. After execution of the subroutine, control returns to the instruction after the failing one, with unpredictable numerical result unless the subroutine takes corrective action (hard to do).
subroutine fovfl_signal(isignal,lu)
| |||
---|---|---|---|
integer | isignal, | < | code of signal to be generated after bus error |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the overflow handling such that an overflow interrupt results in generating a signal. This either aborts the process or enters the optional intercept routine. After execution of the intercept routine, control returns to the instruction after the failing one, with unpredictable numerical result unless the intercept routine takes corrective action (hard to do).
subroutine fovfl_stop(lu)
| |||
---|---|---|---|
integer | lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the overflow handling such that an overflow interrupt stops the process after the optional traceback output. This mode with output to the standard error output path is the default used by the RTF library, by calling fovfl_stop(2) internally.
Not all illegal numbers cause an interrupt during all floating point operations. Numbers with an all-1's exponent and a non-zero mantissa are illegal numbers - that is, typically numbers with bit patterns like small negative integers. The two cases "Signalling Not-A-Number" and "Branch/Set on Unordered Condition" distinguished by the hardware are given to the same handler in this package. Details are found in the MC68881/2 User's Manual.
subroutine fnan_jump(label,lu)
| |||
---|---|---|---|
integer | label, | < | address of Fortran label inside routine calling this one (e.g.*999); calling routine is usually the main program |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes illegal number handling such that NAN/BSUN interrupts acts much like a GOTO label, possibly directly out of the depth of nested subroutine calls. Stack and frame pointers etc. are reset to the conditions at the time fnan_jump was called.
subroutine fnan_call(entry,lu)
| |||
---|---|---|---|
integer | entry, | < | address of Fortran subroutine (declared EXTERNAL in calling program) |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the illegal number handling such that NAN/BSUN interrupts results in a call to entry, with no arguments. After execution of the subroutine, control returns to the instruction after the failing one, with unpredictable numerical result unless the subroutine takes corrective action (hard to do).
subroutine fnan_signal(isignal,lu)
| |||
---|---|---|---|
integer | isignal, | < | code of signal to be generated after bus error |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the illegal number handling such that NAN/BSUN interrupts results in generating a signal. This either aborts the process or enters the optional intercept routine. After execution of the intercept routine, control returns to the instruction after the failing one, with unpredictable numerical result unless the intercept routine takes corrective action (hard to do).
subroutine fnan_stop(lu)
| |||
---|---|---|---|
integer | lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes the illegal number handling such that NAN/BSUN interrupts stop the process after the optional traceback output. This mode with output to the standard error output path is the default used by the RTF library, by calling fnan_stop(2) internally.
It may be useful to react to certain, not interrupt-related conditions by a jump e.g. back into the main program out of nested subroutines. The following entry points implement that.
subroutine set_jump(label,lu)
| |||
---|---|---|---|
integer | label, | < | address of Fortran label inside routine calling this one (e.g.*999); calling routine is usually the main program |
lu | < | Fortran logical unit number of optional traceback output (usually 2 for standard error output); 0 means no output |
Function: initializes do_jump handling such that do_jump acts much like a GOTO label, possibly directly out of the depth of nested subroutine calls. Stack and frame pointers etc. are reset to the conditions at the time set_jump was called.
subroutine do_jump(code)
| |||
---|---|---|---|
integer | label, | < | user-defined error code for later use |
Function: transfers control to the label specified in set_jump, with the proper stack and frame pointer setting for the target program unit. The program counter of the instruction calling do_jump and the code are stored for optional traceback or retrieval with err_detail.
Example: jump out of an intercept routine into the main program.
program jump external icpt call f_icpt(icpt) call set_jump(*99,2) ... ... 99 call err_detail(ipc,icode) type '(a,z9)','Stopped for reason:',icode end subroutine icpt(dummy,#sig) integer*2 sig i=sig call do_jump(i) end
subroutine err_detail(ierr_pc,ierr_addr)
| |||
---|---|---|---|
integer | ierr_pc, | > | Program counter of failing instruction or 'closeby' |
ierr_addr | > | Address failing to reply (applies only to bus errors) |
Function: copies the program counter and the failure address (only for bus errors) of the last interrupt to user's variables. 'Closeby' means that the program counter points to the failing instruction, the next instruction , or even into the middle of the next instruction on 68000 systems. err_pc is precise enough to locate the problem in the program. For bus errors, err_pc is not good enough to allow smooth continuation from the point of error on 68000 systems, while 68020/30 processors have enough extra internal information available for this. err_addr allows to determine safely which hardware failed in the case of a bus error. - For other than bus errors, corrective action by the user is required to make continuation useful.
EDT <filename> | for VT100 compatible terminals |
EDT <filename> -vt52 | for VT52 compatible terminals. |
The layout of the numeric keypad is like on the VAX. Use PF2 to get a help display. When leaving EDT with EXIT or EX, it renames the old file to .BAK and stores the updated information under the old name. When leaving with QUIT, the updated information is kept in a .TMP file. When leaving with ABRT, updates will be lost.
FOR <filename> [[,]<filename>...] [-<option> [,<option>...]]<filename> may contain wildcard characters. If no filename extension is given, it is assumed to be .f (if it is given, it is stripped off and replaced by .f - such that Fortran sources should always have extension .f). The <options> are as given in the RTF manual. Examples:
FOR myfile -list=on for b.f for a b c for *.f -list=on,check=offThe current working directory may be different from the directory containing the source. The intermediate assembly code is always written to the current directory, while the generated relocatable code is written back to the directory of the source. Any include files used by the source inherit the source's path unless they are given as a full pathname, i.e. start with a /. Thus one can speed up compilation by using a fast device (e.g. ram disk) as current directory.
If you are interested in the generated assembler code, run the compiler alone, using the RTF command. RTF wants only one source file at a time, and wants the options without a hyphen (sorry). Example:
rtf myfile.f mix=onThen myfile.a contains the generated code together with the Fortran source as comments, due to the mix option.
#define MVBITS(m,i,len,n,j) BITFINS(BITFLD(m,i,len),n,j,len) Program T ii=5 jj=0 Call MVBITS(ii,2,5,jj,7) c Call BITFINS(BITFLD(ii,2,5),jj,7,5) ! just the same EndFor compiling, use
FP myfileThe call to MVBITS is expanded to the call to BITFINS as indicated. Note that the macro preprocessor is case sensitive, as usual in the C language. As a consequence, the macro definition and macro reference must be written in exactly the same case.
LNK test lnk test,testsub lnk bigone -ga lnk -z=t.lnk -l=/m2/hb.l -o=thbThe -g option generates a symbol table in a separate file; is useful when you want to execute under the debugger (see ALD manual). Apart from that, it has no influence on the speed of execution. - In the last example, t.lnk contains a list of relocatable files (with extension .r - sorry again), one per line.
For mixtures of RTF and C, where the main program is in RTF, similar command LNC is provided. Here, the file rtfcstart.r. This contains initialisations for C as well as for RTF. The C library, clib.l, is used. Example for the entire program preparation:
for mainf for subf cc -r subc lnc mainf subc subfThis generates an executable module named mainf. Note the option -r (generate relocatable) of cc.
To execute under the debugger, type DEBUG <module> rather than just <module>. Presently the debugger is a assembly level debugger, not Fortran source level. Global symbols like subroutines names etc. are nevertheless accessible by name. After some experience, you will find the debugger more useful than putting TYPE statements into your source all the time.
Remember the various ways to have pointer-based COMMON blocks:
INDIRECT NNN COMMON /NNN/ X,Y...
COMMON /@NNN/ X,Y...
RECORD /NNN/ X,Y...
INTEGER @NNN COMMON /@NNN/ X,Y...
TEMPLATE NNN COMMON /NNN/ X,Y
COMMON /PNNN/ @NNN RECORD /NNN/ X,Y...
COMMON /PNNN/ @NNN COMMON /@NNN/ X,Y...
In cases 2a and 2b, the pointers are explicitely declared. No space allocation is done; rather the program has to allocate space explicitely (e.g. by linking to a data module with F_LINK). Setting the pointer has to be done explicitely as well. Depending on how global the declaration of the pointer is, it may be valid in the current routine only, in the file currently compiled, or even in separately compiled files.
In cases 3a, 3b and 3c, the same is true as for 2a and 2b, but the pointer is guaranteed to be to be valid even in separately compiled files.
In consequence, method 3a is recommended for sharing data which reside in a data module. 3b or 3c could also be used but 3a seems more obvious.
Example:
Program Main Integer F_Link,F_DatMod Template Evnt Common /Evnt/ IEvent(100000) ... If(F_Link('EventMod',@Evnt,Junk).ne.0) Then If(F_DatMod('EventMod',100000*4,@Evnt,Junk).ne.0) Stop 'error' EndIf ... (access to IEvent) ... End Subroutine Subr Template Evnt Common /Evnt/ IEvent(100000) ... (access to IEvent) ... EndThe main program allocates space by linking to / creating a data module, getting the pointer @Evnt set up properly by the call to F_Link or F_DatMod. The subroutine, whether compiled separately or not, uses the same pointer, because @Evnt is itself in a COMMON block and thus global.
Therefore, method 1a is recommended for big COMMON blocks. 1b could also be used but 1a seems more obvious.
Example:
Program Main Indirect Evt Common /Evt/ IEvnet(100000) ... End Subroutine Subr Indirect Evt Common /Evt/ IEvnet(100000) ... EndSpace is allocated automatically when the program starts execution, using the F$SRqMem system call. As with normal COMMONs, the subroutine accesses the same data as the main program, whether compiled separately or not.
Subroutine Junk Record /D/ Flags,X,Y,Z; Integer Flags; Real X,Y,Z @D=... ! set base address of RECORD If(Btest(Flags,0)) X=...
Subroutine Junk(D) ! @D supplied by subroutine call Record /D/ Flags,X,Y,Z; Integer Flags; Real X,Y,Z If(Btest(Flags,0)) X=...
The basic features of signals and events have been given in chapter A1.1.1 together with the description of the library calls to use them from RTF. In short, signals as well as events are fast. Signals provide easy timeout implementation. The wakeup signal can be lost, such that safe use of signals usually requires intercept routines. Events are safe and have the advantage that they are known to the system by name; they are thus more recommended as signals.
Very different is the use of the I/O system for communication. It is somewhat less efficient (for the silicon) but is much more portable (to UNIX) and straightforward to use. The SHELL's feature of I/O rerouting and the unified I/O system allow to write processes which are totally unaware of the way they are communicating. Moreover, such processes can be tested easily and independently of each other. By means of networks like OS9Net, the I/O system can be extended transparently across CPU boundaries, such that the use of pipes for interprocess communication makes even implementations on a multiprocessor system a relatively simple task. In addition, small amounts of data (a few hundered bytes) can be transported together with the data-available signal. Such data could consist for example of a pointer to a memory area where the bulk of data (e.g. an event buffer) may be found.
The recommended method here is to write processes which read from and write to their standard input and output paths, i.e. read(*...) and write(*...) in Fortran. Usually they would then communicate interactively via the terminal used to start them. After testing the processes this way from the terminal, the I/O can be rerouted to other I/O paths, e.g pipes between them, by starting them with the appropriate SHELL command. The processes' code need not be touched any more. - In short, use the method of UNIX filters.
A simple application would be to clean up things in a controlled way before terminating with STOP or a call to f_exit. Note the use of the keyword 'eventflag *' as the first declaration statement in the intercept routine.
Example:
Program Main Integer F_Icpt External Cleanup ... I=F_Icpt(Cleanup) ! let OS-9 install the intercept routine ... call resource_allocate(...) ! this could e.g. lock a CAMAC module ... End Subroutine Cleanup ! entered e.g. on CTRL-C, CTRL-E Eventflag * ... call resource_release(...) ! clean up things OS-9 doesn't clean up ... Stop 'forced termination' ! stop the process orderly (exit code 0) EndAnother example deals with the interpretation of the signal code and possible return to normal processing. Note the use of the keyword 'eventflag *' as the first declaration statement in the intercept routine which is mandatory for resumption of normal processing.
Program GetInput Integer F_Icpt,F_SigMask,I_SSig External GetSignal Common/Signal/ICode ... Open(10,'/pipe/SecondaryInput',access='read') I=F_Icpt(GetSignal) ! let OS-9 install the intercept routine I=F_SigMask(1) ! mask signals to ensure no loss of ! signals from I_SSig While(InChr(1).ne.0) EndDo ! eat up old input While(InChr(10).ne.0) EndDo I=I_SSig(1,101) ! request signal on standard input ready I=I_SSig(10,110) ! request signal on other input ready ... Do While(.true.) ICode=0 I=F_Sleep(1000,J) ! wait for something with timeout ! this also unmasks signals I=F_SigMask(1) ! mask signals again If(ICode.eq.0) Then Type *,'No input for 10 seconds' ElseIf(ICode.eq.101) Then Read(1,*) ... ! react to standard input ... I=I_SSig(1,101) ElseIf(ICode.eq.110) Then Read(10,*) ... ! react to other input ... I=I_SSig(10,110) ElseIf(ICode.eq.2 .or. ICode.eq.3) Then ... ! react to termination requests Stop 'operator cancelled process' EndIf EndDo End Subroutine GetSignal(Dummy,#SigCode) EventFlag * ! don't forget this one Integer*2 SigCode ! signal code is passed by value in d1 Common/Signal/ICode ICode=SigCode ! pass signal code to main process End ! this returns to main via F$RTE
Program TranspMode Integer F_Icpt,F_SigMask,I_SSig External GetSig Common/Signal/LuIn,LuOut,ISig Parameter (META=4) ! use CTRL-^ as meta character ... Open(10,'/t1') Open(11,'/t2') I=F_Icpt(GetSig) I=F_SigMask(1) ! mask signals While(InChr(10).ne.0) EndDo ! eat up old input While(InChr(11).ne.0) EndDo I=I_SSig(10,1010) ! request signals from the devices I=I_SSig(11,1011) ... Do While(.true.) LuIn=0 I=F_Sleep(0,J) ! wait, unmask signals I=F_SigMask(1) ! mask signals again If(LuIn.ne.0) Then ! react I=InChr(LuIn) If(I.eq.META) stop ! stop on meta character Call OutChr(LuIn,I) ! else transmit I=I_SSig(LuIn,ISig) EndIf EndDo End Subroutine GetSig(Dummy,#SigCode) EventFlag * Integer*2 SigCode Common/Signal/ICode If(SigCode.eq.1010) Then LuIn=10 LuOut=11 ElseIf(SigCode.eq.1011) Then LuIn=11 LuOut=10 Endif ISig=SigCode End
046:nnn | RTF finished with a total number of nnn errors (only if nnn non-zero). |
047:001 | The RTF command is wrong or incomplete. |
047:002 | RTF does not get sufficient workspace from the system. |
047:003 | RTF cannot open the source file. |
047:004 | RTF has been aborted due to internal errors. |
047:005 | RTF cannot open an include file. |
048:010 | Invalid CAMAC address given to function ICAMAD. |
048:011 | Invalid interrupt vector number given to subroutine ACTIVATE. |
048:012 | Wrong number of actual arguments given to called routine. |
048:013 | Attempt to store into a character constant. |
048:015 | Stack limit exceeded. Usually no traceback available after this error. |
048:023 | Output record is too long (i.e. more than 512 bytes). |
048:024 | Format out of order or not supported. |
048:025 | Too many (i.e. more than 10) concatenations in actual CHARACTER argument. |
048:030 | This is 68020/30 code - cannot execute on a 68000/10. |
048:040 | Conversion error in formatted input/output. Note that input/output request errors (from OPEN,CLOSE,READ,WRITE) result in the corresponding OS-9 exit codes. |
048:048 | Wildcards are not accepted by subroutine DELETE. |
048:000 | Non-implemented floating point instruction. |
048:001 | Floating point overflow. |
048:002 | Floating point divide by zero. |
048:003 | Floating to integer conversion overflow. |
048:004 | EXP function argument too big. |
048:005 | ALOG function argument zero or negative. |
048:006 | SQRT argument negative. |
048:007 | Attempt to use illegal floating point number (not-a-number). |
RTF programs need recompilation mainly because of this new convention. In order to avoid undetected compatibility problems, some crucial entry point names have been changed on purpose. Also, the name of the runtime module, formerly os9lib, has been changed to rtflib. Old code can neither be run nor re-linked in the new system.
From OS-9 version 2.2 on, COMMON variables can be accessed directly. Thus the default has been changed such that direct addressing is used normally (space is allocated in the VSECT).
Note that in OS-9 version 2.1, this scheme does not work yet because of a bug in the linker, l68. Version 2.2 or at least the l68 of 2.2 (which runs also under 2.1) is required to run RTF version 3.1 or higher.
The advantages are improved speed and considerably more compact code for programs with much use of COMMON variables. The disadvantage is that if one wants to re-map a COMMON block, it has to be based explicitely on a pointer. Also, big COMMON blocks (more than 65000 bytes long) have to be accessed indirectly even in the new version, such that they also have to be based on pointers explicitely. The compiler will give a warning else. Moreover, all COMMONs together have to fit into the 64k limit. The linker will give messages otherwise.
This is a new potential source of inconvenience. To overcome this, the extra declaration INDIRECT cname[,cname,...] has been introduced. The cname are COMMON block names. This allows to state in a preamble (e.g. by a global INCLUDE statement at the beginning of each source file) which COMMON blocks should be addressed indirectly while all others are handled the fast way, without using the pointer mark '@' explicitely in the COMMON block declarations.
A (bad) alternative is to use the compiler option COMMON=INDIRECT which switches to the previous default of all COMMONs being pointer-based automatically. This is, however, not recommended for efficiency reasons. Also, mixing of code containing the same COMMON, but compiled partly with COMMON=INDIRECT and partly with COMMON=ABSOLUTE will not work.
The pointers to pointer-based COMMONs are now themselves put into a COMMON area automatically. The USE statement (which affected the use of libraries) is now no longer necessary.
In order that the code optimized for the 68020+68881 can run on the 68000/10 unchanged, the Fortran runtime library now emulates floating point hardware and 32-bit multiply/divide instructions. The old entry points for floating point software are eliminated, such that the option FLOAT=SOFT cannot be used with code containing any floating point operations. Caution: double precision calculations are not currently emulated but require a 68881/68881 coprocessor or a 68040 processor.
In addition, long-distance branch to subroutines (32-bit offset) are emulated. The kernel itself emulates the instruction move to ccr which does not exist on the 68000 but is generated by RTF.
If the compiler option CPU=68020 or 68030 is used, marginally more efficient code is generated for the 68020/30. This, however, can then not run on a 68000 or 68010 because of addressing modes which cannot be emulated efficiently. The code is actively aborted when trying to run it on a 68000/10, with an appropriate error message.
Standard | in RTF | |
---|---|---|
OPEN(LU,...,RECL=LNG...) | OPEN(LU,...) | |
WRITE(LU,...,REC=N...) | CALL I_SEEK(LU,(N-1)*LNG) WRITE(LU,...) |
for *.f or for a*.f , z?.fare now allowed. For example, for compiling a large amount of code in the background with the compiler messages routed to a file, one can use a command like e.g.
for *.f >>>rtf.list &FOR always invokes the assembler for the 68020/30, r68020, even when producing code without the compiler option CPU=68020 or 68030. A dummy r68 has been made which calls r68020 (this dummy is used also by the C compiler).