Having seen how the standard Tube host code and the extra facilities provided by 6502.SYS are implemented on the host's side of the Tube, this chapter details the MOS and filing system calls which can be made from within 512 code.
In 512 user programs, any language which includes the ability to load nominated 80186 registers with specified values, directly as in machine code or indirectly as in, for example, BASIC's CALL or USR functions, can access the host's MOS or filing system via these calls. The various facilities of 6502.SYS can likewise be accessed by means of issuing the appropriate unknown OSWORD call.
Note though, that in general applications programming it is neither necessary nor desirable to directly program the host's hardware device controllers or internal software flags, the FDC, perhaps, being the most obvious example. Most languages have specific filing system support commands for loading or saving data and these should be used whenever possible. Screen mapping too should remain transparent in DOS applications code.
If standard DOS Plus or CP/M facilities are used, not only will the resulting programs be easier to write and understand, they will also be more easily maintained or transferred to a different machine or a different language, should the need arise. 512 users, perhaps more than others, should appreciate the penalties of dubious programming techniques or 'illegal' direct hardware device control. Programs which use MOS Tube calls will no more work on a PC than PC programs that used direct PC hardware access do on the 512.
The following information is intended to allow programs to be written for the 512 which must, for particular reasons, gain direct access to the MOS or filing system calls of the host. Readers should note that, as we are now referring to 80186 registers and DOS functions, 86 series conventions apply and hexadecimal values are written according to the normal 86 standards. For example, a value of 127, which in native BBC mode would be written as &7Fh, is shown here as 7Fh.
All Operating System functions required by code running in the 512 under DOS Plus are made by calling a DOS interrupt. In fact, unless illegal coding techniques are employed, all program communication with all other software and the machine's hardware should be achieved through these calls. The bottom 1024 bytes of DOS memory is reserved for the interrupt vector table, each entry of which points to the DOS routines designed to handle the particular type of call Each interrupt vector entry is a four-byte segment:offset address, therefore the full range of interrupts number 256(1024/4).
The MOS Operating System calls of the Tube host code detailed in Chapter Four, and the unknown OSWORD giving access to 6502.SYS explained in Chapter Five, can be called from the 512 by means of several (otherwise unused) DOS interrupt numbers appropriated for the purpose. Of the possible total of 256 hardware and software interrupts, the majority are unused in all DOS versions to date. Although more will inevitably be used by succeeding versions of MSDOS or PCDOS and later hardware, even as far as MSDOS version 3.3 only (some of) the interrupt numbers up to 2Fh, plus 33h, 44h and 67h had been allocated.
In the version of DOS Plus supplied for the 512, interrupt numbers between 040h and 04Ch are used for the eleven different MOS call types supported by the 6502's Tube host code, plus two MOS calls which are simulated. Some MOS calls, for example OSBYTE, normally require parameters to be placed in the 6502's registers. When called from DOS the values are placed in the 80186's AL, BH and BL registers. When the call is passed to the host for service through the Tube protocol, these values will be transferred to the 6502's A, X and Y registers respectively.
The following is an outline of the supported call types, but users wishing to employ them should refer to suitable MOS reference texts for the precise details of parameters and how the calls are implemented in the host.
The 13 MOS calls supported by the Tube host code are listed in Table 6.1 below in order of ascending interrupt call numbers. Interrupts 7h and 48h are included in the table only for completeness, though these are not supported by the Tube host code, as can be seen from Chapter Three and the host code Source listing.
Interrupts 47h and 48h are actually simulations provided in the XIOS to avoid the need for two more explicit calls in the Tube host code or 6502.SYS. A call to INT 47h, OSASCI, results in the current output character value being tested. If the character is Dh, (CHRS13) then INT 48h is called, if not then it is output directly through a call to INT 49h. A call to INT 48h, OSNEWL, simply loads Character Dh and calls INT 49h, then loads Ah and calls INT 49h.
Routine INT Function OSFIND 40h Open or close a file for byte access OSGBPB 41h Multiple byte read or write an open file OSBPUT 42h Put (write) a byte to an open file OSBGET 43h Get (read) a byte from an open file OSARGS 44h Read/write file attributes or read filing system type OSFILE 45h Read or write a whole file or its attributes OSRDCH 46h Host operating system read character OSASCI 47h simulated, if Dh also send Ah through INT 49h OSNEWL 48h simulated, output Ah and Dh through INT 49h OSWRCH 49h Host operating system write character OSWORD 4Ah Host operating system word general function call OSBYTE 4Bh Host operating system byte general function call OSCLI Host operating system command line interpreterTable 6.1 MOS calls supported by the Tube
The only 'standard' additions to this list are the functions provided by 6502.SYS, explained in the preceding chapter, or routines you may implement yourself by patching an additional 6502 routine into the jump table in 6502.SYS. Such a routine must, of course, be loaded after booting the system.
It should be understood that the following calls, when referencing a disc filing system operation, relate only to ADFS format (that is, bootable DOS 640K or true ADFS) or DFS format discs, not to any of the IBM DOS formats controlled through 6502.SYS. It should also be appreciated that, unless you are accessing a true MOS format disc for a special purpose, many of the host's filing system options are meaningless in DOS.
The same is true for the more general MOS calls which must be used with care. As a dramatic and salutary demonstration, you can prove this very simply by trying this example. While *FX13, 4 in native mode produces no visible effects, (the MOS does not normally use this event itself) the same command issued as STAR FX13, 4 from DOS will instantly and permanently paralyse the system by disabling all 6502.SYS operations.
As can be seen in the preceding chapter, event four is critical to the functioning of 6502.SYS, particularly for keyboard input. While both the MOS and DOS actually continue to function after this 'FX', you will have irreversibly severed their (and your) only means of communication through the Tube. It is not, in fact, just the keyboard you have disabled, all inter-processor communication is triggered by event four, which causes 50 IRQs per second in the 512 and which you have now permanently (until re-booting) disabled.
Function: | Open or close a file for byte access | |||||||||||
On entry: | AL specifies the operation DS contains the segment pointer to the filename BX contain the offset pointer to the filename |
|||||||||||
Operations: |
|
|||||||||||
On exit: | AL contains the returned file handle, or 0 if file has been closed or could not be opened. | |||||||||||
80186 flags: | Undefined |
Function: | Read/write a block of bytes from / to a specified open file. | ||||||||||||||||
On entry: | AL specifies the operation type DS:BX Point to a file control block which may be in either processor, where bytes contain the following
|
||||||||||||||||
Operations: |
|
||||||||||||||||
On exit: | AL = 0 Operation was attempted AL = entry value: Call not supported by current host FS. |
||||||||||||||||
80186 flags: | CF unset = Call completed succesfully CF set = Call failed Others = Undefined |
Function: | Write a single byte to an open file using the file's sequential pointer |
On entry: | AL contains the byte to be written BH contains the file handle (provided by OSFIND) |
On exit: | Nothing returned |
80186 flags: | Undefined |
Function: | Read a single byte from an open file using the file's sequential pointer. |
On entry: | BH contains the file handle (provided by OSFIND) |
On exit: | AL contains the byte read from the file |
80186 flags: | CF is set if an attempt is made to read past the end of the file- others are undefined. |
Function: | Read/write an open file's arguments or read the
current filing system type On entry: |
||||||||||||||||||
On entry: | AL = operation type AH = file handle (provided by OSFIND) or 0. BX points to a 4-byte attribute block, which must have been previously set up in the host's RAM |
||||||||||||||||||
Operations: | If AH = 0 and AL = 0 Return the current filing system type AL = 1 Return the address of the rest of the command line in the zero page control block AL =FFh Update all files to the media (i.e. ensure that all file's buffers are written) If AH is greater than 0 and AL = 0 Read sequential pointer of file AL = 1 Write sequential pointer of file AL = 2 Read length of file AL = 3 Write the length of the file AL = FFh Update the file to the media |
||||||||||||||||||
On exit: | If entered with AH=0 and AL=0, AL contains the filing
system number as follows:
If entered with AH = 0 and AL = 1, then the address of
the remainder of the last command line is returned in a
four byte zero page control block pointed to by BX. |
||||||||||||||||||
80186 flags: |
Function: | Read/write a complete file or catalogue information | |||||||||||||||||
On entry: | AL contains the operation type DS:BX point to the file's control block |
|||||||||||||||||
Operations: | AL = 0 | Save a block of memory as a file | ||||||||||||||||
AL = 1 | Write the information in the parameter block to the catalogue of an existing file | |||||||||||||||||
AL = 2 | Write the load address of an existing file | |||||||||||||||||
AL = 3 | Write the execution address of an existing file | |||||||||||||||||
AL = 4 | Write the attributes of an existing file | |||||||||||||||||
AL = 5 | Read a file's catalogue info with the file type returned in AL and the info returned in the parameter block | |||||||||||||||||
AL = 6 | Delete a named file | |||||||||||||||||
AL = 7 | Create a named file without transferring data | |||||||||||||||||
AL = FFh | Load a named file | |||||||||||||||||
The file control block is in the form: | ||||||||||||||||||
00-01 = | Address (lo-hi) of the filename | |||||||||||||||||
02-05 = | Four byte load address (low byte first) | |||||||||||||||||
06-09 = | Four byte execution address (low byte first) | |||||||||||||||||
0A-0D = | Start address of data for save (low byte first) or file length otherwise | |||||||||||||||||
0E-11 = | End address of data for save (low byte first) or file attributes | |||||||||||||||||
File attributes are stored in 4 bytes.
The most significant 3 bytes are filing system specific.
The least significant byte indicates the following when a
bit is set on:
ADFS Note: The three most significant bytes are
undefined, i.e. not used. In the least significant byte,
bit 2 is not used and bits 4-7 are always the same as
bits 0-3. |
||||||||||||||||||
On exit: | AL contains the result code as follows:
|
|||||||||||||||||
80186 flags: | Undefined |
Function: | Read a character from currently selected input stream |
On entry: | No parameters |
On exit: | AL contains the character or an error code |
80186 flags: | CF unset = Valid character read CF set = Error condition (code in AL) |
Function: | Write character to the currently selected output
stream but also output character Ah if current character is Dh |
On entry: | AL contains the character to be written |
Operations: | IF AL = Dh (CHR$13) THEN call INT 48h ELSE call INT 49h |
On exit: | No returned information |
80186 flags: | Undefined |
Function: | Write carriage return / linefeed to current output stream |
On entry: | No parameters |
Operations: | Loads AL with Dh (CHR$13) and calls INT 49h then loads AL with Ah (CHR$10) and calls INT 49h |
On exit: | No returned information |
80186 flags: | Undefined |
Function: | Write a character to the currently selected output stream |
On entry: | AL contains the character to be written |
On exit: | No returned information |
80186 flags: | Undefined |
Function: | Various functions, with parameters in a memory control block. (See also OSWORD FAh at the end of the chapter). |
On entry: | AL contains the OSWORD function. DS:BX points to a control block, the size and organisation of which is call dependent. See 6502 MOS reference texts for full call specifications. |
On exit: | Parameters returned are call dependent and if any, are placed in the control block |
80186 flags: | Undefined |
Function: | Various MOS byte operations |
On entry: | AL = OSBYTE type. See 6502 MOS texts for OSBYTE calls BL = 6502 X register parameter BH = 6502 Y register parameter (if required) |
On exit: | BL contains the returned 6502 X register value BH contains any returned 6502 Y register value (see note) Note: For OSBYTE calls that do not require a Y parameter, the Tube host code implements a short OSBYTE routine which neither expects nor transfers the value in BH, which therefore may be safely ignored. However, for all OSBYTE calls, if the value in BH is important it should be preserved by the caller. When a short OSBYTE call is used, the Tube host code does not actually return this value and BH is therefore undefined. For other OSBYTE calls the Y register value is returned, but is not meaningful. |
80186 flags: | CF value is call dependent but unless significant to the 6502, returned values should be regarded as undefined. |
Function: | Sends a string to the host's MOS Command Line Interpreter. (* command) |
On entry: | DS:BX point to the command string |
On exit: | No returned values |
80186 flags: | Undefined |
Notes: The command string passed does not need a preceeding '*' and may be up to a maximum of 256 characters long.
The string should be terminated by Dh (CHR$13). E.g., setting DS:BX to point to the string cat<CR> would produce a catalogue of the currently selected filing system directory of the chosen drive.
Any variable parameters you wish to pass must be entirely included within the command string length. Unrecognised commands will produce an error which will be reported via the Tube register four error IRQ, ultimately causing a DOS error unless this is trapped by your own code.
As a simple example of how the MOS interrupts are called, the following extract of 80186 assembler code shows how OSCLI (interrupt 4Ch) would be called with a fixed string which is the equivalent to '*HELP ADFS' issued in native mode.
; some fxed constant declarations oscli equ 04Ch ; OSCLI interrupt cr equ 0Dh ; Carriage return
; the code that does the call mov ds, cs ; just in case it wasn't xor al, al ; clear AL to be neat mov bx, offset string_1 ; point BX to the string int oscli ; call INT 04Ch
string_1: ds "help adfs" db CR
The OSWORD &FA which was removed from 6502.SYS is still available, but has been moved from the host code to the 80186 monitor, which already provides a slinilar facility for manual entry In TFER. It permits transfers to or from the 512.
The OSWORD interrupt code tests for a value of AL = 0FAh and diverts the call if it matches. This OSWORD call requires a control block to be set up in the 512, the location of which is pointed to by DS.BX. The format of the control block is:
0 Number of parameters sent to I/O processor (0Dh or 0Eh) 1 Number or parameters read from I/O processor (01h) 2 LSB of I/O processor address 3 ... 4 ... 5 MSB of I/O processor address 6 LSB of 512 offset address 7 MSB of 512 offset address 8 LSB of 512 segment address 9 MSB of 512 segment address A LSB of length of transfer B MSB of length of transfer C Operation type (See below) D 6502 memory access control
The operation type specifies the type of transfer as follows:
0 Write to 6502 at 24 µs/byte 1 Read from 6502 at 24 µs/byte 2 Write to 6502 at 26 µs/pair of bytes 3 Read from 6502 at 26 µs/pair of bytes 6 Write to 6502 at 10 µs/byte using 256 byte blocks 7 Read from 6502 at 10 µs/byte using 256 byte blocks
The memory access control byte allows access to the paged RAMs, paged RAM and shadow RAM in the host machine and is laid out as follows:
7 6 5 4 3 2 1 0 - sm m/s c pr3 pr2 pr1 pr0
where the bits have the following functions.
Bit7 Unused sm IF (I/O address between 3000h and 8000h) AND (sm=SET) THEN use screen memory regardless of state of *SHADOW - overrides bit 5 m/s 0 = Use main memory if screen address specified 1 = Use shadow memory if screen address specified C IF (I/O address between 3000h and 8000h) AND (C=SET) THEN use currently selected ROM pr3-pr0 Paged ROM number binary value 0 to Fh)
The memory access byte is only used if the first byte of the control block is set to OEh, otherwise it is ignored. Use of the memory access byte allows paged ROM software to be copied and therefore should be restricted to system use. This would prevent access to the shadow RAM, which is not used by the system and could not be legally accessed by other means.
A small example of the call is now given. This assumes that the control block has been set tip correctly and is located in the first 64k segment. A contiguous 36 kbyte area of memory is used as a buffer for data written from 2000:1000 in the 512. The host buffer starts at 3000h and extends to BFFFh. 3000h to 7FFFh is specified as shadow screen memory and 8000h to BFFFh is specified as paged RAM in bank 5.
osword equ 04Ah transfer equ 0FAh sub ax,ax ; nake ax zero mov ds,ax ; point DS at segment 0 mov bx,offset_transfer_block mov al,transfe ; set up OSWORD type int osword ; call interrupt 4Ah
transfer_block: db 0Eh ; number of parameters sent db 01h ; number of parameters read dw 3000h,0 ; base address in 6502 dw l000h,2000h ; base address in 512 dw 9000h ; length = 36K db 6 ; fast 256 byte type 6 transfer db 025h ; use shadow and paged RAM