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)