home *** CD-ROM | disk | FTP | other *** search
Text File | 1985-02-10 | 45.0 KB | 1,064 lines |
- >>>>>>>>>>>>>>>>>>>>> CP/M-Net News <<<<<<<<<<<<<<<<<<<<<<<<
-
- ============================================================
- Number 9 September, 1981 Volume 1, Issue 9
- ============================================================
-
- In This Issue
- =============
-
- Assembly Language Interface to PL/I-80
- By: Michael J. Karas, MICRO RESOURCES
-
- CP/M-Net "Tip-of-the-Month"
- The Absolute Minimum Typing, to Run a CP/M Submit File...
- By: Mike Karas and Kelly Smith
-
- Printed monthly (at worst quarterly) to inform user's of
- RCPM Systems to the latest software news, information, and
- updates of public domain software accessible via
- telephone/modem transfer. Yearly subscription for copies of
- the CP/M-Net News may be obtained by mailing $18.00 (check
- or money orders only) to Kelly Smith, CP/M-Net, 3055 Waco
- Street, Simi Valley, California 93063. CP/M-Net is a non-
- profit orginization and all money received on subscriptions
- are utilized for the sustaining and enhancments of the CP/M-
- Net System.
-
- If you would like to contribute an article, include a
- column containing your area of interest and expertise, or
- participate in an open forum for conversation and transfer
- of ideas, feel free to send it to the CP/M-Net System and
- indicate that you would like it to be included in the CP/M-
- Net News...if possible, use WordStar (trademark, MicroPro
- International) or Electric Pencil (trademark, Micheal
- Shrayer) in 60 column format.
-
- Note: CP/M is a registerd trademark of Digital Research
-
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
- Assembly Language Interface to PL/I-80
- ======================================
-
- by: Michael J. Karas
- MICRO RESOURCES
- 2468 Hansen Court
- Simi Valley, California 93065
-
-
- The advent of the PL/I-80 high level programming
- language for CP/M based machines has opened up the wide wide
- world of easy, sophisticated, and structured programming for
- business, commercial and scientific applications. The
- language features offer the most capable development tools
- of any microprocessor programming language available in the
- marketplace today. Through extended use of the language,
- others like my self, are going to find out that the features
- of PL/I-80 offer far more than just programming niceity for
- applications software development. The structure, speed of
- execution, self documentation features, and full CP/M
- compatability make PL/I-80 the obvious choice for many
- systems utility and dedicated function processor programming
- exercises.
-
- The one main disadvantage of any high level language is
- the isolation from the "guts" of the computer machinery that
- results for the programmer. Don't get me wrong in that this
- is an altogether disadvantage. After all, it is the whole
- idea behind the use of a high level language in the first
- place. But for certain aspects of systems utility and
- dedicated function processor programming, more access to the
- internals of the computer are generally needed. The normal
- manner to obtain this capability is through development of
- programs in machine language. But we all know what a pain
- that can be for very large programs in the thousands of
- bytes in size. It always seems that when an assembly
- language program gets over about 2000 bytes, that there is a
- screaming need for easy access to disk files, the operator
- interfaces, and simplified development of complex logical
- structures. PL/I-80 offers all of the things the heavy duty
- assembly language programmer needs to make life easy. The
- next obvious question is... How do I handle that special
- interface?..or How can I do IN and OUT in PL/I-80?..or How
- can PL/I-80 access the SYSTEM tracks of a CP/M floppy
- disk?...and the list of questions goes on and on and on. The
- answer to all these questions is to use the assembly
- language interface facilities offered through the mechanism
- of external procedure calls in PL/I-80.
-
-
- CP/M is a registered TRADEMARK and PL/I-80, RMAC, and LINK-
- 80 are TRADEMARKS of Digital Research Inc. Pacific Grove,
- California.
-
- The Digital Research LINK-80 manual describes how it
- all works but doesn't make it very easy to understand. Here
- in example form, I intend to present an easy explanation of
- how to implement an assembly language interface to PL/I-80.
- I have chosen to implement "hooks" to allow direct access to
- the CP/M BIOS vector table of CP/M 2.2 to allow the PL/I-80
- programmer to make those special system utility packages
- with a minimum of pain yet leaving the avenue open to
- perform all those special I/O functions that the standard
- CP/M BDOS interface never seems to have enough of. I have
- chosen to write a diskette copy utility program in PL/I-80
- and let the compiler make it easy to write all the operator
- prompting messages and to allow quick human readable
- presentation of the logical structure of the program while
- at the same time allowing direct high speed access to the
- disk drivers in the BIOS.
-
- The start of this project resulted in the assembly
- language module given below. This module provides interface
- translation between the external procedure calling
- mechanisms of PL/I-80 and the entry/exit requirements of the
- various assembly language hardware interface drivers of the
- CP/M 2.2 BIOS. Detailed discussion of all aspects of the
- interface conventions are well beyond the scope of this
- article but a few general comments are in order. Readers who
- desire to "understand to the MAX" are encouraged to (1)
- study the examples given here carefully while (2) consulting
- the PL/I-80 LINK-80 Users Manual and (3) consulting the CP/M
- 2.2 System Alteration Guide. As a start, to become the most
- familiar with the mechanisms, I would suggest implementing
- the examples given here on your own computer system. It only
- takes a few days or evenings and the experience can be quite
- rewarding.
-
- The interface to the BIOS, in general, is done as
- follows: The location of the BIOS vector table of entry
- points is determinable in any CP/M system by looking at the
- address in locations 1 and 2 of low memory. This address
- gives the pointer to the warm boot address of the BIOS
- vector table. All other BIOS entry points are accessable by
- adding an offset to the warm boot pointer vector. Some
- functions are console status, line printer output, and disk
- track selection. All of the offsets necessary are given in
- the assembly language source code below. The typical
- procedure to get to a BIOS subroutine, with 8080 type
- machine language, would be like this:
-
- function:
-
- lhld 0001 ;get warm boot vector table pointer
- lxi d,offset ;get offset for desired BIOS entry point
- dad d ;make address of entry point
- pchl ;branch indirect through (HL) to BIOS
- ;subroutine
-
- If the label entry "function" had been CALLed from some
- main program, then the return at the end of the BIOS
- subroutine would get program execution back to the calling
- program assuming we use the callers stack all along the way.
- If the entry to the interface routine required post
- processing of BIOS return parameters before returning back
- to the main calling program, then the above program segment
- becomes:
-
- function:
-
- lhld 0001 ;get warm boot vector table pointer
- lxi d,offset ;get offset for desired BIOS entry point
- dad d ;make address of entry point
- lxi d,backhere ;put return address to here on stack
- push d
- pchl ;branch indirect through (HL) to BIOS
- ;subroutine
- backhere:
- <.... post processing
- instructions....>
- ret ;back to main program call point
-
- All parameter information entered at the BIOS follows
- the following general set of rules:
-
- a) If entry parameter is a single byte it is placed in the
- (C) register.
-
- b) If entry parameter is a double byte or an address it is
- entered in the (BC) register pair.
-
- c) Return parameters of one byte values are brought back in
- the (A) register.
-
- d) Return address of double byte parameters are returned in
- the (HL) register.
-
- For now, that should give the reader the information to
- understand the BIOS part of the assembly language module
- given below. The full set of PL/I-80 rules are complicated,
- so I will only touch on the concept here as to the few
- interface types used by the BIOS module to return parameters
- to PL/I-80. For character string variables, the return
- parameter is put on the stack with the length of the string
- given back in the (A) register. This scheme applies to the
- CONIN and READER routines which bring a byte character back
- from the BIOS. These push the character onto the stack and
- send a 01 length back to the calling PL/I-80 program.
-
- If the return parameter is a PL/I-80 data type that is
- one byte in size, but a numerical type variable, then the
- value is returned to PL/I-80 in the (A) register. If a
- numerical type variable of two bytes or an address is being
- passed back then the PL/I-80 program gets the parameter back
- in the (HL) register pair.
-
- All entry data sent from the PL/I-80 program to the
- assembly language module comes as follows, if a parameter is
- defined for passage to the BIOS. The rule is that when
- called, the assembly language program receives an address in
- the (HL) register pair that points to a table of memory
- locations (in our case a single pair). These two bytes of
- memory contain another address that points right at the data
- parameter. The type, size, and number of parameters are
- defined by design of the assembly language program and the
- statement of external entry point characteristics. No type
- coding is passed or error check done. In other words both
- sides have to agree to what is trying to be done before the
- call and return parameter passing will work properly.
-
- The program module "PLIBIOS.ASM", given below in source
- code form, establishes the names for sixteen small programs
- that translate procedure calls from within a main PL/I-80
- program to the forms required by the BIOS. The subsequent
- module below, "BIOSCALL.DCL" is a small file the fully
- defines, in a manner compatible with the assembly language
- program, the form that the PL/I-80 program must use to call
- the entry point definitions to make the parameter passing
- work.
-
- The assembly language program is meant to be assembled
- into a relocatable file of the ".REL" type by use of the
- Digital Research relocating macro assembler, RMAC. This
- assembler, seeing the psuedo opcodes "PUBLIC" on the program
- names builds the .REL file with a table to tell the, later
- utilized, link program where the relative addresses of the
- subroutines in the module are located. After the host PL/I-
- 80 program, like the disk copy utility given later in the
- article, is compiled into a relocatable object module, that
- .REL module also contains a table of subroutine call
- addresses which were known to be external to the PL/I-80
- program. The external nature if the labels is defined by the
- included declare statement from the file "BIOSCALL.DCL"
- which simply told the compiler that I intended to provide
- another ".REL" module that had these program names in it,
- specifically "PLIBIOS.REL". The Link program LINK 80 is used
- to hook the two modules together and make an absolute object
- module out of them. The absolute object module happens
- simply to be the executable CP/M type ".COM" file.
-
-
- File PLIBIOS.ASM
-
-
- ;***********************************************************
- ; Direct CP/M 2.2 Bios access Interface Module For PL/I-80
- ;***********************************************************
- ;
- ; This module to be asembled with Digital Research RMAC
- ; provides interface conversion between PL/I-80 calls and
- ; function references and the Bios vector table entries.The
- ; file "BIOSCALL.DCL" should be included in your PL/I-80
- ; source program with a %include statement to properly
- ; establish the external entry point names and calling
- ; format definition. Most bios entry point routines are
- ; treated as function call modules. The user of these
- ; routine in PL/I-80 calls should be aware that some
- ; differences exist between the CP/M 2.2 BIOS
- ; implementations that are available from various software
- ; and hardware vendors. In particular, not all BIOS
- ; routines perform sector translation with the SECTRAN
- ; routine. Secondly, If the BIOS performs the function of
- ; physical sector deblocking, and the sector translate
- ; function is not used, then logical sector numbers
- ; entered at the BIOS settrk entry point may require
- ; numbering from zero instead of the usual start with
- ; locical sector number 1. This assembly language routine
- ; makes no assumption about the sector number start. Also
- ; no translation is done. The calling PL/I-80 program must
- ; anticipate the characteristics of the host system BIOS.
- ; (BEWARE: especially with tricky utilities being upgraged
- ; from CP/M 1.4, including Digital Research's SYSGEN
- ; program). Hopefully CP/M 3.0 coming out soon will fully
- ; resolve this problem. Note that CP/M 3.0 will probably
- ; fully eliminate the need to have direct BIOS access at
- ; all.
- ;
- ;***********************************************************
- ;
- ;
- ;
- name 'PLIBIOS'
- title 'Direct CP/M BIOS Vector Calls From PL/I-80'
- ;
- ;
- ;***********************************************************
- ;* *
- ;* bios direct calls from pl/i for direct i/o *
- ;* *
- ;***********************************************************
- ;
- public cboot ;cold boot reload of cp/m entry
- public wboot ;warm boot reload of ccp
- public cstat ;return byte for console status
- public conin ;return character input from console
- public conout ;write character to console
- public list ;write character to list device
- public punch ;write character to punch device
- public reader ;return character input from reader
- public home ;home selected disk unit
- public seldsk ;select disk unit and return parameter
- ;table pointer
- public settrk ;select track
- public setsec ;select sector number
- public setdma ;set disk i/o data buffer pointer
- public read ;read selected sector and return status
- public write ;write selected sector and return status
- public lstat ;return byte for console status
- public sectran ;translate sector number
- ;
- ;
- ; Bios vector table offsets from the warm boot vector to
- ; access the vector table entry points off the loc 1 and 2
- ; warm boot vector.
- ;
- cbooto equ -3 ;cold boot offset
- wbooto equ 0 ;warm boot offset
- cstato equ 3 ;console status offset
- conino equ 6 ;console input offset
- conouto equ 9 ;console output offset
- listo equ 12 ;list device output offset
- puncho equ 15 ;punch device offset
- readero equ 18 ;reader ddevice offset
- homeo equ 21 ;disk home offset
- seldsko equ 24 ;select disk offset
- settrko equ 27 ;select disk offset
- setseco equ 30 ;select sector offset
- setdmao equ 33 ;set dma address offset
- reado equ 36 ;read logical sector offset
- writeo equ 39 ;write logical sector offset
- lstato equ 42 ;list status offset
- strano equ 45 ;sector translate offset
- ;
- ;
- ; Define position of CP/M 2.2 warm boot vector location
- ;
- wbvect equ 0 ;addr of warm boot jump
- ;
- ;
- ;***********************************************************
- ;* *
- ;* general purpose routines used upon entry *
- ;* *
- ;***********************************************************
- ;
- ;
- ; get single byte parameter to register c
- ;
- getp1:
- mov e,m ;low (addr)
- inx h
- mov d,m ;high(addr)
- xchg ;hl = .char
- mov c,m ;to register c
- ret
- ;
- ;
- ; get single word value to BC
- ;
- getp2:
- call getp1 ;get low byte of parameter
- inx h
- mov b,m ;get high byte as well
- ret
- ;
- ;
- ; transfer control to indexed bios vector table entry
- ; enter with DE = entry offset index
- ;
- gobios:
- lhld wbvect+1 ;get cp/m warm boot vector
- dad d ;add in vector table offset
- pchl ;go to table entry
- ;
- ;
- ;
- ;***********************************************************
- ; *
- ; direct bios access routines for pl/i-80 calls *
- ; *
- ;***********************************************************
- ;
- ;
- ;
- ; routine to enter bios cold boot to completely reload cp/m
- ;
- cboot:
- lxi d,cbooto ;get offset
- jmp gobios ;on our way
- ;
- ;
- ; routine to enter bios warm boot to reload ccp and bdos
- ;
- wboot:
- lxi d,wbooto ;get offset
- jmp gobios ;go reload
- ;
- ;
- ; routine to return console status byte
- ; return byte value to stack
- ;
- cstat:
- lxi d,cstato ;status offset
- jmp gobios ;return bit(8) in (a) from bios
- ;
- ;
- ; routine to get character from the console for input
- ;
- conin:
- lxi d,conino ;conin offset
- ;
- ret1chr: ;entry point for one character
- ;return to pl/1-80 on stack
- call gobios ;go get the status to (a)
- pop h ;return address
- push psw ;character to stack
- inx sp ;delete flags
- mvi a,1 ;character length is 1
- pchl ;back to calling routine
- ;
- ;
- ; routine to output one character to the console
- ;
- conout:
- call getp1 ;get single output char to (c)
- lxi d,conouto ;console output offset
- jmp gobios ;return to pl/1 direct from bios
- ;
- ;
- ; routine to output one character to the list device
- ;
- list:
- call getp1 ;get single output char to (c)
- lxi d,listo ;list output offset
- jmp gobios ;return to pl/i direct from bios
- ;
- ;
- ; output routine to send one character to the punch
- ;
- punch:
- call getp1 ;get single output char to (c)
- lxi d,puncho ;punch output offset
- jmp gobios ;return to pl/i direct from bios
- ;
- ;
- ; routine to get character from the reader for input
- ;
- reader:
- lxi d,readero ;reader input offset
- jmp ret1chr ;let common code do rest
- ;
- ;
- ; routine to get list device status
- ;
- lstat:
- lxi d,lstato ;list status offset
- jmp gobios ;return bit(8) status in (a) from bios
- ;
- ;
- ; home selected disk entry point
- ;
- home:
- lxi d,homeo ;home offset
- jmp gobios ;return direct from bios
- ;
- ;
- ; entry point to select disk and return parameter table
- ; pointer for selected drive in (hl)
- ;
- seldsk:
- call getp1 ;get single byte drive select byte
- lxi d,seldsko ;select disk offset
- jmp gobios ;return addr pointer in (hl) from bios
- ;
- ;
- ; routine to send double byte track number to bios
- ;
- settrk:
- call getp2 ;get track number to (bc)
- lxi d,settrko ;set track offset
- jmp gobios ;return through bios
- ;
- ;
- ; routine to send double byte sector number to bios
- ;
- setsec:
- call getp2 ;get sector number to (bc)
- lxi d,setseco ;set sector offset
- jmp gobios ;return through bios
- ;
- ;
- ; routine to send data buffer pointer to bios
- ;
- setdma:
- call getp2 ;get dma address to (bc)
- lxi d,setdmao ;setdma offset
- jmp gobios ;return through bios
- ;
- ;
- ; sector translate routine.
- ;
- sectran:
- call getp2 ;get logsec to (bc)
- lxi d,strano ;sectran offset
- jmp gobios ;return through bios
- ;
- ;
- ; routine to read sector of 128 bytes
- ;
- read:
- lxi d,reado ;read sector offset
- jmp gobios ;return error status through bios
- ;
- ;
- ; write sector routine. entry parameter of write type
- ;
- write:
- call getp1 ;get write type to (c)
- lxi d,writeo ;write sector offset
- jmp gobios ;return error status through bios
- ;
- ;
- ;+++...end of file
-
-
-
- The following short file is a single statement PL/I-80
- declare statement that defines in PL/I-80 syntax, all entry
- points that are given in the preceeding assembly language
- program. The file is used so that the same set of declared
- variable names can be used in multiple PL/I-80 source
- programs without having to type them in all the time,
- risking making errors or ommissions. The PL/I-80 lanugage
- contains a feature called the "%include" statement that
- allows the following file to be put in as part of the source
- code as simple as typing the following code as part of your
- program:
-
- %include 'bioscall.dcl';
-
- This will insert the following text into the program
- source code at the point where the %include appears. Note
- that in the above syntax the file "BIOSCALL.DCL" is expected
- to be contained upon the same disk drive as the source
- program. Explanation of the statement formats of the
- declared entry points will be left for the examples below.
- An example of the "%include" function appears in the disk
- copy program below.
-
-
- File "BIOSCALL.DCL"
-
- /* Define names and procedure characteristics for the */
- /* MICRO RESOURCES Direct BIOS Access Procedures of */
- /* "PLIBIOS.ASM" and PL/I-80 linkable module "PLIBIOS.REL'*/
-
-
- dcl
- cboot entry,
- wboot entry,
- cstat entry returns (bit(8)),
- conin entry returns (char(1)),
- conout entry (char(1)),
- list entry (char(1)),
- punch entry (char(1)),
- reader entry returns (char(1)),
- home entry,
- seldsk entry (binary fixed(7)),
- settrk entry (binary fixed(15)),
- setdma entry (ptr),
- read entry returns (bin fixed(7)),
- write entry (bin fixed(7))
- returns (bin fixed(7)),
- lstat entry returns (bit(8)),
- sectran entry (bin fixed(15))
- returns (bin fixed(15));
-
- An example of how to make use of the assembly language
- BIOS access routines is presented below in the form of a
- PL/I-80 source program that is a floppy disk copy program.
- First let me describe the intent of the program and then
- show a few examples of how the external BIOS entry points
- are accessed. The diskette copy program allows full copying
- of a diskette in Drive A: to the diskette in Drive B:.
- Tracks are buffered in memory in track buffer arrays so that
- a whole track may be read at a time to make the program run
- reasonably fast. (Incidently, this copy operation runs
- almost as fast as most assembly language copy utility
- programs I've seen except for those that buffer more that
- one track at a time). Tracks are read sequentially from the
- HOME position of Drive A: and written to the corresponding
- positions of Drive B:. After writing, the Track is reread
- from Drive B: and compared byte for byte with the image read
- in originally from Drive A:. Any errors are reported as to
- track and sector number to inform the operator of any
- difficulties encountered along the way. At the completion of
- the copy process the operator is prompted to see if another
- copy is desired before rebooting the system disk in Drive
- A:.
-
- All console interface and program logic structure is
- implemented in the easy to program PL/I-80 syntax. Speed
- dependant and hardware specific I/O access in the program
- makes use of the BIOS access external entry points. The
- following examples show some of the external procedure
- references made to the entry points defined in "PLIBIOS". In
- the following paragraphs some familiarity with the PL/I-80
- language structure is assumed. A tutorial on the structure
- and syntax of the language is somewhat beyond the intended
- subject of this article.
-
- EXAMPLE ONE - Calling The CONSOLE INPUT ENTRY POINT (CONIN)
-
- The console input entry point is declared as an
- external entry point in the BIOSCALL.DCL include file as
- follows:
-
- DCL conin entry returns(char(1));
-
- This defines conin as a function procedure with
- procedure invocation by name in an expression. The implicit
- CALL to the routine will return the declared type of value,
- CHAR(1) in this case, to the point of the call. The example
- from the disk copy program has the conin call at the point
- of waiting for an operator response. A character string,
- declared as follows:
-
- DCL resp char(80) /* operator response buf */ ;
-
- ...is designated to receive one console character with the
- following statement. The NULL parentheses reference
- designates conin as a function procedure with no passed
- parameters. In this case resp
-
- resp=conin();
-
- ...becomes a string of one entered character padded on the
- right with 79 blanks.
-
-
- EXAMPLE TWO - Calling the SET SECTOR ENTRY POINT (SETSEC)
-
- The set sector function queues the BIOS to a sector to
- read on a subsequent call to the read routine. This
- procedure is very similar in operation to the set track,
- select disk, and set dma address entry points in that all
- are defined in the BIOSCALL.DCL file with declares of the
- form:
-
- DCL settrk entry (bin fixed(15));
-
- This defines settrk as a subroutine procedure that has
- an entry parameter consisting of a double byte binary fixed
- point number that must be referenced with the following type
- of statement:
-
- CALL settrk(n);
-
- ...where n is a variable of the fixed binary variety that
- contains the value of the track number to send to the BIOS.
- Note that no return parameters are involved with the
- procedure invocation. Makes direct BIOS access quite simple
- doesn't it !
-
- EXAMPLE THREE - Calling the DISK READ SECTOR ENTRY (READ)
-
- The read sector entry point is defined as a function
- procedure in that it returns a binary fixed(7) value
- pertaining to the status of the disk read operation.
- (Defined by standard BIOS entry definition, assembly
- language structure of the PLIBIOS program, and the declare
- in the BIOSCALL.DCL file as follows:
-
- DCL read entry returns(bin fixed(7));
-
- Since read is a function call, the read entry point is
- referenced by name and the binary fixed(7) return error code
- is returned to the point of invocation simply as in the
- statement below. This one statement causes the read of a
- previously selected logical 128 byte sector into the buffer
- defined by a previous "setdma" call and at the same time
- defines what action to perform if the read was unsuccessful
- and returned a non-zero error code.
-
-
- if read() ^= 0 then do;
- put edit('Read Error On Control Disk - Track ',
- trkno,' Sector ',secno)
- (col(1),a,f(3),a,f(3));
- put skip(2) edit('Restart Copy ',
- 'Process with new Source Diskette.')
- (col(1),a,a);
- go to copyloop;
- end;
-
- Other BIOS entry points are referenced in a manner
- similar to the examples above. The "write" for instance has
- an entry parameter as well as a return error code like the
- read call. The write entry parameter informs the BIOS, if
- physical sector deblocking is done, of the type of write to
- perform (see the Digital Research CP/M 2.2 System Alteration
- Guide for more information on the exact definition of BIOS
- entry point and return value definitions). A special note
- concerning the select disk entry point "seldsk" is that it
- returns a pointer value that defines the position of the
- disk parameter table for the drive selected in the entry
- parameter. (Note that a PL/I-80 NULL pointer return value
- defines an illegal drive designator).
-
- Careful examination of the following program will
- reveal all instances of direct BIOS entry point invocation.
- The rest of understanding of this program is left as a
- learning exercise for the interested reader.
-
-
- File dskcpy.pli
-
- /***********************************************************
- Full disk copy program to demonstrate the direct CP/M Bios
- access facilities presented in the accompanying article,
- "Assembly Language Interface to PL/I-80."
-
- Track by track copying is utilized through the direct bios
- access facilities of the linked assembly language program
- "PLIBIOS".
- ***********************************************************/
-
- dskcpy:
- proc options(main);
-
- %replace
- trk_per_disk by 77, /* logical bios tracks/diskette */
- sec_per_trk by 26; /* logical cp/m sectors/track */
-
- /* external CP/M bios entry points */
- %include 'bioscall.dcl'; /* bring in the bios entry point
- definition file that defines
- bios function entry points*/
- dcl
- resp char(80), /* operator response buf */
- inbuf(sec_per_trk) char(128)
- based(p), /* input buffer */
- outbuf(sec_per_trk) char(128)
- based(q), /* output buffer */
- trkno bin fixed(15),
- secno bin fixed(15),
- (i,j,k,l) bin fixed(15),
- (p,q,s) pointer,
- e5var bit(8) based(s),
- e5char char(1) based(s),
- e5trk bit(1),
- skew(sec_per_trk) bin fixed(15) static init(
- 1,7,13,19,25,5,11,17,23,3,09,15,21,
- 2,8,14,20,26,6,12,18,24,4,10,16,22),
- e5string char(128),
- partab pointer; /* disk parameter table ptr */
-
-
- /* Print initial message for Diskette copy from drive A: to B: */
-
- put edit('MICRO RESOURCES Diskette Copy program in PL/I-80 ',
- '^m^j',
- 'Version 1.1 of August 3,1981')
- (col(1),3(a));
-
- copyloop:
- put skip edit('Insert Source Diskette in Drive A:',
- '^iDepress <cr> when ready ')(col(1),a);
- resp=conin();
-
- newdisk:
- put skip(1) edit('Insert Destination Diskette in Drive B:',
- '^iDepress <cr> when ready or <ctl-C> to quit')
- (col(1),a);
- resp=conin();
- if resp='^C' then do;
- put edit('Remember to Re-Insert your CP/M ',
- 'System Diskette in Drive A:',
- '^iDepress <cr> when ready ')
- (col(1),a,a);
- resp=conin();
- stop;
- end;
-
- put skip(1) edit('Copy in Progress...')(col(1),a);
-
- allocate inbuf set(p); /* setup buffer storage */
- allocate outbuf set(q);
- allocate e5var set(s); /* setup simple 0EH insertion */
-
- partab=seldsk(0); /* select disk a: (0) */
- call home; /* restore it */
- partab=seldsk(1); /* select disk b: (1) */
- call home; /* restore that too */
-
- e5trk='0'b; /* e5 end track scan switch off */
- e5var='e5'b4;
-
- do i=1 to 128; /* fill e5 record check string */
- substr(e5string,i,1)=e5char;
- end;
-
- trklp:
- do trkno = 0 to trk_per_disk-1 while( ^ e5trk);
-
- partab=seldsk(0); /* select source */
- call settrk(trkno);
-
- j=0; /* set empty sector counter off */
-
- /* read source track loop */
-
- do secno = 1 to sec_per_trk;
- call setdma(addr(inbuf(secno)));
- call setsec(skew(secno));
- /* sectors are zero based */
- /* for some CP/M 2.2 BIOS's */
- /* if so replace (secno) with */
- /* (secno-1) */
-
- if read() ^= 0 then do;
- put edit('Read Error On Control Disk - Track ',
- trkno,' Sector ',secno)
- (col(1),a,f(3),a,f(3));
- put skip(2) edit('Restart Copy ',
- 'Process with new Source Diskette.')
- (col(1),a,a);
- go to copyloop;
- end;
- end;
-
- partab=seldsk(1); /* select destination */
- call settrk(trkno);
-
- /* write destination track loop */
-
- do secno = 1 to sec_per_trk;
- call setdma(addr(inbuf(secno)));
- call setsec(skew(secno));
- /* sectors are zero based */
- /* for some CP/M 2.2 BIOS's */
- /* if so replace (secno) with */
- /* (secno-1) */
- if write(2) ^= 0 then do;
- put edit ('Write Error On Destination',
- ' Disk - Track ',trkno,
- ' Sector ',secno)
- (col(1),a,a,f(3),a,f(3));
- put skip(2) edit ('Bad Diskette in Drive ',
- 'B:, try another.')(col(1),a,a);
- go to newdisk;
- end;
- end;
-
- /* read back destination loop */
-
- do secno = 1 to sec_per_trk;
- call setdma(addr(outbuf(secno)));
- call setsec(skew(secno));
- /* sectors are zero based */
- /* for some CP/M 2.2 BIOS's */
- /* if so replace (secno) with */
- /* (secno-1) */
-
- if read() ^= 0 then do;
- put edit ('Read Verify Error On Destination',
- ' Disk - Track ',trkno,
- ' Sector ',secno)
- (col(1),a,a,f(3),a,f(3));
- put skip(2) edit ('Bad Diskette in Drive ',
- 'B:, try another.')(col(1),a,a);
- go to newdisk;
- end;
- end;
-
- /* data compare loop */
-
- do secno = 1 to sec_per_trk;
-
- if inbuf(secno) ^= outbuf(secno) then do;
- put edit ('Verify Data Compare Error ',
- trkno)
- (col(1),a,f(3));
- put skip(2) edit ('Bad Data on Diskette ',
- 'in Drive B:, retry same diskette.')
- (col(1),a,a);
- go to newdisk;
- end;
- if inbuf(secno) = e5string then j=j+1; /* empty sector */
- end;
-
- if j=sec_per_trk then do;
- e5trk='1'b;
- put edit ('Track by track copy complete ',
- 'at track number ',trkno)
- (col(1),a,a,f(3));
- end;
- end trklp;
-
- free inbuf;
- free outbuf;
- free e5var;
-
- put skip edit('Do you wish to Copy This Another Diskette (Y/N) ')
- (col(1),a);
- resp=conin();
- if (resp = 'Y') ! (resp = 'y') then go to newdisk;
- else stop;
- end dskcpy;
-
-
-
-
- To compile the PL/I-80 program given above the
- following operational sequence would be used to invoke the
- Digital Research PL/I-80 compiler to process source file
- "DSKCPY.PLI". Lower case characters after the "A>" prompt
- are those typed by you the operator. Other text is the
- output of the compiler to the console screen.
-
- A>pli dskcpy<cr> <== Extent of .PLI is assumed
-
-
- PL/I-80 V1.3 COMPILATION OF: DSKCPY
-
-
- %include 'bioscall.dcl'; <== Complier brings in prev-
- iously edited DCL file for
- all external entry points
- in the "PLIBIOS.REL"module.
-
- NO ERROR(S) IN PASS 1
-
- NO ERROR(S) IN PASS 2 <== Compiler informs us of
- pass completions.
-
- CODE SIZE = 05A9 <== Compile statistics for
- DATA AREA = 044F "REL" file of "DSKCPY".
- FREE SYMS = 2BBF
- END COMPILATION
-
- A>
-
-
- The next step to get a final disk copy program out of
- all of this work is to link the "REL" (relocatable object
- code) modules of "DSKCPY", "PLIBIOS", and the necessary
- subroutines from the Digital Research PL/I-80 run time
- library together into a ".COM" file. The LINK 80 linker from
- Digital Research does the job nicely with the following
- console operational "look". As before, the text in lower
- case following the A> prompt was that typed by the operator
- performing the link process. (Please note that the symbol
- values given may not necessarily coincide with those for
- your version of the above program; especially if you
- slightly modify the text strings and signon messages in the
- PL/I-80 source code listing).
-
- A>
- A>link dskcpy,plibios <== ".REL" extensions assumed
- and output to DSKCPY.REL
- is the default output.
- LINK 1.3
-
- PLILIB RQST DSKCPY 0100 CONIN 06CC SELDSK 0705
- HOME 06FF SETTRK 070E SETDMA 0720 SETSEC 0717
- READ 0732 WRITE 0738 CBOOT 06BA WBOOT 06C0
- CSTAT 06C6 CONOUT 06D8 LIST 06E1 PUNCH 06EA
- READER 06F3 LSTAT 06F9 SECTRA 0729 /SYSIN/ 27E7
- /SYSPRI/ 280C
-
- ABSOLUTE 0000 <== Link prints out module
- CODE SIZE 266B (0100-276A) size and address statistics
- DATA SIZE 06E2 (285A-2F3B)
- COMMON SIZE 00EF (276B-2859)
- USE FACTOR 95 <== Hex percent of symbol table
- usage.
- A>
-
- The rest is up to you. I have provided an example of
- how assembly language routines can be tied to PL/I-80 to
- implement special functions that are beyond the scope or
- capability of the language. In this case they were simple
- examples of interface conversions for BIOS access. Other
- examples of assembly language routines that could be made
- include "IN and OUT" functions for direct language access to
- machine dependant input and output ports, high speed special
- access drivers for math chips such as the Intel 8087, or
- tightly coded interrupt service routines to increase program
- performance where PL/I-80 is used as the host development
- language in a real-time application.
-
- Operation of the above example should be self evident
- from a detailed study of the source listing. The best way to
- tackle your own problem is to dive right in. For those who
- feel that they need a little more structured approach or
- partly implemented feel for getting started, I am willing to
- provide the source code for all of the modules described in
- this article on a single density CP/M compatible 8 inch
- diskette free of charge if you just send a diskette, mailer,
- and return postage to the address given at the beginning of
- this article. Feel free to make use of any new ideas you see
- here however you see fit.
-
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
- CP/M-Net "Tip-of-the-Month"
- ===========================
-
- The Absolute Minimum Typing, to Run a CP/M Submit File...
-
- By: Mike Karas and Kelly Smith
-
- On occasion, you may need to run consecutive SUBmit
- files, under 'attended' operation, and MAY have to do it
- numerous times...well here is a trick to enter only two
- characters on your keyboard (S and Carriage Return), to
- minimize the amount of typing required.
-
- Edit your SUBmit file as normally do... end the edit,
- and then:
-
- A>REN .SUB=LAZY.SUB<cr> <-- Rename your .SUB to ONLY .SUB
- A>REN S.COM=SUBMIT.COM<cr> <-- Rename SUBMIT.COM to S.COM
- A>S<cr> <-- Run '.SUB'!!!
-
- How's it work? Easy...SUBMIT "see's" a temporary FCB
- entry of the file " . " (eight spaces for the
- filename and three spaces for the filetype), and goes
- "searching" for a filetype of ".SUB"...and low-and-behold
- FINDS IT!
-
- Now to really speed things up for your SUBMIT, we use
- that old trick of fooling the CCP (Command Console Processor
- with a 'null file'...you remember, 'SAVE 0 @.COM'...and use
- it to minimize the 'loading time' of some redundant
- operation. For example, when generating a pile of system
- disks you might edit a SUBMIT file like this:
-
- sysgen <--- Let's SYSGEN...
- pip b:=pip.*[v] <--- And PIP some goodies we need to B:
- @ b:=xdir.*[v] <--- And use PIP still in memory
- @ b:=stat.*[v] <--- And use PIP again...
- @ b:=asm.*[v] <--- And again...
- @ b:=ed.*[v] <--- Again..
- @ b:=load.[v] <--- Well, you get the point by now!
-
- Keep in mind however, that you may only use the LAST
- file that was loaded into memory...for instance, if you had
- placed something like ABORTSUB.COM in the middle of the
- PIP's, and then intended to CONTINUE PIPing, you MUST again
- invoke PIP explicitly as a filename...THEN you can continue
- using '@' as illustrated here.