Electronics Today International: The Applix Articles
ETI December 1987 — page 70
Project 1616
In the first few months of 1987 we published construction details on the Applix 1616 computer, and promised enhancements as they came to hand. Applix Co, the designers, have just released a BASIC to make programming easier, so here it is.
Paul Berger *
THE 1616 BASIC interpreter started life as a public domain UNIX-based program, written by Phil Cockcroft, somewhere in the US of A. We at Applix evaluated the program and decided it provided basis for the 1616 BASIC system.
Almost all of the code for BASIC is written in the ‘C’ language (as usual) and the interpreter has been adapted to run under 1616/OS, shortened, enhanced and considerably sped up by Andrew Morton, one of the Applix Insomniacs (or AI’s, as they are known in the industry).
The language is pretty standard, and includes just about all the features that a BASIC ever had. Those who have used a Microsoft BASIC will be on familiar ground here: such BASIC programs will run under 1616 BASIC with little or no change.
A BASIC program consists of a 1616/OS ASCII text file. Each line of the program has a line number at its start; the line numbers are used for ordering program lines as they are entered and for referencing sections of the program using the ‘goto’ and ‘gosub’ commands, etc. The ASCII program is ‘tokenised’ when it is read in from disk or typed in; this means that each BASIC keyword which is recognised in a new program line is converted into a single byte before being added to the main body of the program. This saves space and increases execution speed.
BASIC program files may be created using the 1616/OS full screen editor, or by editing individual lines from within the BASIC system. The BASIC ‘edit’ command permits the programmer to use the standard 1616/OS line editor to alter existing program lines.
The language features 10 digit floating point variables, 32-bit integer (whole number only) variables, multi-dimensional arrays and character strings. The first 15 characters of a variable’s name are significant. Numbers may be specified in either decimal or hexadecimal notation (hex numbers are preceded by a ’$’ symbol). The 32-bit integers may range from -2,147,483,648 to 2,147,483,647. Programs written using integer variables are considerably faster than those which use floating point, so integers should be used wherever possible.
The BASIC system provides an environment in which you may interactively alter and run BASIC programs; it also supports a ‘direct’ mode where a few BASIC statements may be executed without actually entering them into a program. Any 1616/OS command may be performed from within the BASIC system by preceding it with a right square bracket ‘]’. You may indefinitely escape back to 1616/OS from BASIC by using the ‘shell’ statement; you return to BASIC with the original program and variables intact by entering the 1616/OS ‘quit’ command.
The 1616-specific video and graphics control commands which are not found in other BASICs are:
set640, setvdp, setvap, setfgcol, setbg-col, setbdcol, setpal, scursmode, plot, sgfgcol, sgbgcol, sgtexture, line, circle, readdot
These commands translate directly into 1616/OS system calls.
The file I/O commands are:
open, create, fread, write, close, rename, delete, seek, tell, eof
These commands relate directly to the 1616/OS file I/O system calls and they all return a value which, if negative, indicates some sort of error. A diagnostic message which describes the error may be obtained using the ‘fileerr$’ command (see the example below).
The ‘seek’, ‘tell’ and ‘eof’ commands may be used to implement random-access files.
In addition, the ‘print’, ‘input’, ‘linput’ and ‘get$’ command save modes in which files are used for I/O, rather than character devices.
One interesting feature of 1616 BASIC is that there are four commands which greatly extend the BASIC and make the entire resources of 1616/OS available to BASIC programs. Owners of 1616s appear to be a cunning breed and they will be doing amazing (and probably incomprehensible) things with these commands.
The ‘syscall’ statement directly performs a 1616/OS system call and passes the 1616 BASIC commands returned value to the BASIC calling program. For example, the following program fragment reads the setting of a joystick:
1010 nul% = syscall (70, 7): rem Select analogue input #7 1020 joystickval% = syscall(73): rem Perform the conversion
In line 1010 above the value returned by the system call was assigned to the variable ‘nul%’ and then ignored. This is because the BASIC ‘syscair statement comes under the variety of statement which returns a value and must be made part of an arithmetic expression.
The ‘exec’ statement takes as its argument
a single string which is passed as a command to 1616/OS. An error code is returned to BASIC; if it is zero, all went well.As an example of the use of this statement consider the following program which, amongst other things, sets up the 1616’s function keys to produce some oft-typed commands:
10 rem Program to demonstrate the use of the 'exec' command 20 rem 30 print "Disk directory listing:" : print 40 nul% = exec("dir"): rem Discard result in nul% 50 rem 60 rem Program the function keys 70 rem 80 for key% — 1 to 10 90 read fkdef$: rem Get a string from the data tables 100 nul% = exec("fkey" + hex$(key%) + " " + fkdef$) 110 if (nul%) then print "Function key definition failed": stop 120 next key% 130 rem 140 rem Now display the time 150 print "On the third stroke it will be"; 160 nul% = exec("date") : rem Use 1616/OS to print the time out 170 for i% = 1 to 3 180 print chr$(7); : rem beep 185 nul% = exec("pause .50") : rem Wait for 1 second 190 next i% 200 print "precisely" 210 end 220 rem 230 rem Data for the function keys 240 rem 250 data "list ", "run ", "print ", "save ", "load " 260 data "]dir ", "for ", "then ", "if ", "edit "
100 ' Program : STRINGS.BAS - 1616 BASIC 110 ' Programmer : Paul Berger, Applix pty limited 120 ' 130 cls : set640(0) : scursmode(0, 1,0) : random : base 0 140 size%=20 150 dim xs%(size%), xe%(size%), ys%(size%),ye%(size%) 160 x1%=100 : x2%-60 : y1%=120 : y2%=175 170 z%=rnd(15)+1 180 d1%=rnd(10)-5 : d2%=rnd(10)-5 : d3%=rnd(10)-5 : d4%=rnd(10)-5 200 if x1%+d1%<0 or x1%+d1%>319 then d1%=(-d1%) 210 if x2%+d2%<0 or x2%+d2%>319 then d2%=(-d2%) 220 if y1%+d3%<0 or y1%+d3%>199 then d3%=(-d3%) 230 if y2%+d4%<0 or y2%+d4%>199 then d4%=<-d4%) 240 sgfgcol(0) : line(xs%(y%),ys%{y%),xe%(y%),ye%(y%)) 250 xs%(y%)=x1%+d1% : xe%(y%)=x2%+d2% : ys%(y%)=y1%+d3% : ye%(y%)=y2%+d4% 260 x1%=xs%(y%) : y1%=ys%(y%) : x2%=xe%(y%) : y2%=ye%(y%) 270 sgfgcol(z%) : line(xs%(y%),ys%(y%),xe%(y%),ye%(y%)) : next : goto 170
The ‘varptr’ statement may be used to find the address of a BASIC variable (floating point, integer, array or string). This is very useful for passing references to your BASIC data to 1616/OS or to assembly language subroutines.
For integer (%) variables, a pointer to a 32 bit point is returned. For floating variables a pointer to a 8 byte floating point number is returned. For strings a pointer to the first byte of the null-terminated string is returned.
As an example, the following program fragments write an array of integers directly to a disk file and read it back in again. Thus its much more efficient than using ‘print’ and ‘input’ statement to and from the file in the normal manner.
10 dim barofsoap%(100): rem The array of integers • • • 1000 rem Write the array to disk 1010 fd% = create("bathtub", 0, 0): rem create the file 1020 if fd% < 0 then ec% = fd% : goto 2000 : rem create failed 1030 ec% = write(fd%, varptr(barofsoap%(0)), 400): rem 4 bytes/integer 1040 if ec% < 0 then goto 2000:rem write failed 1050 ec% = close(fd%) : if ec% < 0 then goto 2000 • • • 1500 rem Read the array from disk, ignoring possible errors 1510 fd% = open("bathtub", 1) 1520 ec% = read(fd%, varptr(barofsoap%(0)), 400) 1530 ec% = close(fd%) 2000 rem Handle file I/O errors 2010 print chr$(7);"Disk file error:";fileerr$(ec%) 2020 stop
100 ' Program : POND.BAS - 1616 BASIC 110 ' Programmer : Paul Berger, Applix pty limited 120 ' 130 ' Be patient.... 140 ' 150 set640(1) : els : base 0 : scursmode(0,1,0) : random 160 dim r(640), c(640), pal(3) : gotoxy(0,24) : print"Wait..."; 170 for i%=1 to 640 : r(i%)-log(i%) : e(i%) = log(i%) : next 180 for r%"1 to 200 : for c%=l to 640 : x=c%*r(c9£) +r&*c( r%) 190 x=x/5:y-int(x):z-x-y:z%=int(s*5):plot(c%-1, r%-l,z%+l):next:next 200 ' 210 ' go through palette making sure each entry is a different colour 220 * 230 pal(0)=rnd(16) 240 pal(1)=rnd(16): if pal(0) = pal(1) then goto 240 250 pal(2)=rnd(16): for z=0 to 1 : if pal(z) = pal(2) then pal(2)-rnd(16): next 260 pal(3)=rnd(16): for z=0 to 2 : if pal(z) - pal(3) then pal(3)=rnd(16): next 270 for z=0 to 3: setpal(z,pal<z)) : next 280 ' 290 ’ wait 5 seconds then change palette colours again 300 ' 310 ticks=syscall(18) 320 repeat until syscall(18)=ticks+(50*5) 330 goto 230
100 ' Program : SPIRO.BAS - 1616 BASIC 110 ' Programmer : Paul Berger, Applix pty limited 120 ' 125 els : set640(0) : c-1 130 input"Number please (8 to 60 is best)";a 140 els 150 ’ 160 ' now do it] 170 ' 180 for t1=0 to (2*pi)-.001 step (2*pi)/a 190 for t2=t1+(2*pi)/a to (2*pi)-.001 step <2*pi)/a 200 line((cos(tl)*120+160),(sin(tl)*99+100),(cos(t2)*120+160),(sin(t2)*99+100)) 210 c=c+1 : sgfgcol(c) : if c>15 then c-1 220 next:next
The BASIC is supplied as a 1616/OS transient program which loads into memory at address $8000, rather than the normal $4000. This provides 16k of memory which is free for assembly language subroutines and data.
The BASIC ‘call’ statement allows the calling of an assembly language subroutine, with a facility for passing up to nine arguments to the subroutine. The ‘call’ statement evaluates as the value which the subroutine returns in the MC68000’s data register 0. The 1616 BASIC ‘varptr’ statement comes into its own here: BASIC programs may pass pointers to arrays of data to assembly code, which can directly access and/or alter the data.
The following program fragment loads such a subroutine and calls it:
10 dim barofsoap%(23) 20 sheepdog% = 12 • • • 1000 nul% = exec("mload sheepdip 4000"): rem load the code in 1010 if nul% then print "Cannot load file sheepdip" : stop 1020 rem Call the assembly code, put d0 value into result % 1030 result % = call($4000, 10, varptr(barofsoap% (0)), sheepdog%)
The 1616 Basic is available from Applix for $50 on tape. It will be available in ROM shortly, and readers interested should contact Applix direct. A disk based version will be available just as soon as the disk drives are available. As we go to press a timetable for this had not been finalised. •
abs absolute value and logical and standard ‘and’ command asc convert ASCII character to its numeric value atn arctangent base starting base for arrays (0 to 1) bye exit BASIC and return to 1616/OS call call a machine language routine from BASIC chr$ converts number to equivalent ASCII character circle draw a circle clear clear program variables close close data file els clear the screen cont continue interrupted program cos cosine create create a data file data standard data statement date $ read the current date/time as a formatted string def fn user defined function del deletes a range of BASIC program lines delete delete a data (disk) file dim dimension array edit edit a program line end end program eof return number of bytes to end of data (disk) file errmsg$ return error message string errline line number of an error that just occurred error generate an error code ermum error code of error that just occurred oval evaulate a string as an expression exec execute 1616/OS command exit exit BASIC and return to 1616/OS exp exponential function fileerr$ return file l/o error message for .. to .. step standard for loop freed read from a data (disk) file get$ get a record gosub execute subroutine goto continue program execution at specified line number gotoxy position cursor at x, y screen coordinate hex$ converts number into a string containing a hexadecimal number equivalent to the original number if .. then .. else standard 'if’ statement inkey$ read a character from the keyboard input read data from keyboard or data file instr find substring within a given string int largest integer number less than or equal to argument lefts take substring starting with first character len length of string let standard assignment statement (eg. let a - 3) line draw line linput read data from keyboard or data file with commas etc list list program (or part thereof) load load a BASIC program file log natural logarithm merge merge a BASIC program into program currently in memory mid$ extract a substring from a given string mod remainder of division new erase program currently in memory next ends ‘for’ loop normal for restoring some sanity to all the video modes not logical ‘not’ on.. error enable error trapping on .. gosub standard computed 'gosub1 command on.. goto standard computed 'goto’ command open open a data file or logical and standard ‘or’ command peek read a value from memory pi returns the value of π plot plot a graphics pixel poke put a specified value into a byte print print to the screen or file random start a new random number sequence read read information from 'data’ statement readdot real a graphic pixel value rem standard remark statement rename rename a data (disk) file renumber renumber BASIC program repeat.. until repeat until expression is true restore reset pointer to 'data’ statements resume return from error routine return return from subroutine rights take substring ending with last character rnd random number run execute program (at optional line number) save save current BASIC program scursmode alter cursor mode seek seek to a new data (disk) file position set640 select video mode setbdcol set border colour setbgcol set text background colour setfgcol set text foreground colour setpal set video pallette entry setvap set video software access page setvdp set video display page sgbgcol set graphics background colour sgfgcol set graphics foreground colour sgtexture set graphics line texture sgn sign of argument shell return to 1616/OS but do not exit BASIC sin sine space$ creates a string full of spaces sqr square root stop stop program execution str$ converts a string to a number strings creates a string filled with ine ASCII constant syscall perform 1616/OS system call system exit BASIC and return to 1616/OS tab spaces over to an absolute print position tan derived function tell return current position within a data (disk) file time$ read the current date/time as a formatted string val converts a string containing a number to numeric value varptr get address to variable wend end 'while’ loop while program loop that executes as long as a given condition is true write output data to file xor exclusive ‘or’