31KW Version of MSU BASIC

MSU BASIC is a four-user time-sharing BASIC system for a HP2116 minicomputer from Montana State University, the source code for Revision A is dated December 1971. Each user was connected to a separate TTY console interface and the system logged activity on a separate TTY (or perhaps one of the user TTY's, not sure if that works). The system was slightly modified in early 2008 to disable logging, and settings were discovered to permit proper simulation under SimH HP2100, I got ahold of the files and slightly modified them to permit configuring a system for a 31KW memory configuration (to leave the top 1KW free for integration and swap/save code), and figured out how to get it to boot straight to the READY prompt, without logging on and clearing memory, thus permitting programs to be entered and saved in binary form. And here we are...

I restricted the mods to the assembly source code (this time:-) to the bare minimum needed to make it spit out a working 31KW binary, theoretically it can still be configured multi-user. There is a texual glitch while preparing, don't know why but it doesn't keep the configured binary from running, so for now ignoring (same glitch happens when assembled with extasmb so it's not an Asm21 glitch, and it doesn't happen with the 16KW so related to something I did... oh well). All further mods were done directly to the configured binary, starting with logging it on so it would initialize its data structures to eliminate the need to re-initialize every time it starts. The patches are essentially memory pokes to skip around some of the startup code and to insert new code to process BYE so that if it is run from HP-IPL/OS it runs the swapper to exit, leaving the BASIC system in alternate memory where it can be saved to disk or punched to a stand-alone ABS file. When the saved results is run the BASIC program is also loaded, ready to run. The patch utility also permits reconfiguring the CLK and TTY slots and entering new information line(s) to be displayed on startup. If desired the stock "_" correction character can be changed to a more user-friendy ascii-8 backspace (if using Linux might have to select a different keymap to use).

Hopefully now the infrastructure is in mostly in place to get on with the fun part - converting and writing more BASIC code to run!


The HP BASIC Language supported by MSU BASIC

The MSU BASIC language is very similar to HP paper-tape BASIC (even the error codes are the same), the main difference is there are no CALL and WAIT functions. Regular variable names are a letter followed by an optional digit, array variable names are restricted to a single letter. String variables are not supported. Program lines must begin with a number between 1 and 9999, the last line must be END. When entering lines, the "_" character logically erases the previous character (if desired this can be changed to a regular backspace, change the octal 137 value in the top memory page to 10 octal, location 75530 in the 31KW version). Press Esc to abort the line and start over. Lines with valid syntax replace existing lines with the same line numbers. A running program can be aborted by entering S at an input prompt, or by pressing any key while computing.

Operation commands...

These are commands given without a line number.

RUN - runs the program in memory
SCRATCH - erases the program in memory
RENUMBER - renumbers the program, starting at line 10 and incrementing by 10
LIST - lists the entire program
LIST 100 - lists lines from line 100 to the end of the program.
TAPE - load a program from the photo reader (not supported under simh?)
PUNCH - lists the program, and punches a binary version (simh device tty2)
MESG message - sends a message to other users (not possible under simh)
BYE - ends the session (location 101 contains the address to jump to)

Program statements...

These are instructions preceded by a line number which form the program. An error number is displayed if it doesn't understand and the matching line in memory (if it exists) is not affected. Parameters can be simple floating point numbers using standard "E" notation, or expressions of multiple numbers and variables per normal BASIC technique. Supported simple mathematical operations include + - * / and ^ (exponent). When used in expressions, AND OR NOT < > <= >= = and # (not equal) return either 0 or 1 depending on if the expression is true or not. Use parenthesis to force a particular evaluation order. For example PRINT (2*3) + (3#5) prints 7. NOT inverts the logic of the following item. Bit logic is not supported.. i.e PRINT 3 AND 4 prints 1 because both 3 and 4 are not 0.

DIM

Dimensions a one or two dimensional array. The array name must be a single letter, the dimension specifications must be numbers between 1 and 255, not expressions. Subscripts range from 1 to the number of elements dimensioned (or redimensioned by a matrix operation). Multiple arrays can be dimensioned with a single DIM statement, separate with commas. If DIM(specs) is entered the line will be converted to DIM[specs]. Array elements are initially undefined and must be assigned values before using in assignments and calculations.

100 DIM X[100],Y[10,20]
110 DIM Z[255]

LET

Assigns an expression to a variable or array element, variable names must be a single letter optionally followed by a digit. Multiple variables and array elements can be set to the same value on one line, separate with additional = symbols.

100 LET A1=100
110 LET C=A1/10 [C contains 10]
120 DIM B[5,5]
130 LET B[1,1]=C+A1 [element 1,1 of array B contains 110]
140 LET X=Y=Z=5 [X Y Z all set to 5]

COM

Like DIM but does not clear the array, useful for multi-part programs that won't all fit in memory at once and for running existing code. Without a working TAPE command the next part has to be pasted or otherwise uploaded to the console after using the SCRATCH command.

100 COM A[2]
110 LET A[1]=5
120 LET A[2]=10
130 END
RUN

READY
SCRATCH

READY
100 COM A[2]
110 PRINT A[1];A[2]
120 END
RUN
 5 10

PRINT / TAB

Prints an expression and/or quoted text list. Separate list elements with commas to separate into fields or with semicolons to space together. Semicolons are not needed to separate quoted text from numerical data. Numbers always print with a certain field size (adjusted if more room is needed) with the sign in the first position. If the last character is ; then no CRLF is emitted, but if the total line length exceeds 72 characters one will be emitted anyway at the beginning of the line that won't fit. TAB(column) moves to the specified column provided the specified column is greater than the current column, if a numerical expression follows separate with a comma or semicolon, not required for quoted text.

100 LET X=5
110 PRINT "X ="X;TAB(20)"X*2 ="X*2
120 END
RUN
X = 5 X*2 = 10

100 LET A1=2
110 LET A2=-1.41837E-23
120 PRINT "A1 ="A1"NEXT PRINT"
130 PRINT "A2 ="A2"NEXT PRINT"
140 END
RUN
A1 = 2 NEXT PRINT
A2 =-1.41837E-23 NEXT PRINT

INPUT

Obtains entry from the console into a variable or array element. To input multiple values separate the variables by commas, when entering the elements can be separated by commas or entered on separate lines. If non-numeric data is entered it prompts again, if S entered it stops the program.

100 PRINT "ENTER A ";
110 INPUT A
120 PRINT "ENTER B,C ";
130 INPUT B,C
140 PRINT "A*B*C ="A*B*C
150 END
RUN
ENTER A ?5
ENTER B,C ?7,9
A*B*C = 315

DATA / READ / RESTORE

DATA statements provide lists of comma-separated numbers to READ into variables or array elements. Multiple variables can be read with successive data items by separating the variable names with commas. The RESTORE statement moves the read pointer to the beginning of the first data statement.

100 DIM X[4]
110 DATA 1,2,3,4
120 READ A,B,C,D
130 RESTORE
140 READ X[A],X[B],X[C],X[D]
150 PRINT "X[] ="X[1];X[2];X[3];X[4]
160 END
RUN
X[] = 1 2 3 4

IF / THEN

Provides conditional branching.. IF expression THEN line#. If the expression is true (non-zero) then the program continues at the specified line, otherwise drops through to the next line. The expression usually is a condition as in something relation something where relation is < > <= >= = or # (<> is converted to #) with multiple conditions separated by AND or OR, but any valid expression seems to be accepted.

100 LET A=5
110 IF A THEN 150
120 IF NOT (A-5) THEN 160
130 PRINT "BOO!"
140 IF A>4 AND A<6 THEN 120
150 IF A=5 THEN 130
160 END
RUN
BOO!

GOTO

Transfers to a specified line.

100 PRINT "PRESS CTRL-C TO STOP"
110 GOTO 110
120 END
RUN
PRESS CTRL-C TO STOP
[control-C pressed]
STOP

GOSUB / RETURN

GOSUB calls a subroutine, when RETURN is encountered the program continues at the line following the subroutine call.

100 GOSUB 200
110 GOSUB 300
120 GOTO 400
200 PRINT "HELLO ";
210 RETURN
300 PRINT "WORLD"
310 RETURN
400 END
RUN
HELLO WORLD

STOP / END

The last statement of a program must be END, however STOP or END may be used before the end of a program to halt execution. Either one will do, STOP can be used to visually distinguish it from the END line.

FOR / TO / STEP / NEXT

FOR loopvar = expr TO expr [STEP expr] - repeats a group of lines while modifying a loop variable (not an array element). The loop variable is initially set to the expression preceding TO and looping stops when the loop variable exceeds the expression after TO (greater or lesser depending on if stepping backwards). If the loop variable already exceeds the termination expression then the lines are skipped. By default the loop variable is incremented by 1 but other positive or negative increments can be specified by STEP.

100 DIM A[2]
110 LET A[1]=1
120 LET A[2]=5
130 FOR I=A[1] TO A[2]
140 PRINT I;
150 NEXT I
160 PRINT
170 FOR J1=10 TO 1 STEP -2
180 PRINT J1;
190 NEXT J1
200 END
RUN
 1 2 3 4 5
 10 8 6 4 2

MAT

MAT can specify a variety of things depending on what follows...
MAT arrayname = ZER  sets all elements to 0
MAT arrayname = CON  sets all elements to 1
MAT arrayname = IDN  sets a square array with 0 with a diagonal of 1's
MAT array1 = TRN (array2)  transposes dimensions.. [1,2] put in [2,1] etc
MAT array1 = array2  copies array 2 to array 1
MAT array1 = array2 + array3  adds elements of arrays (one-to-one)
MAT array1 = array2 - array3  subtracts elements of arrays (one-to-one)
MAT array1 = array2 * array3  multiplies arrays (by weird rules, see here)
MAT array1 = (expression) * array2  multiplies by expression (one-to-one)
MAT PRINT arrayname  prints all elements of an array
MAT INPUT arrayname  inputs all elements of an array
MAT READ arrayname  reads DATA elements into all elements of an array
Some or these can redimension the array, such as MAT X=ZER [2,2]

100 DIM X[4,4],Y[4,4],Z[4,4]
110 DATA 1,2,3,4
120 DATA 5,6,7,8
130 DATA 8,7,6,5
140 DATA 4,3,2,1
150 MAT READ X
160 MAT Y=TRN(X)
170 MAT Z=(2)*X
180 MAT X=Y+Z
190 MAT Z=X*Y
200 MAT PRINT Z
210 END
RUN
 111 263 231 79

187 467 443 163

163 443 467 187

79 231 263 111

SIN / COS / TAN / ATN / EXP / LOG / SQR / INT / ABS / SGN

Mathematical functions that can be used in expressions, these operate on an expression that follows enclosed in parenthesis. SIN thru ATN are trig functions sine, cosine, tangent and arctangent, which operate in radians. EXP and LOG are base "e" exponent and logarithm. SQR takes a square root. INT rounds down to integer. ABS returns the absolute value, and SGN returns the sign of an expression, -1 0 or 1.

100 PRINT SIN(4)
110 PRINT COS(4)
120 PRINT TAN(4)
130 PRINT ATN(4)
140 PRINT LOG(4)
150 PRINT EXP(4)
160 PRINT SQR(4)
170 PRINT INT(-77.7)
180 PRINT ABS(-1.23)
190 PRINT SGN(-10)
200 END
RUN
-.756803
-.653643
 1.15782
 1.32582
 1.38629
 54.5982
 2
-78
 1.23
-1

DEF FNx

Permits defining custom functions to use in expressions, x=single letter defining the function name which always begins with FN. A variable in parenthesis defines the variable name to use for the context of the definition (doesn't affect existing variables with the same name). After defining, FNx(expression) can be used in other expressions.

100 DEF FNA(X)=X*2+1
110 PRINT FNA(2);FNA(3);FNA(4)
120 END
RUN
 5 7 9

RND

A function that returns a "random" number between 0 and 1. Not really random, the sequence is always the same for each run, and the initial values are a bit jumpy. A parameter is required but doesn't seem to do anything.

100 FOR I=1 TO 5
110 PRINT RND(0)
120 NEXT I
130 PRINT "ENTER SEED";
140 INPUT S
150 FOR I=0 TO S
160 LET N=RND(0)
170 NEXT I
180 FOR I=1 TO 5
190 PRINT RND(0)
200 NEXT I
210 END
RUN
 1.52602E-05
 .500092
 .500412
 1.64799E-03
 6.17992E-03
ENTER SEED?1000
 .263123
 .800767
 .936496
 .912073
 .543973

REM

Adds non-executing remarks, program flow continues to the next line.

100 REM MY GOOFY PROGRAM
110 REM PRESS CONTROL-C TO STOP
120 FOR I=1 TO 72
130 IF RND(0)<.5 THEN 160
140 PRINT "*";
150 GOTO 170
160 PRINT " ";
170 NEXT I
180 PRINT
190 GOTO 120
200 END

Error numbers...

This was extracted and edited from the MSU BASIC "monitor" assembly source.

--------------------------------------------
1 PREMATURE STATEMENT END
2 INPUT EXCEEDS 71 CHARACTERS
3 SYSTEM COMMAND NOT RECOGNIZED
4 NO STATEMENT TYPE FOUND
5
6 NO LETTER WHERE EXPECTED
7 LET STATEMENT HAS NO STORE
8 ILLIGAL COM STATEMENT
9 NO FUNCTION IDENTIFIER (OR BAD)
10 MISSING PARAMETER
11 MISSING ASSIGNMENT OPERATOR
12 MISSING 'THEN'
13 MISSING OR IMPROPER FOR-VARIABLE
14 MISSING 'TO'
15 BAD 'STEP' PART IN FOR STATEMENT
16
17
18 NO CONSTAND WHERE EXPECTED
19 NO VARIABLE WHERE EXPECTED
20 NO CLOSING QUOTE FOR STRING
21 PRINT JUXTAPOSES FORMULAS
22 IMPROPER WORD IN MAT STATEMENT
23 NO COMMA WHERE EXPECTED
24 IMPROPER ARRAY FUNCTION
25 NO SUBSCRIPT WHERE EXPECTED
26 ARRAY INVERSION INTO SELF
27 MISSING MULTIPLICATION OPERATOR
28 IMPROPER ARRAY OPERATOR
29 ARRAY MULTIPLICATION INTO SELF
30 MISSING LEFT PARENTHESIS
31 MISSING RIGHT PARENTHESIS
32 UNRECOGNIZED OPERAND
33 MISSING SUBSCRIPT
34 MISSING ARRAY IDENTIFIER
35 MISSING OR BAD INTEGER
36 CHARACTERS AFTER STATEMENT END
37
38 PHOTO READER NOT READY
39 FUNCTION MULTIPLY DEFINED
40 UNMATCHED FOR STATEMENT
41 UNMATCHED NEXT
42 OUT OF STORAGE-SYMBOL TABLE
43 INCONSISTENT DIMENSIONS
44 [missing END]
45 ARRAY DOUBLE DIMENSIONED
46 NO OF DIMENSIONS UNSPECIFIED
47 ARRAY TOO LARGE
48 OUT OF STORAGE-ARRAY ALLOCATION
49 SUBSCRIPT TOO LARGE
50 UNDEFINED OPERAND ACCESSED
51 NEGATIVE BASE POWERED TO REAL
52 ZERO TO ZERO POWER
53 MISSING STATEMENT
54 GOSUBS NESTED 10 DEEP
55 RETURN FINDS NO ADDRES
56 OUT OF DATA
57 OUT OF STORAGE - EXECUTION
58 RE-DIMENSIONED ARRAY TOO LARGE
59
60 MATRIX UNASSIGNED
61 NEARLY SINGULAR MATRIX
62 ARGUMENT TOO LARGE
63 SQRT HAS NEGATIVE ARGUMENT
64 LOG OF NEGATIVE ARGUMENT
** RECOVERABLE ERRORS FOLLOW **
65 OVERFLOW
66 UNDERFLOW
67 LOG OF ZERO
68 EXPONTIAL OVERFLOW
69 DIVIDE BY ZERO
70 ZERO TO NEGATIVE POWER
--------------------------------------------

100 LET A=1/0
110 PRINT "RECOVERED"
120 LET A=SQR(-1)
130 PRINT "WON'T PRINT"
140 END
RUN

ERR 69:100
RECOVERED

ERR 63:120

140 FOR XX=1 TO 4
ERR 11:140

140 FOR X=1 T 4
ERR 14:140

140 DIM X[255]
140 DIM X[256]
ERR 35:140

Change notes and stuff...

4/19/08 - While running stuff on real hardware (as opposed to super-fast sim) I noticed that pressing any key before a program is ready for input causes the program to end. HP "paper-tape" BASIC does the same thing. Will have to keep that in mind when playing "action" games... get too excited and it's game over.

4/16/08 - Removed individual links and replaced with a directory containing converted and original source. Less stuff to update if something changes. Added conversions for GOLF, GOMOKU and BEASTI.

3/22/08 - Updated the 7906sim.zip package, made a new page for the 7906 disk sim.

3/15/08 - [disk sim notes removed, see above]

3/11/08 - Added conversions of WUMPUS and HAMRBI to the PT BASIC "collection", edited OTHPT to make it somewhat faster by recoding unneeded array variables to regular variables. There are many more candidates for conversion in the HP2000 contributed software archives, available from BitSavers in the /bits/HP/tapes/2000tsb/ directory (the .tar.gz files extract to regular files). Renamed hposgames.zip to absgames.zip to be more descriptive of its content.

3/9/08 - MSU BASIC is closer to paper-tape BASIC than I thought... "discovered" that paper-tape BASIC does support letter/digit variables, not sure how I missed that except for having no docs and assuming that because array variables had to be single letters all variables were that way. Edited docs here and there to correct incorrect information. Looks like I did stuff I didn't have to do when making the OTHPT and TREKPT conversions [...].

3/7/08 - Slightly updated hposutil.abs with UNSHAM for converting octal/ascii binary dumps back into binary code. The "tech" docs included a binary dump for reference, so gotta have a way to recover code printed in such a way, handy way to distribute binaries in text or even PDF files. Moved the trek demo to hposgames.zip to avoid duplication and extra updates. Basically just cleaning it up, same system code as the 3/4 version. Previous code-hacking activity...
2/28 - got the nolog source, found it ran OTHPT and got all excited.
3/1 - got even more excited when the 31KW version ran TREKPT, figured out initial patches.
3/3 - made a HP-IPL/OS build containing MSUPATCH and loading/saving utilities
3/4 - stabilized the msubasic.zip binaries, instructions and stuff (I think...)
... along the way wrote technical docs explaining the patches (in msubasic_tech.zip)

Thanks goes to all who helped to get MSU BASIC running under simulation, without pre-figured out working code this 31KW version wouldn't have happened anytime soon. All I had to do was a bit of editing and studying listings to see what to poke... just a week of part time fun, the hard part was already done.


Page created 3/7/08, main sections last modified 4/19/08, links removed/added 11/26/10
Terry Newton (wtnewton@infionline.net)