------ UDEF V3 *-+<[]>+-* USER EXTENSIONS to OS/8 BASIC V3.21 JUNE, 1977 Developed by Benson I. Margulies '77 Notes by Samuel M. V. Tatnall Computer Manager The Haverford School Haverford, Pa. 19041 ------ INTRODUCTION Sixteen special functions have been developed to enhance the capability of OS/8 BASIC. Although several of these functions are specific to hardware constructed at The Haverford School for the Classic PDP/8A computer facility, most of them will support any PDP/8 computer system using OS/8 BASIC. The User functions can be grouped as follows: (1) Keyin functions to permit entry of data "on the fly" from either keyboard. The computer will accept a single character without waiting for a carriage return. (2) Direct access to the LA-36 keyboard and printer eliminates the need to open and close files. (3) Common storage capability. Numeric data can be stored in the highest field of core and passed to other BASIC programs (when chaining) without using files. (4) Two time delay functions utilizing the internal real time clock. One function causes a pause in the program and the other operates as a timer running concurrently with the BASIC program. (5) Simplified cursor control addresses any location of the VT-50 terminal screen without using the PRINT statement. (6) Access to the data acquisition system permits the reading of analog voltages. Two joy-sticks are connected to the A/D Converter system. (7) Special integerize and random integer functions eliminate the need to call another BASIC overlay. (8) The current time of the day can be read from the calendar/clock. (9) The current version number for the User Function file can be obtained. This function is also used to activate a relay for control of external equipment. COMPUTER HARDWARE REQUIREMENTS The Haverford School installation includes a PDP/8A processor with 16K core memory, real time clock (standard with DKC8-AA I/O Option board), dual RX8 floppy disk drive, and a VT-50 terminal. An LA-36 was added as a printer and second keyboard. Special hardware developed at the school includes a calendar/clock and a data acquisition system with two joy-sticks. USER EXTENSIONS-Page 1 ------ INTRODUCTION HELPFUL HINTS Before giving specific instructions for the use of the afore-mentioned functions, the programmer should be reminded of certain considerations when using BASIC functions. OS/8 BASIC was written so as to use as little computer memory as possible. Therefore the operator can write large programs, but at a price. One method used to conserve space without sacrificing versatility is to employ overlays for less frequently used BASIC functions. An overlay is a file containing a group of functions and is read into computer memory (called core) from the disk when called for in the execution of a program. All function overlays occupy the same section of core, hence only one group of functions can be operative at any one time. If, during the execution of a program, a function is encountered that is not core resident, a new overlay must be read from the system disk. This causes a significant delay of perhaps a half-second and can be very time consumming in a large FOR-NEXT loop. The operator should be aware of the contents of these overlays so as to write efficient programs that minimize the number of disk read operations. BASIC OVERLAYS FILE CONTENTS BASIC.AF Arithmetic functions and (operations) ATN, COS, EXP, (Exponentiation), INT, LOG, RND, SGN, SIN, SQR BASIC.SF String functions and Trace ASC, CHR$, DAT$, LEN, POS, SEG$, STR$, VAL, and TRC BASIC.FF File functions CHAIN, CLOSE, FILE BASIC.UF User functions ADC,CLK,CRT,FIX,GTL$,KYI$,KYN,LCH, LNT,RAN,REC,SET,STK,TIM$,TMO,VER If, for example, you wish to use the VAL function and the INT function many times in a program, you would save time as well as the life expectancy of the disk drive mechanism by doing all of the VAL operations before performing the INT operations. In an effort to reduce overlay read operations when programming with the User functions, two of these functions nearly duplicate two frequently called arithmetic functions. RAN creates random integers and FIX converts numbers to integers. USER EXTENSIONS-Page 2 ------ INTRODUCTION HOW TO USE THE USER FUNCTIONS Before incorporating any of the special User functions into a program, you must declare them at the head of your program with one or more UDEF statements. The UDEF list must include and preserve the proper sequence of functions up through the last one you will be using. To avoid confusion and errors, it is recommended that you use the following UDEF list whenever employing one or more User functions: 1 UDEF KYI$(A),KYN(A),LNT(A),LCH(A$,A),FIX(A),GTL$(D),RAN(A),SET(A) 2 UDEF STK(A),REC(D),CLK(A),ADC(C,M),TIM$(D),CRT(X,Y),TMO(A),VER(D) The variables within () are called "arguments" and represent quantities to be operated on by the function, just as SQR(X) says to take the square root of X. All functions must have one or more arguments even if the function does not operate on any quantity supplied by the program. The functions with "D" as the argument do not use the argument, yet some number or variable must be supplied by the programmer. The concept of a "dummy" argument is familiar to anyone who has used the RND function. For example, TIM$(D) provides the time of day, and the value of "D" is irrelevant. The specific meaning of each active argument will be discussed later. The UDEF statements shown above can, of course, be added to your program like any other statements, but it is easier to use another procedure. The above shown UDEF statements are reproduced in a disk file called "UDEF.BA", and you can start a new program with this file or merge it with an existing program you have already created and saved. To begin a new program with the UDEF statements, type the monitor command: * * * * * * NEW PROGRAM: .READ PROG.XY0 THEN 50 30 PRINT "YOU DIDN'T TYPE ANYTHING" 40 STOP 50 PRINT "YOU TYPED THE NUMBER";X 60 END Note: It is only necessary to specify the first two functions in line 1, although the others can be given additionally. KYN is useful in game programs when you want to keep the action going while allowing the operator to interact with the computer. Also, it is easy to write games for two players, each seated at his own keyboard. KYI$ is convenient for returning string characters as illustrated: 10 A$=KYI$(0) However, it is not convenient to ask KYI$ whether or not a character has been typed. To do so requires the use of the LEN function, which means a different overlay must be used. The following program would not run efficiently: 1 UDEF KYI$(A) 10 A$=KYI$(0) 20 IF LEN(A$)>0 THEN 50 USER EXTENSIONS-Page 5 ------ DESCRIPTION OF THE USER FUNCTIONS 30 PRINT "YOU TYPED NOTHING" 40 STOP 50 PRINT "YOU TYPED ";A$ 60 END + [] + LNT(A) This function outputs a single character to the printer and is similar to the PNT function. For example, to ring the bell on the console you might say: 10 PRINT PNT(7) But, to ring the bell on the printer you would say: 10 LET D=LNT(7) Since LNT produces an output action, it does not return a meaningful value to the program. Hence "D" in the above statement is an irrelevant dummy variable. Yet, in order for BASIC to accept the statement it must appear in that form. Other character codes for use with LNT are given in APPENDIX A. + [] + LCH(A$,A) This function outputs a string to the printer. The first argument is the string, and the second argument, if zero, will suppress a carriage return & line feed combination following the string. Therefore, a non-zero second argument causes the printer to advance to the beginning of a new line after printing the string. The following two program segments show the correspondence between the PRINT statement and the LCH function, performing similar actions on respective output devices: 10 LET A$="VT-50" 10 LET A$="LA-36" 20 PRINT "MY NAME IS "; 20 LET D=LCH("MY NAME IS ",0) 30 PRINT A$ 30 LET D=LCH(A$,1) Note the use of the dummy variable in the statements with the LCH function. Also, the UDEF declarations have not been shown. The semicolon in the PRINT statement is like a zero second argument in LCH. + [] + FIX(A) It is similar to the INT function and returns the integer part of the argument. However, its use is restricted to numbers that fall within the range of 0 to 4095. If the argument is negative, the computer will print an "FM" error message, and an attempt to take the integer part of a number greater than 4095 will produce an "FO" error message. USER EXTENSIONS-Page 6 ------ DESCRIPTION OF THE USER FUNCTIONS For most applications FIX duplicates INT and is provided here to eliminate the need to swap in the arithmetic function overlay. Example: 10 V=FIX(Y) + [] + GTL$(D) A string of up to 72 characters in length can be read from the printer keyboard. GTL$ is analogous to the INPUT statement. When GTL$ is executed, the computer pauses and waits for a line to be typed at the printer. The characters entered at the keyboard are echoed on the printer, and the line is terminated in the conventional manner using the RETURN key. Typing CTRL/U causes the computer to ignore characters previously typed and advances the printer to a new line. The argument in GTL$ is a dummy and has no purpose other than to make the statement acceptable to the BASIC compiler. Example: 10 DIM B$(72) 20 B$=GTL$(0) 30 PRINT B$ This program segment shows how to read a string from the printer keyboard and print it on the console screen. Don't forget the UDEF declarations. + [] + RAN(A) This handy random number generator is constructed like RND but produces positive integers in the range of 0 through "A". The smallest integer is zero and the largest is the integer value of the argument, which cannot exceed 4095. A single RANDOMIZE statement should appear somewhere in the program prior to the first occurrence of RAN if you wish the random integers to be different each time you run the program. RANDOMIZE should only be executed once in the course of the program. A negative argument produces an "FM" error message, and an argument exceeding 4095 evokes an "FO" error message. Both errors are fatal, causing the program to halt. RAN was included primarily to avoid the necessity of accessing the Arithmetic overlay for random numbers, and the numbers it produces are no more or less random than those generated by RND. Example: 10 RANDOMIZE 20 X=RAN(10)+5 X will be an integer in the range of 5 to 15. USER EXTENSIONS-Page 7 ------ DESCRIPTION OF THE USER FUNCTIONS + [] + SET(A) This function, along with the next two, comprise a package implementing common storage. Common storage is a concept wherein a section of core is isolated for the storage of data, and the data is preserved even when another BASIC program is executed. Common storage can be used when data generated by one program is to be used by a succeeding program. When a program becomes so large that it must be segmented into two or more separate programs, data can be shared among the segments by using common storage. Ordinarily in BASIC, the programmer would have to write all data onto a disk file before chaining to the next program, whereupon the data would then be read back from the disk file into the new program. This is a cumbersome, time-consuming process. Common storage uses one field of core (one fourth of the computer memory) and thus can hold only 1365 numbers. Strings cannot be stored. And because one field of core is reserved for data, the space is not available for program statements even if only one number is put into common storage. Common storage operates like a "stack". Numbers are placed in storage one at a time and can be retrieved in the reverse order. That is, the last number put into the stack is the first one to be pulled out when data is read from common storage. Either an attempt to put too much data into the stack or pull out more than is available generates a fatal "IA" error message. SET is usually used to initialize the stack with a statement like: 10 D=SET(0) But, it can also be used to manage common storage on a random access basis as discussed later. To ensure that BASIC doesn't write in the common storage area, the programmer must tell BASIC that the highest field of core is not available prior to running any program. Use the Monitor command: .CORE 2 + [] + STK(A) STK is used to store numbers in the common storage stack. The number or variable to be stored is used as the argument. If an attempt is made to put more than 1365 data words into common storage, the computer will respond with the fatal error message "IA" (which stands for ILLEGAL ARGUMENT). Example: 10 D=STK(X) USER EXTENSIONS-Page 8 ------ DESCRIPTION OF THE USER FUNCTIONS This step stores the number in variable "X". "D" is a dummy variable. + [] + REC(D) REC is used to recall the data from common storage. When first called, it will return the value of the most recently stored datum. Succeeding calls to REC return the remaining numbers in the stack in the reverse order of entry. Last in is first out, next to last in is second out, etc.. Example: 10 X=REC(D) This will recall the latest number stored (and not yet retrieved) and give its value to "X". An attempt to recall more data than stored results in an "IA" error message and the program will crash. When a number is stored the location pointer is incremented BEFORE the number is stored. Hence, if you initialize the stack with SET(0), the first number is deposited in location 1, the second automatically goes into location 2, etc. However, when numbers are recalled, the pointer is decremented AFTER each retrieval. Therefore, to recall the first number entered, use SET(1) before REC(D). In general, a number stored following a SET(L-1) statement can be recalled by setting the pointer to word location L. The following program segment illustrates how to store and recall the same number on a random access basis: 10 PRINT "NUMBER LOCATION (1-1365)"; 20 INPUT L 30 PRINT "NUMBER TO BE STORED"; 40 INPUT N1 50 D=SET(L-1) 60 D=STK(N1) 70 D=SET(L) 80 PRINT "NUMBER RECALLED =";REC(D) 90 GO TO 10 In summary: Following initialization, SET(0), the Nth number pushed into the stack will be found at location N. Recalling numbers does not move or delete them, it merely decrements the pointer. The stack pointer is stored in the common storage area at location 0, which is untouched by BASIC, therefore other overlays, even other programs, can be used between store and retrieve operations without causing any difficulty. HINT: Before chaining to another program, the programmer may wish to store the number of data words in common storage so that the next program will know how many USER EXTENSIONS-Page 9 ------ DESCRIPTION OF THE USER FUNCTIONS data words to retrieve. + [] + CLK(A) This creates a pause in the program, the length of which is determined by the argument. The argument gives the number of ticks of the real time clock, where each tick is one hundredth of a second. The argument is restricted to the range of 0-4095 ticks (0 to 40.95 seconds). Larger or smaller srguments than those allowed result in "FO" and "FM" error messages respectively. Example: 10 D=CLK(100) In this case there will be a pause of one second at this point in the program. "D" is a dummy variable. CLK is handy for giving the operator time to read a message or slow down output. HINT: Often in the course of executing a program, BASIC will print part of a line and then proceed to busy itself with some other task before it finishes printing the line. To force BASIC to dump the TTY: ring buffer, you can call CLK(0) without introducing any delay. + [] + ADC(C,M) ADC gives BASIC access to the 8 channel data acquisition system and returns the value of the voltage applied to channel "C". "M" determines the range mode of the analog to digital converter. For greatest precision the programmer should use the lowest range compatible with the voltages being measured. MODE VOLTAGE RANGE 0 -10 TO +10 VOLTS 1 0 TO +10 2 -5 TO +5 3 0 TO +5 The conversion time plus program overhead should cause each measurement to take about 60 microseconds. ADC returns actual Volts, not a reading on some arbitrary scale. Example: 10 V=ADC(0,3) In this case "V" will receive the value of the voltage applied to channel 0. The voltage must be in the range of 0 to 5 volts for a meaningful measurement. At Haverford School, the first four channels can be connected to two joysticks. The channel USER EXTENSIONS-Page 10 ------ DESCRIPTION OF THE USER FUNCTIONS allocations are as follows: CHANNEL COORDINATE 0 X Left hand joy stick 1 Y 2 X Right hand joy stick 3 Y The voltage range coming from the joysticks on each channel is nominally 0 to 5 volts. Moving the joy stick to the right increases the X component, whereas moving the joy stick down increases the Y component. Thus up and left produces (0,0); down and right produces (5,5). This is compatible with the coordinate system of the VT-50 screen. One note of caution! It is possible on occasion for the joy stick to produce values of X or Y slightly less than zero or slightly greater than 5. You may want to check for these circumstances within your program if they could adversely affect operation of your program. To read the X and Y coordinate of the left hand joy stick code your program as follows: 10 X1=ADC(0,3) 20 Y1=ADC(1,3) + [] + TIM$(D) The Haverford School computer has a calendar/clock built into it. It accurately keeps track of the date and time, even if there is a power failure. The computer system software has been modified so that the current date is always available to the system. You can access the date using the DAT$ function in the String overlay, and you can determine the time using the TIM$ function in this overlay. Calling TIM$ causes a string to be returned as in the following example: 11:03:36 AM. There are 11 characters in this string, so remember to DIM any string variable set equal to the time. The argument in TIM$ is irrelevant. Examples: 10 DIM S$(11) 20 LET S$=TIM$(D) 30 PRINT "THE TIME IS ";S$ OR, 10 PRINT "THE TIME IS ";TIM$(D) + [] + CRT(X,Y) CRT moves the cursor on the VT-50 to video screen coordinates (X,Y). The upper left hand corner, or home position, on the screen has coordinates (0,0). The maximum range of X is 79 (the right hand edge of the screen) and the maximum domain for Y is 11 (the bottom of the screen). CRT is completely USER EXTENSIONS-Page 11 ------ DESCRIPTION OF THE USER FUNCTIONS independent of the BASIC PRINT statement, hence cursor control is greatly simplified and all points on the screen can be addressed. The following program shows how to use the joy stick to print asterisks anywhere on the VT-50 display: (UDEF's not shown) 10 X1=ADC(0,3)*79/5 20 Y1=ADC(1,3)*11/5 30 D=CRT(X1,Y1) 40 PRINT "*";PNT(27);"H" 50 GOTO 10 60 END In the above program the voltages from the ADC are first scaled to the dimensions of the display, then the cursor is sent to the appropriate coordinate position with CRT. Finally, an asterisk is printed; and, to avoid the possibility of scrolling, the cursor is sent home before the PRINT statement generates a line feed. In line 30, "D" is a dummy variable. CRT integerizes all coordinates and will not move the cursor beyond the borders of the screen except in the downward direction. Sending CRT a Y coordinate of 12 or more WILL scroll the display. BEWARE! + [] + TMO(A) From a computer programmer's point of view, TMO is the most interesting of all the functions. TMO is an elapsed time counter; once started it runs concurrently with the BASIC program. One can start it ticking by calling TMO with a positive, non-zero integer as the argument. The argument is expressed in ticks of the real time clock (1 tick=0.01 seconds). Calling TMO(0) asks the clock if it has timed out yet. While the clock is running TMO(0)=0, and when it has run out of time TMO(0)=1. Calling TMO with a negative argument turns off the clock. The largest number of ticks allowed is 4095 (40.95 seconds). Exceeding this value generates a fatal "FO" error. TMO uses the interrupt system in the computer. Once the clock is started, the BASIC program can continue to run its course. But every time the clock registers a new tick, the program is interrupted for a few microseconds while the tick counter is incremented. When the preset time is reached, the clock is turned off and the value of TMO is switched from 0 to 1. Aborting a BASIC program by typing CTRL/C also disables the clock so that it can no longer interrupt the computer's USER EXTENSIONS-Page 12 ------ DESCRIPTION OF THE USER FUNCTIONS normal activity. WARNING! While TMO is ticking, no other overlays can be used. Calling other overlays will crash the program requiring a "bootstrap" to recover. The following program prints random numbers on the console display for 10 seconds: (UDEF's not shown) clear screen 10 PRINT PNT(27);"H";PNT(27);"J" start clock 20 D=TMO(1000) random # 30 X=RAN(9) print it 40 PRINT X; check clock 50 IF TMO(0)=0 THEN 30 exit 60 PRINT "YOUR TIME IS UP" 70 END + [] + VER(D) To determine the version number of the User function file, call VER with a dummy argument. Example: 10 PRINT VER(D) VER also activates a relay used to control optional external hardware, thus making it a dual purpose function. CONCLUDING REMARKS Comments and corrections concerning the User functions and this document are cordially invited. The monitor .READ command is unique to the Haverford CCL command repertoire; it simply runs PIP. Only the ADC and TIM$ functions depend on hardware built at The Haverford School, therefore most User functions should be of general interest to those running BASIC programs at other PDP/8 installations. USER EXTENSIONS-Page 13 ------ Appendices APPENDIX A TABLE OF CODES FOR KYN & LNT CHAR CODE CHAR CODE CHAR CODE ! 33 " 34 # 35 $ 36 % 37 & 38 ' 39 ( 40 ) 41 * 42 + 43 , 44 - 45 . 46 / 47 0 48 1 49 2 50 3 51 4 52 5 53 6 54 7 55 8 56 9 57 : 58 ; 59 < 60 = 61 > 62 ? 63 @ 64 A 65 B 66 C 67 D 68 E 69 F 70 G 71 H 72 I 73 J 74 K 75 L 76 M 77 N 78 O 79 P 80 Q 81 R 82 S 83 T 84 U 85 V 86 W 87 X 88 Y 89 Z 90 [ 91 \ 92 ] 93 ^ 94 _ 95 ' 96 a 97 b 98 c 99 d 100 e 101 f 102 g 103 h 104 i 105 j 106 k 107 l 108 m 109 n 110 o 111 p 112 q 113 r 114 s 115 t 116 u 117 v 118 w 119 x 120 y 121 z 122 { 123 | 124 125 126 Special Codes Line Feed = 10 Return = 13 Space = 32 Delete = 127 Tab = 9 Bell = 7 USER EXTENSIONS-Page 14 ------ Appendices APPENDIX B USER FUNCTION SUMMARY KYI$(A) Keyin a string character A = 0 for console, 1 for printer keyboard KYN(A) Keyin ASCII code (7 bits) A = 0 for console, 1 for printer keyboard LNT(A) PNT for printer A = 7 bit ASCII (expressed in decimal) LCH(A$,A) Print string on printer A$ = string, A = 0 for no FIX(A) Integerize number A = floating point number GTL$(D) Get string from printer keyboard D = dummy RAN(A) Generate random integer A = maximum allowable integer SET(A) Set common storage stack pointer A = 0 for initialization STK(A) Put number into common storage stack A = quantity to be stored REC(D) Recall a number from common storage stack D = dummy CLK(A) Delay program A = # ticks in hundredths of seconds ADC(A,B) Read A/D converter A = channel, B = range TIM$(D) Get current time of day D = dummy CRT(X,Y) Move cursor to location on video screen X,Y = coordinates of location TMO(A) Elapsed time counter A = # ticks; = 0 to check for time out; <0 to turn off clock VER(D) Get version # of BASIC.UF, activate relay D = dummy USER EXTENSIONS-Page 15 ------