Index of Topics
- - " -
- The "NO87" Environment Variable
- 1 -
- 16-bit: A Subprogram that Never Returns
16-bit: Alias Names
16-bit: Alternate Method of Passing Character Arguments
16-bit: Alternate Names for Symbols
16-bit: Assembly Language Considerations
16-bit: Auxiliary Pragmas
16-bit: Auxiliary Pragmas and the 80x87
16-bit: Calling Conventions
16-bit: Character Functions
16-bit: Code Models
16-bit: Data Models
16-bit: Defining Exported Symbols in Dynamic Link Libraries
16-bit: Defining Windows Callback Functions
16-bit: Describing Argument Information
16-bit: Describing Calling Information
16-bit: Describing How Subprograms Use Variables in Common
16-bit: Describing Subprogram Return Information
16-bit: Describing the Registers Modified by a Subprogram
16-bit: Forcing Arguments into Specific Registers
16-bit: Linking Applications for the Various Memory Models
16-bit: Loading Data Segment Register
16-bit: Memory Layout
16-bit: Memory Models
16-bit: Mixed Memory Model
16-bit: Passing Arguments in Registers
16-bit: Passing Arguments in Reverse Order
16-bit: Passing Arguments to In-Line Subprograms
16-bit: Passing Arguments to non-FORTRAN Subprograms
16-bit: Pragmas
16-bit: Predefined "__cdecl" Alias
16-bit: Predefined "__pascal" Alias
16-bit: Predefined "__watcall" Alias
16-bit: Predefined Aliases
16-bit: Preserving 80x87 Floating-Point Registers Across Calls
16-bit: Processing Alternate Returns
16-bit: Processing Function Return Values Using an 80x87
16-bit: Processing Function Return Values with no 80x87
16-bit: Removing Arguments from the Stack
16-bit: Returning Floating-Point Data
16-bit: Returning Structures and Complex Numbers
16-bit: Returning Subprogram Values in Registers
16-bit: Returning Values from Assembly Language Functions
16-bit: Specifying Symbol Attributes
16-bit: Summary of Memory Models
16-bit: Using the 80x87 to Pass Arguments
16-bit: Using the 80x87 to Return Subprogram Values
16-bit: Writing Assembly Language Subprograms
- 3 -
- 32-bit: A Subprogram that Never Returns
32-bit: Alias Names
32-bit: Alternate Method of Passing Character Arguments
32-bit: Alternate Names for Symbols
32-bit: Assembly Language Considerations
32-bit: Auxiliary Pragmas
32-bit: Auxiliary Pragmas and the 80x87
32-bit: Calling Conventions
32-bit: Character Functions
32-bit: Code Models
32-bit: Data Models
32-bit: Defining Exported Symbols in Dynamic Link Libraries
32-bit: Describing Argument Information
32-bit: Describing Calling Information
32-bit: Describing How Subprograms Use Variables in Common
32-bit: Describing Subprogram Return Information
32-bit: Describing the Registers Modified by a Subprogram
32-bit: Flat Memory Model
32-bit: Forcing Arguments into Specific Registers
32-bit: Linking Applications for the Various Memory Models
32-bit: Loading Data Segment Register
32-bit: Memory Layout
32-bit: Memory Models
32-bit: Mixed Memory Model
32-bit: Passing Arguments in Registers
32-bit: Passing Arguments in Reverse Order
32-bit: Passing Arguments to In-Line Subprograms
32-bit: Passing Arguments to non-FORTRAN Subprograms
32-bit: Pragmas
32-bit: Predefined "__cdecl" Alias
32-bit: Predefined "__pascal" Alias
32-bit: Predefined "__stdcall" Alias
32-bit: Predefined "__syscall" Alias
32-bit: Predefined "__watcall" Alias (register calling convention)
32-bit: Predefined "__watcall" Alias (stack calling convention)
32-bit: Predefined Aliases
32-bit: Preserving 80x87 Floating-Point Registers Across Calls
32-bit: Processing Alternate Returns
32-bit: Processing Function Return Values Using an 80x87
32-bit: Processing Function Return Values with no 80x87
32-bit: Removing Arguments from the Stack
32-bit: Returning Floating-Point Data
32-bit: Returning Structures and Complex Numbers
32-bit: Returning Subprogram Values in Registers
32-bit: Returning Values from Assembly Language Functions
32-bit: Specifying Symbol Attributes
32-bit: Stack-Based Calling Convention
32-bit: Summary of Memory Models
32-bit: Using the 80x87 to Pass Arguments
32-bit: Using the 80x87 to Return Subprogram Values
32-bit: Using the Stack-Based Calling Convention
32-bit: Writing Assembly Language Subprograms
- A -
- About This Manual
Attributes of Files
- C -
- CHARACTER Data Type
Compiler Diagnostics
Compiler Options
Compiler Options Relating to Floating-point
COMPLEX*16 Data Type
COMPLEX, COMPLEX*8, and DOUBLE COMPLEX Data Types
- D -
- Data Representation On x86-based Platforms
Debugging statements ("D" in Column 1)
Default Windowing Functions
The DEFINE Compiler Directive
DOUBLE PRECISION and REAL*8 Data Types
dwfDeleteOnClose
dwfSetAboutDlg
dwfSetAppTitle
dwfSetConTitle
dwfShutDown
dwfYield
- E -
- The EJECT Compiler Directive
The ELSE Compiler Directive
The ELSEIFDEF and ELSEIFNDEF Compiler Directive
Establishing Connections Between Units and Files
Examples of FAT File Specifications
Examples of HPFS File Specifications
- F -
- File Handling Defaults
File Names in the FAT File System
File Names in the High Performance File System
File Sharing
Files with no Record Structure
FINCLUDE
Floating-point Accuracy On x86-based Platforms
Floating-point Exception Handling
Floating-point Exceptions On x86-based Platforms
FORMATTED Records
Functions IARGC and IGETARG
- G -
- General Notes About Compiler Directives
- I -
- The IFDEF, IFNDEF and ENDIF Compiler Directive
The INCLUDE Compiler Directive
Input/Output Buffer Size
INTEGER and INTEGER*4 Data Types
INTEGER Function FGETCMD
INTEGER Function FGETENV
INTEGER Function FILESIZE
INTEGER Function FLUSHUNIT
INTEGER Function FNEXTRECL
INTEGER Function FSIGNAL
INTEGER Function FSPAWN
INTEGER Function FSYSTEM
INTEGER Function GROWHANDLES
INTEGER Function SEEKUNIT
INTEGER Function SETJMP/Subroutine LONGJMP
INTEGER Function SETSYSHANDLE
INTEGER*1 Data Type
INTEGER*2 Data Type
INTEGER*2 Function SYSHANDLE
- L -
- LFN
LIB
LIBDOS
LIBOS2
LIBPHAR
LIBWIN
LOGICAL and LOGICAL*4 Data Types
Logical File Name Support
LOGICAL*1 Data Type
- M -
- Math Error Functions
- N -
- NO87
- O -
- Open Watcom F77 Options Summary
The Open Watcom F77 Subprogram Library
Open Watcom FORTRAN 77 80x87 Emulator Libraries
Open Watcom FORTRAN 77 Command Line Examples
Open Watcom FORTRAN 77 Command Line Format
The Open Watcom FORTRAN 77 Compiler
Open Watcom FORTRAN 77 Compiler Directives
Open Watcom FORTRAN 77 Compiler Options
Open Watcom FORTRAN 77 File Handling
Open Watcom FORTRAN 77 INCLUDE File Processing
The Open Watcom FORTRAN 77 Libraries
- P -
- PATH
The PRAGMA Compiler Directive
A Preconnection Tutorial
Print File Attributes
Printer Device Support
- R -
- REAL and REAL*4 Data Types
REAL Function URAND
Record Access
Record Format
Record Size
Record Type
- S -
- Serial Device Support
Special DOS Device Names
Special OS/2 Device Names
Storage Organization of Data Types
Subroutine FEXIT
Subroutine FINTR and FINTRF
Subroutine FTRACEBACK
Subroutine GETDAT
Subroutine GETTIM
- T -
- Terminal or Console Device Support
TMP
- U -
- The UNDEFINE Compiler Directive
UNFORMATTED Records
Use of Environment Variables
- W -
- WATCOM
WCGMEMORY
WCL
WCL386
WD
WDW
WFC
WFC/WFC386 Environment Variables
WFC386
WFL
WFL386
WLANG
About This Manual
This manual contains the following chapters:
- Chapter 1 -
- About This Manual.
This chapter provides an overview of the contents of this guide.
Chapter 2 -
- Open Watcom FORTRAN 77 Compiler Options.
This chapter also provides a summary and reference section for the valid compiler options.
Chapter 3 -
- The Open Watcom FORTRAN 77 Compiler.
This chapter describes how to compile an application from the command line, describes compiler environment variables,
provides examples of command line use of the compiler, and and describes compiler diagnostics.
Chapter 4 -
- The Open Watcom FORTRAN 77 Libraries.
This chapter describes the Open Watcom FORTRAN 77 run-time libraries.
Chapter 5 -
- Open Watcom FORTRAN 77 Compiler Directives.
This chapter describes compiler directives including INCLUDE file processing.
Chapter 6 -
- Open Watcom FORTRAN 77 File Handling.
This chapter describes run-time file handling.
Chapter 7 -
- The Open Watcom F77 Subprogram Library.
This chapter describes subprograms available for special operations.
Chapter 8 -
- 16-bit: Memory Models.
This chapter describes the Open Watcom FORTRAN 77 memory models (including code and data models), the tiny memory model,
the mixed memory model, linking applications for the various memory models, creating a tiny memory model application, and
memory layout in an executable.
Chapter 9 -
- 16-bit: Assembly Language Considerations.
This chapter describes issues relating to 16-bit interfacing such as parameter passing conventions.
Chapter 10 -
- 16-bit: Pragmas.
This chapter describes the use of pragmas with the 16-bit compilers.
Chapter 11 -
- 32-bit: Memory Models.
This chapter describes the Open Watcom FORTRAN 77 memory models (including code and data models), the flat memory model,
the mixed memory model, linking applications for the various memory models, and memory layout in an executable.
Chapter 12 -
- 32-bit: Assembly Language Considerations.
This chapter describes issues relating to 32-bit interfacing such as parameter passing conventions.
Chapter 13 -
- 32-bit: Pragmas.
This chapter describes the use of pragmas with the 32-bit compilers.
Appendix A. -
- Use of Environment Variables.
This appendix describes all the environment variables used by the compilers and related tools.
Open Watcom FORTRAN 77 Compiler Options
Source files can be compiled using either the IDE, command-line compilers or IBM WorkFrame/2. This chapter describes
all the compiler options that are available.
For information about compiling applications from the IDE, see the Open Watcom Graphical Tools User's Guide.
For information about compiling applications from the command line, see the chapter entitled The Open Watcom FORTRAN 77 Compiler.
For information about creating applications using IBM WorkFrame/2, refer to IBM's OS/2 Programming Guide
for more information.
Open Watcom F77 Options Summary
In this section, we present a terse summary of the Open Watcom F77 options. The next section describes these options
in more detail. This summary is displayed on the screen by simply entering the "WFC" or "WFC386"
command with no arguments.
- Compiler options:
- Description:
0
- (16-bit only) assume 8088/8086 processor
1
- (16-bit only) assume 188/186 processor
2
- (16-bit only) assume 286 processor
3
- assume 386 processor
4
- assume 486 processor
5
- assume Pentium processor
6
- assume Pentium Pro processor
[NO]ALign
- align COMMON segments
[NO]AUtomatic
- all local variables on the stack
BD
- (32-bit only) dynamic link library
BM
- (32-bit only) multithread application
[NO]BOunds
- generate subscript bounds checking code
BW
- (32-bit only) default windowed application
[NO]CC
- carriage control recognition requested for output devices such as the console
CHInese
- Chinese character set
[NO]COde
- constants in code segment
D1
- include line # debugging information
D2
- include full debugging information
[NO]DEBug
- perform run-time checking
DEFine=<macro>
- define macro
[NO]DEPendency
- generate file dependencies
[NO]DEScriptor
- pass character arguments using string descriptor
DIsk
- write listing file to disk
DT=<size>
- set data threshold
[NO]ERrorfile
- generate an error file
[NO]EXPlicit
- declare type of all symbols
[NO]EXtensions
- issue extension messages
[NO]EZ
- (32-bit only) Easy OMF-386 object files
FO=<obj_default>
- set default object file name
[NO]FORmat
- relax format type checking
FPC
- generate calls to floating-point library
FPD
- enable generation of Pentium FDIV bug check code
FPI
- generate inline 80x87 instructions with emulation
FPI87
- generate inline 80x87 instructions
FPR
- floating-point backward compatibility
FP2
- generate inline 80x87 instructions
FP3
- generate inline 80387 instructions
FP5
- optimize floating-point for Pentium
FP6
- optimize floating-point for Pentium Pro
[NO]FSfloats
- FS not fixed
[NO]GSfloats
- GS not fixed
HC
- Codeview debugging information
HD
- DWARF debugging information
HW
- Open Watcom debugging information
[NO]INCList
- write content of INCLUDE files to listing
INCPath=[d:]path
- [d:]path... path for INCLUDE files
[NO]IPromote
- promote INTEGER*1 and INTEGER*2 arguments to INTEGER*4
Japanese
- Japanese character set
KOrean
- Korean character set
[NO]LFwithff
- LF with FF
[NO]LIBinfo
- include default library information in object file
[NO]LISt
- generate a listing file
[NO]MAngle
- mangle COMMON segment names
MC
- (32-bit only) compact memory model
MF
- (32-bit only) flat memory model
MH
- (16-bit only) huge memory model
ML
- large memory model
MM
- medium memory model
MS
- (32-bit only) small memory model
OB
- (32-bit only) base pointer optimizations
OBP
- branch prediction
OC
- do not convert "call" followed by "ret" to "jmp"
OD
- disable optimizations
ODO
- DO-variables do not overflow
OF
- always generate a stack frame
OH
- enable repeated optimizations (longer compiles)
OI
- generate statement functions in-line
OK
- enable control flow prologues and epilogues
OL
- perform loop optimizations
OL+
- perform loop optimizations with loop unrolling
OM
- generate floating-point 80x87 math instructions in-line
ON
- numeric optimizations
OP
- precision optimizations
OR
- instruction scheduling
OS
- optimize for space
OT
- optimize for time
OX
- equivalent to OBP, ODO, OI, OK, OL, OM, OR, and OT (16-bit) or OB, OBP, ODO, OI, OK, OL, OM, OR, and OT (32-bit)
PRint
- write listing file to printer
[NO]Quiet
- operate quietly
[NO]Reference
- issue unreferenced warning
[NO]RESource
- messages in resource file
[NO]SAve
- SAVE local variables
[NO]SC
- (32-bit only) stack calling convention
[NO]SEpcomma
- allow comma separator in formatted input
[NO]SG
- (32-bit only) automatic stack growing
[NO]SHort
- set default INTEGER/LOGICAL size to 2/1 bytes
[NO]SR
- save/restore segment registers
[NO]SSfloats
- (16-bit only) SS is not default data segment
[NO]STack
- generate stack checking code
[NO]SYntax
- syntax check only
[NO]TErminal
- messages to terminal
[NO]TRace
- generate code for run-time traceback
TYpe
- write listing file to terminal
[NO]WArnings
- issue warning messages
[NO]WILd
- relax wild branch checking
[NO]WIndows
- (16-bit only) compile code for Windows
[NO]XFloat
- extend floating-point precision
[NO]XLine
- extend line length to 132
A summary of the option defaults follows:
- 0
- 16-bit only
5
- 32-bit only
ALign
-
NOAUtomatic
-
NOBOunds
-
NOCC
-
NOCOde
-
NODEBug
-
DEPendency
-
DEScriptor
-
DT=256
-
ERrorfile
-
NOEXPlicit
-
NOEXtensions
-
NOEZ
- 32-bit only
NOFORmat
-
FPI
-
FP2
- 16-bit only
FP3
- 32-bit only
NOFPD
-
FSfloats
- all but flat memory model
NOFSfloats
- flat memory model only
GSfloats
-
NOINCList
-
NOIPromote
-
NOLFwithff
-
LIBinfo
-
NOLISt
-
NOMAngle
-
ML
- 16-bit only
MF
- 32-bit only
NOQuiet
-
Reference
-
NORESource
-
NOSAve
-
NOSC
- 32-bit only
NOSEpcomma
-
NOSG
- 32-bit only
NOSHort
-
NOSR
-
NOSSfloats
- 16-bit only
NOSTack
-
NOSYntax
-
TErminal
-
NOTRace
-
WArnings
-
NOWILd
-
NOWIndows
- 16-bit only
NOXFloat
-
NOXLine
-
Compiler Options
Compiler options may be entered in one of two places. They may be included in the options list of the command line
or they may be included as comments of the form "C$option", "c$option", or "*$option" in the
source input stream. The compiler recognizes these special comments as compiler directives.
Some options may only be specified in the options list of the command line. Unless otherwise stated, an option
can appear on the command line only. We also indicate what the default is for an option or group of options.
When specifying options in the source file, it is possible to specify more than one option on a line. For example,
the following source line tells Open Watcom F77 to not issue any warning or extension messages.
Example:
*$nowarn noext
Note that only the first option must contain the "*$", "C$", or "c$" prefix.
Short forms are indicated by upper case letters.
- Option:
- Description:
0
- (16-bit only) Open Watcom F77 will make use of only 8088/8086 instructions in the generated object code. The resulting
code will run on 8086 and all upward compatible processors. This is the default option for the 16-bit compiler.
1
- (16-bit only) Open Watcom F77 will make use of 188/186 instructions in the generated object code whenever possible.
The resulting code probably will not run on 8086 compatible processors but it will run on 186 and all upward compatible processors.
2
- (16-bit only) Open Watcom F77 will make use of 286 instructions in the generated object code whenever possible. The
resulting code probably will not run on 8086 or 186 compatible processors but it will run on 286 and all upward compatible
processors.
3
- Open Watcom F77 will assume a 386 processor and will generate instructions based on 386 instruction timings.
4
- Open Watcom F77 will assume a 486 processor and will generate 386 instructions based on 486 instruction timings. The
code is optimized for 486 processors rather than 386 processors.
5
- Open Watcom F77 will assume a Pentium processor and will generate 386 instructions based on Pentium instruction timings.
The code is optimized for Pentium processors rather than 386 processors. This is the default option for the 32-bit
compiler.
6
- Open Watcom F77 will assume a Pentium Pro processor and will generate 386 instructions based on Pentium Pro instruction timings.
The code is optimized for Pentium Pro processors rather than 386 processors.
[NO]ALign
- The "align" option tells the compiler to allocate all COMMON blocks on paragraph boundaries (multiples of 16).
If you do not want COMMON blocks to be aligned, specify "noalign". The default is "align".
[NO]AUtomatic
- The "automatic" option tells the compiler to allocate all local variables, including arrays, on the stack.
This is particularly useful for recursive functions or subroutines that require a new set of local variables to be allocated
for each recursive invocation. Note that the "automatic" option may significantly increase the stack requirements
of your application. You can increase your stack size by using the "STACK" option when you link your application.
BD
- (32-bit only, OS/2 and Windows NT only) This option causes the compiler to imbed the appropriate DLL library name in the object
file and to include the appropriate DLL initialization code sequence when the application is linked.
BM
- (32-bit only, OS/2 and Windows NT only) This option causes the compiler to imbed the appropriate multi-thread library name
in the object file.
[NO]BOunds
- The "bounds" option causes the generation of code that performs array subscript and character substring bounds checking.
Note that this option may significantly reduce the performance of your application but is an excellent way to eliminate
many programming errors. The default option is "nobounds".
BW
- (OS/2, Windows 3.x, and Windows NT only) This option causes the compiler to import a special symbol so that the default windowing
library code is linked into your application.
[NO]CC
- The "cc" option specifies that the output to devices contains carriage control information that is to be interpreted
appropriately for the output device (e.g., console device). ASA carriage control characters are converted to ASCII
vertical spacing control characters. Note that a blank carriage control character will automatically be generated for
list-directed output and will be interpreted as a single-line spacing command.
CHInese
- This option is part of the national language support provided by Open Watcom F77. It instructs the compiler that the
source code contains characters from the Traditional Chinese character set. This includes double-byte characters.
This option enables the use of Chinese variable names. The compiler's run-time system will ensure that character strings
are not split in the middle of a double-byte character when output spans record boundaries (as can happen in list-directed
output).
[NO]COde
- The "code" option causes the code generator to place character and numeric constants in code segment. Data
generated for FORMAT statements will also be placed in the code segment. The default option is "nocode".
D1
- Line number information is included in the object file ("type 1 debugging information"). This option provides
additional information to Open Watcom Debugger (at the expense of larger object files and executable files). Line numbers
are handy when debugging your application with Open Watcom Debugger.
D2
- In addition to line number information, local symbol and data type information is included in the object file ("type
2 debugging information"). Although global symbol information can be made available to Open Watcom Debugger through
a Open Watcom Linker option, local symbol and typing information must be requested when the source file is compiled.
This option provides additional information to Open Watcom Debugger (at the expense of larger object files and executable
files). However, it will make the debugging chore somewhat easier.
[NO]DEBug
- The "debug" option causes the generation of run-time checking code. This includes subscript and substring
bounds checking as well as code that allows a run-time traceback to be issued when an error occurs. The default option
is "nodebug".
DEFine=<macro>
- This option is equivalent to specifying the following "define" compiler directive.
*$define <macro>
The macro specified by the "define" option or compiler directive becomes defined. The definition status
of the specified macro can be checked using the "ifdef", "ifndef", "elseifdef" or "elseifndef"
compiler directives. This allows source code to be conditionally compiled depending on the definition status of the
macro.
The macro __i86__ is a special macro that is defined by the compiler and identifies the target as a 16-bit
Intel 80x86 compatible environment.
The macro __386__ is a special macro that is defined by the compiler and identifies the target as a 32-bit
Intel 386 compatible environment.
The macro __stack_conventions__ is a special macro that is defined by the 32-bit compiler when the "sc"
compiler option is specified to indicate that stack calling conventions are to be used for code generation.
The macro __fpi__ is a special macro that is defined by the compiler when one of the following floating-point
options is specified: "fpi" or "fpi87".
[NO]DEPendency
- The "dependency" option specifies that file dependencies are to be included in the object file. This is the
default option. This option is used by the Open Watcom Integrated Development Environment to determine if an object
file is up-to-date with respect to the source files used to build it. You can specify the "nodependency"
option if you do not want file dependencies to be included in the object file.
[NO]DEScriptor
- The "descriptor" option specifies that string descriptors are to be passed for character arguments. This is
the default option. You can specify the "nodescriptor" option if you do not want string descriptors to be
passed for character arguments. Instead, the pointer to the actual character data and the length will be passed as
two arguments. The arguments for the length will be passed as additional arguments following the normal argument list.
For character functions, the pointer to the data and the length of the character function will be passed as the first
two arguments.
DIsk
- When this option is used in conjunction with the "list" option, the listing file is written to the current directory
of the default disk. The listing file name will be the same as the source file name but the file extension will be
.lst. By default, listing files are written to disk. The "disk" option will override any previously
specified "type" or "print" option.
DT=<size>
- The "data threshold" option is used to set the minimum size for data objects to be included in the default data
segment. Normally, all data objects smaller than 256 bytes in size are placed in the default data segment. When
there is a large amount of static data, it is often useful to set the data threshold size so that all objects of the specified
size or larger are placed into another segment. For example, the option:
-DT=100
causes all data objects of 100 bytes or more to be placed in a far data segment. The "data threshold"
only applies to the large and huge memory models where there can be more than one data segment. The default data threshold
value is 256.
[NO]ERrorfile
- This option is used to control whether error messages are output to a separate error file. The error file is a disk
file of type .err and is produced if any diagnostic messages are issued by the compiler. Specifying "noerrorfile"
prevents the creation of an error file. By default, an error file is created.
If an error file exists before compilation begins, it will be erased. If no diagnostic messages are produced then
an error file will not be created even though the "errorfile" option is selected. This option has no effect
on the inclusion of diagnostic messages in the source listing file or the production of diagnostic messages on the screen.
[NO]EXPlicit
- The "explicit" option requires the type of all symbols to be explicitly declared. An error message will be
issued by the compiler if a symbol that does not appear in a type declaration statement is encountered. Specifying
this option is equivalent to using the IMPLICIT NONE statement. By default, symbols do not have to be
explicitly typed.
[NO]EXtensions
- This option is used to control the printing of extension messages. This option may be specified on the command line
or it may be placed anywhere in the source input stream. In a source file, the option appears as a comment line and
takes the following form.
*$[NO]EXtensions
The "extensions" option enables the printing of extension messages, while "noextensions" disables
the printing of these messages. By default, extension messages are not printed.
[NO]EZ
- (32-bit only) Open Watcom F77 will generate an object file in Phar Lap Easy OMF-386 (object module format) instead of the
default Microsoft OMF. The default option is "noez".
FO=<obj_default>
- By default, the object file name is constructed from the source file name. Using the "fo" option, the default
object file drive, path, file name and extension can be specified.
Example:
C>wfc386 report -fo=d:\programs\obj\
A trailing "\" must be specified for directory names. If, for example, the option was specified as
"-fo=d:\programs\obj" then the object file would be called D:\PROGRAMS\OBJ.OBJ.
A default extension must be preceded by a period (".").
Example:
C>wfc386 report -fo=d:\programs\obj\.dbo
[NO]FORmat
- The "format" option suppresses the run-time checking that ensures that the type of an input/output list item matches
the format edit descriptor in a format specification. This allows an input/output list item of type INTEGER to be formatted
using an F, E or D edit descriptor. It also allows an input/output list item of a floating-point type to be formatted
using an I edit descriptor. Normally, this generates an error. The "format" option is particularly
useful for applications that use integer arrays to store integer and floating-point data. The default option is "noformat".
FPC
- All floating-point arithmetic is done with calls to a floating-point emulation library. This option should be used when
speed of floating-point emulation is favoured over code size.
FPI
- (16-bit only) Open Watcom F77 will generate in-line 80x87 numeric data processor instructions into the object code for floating-point
operations. Depending on which library the code is linked against, these instructions will be left as is or they will
be replaced by special interrupt instructions. In the latter case, floating-point will be emulated if an 80x87 is not
present. This is the default floating-point option if none is specified.
(32-bit only) Open Watcom F77 will generate in-line 80x87 numeric data processor instructions into the object code for
floating-point operations. When any module containing floating-point operations is compiled with the "fpi"
option, coprocessor emulation software will be included in the application when it is linked. Thus, an 80x87 coprocessor
need not be present at run-time. This is the default floating-point option if none is specified.
FPI87
- (16-bit only) Open Watcom F77 will generate in-line 80x87 numeric data processor instructions into the object code for floating-point
operations. An 80x87 coprocessor must be present at run-time. If the "2" option is used in conjunction
with this option, Open Watcom F77 will generate 287/387 compatible instructions; otherwise Open Watcom F77 will generate
8087 compatible instructions.
(32-bit only) Open Watcom F77 will generate in-line 80x87 numeric data processor instructions into the object code for
floating-point operations. When the "fpi87" option is used exclusively, coprocessor emulation software is
not included in the application when it is linked. A 80x87 coprocessor must be present at run-time.
16-bit Notes:
- When any module in an application is compiled with a particular "floating-point" option, then all modules must
be compiled with the same option.
- Different math libraries are provided for applications which have been compiled with a particular floating-point option.
See the chapter entitled The Open Watcom FORTRAN 77 Libraries.
32-bit Notes:
- When any module in an application is compiled with the "fpc" option, then all modules must be compiled with
the "fpc" option.
- When any module in an application is compiled with the "fpi" or "fpi87" option, then all modules must
be compiled with one of these two options.
- If you wish to have floating-point emulation software included in the application, you should select the "fpi"
option. A 387 coprocessor need not be present at run-time.
- Different math libraries are provided for applications which have been compiled with a particular floating-point option.
See the chapter entitled The Open Watcom FORTRAN 77 Libraries.
FP2
- Open Watcom F77 will generate in-line 80x87 numeric data processor instructions into the object code for floating-point operations.
For Open Watcom compilers generating 16-bit, this is the default. For 32-bit applications, use this option if
you wish to support those few 386 systems that are equipped with an 80287 numeric data processor ("fp3" is the
default for Open Watcom compilers generating 32-bit code). However, for 32-bit applications, the use of this option
will reduce execution performance.
FP3
- Open Watcom F77 will generate in-line 387-compatible numeric data processor instructions into the object code for floating-point
operations. For 16-bit applications, the use of this option will limit the range of systems on which the application
will run but there are execution performance improvements.
FP5
- Open Watcom F77 will generate in-line 387-compatible numeric data processor instructions into the object code for floating-point
operations. The sequence of floating-point instructions will be optimized for greatest possible performance on the
Intel Pentium processor. For 16-bit applications, the use of this option will limit the range of systems on which the
application will run but there are execution performance improvements.
FP6
- Open Watcom F77 will generate in-line 387-compatible numeric data processor instructions into the object code for floating-point
operations. The sequence of floating-point instructions will be optimized for greatest possible performance on the
Intel Pentium Pro processor. For 16-bit applications, the use of this option will limit the range of systems on which
the application will run but there are execution performance improvements.
[NO]FPD
- A subtle problem was detected in the FDIV instruction of Intel's original Pentium CPU. In certain rare cases, the result
of a floating-point divide could have less precision than it should. Contact Intel directly for more information on
the issue.
As a result, the run-time system startup code has been modified to test for a faulty Pentium. If the FDIV instruction
is found to be flawed, the low order bit of the run-time system variable __chipbug will be set.
If the FDIV instruction does not show the problem, the low order bit will be clear. If the Pentium FDIV flaw
is a concern for your application, there are two approaches that you could take:
- You may test the __chipbug variable in your code in all floating-point and memory models and take appropriate
action (such as display a warning message or discontinue the application).
- Alternately, you can use the "fpd" option when compiling your code. This option directs the compiler to
generate additional code whenever an FDIV instruction is generated which tests the low order bit of __chipbug and,
if on, calls the software workaround code in the math libraries. If the bit is off, an in-line FDIV instruction will
be performed as before.
If you know that your application will never run on a defective Pentium CPU, or your analysis shows that the FDIV problem
will not affect your results, you need not use the "fpd" option.
FPR
- Use this option if you want to generate floating-point instructions that will be compatible with version 9.0 or earlier of
the compilers. For more information on floating-point conventions see the sections entitled 16-bit: Using the 80x87 to Pass Arguments
and 32-bit: Using the 80x87 to Pass Arguments.
[NO]FSfloats
- The "fsfloats" option enables the use of the FS segment register in the generated code. This is the default
for all but the flat memory model. In the flat memory model, the default is "nofsfloats" (the FS segment
register is not used in the generated code).
[NO]GSfloats
- The "gsfloats" option enables the use of the GS segment register in the generated code. This is the default.
If you would like to prevent the use of the GS segment register in the the generated code, specify the "nogsfloats"
option.
HC
- The type of debugging information that is to be included in the object file is "Codeview". The default type
of debugging information is "Dwarf" (HD). If you wish to use the Microsoft Codeview debugger, then choose
the "HC" option. When linking the application, you must also choose the appropriate Open Watcom Linker DEBUG
directive. See the Open Watcom Linker User's Guide for more information.
HD
- The type of debugging information that is to be included in the object file is "Dwarf". This is the default
type of debugging information. If you wish to use the Microsoft Codeview debugger, then choose the "HC" option.
When linking the application, you must also choose the appropriate Open Watcom Linker DEBUG directive. See the
Open Watcom Linker User's Guide for more information.
HW
- The type of debugging information that is to be included in the object file is "Open Watcom". The default
type of debugging information is "Dwarf" (HD). If you wish to use the Microsoft Codeview debugger, then choose
the "HC" option. When linking the application, you must also choose the appropriate Open Watcom Linker DEBUG
directive. See the Open Watcom Linker User's Guide for more information.
[NO]INCList
- This option is used to control the listing of the contents of INCLUDE files to the listing file. The "inclist"
option enables the listing of INCLUDE files, while "noinclist" disables the listing of these files. The default
option is "noinclist".
INCPath=[d:]path
- [d:]path... This option is used to specify directories that are to be searched for include files. Each
path is separated from the previous by a semicolon (";"). These directories are searched in the order listed
before those in the FINCLUDE environment variable.
[NO]IPromote
- The "ipromote" option causes the compiler to promote the INTEGER*1 and INTEGER*2 arguments of some INTEGER*4 intrinsics
without issuing an error diagnostic. This allows code such as the following to be compiled without error:
Example:
INTEGER I*1, J*2
I = 1
J = 2
PRINT *, IDIM( I, J )
END
This works for the following intrinsic functions: ABS(), IABS(), DIM(), IDIM(), SIGN(), ISIGN(), MAX(), AMAX0(),
MAX0(), MIN(), AMIN0(), and MIN0(). When the "ipromote" option is specified, all integer arguments that are
passed to these functions are promoted to INTEGER*4.
Japanese
- This option is part of the national language support provided by Open Watcom F77. It instructs the compiler that the
source code contains characters from the Japanese character set. This includes double-byte characters. This option
enables the use of Japanese variable names. The compiler's run-time system will ensure that character strings are not
split in the middle of a double-byte character when output spans record boundaries (as can happen in list-directed output).
KORean
- This option is part of the national language support provided by Open Watcom F77. It instructs the compiler that the
source code contains characters from the Korean character set. This includes double-byte characters. This option
enables the use of Korean variable names. The compiler's run-time system will ensure that character strings are not
split in the middle of a double-byte character when output spans record boundaries (as can happen in list-directed output).
[NO]LFwithff
- This option is used to control whether a line-feed character (LF=CHAR(10)) is to be emitted before a form-feed character (FF=CHAR(12))
is emitted. This option applies to carriage control handling. Normally, the run-time system will emit only a
form-feed character to cause a page eject when the ASA control character "1" is found in the first column of a
record. The "lfwithff" option will cause the run-time system to emit a line-feed character and then a form-feed
character.
The "lfwithff" option will have little effect on printers, but it will change the appearance of output to the
screen by eliminating overwritten text when form-feed characters are not handled by the output device. The default
option is "nolfwithff".
[NO]LIBinfo
- This option is used to control the inclusion of default library information in the object file. The "libinfo"
option enables the inclusion of default library information, while "nolibinfo" disables the inclusion of this information.
The default option is "libinfo".
[NO]LISt
- This option may be specified on the command line or it may be placed anywhere in the source input stream. On the command
line, this option is used to control the creation of a listing file. The "list" option causes a listing file
to be created while "nolist" requests that no listing file be created. The default option is "nolist".
In a source file, the option appears as a comment line and takes the following form.
*$[NO]LISt
Specifying *$LIST causes the source lines that follow this option to be listed in the source listing file while *$NOLIST
disables the listing of the source lines that follow. This option cannot appear on the same source line with other
options.
[NO]MAngle
- This option is used to alter COMMON block segment and class names.
Example:
REAL R, S
COMMON /BLK/ R, S
END
For a named COMMON block called "BLK", the default convention is to name the segment "BLK" and
the class "BLK".
BLK SEGMENT PARA
COMMON USE32 'BLK'
When you use the "mangle" option, the segment is named "_COMMON_BLK" and the class is named "_COMMON_BLK_DATA".
_COMMON_BLK SEGMENT PARA COMMON USE32 '_COMMON_BLK_DATA'
MC
- (32-bit only) The "compact" memory model (small code, big data) is selected. The various models supported
by Open Watcom F77 are described in the chapters entitled 16-bit: Memory Models
and 32-bit: Memory Models.
MF
- (32-bit only) The "flat" memory model (code and data up to 4 gigabytes) is selected. The various models supported
by Open Watcom F77 are described in the chapters entitled 16-bit: Memory Models
and 32-bit: Memory Models. This is the default memory model option.
MH
- (16-bit only) The "huge" memory model (big code, huge data) is selected. The various models supported by Open
Watcom F77 are described in the chapters entitled 16-bit: Memory Models and 32-bit: Memory Models.
ML
- The "large" memory model (big code, big data) is selected. The various models supported by Open Watcom F77
are described in the chapters entitled 16-bit: Memory Models and 32-bit: Memory Models.
This is the default 16-bit memory model option.
MM
- The "medium" memory model (big code, small data) is selected. The various models supported by Open Watcom
F77 are described in the chapters entitled 16-bit: Memory Models and 32-bit: Memory Models.
MS
- (32-bit only) The "small" memory model (small code, small data) is selected. The various models supported
by Open Watcom F77 are described in the chapters entitled 16-bit: Memory Models
and 32-bit: Memory Models.
OB
- (32-bit only) This option allows the use of the ESP register as a base register to reference local variables and subprogram
arguments in the generated code. This can reduce the size of the prologue/epilogue sequences generated by the compiler
thus improving overall performance. Note that when this option is specified, the compiler will abort when there is
not enough memory to optimize the subprogram. By default, the code generator uses more memory-efficient algorithms
when a low-on-memory condition is detected.
OBP
- This option causes the code generator to try to order the blocks of code emitted such that the "expected" execution
path (as determined by a set of simple heuristics) will be straight through, with other cases being handled by jumps to separate
blocks of code "out of line". This will result in better cache utilization on the Pentium. If the heuristics
do not apply to your code, it could result in a performance decrease.
OC
- This option may be used to disable the optimization where a "CALL" followed by a "RET" (return) is changed
into a "JMP" (jump) instruction. This option is required if you wish to link an overlayed program using the
Microsoft DOS Overlay Linker. The Microsoft DOS Overlay Linker will create overlay calls for a "CALL" instruction
only. This option is not required when using the Open Watcom Linker. This option is not assumed by default.
OD
- Non-optimized code sequences are generated. The resulting code will be much easier to debug when using Open Watcom Debugger.
By default, Open Watcom F77 will select "od" if "d2" is specified.
ODO
- Optimized DO-loop iteration code is generated. Caution should be exercised with the use of this option since the case
of an iterating value overflowing is assumed to never occur. The following example should not be compiled with this
option since the terminal value of IX wraps from a positive integer to a negative integer.
Example:
INTEGER*2 IX
DO IX=32766,32767
.
.
.
ENDDO
The values of IX are 32766, 32767, -32768, -32767, ... since IX is INTEGER*2 (a 16-bit signed
value) and it never exceeds the terminal value.
OF
- This option selects the generation of traceable stack frames for those functions that contain calls or require stack frame
setup. To use Open Watcom's "Dynamic Overlay Manager" (DOS only), you must compile all modules using the
"of" option. For near functions, the following function prologue sequence is generated.
16-bit:
push BP
mov BP,SP
32-bit:
push EBP
mov EBP,ESP
For far functions, the following function prologue sequence is generated.
16-bit:
inc BP
push BP
mov BP,SP
32-bit:
inc EBP
push EBP
mov EBP,ESP
The BP/EBP value on the stack will be even or odd depending on the code model. For 16-bit DOS systems, the Dynamic
Overlay Manager uses this information to determine if the return address on the stack is a short address (16-bit offset)
or long address (32-bit segment:offset). This option is not assumed by default.
OH
- This option enables repeated optimizations (which can result in longer compiles).
OI
- This option causes code for statement functions to be generated in-line.
OK
- This option enables flowing of register save (from prologue) down into the subprogram's flow graph.
OL
- Loop optimizations are performed. This includes moving loop-invariant expressions outside the loops. This option
is not assumed by default.
OL+
- Loop optimizations are performed including loop unrolling. This includes moving loop-invariant expressions outside the
loops and can cause loops to be turned into straight-line code. This option is not assumed by default.
OM
- Generate inline 80x87 code for math functions like sin, cos, tan, etc. If this option is selected, it is the programmer's
responsibility to make sure that arguments to these functions are within the range accepted by the fsin, fcos, etc.
instructions since no run-time check is made.
If the "ot" option is also specified, the exp function is generated inline as well. This option
is not assumed by default.
ON
- This option allows the compiler to perform certain numerical calculations in a more efficient manner. Consider the following
example.
Z1 = X1 / Y
Z2 = X2 / Y
If the "on" option is specified, the code generator will generate code that is equivalent to the following.
T = 1 / Y
Z1 = X1 * T
Z2 = X2 * T
Since floating-point multiplication is more efficient that division, the code generator decided to first compute the
reciprocal of Y and then multiply X1 and X2 by the reciprocal of Y.
Note that this optimization may produce less slightly different results since some, for certain values, precision is lost
when computing the reciprocal. By using this option, you are indicating that you are willing to accept the loss in
precision for the gain in performance.
OP
- By default, floating-point variables may be cached in 80x87 floating-point registers across statements when compiling with
the "fpi" or "fpi87" options. Floating-point register temporaries use 64 bits of precision in the
mantissa whereas single and double-precision variables use fewer bits of precision in the mantissa. The use of this
option will force the result to be stored in memory after each FORTRAN statement is executed. This will produce less
accurate but more predictable floating-point results. The code produced will also be less efficient when the "op"
option is used.
Example:
XMAX = X + Y / Z
YMAX = XMAX + Q
When the "op" option is used in conjunction with the "fpi" or "fpi87" option, the compiler's
code generator will update XMAX before proceeding with the second statement. In the second statement, the
compiler will reload XMAX from memory rather than using the result of the previous statement. The effect of
the "op" option on the resulting code can be seen by the increased code size statistic as well as through the use
of the Open Watcom Disassembler. This option is not assumed by default.
OR
- This option enables reordering of instructions (instruction scheduling) to achieve better performance on pipelined architectures
such as the 486. Selecting this option will make it slightly more difficult to debug because the assembly language
instructions generated for a source statement may be intermixed with instructions generated for surrounding statements.
This option is not assumed by default.
OS
- Space is favoured over time when generating code (smaller code but possibly slower execution). By default, Open Watcom
F77 selects a balance between "space" and "time".
OT
- Time is favoured over space when generating code (faster execution but possibly larger code). By default, Open Watcom
F77 selects a balance between "space" and "time".
OX
- Specifying the "ox" option is equivalent to specifying the "ob" (32-bit only), "obp", "odo",
"oi", "ok", "ol", "om", "or", and "ot" options.
PRint
- This option is used to direct the listing file to the printer (device name "PRN") instead of the disk. The
"print" option will override any previously specified "type" or "disk" option. The default
is to create a listing file on the disk.
[NO]Quiet
- The "quiet" option suppresses the banner and summary information produced by the compiler. Only diagnostic
messages will be displayed. The default option is "noquiet".
[NO]Reference
- When the "reference" option is specified, warning messages will be issued for all unreferenced symbols. In
a source file, the option appears as a comment line and takes the following form.
*$[NO]Reference
This option is most useful when used in an include file that is included by several subprograms. Consider an
include file that defines many parameter constants and only a few are referenced by any one subprogram. If the first
line of the include file is
*$noreference
and the last line is
*$reference
warning messages for all unused parameter constants in the include file would be suppressed. The default option
is "reference".
[NO]RESource
- The "resource" option specifies that the run-time error messages are contained as resource information in the executable
file. All messages will be extracted from the resource area of the executable file when they are required; no messages
will be linked with the application. The default option is "noresource".
[NO]SAve
- The "save" option is used to instruct Open Watcom F77 to "save" all local variables of subprograms.
All local variables are treated as if they had appeared in FORTRAN 77 SAVE statements. By default, local
variables are not saved unless named in a SAVE statement (i.e., "nosave" is the default option).
[NO]SC
- (32-bit only) If the "sc" option is used, Open Watcom F77 will pass all arguments on the stack. The resulting
code will be larger than that which is generated for the register method of passing arguments. The default option is
"nosc".
[NO]SEpcomma
- The "sepcomma" option allows the comma (",") to be used as field separator in formatted input. Thus
the following code would work with the input described.
Example:
REAL R, S
READ(5,21) R, S
PRINT *, R, S
21 FORMAT(2F11.3)
END
Normally the following input would result in a run-time error message.
0.79,0.21
[NO]SG
- (32-bit only) The "sg" option is useful for 32-bit OS/2 multi-threaded applications. It requests the code
generator to emit a run-time call at the start of any function that has more than 4K bytes of automatic variables (variables
located on the stack). Under 32-bit OS/2, the stack is grown automatically in 4K pages using the stack "guard
page" mechanism. The stack consists of in-use committed pages topped off with a special guard page. A memory
reference into the 4K guard page causes OS/2 to grow the stack by one 4K page and to add a new 4K guard page. This
works fine when there is less than 4K of automatic variables in a function. When there is more than 4K of automatic
data, the stack must be grown in an orderly fashion, 4K bytes at a time, until the stack has grown sufficiently to accommodate
all the automatic variable storage requirements.
The "stack growth" run-time routine is called __GRO.
The default option is "nosg".
[NO]SHort
- The "short" option is used to instruct Open Watcom F77 to set the default INTEGER size to 2 bytes and the default
LOGICAL size to 1 bytes. As required by the FORTRAN 77 language standard, the default INTEGER size is 4 bytes and the
default LOGICAL size is 4 bytes. The default option is "noshort".
[NO]SR
- The "sr" option instructs Open Watcom F77 to generate subprogram prologue and epilogue sequences that save and restore
any segment registers that are modified by the subprogram. Caution should be exercised when using this option.
If the value of the segment register being restored matches the value of a segment that was freed within the subprogram,
a general protection fault will occur in protected-mode environments. The default, "nosr", does not save
and restore segment registers.
[NO]SSfloats
- (16-bit only) The "ssfloats" option specifies that the segment register SS does not necessarily point to the default
data segment. The "ssfloats" option must be specified when compiling a module that is part of an OS/2 multi-threaded
application or dynamic link library. By default, it is assumed that the SS segment register contains the segment address
of the default data segment (i.e., "nossfloats").
[NO]STack
- If "stack" is specified, Open Watcom F77 will emit code at the beginning of every subprogram that will check for
the "stack overflow" condition. By default, stack overflow checking is omitted from the generated code ("nostack").
[NO]SYntax
- If "syntax" is specified, Open Watcom F77 will check the source code only and omit the generation of object code.
Syntax checking, type checking, and so on are performed as usual. By default, code is generated if there are
no source code errors (i.e., "nosyntax" is the default).
[NO]TErminal
- The "noterminal" option may be used to suppress the display of diagnostic messages to the screen. By default,
diagnostic messages are displayed.
[NO]TRace
- The "trace" option causes the generation of code that allows a traceback to be issued when an error occurs during
the execution of your program. The default option is "notrace".
TYpe
- This option is used to direct the listing file to the terminal (device name "CON") instead of the disk. The
"type" option will override any previously specified "print" or "disk" option. The default
is to create a listing file on the disk.
[NO]WArnings
- This option is used to control the printing of warning messages. By default, warning messages are printed. This
option may be specified on the command line or it may be placed anywhere in the source input stream. In a source file,
the option appears as a comment line and takes the following form.
*$[NO]WArnings
The "warnings" option enables the printing of warning messages, while "nowarnings" disables the
printing of these messages.
[NO]WILd
- The "wild" option suppresses the compile-time checking that normally causes an error to be issued when an attempt
is made to transfer control into a block structure from outside the block structure and vice versa. For example, this
option will allow a transfer of control into an IF-block from outside the IF-block (which is normally prohibited).
The default option is "nowild".
Extreme caution should be exercised when using this option. For example, transfer of control into a DO-loop from
outside the DO-loop can cause unpredictable results. This programming style is not encouraged by this option.
The option has been made available so that existing programs that do not adhere to the branching restrictions imposed by
the FORTRAN 77 standard (i.e. mainframe applications that are being ported to the PC environment), can be compiled
by Open Watcom FORTRAN 77.
[NO]WIndows
- (16-bit only) The "windows" option causes the compiler to generate the prologue/epilogue code sequences necessary
for use in Microsoft Windows applications. The default option is "nowindows".
[NO]XFloat
- The "xfloat" option specifies that all REAL variables are treated as if they had been declared as "DOUBLE PRECISION".
This effectively increases the precision of REAL variables. Note that the "xfloat" option has implications
on the alignment of variables in common blocks. The default option is "noxfloat".
[NO]Xline
- The "xline" option informs the Open Watcom F77 compiler to extend the last column of the statement portion of a
line to column 132. The default is 72.
The Open Watcom FORTRAN 77 Compiler
This chapter describes the following topics:
The formal Open Watcom FORTRAN 77 command line syntax is shown below.
WFC [options] [d:][path]filename[.ext] [options]
WFC386 [options] [d:][path]filename[.ext] [options]
The square brackets [ ] denote items which are optional.
- WFC
- is the name of the 16-bit Open Watcom F77 compiler.
WFC386
- is the name of the 32-bit Open Watcom F77 compiler.
d:
- is an optional drive specification such as "A:", "B:", etc. If not specified, the default drive
is assumed.
path
- is an optional path specification such as \PROGRAMS\SRC\. If not specified, the current directory is assumed.
filename
- is the file name of the file to be compiled.
ext
- is the file extension of the file to be compiled. If omitted, a file extension of "FOR" is assumed.
If the period "." is specified but not the extension, the file is assumed to have no file extension.
options
- is a list of valid Open Watcom F77 options, each preceded by a slash ("/") or a dash ("-"). Certain
options can include a "no" prefix to disable an option. Options may be specified in any order, with the rightmost
option taking precedence over any conflicting options specified to its left.
WFC/WFC386 Environment Variables
The WFC environment variable can be used to specify commonly used WFC options. The WFC386 environment
variable can be used to specify commonly used WFC386 options. These options are processed before options specified
on the command line.
Example:
C>set wfc=-d1 -ot
C>set wfc386=-d1 -ot
The above example defines the default options to be "d1" (include line number debugging information in the
object file), and "ot" (favour time optimizations over size optimizations).
Whenever you wish to specify an option that requires the use of an "=" character, you can use the "#"
character in its place. This is required by the syntax of the "SET" command.
Once a particular environment variable has been defined, those options listed become the default each time the associated
compiler is used. The compiler command line can be used to override any options specified in the environment string.
These environment variables are not examined by the Open Watcom Compile and Link utilities. Since the Open Watcom
Compile and Link utilities pass the relevant options found in their associated environment variables to the compiler command
line, their environment variable options take precedence over the options specified in the environment variables associated
with the compilers.
Hint: If you are running DOS and you use the same compiler options all the time, you may find
it handy to define the environment variable in your DOS system initialization file, AUTOEXEC.BAT.
If you are running Windows NT, use the "System" icon in the Control Panel to define environment variables.
If you are running OS/2 and you use the same compiler options all the time, you may find it handy to define the environment
variable in your OS/2 system initialization file, CONFIG.SYS.
Open Watcom FORTRAN 77 Command Line Examples
The following are some examples of using Open Watcom FORTRAN 77 to compile FORTRAN 77 source programs.
Example 1:
C>wfc386 report -d1 -stack
The 32-bit Open Watcom F77 compiler processes REPORT.FOR producing an object file which contains source line
number information. Stack overflow checking code is included in the object code.
Example 2:
C>wfc kwikdraw -2 -fpi87
The 16-bit Open Watcom F77 compiler processes KWIKDRAW.FOR producing object code for an Intel 286 system
equipped with an Intel 287 numeric data processor (or any upward compatible 386/387, 486 or Intel Pentium system).
While the choice of these options narrows the number of microcomputer systems where this code will execute, the resulting
code will be highly optimized for this type of system.
Example 3:
C>wfc ..\source\modabs -d2
The 16-bit Open Watcom F77 compiler processes ..\SOURCE\MODABS.FOR (a file in a directory which is adjacent
to the current one). The object file is placed in the current directory. Included with the object code and data
is information on local symbols and data types. The code generated is straight-forward, unoptimized code which can
be readily debugged with Open Watcom Debugger.
Example 4:
C>wfc386 -mf calc
The 32-bit Open Watcom F77 compiler compiles CALC.FOR for the "flat" memory model. 32-bit
memory models are described in the chapter entitled 32-bit: Memory Models.
32-bit argument passing conventions are described in the chapter entitled 32-bit: Assembly Language Considerations.
Example 5:
C>wfc386 kwikdraw -fpi87
The 32-bit Open Watcom F77 compiler processes KWIKDRAW.FOR producing object code for an Intel 386 system
equipped with an Intel 80x87 numeric data processor.
Example 6:
C>set wfc=-short -d2 -fo#*.dbj
C>wfc ..\source\modabs
The options -short, -d2 and -fo=*.dbj are established as defaults using the WFC
environment variable. The 16-bit compiler processes ..\SOURCE\MODABS.FOR (a file in a directory which is adjacent
to the current one). The object file is placed in the current directory and it will have a default file extension of
"DBJ". All INTEGER and LOGICAL variables will have a default type of INTEGER*2 and LOGICAL*1 unless explicitly
typed as INTEGER*4 or LOGICAL*4. Source line number and local symbol information are included with the object file.
Compiler Diagnostics
If the Open Watcom F77 compiler prints diagnostic messages to the screen, it will also place a copy of these messages
in a file in your current directory (unless the "noerrorfile" option is specified). The file will have the
same file name as the source file and an extension of "err". The compiler issues three types of diagnostic
messages, namely extensions, warnings and errors. An extension message indicates that you have used a feature which
is supported by Open Watcom F77 but that is not part of the FORTRAN 77 language standard. A warning message indicates
that the compiler has found a questionable problem in the source code (e.g., an unreachable statement, an unreferenced variable
or statement number, etc.). A warning message does not prevent the production of an object file. An error message
indicates that a problem is severe enough that it must be corrected before the compiler will produce an object file.
The error file is a handy reference when you wish to correct the errors in the source file.
Just to illustrate the diagnostic features of Open Watcom F77, we will compile the following program called "DEMO1".
* This program demonstrates the following features of
* Open Watcom's FORTRAN 77 compiler:
*
* 1. Extensions to the FORTRAN 77 standard are flagged.
*
* 2. Compile time error diagnostics are extensive. As many
* errors as possible are diagnosed.
*
* 3. Warning messages are displayed where potential problems
* can arise.
*
PROGRAM MAIN
DIMENSION A(10)
DO I=1,10
A(I) = I
I = I + 1
ENDLOOP
GO TO 30
J = J + 1
30 END
If we compile this program with the "extensions" option, the following output appears on the screen.
C>wfc demo1 -exten
WATCOM FORTRAN 77/16 Optimizing Compiler Version 2.0 1997/07/16 09:22:47
Copyright (c) 2002-2024 the Open Watcom Contributors. All Rights Reserved.
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See https://github.com/open-watcom/open-watcom-v2 for details.
demo1.for(14): *EXT* DO-05 this DO loop form is not FORTRAN 77 standard
demo1.for(16): *ERR* DO-07 column 13, DO variable cannot be redefined
while DO loop is active
demo1.for(17): *ERR* SP-19 ENDLOOP statement does not match with DO
statement
demo1.for(19): *WRN* ST-08 this statement will never be executed due to
the preceding branch
demo1.for: 9 statements, 0 bytes, 1 extensions, 1 warnings, 2 errors
Here we see an example of the three types of messages, extension (*EXT*), error (*ERR*) and warning (*WRN*).
Diagnostic messages are also included in the listing file if the "list" option is specified. If we
recompile our program and include the "list" option, a listing file will be created.
C>wfc demo1 -exten-list
or
C>wfc386 demo1 -exten-list
The contents of the listing file are:
WATCOM FORTRAN 77/16 Optimizing Compiler Version 2.0 1997/07/16 09:22:47
Copyright (c) 2002-2024 the Open Watcom Contributors. All Rights Reserved.
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See https://github.com/open-watcom/open-watcom-v2 for details.
Options: list,disk,errorfile,extensions,reference,warnings,fpi,oc,of,om,
os,ot,ox,ml,0,terminal,dependency,fsfloats,gsfloats,libinfo,dt=256,
align
1 * This program demonstrates the following features
of
2 * Open Watcom's FORTRAN 77 compiler:
3 *
4 * 1. Extensions to the FORTRAN 77
standard are flagged.
5 *
6 * 2. Compile time error diagnostics
are extensive. As many
7 * errors as possible
are diagnosed.
8 *
9 * 3. Warning messages are displayed
where potential problems
10 * can arise.
11 *
12 PROGRAM
MAIN
13 DIMENSION
A(10)
14 DO I=1,10
*EXT* DO-05 this DO loop form is not FORTRAN 77 standard
15
A(I) = I
16
I = I + 1
$
*ERR* DO-07 DO variable cannot be redefined while DO loop is active
17 ENDLOOP
*ERR* SP-19 ENDLOOP statement does not match with DO statement
18 GO TO 30
19 J = J +
1
*WRN* ST-08 this statement will never be executed due to the preceding branch
20 30 END
Code size (in bytes):
0 Number of errors:
2
Compile time (in seconds): 0 Number
of warnings: 1
Number of statements compiled: 9 Number of extensions:
1
As part of the diagnostic capability of Open Watcom F77, a "$" is often used to indicate the particular
place in the source line where an error has been detected.
Open Watcom FORTRAN 77 INCLUDE File Processing
For information on include file processing, see the section entitled The INCLUDE Compiler Directive
in the chapter entitled Open Watcom FORTRAN 77 Compiler Directives.
The Open Watcom FORTRAN 77 Libraries
The Open Watcom FORTRAN 77 library routines (intrinsic functions) are described in the Open Watcom FORTRAN 77 Language
Reference manual. Additional run-time routines are described in the chapter entitled The Open Watcom F77 Subprogram Library.
Since Open Watcom FORTRAN 77 supports two major architectures, the 286 architecture (which includes the 8088) and the
386 architecture (which includes the 486 and Pentium processors), libraries are grouped under two major directories.
For the 286 architecture, the processor dependent libraries are placed under the \WATCOM\LIB286 directory.
For the 386 architecture, the processor dependent libraries are placed under the \WATCOM\LIB386 directory.
Since Open Watcom FORTRAN 77 also supports several operating systems, including DOS, Windows 3.x, Windows 95, Windows
NT, OS/2 and NetWare, system-dependent libraries are grouped under different directories underneath the processor-dependent
directories.
System 16-bit applications 32-bit applications
--------- --------------------- ---------------------
DOS \WATCOM\LIB286\DOS
\WATCOM\LIB386\DOS
OS/2 \WATCOM\LIB286\OS2
\WATCOM\LIB386\OS2
Windows 3.x \WATCOM\LIB286\WIN \WATCOM\LIB386\WIN
Windows NT
\WATCOM\LIB386\NT
Windows 95
NetWare
\WATCOM\LIB386\NETWARE
\watcom
|
.-----------+----------------.
|
|
lib286
lib386
|
|
.-------+-------. .-------.-------+-------.-------.
| | |
| | |
| |
dos os2 win dos
os2 win nt netware
| | |
| | |
| |
Due to the many code generation strategies possible in the 80x86 family of processors, a number of versions of the
libraries are provided. You must use the libraries which coincide with the particular architecture, operating system,
and code generation strategy or model that you have selected. For the type of code generation strategy or model that
you intend to use, refer to the description of the "m?" memory model compiler option in the chapter entitled Open Watcom FORTRAN 77 Compiler Options.
The various code models supported by Open Watcom FORTRAN 77 are described in the chapters entitled 16-bit: Memory Models
and 32-bit: Memory Models.
We have selected a simple naming convention for the libraries that are provided with Open Watcom FORTRAN 77.
Letters are affixed to the file name to indicate the particular strategy with which the modules in the library have been
compiled.
- M
- denotes a version of the 16-bit Open Watcom FORTRAN 77 libraries which have been compiled for the "medium" memory
model (big code, small data).
L
- denotes a version of the 16-bit Open Watcom FORTRAN 77 libraries which have been compiled for the "large" or "huge"
memory models (big code, big data or huge data).
7
- denotes a version of the Open Watcom FORTRAN 77 libraries which should be used when compiling with the "fpi" or
"fpi87" option. Otherwise the libraries have been compiled using the "fpc" compiler option.
S
- denotes a version of the 32-bit Open Watcom FORTRAN 77 libraries which have been compiled using the "sc" option
(stack calling conventions).
The 16-bit Open Watcom FORTRAN 77 libraries are listed below by directory.
Under \WATCOM\LIB286\DOS
FLIBM.LIB (DOS medium model)
FLIB7M.LIB (DOS medium model, in-line 80x87)
FLIBL.LIB (DOS large/huge model)
FLIB7L.LIB (DOS large/huge model, in-line 80x87)
CLIBM.LIB (DOS i/o system medium model)
CLIBL.LIB (DOS i/o system large/huge model)
GRAPH.LIB (DOS graphics support)
Under \WATCOM\LIB286\WIN
FLIBM.LIB (Windows medium model)
FLIB7M.LIB (Windows medium model, in-line 80x87)
FLIBL.LIB (Windows large/huge model)
FLIB7L.LIB (Windows large/huge model, in-line 80x87)
CLIBM.LIB (Windows i/o system medium model)
CLIBL.LIB (Windows i/o system large/huge model)
WINDOWS.LIB (Windows API library)
Under \WATCOM\LIB286\OS2
FLIBM.LIB (OS/2 medium model)
FLIB7M.LIB (OS/2 medium model, in-line 80x87)
FLIBL.LIB (OS/2 large/huge model)
FLIB7L.LIB (OS/2 large/huge model, in-line 80x87)
CLIBM.LIB (OS/2 i/o system medium model)
CLIBL.LIB (OS/2 i/o system large/huge model)
DOSPMM.LIB (Phar Lap 286 PM medium model)
DOSPML.LIB (Phar Lap 286 PM large/huge model)
The 32-bit Open Watcom FORTRAN 77 libraries are listed below.
Under \WATCOM\LIB386\DOS
FLIB.LIB (floating-point calls)
FLIB7.LIB (in-line 80x87)
FLIBS.LIB (floating-point calls, stack conventions)
FLIB7S.LIB (in-line 80x87, stack conventions)
CLIB3R.LIB (i/o system)
CLIB3S.LIB (i/o system, stack conventions)
GRAPH.LIB (DOS graphics support)
The graphics library GRAPH.LIB is independent of the argument passing conventions or floating-point model.
Under \WATCOM\LIB386\WIN
FLIB.LIB (floating-point calls)
FLIB7.LIB (in-line 80x87)
FLIBS.LIB (floating-point calls, stack conventions)
FLIB7S.LIB (in-line 80x87, stack conventions)
CLIB3R.LIB (i/o system)
CLIB3S.LIB (i/o system, stack conventions)
WIN386.LIB (32-bit Windows API)
Under \WATCOM\LIB386\OS2
FLIB.LIB (floating-point calls)
FLIB7.LIB (in-line 80x87)
FLIBS.LIB (floating-point calls, stack conventions)
FLIB7S.LIB (in-line 80x87, stack conventions)
CLIB3R.LIB (i/o system)
CLIB3S.LIB (i/o system, stack conventions)
Under \WATCOM\LIB386\NT
FLIB.LIB (floating-point calls)
FLIB7.LIB (in-line 80x87)
FLIBS.LIB (floating-point calls, stack conventions)
FLIB7S.LIB (in-line 80x87, stack conventions)
CLIB3R.LIB (i/o system)
CLIB3S.LIB (i/o system, stack conventions)
Open Watcom FORTRAN 77 80x87 Emulator Libraries
One of the following libraries must be used if any of the modules of your application were compiled with the "fpi"
option.
16-bit Libraries
NOEMU87.LIB
DOS\EMU87.LIB (DOS dependent)
WIN\EMU87.LIB (Windows dependent)
OS2\EMU87.LIB (OS/2 dependent)
32-bit Libraries
NOEMU387.LIB
DOS\EMU387.LIB (DOS dependent)
WIN\EMU387.LIB (Windows dependent)
OS2\EMU387.LIB (OS/2 dependent)
NT\EMU387.LIB (Windows NT dependent)
The "fpi" option causes an 80x87 numeric data processor emulator to be linked into your application.
This emulator will decode and emulate 80x87 instructions when an 80x87 is not present in the system or if the environment
variable NO87 has been set (this variable is described below).
If you have compiled your application using the "fpi" option, you can also link with the 16-bit "noemu87.lib"
or 32-bit "noemu387.lib" library, depending on which compiler you are using. However, your application will
only run on a machine equipped with a 80x87 numeric data processor since the actual emulator is not linked into your application.
When the "fpi87" option is used exclusively, the emulator is not included. In this case, the application
must be run on personal computer systems equipped with the numeric data processor.
The "NO87" Environment Variable
If you have a math coprocessor in your system but you wish to test a version of your application that will use floating-point
emulation ("fpi" option) or simulation ("fpc" option), you can define the NO87 environment variable.
The 16-bit application must be compiled using the "fpc" (floating-point calls) option and linked with the
appropriate flib?.lib library or the "fpi" option (default) and linked with the appropriate flib7?.lib
and emu87.lib libraries. The 32-bit application must be compiled using the "fpc" (floating-point
calls) option and linked with the appropriate flib?.lib library or the "fpi" option (default) and linked
with the appropriate flib7?.lib and emu387.lib libraries. Using the "SET" command, define
the environment variable as follows:
C>SET NO87=1
Now, when you run your application, the 80x87 will be ignored. To undefine the environment variable, enter the
command:
C>SET NO87=
Open Watcom FORTRAN 77 Compiler Directives
A number of compiler directives are available that allow, for example, conditional compilation of source code and the
inclusion of source code from other files. A compiler directive is specified by placing a comment character ('c', 'C',
or '*') in column one followed by a dollar sign ('$') immediately followed by the compiler directive. The following
lists all of the compiler directives available with Open Watcom F77.
- EJECT
- INCLUDE
- PRAGMA
- DEFINE
- UNDEFINE
- IFDEF
- IFNDEF
- ENDIF
- ELSE
- ELIFDEF
- ELIFNDEF
These compiler directives will be described in the following sections.
In addition to the above compiler directives, it is also possible to specify certain compiler options in the same
way. The following lists these options.
- [NO]EXTENSIONS
- [NO]LIST
- [NO]REFERENCE
- [NO]WARNINGS
For more information on these options, see the the chapter entitled Open Watcom FORTRAN 77 Compiler Options.
The EJECT Compiler Directive
This compiler directive causes a form-feed to be generated in the listing file. The listing file is a carriage-control
file that is created by the compiler when the "list" compiler option is specified. In the following example,
a form-feed character will be generated immediately before the source for subroutine sub2 and immediately before
the source for subroutine sub3.
Example:
subroutine sub1
! source code
end
*$eject
subroutine sub2
! source code
end
*$eject
subroutine sub3
! source code
end
The INCLUDE Compiler Directive
The INCLUDE compiler directive or INCLUDE statement may be used to imbed source code into
the file being compiled. Either form may be used.
Example:
*$INCLUDE DOS.FI
INCLUDE 'DOS.FI'
When the INCLUDE statement is used the name of the file must be placed inside single quotes (apostrophes).
The file name may include drive, path, and file extension. The default file extension is .for.
It is not necessary to include the drive and path specifiers in the file specification when the file resides on a
different drive or in a different directory. Open Watcom F77 provides a mechanism for looking up include files which
may be located in various directories and disks of the computer system. When the drive and path are omitted from a
file specification, Open Watcom F77 searches directories for include files in the following order.
- First, the current directory is searched.
- Secondly, each directory listed with the "INCPath" option is searched (in the order that they were specified).
- Thirdly, each directory listed in the FINCLUDE environment variable is searched (in the order that they were specified).
The compiler will search the directories listed with the "INCPath" option or in the FINCLUDE environment
variable in a manner analogous to that which used by the operating system when searching for programs by using the PATH
environment variable.
The "INCPath" option takes the following form.
-INCPath=[d:]path;[d:]path...
The "SET" command is used to define an FINCLUDE environment variable that contains a list of directories.
A command of the form
SET FINCLUDE=[d:]path;[d:]path...
is issued before running Open Watcom F77 the first time. The brackets indicate that the drive d:
is optional and the ellipsis indicates that any number of paths may be specified.
We illustrate the use of the INCLUDE statement in the following example.
subroutine ClearScreen()
implicit none
include 'dos.fi'
integer VIDEO_CALL, SCROLL_UP
parameter (VIDEO_CALL=16, SCROLL_UP=6)
DS = ES = FS = GS = 0 ! for safety
on 386 DOS extender
AH = SCROLL_UP
! scroll up
AL = 0
! blank entire window
CX = 0
! set row,column of upper left
DX = 24*256 + 80
! set row,column of lower right
BH = 7
! attribute "white on black"
call fintr( VIDEO_CALL, regs )
end
The third line of this subroutine contains an INCLUDE statement for the file DOS.FI.
If the above source code is stored in the file CLRSCR.FOR in the current directory then we can issue the following
commands to compile the application.
C>set finclude=c:\watcom\src\fortran\dos
C>wfc clsscr
In the above example, the "SET" command is used to define the FINCLUDE environment variable.
It specifies that the \WATCOM\SRC\FORTRAN\DOS directory is to be searched for include files that cannot be located
in the current directory and that have no drive or path specified. The advantage of the FINCLUDE environment
variable is that drives and paths can be omitted from the INCLUDE file specifications in the source code. This allows
the source code to be independent of the disk/directory structure of your computer system.
The PRAGMA Compiler Directive
This compiler directive is described in the chapters entitled 16-bit: Pragmas and
32-bit: Pragmas.
The DEFINE Compiler Directive
The DEFINE compiler directive sets the definition status of a macro to defined. If a macro does not appear
in a DEFINE directive, its definition status is undefined.
Example:
*$define debug
In the above example, the macro debug is defined.
The DEFINE compiler option can also be used to define a macro.
Example:
C>wfc -define=debug test
C>wfc386 -define=debug test
The UNDEFINE Compiler Directive
The UNDEFINE compiler directive sets the definition status of a macro to undefined.
Example:
*$undefine debug
In the above example, the definition status of the macro debug is set to undefined.
The IFDEF, IFNDEF and ENDIF Compiler Directive
The IFDEF and IFNDEF compiler directives check the definition status of a macro. If the macro appearing in an IFDEF
directive is defined or the macro appearing in an IFNDEF directive is not defined, then all source code up to the corresponding
ENDIF compiler directive will be compiled. Otherwise, it will be ignored.
In the following example, the FORTRAN 77 statements represented by <debugging_statements> will be compiled.
Example:
*$define debug
...
*$ifdef debug
<debugging_statements>
*$endif
In the following example, the FORTRAN 77 statements represented by <debugging_statements> will not
be compiled.
Example:
*$undefine debug
...
*$ifdef debug
<debugging_statements>
*$endif
In the following example, the FORTRAN 77 statements represented by <debugging_statements> will be compiled.
Example:
*$undefine debug
...
*$ifndef debug
<debugging statements>
*$endif
The ELSE Compiler Directive
The ELSE compiler directive must be preceded by an IFDEF, IFNDEF, ELSEIFDEF or ELSEIFNDEF compiler directive. If
the condition of the preceding compiler directive was satisfied, then all source code between the ELSE compiler directive
and the corresponding ENDIF compiler directive will be ignored. If the condition of the preceding compiler directive
was not satisfied, then all source code between the ELSE compiler directive and the corresponding ENDIF compiler directive
will be compiled.
In the following example, the FORTRAN 77 statements represented by <debugging_level_2_statements> will
be compiled.
Example:
*$undefine debug_level_1
...
*$ifdef debug_level_1
<debugging_level_1_statements>
*$else
<debugging_level_2_statements>
*$endif
The ELSEIFDEF and ELSEIFNDEF Compiler Directive
The ELSEIFDEF and ELSEIFNDEF compiler directives must be preceded by an IFDEF, IFNDEF, ELSEIFDEF or ELSEIFNDEF compiler
directive. If the condition of the preceding compiler directive was satisfied, then all source code between the ELSEIFDEF
or ELSEIFNDEF compiler directive and the corresponding ENDIF compiler directive will be ignored. If the condition of
the preceding compiler directive was not satisfied, then the definition status of the macro specified in the ELSEIFDEF or
ELSEIFNDEF compiler directive is checked. If the macro appearing in the ELSEIFDEF compiler directive is defined, or
the macro appearing in the ELSEIFNDEF compiler directive is not defined, then all source up to the next ELSEIFDEF, ELSEIFNDEF,
ELSE or ENDIF compiler directive will be compiled.
In the following example, the FORTRAN 77 statements represented by <debugging_level_2_statements> will
be compiled.
Example:
*$define debug_level_2
...
*$ifdef debug_level_1
<debugging_level_1_statements>
*$elseifdef debug_level_2
<debugging_level_2_statements>
*$endif
Debugging statements ("D" in Column 1)
If the character "D" or "d" appears in column 1, that line will be conditionally compiled depending
on the definition status of the macro __debug__. Statements that contain a "D" or "d"
in column 1 are called debugging statements. If the __debug__ macro is defined, the line will be compiled;
otherwise it will be ignored. The __debug__ macro can be defined by using the DEFINE compiler directive or
the "define" option. In the following example, the "define" option is used to force compilation
of debugging statements.
Example:
C>wfc -def=__debug__ test
C>wfc386 -def=__debug__ test
General Notes About Compiler Directives
- Compiler directives must not contain embedded blanks. The following is not a valid ENDIF compiler directive.
Example:
*$end if
- Nesting is allowed up to a maximum of 16 levels.
Example:
*$ifdef sym1
<statements>
*$ifdef sym2
<statements>
*$endif
*$endif
- The macro __i86__ is a special macro that is defined by the compiler and identifies the target as a 16-bit Intel
80x86 compatible environment.
- The macro __386__ is a special macro that is defined by the compiler and identifies the target as a 32-bit Intel
80386 compatible environment.
- The macro __stack_conventions__ is a special macro that is defined by the 32-bit compiler when stack conventions
are used for code generation. Stack conventions are used when the "sc" or "3s" compiler options
are specified.
- The macro __fpi__ is a special macro that is defined by the compiler when one of the following floating-point
options is specified: "fpi" or "fpi87".
- The macro __debug__ is a special macro that can be used to conditionally compile debugging statements.
A debugging statement is one that contains the character "D" or "d" in column one.
Open Watcom FORTRAN 77 File Handling
This chapter describes the file handling and naming conventions of Open Watcom F77. We discuss files and
devices which are used to store, retrieve and display data. For example, a disk can be used to store a file of
student marks. This file is accessible by other programs in order to produce summaries of the data such as marks reports.
A device such as a printer can also be treated as if it were a file, although it is only useful for displaying data;
an attempt to read information from this device is invalid.
In the following sections, we shall describe:
- the techniques that Open Watcom F77 adopts for implementing FORMATTED and UNFORMATTED records and SEQUENTIAL
and DIRECT access to these records,
- the handling of "print" files,
- file naming conventions,
- logical file names,
- the preconnection of files to units, and
- special device support.
Record Access
Two types of record access are supported by Open Watcom F77:
- Sequential
- Sequential access means that records in a file are accessed in order, starting with the first record in the file and proceeding
to the last. Sequential access is permitted to records in both variable-length and fixed-length record files.
Direct
- Direct access means that records in a file are accessed in random order. For example, the fifth record could be accessed,
then the second, and then the tenth. Direct access is permitted for fixed-length record files only.
The access method is described using the ACCESS= specifier of the FORTRAN OPEN statement.
The default access is "SEQUENTIAL".
There are two record formats, "FORMATTED" and "UNFORMATTED", which are supported by Open Watcom F77.
The record format is described using the FORM= specifier of the FORTRAN OPEN statement.
The default format is "FORMATTED" for files connected for sequential access and "UNFORMATTED" for
files connected for direct access.
In describing these two formats, we also refer to the two methods of record access, "SEQUENTIAL" and "DIRECT",
which are supported by Open Watcom F77.
A FORMATTED record is one that contains an arbitrary number of ASCII characters. The end of a record is marked
by an ASCII "LF" (line feed) character optionally preceded by an ASCII "CR" (carriage return) character.
Thus this special sequence may not appear in the middle of a record.
FORMATTED records may vary in length. If all the records in the file have the same length then the records may
be accessed both "sequentially" and "directly". If the records vary in length then it is only possible
to access the records sequentially.
For direct access, the length of the records is specified by the RECL= specifier of the FORTRAN
OPEN statement. The specified length must not include the record separator since it does not form part of the
record.
As an extension to the FORTRAN 77 language standard, Open Watcom F77 also supports the use of the RECL=
specifier for sequential access. The maximum length of the records may be specified by the RECL= specifier
of the FORTRAN OPEN statement. The specified length must not include the record separator since it does
not form part of the record. The length is used to allocate a record buffer for sequential access. If the record
length is not specified, a default maximum length of 1024 characters is assumed.
An UNFORMATTED record is one that contains an arbitrary number of binary storage units. The interpretation
of the data in such a record depends on the FORTRAN program that is processing the record. An UNFORMATTED record may
contain integers, real numbers, character strings, or any other type of FORTRAN data.
UNFORMATTED records may also vary in length. If all records in the file have the same length then the records
may be accessed both "sequentially" and "directly". If the records vary in length then it is only
possible to access the records sequentially.
When a file containing UNFORMATTED records is accessed sequentially, each record must begin and end with a descriptor
that contains the length of the record. The length of the record is represented in 32 bits or 4 bytes (INTEGER*4).
The UNFORMATTED records of a file which are written using sequential access will be automatically supplied with the
appropriate length descriptors. When such a file is read, it is assumed that each record has the appropriate length
descriptors.
Depending on the record length, the output produced by a single unformatted sequential WRITE statement
may cause multiple records to be written. As previously mentioned, each record begins and ends with a length descriptor.
The length descriptors for the first record contain the length of the record. The length descriptors for the
remaining records contain the length of the record with the high bit (bit 31) set to one. In this way, an unformatted
sequential file can be viewed as a number of logical records (a logical record corresponding to the output produced by a
WRITE statement) with each logical record composed of a number of physical records. Files created in
this way cannot be accessed directly unless each logical record is composed of a single physical record and each record is
the same size.
As an extension to the FORTRAN 77 language standard, Open Watcom F77 also supports the use of the RECL=
specifier for sequential access. The maximum length of the records may be specified by the RECL= specifier
of the FORTRAN OPEN statement. The specified length must not include the length descriptors since they
do not form part of the record. The length is used to allocate a record buffer for sequential access. If the
record length is not specified, a default maximum length of 1024 characters is assumed.
When a file containing UNFORMATTED records is accessed directly, each record must be the same length. In this
case, the length of the records is specified by the RECL= specifier of the FORTRAN OPEN statement.
If the file was originally created with sequential access then the specified length must include any length descriptors
which form part of the record. In the direct access mode, no interpretation is placed on any of the data in an UNFORMATTED
record and the programmer must account for any record length descriptors which may form part of the record.
Any records which are written using direct access must include record length descriptors if the file is to be accessed
sequentially at a later time. As an alternative, you may specify RECORDTYPE='VARIABLE' in the FORTRAN
OPEN statement. This specifier is an extension to the FORTRAN 77 language standard and will cause length descriptors
to be generated automatically. In this case, the record length should not include the record length descriptors.
Files with no Record Structure
Certain files, for example a file created by a program written in another language, do not have any internal record structure
that matches any of the record structures supported by Open Watcom F77. These files are simply streams of data.
There are two ways in which these files can be processed.
- You can use unformatted direct access. In this case, the value specified by the RECL= specifier in
the OPEN statement determines the amount of data read or written by a READ or WRITE
statement.
- Alternatively, you can use unformatted sequential access. In this case, the amount of data read or written to the
file is determined by the items in the input/output list of the READ or WRITE statement.
When using unformatted sequential access, you must specify RECORDTYPE='FIXED' to indicate that no record boundaries
are present. Otherwise, the default value of 'VARIABLE' will be used.
Attributes of Files
The file system does not retain any information on the contents of a file. Unlike more sophisticated file systems,
it cannot report whether a file consists of fixed-length or variable-length records, how records are delimited in a file,
the maximum length of the records, etc. Therefore, we have provided a mechanism which will allow you to specify additional
information about a file. This mechanism should be used when the default assumptions about records in a file are not
true for the file in question.
The RECORDTYPE= specifier of the FORTRAN OPEN statement can be used to specify additional
information about the type of records in the file. This specifier is an extension to the FORTRAN 77 language standard.
The RECL= specifier of the FORTRAN OPEN statement can be used to specify additional
information about the length of records in the file. When used with sequential access, this specifier is an extension
to the FORTRAN 77 language standard.
The CARRIAGECONTROL= specifier of the FORTRAN OPEN statement can be used to specify
additional information about the handling of ASA carriage control characters for an output file. This specifier is
an extension to the FORTRAN 77 language standard.
The BLOCKSIZE= specifier of the FORTRAN OPEN statement can be used to specify the size
of the internal input/output buffer. A buffer reduces the number of system input/output calls during input/output to
a particular file and hence improves the overall performance of a program. The default buffer size is 4K. This
specifier is an extension to the FORTRAN 77 language standard.
The following sections describe the attributes of records supported by the Open Watcom F77 run-time system.
Record Type
The RECORDTYPE= specifier of the FORTRAN OPEN statement can be used to specify additional
information about the type of records in the file. This specifier is an extension to the FORTRAN 77 language standard.
The following types may be specified.
RECORDTYPE='TEXT'
RECORDTYPE='VARIABLE'
RECORDTYPE='FIXED'
- TEXT
- indicates that the file contains variable-length or fixed-length records of ASCII characters separated by an ASCII "LF"
(line feed) character optionally preceded with an ASCII "CR" (carriage return) character. By default, the
Open Watcom F77 run-time system assumes that FORMATTED records are of TEXT format in both the
sequential and direct access modes.
By default, the Open Watcom F77 run-time system uses variable-length record TEXT files to implement
FORMATTED records in the sequential access mode. Of course, all records may be the same length.
The record separator is not included in calculating the maximum size of records in the file.
By default, the Open Watcom F77 run-time system uses fixed-length record TEXT files to implement
FORMATTED records in the direct access mode. Each record must be the same length. The record separator
is not included in calculating the size of records in the file.
VARIABLE
- indicates that the file contains variable-length or fixed-length records in which special descriptors are employed to describe
the length of each record. The length of each record is contained in a doubleword (INTEGER*4 item) at the beginning
and end of the record. These descriptors determine the bounds of the records.
By default, the Open Watcom F77 run-time system uses VARIABLE format files to implement UNFORMATTED
records in the sequential access mode. The length descriptors are required to support the FORTRAN BACKSPACE
statement since no other method exists for determining the bounds of a variable-length unformatted record in a file.
FIXED
- indicates that the file contains no extra information that determines the record structure. If the file is a direct
access file, the value specified by the RECL= specifier determines the size of each record in the file.
By default, the Open Watcom F77 run-time system uses FIXED format files to implement UNFORMATTED
records in the direct access mode.
If you specify FIXED with an unformatted sequential file, the size of the records is determined by
the items in the input/output list.
Record Size
When access is direct, the record length must be specified in the RECL= specifier of the FORTRAN
OPEN statement.
OPEN( UNIT=1, FILE='TEST.DAT', ACCESS='DIRECT', RECL=size, ... )
As an extension to the FORTRAN 77 language standard, the record length may also be specified when the access is
sequential. This should be done whenever access is "sequential" and the maximum record length is greater
than the default.
OPEN( UNIT=1, FILE='TEST.DAT', ACCESS='SEQUENTIAL', RECL=size, ... )
The record length specified by size should not include record separators such as CR and LF, nor should it include
record length descriptors when sequentially accessing a file containing unformatted records. However, for all files,
records longer than the size specified will be truncated. The default record size is 1024. The maximum record
size is 65535 for the 16-bit run-time system. Since record buffers are allocated in the dynamic storage region, the
size will be restricted to the amount of dynamic storage available.
Print File Attributes
When the first character of each record written to a file will contain an ASA (American Standards Association) carriage
control character, the CARRIAGECONTROL= specifier of the FORTRAN OPEN statement should be used.
This specifier is an extension to the FORTRAN 77 language standard. The ASA character is used for vertical spacing
control. The valid characters and their interpretation are:
- "1"
- Advance to Top of Page
"+"
- Advance Zero Lines (overprint)
" "
- Advance 1 Line
"0"
- Advance 2 Lines
"-"
- Advance 3 Lines
If CARRIAGECONTROL='YES' is specified then the Open Watcom F77 run-time system will automatically allocate an
extra character at the beginning of a record for the vertical spacing control.
Upon transmitting a record to a file which has the "carriage" attribute, the Open Watcom F77 run-time system
will substitute the appropriate ASCII carriage control characters as follows.
- "1"
- Substitute a FF (form feed) for the "1".
"+"
- Append only a CR (carriage return ) to the previous record.
" "
- Throw away the blank character.
"0"
- Substitute CR (carriage return) and LF (line feed) for the "0".
"-"
- Substitute two pairs of CR and LF for the "-".
Any other character in this position will be treated as if a blank character had been found (i.e., it will be discarded).
If the "carriage" attribute is not specified for a file then records will be written to the file without placing
any interpretation on the first character position of the record.
The BLOCKSIZE= specifier is optional. However if you would like to change the default buffer size
of 16K for 32-bit applications and 4K for 16-bit applications, you must specify the buffer size in the BLOCKSIZE=
specifier of the OPEN statement.
OPEN( UNIT=1, FILE='TEST.DAT', BLOCKSIZE=1024, ... )
File Sharing
On systems that support multi-tasking or networking, it is possible for for a file to be accessed simultaneously by more
that one process. There are two specifiers in the OPEN statement that can be used to control the way
in which files are shared between processes.
The ACTION= specifier indicates the way in which the file is initially accessed. That is, the
way in which the first process to open the file accesses the file. The values allowed for the ACTION=
specifier are the following.
- 'READ'
- the file is opened for read-only access
'WRITE'
- the file is opened for write-only access
'READWRITE'
- the file is opened for both read and write access
The SHARE= specifier can be used to indicate the manner in which subsequent processes are allowed to access
the file while the file is open. The values allowed for the SHARE= specifier are the following.
- 'COMPAT'
- no other process may open the file
'DENYRW'
- other processes are denied read and write access
'DENYWR'
- other process are denied write access (allowed read-only access)
'DENYRD'
- other process are denied read access (allowed write-only access)
'DENYNONE'
- other processes are allowed read and write access
Let us consider the following scenario. Suppose you want several processes to read a file and prevent any process
that is reading the file from changing its contents. We first must establish the method of access for the first process
that opens the file. In this case, we want read-only access so the ACTION='READ' specifier must be used.
Next, we must establish the method of access for subsequent processes. In our example, we do not want any process to
make changes to the file. Therefore, we use the SHARE='DENYWR' specifier. The file would be opened using
the following OPEN statement.
OPEN( UNIT=1, FILE='TEST.DAT', ACTION='READ', SHARE='DENYWR', ... )
File Names in the FAT File System
The FAT file system is supported by DOS and OS/2. OS/2 also supports the High Performance File System (HPFS) which
will be discussed in a later section. File naming conventions are used to form file designations in a given file system.
The file designation for a FAT file system has the following form.
[d:][path]filename[.ext]
- []
- The square brackets denote items which are optional.
d:
- is the drive name. If omitted, the default drive is assumed.
Examples of drive names are: a:, b:, c:, and d:.
path
- is called a "path" specification. The path may be used to refer to files that are stored in sub-directories
of the disk. The complete file specification (including drive, path and file name) cannot exceed 143 characters.
Some examples of path specifications are:
\plot\
\bench\tools\
\fortran\pgms\
Your operating system manuals can tell you more about directories: how to create them, how to store files in
them, how to specify a path, etc.
filename
- is the main part of the file's name. The filename can contain up to 8 characters. If more than 8 characters are
used, only the first 8 are meaningful. For example, "COUNTRIES" and "COUNTRIE" are treated as the
same name for a file.
ext
- is an optional extension consisting of 1 to 3 characters (e.g., DOC). If an extension is specified, it is separated
from the filename by a period. Extensions are normally used to indicate the type of information stored in the file.
For example, a file extension of for is a common convention for FORTRAN programs.
Note: The file specification is case insensitive in that upper and lower case letters can be
used interchangeably.
Special DOS Device Names
Certain file names are reserved for devices. These special device names are:
CON the console (or terminal)
AUX the serial port
COM1 another name for the serial port
COM2 a second serial port
PRN the parallel printer
LPT1 another name for the printer
LPT2 a second parallel printer
LPT3 a third parallel printer
NUL nonexistent device
When using one of these special device names, no other part of the file designation should be specified. A common
mistake is to attempt to create a disk file such as PRN.DAT and attempt to write records to it. If you do
not have a parallel printer attached to your PC, there may be a long delay before the output operation times out.
Examples of FAT File Specifications
The following are some examples of valid file specifications.
- The following file designation refers to a file in the current directory of the default disk.
OPEN( UNIT=1, FILE='DATA.FIL', ... )
- The following file designation refers to a print file in the current directory of drive c:. ASA carriage
control characters will be converted to the appropriate ASCII control codes.
OPEN( UNIT=2, FILE='c:report.lst',
CARRIAGECONTROL='YES', ... )
- The file specification below indicates that the file is to have fixed format records of length 80.
OPEN( UNIT=3, FILE='final.tst',
RECL=80, RECORDTYPE='FIXED', ... )
- The file specification below indicates that the file is to have variable format records of maximum length 145.
OPEN( UNIT=4, FILE='term.rpt',
RECL=145, RECORDTYPE='VARIABLE', ... )
- The file designation below indicates that the file resides in the records directory of drive b:.
OPEN( UNIT=5, FILE='b:\records\customers.dat', ... )
Note that the trailing "S" in the file name will be ignored. Thus the following designation is equivalent.
OPEN( UNIT=5, FILE='b:\records\customer.dat', ... )
- The file designation below refers to the second serial port.
OPEN( UNIT=6, FILE='com2', ... )
- The file designation below refers to a second parallel printer.
OPEN( UNIT=7, FILE='lpt2', ... )
OS/2, in addition to supporting the FAT file system, also supports the High Performance File System (HPFS). The
rules for forming file names in the High Performance File System are different from those used to form file names in the
FAT file system. In HPFS, file names and directory names can be up to 254 characters in length. However, the
complete path (including drive, directories and file name) cannot exceed 259 characters. The period is a valid file
name character and can appear in a file name or directory name as many times as required; HPFS file names do not require
file extensions as in the FAT file system. However, many applications still use the period to denote file extensions.
The HPFS preserves case in file names only in directory listings but ignores case in file searches and other system
operations. For example, a directory cannot have more than one file whose names differ only in case.
Special OS/2 Device Names
The OS/2 operating system has reserved certain file names for character devices. These special device names are:
CLOCK$ Clock
COM1 First serial port
COM2 Second serial port
COM3 Third serial port
COM4 Fourth serial port
CON Console keyboard
and screen
KBD$ Keyboard
LPT1 First parallel printer
LPT2 Second parallel printer
LPT3 Third parallel printer
MOUSE$ Mouse
NUL Nonexistent (dummy)
device
POINTER$ Pointer draw device (mouse screen support)
PRN The default printer,
usually LPT1
SCREEN$ Screen
When using one of these special device names, no other part of the file designation should be specified.
Examples of HPFS File Specifications
The following are some examples of valid file specifications.
- The following file designation refers to a file in the current directory of the default disk.
OPEN( UNIT=1, FILE='DATA.FIL', ... )
- The following file designation refers to a print file in the current directory of drive c:. ASA carriage
control characters will be converted to the appropriate ASCII control codes.
OPEN( UNIT=2, FILE='c:report.lst',
CARRIAGECONTROL='YES', ... )
- The file specification below indicates that the file is to have fixed format records of length 80.
OPEN( UNIT=3, FILE='final.tst',
RECL=80, RECORDTYPE='FIXED', ... )
- The file specification below indicates that the file is to have variable format records of maximum length 145.
OPEN( UNIT=4, FILE='term.rpt',
RECL=145, RECORDTYPE='VARIABLE', ... )
- The file designation below indicates that the file resides in the records directory of drive b:.
OPEN( UNIT=5, FILE='b:\records\customers.dat', ... )
Note that the trailing "S" in the file name is not ignored as is the case in a FAT file system.
- The file designation below refers to the second serial port.
OPEN( UNIT=6, FILE='com2', ... )
- The file designation below refers to a second parallel printer.
OPEN( UNIT=7, FILE='lpt2', ... )
Establishing Connections Between Units and Files
Using Open Watcom F77, FORTRAN unit numbers may range from 0 to 999. Input/output statements such as READ
and WRITE refer to files by a unit number. All input/output statements except OPEN,
CLOSE, and INQUIRE must refer to a unit that is connected to a file. The Open Watcom F77 run-time
system automatically establishes the connection of a unit to a file if no connection previously existed. Any connection
between a unit and a file that is established before execution begins is called a preconnection.
The Open Watcom F77 run-time system defines a preconnection of the unit designated by "*" to the standard
input and output devices (by this we generally mean the keyboard and screen of the personal computer but input/output can
be redirected from/to a file using the standard input/output redirectors "<" and ">" on the command
line). This preconnection cannot be altered in any way. Unit "*" is explicitly or implicitly referred
to by the following input statements:
READ, ...
READ *, ...
READ format-spec, ...
READ(*,...) ...
READ(UNIT=*,...) ...
Unit "*" is explicitly or implicitly referred to by the following output statements:
PRINT, ...
PRINT *, ...
PRINT format-spec, ...
WRITE(*,...) ...
WRITE(UNIT=*,...) ...
The Open Watcom F77 run-time system also defines a preconnection of unit 5 to the standard input device (by this we
generally mean the keyboard of the personal computer but input can be redirected from a file using the standard input redirector
"<" on the command line).
The Open Watcom F77 run-time system also defines a preconnection of unit 6 to the standard output device (by this
we generally mean the screen of the personal computer but output can be redirected to a file using the standard output redirector
">" on the command line).
For all other allowable units, a default preconnection between unit number "nnn" and the file FORnnn
is assumed when no connection between a unit and a file has been established. nnn is a three-digit FORTRAN unit
number. Unit 0 is "000", unit 1 is "001", unit 2 is "002", and so on. There is
no file extension in this case. In other words, a default file name is constructed for any unit number for which no
other connection has been established. Input/output statements of the following forms refer to these units.
CLOSE(nnn,...) OPEN(nnn,...)
CLOSE(UNIT=nnn,...) OPEN(UNIT=nnn,...)
BACKSPACE nnn READ(nnn,...)
BACKSPACE(nnn) READ(UNIT=nnn,...)
BACKSPACE(UNIT=nnn) REWIND nnn
ENDFILE nnn
REWIND(nnn)
ENDFILE(nnn) REWIND(UNIT=nnn)
ENDFILE(UNIT=nnn) WRITE(nnn,...) ...
INQUIRE(nnn,...) WRITE(UNIT=nnn,...) ...
INQUIRE(UNIT=nnn,...)
Of course, it is unlikely that one would be satisfied with using such undistinguished file names such as for000,
for001, and so on. Therefore, the Open Watcom F77 run-time system provides additional ways of establishing a preconnection
between a FORTRAN UNIT and a file.
The Open Watcom F77 run-time system supports the use of the "SET" command to establish a connection between
a unit and a file. The "SET" command is used to create, modify and remove "Environment Variables".
The "SET" command must be issued before running a program. The format for a preconnection using the
"SET" command is:
SET unit=file_spec
- where
- description
unit
- is a FORTRAN unit number in the range 0 to 999.
If this form of the "SET" command is used then FORTRAN unit number unit is preconnected to the specified
file. FORTRAN input/output statements which refer to the unit number will access the records in the specified file.
file_spec
- is the file specification of the preconnected file.
Here are some sample "SET" commands.
Example:
C>set 1=input.dat
C>set 2=output.dat
C>set 3=d:\database\customer.fil
The above example establishes the following preconnections:
- Between unit 1 and the file input.dat which resides (or will reside) in the current directory.
- Between unit 2 and the file output.dat which resides (or will reside) in the current directory.
- Between unit 3 and the file d:\database\customer.fil which resides (or will reside) in another disk and directory.
Any FORTRAN input/output statements which refer to units 1, 2 or 3 will act upon one of these 3 data files.
Notes:
- The "SET" command must be issued before running the program.
- No spaces should be placed before or after the "=" in the "SET" command. The following two examples
are quite distinct from each other:
Example:
C>set 55=testbed.dat
C>set 55 = testbed.dat
To verify this, simply enter the two commands and then enter the "SET" command again with no arguments.
The current environment strings will be displayed. You should find two entries, one for "55" and one
for "55 ".
- Since the number in front of the "=" is simply a character string, you should not specify any leading zeroes
either.
Example:
C>set 01=input.dat
C>set 1=input.dat
In this case, we again have two distinct environment variables. The variable "01" will be ignored
by the Open Watcom F77 run-time system.
- An environment variable will remain in effect until you explicitly remove it or you turn off the personal computer.
To discontinue the preconnection between a unit number and a file, you must issue a "SET" command of the following
form.
C>set <unit>=
In the above command, <unit> is the unit number for which the preconnection is to be discontinued.
By omitting the character string after the "=", the environment variable will be removed. For example,
to remove the environment variable "01" from the list, reenter the "SET" command specifying everything
up to and including the "=" character.
Example:
C>set 01=
- Any time you wish to see the current list of environment strings, simply enter the "SET" command with no arguments.
Example:
C>set
PROMPT=$d $t $p$_$n$g
COMSPEC=d:\dos\command.com
PATH=G:\;E:\CMDS;C:\WATCOM\BIN;D:\DOS;D:\BIN
LIB=c:\watcom\lib286\dos
1=input.dat
2=output.dat
3=d:\database\customer.fil
- An alternative to preconnecting files is provided by the FORTRAN OPEN statement which allows files to be
connected at execution time.
- The preconnection of units 5 and 6 may be overridden using preconnection specifications or the FORTRAN OPEN
statement. The precedence of a connection between a unit number and a file is as follows:
- Precedence:
- User option:
Lowest
- Preconnection Specifications
Highest
- OPEN statement
In other words, the OPEN statement overrides a preconnection.
A Preconnection Tutorial
In this section, we will look at some examples of how to establish the link between a file and a FORTRAN unit.
Exhibit 1:
Consider the following example which reads pairs of numbers from a file and writes out the numbers and their sum.
* File 'iodemo.for'
10 READ( 1, *, END=99 ) X1, X2
WRITE( 6, 20 ) X1, X2, X1 + X2
GO TO 10
20 FORMAT( 3F6.2 )
99 END
The FORTRAN READ statement will read records from a file connected to unit 1. The FORTRAN
WRITE statement will write records to a file connected to unit 6. As we described in the previous section,
unit 6 is preconnected by the Open Watcom F77 run-time system to the screen.
What file will be read when the READ statement refers to unit 1? By default, we know that it
will read a file called for001. However, suppose the data was actually stored in the file called numbers.dat.
We can direct the program to read the data in this file by using a "SET" command before running the program.
Example:
C>set 1=numbers.dat
C>iodemo
1.40 2.50 3.90
3.90 8.70 12.60
1.10 9.90 11.00
8.30 7.10 15.40
8.20 3.50 11.70
Exhibit 2:
Suppose that we now wish to write the output from the above program to a disk file instead of the screen. We
can do this without modifying the program. Since we know that the WRITE statement refers to unit 6,
we can alter the default preconnection of unit 6 to the screen by issuing another "SET" command.
Example:
C>set 6=numbers.rpt
C>iodemo
C>type numbers.rpt
1.40 2.50 3.90
3.90 8.70 12.60
1.10 9.90 11.00
8.30 7.10 15.40
8.20 3.50 11.70
Now any time a program writes or prints to unit 6, the output will be written to the disk file numbers.rpt.
If you are going to run other programs, it would be wise to remove the connection between unit 6 and this file so that
it is not accidentally overwritten. This can be done by issuing the following command.
Example:
C>set 6=
You should also do the same for unit 1.
Exhibit 3:
Must we always use "SET" commands to establish the connection between a unit and a file? Suppose that
you want to run the program quite often and that you do not want to issue "SET" commands every time. We can
do this by modifying the program to include FORTRAN OPEN statements.
* File 'iodemo.for'
OPEN( 1, FILE='NUMBERS.DAT' )
OPEN( 6, FILE='NUMBERS.RPT' )
10 READ( 1, *, END=99 ) X1, X2
WRITE( 6, 20 ) X1, X2, X1 + X2
GO TO 10
20 FORMAT( 3F6.2 )
99 END
This is an example of a connection that is established at execution time. The connection that is established
by the OPEN statement overrides any preconnection that we might have established using a "SET" command.
We say that the OPEN statement has a higher precedence. However, even the OPEN
statement does not have the final word on which files will be accessed. You may wish to read the next section on the
Open Watcom F77 run-time system logical file name support to find out why this is so.
Logical File Name Support
The Open Watcom F77 run-time system supports logical or symbolic file names using the "SET" command. The
"SET" command may be used to define a logical file name and its corresponding actual file name. The format
for defining a logical file name is as follows:
SET name=file_spec
- where
- description
name
- is any character string. The letters in "name" may be specified in upper or lower case. Lower case letters
are treated as if they had been specified in upper case. Thus "SYSINPUT" and "sysinput" are equivalent.
Note, however, that blank characters must not be specified before and after the "=" character.
file_spec
- is the file specification of logical file.
Notes and Examples:
- A logical file name may be used in the FILE= specifier of the FORTRAN OPEN and INQUIRE
statements.
Example:
* File 'iodemo.for'
OPEN( 1, FILE='SYSINPUT' )
10 READ( 1, *, END=99 ) X1, X2
WRITE( 6, 20 ) X1, X2, X1 + X2
GO TO 10
20 FORMAT( 3F6.2 )
99 END
In the following example, we define the logical file name "SYSINPUT" to correspond to the file numbers.dat.
Example:
C>set sysinput=numbers.dat
C>iodemo
1.40 2.50 3.90
3.90 8.70 12.60
1.10 9.90 11.00
8.30 7.10 15.40
8.20 3.50 11.70
- If the name in a FILE= specifier is not included in one of the environment variable names then it is assumed
to be the actual name of a file.
Example:
OPEN( 2, FILE='SYSOUT' )
- The logical file name feature can also be used to provide additional information regarding the file name at execution
time.
Example:
* File 'iodemo.for'
OPEN( 1, FILE='numbers.dat' )
10 READ( 1, *, END=99 ) X1, X2
WRITE( 6, 20 ) X1, X2, X1 + X2
GO TO 10
20 FORMAT( 3F6.2 )
99 END
In the following example, the actual location (and name) of the file numbers.dat is described through the
use of an environment variable.
Example:
C>set numbers.dat=b:\data\input.dat
C>iodemo
As you can see, a logical file name can resemble an actual file name.
Of course, the entire file name could have been specified in the FORTRAN program.
Example:
OPEN( 1, FILE='b:\data\input.dat' )
- Only one level of lookup is performed.
Example:
* File 'iodemo.for'
OPEN( 1, FILE='sysinput' )
10 READ( 1, *, END=99 ) X1, X2
WRITE( 6, 20 ) X1, X2, X1 + X2
GO TO 10
20 FORMAT( 3F6.2 )
99 END
This is illustrated by the following commands.
Example:
C>set sysinput=datafile
C>set datafile=input.dat
C>iodemo
In the above example, unit 1 is connected to the file datafile and not the file input.dat.
- Logical file names can be used to direct output normally intended for one device to another device. Consider the
following examples.
Example:
C>set lpt1=lpt2
If the FORTRAN program specifies the name "LPT1" in an OPEN or INQUIRE statement,
the Open Watcom F77 run-time system will map this name to "LPT2". In an INQUIRE statement,
the NAME= specifier will return the name "LPT2".
- As we mentioned earlier, the case of the name does not matter. Upper or lower case can be used interchangeably.
Example:
C>set sysinput=b:\data\input.dat
C>set SYSINPUT=b:\data\input.dat
- No spaces should be placed before or after the "=" in the "SET" command. The following two examples
are considered quite distinct from each other:
Example:
C>set sysinput=testbed.dat
C>set sysinput = testbed.dat
This example will define two variables, "SYSINPUT" and "SYSINPUT ".
- An environment variable will remain in effect until you explicitly remove it or you turn off the personal computer.
To remove an environment variable from the list, reenter the "SET" command specifying everything up to and including
the "=" character. For example, to remove the definition for "SYSINPUT", the following command
can be issued.
Example:
C>set sysinput=
- Any time you wish to see the current list of environment strings, simply enter the "SET" command with no arguments.
Example:
C>set
PROMPT=$d $t $p$_$n$g
COMSPEC=d:\dos\command.com
PATH=G:\;E:\CMDS;C:\WATCOM\BIN;D:\DOS;D:\BIN
LIB=c:\watcom\lib286\dos
1=input.dat
2=output.dat
3=d:\database\customer.fil
SYSINPUT=b:\data\input.dat
LPT1=lpt2
Terminal or Console Device Support
Input can come from the console or output can be written to the console by using the console device name con
as the file name. The console can be specified in a "SET" command or through the FILE= specifier
of the FORTRAN OPEN statement.
The default action for any file is to open the file for both read and write access (i.e., ACTION='READWRITE').
Under Win32, there is a problem accessing the console device con for both read and write access. This problem
is overcome by using the ACTION= specifier in the OPEN statement. The ACTION=
specifier indicates the way in which the file is initially accessed. The values allowed for the ACTION=
specifier are the following.
- 'READ'
- the file is opened for read-only access
'WRITE'
- the file is opened for write-only access
'READWRITE'
- the file is opened for both read and write access
To open the console device under Win32, you must specify whether you are going to "READ" or "WRITE"
to the file. If you wish to do both reading and writing, then you must use two separate units.
Example:
OPEN( UNIT=1, FILE='CON', ACTION='READ')
OPEN( UNIT=2, FILE='CON', ACTION='WRITE')
The console can be treated as a carriage control device. This is requested by using the CARRIAGECONTROL='YES'
specifier of the FORTRAN OPEN statement.
Example:
OPEN( UNIT=1, FILE='con', CARRIAGECONTROL='YES' )
Carriage control handling is described in the section entitled Print File Attributes.
The console is not capable of supporting carriage control in a fashion identical to a printer. For example,
overprinting of records on the console is destructive in that the previous characters are erased.
End of file is signalled by first pressing the Ctrl/Z key combination and then the line entering key. End of
file may be handled by using the END= specification of the FORTRAN READ statement.
Example:
READ( UNIT=*, FMT=*, END=100 ) X, Y
.
.
.
100 code to handle "End of File"
End of file may also be handled by using the IOSTAT= specifier of the FORTRAN READ statement.
Example:
READ( UNIT=*, FMT=*, IOSTAT=IOS ) X, Y
IF( IOS .NE. 0 )THEN
code to handle "End of File"
ENDIF
Printer Device Support
Output can be written to a printer by using a printer device name as the file name. A printer can be specified in
a "SET" command or through the FILE= specifier of the FORTRAN OPEN statement.
Several device names may be used:
prn or lpt1
lpt2
lpt3
The printer can be treated as a carriage control device. This is requested by using the CARRIAGECONTROL='YES'
specifier of the FORTRAN OPEN statement.
Example:
OPEN( UNIT=1, FILE='prn', CARRIAGECONTROL='YES' )
Carriage control handling is described in the section entitled Print File Attributes.
Serial Device Support
Output can be written to a serial port by using a serial device name as the file name. A serial device can be specified
in a "SET" command or through the FILE= specifier of the FORTRAN OPEN statement.
Three device names may be used:
aux or com1
com2
The serial device can be treated as a carriage control device. This is requested by using the CARRIAGECONTROL='YES'
specifier of the FORTRAN OPEN statement.
Example:
OPEN( UNIT=1, FILE='com1', CARRIAGECONTROL='YES' )
Carriage control handling is described in the section entitled Print File Attributes.
To set serial characteristics such as speed, parity, and word length, the "MODE" command may be used.
Example:
C>mode com1:9600,n,8,1
The above example sets serial port 1 to a speed of 9600 BAUD with no parity, a word length of 8 and 1 stop bit.
File Handling Defaults
The following defaults apply to file specifications:
- The following table indicates the default record type for the allowable access methods and forms.
File
Form
Access Formatted Unformatted
+-----------+-----------+
Sequential | Text | Variable |
+-----------+-----------+
Direct | Text | Fixed
|
+-----------+-----------+
Unless the record type of the file does not correspond to the default assumed by Open Watcom F77, the record type
attribute should not be specified.
- Unless otherwise stated, the default record length for a file is 1024 characters. When access is "direct",
the record length must be specified in the RECL= specifier of the FORTRAN OPEN statement.
The record length may also be specified when the access is "sequential". This should be done whenever access
is "sequential" and the maximum record length is greater than the default.
- The default record access is "sequential".
- When reading from or writing to a unit for which no preconnection has been specified or no "FILE=" form of the
FORTRAN OPEN statement has been executed, the default file name takes the form:
FORnnn
nnn is a three-digit FORTRAN unit number. Unit 0 is "000", unit 1 is "001", unit
2 is "002", and so on. There is no file extension in this case.
- If the connection between a unit number and a file is discontinued through use of the FORTRAN CLOSE statement,
the same rule for constructing a file name will apply on the next attempt to read from or write to the specified unit.
The Open Watcom F77 Subprogram Library
Open Watcom FORTRAN 77 includes additional FORTRAN subprograms which can be called from programs compiled by Open Watcom
F77. The following sections describe these subprograms.
Subroutine FEXIT
The subroutine FEXIT allows an application to terminate execution with a return code. It requires one argument
of type INTEGER that represents the value to be returned to the system.
Example:
INCLUDE 'FSUBLIB.FI'
CALL FEXIT( -1 )
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
INTEGER Function FGETCMD
The INTEGER function FGETCMD allows an application to obtain the command line from within an executing program.
The function FGETCMD requires one argument of type CHARACTER and returns the length of the command line.
Example:
INCLUDE 'FSUBLIB.FI'
INTEGER CMDLEN
CHARACTER*128 CMDLIN
CMDLEN = FGETCMD( CMDLIN )
PRINT *, 'Command length = ', CMDLEN
PRINT *, 'Command line = ', CMDLIN
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
- If the argument to FGETCMD is not long enough then only the first part of the command line is returned.
INTEGER Function FGETENV
The INTEGER function FGETENV allows an application to obtain the value of an environment string from within an
executing program.
The function FGETENV requires two arguments of type CHARACTER. The first argument is the character
string to look for. FGETENV places the associated environment string value in the second argument and returns
the length of the environment string. If no such string is defined, the length returned is zero.
Example:
INCLUDE 'FSUBLIB.FI'
INTEGER STRLEN
CHARACTER*80 STRVAL
STRLEN = FGETENV( 'PATH', STRVAL )
PRINT *, 'Environment string length = ', STRLEN
PRINT *, 'Environment string value = ', STRVAL
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
- If the second argument to FGETENV is not long enough then only the first part of the value is returned.
INTEGER Function FILESIZE
The INTEGER function FILESIZE allows an application to determine the size of a file connected to a specified
unit.
The function FILESIZE requires one argument of type INTEGER, the unit number and returns the size, in bytes,
of the file. If no file is connected to the specified unit, a value of -1 is returned.
Example:
INCLUDE 'FSUBLIB.FI'
OPEN( UNIT=1, FILE='sample.fil' )
PRINT *, FILESIZE( 1 )
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
Subroutine FINTR and FINTRF
The subroutine FINTR and FINTRF allow the user to execute any software interrupt from a FORTRAN 77 program.
Note: These subroutines are only supported by the DOS and Windows libraries.
The subroutine FINTR and FINTRF require two arguments.
- The first argument is an interrupt number. These subroutines will generate the software interrupt given by the this
argument. The type must be INTEGER.
- The second argument is an INTEGER array of ten elements.
When FINTR and FINTRF are called, the array contains the values to be assigned to the registers prior
to issuing the software interrupt. When control is returned from FINTR or FINTRF, it contains the
values of the registers after the software interrupt has completed. The registers are mapped onto the array REGS
as follows.
31
0
REGS(1) EAX
REGS(2) EBX
REGS(3) ECX
REGS(4) EDX
REGS(5) EBP
REGS(6) ESI
REGS(7) EDI
REGS(8) FS | DS
REGS(9) GS | ES
REGS(10) eflags
For 16-bit systems (e.g., 8088, 8086, 186, 286), only the low-order 16 bits of each register contain meaningful results.
31
0
REGS(1) AX
REGS(2) BX
REGS(3) CX
REGS(4) DX
REGS(5) BP
REGS(6) SI
REGS(7) DI
REGS(8) DS
REGS(9) ES
REGS(10) flags
Difference between FINTR and FINTRF is that FINTR reset CPU flags before generate the software
interrupt, but FINTRF set it from REGS(10) element.
The file dos.fi, located in the \WATCOM\src\fortran\dos directory, defines a set of equivalences
for ease of use. The contents of this file are reproduced below.
* Define registers: These correspond to the element of an
* array which is to contain the values of the registers.
integer*4 regd(10), regs(10)
integer*2 regw(2*10)
integer*1 regb(4*4)
integer*4 EAX,EBX,ECX,EDX,EBP,EDI,ESI,EFLAGS
integer*2 AX,BX,CX,DX,BP,DI,SI,DS,ES,FS,GS,FLAGS
integer*1 AH,AL,BH,BL,CH,CL,DH,DL
equivalence (regd,regs),(regd,regw),(regd,regb),
1(EAX,regd(1)), (EBX,regd(2)), (ECX,regd(3)), (EDX,regd(4)),
2(EBP,regd(5)), (EDI,regd(6)), (ESI,regd(7)), (EFLAGS,regd(10)),
3(AX,regw(1)), (BX,regw(3)), (CX,regw(5)),
(DX,regw(7)),
4(BP,regw(9)), (DI,regw(11)), (SI,regw(13)), (DS,regw(15)),
5(FS,regw(16)), (ES,regw(17)), (GS,regw(18)), (FLAGS,regw(19)),
6(AL,regb(1)), (AH,regb(2)), (BL,regb(5)),
(BH,regb(6)),
7(CL,regb(9)), (CH,regb(10)), (DL,regb(13)), (DH,regb(14))
The following is extracted from the "CALENDAR" program. It demonstrates the use of the FINTR
subroutine.
subroutine ClearScreen()
*$noextensions
implicit none
include 'dos.fi'
* Define BIOS functions.
integer VIDEO_CALL, SCROLL_UP
parameter (VIDEO_CALL=16, SCROLL_UP=6)
DS = ES = FS = GS = 0
AH = SCROLL_UP
! scroll up
AL = 0
! blank entire window
CX = 0
! set row,column of upper left
DX = 24*256 + 80
! set row,column of lower right
BH = 7
! attribute "white on black"
call fintr( VIDEO_CALL, regs )
end
INTEGER Function FLUSHUNIT
The INTEGER function FLUSHUNIT flushes the internal input/output buffer for a specified unit. Each file,
except special devices such as con, has an internal buffer. Buffered input/output is much more efficient since
it reduces the number of system calls which are usually quite expensive. For example, many WRITE operations
may be required before filling the internal file buffer and data is physically transferred to the file.
This function is particularly useful for applications that call non-FORTRAN subroutines or functions that wish to
perform input/output to a FORTRAN file.
The function FLUSHUNIT requires one argument, the unit number, of type INTEGER. It returns an INTEGER
value representing the return code of the input/output operation. A return value of 0 indicates success; otherwise
an error occurred.
The following example will flush the contents of the internal input/output buffer for unit 7.
Example:
INCLUDE 'FSUBLIB.FI'
INTEGER ISTAT
ISTAT = FLUSHUNIT( 7 )
IF( ISTAT .NE. 0 )THEN
PRINT *, 'Error in FLUSHUNIT'
END IF
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
INTEGER Function FNEXTRECL
The INTEGER function FNEXTRECL reports the record length of the next unformatted record to be read sequentially
from the specified unit.
The function FNEXTRECL requires one argument, the unit number, of type INTEGER. It returns an INTEGER
value representing the size of the next record to be read.
The following example creates an unformatted file and then reads the records in the file sequentially.
Example:
INCLUDE 'FSUBLIB.FI'
CHARACTER*80 INPUT
OPEN(UNIT=2, FILE='UNFORM.TXT', FORM='UNFORMATTED',
& ACCESS='SEQUENTIAL' )
WRITE( UNIT=2 ) 'A somewhat longish first record'
WRITE( UNIT=2 ) 'A short second record'
WRITE( UNIT=2 ) 'A very, very much longer third record'
CLOSE( UNIT=2 )
OPEN(UNIT=2, FILE='UNFORM.TXT', FORM='UNFORMATTED',
& ACCESS='SEQUENTIAL' )
I = FNEXTRECL( 2 )
PRINT *, 'Record length=', I
READ( UNIT=2 ) INPUT(1:I)
PRINT *, INPUT(1:I)
I = FNEXTRECL( 2 )
PRINT *, 'Record length=', I
READ( UNIT=2 ) INPUT(1:I)
PRINT *, INPUT(1:I)
I = FNEXTRECL( 2 )
PRINT *, 'Record length=', I
READ( UNIT=2 ) INPUT(1:I)
PRINT *, INPUT(1:I)
CLOSE( UNIT=2 )
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
INTEGER Function FSIGNAL
The INTEGER function FSIGNAL allows your application to respond to certain events that occur during execution.
- Event
- Meaning
SIGBREAK
- an interactive attention (Ctrl/Break on keyboard) is signalled
SIGFPE
- an erroneous floating-point operation occurs (such as division by zero, overflow and underflow)
SIGILL
- illegal instruction encountered
SIGINT
- an interactive attention (Ctrl/C on keyboard) is signalled
SIGSEGV
- an illegal memory reference is detected
SIGTERM
- a termination request is sent to the program
SIGIDIVZ
- integer division by zero
SIGIOVFL
- integer overflow
The function FSIGNAL requires two arguments. The first argument is an INTEGER argument and must be one
of the events described above. The second argument, called the handler, is one of the following.
- a subprogram that is called when the event occurs
- the value SIG_DFL, causing the default action to be taken when the event occurs
- the value SIG_IGN, causing the event to be ignored
FSIGNAL returns SIG_ERR if the request could not be processed, or the previous event handler.
Example:
INCLUDE 'FSIGNAL.FI'
EXTERNAL BREAK_HANDLER
LOGICAL BREAK_FLAG
COMMON BREAK_FLAG
BREAK_FLAG = .FALSE.
CALL FSIGNAL( SIGBREAK, BREAK_HANDLER )
WHILE( .NOT. VOLATILE( BREAK_FLAG ) ) CONTINUE
PRINT *, 'Program Interrupted'
END
SUBROUTINE BREAK_HANDLER()
LOGICAL BREAK_FLAG
COMMON BREAK_FLAG
BREAK_FLAG = .TRUE.
END
Notes:
- The FORTRAN include file fsignal.fi contains typing and calling information for FSIGNAL and should be
included when using this function. This file is located in the \watcom\src\fortran directory. The
\watcom\src\fortran directory should be included in the FINCLUDE environment variable so that the compiler can
locate the include file.
- The intrinsic function VOLATILE is used to indicate that the reference to the variable break_flag is
volatile. A volatile reference prevents the compiler from caching a variable in a register. In this case, we
want to retrieve the value of break_flag from memory each time the loop is iterated.
INTEGER Function FSPAWN
The INTEGER function FSPAWN allows an application to run another program as a subprocess. When the program
completes, execution is returned to the invoking application. There must be enough available free memory to start the
subprocess.
The function FSPAWN requires two arguments of type CHARACTER. The first argument is a character string
representing the name of the program to be run. The string must end in a NULL character (i.e., a character with the
binary value 0).
The second argument is a character string argument list to be passed to the program. The first character of
the second argument must contain, in binary, the length of the remainder of the argument list. For example, if the
argument is the string "HELLO" then the first character would be CHAR(5) and the remaining characters would be
"HELLO" (see the example below).
FSPAWN returns an INTEGER value representing the status of subprocess execution. If the value is negative
then the program could not be run. If the value is positive then the value represents the program's return code.
Example:
INCLUDE 'FSUBLIB.FI'
INTEGER CMDLEN, STATUS
CHARACTER CMD*128, CMDLIN*128
* COMSPEC will tell us where DOS 'COMMAND.COM' is hiding
CMDLEN = FGETENV( 'COMSPEC', CMD )
CMD(CMDLEN+1:CMDLEN+1) = CHAR( 0 )
CMDLIN = '/c dir *.for'
CMDLIN(13:13) = CHAR( 0 )
STATUS = FSPAWN( CMD, CMDLIN )
PRINT *, 'Program status = ', STATUS
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
- The INTEGER function FSYSTEM, which is described in a later section, implements a more general form of the example
given above. We recommend its use.
INTEGER Function FSYSTEM
The INTEGER function FSYSTEM allows an application to run another program or execute an operating system command.
The function FSYSTEM requires one argument of type CHARACTER. This argument represents a operating
system command or a program name together with any arguments. FSYSTEM returns an INTEGER value representing
the status of subprocess execution. If the value is negative, the operating system command interpreter or shell could
not be run (an attempt is made to invoke the system command interpreter to run the program). If the value is positive,
the value represents the program's return code.
In the following example, a "COPY" command is executed and then a hypothetical sorting program is run.
Example:
INCLUDE 'FSUBLIB.FI'
INTEGER STATUS
STATUS = FSYSTEM( 'COPY *.FOR \BACKUP\FOR\SRC' )
PRINT *, 'Status of COPY command = ', STATUS
STATUS = FSYSTEM( 'SORTFILE/IN=INP.DAT/OUT=OUT.DAT' )
PRINT *, 'Status of SORT program = ', STATUS
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
Subroutine FTRACEBACK
The subroutine FTRACEBACK allows your application to generate a run-time traceback. The application must
be compiled with the "DEBUG" or "TRACE" option. It is useful when you wish to disclose a problem
in an application and provide an informative report of where the problem occurred in the application.
The FTRACEBACK subroutine requires no arguments. The FTRACEBACK subroutine does not terminate
program execution.
Example:
SUBROUTINE READREC( UN )
INCLUDE 'FSUBLIB.FI'
INTEGER UN
INTEGER RLEN
CHARACTER*35 INPUT
RLEN = FNEXTRECL( UN )
IF( RLEN .GT. 35 )THEN
PRINT *, 'Error: Record too long', RLEN
CALL FTRACEBACK
STOP
ELSE
PRINT *, 'Record length=', RLEN
READ( UNIT=UN ) INPUT(1:RLEN)
PRINT *, INPUT(1:RLEN)
ENDIF
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
Subroutine GETDAT
The subroutine GETDAT allows an application to obtain the current date.
The subroutine GETDAT has three arguments of type INTEGER*2. When control is returned from
GETDAT, they contain the year, month and day of the current date.
The following program prints the current date in the form "YY-MM-DD".
Example:
INCLUDE 'FSUBLIB.FI'
INTEGER*2 YEAR, MONTH, DAY
CALL GETDAT( YEAR, MONTH, DAY )
PRINT 100, YEAR, MONTH, DAY
100 FORMAT( 1X, I4, '-', I2.2, '-', I2.2 )
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
- The arguments to GETDAT must be of type INTEGER*2 in order to obtain correct results.
Subroutine GETTIM
The subroutine GETTIM allows an application to obtain the current time.
The subroutine GETTIM has four arguments of type INTEGER*2. When control is returned from
GETTIM, they contain the hours, minutes, seconds, and hundredths of seconds of the current time.
The following program prints the current time in the form "HH:MM:SS.TT".
Example:
INCLUDE 'FSUBLIB.FI'
INTEGER*2 HRS, MINS, SECS, HSECS
CALL GETTIM( HRS, MINS, SECS, HSECS )
PRINT 100, HRS, MINS, SECS, HSECS
100 FORMAT( 1X, I2.2, ':', I2.2, ':', I2.2, '.', I2.2 )
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
- The arguments to GETTIM must be of type INTEGER*2 in order to obtain correct results.
INTEGER Function GROWHANDLES
The INTEGER function GROWHANDLES allows an application to increase the maximum number of files that can be opened.
It requires one argument of type INTEGER representing the maximum number of files that can be opened and returns an
INTEGER value representing the actual limit. The actual limit may differ from the specified limit. For example,
memory constraints or system parameters may be such that the request cannot be satisfied.
The following example attempts to increase the limit on the number of open files to sixty-four.
Example:
INCLUDE 'FSUBLIB.FI'
INTEGER NEW_LIMIT
NEW_LIMIT = GROWHANDLES( 64 )
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
Functions IARGC and IGETARG
The function IARGC allows an application to determine the number of arguments (including the program name) used
to invoke the program. The function IGETARG can be used to retrieve an argument.
Arguments supplied to a program are assigned indices. Argument zero is the program name, argument one is the
first argument, etc. The function IGETARG requires two arguments. The first argument is the index of
the argument to retrieve and is of type INTEGER. The second argument is of type CHARACTER and is used to return the
argument. The size of the argument (number of characters) is returned.
Example:
INCLUDE 'FSUBLIB.FI'
CHARACTER*128 ARG
INTEGER ARGC, ARGLEN
ARGC = IARGC()
ARGLEN = IGETARG( 0, ARG )
PRINT *, 'Program name is ', ARG(1:ARGLEN)
DO I = 1, ARGC - 1
ARGLEN = IGETARG( I, ARG )
PRINT '(A, I2, 2A)', 'Argument
', I, ' is ',
1
ARG(1:ARGLEN)
END DO
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
Math Error Functions
Math error functions are called when an error is detected in a math library function. For example, if the second
argument to the AMOD intrinsic function is zero, a math error function will be called. A number of math error
functions are defined in the FORTRAN run-time libraries and perform default actions when an error is detected. These
actions typically produce an error message to the screen.
It is possible to replace the FORTRAN run-time library version of the math error functions with your own versions.
The file _matherr.for located in the \watcom\src\fortran directory can be used as a template for
defining your own math error functions. The following functions represent the set of math error functions.
- The function __imath2err is called for math functions of type INTEGER that take two arguments of type INTEGER.
The first argument represents the error information and is an argument of type INTEGER that is passed by value.
The second argument is a pointer to the first argument passed to the math function and the third argument is a pointer to
the second argument passed to the math function. The error function returns a value that is then used as the return
value for the math function.
- The function __amath1err is called for math functions of type REAL that take one argument of type REAL.
The first argument represents the error information and is an argument of type INTEGER that is passed by value. The
second argument is a pointer to the argument passed to the math function. The error function returns a value that is
then used as the return value for the math function.
- The function __amath2err is called for math functions of type REAL that take two arguments of type REAL.
The first argument represents the error information and is an argument of type INTEGER that is passed by value. The
second argument is a pointer to the first argument passed to the math function and the third argument is a pointer to the
second argument passed to the math function. The error function returns a value that is then used as the return value
for the math function.
- The function __math1err is called for math functions of type DOUBLE PRECISION that take one argument of type
DOUBLE PRECISION. The first argument represents the error information and is an argument of type INTEGER that is passed
by value. The second argument is a pointer to the argument passed to the math function. The error function returns
a value that is then used as the return value for the math function.
- The function __math2err is called for math functions of type DOUBLE PRECISION that take two arguments of type
DOUBLE PRECISION. The first argument represents the error information and is an argument of type INTEGER that is passed
by value. The second argument is a pointer to the first argument passed to the math function and the third argument
is a pointer to the second argument passed to the math function. The error function returns a value that is then used
as the return value for the math function.
- The function __zmath2err is called for math functions of type COMPLEX that take two arguments of type COMPLEX.
The first argument represents the error information and is an argument of type INTEGER that is passed by value.
The second argument is a pointer to the first argument passed to the math function and the third argument is a pointer to
the second argument passed to the math function. The error function returns a value that is then used as the return
value for the math function.
- The function __qmath2err is called for math functions of type DOUBLE COMPLEX that take two arguments of type
DOUBLE COMPLEX. The first argument represents the error information and is an argument of type INTEGER that is passed
by value. The second argument is a pointer to the first argument passed to the math function and the third argument
is a pointer to the second argument passed to the math function. The error function returns a value that is then used
as the return value for the math function.
The include file mathcode.fi is included by the file _matherr.for and is located in the \watcom\src\fortran
directory. It defines the information that is contained in the error information argument that is passed to all math
error functions.
INTEGER Function SEEKUNIT
The INTEGER function SEEKUNIT permits seeking to a particular byte offset within a file connected to a FORTRAN
unit. The file must be opened with the following attributes:
FORM='UNFORMATTED'
ACCESS='SEQUENTIAL'
RECORDTYPE='FIXED'
The function SEEKUNIT requires three arguments of type INTEGER, the unit number, the offset to seek, and
the type of positioning to do. The seek positioning may be absolute (indicated by 0) or relative to the current position
(indicated by 1). It returns an INTEGER value representing the new offset in the file. A returned value of -1
indicates that the function call failed.
This function is particularly useful for applications that wish to change the input/output position for a file connected
to a unit.
The following example will set the current input/output position of the file connected to the specified unit.
Example:
EXTERNAL SEEKUNIT
INTEGER SEEKUNIT
INTEGER SEEK_SET, SEEK_CUR
PARAMETER (SEEK_SET=0, SEEK_CUR=1)
INTEGER POSITION
CHARACTER*80 RECORD
OPEN( UNIT=8, FILE='file', FORM='UNFORMATTED',
1 ACCESS='SEQUENTIAL',
RECORDTYPE='FIXED' )
POSITION = SEEKUNIT( 8, 10, SEEK_SET )
IF( POSITION .NE. -1 )THEN
PRINT *, 'New position is', POSITION
READ( UNIT=8 ) RECORD
PRINT *, RECORD
ENDIF
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
- A value of -1 is returned if the requested positioning cannot be done.
INTEGER Function SETJMP/Subroutine LONGJMP
The INTEGER function SETJMP saves the current executing environment, making it possible to restore that environment
by subsequently calling the LONGJMP subroutine. For example, it is possible to implement error handling by
using SETJMP to record the point to which a return will occur following an error. When an error is detected
in a called subprogram, that subprogram uses LONGJMP to jump back to the recorded position. The original subprogram
which called SETJMP must still be active (it cannot have returned to the subprogram which called it).
The SETJMP function requires one argument. The argument is a structure of type jmp_buf and
is used to save the current environment. The return value is an integer and is zero when initially called. It
is non-zero if the return is the result of a call to the LONGJMP subroutine. An IF statement
is often used to handle these two cases. This is demonstrated in the following example.
Example:
include 'fsignal.fi'
include 'setjmp.fi'
record /jmp_buf/ jmp_buf
common jmp_buf
external break_handler
integer rc
call fsignal( SIGBREAK, break_handler )
rc = setjmp( jmp_buf )
if( rc .eq. 0 )then
call do_it()
else
print *, 'abnormal termination:',
rc
endif
end
subroutine do_it()
loop
end loop
end
subroutine break_handler()
include 'setjmp.fi'
record /jmp_buf/ jmp_buf
common jmp_buf
call longjmp( jmp_buf, -1 )
end
Notes:
- The FORTRAN include file setjmp.fi contains typing and calling information for SETJMP and LONGJMP
and must be included. Similarly, fsignal.fi must be included when using the FSIGNAL function.
These files are located in the \watcom\src\fortran directory. The \watcom\src\fortran directory should
be included in the FINCLUDE environment variable so that the compiler can locate these include files.
INTEGER Function SETSYSHANDLE
The INTEGER function SETSYSHANDLE allows an application to set the system file handle for a specified unit.
The function SETSYSHANDLE requires an argument of type INTEGER, the unit number, and an argument of type
INTEGER*2, the handle, and returns an INTEGER value representing the success or fail status of the function call. A
returned value of -1 indicates that the function call failed and 0 indicates that the function call succeeded.
This function is particularly useful for applications that wish to set the system file handle for a unit. The
system file handle may have been obtained from a non-FORTRAN subroutine or function.
The following example will set the system file handle for a paricular unit.
Example:
INCLUDE 'FSUBLIB.FI'
INTEGER STDIN, STDOUT
PARAMETER (STDIN=0, STDOUT=1)
OPEN( UNIT=8, FORM='FORMATTED' )
I = SYSHANDLE( 8 )
PRINT *, 'Old handle was', I
I = SETSYSHANDLE( 8, STDOUT )
IF( I .EQ. 0 )THEN
WRITE( UNIT=8, FMT=* ) 'Output
to UNIT 8 which is stdout'
ENDIF
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
- A value of -1 is returned if the unit is not connected to a file.
- Units 5 and 6 are preconnected to the standard input and standard output devices respectively.
INTEGER*2 Function SYSHANDLE
The INTEGER*2 function SYSHANDLE allows an application to obtain the system file handle for a specified unit.
The function SYSHANDLE requires one argument of type INTEGER, the unit number. and returns an INTEGER*2
value representing the system file handle.
This function is particularly useful for applications that wish to pass the system file handle to non-FORTRAN subroutines
or functions that wish to perform input/output to a FORTRAN 77 file.
The following example will print the system file handles for the standard input and standard output devices.
Example:
INCLUDE 'FSUBLIB.FI'
PRINT *, 'Unit 5 file handle is', SYSHANDLE( 5 )
PRINT *, 'Unit 6 file handle is', SYSHANDLE( 6 )
END
Notes:
- The FORTRAN include file fsublib.fi, located in the \watcom\src\fortran directory, contains typing and
calling information for this subprogram. The \watcom\src\fortran directory should be included in the FINCLUDE
environment variable so that the compiler can locate the include file.
- A value of -1 is returned if the unit is not connected to a file.
- Units 5 and 6 are preconnected to the standard input and standard output devices respectively.
REAL Function URAND
The REAL function URAND returns pseudo-random numbers in the range (0,1).
The function URAND requires one argument of type INTEGER, the initial seed. The seed can contain any
integer value. URAND returns a REAL value which is a pseudo-random number in the range (0.0,1.0).
In the following example, 100 random numbers are printed.
Example:
REAL URAND
INTEGER SEED
SEED = 75347
DO I = 1, 100
PRINT *, URAND( SEED )
ENDDO
END
Notes:
- Upon each invocation of URAND, the seed argument is updated by the random number generator. Therefore,
the argument must not be a constant and, once the seed value has been set, it must not be modified by the programmer.
Default Windowing Functions
The functions described in the following sections provide the capability to manipulate attributes of various windows created
by Open Watcom's default windowing system for Microsoft Windows 3.x, Windows 95, Windows NT, and IBM OS/2. A simple
default windowing FORTRAN application can be built using the following command(s):
- 16-bit Windows
- C>wfl [fn1] [fn2] ... -bw -windows -l=windows
32-bit Windows
- C>wfl386 [fn1] [fn2] ... -bw -l=win386
C>wbind -n [fn1]
32-bit Windows NT or Windows 95
- C>wfl386 [fn1] [fn2] ... -bw -l=nt_win
32-bit OS/2 Presentation Manager
- C>wfl386 [fn1] [fn2] ... -bw -l=os2v2_pm
- Note:
- At present, a restriction in Windows NT prevents you from opening the console device (CON) for both read and write access.
Therefore, it is not possible to open additional windows for both input and output under Windows NT. They must
be either read-only or write-only windows.
dwfDeleteOnClose
integer function dwfDeleteOnClose( unit )
integer unit
The dwfDeleteOnClose function tells the console window that it should close itself when the corresponding file is
closed. The argument unit is the unit number associated with the opened console.
This function is one of the support functions that can be called from an application using Open Watcom's default windowing
support.
The dwfDeleteOnClose function returns 1 if it was successful and 0 if not.
Example:
PROGRAM main
INCLUDE 'FSUBLIB.FI'
INTEGER rc
CHARACTER response
rc = dwfSetAboutDlg( 'Hello World About Dialog',
1
'About Hello World'//CHAR(13)//
2
'Copyright 1994 by WATCOM'//CHAR(13) )
rc = dwfSetAppTitle( 'Hello World Application Title'
)
rc = dwfSetConTitle( 5, 'Hello World Console Title' )
PRINT *, 'Hello World'
OPEN( unit=3, file='CON' )
rc = dwfSetConTitle( 3, 'Hello World Second Console Title'
)
rc = dwfDeleteOnClose( 3 )
WRITE( unit=3, fmt=* ) 'Hello to second console'
WRITE( unit=3, fmt=* ) 'Press Enter to close this console'
READ( unit=3, fmt='(A)', end=100, err=100 ) response
100 CLOSE( unit=3 )
END
dwfSetAboutDlg
integer function dwfSetAboutDlg( title, text )
character*(*) title
character*(*) text
The dwfSetAboutDlg function sets the "About" dialog box of the default windowing system. The argument
title is a character string that will replace the current title. If title is CHAR(0) then the title will
not be replaced. The argument text is a character string which will be placed in the "About" box.
To get multiple lines, embed a new line character (CHAR(13)) after each logical line in the string. If text
is CHAR(0), then the current text in the "About" box will not be replaced.
This function is one of the support functions that can be called from an application using Open Watcom's default windowing
support.
The dwfSetAboutDlg function returns 1 if it was successful and 0 if not.
Example:
PROGRAM main
INCLUDE 'FSUBLIB.FI'
INTEGER rc
CHARACTER response
rc = dwfSetAboutDlg( 'Hello World About Dialog',
1
'About Hello World'//CHAR(13)//
2
'Copyright 1994 by WATCOM'//CHAR(13) )
rc = dwfSetAppTitle( 'Hello World Application Title'
)
rc = dwfSetConTitle( 5, 'Hello World Console Title' )
PRINT *, 'Hello World'
OPEN( unit=3, file='CON' )
rc = dwfSetConTitle( 3, 'Hello World Second Console Title'
)
rc = dwfDeleteOnClose( 3 )
WRITE( unit=3, fmt=* ) 'Hello to second console'
WRITE( unit=3, fmt=* ) 'Press Enter to close this console'
READ( unit=3, fmt='(A)', end=100, err=100 ) response
100 CLOSE( unit=3 )
END
dwfSetAppTitle
integer function dwfSetAppTitle( title )
character*(*) title
The dwfSetAppTitle function sets the main window's title. The argument title is a character string
that will replace the current title.
This function is one of the support functions that can be called from an application using Open Watcom's default windowing
support.
The dwfSetAppTitle function returns 1 if it was successful and 0 if not.
Example:
PROGRAM main
INCLUDE 'FSUBLIB.FI'
INTEGER rc
CHARACTER response
rc = dwfSetAboutDlg( 'Hello World About Dialog',
1
'About Hello World'//CHAR(13)//
2
'Copyright 1994 by WATCOM'//CHAR(13) )
rc = dwfSetAppTitle( 'Hello World Application Title'
)
rc = dwfSetConTitle( 5, 'Hello World Console Title' )
PRINT *, 'Hello World'
OPEN( unit=3, file='CON' )
rc = dwfSetConTitle( 3, 'Hello World Second Console Title'
)
rc = dwfDeleteOnClose( 3 )
WRITE( unit=3, fmt=* ) 'Hello to second console'
WRITE( unit=3, fmt=* ) 'Press Enter to close this console'
READ( unit=3, fmt='(A)', end=100, err=100 ) response
100 CLOSE( unit=3 )
END
dwfSetConTitle
integer function dwfSetConTitle( unit, title )
integer unit
character*(*) title
The dwfSetConTitle function sets the console window's title which corresponds to the unit number passed to it.
The argument unit is the unit number associated with the opened console. The argument title is the
character string that will replace the current title.
This function is one of the support functions that can be called from an application using Open Watcom's default windowing
support.
The dwfSetConTitle function returns 1 if it was successful and 0 if not.
Example:
PROGRAM main
INCLUDE 'FSUBLIB.FI'
INTEGER rc
CHARACTER response
rc = dwfSetAboutDlg( 'Hello World About Dialog',
1
'About Hello World'//CHAR(13)//
2
'Copyright 1994 by WATCOM'//CHAR(13) )
rc = dwfSetAppTitle( 'Hello World Application Title'
)
rc = dwfSetConTitle( 5, 'Hello World Console Title' )
PRINT *, 'Hello World'
OPEN( unit=3, file='CON' )
rc = dwfSetConTitle( 3, 'Hello World Second Console Title'
)
rc = dwfDeleteOnClose( 3 )
WRITE( unit=3, fmt=* ) 'Hello to second console'
WRITE( unit=3, fmt=* ) 'Press Enter to close this console'
READ( unit=3, fmt='(A)', end=100, err=100 ) response
100 CLOSE( unit=3 )
END
dwfShutDown
integer function dwfShutDown()
The dwfShutDown function shuts down the default windowing I/O system. The application will continue to execute
but no windows will be available for output. Care should be exercised when using this function since any subsequent
output may cause unpredictable results.
When the application terminates, it will not be necessary to manually close the main window.
This function is one of the support functions that can be called from an application using Open Watcom's default windowing
support.
The dwfShutDown function returns 1 if it was successful and 0 if not.
Example:
PROGRAM main
INCLUDE 'FSUBLIB.FI'
INTEGER rc
CHARACTER response
rc = dwfSetAboutDlg( 'Hello World About Dialog',
1
'About Hello World'//CHAR(13)//
2
'Copyright 1994 by WATCOM'//CHAR(13) )
rc = dwfSetAppTitle( 'Hello World Application Title'
)
rc = dwfSetConTitle( 5, 'Hello World Console Title' )
PRINT *, 'Hello World'
OPEN( unit=3, file='CON' )
rc = dwfSetConTitle( 3, 'Hello World Second Console Title'
)
rc = dwfDeleteOnClose( 3 )
WRITE( unit=3, fmt=* ) 'Hello to second console'
WRITE( unit=3, fmt=* ) 'Press Enter to close this console'
READ( unit=3, fmt='(A)', end=100, err=100 ) response
100 CLOSE( unit=3 )
rc = dwfShutDown()
* do more computing that does not involve console input/output
* .
* .
* .
END
dwfYield
integer function dwf veld()
The dwfYield function yields control back to the operating system, thereby giving other processes a chance to run.
This function is one of the support functions that can be called from an application using Open Watcom's default windowing
support.
The dwfYield function returns 1 if it was successful and 0 if not.
Example:
PROGRAM main
INCLUDE 'FSUBLIB.FI'
INTEGER rc
CHARACTER response
INTEGER i
rc = dwfSetAboutDlg( 'Hello World About Dialog',
1
'About Hello World'//CHAR(13)//
2
'Copyright 1994 by WATCOM'//CHAR(13) )
rc = dwfSetAppTitle( 'Hello World Application Title'
)
rc = dwfSetConTitle( 5, 'Hello World Console Title' )
PRINT *, 'Hello World'
OPEN( unit=3, file='CON' )
rc = dwfSetConTitle( 3, 'Hello World Second Console Title'
)
rc = dwfDeleteOnClose( 3 )
WRITE( unit=3, fmt=* ) 'Hello to second console'
WRITE( unit=3, fmt=* ) 'Press Enter to close this console'
READ( unit=3, fmt='(A)', end=100, err=100 ) response
100 CLOSE( unit=3 )
DO i = 0, 1000
rc = dwfYield()
* do CPU-intensive calculation
* .
* .
* .
ENDDO
PRINT *, i
END
This chapter describes the internal or machine representation of the basic types supported by Open Watcom F77. The
following table summarizes these data types.
Data Type Size FORTRAN 77
(in
bytes) Standard
LOGICAL 4
LOGICAL*1 1 (extension)
LOGICAL*4 4 (extension)
INTEGER 4
INTEGER*1 1 (extension)
INTEGER*2 2 (extension)
INTEGER*4 4 (extension)
REAL 4
REAL*4 4
(extension)
REAL*8 8
(extension)
DOUBLE PRECISION 8
COMPLEX 8
COMPLEX*8 8 (extension)
COMPLEX*16 16 (extension)
DOUBLE COMPLEX 16 (extension)
CHARACTER 1
CHARACTER*n n
LOGICAL*1 Data Type
An item of type LOGICAL*1 occupies 1 byte of storage. It can only have two values, namely .TRUE.
(a value of 1) and .FALSE. (a value of 0).
LOGICAL and LOGICAL*4 Data Types
An item of type LOGICAL or LOGICAL*4 occupies 4 bytes of storage. It can only have two values, namely
.TRUE. (a value of 1) and .FALSE. (a value of 0).
INTEGER*1 Data Type
An item of type INTEGER*1 occupies 1 byte of storage. Its value is in the following range. An integer
n can be represented in 1 byte if
-128 <= n <= 127
INTEGER*2 Data Type
An item of type INTEGER*2 occupies 2 bytes of storage. An integer n can be represented in 2 bytes
if
-32768 <= n <= 32767
INTEGER and INTEGER*4 Data Types
An item of type INTEGER or INTEGER*4 occupies 4 bytes of storage (one numeric storage unit). An integer
n can be represented in 4 bytes if
-2147483648 <= n <= 2147483647
REAL and REAL*4 Data Types
An item of type REAL or REAL*4 is an approximate representation of a real number and occupies 4 bytes (one
numeric storage unit). If m is the magnitude of a real number x, then x can be approximated
if
-126 128
2 <= m < 2
or in more approximate terms if
1.175494e-38 <= m <= 3.402823e38
Items of type REAL or REAL*4 are represented internally as follows. Note that bytes are stored
in memory with the least significant byte first and the most significant byte last.
S Biased Significand
Exponent
31 30-23 22-0
- S
- S = Sign bit (0=positive, 1=negative)
Exponent
- The exponent bias is 127 (i.e., exponent value 1 represents 2**-126; exponent value 127 represents 2**0; exponent value 254
represents 2**127; etc.). The exponent field is 8 bits long.
Significand
- The leading bit of the significand is always 1, hence it is not stored in the significand field. Thus the significand
is always "normalized". The significand field is 23 bits long.
Zero
- A real zero quantity occurs when the sign bit, exponent, and significand are all zero.
Infinity
- When the exponent field is all 1 bits and the significand field is all zero bits then the quantity represents positive or
negative infinity, depending on the sign bit.
Not Numbers
- When the exponent field is all 1 bits and the significand field is non-zero then the quantity is a special value called a
NAN (Not-A-Number).
When the exponent field is all 0 bits and the significand field is non-zero then the quantity is a special value called
a "denormal" or nonnormal number.
DOUBLE PRECISION and REAL*8 Data Types
An item of type DOUBLE PRECISION or REAL*8 is an approximate representation of a real number, occupies 8
bytes (two numeric storage units) and has precision greater than or equal to that of an item of type REAL or REAL*4.
If m is the magnitude of a real number x, then x can be approximated if
-1022 1024
2 <= m < 2
or in more approximate terms if
2.2250738585072e-308 <= m <= 1.79769313486232e308
Items of type DOUBLE PRECISION or REAL*8 are represented internally as follows. Note that bytes
are stored in memory with the least significant byte first and the most significant byte last.
S Biased
Significand
Exponent
63 62-52
51-0
- S
- S = Sign bit (0=positive, 1=negative)
Exponent
- The exponent bias is 1023 (i.e., exponent value 1 represents 2**-1022; exponent value 1023 represents 2**0; exponent value
2046 represents 2**1023; etc.). The exponent field is 11 bits long.
Significand
- The leading bit of the significand is always 1, hence it is not stored in the significand field. Thus the significand
is always "normalized". The significand field is 52 bits long.
Zero
- A double precision zero quantity occurs when the sign bit, exponent, and significand are all zero.
Infinity
- When the exponent field is all 1 bits and the significand field is all zero bits then the quantity represents positive or
negative infinity, depending on the sign bit.
Not Numbers
- When the exponent field is all 1 bits and the significand field is non-zero then the quantity is a special value called a
NAN (Not-A-Number).
When the exponent field is all 0 bits and the significand field is non-zero then the quantity is a special value called
a "denormal" or nonnormal number.
COMPLEX, COMPLEX*8, and DOUBLE COMPLEX Data Types
An item of type COMPLEX or COMPLEX*8 is an approximate representation of a complex number. The representation
is an ordered pair of real numbers, the first representing the real part of the complex number and the second representing
the imaginary part of the complex number. Each item of type COMPLEX or COMPLEX*8 occupies 8 bytes (two
consecutive numeric storage units), the first being the real part and the second the imaginary part. The approximation
of the real and imaginary parts of a complex number is the same degree of approximation used for items of type REAL.
COMPLEX*16 Data Type
An item of type COMPLEX*16 is an approximate representation of a complex number. The representation is an
ordered pair of real numbers, the first representing the real part of the complex number and the second representing the
imaginary part of the complex number. Each item of type COMPLEX*16 occupies 16 bytes (four consecutive numeric
storage units), the first two being the real part and the last two the imaginary part. The approximation of the real
and imaginary parts of a complex number is the same degree of approximation used for items of type DOUBLE PRECISION.
CHARACTER Data Type
An item of type CHARACTER represents a sequence of characters. Each character occupies 1 byte of storage
(1 character storage unit). The length of an item of type CHARACTER is the number of characters it contains.
Each character is assigned an integer that represents its position. Characters are numbered from 1 to n
starting from the left, n being the number of characters.
Items of type CHARACTER are represented by a string descriptor. A string descriptor has the following
format.
Offset
0 pointer to data
4 length of data
The pointer to the actual data is a 32-bit offset in the default data segment. The length is represented as
a 32-bit unsigned integer.
Storage Organization of Data Types
The following illustrates the relative size of the data types in terms of bytes. LOGICAL is equivalent to
LOGICAL*4, INTEGER is equivalent to INTEGER*4, DOUBLE PRECISION is equivalent to REAL*8,
and COMPLEX is equivalent to COMPLEX*8. If the "short" option is used, LOGICAL is equivalent
to LOGICAL*1 and INTEGER is equivalent to INTEGER*2.
Offset 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
in bytes
LOGICAL*1
LOGICAL*4
INTEGER*1
INTEGER*2
INTEGER*4
REAL*4
REAL*8
COMPLEX*8 real imaginary
COMPLEX*16 real part imaginary part
There are a number of issues surrounding floating-point accuracy, calculations, exceptions, etc. on the x86-based
personal computer platform that we will address in the following sections. Some result from differences in the behaviour
of standard-conforming FORTRAN 77 compilers. Other result from idiosyncrasies of the IEEE Standard 754 floating-point
that is supported on the x86 platform.
Some FORTRAN 77 compilers extend the precision of single-precision constants in DATA statement initialization lists
when the corresponding variable is double precision. This is permitted by the FORTRAN 77 Standard. Open Watcom
FORTRAN 77, however, does not do this. This is illustrated by the following example.
Example:
double precision pi1, pi2
data pi1 /3.141592653589793/
data pi2 /3.141592653589793d0/
write(unit=*,fmt='(1x,z16,1x,f18.15)') pi1, pi1
write(unit=*,fmt='(1x,z16,1x,f18.15)') pi2, pi2
end
The output produces two very different results for our pi variables. The variable PI1 is initialized
with a single precision (i.e., REAL) constant.
400921FB60000000 3.141592741012573
400921FB54442D18 3.141592653589793
A single precision datum has 23 bits in the mantissa; a double precision datum has 52 bits in the mantissa.
Hence PI1 has 29 fewer bits of accuracy in the mantissa (the difference between 52 and 23) since it is initialized
with a single precision constant. You can verify this by examining the hexadecimal output of the two pi's. The
bottom 29 bits of the mantissa in PI1 are all zero.
To be on the safe side, the rule is always use double precision constants (even in DATA statements) if you want as
much accuracy as possible.
This behaviour treats DATA statement initialization as equivalent to simple assignment as shown in the following example.
Example:
double precision pi1, pi2
pi1 = 3.141592653589793
pi2 = 3.141592653589793d0
write(unit=*,fmt='(1x,z16,1x,f18.15)') pi1, pi1
write(unit=*,fmt='(1x,z16,1x,f18.15)') pi2, pi2
end
The output follows:
400921FB60000000 3.141592741012573
400921FB54442D18 3.141592653589793
A second consideration is illustrated by the next example. On some computer architectures, there is no difference
in the exponent range between single and double precision floating-point representation. One such architecture is the
IBM mainframe computer (e.g., IBM System/370). When a double precision result is assigned to a single precision (REAL)
variable, only precision in the mantissa is lost.
The x86 platform uses the IEEE Standard 754 floating-point representation. In this representation, the range
of exponent values is greater in double precision than in single precision. As described in the section entitled REAL and REAL*4 Data Types,
the range for single precision (REAL, REAL*4) numbers is:
1.175494e-38 <= m <= 3.402823e38
On the other hand, the range for double precision (DOUBLE PRECISION, REAL*8) numbers is:
2.2250738585072e-308 <= m <= 1.79769313486232e308
Double precision is described in the section entitled DOUBLE PRECISION and REAL*8 Data Types.
So you can see that a number like 1.0E234 can easily be represented in double precision but not in single precision
since the maximum positive exponent value for single precision is 38.
The following types of exceptions can be enabled/disabled on PC's with an 80x87 floating-point unit (either a real FPU
or a true emulator).
- DENORMAL
- The result has become denormalized. When the exponent field is all 0 bits and the significand field is non-zero then
the quantity is a special value called a "denormal" or nonnormal number. By providing a significand with
leading zeros, the range of possible negative exponents can be extended by the number of bits in the significand. Each
leading zero is a bit of lost accuracy, so the extended exponent range is obtained by reducing significance.
ZERODIVIDE
- A division by zero was attempted. A real zero quantity occurs when the sign bit, exponent, and significand are all zero.
OVERFLOW
- The result has overflowed. The correct answer is finite, but has a magnitude too great to be represented in the destination
floating-point format.
UNDERFLOW
- The result has numerically underflowed. The correct answer is non-zero but has a magnitude too small to be represented
as a normal number in the destination floating-point format. IEEE Standard 754 specifies that an attempt be made to
represent the number as a denormal. This denormalization may result in a loss of significant bits from the significand.
PRECISION
- A calculation does not return an exact answer. This exception is usually masked (disabled) and ignored. It is
used in extremely critical applications, when the user must know if the results are exact. The precision exception
is called "inexact" in IEEE Standard 754.
INVALID
- This is the exception condition that covers all cases not covered by the other exceptions. Included are FPU stack overflow
and underflow, NAN inputs, illegal infinite inputs, out-of-range inputs, and inputs in unsupported formats.
Which exceptions does Open Watcom FORTRAN 77 catch and which ones does it ignore by default? We can determine the
answer to this with the following program.
* This program uses the C Library routine "_control87"
* to obtain the math coprocessor exception mask.
implicit none
include 'fsignal.fi'
character*8 status
integer fp_cw, bits
fp_cw = _control87( 0, 0 )
bits = IAND( fp_cw, MCW_EM )
print '(a,1x,z4)', 'Interrupt exception mask', bits
print *,'Invalid operation exception ', status(bits,
EM_INVALID)
print *,'Denormalized exception ', status(bits, EM_DENORMAL)
print *,'Divide by 0 exception ', status(bits, EM_ZERODIVIDE)
print *,'Overflow exception ', status(bits, EM_OVERFLOW)
print *,'Underflow exception ', status(bits, EM_UNDERFLOW)
print *,'Precision exception ', status(bits, EM_PRECISION)
end
character*8 function status( bits, mask )
integer bits, mask
if( IAND(bits,mask) .eq. 0 ) then
status = 'enabled'
else
status = 'disabled'
endif
end
If you compile and run this program, the following output is produced.
Interrupt exception mask 0032
Invalid operation exception enabled
Denormalized exception disabled
Divide by 0 exception enabled
Overflow exception enabled
Underflow exception disabled
Precision exception disabled
So, by default, the Open Watcom FORTRAN 77 run-time system will catch "invalid operation", "divide
by 0", and "overflow" exceptions. It ignores "denormal", "underflow", and "precision"
exceptions. Thus calculations that produce very small results trend towards zero. Also, calculations that produce
inexact results (a very common occurrence in floating-point calculations) are allowed to continue.
Suppose that you were interested in flagging calculations that result in denormalized or underflowed results.
To do this, we need to enable both DENORMAL and UNDERFLOW exceptions. This following program illustrates how to do
this.
*$ifdef __386__
*$ifdef __stack_conventions__
*$pragma aux _clear87 "!"
*$else
*$pragma aux _clear87 "!_"
*$endif
*$else
*$pragma aux _clear87 "!_"
*$endif
implicit none
include 'fsignal.fi'
character*8 status
integer fp_cw, fp_mask, bits
* get rid of any errors so we don't cause an instant exception
call _clear87
* fp_mask determines the bits to enable and/or disable
fp_mask = 0
1 + EM_DENORMAL
2 + EM_UNDERFLOW
* fp_cw determines whether to enable(0) or disable(1)
* (in this case, nothing is disabled)
fp_cw = '0000'x
fp_cw = _control87( fp_cw, fp_mask )
bits = IAND( fp_cw, MCW_EM )
print '(a,1x,z4)', 'Interrupt exception mask', bits
print *,'Invalid operation exception ', status(bits,
EM_INVALID)
print *,'Denormalized exception ', status(bits, EM_DENORMAL)
print *,'Divide by 0 exception ', status(bits, EM_ZERODIVIDE)
print *,'Overflow exception ', status(bits, EM_OVERFLOW)
print *,'Underflow exception ', status(bits, EM_UNDERFLOW)
print *,'Precision exception ', status(bits, EM_PRECISION)
end
character*8 function status( bits, mask )
integer bits, mask
if( IAND(bits,mask) .eq. 0 ) then
status = 'enabled'
else
status = 'disabled'
endif
end
If you compile and run this program, the following output is produced.
Interrupt exception mask 0020
Invalid operation exception enabled
Denormalized exception enabled
Divide by 0 exception enabled
Overflow exception enabled
Underflow exception enabled
Precision exception disabled
Compiler Options Relating to Floating-point
Let us take the program that we developed in the previous section and test it out. If you introduce the variable
FLT to the program and calculate the expression "2e-38 x 2e-38", you would expect to see 0.0 printed when
underflow exceptions are disabled and a run-time diagnostic when underflow exceptions are enabled. The statements that
you would add are show in the following.
real flt
flt=2e-38
print *, flt*flt
* code to enable exceptions goes here
print *, flt*flt
end
If you compile the modified program with default options and run it, the result is as follows.
0.0000000
Interrupt exception mask 0020
Invalid operation exception enabled
Denormalized exception enabled
Divide by 0 exception enabled
Overflow exception enabled
Underflow exception enabled
Precision exception disabled
0.0000000
This is not what we expected. Evaluation of the second expression did not produce the run-time diagnostic that
we expected. The reason this happened is related to the compiler's processing of the source code. By default,
the compiler optimized the generated code by evaluating the expression "2e-38 x 2e-38" at compile time producing
0.0 as the result (due to the underflow).
flt=2e-38
print *, flt*flt
reduces to
print *, 2e-28*2e-38
which further reduces to
print *, 0.0
Recompile the program using the "OP" option and run it. The result is as follows.
0.0000000
Interrupt exception mask 0020
Invalid operation exception enabled
Denormalized exception enabled
Divide by 0 exception enabled
Overflow exception enabled
Underflow exception enabled
Precision exception disabled
*ERR* KO-03 floating-point underflow
The use of the "OP" option will force the result to be stored in memory after each FORTRAN statement is
executed. Thus, the source code is not optimized across statements. Compile-time versus run-time evaluation of
expressions can lead to different results. It is very instructive to compile and then run your application with a variety
of compile-time options to see the effect of optimizations. See the chapter entitled Open Watcom FORTRAN 77 Compiler Options
for more information on compiler options.
Before we end this section, there is another important aspect of floating-point exceptions to consider. A floating-point
exception is triggered upon the execution of the next FPU instruction following the one that caused the exception.
implicit none
real*4 a
real*8 b
b=12.0d123
a=b*b
b=1.0
a=b/2.0
print *, a, b
end
Compile this program with the "OP" and "DEBUG" options and then run it. The result is displayed
next.
*ERR* KO-02 floating-point overflow
- Executing line 9 in file pi4.for
Line 9 is the line containing the statement a=b/2.0 which could not possibly be responsible for an overflow.
However, it contains the first floating-point instruction following the instruction in line 7 where the overflow actually
occurred. To see this, it helps to disassemble the object file.
a=b*b
0029 B8 07 00 00 00 mov
eax,0x00000007
002E E8 00 00 00 00 call
RT@SetLine
0033 DD 45 F4
fld qword ptr -0xc[ebp]
0036 D8 C8
fmul st,st
0038 D9 5D FC
fstp dword ptr -0x4[ebp]
b=1.0
003B B8 09 00 00 00 mov
eax,0x00000009
0040 E8 00 00 00 00 call
RT@SetLine
0045 31 DB
xor ebx,ebx
0047 89 5D F4
mov -0xc[ebp],ebx
004A C7 45 F8 00 00 F0 3F
mov dword
ptr -0x8[ebp],0x3ff00000
a=b/2.0
0051 B8 0A 00 00 00 mov
eax,0x0000000a
0056 E8 00 00 00 00 call
RT@SetLine
005B DD 45 F4
fld qword ptr -0xc[ebp]
005E DC 0D 08 00 00 00
fmul qword ptr
L$2
0064 D9 5D FC
fstp dword ptr -0x4[ebp]
The overflow occurred when the "fstp" was executed but is signalled when the subsequent "fld"
is executed. The overflow could also be signalled while executing down in a run-time routine. This behaviour
of the FPU can be somewhat exasperating.
Floating-point Exception Handling
In certain situations, you want to handle floating-point exceptions in the application itself rather than let the run-time
system terminate your application. The following example illustrates how to do this by installing a FORTRAN subroutine
as a floating-point exception handler.
implicit none
include 'fsignal.fi'
real flt
external fpehandler
integer signal_count, signal_number,
signal_type
common /fpe/ signal_count, signal_number, signal_type
* begin the signal handling process for floating-point exceptions
call fsignal( SIGFPE, fpehandler )
*
* main body of application goes here
*
flt = 2.0
print *, 'number of signals', volatile( signal_count
)
print *, flt / 0.0
print *, 'number of signals', volatile( signal_count
)
end
*$ifdef __386__
*$ifdef __stack_conventions__
*$pragma aux _clear87 "!"
*$else
*$pragma aux _clear87 "!_"
*$endif
*$else
*$pragma aux _clear87 "!_"
*$endif
*$pragma aux fpehandler parm( value, value )
subroutine fpehandler( sig_num, fpe_type )
implicit none
* sig_num and fpe_type are passed by value, not by reference
integer sig_num, fpe_type
include 'fsignal.fi'
integer signal_count,
signal_number, signal_type
common /fpe/ signal_count, signal_number, signal_type
* we could add this to our common block
integer signal_split( FPE_INVALID:FPE_IOVERFLOW
)
signal_count = signal_count + 1
signal_number = sig_num
signal_type = fpe_type
* floating-point exception types
* FPE_INVALID
= 129 (0)
* FPE_DENORMAL = 130 (1)
* FPE_ZERODIVIDE = 131 (2)
* FPE_OVERFLOW = 132 (3)
* FPE_UNDERFLOW = 133 (4)
* FPE_INEXACT = 134
(5)
* FPE_UNEMULATED = 135 (6)
* FPE_SQRTNEG = 136
(7)
* undefined
= 138 (8)
* FPE_STACKOVERFLOW = 137 (9)
* FPE_STACKUNDERFLOW = 138 (10)
* FPE_EXPLICITGEN = 139 (11)
* FPE_IOVERFLOW = 140 (12)
* log the type of error for interest only */
signal_split( fpe_type ) =
1signal_split( fpe_type ) + 1
* get rid of any errors
call _clear87
* resignal for more exceptions
call fsignal( SIGFPE, fpehandler )
* if we don't then a subsequent exception will
* cause an abnormal program termination
end
Note the use of the VOLATILE intrinsic function to obtain up-to-date contents of the variable SIGNAL_COUNT.
16-bit: Memory Models
This chapter describes the various memory models supported by Open Watcom F77. Each memory model is distinguished
by two properties; the code model used to implement subprogram calls and the data model used to reference data.
16-bit: Code Models
There are two code models:
- the small code model
- the big code model
A small code model is one in which all calls to subprograms are made with near calls. In a near call, the
destination address is 16 bits and is relative to the segment value in segment register CS. Hence, in a small code
model, all code comprising your program, including library subprograms, must be less than 64kB.
A big code model is one in which all calls to subprograms are made with far calls. In a far call, the
destination address is 32 bits (a 16-bit segment value and a 16-bit offset relative to the segment value). This model
allows the size of the code comprising your program to exceed 64kB.
Note: Open Watcom F77 does not support the small code model.
16-bit: Data Models
There are three data models:
- the small data model
- the big data model
- the huge data model
A small data model is one in which all references to data are made with near pointers. Near pointers are
16 bits; all data references are made relative to the segment value in segment register DS. Hence, in a small data
model, all data comprising your program must be less than 64kB.
A big data model is one in which all references to data are made with far pointers. Far pointers are
32 bits (a 16-bit segment value and a 16-bit offset relative to the segment value). This removes the 64kB limitation
on data size imposed by the small data model. However, when a far pointer is incremented, only the offset is adjusted.
Open Watcom F77 assumes that the offset portion of a far pointer will not be incremented beyond 64kB. The compiler
will assign an object to a new segment if the grouping of data in a segment will cause the object to cross a segment boundary.
Implicit in this is the requirement that no individual object exceed 64kB. For example, an array containing 40,000
integers does not fit into the big data model. An object such as this should be described as huge.
A huge data model is one in which all references to data are made with far pointers. This is similar to the
big data model. However, in the huge data model, incrementing a far pointer will adjust the offset and the segment
if necessary. The limit on the size of an object pointed to by a far pointer imposed by the big data model is removed
in the huge data model.
Notes:
- The huge data model has the same characteristics as the big data model, but formal array arguments are assumed to exceed
64kB. You should use the huge data model whenever any arrays in your application exceed 64kB in size.
- The huge data model should be used only if needed. The code generated in the huge data model is not very efficient
since a run-time routine is called in order to increment far pointers. This increases the size of the code significantly
and increases execution time.
- If your program contains less than 64kB of data, you should use the small data model. This will result in smaller
and faster code since references using near pointers produce fewer instructions.
16-bit: Summary of Memory Models
As previously mentioned, a memory model is a combination of a code model and a data model. The following table describes
the memory models supported by Open Watcom F77.
Memory Code Data
Default Default
Model Model Model
Code Data
Pointer Pointer
-------- -------- -------- --------
--------
medium big
small far near
large big
big far far
huge big
huge far huge
16-bit: Mixed Memory Model
A mixed memory model application combines elements from the various code and data models. A mixed memory model application
might be characterized as one that includes arrays which are larger than 64kB.
For example, a medium memory model application that uses some arrays which exceed 64kB in total size can be described
as a mixed memory model. In an application such as this, most of the data is in a 64kB segment (DGROUP) and hence can
be referenced with near pointers relative to the segment value in segment register DS. This results in more efficient
code being generated and better execution times than one can expect from a big data model.
16-bit: Linking Applications for the Various Memory Models
Each memory model requires different run-time and floating-point libraries. Each library assumes a particular memory
model and should be linked only with modules that have been compiled with the same memory model. The following table
lists the libraries that are to be used to link an application that has been compiled for a particular memory model.
The following table lists the run-time libraries used by FORTRAN 77 and the compiler options that cause their use.
- The "Library" column specified the library name.
- The "Memory model" column indicates the compiler options that specify the memory model of the library.
- The "Floating-point column" indicates the compiler options that specify the floating-point model of the library.
Library Memory
Floating-point
model model
----------- ------------- ------------------
flibm.lib -mm
-fpc
flibl.lib -ml, -mh
-fpc
flib7m.lib -mm
-fpi, -fpi87
flib7l.lib -ml, -mh
-fpi, -fpi87
clibm.lib -mm
-fpc, -fpi, -fpi87
clibl.lib -ml, -mh
-fpc, -fpi, -fpi87
mathm.lib -mm,
-fpc
mathl.lib -ml, -mh
-fpc
math87m.lib -mm,
-fpi, -fpi87
math87l.lib -ml, -mh
-fpi, -fpi87
emu87.lib -mm, -ml, -mh -fpi
noemu87.lib -mm, -ml, -mh -fpi87
16-bit: Memory Layout
The following describes the segment ordering of an application linked by the Open Watcom Linker. Note that this
assumes that the "DOSSEG" linker option has been specified.
- all segments not belonging to group "DGROUP" with class "CODE"
- all other segments not belonging to group "DGROUP"
- all segments belonging to group "DGROUP" with class "BEGDATA"
- all segments belonging to group "DGROUP" not with class "BEGDATA", "BSS" or "STACK"
- all segments belonging to group "DGROUP" with class "BSS"
- all segments belonging to group "DGROUP" with class "STACK"
A special segment belonging to class "BEGDATA" is defined when linking with Open Watcom run-time libraries.
This segment is initialized with the hexadecimal byte pattern "01" and is the first segment in group "DGROUP"
so that storing data at location 0 can be detected.
Segments belonging to class "BSS" contain uninitialized data. Note that this only includes uninitialized
data in segments belonging to group "DGROUP". Segments belonging to class "STACK" are used to define
the size of the stack used for your application. Segments belonging to the classes "BSS" and "STACK"
are last in the segment ordering so that uninitialized data need not take space in the executable file.
In addition to these special segments, the following conventions are used by Open Watcom F77.
- The "CODE" class contains the executable code for your application. In a small code model, this consists
of the segment "_TEXT". In a big code model, this consists of the segments "<subprogram>_TEXT"
where <subprogram> is the name of a subprogram.
- The "FAR_DATA" class consists of the following:
- (a)
- arrays whose size exceeds the data threshold in large data memory models (the data threshold is 256 bytes unless changed using
the "dt" compiler option)
(b)
- equivalenced variables in large data memory models
16-bit: Assembly Language Considerations
This chapter will deal with the following topics.
- The memory layout of a program compiled by Open Watcom F77.
- The method for passing arguments and returning values.
- The two methods for passing floating-point arguments and returning floating-point values.
One method is used when one of the Open Watcom F77 "fpi", "fpi87" or "fpi387" options
is specified for the generation of in-line 80x87 instructions. When the "fpi" option is specified, an 80x87
emulator is included from a math library if the application includes floating-point operations. When the "fpi87"
or "fpi387" option is used exclusively, the 80x87 emulator will not be included.
The other method is used when the Open Watcom F77 "fpc" option is specified. In this case, the compiler
generates calls to floating-point support routines in the alternate math libraries.
An understanding of the Intel 80x86 architecture is assumed.
16-bit: Calling Conventions
The following sections describe the method used by Open Watcom F77 to pass arguments.
The FORTRAN 77 language specifically requires that arguments be passed by reference. This means that instead
of passing the value of an argument, its address is passed. This allows a called subprogram to modify the value of
the actual arguments. The following illustrates the method used to pass arguments.
Type of Argument Method Used to Pass Argument
non-character
constant address of constant
non-character
expression address of value of expression
non-character
variable address of variable
character constant address of string descriptor
character
expression address of string descriptor
character variable address of string descriptor
non-character array address of array
non-character array
element address of array
character array address of string descriptor
character array
element address of string descriptor
character substring address of string descriptor
subprogram address of subprogram
alternate return
specifier no argument passed
user-defined
structure address of structure
When passing a character array as an argument, the string descriptor contains the address of the first element of
the array and the length of an element of the array.
The address of arguments are either passed in registers or on the stack. The registers used to pass the address
of arguments to a subprogram are AX, BX, CX and DX. The address of arguments are passed in the following way.
- For memory models with a big data model, address of arguments consist of a 16-bit offset and a 16-bit segment. Hence,
two registers are required to pass the address of an argument. The first argument will be passed in registers DX:AX
with register DX containing the segment and register AX containing the offset. The second argument will be passed in
registers CX:BX with register CX containing the segment and register BX containing the offset.
- For memory models with a small data model, address of arguments consists of only a 16-bit offset into the default data
segment. Hence, only a single register is required to pass the address of an argument. The first argument is
passed in register AX, the second argument is passed in register DX, the third argument is passed in register BX, and the
fourth argument is passed in register CX.
- For any remaining arguments, their address is passed on the stack. Note that addresses of arguments are pushed on
the stack from right to left.
16-bit: Processing Function Return Values with no 80x87
The way in which function values are returned is also dependent on the data type of the function. The following
describes the method used to return function values.
- LOGICAL*1 values are returned in register AL.
- LOGICAL*4 values are returned in registers DX:AX.
- INTEGER*1 values are returned in register AL.
- INTEGER*2 values are returned in register AX.
- INTEGER*4 values are returned in registers DX:AX.
- REAL*4 values are returned in registers DX:AX.
- REAL*8 values are returned in registers AX:BX:CX:DX.
- For COMPLEX*8 functions, space is allocated on the stack by the caller for the return value. Register SI
is set to point to the destination of the result. The called function places the result at the location pointed to
by register SI.
- For COMPLEX*16 functions, space is allocated on the stack by the caller for the return value. Register SI
is set to point to the destination of the result. The called function places the result at the location pointed to
by register SI.
- For CHARACTER functions, an additional argument is passed. This argument is the address of the string descriptor
for the result. Note that the address of the string descriptor can be passed in any of the registers that are used
to pass actual arguments.
- For functions that return a user-defined structure, space is allocated on the stack by the caller for the return value.
Register SI is set to point to the destination of the result. The called function places the result at the location
pointed to by register SI. Note that a structure of size 1, 2 or 4 bytes is returned in register AL, AX or DX:AX respectively.
16-bit: Processing Function Return Values Using an 80x87
The following describes the method used to return function values when your application is compiled using the "fpi87"
or "fpi" option.
- For REAL*4 functions, the result is returned in floating-point register ST(0).
- For REAL*8 functions, the result is returned in floating-point register ST(0).
- All other function values are returned in the way described in the previous section.
16-bit: Processing Alternate Returns
Alternate returns are processed by the caller and are only allowed in subroutines. The called subroutine places
the value specified in the RETURN statement in register AX. Note that the value returned in register
AX is ignored if there are no alternate return specifiers in the actual argument list.
16-bit: Alternate Method of Passing Character Arguments
As previously described, character arguments are passed using string descriptors. Recall that a string descriptor
contains a pointer to the actual character data and the length of the character data. When passing character data,
both a pointer and length are required by the subprogram being called. When using a string descriptor, this information
can be passed using a single argument, namely the pointer to the string descriptor.
An alternate method of passing character arguments is also supported and is selected when the "nodescriptor"
option is specified. In this method, the pointer to the character data and the length of the character data are passed
as two separate arguments. The character argument lengths are appended to the end of the actual argument list.
Let us consider the following example.
INTEGER A, C
CHARACTER B, D
CALL SUB( A, B, C, D )
In the above example, the first argument is of type INTEGER, the second argument is of type CHARACTER, the third argument
is of type INTEGER, and the fourth argument is of type CHARACTER. If the character arguments were passed by descriptor,
the argument list would resemble the following.
- The first argument would be the address of A.
- The second argument would be the address of the string descriptor for B.
- The third argument would be the address of C.
- The fourth argument would be the address of the string descriptor for D.
If we specified the "nodescriptor" option, the argument list would be as follows.
- The first argument would be the address of A.
- The second argument would be the address of the character data for B.
- The third argument would be the address of C.
- The fourth argument would be the address of the character data for D.
- A hidden argument for the length of B would be the fifth argument.
- A hidden argument for the length of D would be the sixth argument.
Note that the arguments corresponding to the length of the character arguments are passed as INTEGER*2 arguments.
16-bit: Character Functions
By default, when a character function is called, a hidden argument is passed at the end of the actual argument list.
This hidden argument is a pointer to the string descriptor used for the return value of the character function. When
the alternate method of passing character arguments is specified by using the "nodescriptor" option, the string
descriptor for the return value is passed to the function as two hidden arguments, similar to the way character arguments
were passed. However the two hidden arguments for the return value of the character function are placed at the beginning
of the actual argument list. The first argument is the the pointer to the storage immediately followed by the size
of the storage.
16-bit: Writing Assembly Language Subprograms
When writing assembly language subprograms, use the following guidelines.
- All used registers must be saved on entry and restored on exit except those used to pass arguments and return values.
Note that segment registers only have to be saved and restored if you are compiling your application with the "sr"
option.
- The direction flag must be clear before returning to the caller.
- In a small code model, any segment containing executable code must belong to the segment "_TEXT" and the class
"CODE". The segment "_TEXT" must have a "combine" type of "PUBLIC". On
entry, register CS contains the segment address of the segment "_TEXT". In a big code model there is no restriction
on the naming of segments which contain executable code.
- In a small data model, segment register DS contains the segment address of the default data segment (group "DGROUP").
In a big data model, segment register SS (not DS) contains the segment address of the default data segment (group "DGROUP").
- When writing assembly language subprograms for the small code model, you must declare them as "near".
If you wish to write assembly language subprograms for the big code model, you must declare them as "far".
- Use the ".8087" pseudo-op so that floating-point constants are in the correct format.
- The called subprogram must remove arguments that were passed on the stack in the "ret" instruction.
- In general, when naming segments for your code or data, you should follow the conventions described in the section entitled
"Memory Layout" in this chapter.
Consider the following example.
INTEGER HRS, MINS, SECS, HSECS
CALL GETTIM( HRS, MINS, SECS, HSECS )
PRINT 100, HRS, MINS, SECS, HSECS
100 FORMAT( 1X,I2.2,':',I2.2,':',I2.2,'.',I2.2 )
END
GETTIM is an assembly language subroutine that gets the current time. It requires four integer arguments.
The arguments are passed by reference so that the subroutine can return the hour, minute, seconds and hundredths of
a second for the current time. These arguments will be passed to GETTIM in the following way.
- The address of the first argument will be passed in registers DX:AX.
- The address of the second argument will be passed in registers CX:BX.
- The address of the third argument will be passed on the stack.
- The address of the fourth argument will be passed on the stack.
The following is an assembly language subprogram which implements GETTIM.
Large Memory Model (big code, big data)
GETTIM_TEXT segment byte public 'CODE'
assume CS:GETTIM_TEXT
public GETTIM
GETTIM proc far
push DI
; save register(s)
push ES
; ...
push DS
; ...
push BP
; get addressability to arguments
mov BP,SP
; ...
mov ES,DX
; ES:DI points to hours
mov DI,AX
; ...
mov DS,CX
; DS:BX points to minutes
mov AH,2ch
; set DOS "get time" function
int 21h
; issue DOS function call
mov AL,CH
; get hours
cbw
; ...
mov ES:[DI],AX
; return hours
sub AX,AX
; ...
mov ES:2[DI],AX
; ...
mov AL,CL
; get minutes
cbw
; ...
mov [BX],AX
; return minutes
sub AX,AX
; ...
mov 2[BX],AX
; ...
mov DS,14[BP]
; get address of seconds
mov DI,12[BP]
; ...
mov AL,DH
; get seconds
cbw
; ...
mov [DI],AX
; return seconds
sub AX,AX
; ...
mov 2[DI],AX
; ...
mov DS,18[BP]
; get address of ticks
mov DI,16[BP]
; ...
mov AL,DL
; get ticks
cbw
; ...
cwd
; ...
mov [DI],AX
; return ticks
mov 2[DI],DX
; ...
pop BP
; restore register(s)
pop DS
; ...
pop ES
; ...
pop DI
; ...
ret 8
; return
GETTIM endp
GETTIM_TEXT ends
end
Notes:
- Two arguments were passed on the stack so a "ret 8" instruction is used to return to the caller.
- Registers AX, BX, CX and DX were not saved and restored since they were used to pass arguments. However, registers
DS, ES, DI and BP were modified in the subprogram and hence must be saved and restored.
Let us look at the stack upon entry to GETTIM.
Large Model (big code, big data)
Offset
0 +----------------+ <- SP points here
| return address |
4 +----------------+
| argument #3
|
8 +----------------+
| argument #4
|
12 +----------------+
|
|
Notes:
- The top element of the stack is a segment/offset pair forming a 32-bit return address. Hence, the third argument
will be at offset 4 from the top of the stack and the fourth argument at offset 8.
Register SP cannot be used as a base register to address the arguments on the stack. Register BP is normally used
to address arguments on the stack. Upon entry to the subroutine, registers that are modified (except those used to
pass arguments) are saved and register BP is set to point to the stack. After performing this prologue sequence, the
stack looks like this.
Large Model (big code, big data)
Offset
0 +----------------+ <- BP and SP point
here
| saved BP
|
2 +----------------+
| saved DS
|
4 +----------------+
| saved ES
|
6 +----------------+
| saved DI
|
8 +----------------+
| return address |
12 +----------------+
| argument #3
|
16 +----------------+
| argument #4
|
20 +----------------+
|
|
As the above diagram shows, the third argument is at offset 12 from register BP and the fourth argument is at offset
16.
16-bit: Returning Values from Assembly Language Functions
The following illustrates the way function values are to be returned from assembly language functions.
- A LOGICAL*1 function.
L1_TEXT segment byte public 'CODE'
assume CS:L1_TEXT
public L1
L1 proc far
mov AL,1
ret
L1 endp
L1_TEXT ends
end
- A LOGICAL*4 function.
L4_TEXT segment byte public 'CODE'
assume CS:L4_TEXT
public L4
L4 proc far
mov AX,0
cwd
ret
L4 endp
L4_TEXT ends
end
- An INTEGER*1 function.
I1_TEXT segment byte public 'CODE'
assume CS:I1_TEXT
public I1
I1 proc far
mov AL,73
ret
I1 endp
I1_TEXT ends
end
- An INTEGER*2 function.
I2_TEXT segment byte public 'CODE'
assume CS:I2_TEXT
public I2
I2 proc far
mov AX,7143
ret
I2 endp
I2_TEXT ends
end
- An INTEGER*4 function.
I4_TEXT segment byte public 'CODE'
assume CS:I4_TEXT
public I4
I4 proc far
mov AX,383
cwd
ret
I4 endp
I4_TEXT ends
end
- A REAL*4 function.
.8087
DGROUP group R4_DATA
R4_TEXT segment byte public 'CODE'
assume CS:R4_TEXT
assume SS:DGROUP
public R4
R4 proc far
mov AX,word ptr
SS:R4Val
mov DX,word ptr SS:R4Val+2
ret
R4 endp
R4_TEXT ends
R4_DATA segment byte public 'DATA'
R4Val dd 1314.3
R4_DATA ends
end
- A REAL*8 function.
.8087
DGROUP group R8_DATA
R8_TEXT segment byte public 'CODE'
assume CS:R8_TEXT
assume SS:DGROUP
public R8
R8 proc far
mov DX,word ptr SS:R8Val
mov CX,word ptr
SS:R8Val+2
mov BX,word ptr SS:R8Val+4
mov AX,word ptr SS:R8Val+6
ret
R8 endp
R8_TEXT ends
R8_DATA segment byte public 'DATA'
R8Val dq 103.3
R8_DATA ends
end
- A COMPLEX*8 function.
.8087
DGROUP group C8_DATA
C8_TEXT segment byte public 'CODE'
assume CS:C8_TEXT
assume SS:DGROUP
public C8
C8 proc far
push DI
push ES
xchg DI,SI
push SS
pop ES
mov SI,offset SS:C8Val
movsw
movsw
movsw
movsw
pop ES
pop DI
ret
C8 endp
C8_TEXT ends
C8_DATA segment byte public 'DATA'
C8Val dd 2.2
dd 2.2
C8_DATA ends
end
- A COMPLEX*16 function.
.8087
DGROUP group C16_DATA
C16_TEXT segment byte public 'CODE'
assume CS:C16_TEXT
assume SS:DGROUP
public C16
C16 proc far
push DI
push ES
push CX
xchg DI,SI
push SS
pop ES
mov SI,offset SS:C16Val
mov CX,8
repe movsw
pop CX
pop ES
pop DI
ret
C16 endp
C16_TEXT ends
C16_DATA segment byte public 'DATA'
C16Val dq 3.3
dq 3.3
C16_DATA ends
end
- A CHARACTER function.
CHR_TEXT segment byte public 'CODE'
assume CS:CHR_TEXT
public CHR
CHR proc far
push DI
push ES
mov ES,DX
mov DI,AX
les DI,ES:[DI]
mov byte ptr
ES:[DI],'F'
pop ES
pop DI
ret
CHR endp
CHR_TEXT ends
end
- A function returning a user-defined structure.
DGROUP group STRUCT_DATA
STRUCT_TEXT segment byte public 'CODE'
assume CS:STRUCT_TEXT
assume SS:DGROUP
public C16
STRUCT proc far
push DI
push ES
push CX
xchg DI,SI
push SS
pop ES
mov SI,offset SS:StructVal
mov CX,4
repe movsw
pop CX
pop ES
pop DI
ret
STRUCT endp
STRUCT_TEXT ends
STRUCT_DATA segment byte public 'DATA'
StructVal dd 7
dd 3
STRUCT_DATA ends
end
If you are using an 80x87 to return floating-point values, only assembly language functions of type REAL*4 and
REAL*8 need to be modified.
- A REAL*4 function using an 80x87.
.8087
DGROUP group R4_DATA
R4_TEXT segment byte public 'CODE'
assume CS:R4_TEXT
assume SS:DGROUP
public R4
R4 proc far
fld dword ptr SS:R4Val
ret
R4 endp
R4_TEXT ends
R4_DATA segment byte public 'DATA'
R4Val dd 1314.3
R4_DATA ends
end
- A REAL*8 function using an 80x87.
.8087
DGROUP group R8_DATA
R8_TEXT segment byte public 'CODE'
assume CS:R8_TEXT
assume SS:DGROUP
public R8
R8 proc far
fld qword ptr SS:R8Val
ret
R8 endp
R8_TEXT ends
R8_DATA segment byte public 'DATA'
R8Val dq 103.3
R8_DATA ends
end
Notes:
- The ".8087" pseudo-op must be specified so that all floating-point constants are generated in 8087 format.
- When returning values on the stack, remember to use a segment override to the stack segment (SS).
The following is an example of a Open Watcom F77 program calling the above assembly language subprograms.
logical l1*1, l4*4
integer i1*1, i2*2, i4*4
real r4*4, r8*8
complex c8*8, c16*16
character chr
structure /coord/
integer x, y
end structure
record /coord/ struct
print *, l1()
print *, l4()
print *, i1()
print *, i2()
print *, i4()
print *, r4()
print *, r8()
print *, c8()
print *, c16()
print *, chr()
print *, struct()
end
16-bit: Pragmas
A pragma is a compiler directive that provides the following capabilities.
- Pragmas can be used to direct the Open Watcom F77 code generator to emit specialized sequences of code for calling functions
which use argument passing and value return techniques that differ from the default used by Open Watcom F77.
- Pragmas can be used to describe attributes of functions (such as side effects) that are not possible at the FORTRAN 77
language level. The code generator can use this information to generate more efficient code.
- Any sequence of in-line machine language instructions, including DOS and BIOS function calls, can be generated in the
object code.
Pragmas are specified in the source file using the pragma directive.
The following notation is used to describe the syntax of pragmas.
- keywords
- A keyword is shown in a mono-spaced courier font.
program-item
- A program-item is shown in a roman bold-italics font. A program-item is a symbol name or
numeric value supplied by the programmer.
punctuation
- A punctuation character shown in a mono-spaced courier font must be entered as is.
A punctuation character shown in a roman bold-italics font is used to describe syntax. The following
syntactical notation is used.
- [abc]
- The item abc is optional.
{abc}
- The item abc may be repeated zero or more times.
a|b|c
- One of a, b or c may be specified.
a ::= b
- The item a is defined in terms of b.
(a)
- Item a is evaluated first.
The following classes of pragmas are supported.
- pragmas that specify default libraries
- pragmas that provide auxiliary information used for code generation
16-bit: Auxiliary Pragmas
The following sections describe the capabilities provided by auxiliary pragmas.
The backslash character ('\') is used to continue a pragma on the next line. Text following the backslash character
is ignored. The line continuing the pragma must start with a comment character ('c', 'C' or '*').
16-bit: Specifying Symbol Attributes
Auxiliary pragmas are used to describe attributes that affect code generation. Initially, the compiler defines a
default set of attributes. Each auxiliary pragma refers to one of the following.
- a symbol (such as a variable or function)
- the default set of attributes defined by the compiler
When an auxiliary pragma refers to a particular symbol, a copy of the current set of default attributes is made and merged
with the attributes specified in the auxiliary pragma. The resulting attributes are assigned to the specified symbol
and can only be changed by another auxiliary pragma that refers to the same symbol.
When "default" is specified instead of a symbol name, the attributes specified by the auxiliary pragma change
the default set of attributes. The resulting attributes are used by all symbols that have not been specifically referenced
by a previous auxiliary pragma.
Note that all auxiliary pragmas are processed before code generation begins. Consider the following example.
code in which symbol x is referenced
*$pragma aux y <attrs_1>
code in which symbol y is referenced
code in which symbol z is referenced
*$pragma aux default <attrs_2>
*$pragma aux x <attrs_3>
Auxiliary attributes are assigned to x, y and z in the following way.
- Symbol x is assigned the initial default attributes merged with the attributes specified by <attrs_2>
and <attrs_3>.
- Symbol y is assigned the initial default attributes merged with the attributes specified by <attrs_1>.
- Symbol z is assigned the initial default attributes merged with the attributes specified by <attrs_2>.
16-bit: Alias Names
When a symbol referred to by an auxiliary pragma includes an alias name, the attributes of the alias name are also assumed
by the specified symbol.
There are two methods of specifying alias information. In the first method, the symbol assumes only the attributes
of the alias name; no additional attributes can be specified. The second method is more general since it is possible
to specify an alias name as well as additional auxiliary information. In this case, the symbol assumes the attributes
of the alias name as well as the attributes specified by the additional auxiliary information.
The simple form of the auxiliary pragma used to specify an alias is as follows.
*$pragma aux ( sym, alias )
- where
- description
sym
- is any valid FORTRAN 77 identifier.
alias
- is the alias name and is any valid FORTRAN 77 identifier.
Consider the following example.
*$pragma aux value_args parm (value)
*$pragma aux ( rtn, value_args )
The routine rtn assumes the attributes of the alias name push_args which specifies that the arguments
to rtn are passed by value.
The general form of an auxiliary pragma that can be used to specify an alias is as follows.
*$pragma aux ( alias ) sym aux_attrs
- where
- description
alias
- is the alias name and is any valid FORTRAN 77 identifier.
sym
- is any valid FORTRAN 77 identifier.
aux_attrs
- are attributes that can be specified with the auxiliary pragma.
Consider the following example.
*$pragma aux WC "*_" parm (value)
*$pragma aux (WC) rtn1
*$pragma aux (WC) rtn2
*$pragma aux (WC) rtn3
The routines rtn1, rtn2 and rtn3 assume the same attributes as the alias name WC
which defines the calling convention used by the Open Watcom C compiler. Whenever calls are made to rtn1,
rtn2 and rtn3, the Open Watcom C calling convention will be used. Note that arguments must be passed
by value. By default, Open Watcom F77 passes arguments by reference.
Note that if the attributes of WC change, only one pragma needs to be changed. If we had not used an
alias name and specified the attributes in each of the three pragmas for rtn1, rtn2 and rtn3,
we would have to change all three pragmas. This approach also reduces the amount of memory required by the compiler
to process the source file.
WARNING! The alias name WC is just another symbol. If WC appeared in
your source code, it would assume the attributes specified in the pragma for WC.
16-bit: Predefined Aliases
A number of symbols are predefined by the compiler with a set of attributes that describe a particular calling convention.
These symbols can be used as aliases. The following is a list of these symbols.
- __cdecl
- __cdecl defines the calling convention used by Microsoft compilers.
__fastcall
- __fastcall defines the calling convention used by Microsoft compilers.
__fortran
- __fortran defines the calling convention used by Open Watcom FORTRAN compilers.
__pascal
- __pascal defines the calling convention used by OS/2 1.x and Windows 3.x API functions.
__stdcall
- __stdcall defines the calling convention used by Microsoft compilers.
__watcall
- __watcall defines the calling convention used by Open Watcom compilers.
The following describes the attributes of the above alias names.
16-bit: Predefined "__cdecl" Alias
*$pragma aux __cdecl "_*" \
c parm caller [] \
c value struct float struct routine
[ax] \
c modify [ax bx cx dx es]
Notes:
- All symbols are preceded by an underscore character.
- Arguments are pushed on the stack from right to left. That is, the last argument is pushed first. The calling
routine will remove the arguments from the stack.
- Floating-point values are returned in the same way as structures. When a structure is returned, the called routine
allocates space for the return value and returns a pointer to the return value in register AX.
- Registers AX, BX, CX and DX, and segment register ES are not saved and restored when a call is made.
16-bit: Predefined "__pascal" Alias
*$pragma aux __pascal "^" \
c parm reverse routine []
\
c value struct float struct caller
[] \
c modify [ax bx cx dx es]
Notes:
- All symbols are mapped to upper case.
- Arguments are pushed on the stack in reverse order. That is, the first argument is pushed first, the second argument
is pushed next, and so on. The routine being called will remove the arguments from the stack.
- Floating-point values are returned in the same way as structures. When a structure is returned, the caller allocates
space on the stack. The address of the allocated space will be pushed on the stack immediately before the call instruction.
Upon returning from the call, register AX will contain address of the space allocated for the return value.
- Registers AX, BX, CX and DX, and segment register ES are not saved and restored when a call is made.
16-bit: Predefined "__watcall" Alias
*$pragma aux __watcall "*_" \
c parm routine [ax bx cx
dx] \
c value struct caller
Notes:
- Symbol names are followed by an underscore character.
- Arguments are processed from left to right. The leftmost arguments are passed in registers and the rightmost arguments
are passed on the stack (if the registers used for argument passing have been exhausted). Arguments that are passed
on the stack are pushed from right to left. The calling routine will remove the arguments if any were pushed on the
stack.
- When a structure is returned, the caller allocates space on the stack. The address of the allocated space is put
into SI register. The called routine then places the return value there. Upon returning from the call, register
AX will contain address of the space allocated for the return value.
- Floating-point values are returned using 80x86 registers ("fpc" option) or using 80x87 floating-point registers
("fpi" or "fpi87" option).
- All registers must be preserved by the called routine.
16-bit: Alternate Names for Symbols
The following form of the auxiliary pragma can be used to describe the mapping of a symbol from its source form to its
object form.
*$pragma aux sym obj_name
- where
- description
sym
- is any valid FORTRAN 77 identifier.
obj_name
- is any character string enclosed in double quotes.
When specifying obj_name, some characters have a special meaning:
- where
- description
*
- is unmodified symbol name
^
- is symbol name converted to uppercase
!
- is symbol name converted to lowercase
#
- is a placeholder for "@nnn", where nnn is size of all function parameters on the stack; it is ignored for functions
with variable argument lists, or for symbols that are not functions
\
- next character is treated as literal
Several examples of source to object form symbol name translation follow: By default, the upper case version "MYRTN"
or "MYVAR" is placed in the object file.
In the following example, the name "MyRtn" will be replaced by "MYRTN_" in the object file.
*$pragma aux MyRtn "^_"
In the following example, the name "MyVar" will be replaced by "_MYVAR" in the object file.
*$pragma aux MyVar "_^"
In the following example, the lower case version "myrtn" will be placed in the object file.
*$pragma aux MyRtn "!"
In the following example, the name "MyRtn" will be replaced by "_MyRtn@nnn" in the object file.
"nnn" represents the size of all function parameters.
*$pragma aux MyRtn "_*#"
In the following example, the name "MyRtn" will be replaced by "_MyRtn#" in the object file.
*$pragma aux MyRtn "_*\#"
The default mapping for all symbols can also be changed as illustrated by the following example.
*$pragma aux default "_^_"
The above auxiliary pragma specifies that all names will be prefixed and suffixed by an underscore character ('_').
The following form of the auxiliary pragma can be used to describe the way a subprogram is to be called.
*$pragma aux sym far
or
*$pragma aux sym near
or
*$pragma aux sym = in_line
in_line ::= { const | "asm" | (float
fpinst) }
- where
- description
sym
- is a subprogram name.
const
- is a valid FORTRAN 77 hexadecimal constant.
fpinst
- is a sequence of bytes that forms a valid 80x87 instruction. The keyword float must precede fpinst
so that special fixups are applied to the 80x87 instruction.
asm
- is an assembly language instruction or directive.
In the following example, Open Watcom F77 will generate a far call to the subprogram myrtn.
*$pragma aux myrtn far
Note that this overrides the calling sequence that would normally be generated for a particular memory model.
In other words, a far call will be generated even if you are compiling for a memory model with a small code model.
In the following example, Open Watcom F77 will generate a near call to the subprogram myrtn.
*$pragma aux myrtn near
Note that this overrides the calling sequence that would normally be generated for a particular memory model.
In other words, a near call will be generated even if you are compiling for a memory model with a big code model.
In the following DOS example, Open Watcom F77 will generate the sequence of bytes following the "=" character
in the auxiliary pragma whenever a call to mode4 is encountered. mode4 is called an in-line subprogram.
*$pragma aux mode4 = \
* zb4 z00
\ mov AH,0
* zb0 z04
\ mov AL,4
* zcd z10
\ int 10h
* modify [ ah al ]
The sequence in the above DOS example represents the following lines of assembly language instructions.
mov AH,0 ; select function "set mode"
mov AL,4 ; specify mode (mode 4)
int 10H ; BIOS video call
The above example demonstrates how to generate BIOS function calls in-line without writing an assembly language function
and calling it from your FORTRAN 77 program.
The following DOS example is equivalent to the above example but mnemonics for the assembly language instructions
are used instead of the binary encoding of the assembly language instructions.
*$pragma aux mode4 = \
* "mov AH,0"
\
* "mov AL,4"
\
* "int 10H"
\
* modify [ ah al ]
If a sequence of in-line assembly language instructions contains 80x87 floating-point instructions, each floating-point
instruction must be preceded by "float". Note that this is only required if you have specified the "fpi"
compiler option; otherwise it will be ignored.
The following example generates the 80x87 "square root" instruction.
*$pragma aux mysqrt parm( value ) [8087] = \
* float zd9fa
16-bit: Loading Data Segment Register
An application may have been compiled so that the segment register DS does not contain the segment address of the default
data segment (group "DGROUP"). This is usually the case if you are using a large data memory model.
Suppose you wish to call a subprogram that assumes that the segment register DS contains the segment address of the default
data segment. It would be very cumbersome if you were forced to compile your application so that the segment register
DS contained the default data segment (a small data memory model).
The following form of the auxiliary pragma will cause the segment register DS to be loaded with the segment address
of the default data segment before calling the specified subprogram.
*$pragma aux sym parm loadds
- where
- description
sym
- is a subprogram name.
Alternatively, the following form of the auxiliary pragma will cause the segment register DS to be loaded with the segment
address of the default data segment as part of the prologue sequence for the specified subprogram.
*$pragma aux sym loadds
- where
- description
sym
- is a subprogram name.
16-bit: Defining Exported Symbols in Dynamic Link Libraries
An exported symbol in a dynamic link library is a symbol that can be referenced by an application that is linked with
that dynamic link library. Normally, symbols in dynamic link libraries are exported using the Open Watcom Linker "EXPORT"
directive. An alternative method is to use the following form of the auxiliary pragma.
*$pragma aux sym export
- where
- description
sym
- is a subprogram name.
16-bit: Defining Windows Callback Functions
When compiling a Microsoft Windows application, you must use the "windows" option so that special prologue/epilogue
sequences are generated. Furthermore, callback functions require larger prologue/epilogue sequences than those generated
when the "windows" compiler option is specified. The following form of the auxiliary pragma will cause a
callback prologue/epilogue sequence to be generated for a callback function when compiled using the "windows" option.
*$pragma aux sym export
- where
- description
sym
- is a callback function name.
Using auxiliary pragmas, you can describe the calling convention that Open Watcom F77 is to use for calling subprograms.
This is particularly useful when interfacing to subprograms that have been compiled by other compilers or subprograms
written in other programming languages.
The general form of an auxiliary pragma that describes argument passing is the following.
*$pragma aux sym parm { arg_info | pop_info | reverse
{reg_set} }
arg_info ::= ( arg_attr {, arg_attr}
)
arg_attr ::= value [v_attr] | reference
[r_attr] | data_reference [d_attr]
v_attr ::= far | near | *1 | *2
| *4 | *8
r_attr ::= [far | near]
[descriptor | nodescriptor]
d_attr ::= [far | near]
pop_info ::= caller | routine
- where
- description
sym
- is a subprogram name.
reg_set
- is called a register set. The register sets specify the registers that are to be used for argument passing. A
register set is a list of registers separated by spaces and enclosed in square brackets.
16-bit: Passing Arguments to non-FORTRAN Subprograms
When calling a subprogram written in a different language, it may be necessary to provide the arguments in a form different
than the default methods used by Open Watcom F77. For example, C functions require scalar arguments to be passed by
value instead of by reference. For information on the methods Open Watcom F77 uses to pass arguments, see the chapter
entitled "Assembly Language Considerations".
The following form of the auxiliary pragma can be used to alter the default calling mechanism used for passing arguments.
*$pragma aux sym parm ( arg_attr {, arg_attr}
)
arg_attr ::= value [v_attr] | reference
[r_attr] | data_reference [d_attr]
v_attr ::= far | near | *1 | *2
| *4 | *8
r_attr ::= [far | near]
[descriptor | nodescriptor]
d_attr ::= [far | near]
- where
- description
sym
- is a subprogram name.
REFERENCE
- specifies that arguments are to be passed by reference. For non-character arguments, the address is a pointer to the
data. For character arguments, the address is a pointer to a string descriptor. See the chapter entitled "Assembly
Language Considerations" for a description of a string descriptor. This is the default calling mechanism.
If "NEAR" or "FAR" is specified, a near pointer or far pointer is passed regardless of the memory model
used at compile-time.
If the "DESCRIPTOR" attribute is specified, a pointer to the string descriptor is passed. This is the
default. If the "NODESCRIPTOR" attribute is specified, a pointer to the the actual character data is passed
instead of a pointer to the string descriptor.
DATA_REFERENCE
- specifies that arguments are to be passed by data reference. For non-character items, this is identical to passing by
reference. For character items, a pointer to the actual character data (instead of the string descriptor) is passed.
If "NEAR" or "FAR" is specified, a near pointer or far pointer is passed regardless of the memory
model used at compile-time.
VALUE
- specifies that arguments are to be passed by value. Character arguments are treated specially when passed by value.
Instead of passing a pointer to a string descriptor, a pointer to the actual character data is passed. See the
chapter entitled "Assembly Language Considerations" for a description of a string descriptor.
Notes:
- Arrays and subprograms are always passed by reference, regardless of the argument attribute specified.
- When character arguments are passed by reference, the address of a string descriptor is passed. The string descriptor
contains the address of the actual character data and the number of characters. When character arguments are passed
by value or data reference, the address of the actual character data is passed instead of the address of a string descriptor.
Character arguments are passed by value by specifying the "VALUE" or "DATA_REFERENCE" attribute.
If "NEAR" or "FAR" is specified, a near pointer or far pointer to the character data is passed
regardless of the memory model used at compile-time.
- When complex arguments are passed by value, the real part and the imaginary part are passed as two separate arguments.
- When an argument is a user-defined structure and is passed by value, a copy of the structure is made and passed as an
argument.
- For scalar arguments, arguments of type INTEGER*1, INTEGER*2, INTEGER*4 ct , REAL or DOUBLE
PRECISION, a length specification can be specified when the "VALUE" attribute is specified to pass the argument
by value. This length specification refers to the size of the argument; the compiler will convert the actual argument
to a type that matches the size. For example, if an argument of type REAL is passed to a subprogram that has
an argument attribute of "VALUE*8", the argument will be converted to DOUBLE PRECISION. If an argument
of type DOUBLE PRECISION is passed to a subprogram that has an argument attribute of "VALUE*4", the argument
will be converted to REAL. If an argument of type INTEGER*4 is passed to a subprogram that has an argument
attribute of "VALUE*2" or VALUE*1, the argument will be converted to INTEGER*2 or INTEGER*1.
If an argument of type INTEGER*2 is passed to a subprogram that has an argument attribute of "VALUE*4 or VALUE*1",
the argument will be converted to INTEGER*4 or INTEGER*1. If an argument of type INTEGER*1 is
passed to a subprogram that has an argument attribute of "VALUE*4 or VALUE*2", the argument will be converted to
INTEGER*4 or INTEGER*2.
- If the number of arguments exceeds the number of entries in the argument-attribute list, the last attribute will be assumed
for the remaining arguments.
Consider the following example.
*$pragma aux printf "*_" parm (value) caller []
character cr/z0d/, nullchar/z00/
call printf( 'values: %ld, %ld'//cr//nullchar,
1
77, 31410 )
end
The C "printf" function is called with three arguments. The first argument is of type CHARACTER
and is passed as a C string (address of actual data terminated by a null character). The second and third arguments
are passed by value. Also note that "printf" is a function that takes a variable number of arguments, all
passed on the stack (an empty register set was specified), and that the caller must remove the arguments from the stack.
16-bit: Passing Arguments in Registers
The following form of the auxiliary pragma can be used to specify the registers that are to be used to pass arguments
to a particular subprogram.
*$pragma aux sym parm {reg_set}
- where
- description
sym
- is a subprogram name.
reg_set
- is called a register set. The register sets specify the registers that are to be used for argument passing. A
register set is a list of registers separated by spaces and enclosed in square brackets.
Register sets establish a priority for register allocation during argument list processing. Register sets are processed
from left to right. However, within a register set, registers are chosen in any order. Once all register sets
have been processed, any remaining arguments are pushed on the stack.
Note that regardless of the register sets specified, only certain combinations of registers will be selected for arguments
of a particular type.
Note that arguments of type REAL and DOUBLE PRECISION are always pushed on the stack when the "fpi"
or "fpi87" option is used.
- DOUBLE PRECISION
- Arguments of type DOUBLE PRECISION, when passed by value, can only be passed in the following register combination:
AX:BX:CX:DX. For example, if the following register set was specified for a routine having an argument of type
DOUBLE PRECISION,
[ax bx si di]
the argument would be pushed on the stack since a valid register combination for 8-byte arguments is not contained
in the register set. Note that this method for passing arguments of type DOUBLE PRECISION is supported only
when the "fpc" option is used. Note that this argument passing method does not include arguments of type
COMPLEX*8 or user-defined structures whose size is 8 bytes when these arguments are passed by value.
far pointer
- A far pointer can only be passed in one of the following register pairs: DX:AX, CX:BX, CX:AX, CX:SI, DX:BX, DI:AX, CX:DI,
DX:SI, DI:BX, SI:AX, CX:DX, DX:DI, DI:SI, SI:BX, BX:AX, DS:CX, DS:DX, DS:DI, DS:SI, DS:BX, DS:AX, ES:CX, ES:DX, ES:DI, ES:SI,
ES:BX or ES:AX. For example, if a far pointer is passed to a function with the following register set,
[es bp]
the argument would be pushed on the stack since a valid register combination for a far pointer is not contained in
the register set. Far pointers are used to pass arguments by reference in a big data memory model.
INTEGER*4, REAL
- The only registers that will be assigned to 4-byte arguments (e.g., arguments of type INTEGER*4, when passed by value)
are: DX:AX, CX:BX, CX:AX, CX:SI, DX:BX, DI:AX, CX:DI, DX:SI, DI:BX, SI:AX, CX:DX, DX:DI, DI:SI, SI:BX and BX:AX.
For example, if the following register set was specified for a routine with one argument of type INTEGER*4,
[es di]
the argument would be pushed on the stack since a valid register combination for 4-byte arguments is not contained
in the register set. Note that this argument passing method includes arguments of type REAL but only when the
"fpc" option is used.
INTEGER*2
- The only registers that will be assigned to 2-byte arguments (e.g., arguments of type INTEGER*2 when passed by value
or arguments passed by reference in a small data memory model) are: AX, BX, CX, DX, SI and DI. For example, if
the following register set was specified for a routine with one argument of type INTEGER*2,
[bp]
the argument would be pushed on the stack since a valid register combination for 2-byte arguments is not contained
in the register set.
INTEGER*1
- Arguments whose size is 1 byte (e.g., arguments of type INTEGER*1 when passed by value) are promoted to 2 bytes and
are then assigned registers as if they were 2-byte arguments.
others
- Arguments that do not fall into one of the above categories cannot be passed in registers and are pushed on the stack.
Once an argument has been assigned a position on the stack, all remaining arguments will be assigned a position on the stack
even if all register sets have not yet been exhausted.
Notes:
- The default register set is [ax bx cx dx].
- Specifying registers AH and AL is equivalent to specifying register AX. Specifying registers DH and DL is equivalent
to specifying register DX. Specifying registers CH and CL is equivalent to specifying register CX. Specifying
registers BH and BL is equivalent to specifying register BX.
- If you are compiling for a memory model with a small data model, any register combination containing register DS becomes
illegal. In a small data model, segment register DS must remain unchanged as it points to the program's data segment.
Consider the following example.
*$pragma aux myrtn parm (value) \
*
[ax bx cx dx] [bp si]
Suppose myrtn is a routine with 3 arguments each of type INTEGER. Note that the arguments are
passed by value.
- The first argument will be passed in the register pair DX:AX.
- The second argument will be passed in the register pair CX:BX.
- The third argument will be pushed on the stack since BP:SI is not a valid register pair for arguments of type INTEGER.
It is possible for registers from the second register set to be used before registers from the first register set are
used. Consider the following example.
*$pragma aux myrtn parm (value) \
*
[ax bx cx dx] [si di]
Suppose myrtn is a routine with 3 arguments, the first of type INTEGER and the second and third of
type INTEGER. Note that all arguments are passed by value.
- The first argument will be passed in the register AX.
- The second argument will be passed in the register pair CX:BX.
- The third argument will be passed in the register set DI:SI.
Note that registers are no longer selected from a register set after registers are selected from subsequent register sets,
even if all registers from the original register set have not been exhausted.
An empty register set is permitted. All subsequent register sets appearing after an empty register set are ignored;
all remaining arguments are pushed on the stack.
Notes:
- If a single empty register set is specified, all arguments are passed on the stack.
- If no register set is specified, the default register set [ax bx cx dx] is used.
16-bit: Forcing Arguments into Specific Registers
It is possible to force arguments into specific registers. Suppose you have a subprogram, say "mycopy",
that copies data. The first argument is the source, the second argument is the destination, and the third argument
is the length to copy. If we want the first argument to be passed in the register SI, the second argument to be passed
in register DI and the third argument to be passed in register CX, the following auxiliary pragma can be used.
*$pragma aux mycopy parm (value) \
*
[si] [di] [cx]
character*10 dst
call mycopy( dst, '0123456789', 10 )
...
end
Note that you must be aware of the size of the arguments to ensure that the arguments get passed in the appropriate
registers.
16-bit: Passing Arguments to In-Line Subprograms
For subprograms whose code is generated by Open Watcom F77 and whose argument list is described by an auxiliary pragma,
Open Watcom F77 has some freedom in choosing how arguments are assigned to registers. Since the code for in-line subprograms
is specified by the programmer, the description of the argument list must be very explicit. To achieve this, Open Watcom
F77 assumes that each register set corresponds to an argument. Consider the following DOS example of an in-line subprogram
called scrollactivepgup.
*$pragma aux scrollactivepgup = \
* "mov AH,6" \
* "int 10h" \
* parm (value) \
* [ch] [cl] [dh] [dl]
[al] [bh] \
* modify [ah]
The BIOS video call to scroll the active page up requires the following arguments.
- The row and column of the upper left corner of the scroll window is passed in registers CH and CL respectively.
- The row and column of the lower right corner of the scroll window is passed in registers DH and DL respectively.
- The number of lines blanked at the bottom of the window is passed in register AL.
- The attribute to be used on the blank lines is passed in register BH.
When passing arguments, Open Watcom F77 will convert the argument so that it fits in the register(s) specified in the
register set for that argument. For example, in the above example, if the first argument to scrollactivepgup
was called with an argument whose type was INTEGER, it would first be converted to INTEGER*1 before assigning
it to register CH. Similarly, if an in-line subprogram required its argument in register pair DX:AX and the argument
was of type INTEGER*2, the argument would be converted to INTEGER*4 before assigning it to register pair DX:AX.
In general, Open Watcom F77 assigns the following types to register sets.
- A register set consisting of a single 8-bit register (1 byte) is assigned a type of INTEGER*1.
- A register set consisting of a single 16-bit register (2 bytes) is assigned a type of INTEGER*2.
- A register set consisting of two 16-bit registers (4 bytes) is assigned a type of INTEGER*4.
- A register set consisting of four 16-bit registers (8 bytes) is assigned a type of DOUBLE PRECISION.
If the size of an integer argument is larger than the size specified by the register set, the argument will be truncated
to the required size. If the size of an integer argument is smaller than the size specified by the register set, the
argument will be padded (to the left) with zeros.
16-bit: Removing Arguments from the Stack
The following form of the auxiliary pragma specifies who removes from the stack arguments that were pushed on the stack.
*$pragma aux sym parm (caller | routine)
- where
- description
sym
- is a subprogram name.
"caller" specifies that the caller will pop the arguments from the stack; "routine" specifies that
the called routine will pop the arguments from the stack. If "caller" or "routine" is omitted,
"routine" is assumed unless the default has been changed in a previous auxiliary pragma, in which case the new
default is assumed.
Consider the following example. It describes the pragma required to call the C "printf" function.
*$pragma aux printf "*_" parm (value) caller []
character cr/z0d/, nullchar/z00/
call printf( 'value is %ld'//cr//nullchar,
1
7143 )
end
The first argument must be passed as a C string, a pointer to the actual character data terminated by a null character.
By default, the address of a string descriptor is passed for arguments of type CHARACTER. See the chapter
entitled "Assembly Language Considerations" for more information on string descriptors. The second argument
is of type INTEGER and is passed by value. Also note that "printf" is a function that takes a variable
number of arguments, all pushed on the stack (an empty register set was specified).
16-bit: Passing Arguments in Reverse Order
The following form of the auxiliary pragma specifies that arguments are passed in the reverse order.
*$pragma aux sym parm reverse
- where
- description
sym
- is a subprogram name.
Normally, arguments are processed from left to right. The leftmost arguments are passed in registers and the rightmost
arguments are passed on the stack (if the registers used for argument passing have been exhausted). Arguments that
are passed on the stack are pushed from right to left.
When arguments are reversed, the rightmost arguments are passed in registers and the leftmost arguments are passed
on the stack (if the registers used for argument passing have been exhausted). Arguments that are passed on the stack
are pushed from left to right.
Reversing arguments is most useful for subprograms that require arguments to be passed on the stack in an order opposite
from the default. The following auxiliary pragma demonstrates such a subprogram.
*$pragma aux rtn parm reverse []
Using auxiliary pragmas, you can describe the way functions are to return values. This is particularly useful when
interfacing to functions that have been compiled by other compilers or functions written in other programming languages.
The general form of an auxiliary pragma that describes the way a function returns its value is the following.
*$pragma aux sym value {no8087 | reg_set
| struct_info}
struct_info ::= struct {float | struct |
(routine | caller) | reg_set}
- where
- description
sym
- is a function name.
reg_set
- is called a register set. The register sets specify the registers that are to be used for argument passing. A
register set is a list of registers separated by spaces and enclosed in square brackets.
16-bit: Returning Subprogram Values in Registers
The following form of the auxiliary pragma can be used to specify the registers that are to be used to return a function's
value.
*$pragma aux sym value reg_set
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set.
Note that the method described below for returning values of type REAL or DOUBLE PRECISION is supported
only when the "fpc" option is used.
Depending on the type of the return value, only certain registers are allowed in reg_set.
- 1-byte
- For 1-byte return values, only the following registers are allowed: AL, AH, DL, DH, BL, BH, CL or CH. If no register
set is specified, register AL will be used.
2-byte
- For 2-byte return values, only the following registers are allowed: AX, DX, BX, CX, SI or DI. If no register set
is specified, register AX will be used.
4-byte
- For 4-byte return values (except far pointers), only the following register pairs are allowed: DX:AX, CX:BX, CX:AX,
CX:SI, DX:BX, DI:AX, CX:DI, DX:SI, DI:BX, SI:AX, CX:DX, DX:DI, DI:SI, SI:BX or BX:AX. If no register set is specified,
registers DX:AX will be used. This form of the auxiliary pragma is legal for functions of type REAL when using
the "fpc" option only.
far pointer
- For functions that return far pointers, the following register pairs are allowed: DX:AX, CX:BX, CX:AX, CX:SI, DX:BX,
DI:AX, CX:DI, DX:SI, DI:BX, SI:AX, CX:DX, DX:DI, DI:SI, SI:BX, BX:AX, DS:CX, DS:DX, DS:DI, DS:SI, DS:BX, DS:AX, ES:CX, ES:DX,
ES:DI, ES:SI, ES:BX or ES:AX. If no register set is specified, the registers DX:AX will be used.
8-byte
- For 8-byte return values (including functions of type DOUBLE PRECISION), only the following register combination is
allowed: AX:BX:CX:DX. If no register set is specified, the registers AX:BX:CX:DX will be used. This form
of the auxiliary pragma is legal for functions of type DOUBLE PRECISION when using the "fpc" option only.
Notes:
- An empty register set is not allowed.
- If you are compiling for a memory model which has a small data model, any of the above register combinations containing
register DS becomes illegal. In a small data model, segment register DS must remain unchanged as it points to the program's
data segment.
16-bit: Returning Structures and Complex Numbers
Typically, structures and complex numbers are not returned in registers. Instead, the caller allocates space on
the stack for the return value and sets register SI to point to it. The called routine then places the return value
at the location pointed to by register SI.
Complex numbers are not scalars but rather an ordered pair of real numbers. One can also view complex numbers
as a structure containing two real numbers.
The following form of the auxiliary pragma can be used to specify the register that is to be used to point to the
return value.
*$pragma aux sym value struct (caller | routine)
reg_set
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set.
"caller" specifies that the caller will allocate memory for the return value. The address of the memory
allocated for the return value is placed in the register specified in the register set by the caller before the function
is called. If an empty register set is specified, the address of the memory allocated for the return value will be
pushed on the stack immediately before the call and will be returned in register AX by the called routine. It is assumed
that the memory for the return value is allocated from the stack segment (the stack segment is contained in segment register
SS).
"routine" specifies that the called routine will allocate memory for the return value. Upon returning
to the caller, the register specified in the register set will contain the address of the return value. An empty register
set is not allowed.
Only the following registers are allowed in the register set: AX, DX, BX, CX, SI or DI. Note that in a
big data model, the address in the return register is assumed to be in the segment specified by the value in the SS segment
register.
If the size of the structure being returned is 1, 2 or 4 bytes, it will be returned in registers. The return
register will be selected from the register set in the following way.
- A 1-byte structure will be returned in one of the following registers: AL, AH, DL, DH, BL, BH, CL or CH. If
no register set is specified, register AL will be used.
- A 2-byte structure will be returned in one of the following registers: AX, DX, BX, CX, SI or DI. If no register
set is specified, register AX will be used.
- A 4-byte structure will be returned in one of the following register pairs: DX:AX, CX:BX, CX:AX, CX:SI, DX:BX, DI:AX,
CX:DI, DX:SI, DI:BX, SI:AX, CX:DX, DX:DI, DI:SI, SI:BX or BX:AX. If no register set is specified, register pair DX:AX
will be used.
The following form of the auxiliary pragma can be used to specify that structures whose size is 1, 2 or 4 bytes are not
to be returned in registers. Instead, the caller will allocate space on the stack for the structure return value and
point register SI to it.
*$pragma aux sym value struct struct
- where
- description
sym
- is a subprogram name.
16-bit: Returning Floating-Point Data
There are a few ways available for specifying how the value for a function whose type is REAL or DOUBLE PRECISION
is to be returned.
The following form of the auxiliary pragma can be used to specify that function return values whose type is REAL
or DOUBLE PRECISION are not to be returned in registers. Instead, the caller will allocate space on the stack
for the return value and point register SI to it.
*$pragma aux sym value struct float
- where
- description
sym
- is a function name.
In other words, floating-point values are to be returned in the same way complex numbers are returned.
The following form of the auxiliary pragma can be used to specify that function return values whose type is REAL
or DOUBLE PRECISION are not to be returned in 80x87 registers when compiling with the "fpi" or "fpi87"
option. Instead, the value will be returned in 80x86 registers. This is the default behaviour for the "fpc"
option. Function return values whose type is REAL will be returned in registers DX:AX. Function return
values whose type is DOUBLE PRECISION will be returned in registers AX:BX:CX:DX. This is the default method
for the "fpc" option.
*$pragma aux sym value no8087
- where
- description
sym
- is a function name.
The following form of the auxiliary pragma can be used to specify that function return values whose type is REAL
or DOUBLE PRECISION are to be returned in ST(0) when compiling with the "fpi" or "fpi87" option.
This form of the auxiliary pragma is not legal for the "fpc" option.
*$pragma aux sym value [8087]
- where
- description
sym
- is a function name.
16-bit: A Subprogram that Never Returns
The following form of the auxiliary pragma can be used to describe a subprogram that does not return to the caller.
*$pragma aux sym aborts
- where
- description
sym
- is a subprogram name.
Consider the following example.
*$pragma aux exitrtn aborts
...
call exitrtn()
end
exitrtn is defined to be a function that does not return. For example, it may call exit to
return to the system. In this case, Open Watcom F77 generates a "jmp" instruction instead of a "call"
instruction to invoke exitrtn.
16-bit: Describing How Subprograms Use Variables in Common
The following form of the auxiliary pragma can be used to describe a subprogram that does not modify any variable that
appears in a common block defined by the caller.
*$pragma aux sym modify nomemory
- where
- description
sym
- is a subprogram name.
Consider the following example.
integer i
common /blk/ i
while( i .lt. 1000 )do
i = i + 383
endwhile
call myrtn()
i = i + 13143
end
block data
common /blk/ i
integer i/1033/
end
To compile the above program, "rtn.for", we issue the following command.
C>wfc rtn -mm -d1
C>wfc386 rtn -d1
The "d1" compiler option is specified so that the object file produced by Open Watcom F77 contains source
line information.
We can generate a file containing a disassembly of rtn.obj by issuing the following command.
C>wdis rtn -l -s -r
The "s" option is specified so that the listing file produced by the Open Watcom Disassembler contains source
lines taken from rtn.for. The listing file rtn.lst appears as follows.
Let us add the following auxiliary pragma to the source file.
*$pragma aux myrtn modify nomemory
If we compile the source file with the above pragma and disassemble the object file using the Open Watcom Disassembler,
we get the following listing file.
Module: rtn.for
Group: 'DGROUP' _DATA,LDATA,CDATA,BLK
Segment: 'FMAIN_TEXT' BYTE 00000024 bytes
*$pragma aux myrtn modify nomemory
integer*2 i
common /blk/ i
0000 52
FMAIN push dx
0001 8b 16 00 00
mov dx,L3
while( i .lt. 1000 )do
0005 81 fa e8 03 L1
cmp dx,03e8H
0009 7d 06
jge
L2
i = i + 383
endwhile
000b 81 c2 7f 01
add dx,017fH
000f eb f4
jmp
L1
call myrtn()
0011 89 16 00 00 L2
mov L3,dx
0015 9a 00 00 00 00
call far MYRTN
i = i + 13143
001a 81 c2 57 33
add dx,3357H
001e 89 16 00 00
mov L3,dx
end
block data
common /blk/ i
integer*2 i/1033/
end
0022 5a
pop
dx
0023 cb
retf
No disassembly errors
List of external symbols
Symbol
----------------
MYRTN 00000016
------------------------------------------------------------
Segment: 'BLK' PARA 00000002 bytes
0000 09 04
L3
- ..
No disassembly errors
------------------------------------------------------------
List of public symbols
SYMBOL GROUP
SEGMENT ADDRESS
---------------------------------------------------------
FMAIN
FMAIN_TEXT 00000000
------------------------------------------------------------
Notice that the value of i is in register DX after completion of the "while" loop. After
the call to myrtn, the value of i is not loaded from memory into a register to perform the final addition.
The auxiliary pragma informs the compiler that myrtn does not modify any variable that appears in a common
block defined by Rtn and hence register DX contains the correct value of i.
The preceding auxiliary pragma deals with routines that modify variables in common. Let us consider the case
where routines reference variables in common. The following form of the auxiliary pragma can be used to describe a
subprogram that does not reference any variable that appears in a common block defined by the caller.
*$pragma aux sym parm nomemory modify nomemory
- where
- description
sym
- is a subprogram name.
Notes:
- You must specify both "parm nomemory" and "modify nomemory".
Let us replace the auxiliary pragma in the above example with the following auxiliary pragma.
*$pragma aux myrtn parm nomemory modify nomemory
If you now compile our source file and disassemble the object file using WDIS, the result is the following listing
file.
Module: rtn.for
Group: 'DGROUP' _DATA,LDATA,CDATA,BLK
Segment: 'FMAIN_TEXT' BYTE 00000020 bytes
*$pragma aux myrtn parm nomemory modify nomemory
integer*2 i
common /blk/ i
0000 52
FMAIN push dx
0001 8b 16 00 00
mov dx,L3
while( i .lt. 1000 )do
0005 81 fa e8 03 L1
cmp dx,03e8H
0009 7d 06
jge
L2
i = i + 383
endwhile
000b 81 c2 7f 01
add dx,017fH
000f eb f4
jmp
L1
call myrtn()
0011 9a 00 00 00 00 L2
call far MYRTN
i = i + 13143
0016 81 c2 57 33
add dx,3357H
001a 89 16 00 00
mov L3,dx
end
block data
common /blk/ i
integer*2 i/1033/
end
001e 5a
pop
dx
001f cb
retf
No disassembly errors
List of external symbols
Symbol
----------------
MYRTN 00000012
------------------------------------------------------------
Segment: 'BLK' PARA 00000002 bytes
0000 09 04
L3
- ..
No disassembly errors
------------------------------------------------------------
List of public symbols
SYMBOL GROUP
SEGMENT ADDRESS
---------------------------------------------------------
FMAIN
FMAIN_TEXT 00000000
------------------------------------------------------------
Notice that after completion of the "while" loop we did not have to update i with the value in
register DX before calling myrtn. The auxiliary pragma informs the compiler that myrtn does not reference
any variable that appears in a common block defined by myrtn so updating i was not necessary before calling
myrtn.
16-bit: Describing the Registers Modified by a Subprogram
The following form of the auxiliary pragma can be used to describe the registers that a subprogram will use without saving.
*$pragma aux sym modify [exact] reg_set
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set.
Specifying a register set informs Open Watcom F77 that the registers belonging to the register set are modified by the
subprogram. That is, the value in a register before calling the subprogram is different from its value after execution
of the subprogram.
Registers that are used to pass arguments are assumed to be modified and hence do not have to be saved and restored
by the called subprogram. Also, since the AX register is frequently used to return a value, it is always assumed to
be modified. If necessary, the caller will contain code to save and restore the contents of registers used to pass
arguments. Note that saving and restoring the contents of these registers may not be necessary if the called subprogram
does not modify them. The following form of the auxiliary pragma can be used to describe exactly those registers that
will be modified by the called subprogram.
*$pragma aux sym modify exact reg_set
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set.
The above form of the auxiliary pragma tells Open Watcom F77 not to assume that the registers used to pass arguments will
be modified by the called subprogram. Instead, only the registers specified in the register set will be modified.
This will prevent generation of the code which unnecessarily saves and restores the contents of the registers used to pass
arguments.
Also, any registers that are specified in the value register set are assumed to be unmodified unless explicitly
listed in the exact register set. In the following example, the code generator will not generate code to save
and restore the value of the stack pointer register since we have told it that "GetSP" does not modify any register
whatsoever.
Example:
*$ifdef __386__
*$pragma aux GetSP = value [esp] modify exact []
*$else
*$pragma aux GetSP = value [sp] modify exact []
*$endif
program main
integer GetSP
print *, 'Current SP =', GetSP()
end
16-bit: Auxiliary Pragmas and the 80x87
This section deals with those aspects of auxiliary pragmas that are specific to the 80x87. The discussion in this
chapter assumes that one of the "fpi" or "fpi87" options is used to compile subprograms. The following
areas are affected by the use of these options.
- passing floating-point arguments to functions,
- returning floating-point values from functions and
- which 80x87 floating-point registers are allowed to be modified by the called routine.
16-bit: Using the 80x87 to Pass Arguments
By default, floating-point arguments are passed on the 80x86 stack. The 80x86 registers are never used to pass floating-point
arguments when a subprogram is compiled with the "fpi" or "fpi87" option. However, they can be
used to pass arguments whose type is not floating-point such as arguments of type "int".
The following form of the auxiliary pragma can be used to describe the registers that are to be used to pass arguments
to subprograms.
*$pragma aux sym parm {reg_set}
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set. The register set can contain 80x86 registers and/or the string "8087".
Notes:
- If an empty register set is specified, all arguments, including floating-point arguments, will be passed on the 80x86
stack.
When the string "8087" appears in a register set, it simply means that floating-point arguments can be passed
in 80x87 floating-point registers if the source file is compiled with the "fpi" or "fpi87" option.
Before discussing argument passing in detail, some general notes on the use of the 80x87 floating-point registers are given.
The 80x87 contains 8 floating-point registers which essentially form a stack. The stack pointer is called ST
and is a number between 0 and 7 identifying which 80x87 floating-point register is at the top of the stack. ST is initially
0. 80x87 instructions reference these registers by specifying a floating-point register number. This number is
then added to the current value of ST. The sum (taken modulo 8) specifies the 80x87 floating-point register to be used.
The notation ST(n), where "n" is between 0 and 7, is used to refer to the position of an 80x87 floating-point
register relative to ST.
When a floating-point value is loaded onto the 80x87 floating-point register stack, ST is decremented (modulo 8),
and the value is loaded into ST(0). When a floating-point value is stored and popped from the 80x87 floating-point
register stack, ST is incremented (modulo 8) and ST(1) becomes ST(0). The following illustrates the use of the 80x87
floating-point registers as a stack, assuming that the value of ST is 4 (4 values have been loaded onto the 80x87 floating-point
register stack).
+----------------+
0 | 4th from top
| ST(4)
+----------------+
1 | 5th from top
| ST(5)
+----------------+
2 | 6th from top
| ST(6)
+----------------+
3 | 7th from top
| ST(7)
+----------------+
ST -> 4 | top of stack | ST(0)
+----------------+
5 | 1st from top
| ST(1)
+----------------+
6 | 2nd from top
| ST(2)
+----------------+
7 | 3rd from top
| ST(3)
+----------------+
Starting with version 9.5, the Open Watcom compilers use all eight of the 80x87 registers as a stack. The initial
state of the 80x87 register stack is empty before a program begins execution.
- Note:
- For compatibility with code compiled with version 9.0 and earlier, you can compile with the "fpr" option.
In this case only four of the eight 80x87 registers are used as a stack. These four registers were used to pass arguments.
The other four registers form what was called the 80x87 cache. The cache was used for local floating-point variables.
The state of the 80x87 registers before a program began execution was as follows.
- The four 80x87 floating-point registers that form the stack are uninitialized.
- The four 80x87 floating-point registers that form the 80x87 cache are initialized with zero.
Hence, initially the 80x87 cache was comprised of ST(0), ST(1), ST(2) and ST(3). ST had the value 4 as in the above
diagram. When a floating-point value was pushed on the stack (as is the case when passing floating-point arguments),
it became ST(0) and the 80x87 cache was comprised of ST(1), ST(2), ST(3) and ST(4). When the 80x87 stack was full,
ST(0), ST(1), ST(2) and ST(3) formed the stack and ST(4), ST(5), ST(6) and ST(7) formed the 80x87 cache. Version 9.5
and later no longer use this strategy.
The rules for passing arguments are as follows.
- If the argument is not floating-point, use the procedure described earlier in this chapter.
- If the argument is floating-point, and a previous argument has been assigned a position on the 80x86 stack (instead of
the 80x87 stack), the floating-point argument is also assigned a position on the 80x86 stack. Otherwise proceed to
the next step.
- If the string "8087" appears in a register set in the pragma, and if the 80x87 stack is not full, the floating-point
argument is assigned floating-point register ST(0) (the top element of the 80x87 stack). The previous top element (if
there was one) is now in ST(1). Since arguments are pushed on the stack from right to left, the leftmost floating-point
argument will be in ST(0). Otherwise the floating-point argument is assigned a position on the 80x86 stack.
Consider the following example.
*$pragma aux myrtn parm (value) [8087]
real x
double precision y
integer*2 i
integer j
x = 7.7
i = 7
y = 77.77
j = 77
call myrtn( x, i, y, j )
end
myrtn is an assembly language subprogram that requires four arguments. The first argument of type
REAL (4 bytes), the second argument is of type INTEGER*2 (2 bytes), the third argument is of type DOUBLE PRECISION
(8 bytes) and the fourth argument is of type INTEGER*4 (4 bytes). These arguments will be passed to myrtn
in the following way.
- Since "8087" was specified in the register set, the first argument, being of type REAL, will be passed
in an 80x87 floating-point register.
- The second argument will be passed on the stack since no 80x86 registers were specified in the register set.
- The third argument will also be passed on the stack. Remember the following rule: once an argument is assigned
a position on the stack, all remaining arguments will be assigned a position on the stack. Note that the above rule
holds even though there are some 80x87 floating-point registers available for passing floating-point arguments.
- The fourth argument will also be passed on the stack.
Let us change the auxiliary pragma in the above example as follows.
*$pragma aux myrtn parm [ax 8087]
The arguments will now be passed to myrtn in the following way.
- Since "8087" was specified in the register set, the first argument, being of type REAL will be passed
in an 80x87 floating-point register.
- The second argument will be passed in register AX, exhausting the set of available 80x86 registers for argument passing.
- The third argument, being of type DOUBLE PRECISION, will also be passed in an 80x87 floating-point register.
- The fourth argument will be passed on the stack since no 80x86 registers remain in the register set.
16-bit: Using the 80x87 to Return Subprogram Values
The following form of the auxiliary pragma can be used to describe a subprogram that returns a floating-point value in
ST(0).
*$pragma aux sym value reg_set
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set containing the string "8087", i.e. [8087].
16-bit: Preserving 80x87 Floating-Point Registers Across Calls
The code generator assumes that all eight 80x87 floating-point registers are available for use within a subprogram unless
the "fpr" option is used to generate backward compatible code (older Open Watcom compilers used four registers
as a cache). The following form of the auxiliary pragma specifies that the floating-point registers in the 80x87 cache
may be modified by the specified subprogram.
*$pragma aux sym modify reg_set
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set containing the string "8087", i.e. [8087].
This instructs Open Watcom F77 to save any local variables that are located in the 80x87 cache before calling the specified
routine.
32-bit: Memory Models
This chapter describes the various memory models supported by Open Watcom F77. Each memory model is distinguished
by two properties; the code model used to implement subprogram calls and the data model used to reference data.
32-bit: Code Models
There are two code models:
- the small code model
- the big code model
A small code model is one in which all calls to subprograms are made with near calls. In a near call, the
destination address is 32 bits and is relative to the segment value in segment register CS. Hence, in a small code
model, all code comprising your program, including library subprograms, must be less than 4GB.
A big code model is one in which all calls to subprograms are made with far calls. In a far call, the
destination address is 48 bits (a 16-bit segment value and a 32-bit offset relative to the segment value). This model
allows the size of the code comprising your program to exceed 4GB.
Note: If your program contains less than 4GB of code, you should use a memory model that employs
the small code model. This will result in smaller and faster code since near calls are smaller instructions and are
processed faster by the CPU.
32-bit: Data Models
There are two data models:
- the small data model
- the big data model
A small data model is one in which all references to data are made with near pointers. Near pointers are
32 bits; all data references are made relative to the segment value in segment register DS. Hence, in a small data
model, all data comprising your program must be less than 4GB.
A big data model is one in which all references to data are made with far pointers. Far pointers are
48 bits (a 16-bit segment value and a 32-bit offset relative to the segment value). This removes the 4GB limitation
on data size imposed by the small data model. However, when a far pointer is incremented, only the offset is adjusted.
Open Watcom F77 assumes that the offset portion of a far pointer will not be incremented beyond 4GB. The compiler
will assign an object to a new segment if the grouping of data in a segment will cause the object to cross a segment boundary.
Implicit in this is the requirement that no individual object exceed 4GB.
Note: If your program contains less than 4GB of data, you should use the small data model.
This will result in smaller and faster code since references using near pointers produce fewer instructions.
32-bit: Summary of Memory Models
As previously mentioned, a memory model is a combination of a code model and a data model. The following table describes
the memory models supported by Open Watcom F77.
Memory Code Data
Default Default
Model Model Model
Code Data
Pointer Pointer
-------- -------- -------- --------
--------
flat small
small near near
small small small
near near
medium big
small far near
compact small big
near far
large big
big far far
32-bit: Flat Memory Model
In the flat memory model, the application's code and data must total less than 4GB in size. Segment registers CS,
DS, SS and ES point to the same linear address space (this does not imply that the segment registers contain the same value).
That is, a given offset in one segment refers to the same memory location as that offset in another segment.
Essentially, a flat model operates as if there were no segments.
32-bit: Mixed Memory Model
A mixed memory model application combines elements from the various code and data models. A mixed memory model application
might be characterized as one that includes arrays which are larger than 4GB.
For example, a medium memory model application that uses some arrays which exceed 4GB in total size can be described
as a mixed memory model. In an application such as this, most of the data is in a 4GB segment (DGROUP) and hence can
be referenced with near pointers relative to the segment value in segment register DS. This results in more efficient
code being generated and better execution times than one can expect from a big data model.
32-bit: Linking Applications for the Various Memory Models
Each memory model requires different run-time and floating-point libraries. Each library assumes a particular memory
model and should be linked only with modules that have been compiled with the same memory model. The following table
lists the libraries that are to be used to link an application that has been compiled for a particular memory model.
Note: Currently, only libraries for the flat/small memory model are provided.
- The "Library" column specified the library name.
- The "Memory model" column indicates the compiler options that specify the memory model of the library.
- The "Floating-point column" indicates the compiler options that specify the floating-point model of the library.
- The "Calling convention" column indicates the compiler option that specifies the calling convention of the library
(register-based or stack-based).
Library Memory
Floating-point Calling
model model
convention
------------ -------- ------------------
----------
flib.lib -mf, -ms -fpc
flibs.lib -mf, -ms -fpc
-sc
flib7.lib -mf, -ms -fpi, -fpi87
flib7s.lib -mf, -ms -fpi, -fpi87
-sc
clib3r.lib -mf, -ms -fpc, -fpi, -fpi87
clib3r.lib -mf, -ms -fpc, -fpi, -fpi87
-sc
math387r.lib -mf, -ms -fpi, -fpi87
math387s.lib -mf, -ms -fpi, -fpi87
-sc
math3r.lib -mf, -ms -fpc
math3s.lib -mf, -ms -fpc
-sc
emu387.lib -mf, -ms -fpi
noemu387.lib -mf, -ms -fpi87
32-bit: Memory Layout
The following describes the segment ordering of an application linked by the Open Watcom Linker. Note that this
assumes that the "DOSSEG" linker option has been specified.
- all "USE16" segments. These segments are present in applications that execute in both real mode and protected
mode. They are first in the segment ordering so that the "REALBREAK" option of the "RUNTIME" directive
can be used to separate the real-mode part of the application from the protected-mode part of the application. Currently,
the "RUNTIME" directive is valid for Phar Lap executables only.
- all segments not belonging to group "DGROUP" with class "CODE"
- all other segments not belonging to group "DGROUP"
- all segments belonging to group "DGROUP" with class "BEGDATA"
- all segments belonging to group "DGROUP" not with class "BEGDATA", "BSS" or "STACK"
- all segments belonging to group "DGROUP" with class "BSS"
- all segments belonging to group "DGROUP" with class "STACK"
Segments belonging to class "BSS" contain uninitialized data. Note that this only includes uninitialized
data in segments belonging to group "DGROUP". Segments belonging to class "STACK" are used to define
the size of the stack used for your application. Segments belonging to the classes "BSS" and "STACK"
are last in the segment ordering so that uninitialized data need not take space in the executable file.
In addition to these special segments, the following conventions are used by Open Watcom F77.
- The "CODE" class contains the executable code for your application. In a small code model, this consists
of the segment "_TEXT". In a big code model, this consists of the segments "<subprogram>_TEXT"
where <subprogram> is the name of a subprogram.
- The "FAR_DATA" class consists of the following:
- (a)
- arrays whose size exceeds the data threshold in large data memory models (the data threshold is 256 bytes unless changed using
the "dt" compiler option)
(b)
- equivalenced variables in large data memory models
32-bit: Assembly Language Considerations
This chapter will deal with the following topics.
- The memory layout of a program compiled by Open Watcom F77.
- The method for passing arguments and returning values.
- The two methods for passing floating-point arguments and returning floating-point values.
One method is used when one of the Open Watcom F77 "fpi", "fpi87" or "fpi287" options
is specified for the generation of in-line 80x87 instructions. When the "fpi" option is specified, an 80x87
emulator is included from a math library if the application includes floating-point operations. When the "fpi87"
or "fpi287" option is used exclusively, the 80x87 emulator will not be included.
The other method is used when the Open Watcom F77 "fpc" option is specified. In this case, the compiler
generates calls to floating-point support routines in the alternate math libraries.
An understanding of the Intel 80x86 architecture is assumed.
32-bit: Calling Conventions
The following sections describe the method used by Open Watcom F77 to pass arguments.
The FORTRAN 77 language specifically requires that arguments be passed by reference. This means that instead
of passing the value of an argument, its address is passed. This allows a called subprogram to modify the value of
the actual arguments. The following illustrates the method used to pass arguments.
Type of Argument Method Used to Pass Argument
non-character
constant address of constant
non-character
expression address of value of expression
non-character
variable address of variable
character constant address of string descriptor
character
expression address of string descriptor
character variable address of string descriptor
non-character array address of array
non-character array
element address of array
character array address of string descriptor
character array
element address of string descriptor
character substring address of string descriptor
subprogram address of subprogram
alternate return
specifier no argument passed
user-defined
structure address of structure
When passing a character array as an argument, the string descriptor contains the address of the first element of
the array and the length of an element of the array.
The address of arguments are either passed in registers or on the stack. The registers used to pass the address
of arguments to a subprogram are EAX, EBX, ECX and EDX. The address of arguments are passed in the following way.
- The first argument is passed in register EAX, the second argument is passed in register EDX, the third argument is passed
in register EBX, and the fourth argument is passed in register ECX.
- For any remaining arguments, their address is passed on the stack. Note that addresses of arguments are pushed on
the stack from right to left.
32-bit: Stack-Based Calling Convention
The previous section described a register-based calling convention in which registers were used to pass arguments to subprograms.
A stack-based calling convention is another method that can be used to pass arguments. The calling convention
is selected when the "sc" compiler option is specified.
The most significant difference between the stack-based calling convention and the register-based calling convention
is the way the arguments are passed. When using the stack-based calling conventions, no registers are used to pass
arguments. Instead, all arguments are passed on the stack.
32-bit: Processing Function Return Values with no 80x87
The way in which function values are returned is also dependent on the data type of the function. The following
describes the method used to return function values.
- LOGICAL*1 values are returned in register AL.
- LOGICAL*4 values are returned in register EAX.
- INTEGER*1 values are returned in register AL.
- INTEGER*2 values are returned in register AX.
- INTEGER*4 values are returned in register EAX.
- REAL*4 values are returned in register EAX.
- REAL*8 values are returned in registers EDX:EAX.
- For COMPLEX*8 functions, space is allocated on the stack by the caller for the return value. Register ESI
is set to point to the destination of the result. The called function places the result at the location pointed to
by register ESI.
- For COMPLEX*16 functions, space is allocated on the stack by the caller for the return value. Register ESI
is set to point to the destination of the result. The called function places the result at the location pointed to
by register ESI.
- For CHARACTER functions, an additional argument is passed. This argument is the address of the string descriptor
for the result. Note that the address of the string descriptor can be passed in any of the registers that are used
to pass actual arguments.
- For functions that return a user-defined structure, space is allocated on the stack by the caller for the return value.
Register ESI is set to point to the destination of the result. The called function places the result at the location
pointed to by register ESI. Note that a structure of size 1, 2 or 4 bytes is returned in register AL, AX or EAX respectively.
Note: The way in which a function returns its value does not change when the stack-based calling
convention is used.
32-bit: Processing Function Return Values Using an 80x87
The following describes the method used to return function values when your application is compiled using the "fpi87"
or "fpi" option.
- For REAL*4 functions, the result is returned in floating-point register ST(0).
- For REAL*8 functions, the result is returned in floating-point register ST(0).
- All other function values are returned in the way described in the previous section.
Note: When the stack-based calling convention is used, floating-point values are not returned
using the 80x87. REAL*4 values are returned in register EAX. REAL*8 values are returned in registers
EDX:EAX.
32-bit: Processing Alternate Returns
Alternate returns are processed by the caller and are only allowed in subroutines. The called subroutine places
the value specified in the RETURN statement in register EAX. Note that the value returned in register
EAX is ignored if there are no alternate return specifiers in the actual argument list.
Note: The way in which a alternate returns are processed does not change when the stack-based
calling convention is used.
32-bit: Alternate Method of Passing Character Arguments
As previously described, character arguments are passed using string descriptors. Recall that a string descriptor
contains a pointer to the actual character data and the length of the character data. When passing character data,
both a pointer and length are required by the subprogram being called. When using a string descriptor, this information
can be passed using a single argument, namely the pointer to the string descriptor.
An alternate method of passing character arguments is also supported and is selected when the "nodescriptor"
option is specified. In this method, the pointer to the character data and the length of the character data are passed
as two separate arguments. The character argument lengths are appended to the end of the actual argument list.
Let us consider the following example.
INTEGER A, C
CHARACTER B, D
CALL SUB( A, B, C, D )
In the above example, the first argument is of type INTEGER, the second argument is of type CHARACTER, the third argument
is of type INTEGER, and the fourth argument is of type CHARACTER. If the character arguments were passed by descriptor,
the argument list would resemble the following.
- The first argument would be the address of A.
- The second argument would be the address of the string descriptor for B.
- The third argument would be the address of C.
- The fourth argument would be the address of the string descriptor for D.
If we specified the "nodescriptor" option, the argument list would be as follows.
- The first argument would be the address of A.
- The second argument would be the address of the character data for B.
- The third argument would be the address of C.
- The fourth argument would be the address of the character data for D.
- A hidden argument for the length of B would be the fifth argument.
- A hidden argument for the length of D would be the sixth argument.
Note that the arguments corresponding to the length of the character arguments are passed as INTEGER*4 arguments.
32-bit: Character Functions
By default, when a character function is called, a hidden argument is passed at the end of the actual argument list.
This hidden argument is a pointer to the string descriptor used for the return value of the character function. When
the alternate method of passing character arguments is specified by using the "nodescriptor" option, the string
descriptor for the return value is passed to the function as two hidden arguments, similar to the way character arguments
were passed. However the two hidden arguments for the return value of the character function are placed at the beginning
of the actual argument list. The first argument is the the pointer to the storage immediately followed by the size
of the storage.
32-bit: Writing Assembly Language Subprograms
When writing assembly language subprograms, use the following guidelines.
- All used registers must be saved on entry and restored on exit except those used to pass arguments and return values.
Note that segment registers only have to be saved and restored if you are compiling your application with the "sr"
option.
- The direction flag must be clear before returning to the caller.
- In a small code model, any segment containing executable code must belong to the segment "_TEXT" and the class
"CODE". The segment "_TEXT" must have a "combine" type of "PUBLIC". On
entry, register CS contains the segment address of the segment "_TEXT". In a big code model there is no restriction
on the naming of segments which contain executable code.
- In a small data model, segment register DS contains the segment address of the default data segment (group "DGROUP").
In a big data model, segment register SS (not DS) contains the segment address of the default data segment (group "DGROUP").
- When writing assembly language subprograms for the small code model, you must declare them as "near".
If you wish to write assembly language subprograms for the big code model, you must declare them as "far".
- Use the ".8087" pseudo-op so that floating-point constants are in the correct format.
- The called subprogram must remove arguments that were passed on the stack in the "ret" instruction.
- In general, when naming segments for your code or data, you should follow the conventions described in the section entitled
"Memory Layout" in this chapter.
Consider the following example.
INTEGER HRS, MINS, SECS, HSECS
CALL GETTIM( HRS, MINS, SECS, HSECS )
PRINT 100, HRS, MINS, SECS, HSECS
100 FORMAT( 1X,I2.2,':',I2.2,':',I2.2,'.',I2.2 )
END
GETTIM is an assembly language subroutine that gets the current time. It requires four integer arguments.
The arguments are passed by reference so that the subroutine can return the hour, minute, seconds and hundredths of
a second for the current time. These arguments will be passed to GETTIM in the following way.
- The address of the first argument will be passed in register EAX.
- The address of the second argument will be passed in register EDX.
- The address of the third argument will be passed in register EBX.
- The address of the fourth argument will be passed in register ECX.
The following is an assembly language subprogram which implements GETTIM.
Small or Flat Memory Model (small code, small data)
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public GETTIM
GETTIM proc near
push EAX
; save registers modified by
push ECX
; ... DOS function call
push EDX
; ...
mov AH,2ch
; set DOS "get time" function
int 21h
; issue DOS function call
movzx EAX,DH
; get seconds
mov [EBX],EAX
; return seconds
pop EBX
; get address of minutes
movzx EAX,CL
; get minutes
mov [EBX],EAX
; return minutes
pop EBX
; get address of ticks
movzx EAX,DL
; get ticks
mov [EBX],EAX
; return ticks
pop EBX
; get address of hours
movzx EAX,CH
; get hours
mov [EBX],EAX
; return hours
ret
; return
GETTIM endp
_TEXT ends
end
Notes:
- No arguments were passed on the stack so a simple "ret" instruction is used to return to the caller. If
a single argument was passed on the stack, a "ret 4" instruction would be required to return to the caller.
- Registers EAX, EBX, ECX and EDX were not saved and restored since they were used to pass arguments.
32-bit: Using the Stack-Based Calling Convention
When writing assembly language subprograms that use the stack-based calling convention, use the following guidelines.
- All used registers, except registers EAX, ECX and EDX must be saved on entry and restored on exit. Also, if segment
registers ES and DS are used, they must be saved on entry and restored on exit. Note that segment registers only have
to be saved and restored if you are compiling your application with the "sr" option.
- The direction flag must be clear before returning to the caller.
- In a small code model, any segment containing executable code must belong to the segment "_TEXT" and the class
"CODE". The segment "_TEXT" must have a "combine" type of "PUBLIC". On
entry, register CS contains the segment address of the segment "_TEXT". In a big code model there is no restriction
on the naming of segments which contain executable code.
- In a small data model, segment register DS contains the segment address of the default data segment (group "DGROUP").
In a big data model, segment register SS (not DS) contains the segment address of the default data segment (group "DGROUP").
- When writing assembly language subprograms for the small code model, you must declare them as "near".
If you wish to write assembly language subprograms for the big code model, you must declare them as "far".
- Use the ".8087" pseudo-op so that floating-point constants are in the correct format.
- The caller will remove arguments that were passed on the stack.
- In general, when naming segments for your code or data, you should follow the conventions described in the section entitled
"Memory Layout" in this chapter.
Consider the following example.
INTEGER HRS, MINS, SECS, HSECS
CALL GETTIM( HRS, MINS, SECS, HSECS )
PRINT 100, HRS, MINS, SECS, HSECS
100 FORMAT( 1X,I2.2,':',I2.2,':',I2.2,'.',I2.2 )
END
GETTIM is an assembly language subroutine that gets the current time. It requires four integer arguments.
The arguments are passed by reference so that the subroutine can return the hour, minute, seconds and hundredths of
a second for the current time. These arguments will be passed to GETTIM on the stack.
The following is an assembly language subprogram which implements GETTIM.
Small or Flat Memory Model (small code, small data)
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public GETTIM
GETTIM proc near
push EBP
; save registers
mov EBP,ESP
; ...
push ESI
; ...
mov AH,2ch
; set DOS "get time" function
int 21h
; issue DOS function call
movzx EAX,CH
; get hours
mov ESI,8[EBP]
; get address of hours
mov [ESI],EAX
; return hours
movzx EAX,CL
; get minutes
mov ESI,12[BP]
; get address of minutes
mov [ESI],EAX
; return minutes
movzx EAX,DH
; get seconds
mov ESI,16[BP]
; get address of seconds
mov [ESI],EAX
; return seconds
movzx EAX,DL
; get ticks
mov ESI,20[BP]
; get address of ticks
mov [ESI],EAX
; return ticks
pop ESI
; restore registers
mov ESP,EBP
; ...
pop EBP
; ...
ret
; return
GETTIM endp
_TEXT ends
end
Notes:
- The four arguments that were passed on the stack will be removed by the caller.
- Registers ESI and EBP were saved and restored since they were used in GETTIM.
Let us look at the stack upon entry to GETTIM.
Offset
0 +----------------+ <- ESP points here
| return address |
4 +----------------+
| argument #1
|
8 +----------------+
| argument #2
|
12 +----------------+
| argument #3
|
16 +----------------+
| argument #4
|
20 +----------------+
|
|
Notes:
- The top element of the stack is a the 32-bit return address. The first argument is at offset 4 from the top of the
stack, the second argument at offset 8, the third argument at offset 12, and the fourth argument at offset 16.
Register EBP is normally used to address arguments on the stack. Upon entry to the subroutine, registers that are
modified (except registers EAX, ECX and EDX) are saved and register EBP is set to point to the stack. After performing
this prologue sequence, the stack looks like this.
Offset from EBP
-4 +----------------+ <- ESP point here
| saved ESI
|
0 +----------------+ <- EBP point here
| saved EBP
|
4 +----------------+
| return address |
8 +----------------+
| argument #1
|
12 +----------------+
| argument #2
|
16 +----------------+
| argument #3
|
20 +----------------+
| argument #4
|
24 +----------------+
|
|
As the above diagram shows, the first argument is at offset 8 from register EBP, the second argument is at offset
12, the third argument is at offset 16, and the fourth argument is at offset 20.
32-bit: Returning Values from Assembly Language Functions
The following illustrates the way function values are to be returned from assembly language functions.
Note: The way in which a function returns its value does not change when the stack-based calling
convention is used.
- A LOGICAL*1 function.
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public L1
L1 proc near
mov AL,1
ret
L1 endp
_TEXT ends
end
- A LOGICAL*4 function.
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public L4
L4 proc near
mov EAX,0
ret
L4 endp
_TEXT ends
end
- An INTEGER*1 function.
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public I1
I1 proc near
mov AL,73
ret
I1 endp
_TEXT ends
end
- An INTEGER*2 function.
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public I2
I2 proc near
mov AX,7143
ret
I2 endp
_TEXT ends
end
- An INTEGER*4 function.
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public I4
I4 proc near
mov EAX,383
ret
I4 endp
_TEXT ends
end
- A REAL*4 function.
.8087
DGROUP group R4_DATA
_TEXT segment byte public 'CODE'
assume CS:_TEXT
assume DS:DGROUP
public R4
R4 proc near
mov EAX,dword
ptr R4Val
ret
R4 endp
_TEXT ends
R4_DATA segment byte public 'DATA'
R4Val dd 1314.3
R4_DATA ends
end
- A REAL*8 function.
.8087
DGROUP group R8_DATA
_TEXT segment byte public 'CODE'
assume CS:_TEXT
assume DS:DGROUP
public R8
R8 proc near
mov EAX,dword ptr
R8Val
mov EDX,dword ptr
R8Val+4
ret
R8 endp
_TEXT ends
R8_DATA segment byte public 'DATA'
R8Val dq 103.3
R8_DATA ends
end
- A COMPLEX*8 function.
.8087
DGROUP group C8_DATA
_TEXT segment byte public 'CODE'
assume CS:_TEXT
assume DS:DGROUP
public C8
C8 proc near
push EAX
mov EAX,C8Val
mov [ESI],EAX
mov EAX,C8Val+4
mov 4[ESI],EAX
pop EAX
ret
C8 endp
_TEXT ends
C8_DATA segment byte public 'DATA'
C8Val dd 2.2
dd 2.2
C8_DATA ends
end
- A COMPLEX*16 function.
.8087
DGROUP group C16_DATA
_TEXT segment byte public 'CODE'
assume CS:_TEXT
assume DS:DGROUP
public C16
C16 proc near
push EAX
mov EAX,dword ptr
C16Val
mov [ESI],EAX
mov EAX,dword
ptr C16Val+4
mov 4[ESI],EAX
mov EAX,dword ptr
C16Val+8
mov 8[ESI],EAX
mov EAX,dword
ptr C16Val+12
mov 12[ESI],EAX
pop EAX
ret
C16 endp
_TEXT ends
C16_DATA segment byte public 'DATA'
C16Val dq 3.3
dq 3.3
C16_DATA ends
end
- A CHARACTER function.
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public CHR
CHR proc near
push EAX
mov EAX,[EAX]
mov byte ptr [EAX],'F'
pop EAX
ret
CHR endp
_TEXT ends
end
Remember, if you are using stack calling conventions (i.e., you specified the "sc" compiler option), arguments
will be passed on the stack. The above character function must be modified as follows.
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public CHR
CHR proc near
push EAX
mov EAX,8[ESP]
mov EAX,[EAX]
mov byte ptr [EAX],'F'
pop EAX
ret
CHR endp
_TEXT ends
end
- A function returning a user-defined structure.
DGROUP group STRUCT_DATA
_TEXT segment byte public 'CODE'
assume CS:_TEXT
assume DS:DGROUP
public STRUCT
STRUCT proc near
push EAX
mov EAX,dword ptr
StructVal
mov [ESI],EAX
mov EAX,dword
ptr StructVal+4
mov 4[ESI],EAX
pop EAX
ret
STRUCT endp
_TEXT ends
STRUCT_DATA segment byte public 'DATA'
StructVal dd 7
dd 3
STRUCT_DATA ends
end
If you are using an 80x87 to return floating-point values, only REAL*4 and REAL*8 assembly language functions
need to be modified. Remember, this does not apply if you are using the stack-based calling convention.
- A REAL*4 function using an 80x87.
.8087
DGROUP group R4_DATA
_TEXT segment byte public 'CODE'
assume CS:_TEXT
assume DS:DGROUP
public R4
R4 proc near
fld dword ptr R4Val
ret
R4 endp
_TEXT ends
R4_DATA segment byte public 'DATA'
R4Val dd 1314.3
R4_DATA ends
end
- A REAL*8 function using an 80x87.
.8087
DGROUP group R8_DATA
_TEXT segment byte public 'CODE'
assume CS:_TEXT
assume DS:DGROUP
public R8
R8 proc near
fld qword ptr R8Val
ret
R8 endp
_TEXT ends
R8_DATA segment byte public 'DATA'
R8Val dq 103.3
R8_DATA ends
end
The following is an example of a Open Watcom F77 program calling the above assembly language subprograms.
logical l1*1, l4*4
integer i1*1, i2*2, i4*4
real r4*4, r8*8
complex c8*8, c16*16
character chr
structure /coord/
integer x, y
end structure
record /coord/ struct
print *, l1()
print *, l4()
print *, i1()
print *, i2()
print *, i4()
print *, r4()
print *, r8()
print *, c8()
print *, c16()
print *, chr()
print *, struct()
end
32-bit: Pragmas
A pragma is a compiler directive that provides the following capabilities.
- Pragmas can be used to direct the Open Watcom F77 code generator to emit specialized sequences of code for calling functions
which use argument passing and value return techniques that differ from the default used by Open Watcom F77.
- Pragmas can be used to describe attributes of functions (such as side effects) that are not possible at the FORTRAN 77
language level. The code generator can use this information to generate more efficient code.
- Any sequence of in-line machine language instructions, including DOS and BIOS function calls, can be generated in the
object code.
Pragmas are specified in the source file using the pragma directive.
The following notation is used to describe the syntax of pragmas.
- keywords
- A keyword is shown in a mono-spaced courier font.
program-item
- A program-item is shown in a roman bold-italics font. A program-item is a symbol name or
numeric value supplied by the programmer.
punctuation
- A punctuation character shown in a mono-spaced courier font must be entered as is.
A punctuation character shown in a roman bold-italics font is used to describe syntax. The following
syntactical notation is used.
- [abc]
- The item abc is optional.
{abc}
- The item abc may be repeated zero or more times.
a|b|c
- One of a, b or c may be specified.
a ::= b
- The item a is defined in terms of b.
(a)
- Item a is evaluated first.
The following classes of pragmas are supported.
- pragmas that specify default libraries
- pragmas that provide auxiliary information used for code generation
32-bit: Auxiliary Pragmas
The following sections describe the capabilities provided by auxiliary pragmas.
The backslash character ('\') is used to continue a pragma on the next line. Text following the backslash character
is ignored. The line continuing the pragma must start with a comment character ('c', 'C' or '*').
32-bit: Specifying Symbol Attributes
Auxiliary pragmas are used to describe attributes that affect code generation. Initially, the compiler defines a
default set of attributes. Each auxiliary pragma refers to one of the following.
- a symbol (such as a variable or function)
- the default set of attributes defined by the compiler
When an auxiliary pragma refers to a particular symbol, a copy of the current set of default attributes is made and merged
with the attributes specified in the auxiliary pragma. The resulting attributes are assigned to the specified symbol
and can only be changed by another auxiliary pragma that refers to the same symbol.
When "default" is specified instead of a symbol name, the attributes specified by the auxiliary pragma change
the default set of attributes. The resulting attributes are used by all symbols that have not been specifically referenced
by a previous auxiliary pragma.
Note that all auxiliary pragmas are processed before code generation begins. Consider the following example.
code in which symbol x is referenced
*$pragma aux y <attrs_1>
code in which symbol y is referenced
code in which symbol z is referenced
*$pragma aux default <attrs_2>
*$pragma aux x <attrs_3>
Auxiliary attributes are assigned to x, y and z in the following way.
- Symbol x is assigned the initial default attributes merged with the attributes specified by <attrs_2>
and <attrs_3>.
- Symbol y is assigned the initial default attributes merged with the attributes specified by <attrs_1>.
- Symbol z is assigned the initial default attributes merged with the attributes specified by <attrs_2>.
32-bit: Alias Names
When a symbol referred to by an auxiliary pragma includes an alias name, the attributes of the alias name are also assumed
by the specified symbol.
There are two methods of specifying alias information. In the first method, the symbol assumes only the attributes
of the alias name; no additional attributes can be specified. The second method is more general since it is possible
to specify an alias name as well as additional auxiliary information. In this case, the symbol assumes the attributes
of the alias name as well as the attributes specified by the additional auxiliary information.
The simple form of the auxiliary pragma used to specify an alias is as follows.
*$pragma aux ( sym, alias )
- where
- description
sym
- is any valid FORTRAN 77 identifier.
alias
- is the alias name and is any valid FORTRAN 77 identifier.
Consider the following example.
*$pragma aux value_args parm (value)
*$pragma aux ( rtn, value_args )
The routine rtn assumes the attributes of the alias name push_args which specifies that the arguments
to rtn are passed by value.
The general form of an auxiliary pragma that can be used to specify an alias is as follows.
*$pragma aux ( alias ) sym aux_attrs
- where
- description
alias
- is the alias name and is any valid FORTRAN 77 identifier.
sym
- is any valid FORTRAN 77 identifier.
aux_attrs
- are attributes that can be specified with the auxiliary pragma.
Consider the following example.
*$pragma aux WC "*_" parm (value)
*$pragma aux (WC) rtn1
*$pragma aux (WC) rtn2
*$pragma aux (WC) rtn3
The routines rtn1, rtn2 and rtn3 assume the same attributes as the alias name WC
which defines the calling convention used by the Open Watcom C compiler. Whenever calls are made to rtn1,
rtn2 and rtn3, the Open Watcom C calling convention will be used. Note that arguments must be passed
by value. By default, Open Watcom F77 passes arguments by reference.
Note that if the attributes of WC change, only one pragma needs to be changed. If we had not used an
alias name and specified the attributes in each of the three pragmas for rtn1, rtn2 and rtn3,
we would have to change all three pragmas. This approach also reduces the amount of memory required by the compiler
to process the source file.
WARNING! The alias name WC is just another symbol. If WC appeared in
your source code, it would assume the attributes specified in the pragma for WC.
32-bit: Predefined Aliases
A number of symbols are predefined by the compiler with a set of attributes that describe a particular calling convention.
These symbols can be used as aliases. The following is a list of these symbols.
- __cdecl
- __cdecl defines the calling convention used by Microsoft compilers.
__fastcall
- __fastcall defines the calling convention used by Microsoft compilers.
__fortran
- __fortran defines the calling convention used by Open Watcom FORTRAN compilers.
__pascal
- __pascal defines the calling convention used by OS/2 1.x and Windows 3.x API functions.
__stdcall
- __stdcall defines a special calling convention used by the Win32 API functions.
__syscall
- __syscall defines the calling convention used by the 32-bit OS/2 API functions.
__watcall
- __watcall defines the calling convention used by Open Watcom compilers.
The following describes the attributes of the above alias names.
32-bit: Predefined "__cdecl" Alias
*$pragma aux __cdecl "_*" \
c parm caller [] \
c value struct float struct routine
[eax] \
c modify [eax ecx edx]
Notes:
- All symbols are preceded by an underscore character.
- Arguments are pushed on the stack from right to left. That is, the last argument is pushed first. The calling
routine will remove the arguments from the stack.
- Floating-point values are returned in the same way as structures. When a structure is returned, the called routine
allocates space for the return value and returns a pointer to the return value in register EAX.
- Registers EAX, ECX and EDX are not saved and restored when a call is made.
32-bit: Predefined "__pascal" Alias
*$pragma aux __pascal "^" \
c parm reverse routine []
\
c value struct float struct caller
[] \
c modify [eax ebx ecx edx]
Notes:
- All symbols are mapped to upper case.
- Arguments are pushed on the stack in reverse order. That is, the first argument is pushed first, the second argument
is pushed next, and so on. The routine being called will remove the arguments from the stack.
- Floating-point values are returned in the same way as structures. When a structure is returned, the caller allocates
space on the stack. The address of the allocated space will be pushed on the stack immediately before the call instruction.
Upon returning from the call, register EAX will contain address of the space allocated for the return value.
- Registers EAX, EBX, ECX and EDX are not saved and restored when a call is made.
32-bit: Predefined "__stdcall" Alias
*$pragma aux __stdcall "_*@nnn" \
c parm routine [] \
c value struct struct caller
[] \
c modify [eax ecx edx]
Notes:
- All symbols are preceded by an underscore character.
- All C symbols (extern "C" symbols in C++) are suffixed by "@nnn" where "nnn" is the sum
of the argument sizes (each size is rounded up to a multiple of 4 bytes so that char and short are size 4). When the
argument list contains "...", the "@nnn" suffix is omitted.
- Arguments are pushed on the stack from right to left. That is, the last argument is pushed first. The called
routine will remove the arguments from the stack.
- When a structure is returned, the caller allocates space on the stack. The address of the allocated space will be
pushed on the stack immediately before the call instruction. Upon returning from the call, register EAX will contain
address of the space allocated for the return value. Floating-point values are returned in 80x87 register ST(0).
- Registers EAX, ECX and EDX are not saved and restored when a call is made.
32-bit: Predefined "__syscall" Alias
*$pragma aux __syscall "*" \
c parm caller [] \
c value struct struct caller
[] \
c modify [eax ecx edx]
Notes:
- Symbols names are not modified, that is, they are not adorned with leading or trailing underscores.
- Arguments are pushed on the stack from right to left. That is, the last argument is pushed first. The calling
routine will remove the arguments from the stack.
- When a structure is returned, the caller allocates space on the stack. The address of the allocated space will be
pushed on the stack immediately before the call instruction. Upon returning from the call, register EAX will contain
address of the space allocated for the return value. Floating-point values are returned in 80x87 register ST(0).
- Registers EAX, ECX and EDX are not saved and restored when a call is made.
32-bit: Predefined "__watcall" Alias (register calling convention)
*$pragma aux __watcall "*_" \
c parm routine [eax ebx ecx
edx] \
c value struct caller
Notes:
- Symbol names are followed by an underscore character.
- Arguments are processed from left to right. The leftmost arguments are passed in registers and the rightmost arguments
are passed on the stack (if the registers used for argument passing have been exhausted). Arguments that are passed
on the stack are pushed from right to left. The calling routine will remove the arguments if any were pushed on the
stack.
- When a structure is returned, the caller allocates space on the stack. The address of the allocated space is put
into ESI register. The called routine then places the return value there. Upon returning from the call, register
EAX will contain address of the space allocated for the return value.
- Floating-point values are returned using 80x86 registers ("fpc" option) or using 80x87 floating-point registers
("fpi" or "fpi87" option).
- All registers must be preserved by the called routine.
32-bit: Predefined "__watcall" Alias (stack calling convention)
*$pragma aux __watcall "*" \
c parm caller [] \
c value no8087 struct caller
\
c modify [eax ecx edx 8087]
Notes:
- All symbols appear in object form as they do in source form.
- Arguments are pushed on the stack from right to left. That is, the last argument is pushed first. The calling
routine will remove the arguments from the stack.
- When a structure is returned, the caller allocates space on the stack. The address of the allocated space will be
pushed on the stack immediately before the call instruction. Upon returning from the call, register EAX will contain
address of the space allocated for the return value.
- Floating-point values are returned only using 80x86 registers.
- Registers EAX, ECX and EDX are not preserved by the called routine.
- Any local variables that are located in the 80x87 cache are not preserved by the called routine.
32-bit: Alternate Names for Symbols
The following form of the auxiliary pragma can be used to describe the mapping of a symbol from its source form to its
object form.
*$pragma aux sym obj_name
- where
- description
sym
- is any valid FORTRAN 77 identifier.
obj_name
- is any character string enclosed in double quotes.
When specifying obj_name, some characters have a special meaning:
- where
- description
*
- is unmodified symbol name
^
- is symbol name converted to uppercase
!
- is symbol name converted to lowercase
#
- is a placeholder for "@nnn", where nnn is size of all function parameters on the stack; it is ignored for functions
with variable argument lists, or for symbols that are not functions
\
- next character is treated as literal
Several examples of source to object form symbol name translation follow: By default, the upper case version "MYRTN"
or "MYVAR" is placed in the object file.
In the following example, the name "MyRtn" will be replaced by "MYRTN_" in the object file.
*$pragma aux MyRtn "^_"
In the following example, the name "MyVar" will be replaced by "_MYVAR" in the object file.
*$pragma aux MyVar "_^"
In the following example, the lower case version "myrtn" will be placed in the object file.
*$pragma aux MyRtn "!"
In the following example, the name "MyRtn" will be replaced by "_MyRtn@nnn" in the object file.
"nnn" represents the size of all function parameters.
*$pragma aux MyRtn "_*#"
In the following example, the name "MyRtn" will be replaced by "_MyRtn#" in the object file.
*$pragma aux MyRtn "_*\#"
The default mapping for all symbols can also be changed as illustrated by the following example.
*$pragma aux default "_^_"
The above auxiliary pragma specifies that all names will be prefixed and suffixed by an underscore character ('_').
The following form of the auxiliary pragma can be used to describe the way a subprogram is to be called.
*$pragma aux sym far
or
*$pragma aux sym far16
or
*$pragma aux sym near
or
*$pragma aux sym = in_line
in_line ::= { const | "asm" }
- where
- description
sym
- is a subprogram name.
const
- is a valid FORTRAN 77 hexadecimal constant.
asm
- is an assembly language instruction or directive.
In the following example, Open Watcom F77 will generate a far call to the subprogram myrtn.
*$pragma aux myrtn far
Note that this overrides the calling sequence that would normally be generated for a particular memory model.
In other words, a far call will be generated even if you are compiling for a memory model with a small code model.
In the following example, Open Watcom F77 will generate a near call to the subprogram myrtn.
*$pragma aux myrtn near
Note that this overrides the calling sequence that would normally be generated for a particular memory model.
In other words, a near call will be generated even if you are compiling for a memory model with a big code model.
In the following DOS example, Open Watcom F77 will generate the sequence of bytes following the "=" character
in the auxiliary pragma whenever a call to mode4 is encountered. mode4 is called an in-line subprogram.
*$pragma aux mode4 = \
* zb4 z00
\ mov AH,0
* zb0 z04
\ mov AL,4
* zcd z10
\ int 10h
* modify [ ah al ]
The sequence in the above DOS example represents the following lines of assembly language instructions.
mov AH,0 ; select function "set mode"
mov AL,4 ; specify mode (mode 4)
int 10H ; BIOS video call
The above example demonstrates how to generate BIOS function calls in-line without writing an assembly language function
and calling it from your FORTRAN 77 program.
The following DOS example is equivalent to the above example but mnemonics for the assembly language instructions
are used instead of the binary encoding of the assembly language instructions.
*$pragma aux mode4 = \
* "mov AH,0"
\
* "mov AL,4"
\
* "int 10H"
\
* modify [ ah al ]
The __far16 attribute should only be used on systems that permit the calling of 16-bit code from 32-bit
code. Currently, the only supported operating system that allows this is 32-bit OS/2. If you have any libraries
of subprograms or APIs that are only available as 16-bit code and you wish to access these subprograms and APIs from 32-bit
code, you must specify the __far16 attribute. If the __far16 attribute is specified, the compiler
will generate special code which allows the 16-bit code to be called from 32-bit code. Note that a __far16
function must be a function whose attributes are those specified by one of the alias names __cdecl or __pascal.
These alias names will be described in a later section.
The file bsesub.fap in the \watcom\src\fortran\os2 directory contains examples of pragmas that use
the far16 attribute to describe the 16-bit VIO, KBD and MOU subsystems available in 32-bit OS/2.
32-bit: Loading Data Segment Register
An application may have been compiled so that the segment register DS does not contain the segment address of the default
data segment (group "DGROUP"). This is usually the case if you are using a large data memory model.
Suppose you wish to call a subprogram that assumes that the segment register DS contains the segment address of the default
data segment. It would be very cumbersome if you were forced to compile your application so that the segment register
DS contained the default data segment (a small data memory model).
The following form of the auxiliary pragma will cause the segment register DS to be loaded with the segment address
of the default data segment before calling the specified subprogram.
*$pragma aux sym parm loadds
- where
- description
sym
- is a subprogram name.
Alternatively, the following form of the auxiliary pragma will cause the segment register DS to be loaded with the segment
address of the default data segment as part of the prologue sequence for the specified subprogram.
*$pragma aux sym loadds
- where
- description
sym
- is a subprogram name.
32-bit: Defining Exported Symbols in Dynamic Link Libraries
An exported symbol in a dynamic link library is a symbol that can be referenced by an application that is linked with
that dynamic link library. Normally, symbols in dynamic link libraries are exported using the Open Watcom Linker "EXPORT"
directive. An alternative method is to use the following form of the auxiliary pragma.
*$pragma aux sym export
- where
- description
sym
- is a subprogram name.
Using auxiliary pragmas, you can describe the calling convention that Open Watcom F77 is to use for calling subprograms.
This is particularly useful when interfacing to subprograms that have been compiled by other compilers or subprograms
written in other programming languages.
The general form of an auxiliary pragma that describes argument passing is the following.
*$pragma aux sym parm { arg_info | pop_info | reverse
{reg_set} }
arg_info ::= ( arg_attr {, arg_attr}
)
arg_attr ::= value [v_attr] | reference
[r_attr] | data_reference [d_attr]
v_attr ::= far | near | *1 | *2
| *4 | *8
r_attr ::= [far | near]
[descriptor | nodescriptor]
d_attr ::= [far | near]
pop_info ::= caller | routine
- where
- description
sym
- is a subprogram name.
reg_set
- is called a register set. The register sets specify the registers that are to be used for argument passing. A
register set is a list of registers separated by spaces and enclosed in square brackets.
32-bit: Passing Arguments to non-FORTRAN Subprograms
When calling a subprogram written in a different language, it may be necessary to provide the arguments in a form different
than the default methods used by Open Watcom F77. For example, C functions require scalar arguments to be passed by
value instead of by reference. For information on the methods Open Watcom F77 uses to pass arguments, see the chapter
entitled "Assembly Language Considerations".
The following form of the auxiliary pragma can be used to alter the default calling mechanism used for passing arguments.
*$pragma aux sym parm ( arg_attr {, arg_attr}
)
arg_attr ::= value [v_attr] | reference
[r_attr] | data_reference [d_attr]
v_attr ::= far | near | *1 | *2
| *4 | *8
r_attr ::= [far | near]
[descriptor | nodescriptor]
d_attr ::= [far | near]
- where
- description
sym
- is a subprogram name.
REFERENCE
- specifies that arguments are to be passed by reference. For non-character arguments, the address is a pointer to the
data. For character arguments, the address is a pointer to a string descriptor. See the chapter entitled "Assembly
Language Considerations" for a description of a string descriptor. This is the default calling mechanism.
If "NEAR" or "FAR" is specified, a near pointer or far pointer is passed regardless of the memory model
used at compile-time.
If the "DESCRIPTOR" attribute is specified, a pointer to the string descriptor is passed. This is the
default. If the "NODESCRIPTOR" attribute is specified, a pointer to the the actual character data is passed
instead of a pointer to the string descriptor.
DATA_REFERENCE
- specifies that arguments are to be passed by data reference. For non-character items, this is identical to passing by
reference. For character items, a pointer to the actual character data (instead of the string descriptor) is passed.
If "NEAR" or "FAR" is specified, a near pointer or far pointer is passed regardless of the memory
model used at compile-time.
VALUE
- specifies that arguments are to be passed by value. Character arguments are treated specially when passed by value.
Instead of passing a pointer to a string descriptor, a pointer to the actual character data is passed. See the
chapter entitled "Assembly Language Considerations" for a description of a string descriptor.
Notes:
- Arrays and subprograms are always passed by reference, regardless of the argument attribute specified.
- When character arguments are passed by reference, the address of a string descriptor is passed. The string descriptor
contains the address of the actual character data and the number of characters. When character arguments are passed
by value or data reference, the address of the actual character data is passed instead of the address of a string descriptor.
Character arguments are passed by value by specifying the "VALUE" or "DATA_REFERENCE" attribute.
If "NEAR" or "FAR" is specified, a near pointer or far pointer to the character data is passed
regardless of the memory model used at compile-time.
- When complex arguments are passed by value, the real part and the imaginary part are passed as two separate arguments.
- When an argument is a user-defined structure and is passed by value, a copy of the structure is made and passed as an
argument.
- For scalar arguments, arguments of type INTEGER*1, INTEGER*2, INTEGER*4 ct , REAL or DOUBLE
PRECISION, a length specification can be specified when the "VALUE" attribute is specified to pass the argument
by value. This length specification refers to the size of the argument; the compiler will convert the actual argument
to a type that matches the size. For example, if an argument of type REAL is passed to a subprogram that has
an argument attribute of "VALUE*8", the argument will be converted to DOUBLE PRECISION. If an argument
of type DOUBLE PRECISION is passed to a subprogram that has an argument attribute of "VALUE*4", the argument
will be converted to REAL. If an argument of type INTEGER*4 is passed to a subprogram that has an argument
attribute of "VALUE*2" or VALUE*1, the argument will be converted to INTEGER*2 or INTEGER*1.
If an argument of type INTEGER*2 is passed to a subprogram that has an argument attribute of "VALUE*4 or VALUE*1",
the argument will be converted to INTEGER*4 or INTEGER*1. If an argument of type INTEGER*1 is
passed to a subprogram that has an argument attribute of "VALUE*4 or VALUE*2", the argument will be converted to
INTEGER*4 or INTEGER*2.
- If the number of arguments exceeds the number of entries in the argument-attribute list, the last attribute will be assumed
for the remaining arguments.
Consider the following example.
*$pragma aux printf "*_" parm (value) caller []
character cr/z0d/, nullchar/z00/
call printf( 'values: %ld, %ld'//cr//nullchar,
1
77, 31410 )
end
The C "printf" function is called with three arguments. The first argument is of type CHARACTER
and is passed as a C string (address of actual data terminated by a null character). The second and third arguments
are passed by value. Also note that "printf" is a function that takes a variable number of arguments, all
passed on the stack (an empty register set was specified), and that the caller must remove the arguments from the stack.
32-bit: Passing Arguments in Registers
The following form of the auxiliary pragma can be used to specify the registers that are to be used to pass arguments
to a particular subprogram.
*$pragma aux sym parm {reg_set}
- where
- description
sym
- is a subprogram name.
reg_set
- is called a register set. The register sets specify the registers that are to be used for argument passing. A
register set is a list of registers separated by spaces and enclosed in square brackets.
Register sets establish a priority for register allocation during argument list processing. Register sets are processed
from left to right. However, within a register set, registers are chosen in any order. Once all register sets
have been processed, any remaining arguments are pushed on the stack.
Note that regardless of the register sets specified, only certain combinations of registers will be selected for arguments
of a particular type.
Note that arguments of type REAL and DOUBLE PRECISION are always pushed on the stack when the "fpi"
or "fpi87" option is used.
- DOUBLE PRECISION
- Arguments of type DOUBLE PRECISION, when passed by value, can only be passed in one of the following register pairs:
EDX:EAX, ECX:EBX, ECX:EAX, ECX:ESI, EDX:EBX, EDI:EAX, ECX:EDI, EDX:ESI, EDI:EBX, ESI:EAX, ECX:EDX, EDX:EDI, EDI:ESI,
ESI:EBX or EBX:EAX. For example, if the following register set was specified for a routine having an argument of type
DOUBLE PRECISION,
[ebp ebx]
the argument would be pushed on the stack since a valid register combination for 8-byte arguments is not contained
in the register set. Note that this method for passing arguments of type DOUBLE PRECISION is supported only
when the "fpc" option is used. Note that this argument passing method does not include arguments of type
COMPLEX*8 or user-defined structures whose size is 8 bytes when these arguments are passed by value.
far pointer
- A far pointer can only be passed in one of the following register pairs: DX:EAX, CX:EBX, CX:EAX, CX:ESI, DX:EBX, DI:EAX,
CX:EDI, DX:ESI, DI:EBX, SI:EAX, CX:EDX, DX:EDI, DI:ESI, SI:EBX, BX:EAX, FS:ECX, FS:EDX, FS:EDI, FS:ESI, FS:EBX, FS:EAX, GS:ECX,
GS:EDX, GS:EDI, GS:ESI, GS:EBX, GS:EAX, DS:ECX, DS:EDX, DS:EDI, DS:ESI, DS:EBX, DS:EAX, ES:ECX, ES:EDX, ES:EDI, ES:ESI, ES:EBX
or ES:EAX. For example, if a far pointer is passed to a function with the following register set,
[es ebp]
the argument would be pushed on the stack since a valid register combination for a far pointer is not contained in
the register set. Far pointers are used to pass arguments by reference in a big data memory model.
INTEGER
- The only registers that will be assigned to 4-byte arguments (e.g., arguments of type INTEGER when passed by value
or arguments passed by reference in a small data memory model) are: EAX, EBX, ECX, EDX, ESI and EDI. For example,
if the following register set was specified for a routine with one argument of type INTEGER,
[ebp]
the argument would be pushed on the stack since a valid register combination for 4-byte arguments is not contained
in the register set. Note that this argument passing method also includes arguments of type REAL but only when
the "fpc" option is used.
INTEGER*1, INTEGER*2
- Arguments whose size is 1 byte or 2 bytes (e.g., arguments of type INTEGER*1 and INTEGER*2 as well as 2-byte
structures when passed by value) are promoted to 4 bytes and are then assigned registers as if they were 4-byte arguments.
others
- Arguments that do not fall into one of the above categories cannot be passed in registers and are pushed on the stack.
Once an argument has been assigned a position on the stack, all remaining arguments will be assigned a position on the stack
even if all register sets have not yet been exhausted.
Notes:
- The default register set is [eax ebx ecx edx].
- Specifying registers AH and AL is equivalent to specifying register AX. Specifying registers DH and DL is equivalent
to specifying register DX. Specifying registers CH and CL is equivalent to specifying register CX. Specifying
registers BH and BL is equivalent to specifying register BX. Specifying register EAX implies that register AX has been
specified. Specifying register EBX implies that register BX has been specified. Specifying register ECX implies
that register CX has been specified. Specifying register EDX implies that register DX has been specified. Specifying
register EDI implies that register DI has been specified. Specifying register ESI implies that register SI has been
specified. Specifying register EBP implies that register BP has been specified. Specifying register ESP implies
that register SP has been specified.
- If you are compiling for a memory model with a small data model, any register combination containing register DS becomes
illegal. In a small data model, segment register DS must remain unchanged as it points to the program's data segment.
- If you are compiling for the flat memory model, any register combination containing DS or ES becomes illegal. In
a flat memory model, code and data reside in the same segment. Segment registers DS and ES point to this segment and
must remain unchanged.
Consider the following example.
*$pragma aux myrtn parm (value) \
*
[eax ebx ecx edx] [ebp esi]
Suppose myrtn is a routine with 3 arguments each of type DOUBLE PRECISION. Note that the arguments
are passed by value.
- The first argument will be passed in the register pair EDX:EAX.
- The second argument will be passed in the register pair ECX:EBX.
- The third argument will be pushed on the stack since EBP:ESI is not a valid register pair for arguments of type DOUBLE
PRECISION.
It is possible for registers from the second register set to be used before registers from the first register set are
used. Consider the following example.
*$pragma aux myrtn parm (value) \
*
[eax ebx ecx edx] [esi edi]
Suppose myrtn is a routine with 3 arguments, the first of type INTEGER and the second and third of
type DOUBLE PRECISION. Note that all arguments are passed by value.
- The first argument will be passed in the register EAX.
- The second argument will be passed in the register pair ECX:EBX.
- The third argument will be passed in the register set EDI:ESI.
Note that registers are no longer selected from a register set after registers are selected from subsequent register sets,
even if all registers from the original register set have not been exhausted.
An empty register set is permitted. All subsequent register sets appearing after an empty register set are ignored;
all remaining arguments are pushed on the stack.
Notes:
- If a single empty register set is specified, all arguments are passed on the stack.
- If no register set is specified, the default register set [eax ebx ecx edx] is used.
32-bit: Forcing Arguments into Specific Registers
It is possible to force arguments into specific registers. Suppose you have a subprogram, say "mycopy",
that copies data. The first argument is the source, the second argument is the destination, and the third argument
is the length to copy. If we want the first argument to be passed in the register ESI, the second argument to be passed
in register EDI and the third argument to be passed in register ECX, the following auxiliary pragma can be used.
*$pragma aux mycopy parm (value) \
*
[esi] [edi] [ecx]
character*10 dst
call mycopy( dst, '0123456789', 10 )
...
end
Note that you must be aware of the size of the arguments to ensure that the arguments get passed in the appropriate
registers.
32-bit: Passing Arguments to In-Line Subprograms
For subprograms whose code is generated by Open Watcom F77 and whose argument list is described by an auxiliary pragma,
Open Watcom F77 has some freedom in choosing how arguments are assigned to registers. Since the code for in-line subprograms
is specified by the programmer, the description of the argument list must be very explicit. To achieve this, Open Watcom
F77 assumes that each register set corresponds to an argument. Consider the following DOS example of an in-line subprogram
called scrollactivepgup.
*$pragma aux scrollactivepgup = \
* "mov AH,6" \
* "int 10h" \
* parm (value) \
* [ch] [cl] [dh] [dl]
[al] [bh] \
* modify [ah]
The BIOS video call to scroll the active page up requires the following arguments.
- The row and column of the upper left corner of the scroll window is passed in registers CH and CL respectively.
- The row and column of the lower right corner of the scroll window is passed in registers DH and DL respectively.
- The number of lines blanked at the bottom of the window is passed in register AL.
- The attribute to be used on the blank lines is passed in register BH.
When passing arguments, Open Watcom F77 will convert the argument so that it fits in the register(s) specified in the
register set for that argument. For example, in the above example, if the first argument to scrollactivepgup
was called with an argument whose type was INTEGER, it would first be converted to INTEGER*1 before assigning
it to register CH. Similarly, if an in-line subprogram required its argument in register EAX and the argument was of
type INTEGER*2, the argument would be converted to INTEGER*4 before assigning it to register EAX.
In general, Open Watcom F77 assigns the following types to register sets.
- A register set consisting of a single 8-bit register (1 byte) is assigned a type of INTEGER*1.
- A register set consisting of a single 16-bit register (2 bytes) is assigned a type of INTEGER*2.
- A register set consisting of a single 32-bit register (4 bytes) is assigned a type of INTEGER*4.
- A register set consisting of two 32-bit registers (8 bytes) is assigned a type of DOUBLE PRECISION.
If the size of an integer argument is larger than the size specified by the register set, the argument will be truncated
to the required size. If the size of an integer argument is smaller than the size specified by the register set, the
argument will be padded (to the left) with zeros.
32-bit: Removing Arguments from the Stack
The following form of the auxiliary pragma specifies who removes from the stack arguments that were pushed on the stack.
*$pragma aux sym parm (caller | routine)
- where
- description
sym
- is a subprogram name.
"caller" specifies that the caller will pop the arguments from the stack; "routine" specifies that
the called routine will pop the arguments from the stack. If "caller" or "routine" is omitted,
"routine" is assumed unless the default has been changed in a previous auxiliary pragma, in which case the new
default is assumed.
Consider the following example. It describes the pragma required to call the C "printf" function.
*$pragma aux printf "*_" parm (value) caller []
character cr/z0d/, nullchar/z00/
call printf( 'value is %ld'//cr//nullchar,
1
7143 )
end
The first argument must be passed as a C string, a pointer to the actual character data terminated by a null character.
By default, the address of a string descriptor is passed for arguments of type CHARACTER. See the chapter
entitled "Assembly Language Considerations" for more information on string descriptors. The second argument
is of type INTEGER and is passed by value. Also note that "printf" is a function that takes a variable
number of arguments, all pushed on the stack (an empty register set was specified).
32-bit: Passing Arguments in Reverse Order
The following form of the auxiliary pragma specifies that arguments are passed in the reverse order.
*$pragma aux sym parm reverse
- where
- description
sym
- is a subprogram name.
Normally, arguments are processed from left to right. The leftmost arguments are passed in registers and the rightmost
arguments are passed on the stack (if the registers used for argument passing have been exhausted). Arguments that
are passed on the stack are pushed from right to left.
When arguments are reversed, the rightmost arguments are passed in registers and the leftmost arguments are passed
on the stack (if the registers used for argument passing have been exhausted). Arguments that are passed on the stack
are pushed from left to right.
Reversing arguments is most useful for subprograms that require arguments to be passed on the stack in an order opposite
from the default. The following auxiliary pragma demonstrates such a subprogram.
*$pragma aux rtn parm reverse []
Using auxiliary pragmas, you can describe the way functions are to return values. This is particularly useful when
interfacing to functions that have been compiled by other compilers or functions written in other programming languages.
The general form of an auxiliary pragma that describes the way a function returns its value is the following.
*$pragma aux sym value {no8087 | reg_set
| struct_info}
struct_info ::= struct {float | struct |
(routine | caller) | reg_set}
- where
- description
sym
- is a function name.
reg_set
- is called a register set. The register sets specify the registers that are to be used for argument passing. A
register set is a list of registers separated by spaces and enclosed in square brackets.
32-bit: Returning Subprogram Values in Registers
The following form of the auxiliary pragma can be used to specify the registers that are to be used to return a function's
value.
*$pragma aux sym value reg_set
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set.
Note that the method described below for returning values of type REAL or DOUBLE PRECISION is supported
only when the "fpc" option is used.
Depending on the type of the return value, only certain registers are allowed in reg_set.
- 1-byte
- For 1-byte return values, only the following registers are allowed: AL, AH, DL, DH, BL, BH, CL or CH. If no register
set is specified, register AL will be used.
2-byte
- For 2-byte return values, only the following registers are allowed: AX, DX, BX, CX, SI or DI. If no register set
is specified, register AX will be used.
4-byte
- For 4-byte return values (including near pointers), only the following register are allowed: EAX, EDX, EBX, ECX, ESI
or EDI. If no register set is specified, register EAX will be used. This form of the auxiliary pragma is legal
for functions of type REAL when using the "fpc" option only.
far pointer
- For functions that return far pointers, the following register pairs are allowed: DX:EAX, CX:EBX, CX:EAX, CX:ESI, DX:EBX,
DI:EAX, CX:EDI, DX:ESI, DI:EBX, SI:EAX, CX:EDX, DX:EDI, DI:ESI, SI:EBX, BX:EAX, FS:ECX, FS:EDX, FS:EDI, FS:ESI, FS:EBX, FS:EAX,
GS:ECX, GS:EDX, GS:EDI, GS:ESI, GS:EBX, GS:EAX, DS:ECX, DS:EDX, DS:EDI, DS:ESI, DS:EBX, DS:EAX, ES:ECX, ES:EDX, ES:EDI, ES:ESI,
ES:EBX or ES:EAX. If no register set is specified, the registers DX:EAX will be used.
8-byte
- For 8-byte return values (including functions of type DOUBLE PRECISION), only the following register pairs are allowed:
EDX:EAX, ECX:EBX, ECX:EAX, ECX:ESI, EDX:EBX, EDI:EAX, ECX:EDI, EDX:ESI, EDI:EBX, ESI:EAX, ECX:EDX, EDX:EDI, EDI:ESI,
ESI:EBX or EBX:EAX. If no register set is specified, the registers EDX:EAX will be used. This form of the auxiliary
pragma is legal for functions of type DOUBLE PRECISION when using the "fpc" option only.
Notes:
- An empty register set is not allowed.
- If you are compiling for a memory model which has a small data model, any of the above register combinations containing
register DS becomes illegal. In a small data model, segment register DS must remain unchanged as it points to the program's
data segment.
- If you are compiling for the flat memory model, any register combination containing DS or ES becomes illegal. In
a flat memory model, code and data reside in the same segment. Segment registers DS and ES point to this segment and
must remain unchanged.
32-bit: Returning Structures and Complex Numbers
Typically, structures and complex numbers are not returned in registers. Instead, the caller allocates space on
the stack for the return value and sets register ESI to point to it. The called routine then places the return value
at the location pointed to by register ESI.
Complex numbers are not scalars but rather an ordered pair of real numbers. One can also view complex numbers
as a structure containing two real numbers.
The following form of the auxiliary pragma can be used to specify the register that is to be used to point to the
return value.
*$pragma aux sym value struct (caller | routine)
reg_set
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set.
"caller" specifies that the caller will allocate memory for the return value. The address of the memory
allocated for the return value is placed in the register specified in the register set by the caller before the function
is called. If an empty register set is specified, the address of the memory allocated for the return value will be
pushed on the stack immediately before the call and will be returned in register EAX by the called routine.
"routine" specifies that the called routine will allocate memory for the return value. Upon returning
to the caller, the register specified in the register set will contain the address of the return value. An empty register
set is not allowed.
Only the following registers are allowed in the register set: EAX, EDX, EBX, ECX, ESI or EDI. Note that
in a big data model, the address in the return register is assumed to be in the segment specified by the value in the SS
segment register.
If the size of the structure being returned is 1, 2 or 4 bytes, it will be returned in registers. The return
register will be selected from the register set in the following way.
- A 1-byte structure will be returned in one of the following registers: AL, AH, DL, DH, BL, BH, CL or CH. If
no register set is specified, register AL will be used.
- A 2-byte structure will be returned in one of the following registers: AX, DX, BX, CX, SI or DI. If no register
set is specified, register AX will be used.
- A 4-byte structure will be returned in one of the following registers: EAX, EDX, EBX, ECX, ESI or EDI. If
no register set is specified, register EAX will be used.
The following form of the auxiliary pragma can be used to specify that structures whose size is 1, 2 or 4 bytes are not
to be returned in registers. Instead, the caller will allocate space on the stack for the structure return value and
point register ESI to it.
*$pragma aux sym value struct struct
- where
- description
sym
- is a subprogram name.
32-bit: Returning Floating-Point Data
There are a few ways available for specifying how the value for a function whose type is REAL or DOUBLE PRECISION
is to be returned.
The following form of the auxiliary pragma can be used to specify that function return values whose type is REAL
or DOUBLE PRECISION are not to be returned in registers. Instead, the caller will allocate space on the stack
for the return value and point register ESI to it.
*$pragma aux sym value struct float
- where
- description
sym
- is a function name.
In other words, floating-point values are to be returned in the same way complex numbers are returned.
The following form of the auxiliary pragma can be used to specify that function return values whose type is REAL
or DOUBLE PRECISION are not to be returned in 80x87 registers when compiling with the "fpi" or "fpi87"
option. Instead, the value will be returned in 80x86 registers. This is the default behaviour for the "fpc"
option. Function return values whose type is REAL will be returned in register EAX. Function return values
whose type is DOUBLE PRECISION will be returned in registers EDX:EAX. This is the default method for the "fpc"
option.
*$pragma aux sym value no8087
- where
- description
sym
- is a function name.
The following form of the auxiliary pragma can be used to specify that function return values whose type is REAL
or DOUBLE PRECISION are to be returned in ST(0) when compiling with the "fpi" or "fpi87" option.
This form of the auxiliary pragma is not legal for the "fpc" option.
*$pragma aux sym value [8087]
- where
- description
sym
- is a function name.
32-bit: A Subprogram that Never Returns
The following form of the auxiliary pragma can be used to describe a subprogram that does not return to the caller.
*$pragma aux sym aborts
- where
- description
sym
- is a subprogram name.
Consider the following example.
*$pragma aux exitrtn aborts
...
call exitrtn()
end
exitrtn is defined to be a function that does not return. For example, it may call exit to
return to the system. In this case, Open Watcom F77 generates a "jmp" instruction instead of a "call"
instruction to invoke exitrtn.
32-bit: Describing How Subprograms Use Variables in Common
The following form of the auxiliary pragma can be used to describe a subprogram that does not modify any variable that
appears in a common block defined by the caller.
*$pragma aux sym modify nomemory
- where
- description
sym
- is a subprogram name.
Consider the following example.
integer i
common /blk/ i
while( i .lt. 1000 )do
i = i + 383
endwhile
call myrtn()
i = i + 13143
end
block data
common /blk/ i
integer i/1033/
end
To compile the above program, "rtn.for", we issue the following command.
C>wfc rtn -mm -d1
C>wfc386 rtn -d1
The "d1" compiler option is specified so that the object file produced by Open Watcom F77 contains source
line information.
We can generate a file containing a disassembly of rtn.obj by issuing the following command.
C>wdis rtn -l -s -r
The "s" option is specified so that the listing file produced by the Open Watcom Disassembler contains source
lines taken from rtn.for. The listing file rtn.lst appears as follows.
Module: rtn.for
Group: 'DGROUP' _DATA,LDATA,CDATA,BLK
Segment: 'FMAIN_TEXT' BYTE USE32 00000036 bytes
integer i
common /blk/ i
0000 52
FMAIN push edx
0001 8b 15 00 00 00 00
mov edx,L3
while( i .lt. 1000 )do
0007 81 fa e8 03 00 00 L1
cmp edx,000003e8H
000d 7d 08
jge
L2
i = i + 383
endwhile
000f 81 c2 7f 01 00 00
add edx,0000017fH
0015 eb f0
jmp
L1
call myrtn()
0017 89 15 00 00 00 00 L2
mov L3,edx
001d e8 00 00 00 00
call MYRTN
0022 8b 15 00 00 00 00
mov edx,L3
i = i + 13143
0028 81 c2 57 33 00 00
add edx,00003357H
002e 89 15 00 00 00 00
mov L3,edx
end
block data
common /blk/ i
integer i/1033/
end
0034 5a
pop
edx
0035 c3
ret
No disassembly errors
List of external symbols
Symbol
----------------
MYRTN 0000001e
------------------------------------------------------------
Segment: 'BLK' PARA USE32 00000004 bytes
0000 09 04 00 00
L3 - ....
No disassembly errors
------------------------------------------------------------
List of public symbols
SYMBOL GROUP
SEGMENT ADDRESS
---------------------------------------------------------
FMAIN
FMAIN_TEXT 00000000
------------------------------------------------------------
Let us add the following auxiliary pragma to the source file.
*$pragma aux myrtn modify nomemory
If we compile the source file with the above pragma and disassemble the object file using the Open Watcom Disassembler,
we get the following listing file.
Module: rtn.for
Group: 'DGROUP' _DATA,LDATA,CDATA,BLK
Segment: 'FMAIN_TEXT' BYTE USE32 00000030 bytes
*$pragma aux myrtn modify nomemory
integer i
common /blk/ i
0000 52
FMAIN push edx
0001 8b 15 00 00 00 00
mov edx,L3
while( i .lt. 1000 )do
0007 81 fa e8 03 00 00 L1
cmp edx,000003e8H
000d 7d 08
jge
L2
i = i + 383
endwhile
000f 81 c2 7f 01 00 00
add edx,0000017fH
0015 eb f0
jmp
L1
call myrtn()
0017 89 15 00 00 00 00 L2
mov L3,edx
001d e8 00 00 00 00
call MYRTN
i = i + 13143
0022 81 c2 57 33 00 00
add edx,00003357H
0028 89 15 00 00 00 00
mov L3,edx
end
block data
common /blk/ i
integer i/1033/
end
002e 5a
pop
edx
002f c3
ret
No disassembly errors
List of external symbols
Symbol
----------------
MYRTN 0000001e
------------------------------------------------------------
Segment: 'BLK' PARA USE32 00000004 bytes
0000 09 04 00 00
L3 - ....
No disassembly errors
------------------------------------------------------------
List of public symbols
SYMBOL GROUP
SEGMENT ADDRESS
---------------------------------------------------------
FMAIN
FMAIN_TEXT 00000000
------------------------------------------------------------
Notice that the value of i is in register EDX after completion of the "while" loop. After
the call to myrtn, the value of i is not loaded from memory into a register to perform the final addition.
The auxiliary pragma informs the compiler that myrtn does not modify any variable that appears in a common
block defined by Rtn and hence register EDX contains the correct value of i.
The preceding auxiliary pragma deals with routines that modify variables in common. Let us consider the case
where routines reference variables in common. The following form of the auxiliary pragma can be used to describe a
subprogram that does not reference any variable that appears in a common block defined by the caller.
*$pragma aux sym parm nomemory modify nomemory
- where
- description
sym
- is a subprogram name.
Notes:
- You must specify both "parm nomemory" and "modify nomemory".
Let us replace the auxiliary pragma in the above example with the following auxiliary pragma.
*$pragma aux myrtn parm nomemory modify nomemory
If you now compile our source file and disassemble the object file using WDIS, the result is the following listing
file.
Module: rtn.for
Group: 'DGROUP' _DATA,LDATA,CDATA,BLK
Segment: 'FMAIN_TEXT' BYTE USE32 0000002a bytes
*$pragma aux myrtn parm nomemory modify nomemory
integer i
common /blk/ i
0000 52
FMAIN push edx
0001 8b 15 00 00 00 00
mov edx,L3
while( i .lt. 1000 )do
0007 81 fa e8 03 00 00 L1
cmp edx,000003e8H
000d 7d 08
jge
L2
i = i + 383
endwhile
000f 81 c2 7f 01 00 00
add edx,0000017fH
0015 eb f0
jmp
L1
call myrtn()
0017 e8 00 00 00 00 L2
call MYRTN
i = i + 13143
001c 81 c2 57 33 00 00
add edx,00003357H
0022 89 15 00 00 00 00
mov L3,edx
end
block data
common /blk/ i
integer i/1033/
end
0028 5a
pop
edx
0029 c3
ret
No disassembly errors
List of external symbols
Symbol
----------------
MYRTN 00000018
------------------------------------------------------------
Segment: 'BLK' PARA USE32 00000004 bytes
0000 09 04 00 00
L3 - ....
No disassembly errors
------------------------------------------------------------
List of public symbols
SYMBOL GROUP
SEGMENT ADDRESS
---------------------------------------------------------
FMAIN
FMAIN_TEXT 00000000
------------------------------------------------------------
Notice that after completion of the "while" loop we did not have to update i with the value in
register EDX before calling myrtn. The auxiliary pragma informs the compiler that myrtn does not
reference any variable that appears in a common block defined by myrtn so updating i was not necessary
before calling myrtn.
32-bit: Describing the Registers Modified by a Subprogram
The following form of the auxiliary pragma can be used to describe the registers that a subprogram will use without saving.
*$pragma aux sym modify [exact] reg_set
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set.
Specifying a register set informs Open Watcom F77 that the registers belonging to the register set are modified by the
subprogram. That is, the value in a register before calling the subprogram is different from its value after execution
of the subprogram.
Registers that are used to pass arguments are assumed to be modified and hence do not have to be saved and restored
by the called subprogram. Also, since the EAX register is frequently used to return a value, it is always assumed to
be modified. If necessary, the caller will contain code to save and restore the contents of registers used to pass
arguments. Note that saving and restoring the contents of these registers may not be necessary if the called subprogram
does not modify them. The following form of the auxiliary pragma can be used to describe exactly those registers that
will be modified by the called subprogram.
*$pragma aux sym modify exact reg_set
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set.
The above form of the auxiliary pragma tells Open Watcom F77 not to assume that the registers used to pass arguments will
be modified by the called subprogram. Instead, only the registers specified in the register set will be modified.
This will prevent generation of the code which unnecessarily saves and restores the contents of the registers used to pass
arguments.
Also, any registers that are specified in the value register set are assumed to be unmodified unless explicitly
listed in the exact register set. In the following example, the code generator will not generate code to save
and restore the value of the stack pointer register since we have told it that "GetSP" does not modify any register
whatsoever.
Example:
*$ifdef __386__
*$pragma aux GetSP = value [esp] modify exact []
*$else
*$pragma aux GetSP = value [sp] modify exact []
*$endif
program main
integer GetSP
print *, 'Current SP =', GetSP()
end
32-bit: Auxiliary Pragmas and the 80x87
This section deals with those aspects of auxiliary pragmas that are specific to the 80x87. The discussion in this
chapter assumes that one of the "fpi" or "fpi87" options is used to compile subprograms. The following
areas are affected by the use of these options.
- passing floating-point arguments to functions,
- returning floating-point values from functions and
- which 80x87 floating-point registers are allowed to be modified by the called routine.
32-bit: Using the 80x87 to Pass Arguments
By default, floating-point arguments are passed on the 80x86 stack. The 80x86 registers are never used to pass floating-point
arguments when a subprogram is compiled with the "fpi" or "fpi87" option. However, they can be
used to pass arguments whose type is not floating-point such as arguments of type "int".
The following form of the auxiliary pragma can be used to describe the registers that are to be used to pass arguments
to subprograms.
*$pragma aux sym parm {reg_set}
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set. The register set can contain 80x86 registers and/or the string "8087".
Notes:
- If an empty register set is specified, all arguments, including floating-point arguments, will be passed on the 80x86
stack.
When the string "8087" appears in a register set, it simply means that floating-point arguments can be passed
in 80x87 floating-point registers if the source file is compiled with the "fpi" or "fpi87" option.
Before discussing argument passing in detail, some general notes on the use of the 80x87 floating-point registers are given.
The 80x87 contains 8 floating-point registers which essentially form a stack. The stack pointer is called ST
and is a number between 0 and 7 identifying which 80x87 floating-point register is at the top of the stack. ST is initially
0. 80x87 instructions reference these registers by specifying a floating-point register number. This number is
then added to the current value of ST. The sum (taken modulo 8) specifies the 80x87 floating-point register to be used.
The notation ST(n), where "n" is between 0 and 7, is used to refer to the position of an 80x87 floating-point
register relative to ST.
When a floating-point value is loaded onto the 80x87 floating-point register stack, ST is decremented (modulo 8),
and the value is loaded into ST(0). When a floating-point value is stored and popped from the 80x87 floating-point
register stack, ST is incremented (modulo 8) and ST(1) becomes ST(0). The following illustrates the use of the 80x87
floating-point registers as a stack, assuming that the value of ST is 4 (4 values have been loaded onto the 80x87 floating-point
register stack).
+----------------+
0 | 4th from top
| ST(4)
+----------------+
1 | 5th from top
| ST(5)
+----------------+
2 | 6th from top
| ST(6)
+----------------+
3 | 7th from top
| ST(7)
+----------------+
ST -> 4 | top of stack | ST(0)
+----------------+
5 | 1st from top
| ST(1)
+----------------+
6 | 2nd from top
| ST(2)
+----------------+
7 | 3rd from top
| ST(3)
+----------------+
Starting with version 9.5, the Open Watcom compilers use all eight of the 80x87 registers as a stack. The initial
state of the 80x87 register stack is empty before a program begins execution.
- Note:
- For compatibility with code compiled with version 9.0 and earlier, you can compile with the "fpr" option.
In this case only four of the eight 80x87 registers are used as a stack. These four registers were used to pass arguments.
The other four registers form what was called the 80x87 cache. The cache was used for local floating-point variables.
The state of the 80x87 registers before a program began execution was as follows.
- The four 80x87 floating-point registers that form the stack are uninitialized.
- The four 80x87 floating-point registers that form the 80x87 cache are initialized with zero.
Hence, initially the 80x87 cache was comprised of ST(0), ST(1), ST(2) and ST(3). ST had the value 4 as in the above
diagram. When a floating-point value was pushed on the stack (as is the case when passing floating-point arguments),
it became ST(0) and the 80x87 cache was comprised of ST(1), ST(2), ST(3) and ST(4). When the 80x87 stack was full,
ST(0), ST(1), ST(2) and ST(3) formed the stack and ST(4), ST(5), ST(6) and ST(7) formed the 80x87 cache. Version 9.5
and later no longer use this strategy.
The rules for passing arguments are as follows.
- If the argument is not floating-point, use the procedure described earlier in this chapter.
- If the argument is floating-point, and a previous argument has been assigned a position on the 80x86 stack (instead of
the 80x87 stack), the floating-point argument is also assigned a position on the 80x86 stack. Otherwise proceed to
the next step.
- If the string "8087" appears in a register set in the pragma, and if the 80x87 stack is not full, the floating-point
argument is assigned floating-point register ST(0) (the top element of the 80x87 stack). The previous top element (if
there was one) is now in ST(1). Since arguments are pushed on the stack from right to left, the leftmost floating-point
argument will be in ST(0). Otherwise the floating-point argument is assigned a position on the 80x86 stack.
Consider the following example.
*$pragma aux myrtn parm (value) [8087]
real x
double precision y
integer i
integer j
x = 7.7
i = 7
y = 77.77
j = 77
call myrtn( x, i, y, j )
end
myrtn is an assembly language subprogram that requires four arguments. The first argument of type
REAL (4 bytes), the second argument is of type INTEGER (4 bytes), the third argument is of type DOUBLE PRECISION
(8 bytes) and the fourth argument is of type INTEGER*4 (4 bytes). These arguments will be passed to myrtn
in the following way.
- Since "8087" was specified in the register set, the first argument, being of type REAL, will be passed
in an 80x87 floating-point register.
- The second argument will be passed on the stack since no 80x86 registers were specified in the register set.
- The third argument will also be passed on the stack. Remember the following rule: once an argument is assigned
a position on the stack, all remaining arguments will be assigned a position on the stack. Note that the above rule
holds even though there are some 80x87 floating-point registers available for passing floating-point arguments.
- The fourth argument will also be passed on the stack.
Let us change the auxiliary pragma in the above example as follows.
*$pragma aux myrtn parm [eax 8087]
The arguments will now be passed to myrtn in the following way.
- Since "8087" was specified in the register set, the first argument, being of type REAL will be passed
in an 80x87 floating-point register.
- The second argument will be passed in register EAX, exhausting the set of available 80x86 registers for argument passing.
- The third argument, being of type DOUBLE PRECISION, will also be passed in an 80x87 floating-point register.
- The fourth argument will be passed on the stack since no 80x86 registers remain in the register set.
32-bit: Using the 80x87 to Return Subprogram Values
The following form of the auxiliary pragma can be used to describe a subprogram that returns a floating-point value in
ST(0).
*$pragma aux sym value reg_set
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set containing the string "8087", i.e. [8087].
32-bit: Preserving 80x87 Floating-Point Registers Across Calls
The code generator assumes that all eight 80x87 floating-point registers are available for use within a subprogram unless
the "fpr" option is used to generate backward compatible code (older Open Watcom compilers used four registers
as a cache). The following form of the auxiliary pragma specifies that the floating-point registers in the 80x87 cache
may be modified by the specified subprogram.
*$pragma aux sym modify reg_set
- where
- description
sym
- is a subprogram name.
reg_set
- is a register set containing the string "8087", i.e. [8087].
This instructs Open Watcom F77 to save any local variables that are located in the 80x87 cache before calling the specified
routine.
Use of Environment Variables
In the Open Watcom FORTRAN 77 software development package, a number of environment variables are used. This
appendix summarizes their use with a particular component of the package.
FINCLUDE
The FINCLUDE environment variable describes the location of the Open Watcom FORTRAN 77 include files. This
variable is used by Open Watcom FORTRAN 77.
SET FINCLUDE=[d:][path];[d:][path]...
The FINCLUDE environment string is like the PATH string in that you can specify one or more directories
separated by semicolons (";").
LFN
The LFN environment variable is checked by the Open Watcom run-time C libraries and it is used to control DOS
LFN (DOS Long File Name) support. Normally, these libraries will use DOS LFN support if it is available on host OS.
If you don't wish to use DOS LFN support, you can define the LFN environment variable and setup it's value
to 'N'. Using the "SET" command, define the environment variable as follows:
SET LFN=N
Now, when you run your application, the DOS LFN support will be ignored. To undefine the environment variable,
enter the command:
SET LFN=
LIB
The use of the WATCOM environment variable and the Open Watcom Linker "SYSTEM" directive is recommended
over the use of this environment variable.
The LIB environment variable is used to select the libraries that will be used when the application is linked.
This variable is used by the Open Watcom Linker (WLINK.EXE). The LIB environment string is like the
PATH string in that you can specify one or more directories separated by semicolons (";").
If you have the 286 development system, 16-bit applications can be linked for DOS, Microsoft Windows, OS/2, and QNX
depending on which libraries are selected. If you have the 386 development system, 32-bit applications can be linked
for DOS Extender systems, Microsoft Windows and QNX.
LIBDOS
The use of the WATCOM environment variable and the Open Watcom Linker "SYSTEM" directive is recommended
over the use of this environment variable.
If you are developing a DOS application, the LIBDOS environment variable must include the location of the
16-bit Open Watcom F77 DOS library files (files with the ".lib" filename extension). This variable is used
by the Open Watcom Linker (WLINK.EXE). The default installation directory for the 16-bit Open Watcom F77 DOS libraries
is \WATCOM\LIB286\DOS.
Example:
C>set libdos=c:\watcom\lib286\dos
LIBWIN
The use of the WATCOM environment variable and the Open Watcom Linker "SYSTEM" directive is recommended
over the use of this environment variable.
If you are developing a 16-bit Microsoft Windows application, the LIBWIN environment variable must include
the location of the 16-bit Open Watcom F77 Windows library files (files with the ".lib" filename extension).
This variable is used by the Open Watcom Linker (WLINK.EXE). If you are developing a 32-bit Microsoft Windows application,
see the description of the LIBPHAR environment variable. The default installation directory for the 16-bit
Open Watcom F77 Windows libraries is \WATCOM\LIB286\WIN.
Example:
C>set libwin=c:\watcom\lib286\win
LIBOS2
The use of the WATCOM environment variable and the Open Watcom Linker "SYSTEM" directive is recommended
over the use of this environment variable.
If you are developing an OS/2 application, the LIBOS2 environment variable must include the location of the
16-bit Open Watcom F77 OS/2 library files (files with the ".lib" filename extension). This variable is used
by the Open Watcom Linker (WLINK.EXE). The default installation directory for the 16-bit Open Watcom F77 OS/2 libraries
is \WATCOM\LIB286\OS2. The LIBOS2 environment variable must also include the directory of the OS/2
DOSCALLS.LIB file which is usually \OS2.
Example:
C>set libos2=c:\watcom\lib286\os2;c:\os2
LIBPHAR
The use of the WATCOM environment variable and the Open Watcom Linker "SYSTEM" directive is recommended
over the use of this environment variable.
If you are developing a 32-bit Windows or DOS Extender application, the LIBPHAR environment variable must
include the location of the 32-bit Open Watcom F77 DOS Extender library files or the 32-bit Open Watcom F77 Windows library
files (files with the ".lib" filename extension). This variable is used by the Open Watcom Linker (WLINK.EXE).
The default installation directory for the 32-bit Open Watcom F77 DOS Extender libraries is \WATCOM\LIB386\DOS.
The default installation directory for the 32-bit Open Watcom F77 Windows libraries is \WATCOM\LIB386\WIN.
Example:
C>set libphar=c:\watcom\lib386\dos
or
C>set libphar=c:\watcom\lib386\win
NO87
The NO87 environment variable is checked by the Open Watcom FORTRAN 77 run-time libraries that include floating-point
emulation support. Normally, these libraries will detect the presence of a numeric data processor (80x87) and use it.
If you have a numeric data processor in your system but you wish to test a version of your application that will use
floating-point emulation, you can define the NO87 environment variable. Using the "SET" command,
define the environment variable as follows:
SET NO87=1
Now, when you run your application, the 80x87 will be ignored. To undefine the environment variable, enter the
command:
SET NO87=
PATH
The PATH environment variable is used by DOS "COMMAND.COM" or OS/2 "CMD.EXE" to locate programs.
PATH [d:][path];[d:][path]...
The PATH environment variable should include the disk and directory of the Open Watcom FORTRAN 77 binary program
files when using Open Watcom FORTRAN 77 and its related tools.
If your host system is DOS:
The default installation directory for 16-bit Open Watcom F77 and 32-bit Open Watcom F77 DOS binaries is called
\WATCOM\BINW.
Example:
C>path c:\watcom\binw;c:\dos;c:\windows
If your host system is OS/2:
The default installation directories for 16-bit Open Watcom F77 and 32-bit Open Watcom F77 OS/2 binaries are called
\WATCOM\BINP and \WATCOM\BINW.
Example:
[C:\]path c:\watcom\binp;c:\watcom\binw
If your host system is Windows NT:
The default installation directories for 16-bit Open Watcom F77 and 32-bit Open Watcom F77 Windows NT binaries are
called \WATCOM\BINNT and \WATCOM\BINW.
Example:
C>path c:\watcom\binnt;c:\watcom\binw
The PATH environment variable is also used by the following programs in the described manner.
- Open Watcom Compile and Link to locate the 16-bit Open Watcom F77 and 32-bit Open Watcom F77 compilers and the Open Watcom
Linker.
- "WD.EXE" to locate programs and debugger command files.
TMP
The TMP environment variable describes the location (disk and path) for temporary files created by the 16-bit
Open Watcom F77 and 32-bit Open Watcom F77 compilers and the Open Watcom Linker.
SET TMP=[d:][path]
Normally, Open Watcom FORTRAN 77 will create temporary spill files in the current directory. However, by defining
the TMP environment variable to be a certain disk and directory, you can tell Open Watcom FORTRAN 77 where to place
its temporary files. The same is true of the Open Watcom Linker temporary file.
Consider the following definition of the TMP environment variable.
Example:
C>set tmp=d:\watcom\tmp
The Open Watcom FORTRAN 77 compiler and Open Watcom Linker will create its temporary files in d:\watcom\tmp.
WATCOM
In order for the Open Watcom Linker to locate the 16-bit Open Watcom F77 and 32-bit Open Watcom F77 library files, the
WATCOM environment variable should be defined. The WATCOM environment variable is used to locate the
libraries that will be used when the application is linked. The default directory for 16-bit Open Watcom F77 and 32-bit
Open Watcom F77 files is "\WATCOM".
Example:
C>set watcom=c:\watcom
WCL
The WCL environment variable can be used to specify commonly-used WFL options.
SET WCL=-option1 -option2 ...
These options are processed before options specified on the command line. The following example defines the
default options to be "mm" (compile code for medium memory model), "d1" (include line number debug information
in the object file), and "ox" (compile for maximum number of code optimizations).
Example:
C>set wcl=-mm -d1 -ox
Once the WCL environment variable has been defined, those options listed become the default each time the
WFL command is used.
WCL386
The WCL386 environment variable can be used to specify commonly-used WFL386 options.
SET WCL386=-option1 -option2 ...
These options are processed before options specified on the command line. The following example defines the
default options to be "3s" (compile code for stack-based argument passing convention), "d1" (include
line number debug information in the object file), and "ox" (compile for maximum number of code optimizations).
Example:
C>set wcl386=-3s -d1 -ox
Once the WCL386 environment variable has been defined, those options listed become the default each time the
WFL386 command is used.
WCGMEMORY
The WCGMEMORY environment variable may be used to request a report of the amount of memory used by the compiler's
code generator for its work area.
Example:
C>set WCGMEMORY=?
When the memory amount is "?" then the code generator will report how much memory was used to generate the
code.
It may also be used to instruct the compiler's code generator to allocate a fixed amount of memory for a work area.
Example:
C>set WCGMEMORY=128
When the memory amount is "nnn" then exactly "nnnK" bytes will be used. In the above example,
128K bytes is requested. If less than "nnnK" is available then the compiler will quit with a fatal error
message. If more than "nnnK" is available then only "nnnK" will be used.
There are two reasons why this second feature may be quite useful. In general, the more memory available to
the code generator, the more optimal code it will generate. Thus, for two personal computers with different amounts
of memory, the code generator may produce different (although correct) object code. If you have a software quality
assurance requirement that the same results (i.e., code) be produced on two different machines then you should use this feature.
To generate identical code on two personal computers with different memory configurations, you must ensure that the
WCGMEMORY environment variable is set identically on both machines.
The second reason where this feature is useful is on virtual memory paging systems (e.g., OS/2) where an unlimited
amount of memory can be used by the code generator. If a very large module is being compiled, it may take a very long
time to compile it. The code generator will continue to allocate more and more memory and cause an excessive amount
of paging. By restricting the amount of memory that the code generator can use, you can reduce the amount of time required
to compile a routine.
WD
The WD environment variable can be used to specify commonly-used Open Watcom Debugger options. This environment
variable is not used by the Windows version of the debugger, WDW.
SET WD=-option1 -option2 ...
These options are processed before options specified on the command line. The following example defines the
default options to be "noinvoke" (do not execute the profile.dbg file) and "reg=10" (retain
up to 10 register sets while tracing).
Example:
C>set wd=-noinvoke -reg#10
Once the WD environment variable has been defined, those options listed become the default each time the WD
command is used.
WDW
The WDW environment variable can be used to specify commonly-used Open Watcom Debugger options. This environment
variable is used by the Windows version of the debugger, WDW.
SET WDW=-option1 -option2 ...
These options are processed before options specified in the WDW prompt dialogue box. The following example defines
the default options to be "noinvoke" (do not execute the profile.dbg file) and "reg=10" (retain
up to 10 register sets while tracing).
Example:
C>set wdw=-noinvoke -reg#10
Once the WDW environment variable has been defined, those options listed become the default each time the
WDW command is used.
WFC
The WFC environment variable can be used to specify commonly-used Open Watcom F77 options.
SET WFC=-option1 -option2 ...
These options are processed before options specified on the command line. The following example defines the
default options to be "d1" (include line number debug information in the object file) and "om" (compile
with math optimizations).
Example:
C>set wfc=-d1 -om
Once the WFC environment variable has been defined, those options listed become the default each time the
WFC command is used.
WFC386
The WFC386 environment variable can be used to specify commonly-used Open Watcom F77 options.
SET WFC386=-option1 -option2 ...
These options are processed before options specified on the command line. The following example defines the
default options to be "d1" (include line number debug information in the object file) and "om" (compile
with math optimizations).
Example:
C>set wfc386=-d1 -om
Once the WFC386 environment variable has been defined, those options listed become the default each time the
WFC386 command is used.
WFL
The WFL environment variable can be used to specify commonly-used WFL options.
SET WFL=-option1 -option2 ...
These options are processed before options specified on the command line. The following example defines the
default options to be "mm" (compile code for medium memory model), "d1" (include line number debug information
in the object file), and "ox" (default optimizations).
Example:
C>set wfl=-mm -d1 -ox
Once the WFL environment variable has been defined, those options listed become the default each time the
WFL command is used.
WFL386
The WFL386 environment variable can be used to specify commonly-used WFL386 options.
SET WFL386=-option1 -option2 ...
These options are processed before options specified on the command line. The following example defines the
default options to be "mf" (flat memory model), "d1" (include line number debug information in the object
file), and "ox" (default optimizations).
Example:
C>set wfl386=-mf -d1 -ox
Once the WFL386 environment variable has been defined, those options listed become the default each time the
WFL386 command is used.
WLANG
The WLANG environment variable can be used to control which language is used to display diagnostic and program
usage messages by various Open Watcom software tools. The two currently-supported values for this variable are "English"
or "Japanese".
SET WLANG=English
SET WLANG=Japanese
Alternatively, a numeric value of 0 (for English) or 1 (for Japanese) can be specified.
Example:
C>set wlang=0
By default, Japanese messages are displayed when the current codepage is 932 and English messages are displayed otherwise.
Normally, use of the WLANG environment variable should not be required.