TRS-80 Model I Level 2 BASIC Language Reference

TRS-80 Model I Level 2 BASIC Language Reference

By Joe Ganley

The following is republished here, unchanged (other than this line), with permission of Ron Kneusel

This document is in beta release and has been discontinued by its prior author.


		Types and Notation
		Program Structure
		Storage Representations
		Casting Rules
		Commands and Functions
		Utility Functions
		Control Structures
		Error Handling
		Static Data
		Type Declarations
		String Functions
		Math Functions
		Random Number Generation
		Hardware/Assembly Access
		Storage Access
		Keyword Index
		Level 3 Keywords


Types and Notation

Values in TRS-80 Level 2 BASIC may have one of four types: integer, single- or double-precision floating point, or string. Throughout this document, values beginning with I have integer type, values beginning with F have single-precision floating point type, values beginning with D have double-precision floating point type, and values beginning with S have string type. Values beginning with N may have any of the three numeric types. Values beginning with B have integer type and must be in the range 0 to 255, inclusive. Values beginning with L are line numbers, which are integer literals (integer variables cannot be used). Prepending V to a value notation indicates that the name of a variable with the corresponding type is expected; V alone indicates a variable of any type, or of an unspecified type.

The notation “[ stuff ]” indicates that stuff is optional. The notation “{ a | b | … }” indicates that any one of the values indicated is acceptable. The notation * indicates that the quantity it follows can be repeated zero or more times.

Program Structure

Each line in a BASIC program has a line number, which is an integer in the range 0 to 65529, inclusive. The line number from 65530 to 65535 are reserved for system use; e.g., 65535 is used internally to store a line entered directly without a line number. The character “.” gives the current line, i.e. the line at which the program was stopped by a STOP or END command, a user interrupt, or an error. The “.” character can be used anywhere a line number is expected. When a program is executed, its lines are executed in line-number order unless a control command causes the execution order to behave otherwise.

Multiple commands can appear on a single line; these commands are separated from one another by the “:” character.

In addition, commands (or multiple commands separated by “:“) can be entered directly, without a line number. These commands are executed immediately, as soon as the line is completed. Some commands have no effect (e.g. DATA) or do not make sense (e.g. RETURN) when entered without a line number. Other commands (e.g. NEW) are almost always used without a line number.


A numeric variable stores a numeric value of type integer, single, or double. The lexical structure of a numeric variable name is letter {letter | number}* [{ % | ! | # }]. However, only the first two characters of a variable name are significant. Thus, AA, AAA, AAAA, etc. are all considered to be the same variable. The suffix character “%” indicates an integer value, “!” indicates a single, and “#” indicates a double. Variables are dynamically typed unless their type is explicitly specified using one of these suffix characters or a type declaration. Variable names cannot contain any BASIC keyword as a substring. An uninitialized numeric variable is considered to have value 0.

A string variable stores a string value. The lexical structure of a string variable name is letter {letter | number}* $ (i.e. the same as a numeric variable but with $ appended). Like numeric variable names, only the first two characters are significant. As with numeric variables, string variable names cannot contain any BASIC keyword as a substring. Strings are implicitly dynamically allocated and their contents and length can be changed at any time. String length cannot exceed 255. There is no character type; a character is represented by a string of length 1. The empty string “” is a valid string, and has length 0.

In the absence of any type declarations, the name spaces for the four types are all separate, i.e. “A%“, “A!“, “A#“, and “A$” can all have distinct values. The default type of, e.g. “A“, is single.

Storage Representations

Integers are stored in 16-bit, two’s complement format; thus, their range is -32768 to 32767. They are stored little-endian, i.e. the least significant byte is at the lower memory address.

How Floating Point Numbers Are Represented.

String variables’ values are allocated on a heap starting from the highest available memory address and working backward. For each string variable, a three-byte record is stored in the normal variable address space. The first byte contains the length of the string. The second two bytes contain an unsigned, little-endian integer specifying the address a containing the first character in the actual string data. The remaining characters appear contiguously in the next memory addresses above a.

Casting Rules

Casting only applies to numeric types. When a single or double is cast to an integer, the fractional part of the number is truncated. When a double is cast to a single, the value is rounded to the nearest single-precision value (I think).


Mathematical expressions on numeric types are like in most any programming language, with the operators being “+” (addition), “” (subtraction), “*” (multiplication), “/” (division), and up-arrow, denoted “^” in this document (exponentiation), as well as unary “+” and ““, which indicate a number’s sign.

The operators “AND“, “OR“, and “NOT” perform the corresponding bitwise operations on their operands, which are cast to integers.

The relational operators are “<” (less than), “<=” (less than or equal to), “=” (equal to), “&gt=” (greater than or equal to), “&gt” (greater than), and “<>” (not equal to). These are boolean operators, but since there is no boolean type, they return integer 0 (whose bit representation is hexadecimal 0000) for “false” and integer -1 (whose bit representation is hexadecimal FFFF) for “true”. Thus, the bitwise operators “AND“, “OR“, and “NOT” behave as expected on the results of these “boolean” operators.

Finally, the “+” operator with string operands concatenates the right operand onto the end of the left one.

The precedence of the operators is as follows (highest precedence first):
unary + – NOT
* / AND
binary + – OR
< <= = <> &gt= &gt

Commands and Functions

Utility Functions

AUTO [ L1 [ , L2 ] ]

Initiate automatic line numbering. Lines are numbered starting with L1, or 10 if it is absent, and incremented by L2, or 10 if it is absent. Once AUTO has been started, the program produces the appropriate line numbers and waits for the user to enter the code for each. Hitting BREAK on an empty line terminates and returns to the READY prompt. If a line already exists, its line number is followed by a “*“; hitting anything but BREAK at this point replaces the existing line with whatever the user types. If the user hits RETURN on a blank line, the line is deleted.


Clears the screen and returns the cursor to the upper left.


Enters edit mode for a particular line L. In edit mode, the following keystroke commands are available:

  • SPACE moves the cursor one character to the right.
  • BACKSPACE moves the cursor one character to the left.
  • D deletes the character at the current position.
  • ID deletes I characters.
  • I enters insert mode. In insert mode, characters are inserted as they are typed.
  • SHIFT-[ leaves insert mode.
Pressing RETURN ends insert mode, enters the changes made, and returns to the READY prompt. Other EDIT subcommands are under construction

LIST [ L1 ] [ – L2 ]
LLIST [ L1 ] [ – L2 ]

LIST prints the program lines to the screen. It lists line numbers from L1, or the first line if L1 is absent, to L2, or the last line if L2 is absent. LLIST is exactly the same except that the listing is sent to the printer rather than the screen.


Erases all program data and variables currently in memory.


Erases all variables currently in memory. If present, I indicates the amount of space to be allocated for the string heap; otherwise, the default is 50 or 200 bytes (depending on ROM version).

RUN [ L ]

Runs the program starting with line L, or starting with the first line if L is absent.


Turns tracing on or off, respectively. When tracing is on, the line numbers being executed are printed as they are run.


Remark: everything from REM to the end of the line is ignored.


[ LET ] VN = N
[ LET ] VS = S

Assigns N to VN, casting if necessary, or assigns S to VS.


{ PRINT | ? } { X | ; | , } *
LPRINT { X | ; | , } *

PRINT prints zero or more values to the screen. The values denoted X can be anything at all: a variable or literal of any type. The tokens following PRINT are handled in order. For values X, the value of X is printed. If values are separated by “;” or by no separator at all, then the values are printed right next to one another. Each time a “,” is encountered, PRINT tabs over to the next column evenly divisible by 16, moving to the next line if necessary. If a PRINT command ends with “;” or “,“, then the next PRINT command will resume in the position where this one left off, just as though its arguments were appended to the current PRINT command’s arguments. Otherwise, the line is ended by a carriage return, and the next PRINT command will resume at the beginning of the next line. The character “?” can be used as a shorthand for “PRINT“. LPRINT works exactly the same as PRINT except that output is directed to the printer rather than to the screen.

{ PRINT | ? } @ I { X | ; | , } *

Same as PRINT, but starts at screen position I. Screen positions are numbered in row-major order, i.e. the upper left corner is 0, the leftmost position in the second line is 64, and so forth, with the lower right corner at 1023.

TAB ( I )

Tabs to position I on the current line (modulo 64). Has no effect if the current cursor position is right of position I.

PRINT USING S ; { X | ; | , } *

Print the arguments using the format string S. Specifics of S are under construction.

INPUT [ S ; ] V [ , Vn ] *

Prints the value of S, if present, and then prompts the user to enter values, which are assigned to the remaining arguments in order. Multiple values may be entered separated by commas, by hitting RETURN after each, or in any combination of the two.

INKEY$ returns S

If a key is currently pressed, then INKEY$ returns a one-character string containing that key’s value; otherwise, it returns the empty string. The keypress is stored in a buffer which is then flushed without repeat, so if a key is held down, INKEY$ returns its value only once.

POS ( any ) returns I

Returns the current horizontal cursor position, between 0 and 63 inclusive. The argument is ignored, and thus can be any pretty much anything.


SET ( IX , IY )

SET turns on the pixel at position (IX,IY), where 0 <= IX <= 127 and 0 <= IY <= 47. RESET turns off the pixel.

POINT ( IX , IY ) returns I

Returns a nonzero value if pixel (IX,IY) is on, or 0 if it is off.

Control Structures


Jumps to the first command on line L.


The GOSUB command jumps to the first command on line L. A subsequent RETURN command then jumps back to the next command following the most recently executed GOSUB. If at any point the number of RETURN commands executed exceeds the number of GOSUB commands executed, a runtime error is thrown.

ON N GOTO L [ , Ln ] *
ON N GOSUB L [ , Ln ] *

Jumps, with either GOTO or GOSUB semantics, to a line number depending on the value x of the greatest integer less than or equal to N. If x is 1, it jumps to the first line in the list; if x is 2, it jumps to the second line, and so on. If x is 0 or is greater than the length of the list of lines, then the command has no effect and control continues to the next command. If x is negative, then a runtime error is thrown.

IF I THEN commands [ ELSE commands ]

If I evaluates to a nonzero value, then the commands from after the THEN statement to the end of the line or the ELSE keyword (if present) are executed. If commands consists solely of a line number L, then it behaves as if commands were “GOTO L“. If I evaluates to 0, then the same action is performed with the commands or line number from the ELSE to the end of the line.

FOR VN = N1 TO N2 [ STEP N3 ]
NEXT [ VN [ , VNn ] * ]

The first time the FOR statement is hit, VN is set to N1. When the NEXT is hit, the value of VN is incremented by N3, or by 1 if the STEP clause is absent. If the resulting value is less than or equal to N2, then control is transferred back to the statement following the FOR statement; otherwise, control continues to the statement following the NEXT. If the NEXT has no argument, then it is associated with the nearest matching FOR. NEXT VI,VJ is equivalent to NEXT VI:NEXT VJ. It is permissible to modify VN inside the loop. The looping happens at the NEXT, so a FOR with no matching NEXT is equivalent to VN = N1. A NEXT without a matching FOR causes a runtime error.


Stops the program just as if the user had hit BREAK.


Stops the program like STOP, but without the “BREAK IN line” message being printed.


After the user hits BREAK or a STOP or END command is executed, CONT continues program execution. If CONT is executed when the program has not been stopped in one of these ways, a runtime error is thrown.

Error Handling


Once this command is executed, if an error occurs, rather than stopping the program and printing an error message, the interpreter executes a “GOTO L” command. After the GOTO is executed, the variable ERL contains the line number where the error occurred, and the variable ERR contains an integer code for the type of error that occurred. The ERR error codes are as follows:

	Code Abbreviation Error
	  1       NF      NEXT without FOR
	  2       SN      Syntax error
	  3       RG      RETURN without GOSUB
	  4       OD      Out of data
	  5       FC      Illegal function call (e.g. argument type mismatch)
	  6       OV      Numeric overflow
	  7       OM      Out of memory
	  8       UL      Undefined line
	  9       BS      Subscript out of range
	 10       DD      Redimensioned array
	 11       /0      Division by zero
	 12       ID      Illegal direct (can't use INPUT at READY prompt)
	 13       TM      Type mismatch
	 14       OS      Out of string space
	 15       LS      String too long
	 16       ST      String formula too complex
	 17       CN      Can't CONTinue
	 18       NR      No RESUME
	 19       RW      RESUME without error
	 20       UE      Unprintable error (e.g. nested error)
	 21       MO      Missing operand
	 22       FD      Bad file data
	 23       L3      Level 3 (disk) BASIC only

RESUME [ { NEXT | L } ]

After an error is caught, RESUME resumes execution of the program. RESUME with no argument resumes starting with the offending command. RESUME NEXT starts with the command following the offending command. RESUME L starts with line L. A RESUME that is reached other than as the result of an ON ERROR GOTO is an error.

Static Data

DATA value [ , values ] *
READ V , [ Vn } ] *

These commands are used for storing and retrieving static data stored as part of a program’s code. The values in the DATA statement are literals of any type, though string values should be entered without quotation marks. All of the DATA values in a program are indexed from left to right within each statement, and in line-number order throughout the program, and a pointer is maintained to the next item to be read (which is initially the first item in the program). The READ command reads the next DATA item (or items) into the variables specified, and increments the “next item” pointer appropriately. If the variable specified in a READ is a string variable, then the data is read as a string, regardless of its apparent type. If the variable is numeric, then the data is read as a numeric value if possible; if an attempt is made to read a non-numeric data value into a numeric variable, then (rather cryptically) a syntax error is thrown at the line number of the DATA statement. The RESTORE command reinitializes the “next item” pointer to point to the first data item in the program.

Type Declarations

DEFINT V [ – V [ , V [ – V ] ] ] *
DEFSNG V [ – V [ , V [ – V ] ] ] *
DEFDBL V [ – V [ , V [ – V ] ] ] *
DEFSTR V [ – V [ , V [ – V ] ] ] *

Declares one or more variables to be of type integer, single, double, or string, respectively. The hyphen is used for ranges of variables; e.g., A – E is the variables A, B, C, D, and E. Separate variables or separate ranges of variables are separated by commas. Once a variable has been declared to a particular numerical type, assigning a value of another numerical type to it causes the value to be cast to the variable’s type. Ranges of variables only work for single-letter variable names. A variable can be redeclared, but doing so destroys the value it held before the redeclaration if the new type is not the same as the old type. If a variable is declared to be of string type, then the “$” following its name becomes implicit; i.e., If “DEFSTR A” is executed, then henceforth “A” and “A$” both refer to the same string variable.

DIM V ( I )

Declares an array variable V containing I number of elements, which are indexed from 0 to I. The value of an array element is accessed as V(I). If the argument is out of array bounds, a runtime error is thrown. Array variables that are used without declaring them in a DIM statement have dimension 10 by default.

String Functions

ASC ( S ) returns B

Returns the ASCII value of the first character in S.

CHR$ ( B ) returns S

Returns a string consisting of a single character whose ASCII value is B.

LEFT$ ( S1 , I ) returns S2
RIGHT$ ( S1 , I ) returns S2

Returns a string containing, respectively, the leftmost or rightmost I characters in S1.

MID$ ( S1 , I1 , I2 ) returns S2

Returns substring of S1 that starts at index I1 and has length I2.

LEN ( S ) returns I

Returns the length of S.

STR$ ( N ) returns S

Returns the string representation of N, e.g. STR$(3.14) = “3.14”.

VAL ( S ) returns N

Returns the value of S considered as a number, e.g. VAL(“3.14”) = 3.14. If S does not contain a valid number, then VAL returns 0.

STRING$ ( I , S1 ) returns S2

Returns a string of length I, all of whose characters are the first character of S1.

Math Functions

ABS ( N ) returns S

Returns the absolute value of N.

SIN ( N ) returns S
COS ( N ) returns S
TAN ( N ) returns S
ATN ( N ) returns S

Returns the sine, cosine, tangent, or arctangent, respectively, of N.

CINT ( N ) returns I
CSNG ( N ) returns F
CDBL ( N ) returns D

Casts N to integer, single, or double type, respectively (see above for casting rules).

FIX ( N ) returns I

Returns N with the fractional portion truncated, i.e. returns the integer highest in absolute value but nearer to 0 than N.

INT ( N ) returns I

Returns the greatest integer less than or equal to N.

EXP ( N ) returns S

Returns e (approximately 2.71828) raised to the N power.

LOG ( N ) returns S

Returns the natural (base-e) logarithm of N. A runtime error is thrown if N is less than or equal to 0.

SQR ( N ) returns S

Returns the square root of N. A runtime error is thrown if N is less than 0.

Random Number Generation


Seeds the random number generator. The seed is based on the value of the R (refresh) register, which is clocked at a higher rate than the CPU and thus produces a more or less random value.

RND ( I1 ) returns I2 if I1 > 0
RND ( 0 ) returns S

RND(I1), for I1 > 0, returns a pseudorandom integer value I2 such that 1 <= I2 <= I1.
RND(0) returns a pseudorandom single-precision floating-point value S such that 0 < S < 1.

Hardware/Assembly Access

PEEK ( I ) returns B

POKE sets the value of memory location I to B. PEEK returns the value stored in memory location I.

VARPTR ( V ) returns I

Returns the memory address of the variable V. For a numeric variable, this is the actual address of the low-order byte of the number (see above for details on how numbers are stored in memory). For a string variable, the address returned by VARPTR is the address of the three-byte record containing the string’s length and a pointer to its data (see above for details on how strings are stored in memory). Note that position (I – 3) holds the variable’s type (2 for integer, 3 for string, 4 for single, and 8 for double), and positions (I – 2) and (I – 1) hold the first two characters in the variable’s name.

MEM returns I

Returns the amount of memory currently available, in bytes.

FRE ( { V | S | N } ) returns I

Returns the amount of memory currently available for variables of the same type as the argument. If the type of the argument is numeric, then this is the same as MEM. If the type of the argument is string, then this indicates the amount of string heap space available. (The amount of string heap space available can be changed using the CLEAR command.)


Puts the machine in monitor mode, giving a “*?” prompt, from which two commands are available. Entering a filename loads the named assembly-language file from cassette. Entering “/” executes an unconditional jump to the starting address of the last program loaded, or entering “/” followed by an integer I executes an unconditional jump to address I.

USR ( I1 ) returns I2

Calls an assembly-language routine. Prior to calling USR, the address of the routine must be stored (using, e.g., POKE), little-endian, in addresses 16526 and 16527. Within the assembly-language program, “CALL 0A7FH” loads I1 into the HL register pair, and “JP 0A9AH” returns the HL register pair as I2. Note that an assembly-language routine called by USR is only allocated 8 stack entries.

OUT B1 , B2
IN ( B1 ) returns B2

OUT sends the value B2 to expansion interface port number B1. IN returns the value read from port B1 on the expansion interface.

Storage Access


Load a file named S from or save it to cassette, respectively.


Verifies that program S on tape matches the program in memory.

Keyword Index


Level 3 Keywords

Disk systems enhanced the machine’s BASIC to Level 3, storing the routines in RAM and plugging their locations into the jump tables for the appropriate keywords. Thus, a number of Level 3 BASIC keywords are reserved words in Level 2 BASIC, but attempting to use them results in an error. These Level 3 keywords are:
	CLOSE   CMD     CVD     CVI     CVS     DEF     EOF     FIELD   FN
	GET     INSTR   KILL    LINE    LOAD    LOC     LOF     LSET    MERGE
	MKD$    MKI$    MKS$    NAME    OPEN    PUT     RSET    SAVE    TIME$


I am grateful for contributions to this page from James Cameron, Pete Cervasio, Jeff Hunsinger, Gary Katz, Don Moore, and Randy Williams.
Last Modified 23 April 1997
“TRS-80” is a trademark of the Tandy Corporation.
Copyright &#169 1996-97 J. L. Ganley. All rights reserved.

3 thoughts to “TRS-80 Model I Level 2 BASIC Language Reference”

  1. The TRS80 stuff looks great. I’m trying to get a program from 40 years ago into this but I am having some problems.
    Using Windows 7 64 bit and the TRS80 emulator seems to work fine on command line.
    I am trying to redo a very old program that I used on a very much computer (OSI C24P) and have used the Windows text editor to type in hundreds of lines of code. When I try to copy this code into TRS80 BASIC it looks like I’m trying to do this from a cassette at 300 baud.
    The program isn’t all that important, but I would like to get it to work again. I am retired but in these days of pandemic I am trying to school some children in code writing. I thought that your BASIC from decades ago would be a good start.

    I got the program from a book BUSINESS Programming Applications by William Barden. In the late 1970’s I was able to wright code for a spreadsheet that helped me with expense reports.
    In the early 1980’s I was able to wright programs for other techs to deal with not only their expense reports but also with customer location and some customer ‘preferences’.
    So sorry but just trying to get my chops back.
    If I do a program in Windows Notepad and do a control a and then go to sdltrls and do a control z it takes absolutely forever to transfer the file. Once the file is there is there any way that I can capture the file so I don’t have to do the hours long transfer again?

  2. There should be a way to mount disks and do a disk load and a disk save.
    Loading from and saving to cassette is just too slow.

  3. Use trs80gp and simply “Load…” the BASIC text file from the “File” menu.

    You will need to select “All files” from the file-type dropdown for it to show .txt files, but that’s no problem.

    It will load instantly, but with no feedback that it did!

    FYI, there’s an error on this page when it compares Disk BASIC to Level III BASIC. They are NOT the same thing! Disk BASIC didn’t have the advanced graphics commands and worked in different ways.

Leave a Reply

Your email address will not be published. Required fields are marked *