HDOS System Calls
This page will document the set of system calls that make up the HDOS assembly language Application Program Interface (API). The calls will be documented as they were in the HDOS System Programmer's Guide, grouped by resident calls, HDOSOVL0 calls, and HDOSOVL1 calls. A table of scall values and a table of error code values will follow.
SCALL Pseudo Opcode
A system call (scall) consists of an RST 7 instruction followed by a one-byte code. The assembler has a special pseudo opcode for scalls:
SCALL code...where 'code' is the number of the scall request (ref. SCALL Value Tables). This statement is equivalent to:
DB 377Q,code...or...
RST 7You should build a .ACM file with the scall codes in it, or use the version included on the Extra's disk, and include that file in any assembly language program that uses HDOS system calls.
Resident Scalls
These scalls are part of the resident HDOS system; they do not require that either overlay be present in memory.
End program and return to HDOS (to COMMAND.SYS, actually).
Entry:Abort exit is not recommended.
Read one byte from the console. If the console options have not been changed, the console will be in "line mode" and your program will wait until the user presses return or enter before it starts receiving characters. You can change to character mode with the .CONSL scall and subsequently get characters as they are typed. However, you will need to handle backspace and other editing that is provided by HDOS in line mode.
Entry:Write one character to the system console.
Entry:Print a line of text on the console. The last character must have the 200Q bit set to mark the end of the string.
Entry:Read data from an open file channel. The channel can be open on a disk file or a character device (TT: or AT:).
All I/O done with .READ and .WRITE is in "block mode" with the block size being a multiple of 256 bytes. For text files, the last sector should be padded out with nulls (00H bytes).
Entry:Write data to an open file channel. The channel can be open on a disk file or a character device (TT: or AT:).
All I/O done with .READ and .WRITE is in "block mode" with the block size being a multiple of 256 bytes. For text files, the last sector should be padded out with nulls (00H bytes).
Entry:Set and clear console control bits and bytes. These bytes are available in well-known locations in memory, but use of the .CONSL call is recommended.
You supply HDOS with three values: the index of the byte to be changed, a bit mask of the bits to be changed, and a "new values" pattern. The use of a mask and a new-value pattern allows you to set or clear just one bit without having to know how the other bits are set.
There are a number of definitions that you should have in a common deck:
I.CSLMD EQU 0 Console mode byteClear console type-ahead buffer. This can be used if the user enters Ctl-C, for example, and you want to flush any type-ahead and reprint a fresh prompt for input.
Entry:Load an overlay.
You must load both overlays before dismounting the system disk. Make sure that you do this before allocating all system memory for your application.
You do not need to load the overlays before using an overlay-resident scall, however: HDOS does this for you.
Entry:Returns the HDOS version number as a one-byte BCD number. HDOS 2.0 will return the value 020H.
HDOS versions prior to 1.5 did not respond to this scall and would return 'C'. That's not going to happen with 2.0.
Entry:HDOSOVL0 Scalls
These scalls require that HDOSOVL0 be in memory. If it is not already in memory, it will need to be swapped in by HDOS with a resulting performance penalty.
If you have allocated all available RAM for your program, the top end of your memory space may have to be swapped out to load the overlay. Make sure that neither the scall nor the data areas being worked on as part of the scall are in this memory area.
Many of these calls require a file name. File names generally follow the form:
[device and unit:]name[.ext]
Names in memory must be delimited somehow so that HDOS knows where the end is. There exists no exhaustive list of valid delimeters that the author is aware of. The list does include null (0H), comma, blank, equal sign, and slash. There may well be others.
Your program can provide defaults for device and unit and for extension. This is done via a "default block." Here are two examples:
DFLTBLK DB 'SY0ASM'The first example gives a default drive of sy0: and a default extension of .ASM. The second gives a default drive of sy1: and no default extension; files which specify a name and no extension will be assumed to have a null extension.
See further examples in the scall descriptions below.
Load and execute another program.
All open files, system tables, and the stack are completely undisturbed. The value in register (A) is passed undisturbed.
If the .LINK scall is successful, the .LINK scall will be the last statement executed in the old program; the new program will begin execution at its entry point. If the .LINK scall is not successful, execution proceeds with the statement following the .LINK scall. You should include some kind of error trap in case this happens.
In the example, we're going to use the .NAME scall to get the device that we were run from, and then .LINK to a program called CLEANUP.ABS that should be found on the same device.
Entry:Set a trap to handle Ctl-A, Ctl-B and/or Ctl-C at interrupt time.
After the trap is set up, when the user types the control character, your routine is entered after HDOS handles the interrupt. Interrupts are enabled when your routine receives control.
On entry to your processing routine, registers B, C, D, E, H, and L have whatever they had in them at the time of the interrupt. The stack contains:
((SP)+0) = return address into HDOS
((SP)+2) = PSW from interrupted program
((SP)+4) = (PC) from interrupted program
There no restrictions on what you can do from here. You may do some processing and then return to HDOS, which will clean up and return to your program at the point where it was interrupted, with all registers intact. You may pop the first two words off the stack and return to your program yourself. Or you may clean up the stack and JMP to some other routine.
The example will show a trap setup for Ctl-C. It will not show a trap processing routine.
Entry:Open a file for read access. Any given file can be open for read on as many channels as you like.
Entry:Valid channel numbers are -1 through 5. -1 is a special case: when your program is first launched, channel -1 is open for read on your program file. This is so that you can use the .NAME scall to get your program name and device. In order to reuse channel -1, you will have to .CLOSE or .CLEAR it first.
Example:Open a file for write access. See .OPENR for parameters and a discussion of valid channel numbers.
.OPENW opens a file for exclusive access on one channel only. If the file exists, new space will be created for the file and the directory entry will remain undisurbed until the file is successfully closed. At that time, the old space is returned to the free pool and the new file takes it's place in the directory.
You can both read and write to a file open for write access. After writing some sectors, use the .POSIT scall to "rewind" the file to the beginning and read the file back.
If you .CLEAR a file opened for write, any sectors written will be returned to the free pool and any existing file with the same name will be preserved unchanged.
Open a file for update access. See .OPENR for parameters and a discussion of valid channel numbers.
.OPENU opens a file for exclusive access on one channel only. The file is open for both read and write access. The sector cursor is positioned before sector 0. Writes will overwrite existing data. To add to the end of the file, use .POSIT to set the sector cursor to the end and then write. Thus, you can append to an existing file by using .OPENU and .POSIT.
Be sure to close a file open for update. If you .CLEAR the file after adding to the end, those additions will be lost and the sectors will not be returned to the free pool until the next time the disk is mounted. Any changed sectors, however, will remain changed.
Close a file.
Entry:You should always close a file that you opened, with two exceptions:
HDOS enters your program with channel -1 open. If you don't use it yourself, you don't have to close it; HDOS will take care of that for you.
Scratch files that you opened with .OPENW and that you don't intend to keep can be cleared with .CLEAR to throw the file away and return its space to the free pool
Move the sector cursor to a new logical sector number.
Setting the cursor to logical sector 0 effectively "rewinds" the file to the beginning (e.g., positions the cursor before the first sector). Setting it to 5 positions the cursor before the 6th sector, etc.
To position to the end of the file, .POSIT to 'n' where 'n' is equal to the number of sectors in the file. If you don't know how many sectors there are, use -1 and verify that you got an error of EC.EOF. The sector cursor is positioned at the end of the file.
Entry:If you want to know the file size, you can .POSIT to -1 and then subtract the (BC) pair from 377377A to get the number of sectors.
Example:Delete an existing file.
Entry:Rename a file.
The new name must not already exist. Unfortunately, .RENAME doesn't check for this, so you should check by trying to .OPENR the new file name before renaming it. If you don't get an error (EC.FNF), you can't rename the file. Also, both the old and new file must be on the same disk drive.
The default block applies only to the old name. The new name must be fully specified including device and unit, name and extension.
Entry:Set the highest memory address that your program will use.
HDOS uses any free memory above your program to load overlays and device drivers. If you intend to use that memory for yourself, you have to inform HDOS or you stand a chance of having your memory overwitten.
On entry, your program top is set to the address of the last program byte loaded. If you have allocated additional space off the end of your program using DS statements, you will need to inform HDOS of that by using .SETTOP as in the first example.
To allocate all free memory to your program, use -1 to find out the highest possible address and then set that address, as shown in the second example (ref: Address Space Utilization).
Entry:In the second and third examples, we have to save MAXMEM before we set the top, as a successful .SETTOP scall will destroy the contents of the (HL) pair. Of course, we could always retrieve the value from S.USRM.
In the third example, we subtract the size of the largest overlay, kept in S.OMAX, from the maximum available memory, and set that as the top of our application space. HDOS will be able to use that area to read in either overlay without the need for swapping our space to disk. And the overlay can remain in memory, further speeding execution.
Decode a file name into its component parts. The format of the decoded file name is shown in the example below. It is also included in the version of HDOS.ACM that is included on the Extra's disk.
Entry:Return the device, unit, name and extension from an open file channel.
The file name is returned as a string of 8 characters followed by a null (0H). The device, unit and extension are returned in default block format.
Entry:Clear a file channel.
If the file was open for read access, this is the same as .CLOSE, which is the preferred way to close a file.
If the file was open for write access, the file is forgotten and any sectors written are returned to the free pool. If the file was open for update access, any sectors appended to the file will be lost until the next time the disk is mounted (ref. .OPENU). But any changed sectors remain changed.
Emulator note: If you are closing the AT: or LP: device drivers, please use .CLOSE and not .CLEAR. The driver needs to inform the emulator that the file has closed, but the driver is not notified of a .CLEAR call so it can't inform the emulator.
Entry:Print an error message on the console from the file "sy0:errormsg.sys".
If errormsg.sys is not on the sy0: drive, the error message printed will be "SYSTEM ERROR # nnn" with "nnn" replaced by the error code passed to .ERROR.
.ERROR will itself, thankfully, never return an error.
Entry:Change file flags. File flags are:
Mnemonic | Bit Value | Meaning |
DIF.SYS | 200Q | System file |
DIF.LOC | 100Q | Locked for change (can't change flags again) |
DIF.WP | 040Q | Write protected |
If you set the lock flag, the only way to clear it is to copy the file, delete the old file, and rename the new file. If you set both lock and write protect, then the file is there "forever" (until the disk volume is re-initialized).
Load a device driver into memory.
Like .LOADO, this call can't be used after the SY0: device is dismounted, so any driver not in memory when the disk is dismounted is inaccessable until the next boot.
Entry:HDOSOVL1 Scalls
These scalls require that HDOSOVL0 be in memory. If it is not already in memory, it will need to be swapped in by HDOS with a resulting performance penalty.
If you have allocated all available RAM for your program, the top end of your memory space may have to be swapped out to load the overlay. Make sure that neither the scall nor the data areas being worked on as part of the call are in this memory area.
Mount a disk drive and print a message on the console informing the user.
Entry:Dismount a disk and print a message on the console. Parameters same as .MOUNT.
Mount a disk, but do not produce a mount message on the console. See .MOUNT above.
Dismount a disk, but do not produce a dismount message on the console. See .DMOUN above.
Reset a drive. This is effectively the same as a dismount followed by a mount.
The drive will be dismounted with a message printed on the console. If there is no disk currently on the drive, this step will be skipped.
A message will be printed asking the user to replace the disk. HDOS will wait until the drive becomes not ready (e.g., the disk is removed), and then wait until the drive becomes ready again (e.g., a new disk is inserted). Then the disk will be mounted, with message.
The call may be interrupted (by a Ctl-C, etc.) between the dismount and mount. In that case, the drive will be left in the dismounted condition.
The parameters are the same as the .MOUNT call above.
Emulator note: When prompted to mount the new disk, open the Manage Diskettes dialog box, remove the disk and insert a new one. If you want to keep the same disk on the drive, open the Manage Diskettes dialog box and click the Reset button associated with the drive.
SCALL Value Tables
Mnemonic | Value | Description |
.EXIT | 000Q | Exit and return to HDOS command prompt. |
.SCIN | 001Q | Read a character from the console |
.SCOUT | 002Q | Write a character to the console |
003Q | Write a string to the console | |
.READ | 004Q | Read from a file |
.WRITE | 005Q | Write to a file |
.CONSL | 006Q | Change console options |
.CLRCO | 007Q | Clear console type-ahead buffer |
.LOADO | 010Q | Load an overlay |
.VERS | 011Q | Return the HDOS version |
Mnemonic | Value | Description |
.LINK | 040Q | Load and execute another program |
.CTLC | 041Q | Set a control character trap |
.OPENR | 042Q | Open a file for read access |
.OPENW | 043Q | Open a file for write access |
.OPENU | 044Q | Open a file for update access |
.CLOSE | 046Q | Close an open file |
.POSIT | 047Q | Position the file sector cursor |
.DELETE | 050Q | Delete a file |
.RENAME | 051Q | Rename a file |
.SETTOP | 052Q | Allocate memory to your program |
.DECODE | 053Q | Decode a file name |
.NAME | 054Q | Retrieve a file name from an open channel |
.CLEAR | 055Q | Clear a file channel |
.ERROR | 057Q | Display an error message |
.CHFLG | 060Q | Change file flags |
.LOADD | 062Q | Load a device driver |
Mnemonic | Value | Description |
.MOUNT | 200Q | Mount a disk on a device |
.DMOUN | 201Q | Dismount a disk |
.MONMS | 202Q | Mount with no console message |
.DMNMS | 203Q | Dismount with no console message |
.RESET | 204Q | Reset a disk device (dismount/mount) |
Error Code Value Table
Mnemonic | Value | Description |
EC.EOF | 001Q | End of file |
EC.EOM | 002Q | End of media |
EC.ILC | 003Q | Illegal Syscall code |
EC.CNA | 004Q | Channel not available |
EC.DNS | 005Q | Device not suitable |
EC.IDN | 006Q | Illegal device name |
EC.IFN | 007Q | Illegal file name |
EC.NRD | 010Q | No room for device driver |
EC.FNO | 011Q | Channel not open |
EC.ILR | 012Q | Illegal request |
EC.FUC | 013Q | File usage conflict |
EC.FNF | 014Q | File name not found |
EC.UND | 015Q | Unknown device |
EC.ICN | 016Q | Illegal channel number |
EC.DIF | 017Q | Directory full |
EC.IFC | 020Q | Illegal file contents |
EC.NEM | 021Q | Not enough memory |
EC.RF | 022Q | Read failure |
EC.WF | 023Q | Write failure |
EC.WPV | 024Q | Write protection violation |
EC.WP | 025Q | Disk write protected |
EC.FAP | 026Q | File already present |
EC.DDA | 027Q | Device driver abort |
EC.FL | 030Q | File locked |
EC.FAO | 031Q | File already open |
EC.IS | 032Q | Illegal switch |
EC.UUN | 033Q | Unknown unit number |
EC.FNR | 034Q | File name required |
EC.DIW | 035Q | Device is not writable (or write locked) |
EC.UNA | 036Q | Unit not available |
EC.ILV | 037Q | Illegal value |
EC.ILO | 040Q | Illegal option |
EC.VPM | 041Q | Volume presently mounted on device |
EC.NVM | 042Q | No volume presently mounted |
EC.FOD | 043Q | File open on device |
EC.NPM | 044Q | No provisions made for remounting more disks |
EC.DNI | 045Q | Disk not initialized |
EC.DNR | 046Q | Disk is not readable |
EC.DSC | 047Q | Disk structure is corrupt |
EC.NCV | 050Q | Not correct version of HDOS |
EC.NOS | 051Q | No operating system mounted |
EC.IOI | 052Q | Illegal overlay index |
EC.OTL | 053Q | Overlay too large |