11 888888 000000 222222 111 88 88 00 00 22 22 11 88 88 00 00 22 11 888888 00 00 22222 11 88 88 00 00 22 11 88 88 00 00 22 1111 888888 000000 22222222 TTTTTTTT IIII NN NN YY YY TT II NNN NN YY YY TT II NNNN NN YY YY TT II NN NN NN YYYY TT II NN NNNN YY TT II NN NNN YY TT IIII NN NN YY BBBBBBB AA SSSSSS IIII CCCCCC BB BB AAAA SS SS II CC CC BB BB AA AA SS II CC BBBBBBB AA AA SSSSSS II CC BB BB AAAAAAAA SS II CC BB BB AA AA SS SS II CC CC BBBBBBB AA AA SSSSSS IIII CCCCCC TMSI Tiny BASIC for the 1802 User Manual Copyright (C) 1981 by Technical Micro Systems, Inc. 366 Cloverdale Ann Arbor, MI 48105 (313) 994-0784 3/31/2002: This manual is being provided with the permission of its original author, Lee A. Hart, for historical and educational use. It may be used without charge for any non-commercial purpose. Technical Micro Systems is out of business, so the above address and phone number are not valid. To contact the author, write to Lee A. Hart, 814 8th Ave. N, Sartell MN 56366, or email . TABLE OF CONTENTS 1. INTRODUCTION . . . . . . . . . . . . . . . . . . . . 1 2. OVERVIEW . . . . . . . . . . . . . . . . . . . . . . 2 3. HARDWARE REQUIREMENTS . . . . . . . . . . . . . . . 3 4. INSTALLATION . . . . . . . . . . . . . . . . . . . . 4 5. CHECKOUT . . . . . . . . . . . . . . . . . . . . . . 5 In Case of Difficulty . . . . . . . . . . . . . . 5 6. TINY BASIC . . . . . . . . . . . . . . . . . . . . . 7 The Command Mode . . . . . . . . . . . . . . . . 8 The Execute Mode . . . . . . . . . . . . . . . . 9 Error Messages . . . . . . . . . . . . . . . . . 9 Numbers . . . . . . . . . . . . . . . . . . . . . 9 Variables . . . . . . . . . . . . . . . . . . . . 10 Expressions . . . . . . . . . . . . . . . . . . . 10 Statements . . . . . . . . . . . . . . . . . . . 11 Functions . . . . . . . . . . . . . . . . . . . . 18 7. THE MACHINE-LEVEL MONITOR . . . . . . . . . . . . . 21 Operation . . . . . . . . . . . . . . . . . . . . 21 Examine Memory (?M) . . . . . . . . . . . . . . . 22 Change Memory (!M) . . . . . . . . . . . . . . . 23 Move Memory (?M --- !M) . . . . . . . . . . . . . 24 Examine Registers (?R) . . . . . . . . . . . . . 24 Run Registers ($R) . . . . . . . . . . . . . . . 26 Run Program ($P) . . . . . . . . . . . . . . . . 27 8. INTERNAL OPERATION . . . . . . . . . . . . . . . . . 28 Memory Allocation . . . . . . . . . . . . . . . . 28 Internal BASIC Program Format . . . . . . . . . . 29 Saving a BASIC Program in ROM . . . . . . . . . . 30 Register Usage . . . . . . . . . . . . . . . . . 33 User-Accessible Subroutines . . . . . . . . . . . 34 Writing USR Functions . . . . . . . . . . . . . . 39 USR Function Example . . . . . . . . . . . . . . 40 APPENDICES Serial Terminal Interface . . . . . . . . . . . A-1 ASCII Control Codes . . . . . . . . . . . . . . B-1 Error Message Summary . . . . . . . . . . . . . C-1 Formal Definition of Tiny BASIC . . . . . . . . D-1 ASCII/Decimal/Hex Conversions . . . . . . . . . E-1 Tiny BASIC Memory Map . . . . . . . . . . . . . F-1 Tiny BASIC Assembly Listing . . . . . . . . . . G-1 CHAPTER 1 INTRODUCTION Thank you for your purchase of TMSI(tm) Tiny BASIC. We hope you find it a quick and easy way to get familiar with the BASYS/1 1802 Microcomputer and apply it to simple applications. Tiny BASIC originated with the People's Computer Company, and was written for the COSMAC microprocessor by Tom Pittman of Itty Bitty Computers Company. RCA Corporation funded its development, and it is with their permission that it has been made available. TMSI Tiny BASIC has all the features of regular Tiny BASIC, plus I/O extensions and a powerful machine-level monitor. Programs written in TMSI Tiny BASIC can also be saved in EPROM so that they execute immediately upon power-up. This program has been extensively tested, and we believe it to be free of errors. It does carry our standard 90-day warranty (see warranty statement) so if any errors are found during the first 90 days, we will correct them free of charge. Good documentation is the key to solid, reliable software. Accordingly, it is our policy to supply complete source code listings for all TMSI software. Although it increases our costs, we feel that it makes the program far more useful to you. Please help us continue this policy by respecting our copyright notices. If there are any questions or problems with this product, call or write: TMSI c/o Lee A. Hart 814 8th Avenue North Sartell, MN 56377 (Contact information updated, and valid as of 3/31/2002.) -1- CHAPTER 2 OVERVIEW TMSI Tiny BASIC is a simple, high-level language for the BASYS/1 and other microcomputers based on the RCA "COSMAC" microprocessor. It executes a subset of the popular BASIC language and is unusually easy to learn and use. A line editor is provided to enter programs, and an extensive set of error checks and messages is available for program debugging. For control-oriented applications, TMSI Tiny BASIC has a complete set of I/O commands for controlling the computer's inputs and outputs without machine language programming. A Tiny BASIC program can also be saved in EPROM for dedicated applications. It will then be executed immediately upon power-up or reset, without the need for any operator input (see chapter 8: Internal Operation). All numbers in Tiny BASIC are integers within the range of -32768 to +32767. There are 26 named variables (A-Z), and four math operators (add, subtract, multiply, and divide). Statements include LET, PRINT, INPUT, GOTO, GOSUB, RETURN, IF-THEN, LIST, RUN, and NEW. There are two functions; RND for generating a random number, and USR for linking to machine-language subroutines. For advanced users, a machine-level monitor program is included. Using the monitor, critical functions can be programmed and debugged in machine language, and then called by Tiny BASIC as needed. The monitor can examine, change, and move memory; examine and change CPU register contents; and execute programs with breakpoints. The read and type formats are fully compatible with those used by RCA. TMSI Tiny BASIC is specifically designed to run in very small systems -- consequently, it trades execution speed for low memory requirements. All software is contained in a single 4K byte EPROM (with 1K bytes available for user programs), and the minimum RAM requirement is 256 bytes. A serial ASCII data terminal is needed for user inputs and outputs, using the COSMAC's Q and EF4 I/O pins. Execution speed is quite slow (approximately 5 lines per second at 2 MHz), but adequate for many simple applications. Conventions Tiny BASIC normally uses only upper-case letters. Commands typed in lower-case letters will cause syntax errors. However, lower-case letters can be used in REMarks, comments, and PRINT statements. In this manual, numbers are in decimal unless otherwise noted. means the ASCII "Carriage Return" control code (13 decimal, 0D hex), which is the RETURN or ENTER key on you keyboard. -2- CHAPTER 3 HARDWARE REQUIREMENTS TMSI Tiny BASIC will run in the BASYS/1 microcomputer, or any other COSMAC based system that meets the following minimum requirements: CPU RCA, Hughes, or Solid State Scientific "COSMAC" microprocessor; 1802, 1804, 1805, or 1806. Any clock frequency is acceptable; however, it sets the maximum baud rate for serial communications (see I/O below). MEMORY RAM: 256 bytes minimum, fully decoded and starting at address 1000 (hex). TMSI Tiny BASIC will test for RAM starting at this address, and adapt itself to the amount found. RAM in excess of 256 bytes is used to hold Tiny BASIC programs, so the more RAM, the larger the program. BASIC ROM: One socket for a 27C32 4K byte EPROM, fully decoded at address 0000. EPROM access time is 450nS, which is acceptable for COSMAC systems running at up to 5 MHz. Data in the EPROM is active high (not inverted). Execution should begin at 0000 with P = X = 0. User EPROM (containing user BASIC programs): 1K bytes of space are available in the TMSI Tiny BASIC EPROM for user BASIC programs. Additional EPROMs may be added for larger programs. They must be addressed above the first page of RAM at 1000 (hex), and preferably above all RAM. If a user EPROM is found by TMSI Tiny BASIC after reset, it will be executed immediately as a BASIC program. If a user EPROM is not used or not addressed immediately above RAM, then pull-up resistors to +5v should be used on the data bus to insure that TMSI Tiny BASIC does not mistake a floating data bus for a user EPROM program. I/O User terminal input and output is serial ASCII, using the COSMAC's EF4 and Q pins respectively with a "software UART" program. The baud rate can be from 60 to 2400 baud with a 2 MHz clock; scale proportionately for other CPU clock frequencies. TMSI Tiny BASIC automatically determines the baud rate from the first character received after Reset, which should be a (your RETURN or ENTER key) for full duplex, or (your LINE FEED or control-J key) for half duplex. See Appendix A for a sample RS-232 serial interface circuit. -3- CHAPTER 4 INSTALLATION These instructions are for the TMSI BASYS/1 microcomputer. However, they should serve as a guide for other systems as well. To avoid damaging the parts from static electricity, follow the instructions exactly as given. Then place a check mark in the space provided ( ). ( ) Touch the metal case of crystal Y1 on the BASYS/1 board first to discharge any static potential safely. ( ) U11: Remove the chip at U11 from its socket, and hold it in one hand. With the other hand, pick up the piece of protective foam holding the Tiny BASIC IC. Insert U11 into the back of this piece. Now remove the Tiny BASIC IC, and insert it into socket U11. Be sure to position pin 1 (with the dot) as shown below. ( ) X5: Install jumpers at ____________________________________ pins 1-2, 3-14, 6-12, / | | \ and 8-10 (configures | | P2 | | U11 for a 27C32 EPROM). | |::::::::::::::::::::| | .-----------------. | `--------------------' | | O O O O O O O O | | .-----. .----. .--------. .--..--. | | | | | | | |.U3 | |.U9 | |.U17 | U25|U26| | X5 > _ | \ \ | | `-----' `----' `--------' `--'`--' | | | | | | | | | .-----. .-----. .--------. .-----. | | O O O O O O O O | | |.U2 | |.U8 | |.U16 | |.U24 | | `-----------------' | `-----' `-----' `--------' `-----' | ( ) XD2: Install five diode | .----------------. .------. .-----. | jumpers as shown (A= | | | |.U15 | |.U23 | | anode, C=cathode). Puts | | BREADBOARD | `------' `-----' | RAM at 1000-17FF (hex). | | AREA | .------. .-----. | .-------------------. | | | |.U14 | |.U22 | | | O O O O O O O O O | | | | `------' `-----' | | | | \ \ \ | | `----------------'.------. .---. | XD2 \ C A C A C | | .------. .----. |.U13 | |.X6| | / A C A C A | | |.XD2 | |.X3 | `------' `---' | | \ | | | | | | `------' `----' .------. .-----. | | O O O O O O O O O | | .------. .-----. |.U12 | |.X5 | | `-------------------' | |.XD1 | |.U7 | `------' `-----' | ( ) XD1: Install four diode | ------ ----- .---------. | jumpers as shown. Puts | .-----. .------. | | .-----. | BASIC at 0-0FFF (hex). | |.U1 | |.U6 | | | |.U21 | | .-------------------. | `-----' `------' |.U11 | `-----' | | O O O O O O O O O | | `---------' | | \ \ \ \ | | .------------------. .----. | XD1 \ A C A C | | | | | | |.U20| | / C A C A | | .----. | | `----' | | | | | | | | | | |.U5 |D20 | | O O O O O O O O O | | | Y1 | `------------------' .-----. | `-------------------' | | |.-----. .-----. .-----.|.U19 | | ( ) D20: If diode D20 is | `----'|.U4 | |.U10 | |.U18 |`-----' | installed, remove it. |__ `-----' `-----' `-----' __| | P1 | This completes installation | |||||||||||||||||||||||||||||| | of the TMSI Tiny BASIC EPROM. |_||||||||||||||||||||||||||||||_| -4- CHAPTER 5 CHECKOUT Re-install the BASYS/1 board in its cabinet, and connect it to a serial RS-232 or current-loop terminal. Appendix A gives a sample circuit for non-BASYS systems. Set the terminal for 300 baud, 8 data bits, no parity, 2 stop bits, and full duplex. Turn on the computer and reset it. There should be no response displayed on the terminal. Now push your or key. The computer will echo the Carriage Return, then print a Line Feed, and the message "NEW?". Respond by typing "Y" for yes, and then the key. This tells Tiny BASIC to start with a new program. Tiny BASIC will clear any old programs in memory, and print a ":" (colon) to indicate that it is ready for a BASIC statement or command. Type "PRINT 2+2" and then the key. Tiny BASIC will respond by printing "4". It's alive! This completes the initial checkout procedure. In Case of Difficulty Check the following list of problems, and their possible causes. If the symptoms of your problem are not on the list, your you are unable to fix the problem, please write or call Customer Service, and we'll do our best to help. 1. No response -- terminal prints nothing at all. a. No input at EF4 from keyboard. Check the voltage at pin 21 of the COSMAC (U5). It should be low (<0.5 volts) when no key is pressed, and high (>4 volts) when the key is pressed or the terminal is turned off or disconnected. b. Q output not reaching terminal. Check the voltage between pins 5 and 4 of opto-coupler U25. When no key is pressed, pin 5 should be +0.5v to +1.5v above pin 4 (i.e. the opto-coupler is "on". When keys are typed and the computer echoes them (try typing a "repeat+" or "repeat+control+shift+L"), the opto-coupler will turn "off" during each character, and the voltage between pins 5 and 4 will be close to (V+)-(V-) (P2 pin 36 and P2 pin 35 respectively). c. Tiny BASIC EPROM not addressed at 0000 (hex). Check the address decoding. On BASYS/1, there should be four diodes in XD1, all installed at an angle (not straight across the socket). See Chapter 4: INSTALLATION for details. d. No RAM at 1000 (hex). Check the address decoding. On BASYS/1, diodes D14, D15, D16, and D18 should be installed at an angle in XD2, and D17 should be straight across XD2. See Chapter 4: INSTALLATION for details. -5- e. Baud rate too high. Be sure the baud rate is not above 1200 baud if a 2 MHz CPU clock is used, or a proportionate rate for lower clock frequencies. 2. Tiny BASIC types "!(number) AT#(number)". a. A second user EPROM or write-protected RAM was found that does not contain a valid BASIC program. Disable or remove the EPROM, or write-enable the RAM. If this is not easily done, type "A=USR(2552)" and the key to jump to the monitor program. Then type a second to set the baud rate. The message "NEW?" will appear, to which you should type another . Tiny BASIC will now ignore the EPROM and start again. b. Write-protected RAM or partially-decoded images of the Tiny BASIC EPROM appear in the memory map. Memory should be fully decoded for TMSI Tiny BASIC. If not possible, BASIC will improperly size RAM and won't be able to find and run user programs in EPROMs. 3. Terminal prints several characters of nonsense. a. Terminal baud rate is too high, so an error message is being printed but is unreadable. Before you type the first , Tiny BASIC does not know your baud rate, and so assumes 300 baud and a 2 MHz clock. Also, the opto-couplers used for the serial interface are not particularly fast; they will limit the baud rate to about 2400 baud maximum no matter how fast the COSMAC's clock speed is. Select a lower baud rate, and correct the problem as in 2b above. b. Serial output is inverted, or not working properly. See 1a and 1b above. c. Terminal has parity enabled, or is not ASCII (Baudot, EBCDIC, etc.). Disable parity and try again. -6- CHAPTER 6 OPERATION When power is first applied or whenever the computer is Reset, TMSI Tiny BASIC searches for a user's program in the EPROM. If one is found, it is executed immediately, and all further actions are controlled by that program. If no user program is found in the EPROM, TMSI Tiny BASIC waits for you to type a key so it can determine the baud rate and echo status. Press the key for full duplex (so all serial inputs will be echoed as received), or the for half duplex operation (so keys you type are not echoed, because your terminal prints them directly by itself). TMSI Tiny BASIC will then print "NEW?" to ask if you want to begin with a new BASIC program (a "cold start"), or continue with one already in memory (a "warm start"). Type "Y" for yes, or "N" for no, and follow either response with the key. If you answer "yes", Tiny BASIC will test RAM and adapt itself to use the full amount available. The RAM test checks every location above 1100 (hex) and can serve as a simple confidence test to find bad bits or addressing problems. Tiny BASIC now copies the initial values of its control parameters from the EPROM to RAM, where they can easily be examined or changed. See Appendix B for the location and function of these parameters. The program space is now defined as "empty", and BASIC prints its command-mode prompt ":" and is ready for use. If you answer "no", Tiny BASIC assumes that RAM has already been sized, the control parameters already moved, and that RAM contains a valid BASIC program. Therefore, there must have been at least one previous "NEW" since power-up to do this initialization. Everything is left as-is, and BASIC signs on with its command-mode ":" prompt and is ready for use. All inputs to Tiny BASIC are held in a 72-character buffer until the final key is typed. Excess characters will be ignored, and signaled by ringing the terminal's bell. When the final is typed, Tiny BASIC responds with a and then processes the line. When finished, it again types its ":" prompt and is ready for the next line. If you make a mistake when typing a line, there are two ways to correct it before the final key. First, you can "rubout" the error one key at a time. As supplied, this is the key on most keyboards; ASCII code 08 (hex). Second, you can "cancel" the entire line. As supplied, this is this is the Control-X key on most keyboards; ASCII code 18 (hex). Both of these codes can be changed to suit your preferences (see Appendix B: ASCII Control Codes). -7- Tiny BASIC provides one more control function, useful for loading programs from a cassette recorder or paper tape reader that transmits its data continuously without stopping. If a line feed is received, all outputs from BASIC itself are disabled (prompts and program outputs; echoed inputs are not affected). BASIC can then receive data continuously without pausing to type a prompt or other data. Normal printing is restored by an X-OFF character (ASCII DC3, code 13 hex, control-S), or by any action that returns BASIC to the Command mode. The Command Mode When BASIC is not running a BASIC program, it is in the "immediate" or command mode, and types a colon ":" on the left margin. You may type in any BASIC statement, with or without a line number. If a line number is included, it will be inserted into the present program at the appropriate place without further action. Any previous line with the same number is deleted. If the line contains the line number only (a blank line), that line will be deleted from the program. 0 is not a valid line number. Tiny BASIC ignores blanks, so they may be used where desired to improve readability. However, after the first non-blank non-numeric character in the line, all blanks will be saved in memory. The following are all valid lines with line numbers. 10 PRINT "HELLO" 2 0 PRINT "THIS IS LINE #20" 10 3 0 P R I N T " S P A C E S " 1PRINT"smallest line number" 32767 PRINT "largest line number" 12345 Tiny BASIC ignores the contents of a line at insertion If the input line does not start with a line number, then it will be considered an immediate command and will be executed. The following is a list of the valid commands. They will be explained in more detail in the following pages: IF ... THEN GOSUB REM INPUT GOTO NEW PRINT RETURN LIST LET END RUN Note that all twelve of these can be used in the command mode (without a line number) or as statements within a BASIC program (with a line number). They all work the same as commands and program statements except INPUT and RUN, which behave slightly differently. Although it does not make much sense to use RUN or NEW in a program, they are still legal statements. Similarly, using GOSUB in the command mode will work, but will cause an error stop when the corresponding RETURN is executed because there is no program to return to. -8- The Execute Mode Once a BASIC program has been loaded into memory, it can be executed by simply typing "RUN". Tiny BASIC then enters the Execute mode. Execution begins at the first (lowest) line number, and continues from there. BASIC will return to the Command mode when a) the program executes an END statement, b) an error condition is detected (see below), or c) the user stops the program by hitting the terminals BREAK key (or by repeatedly hitting any other key). In the latter two cases, BASIC will print an error message indicating the cause of the halt, and the line number on which it occurred. Error Messages Tiny BASIC checks each line for errors when it is executed. An immediate command (typed without a line number) is thus checked for errors immediately after the final is typed. If there is an error on the line (mis-spelled keyword, divide by 0, etc.) BASIC prints an error message of the form: !number where "number" is a number indicating the type of error. For example, "!243" indicates an attempt to divide by zero. A list of the error numbers and their meanings is given in Appendix C. Lines typed with a line number are entered into the program space exactly as typed. They will be checked for errors only when executed as part of a BASIC program. Thus lines of miscellaneous data, comments, instructions, or plain text can be entered, edited, and listed by Tiny BASIC. Errors found during execution of a BASIC program print an error message of the form: !number AT#line and Tiny BASIC halts and returns to the command mode. "Number" is the error number as above, and "line" is the line number in the BASIC program in which the error occurred. Numbers A number in Tiny BASIC is any sequence of decimal digits (0-9) optionally preceded by a sign (+ or -). If no sign is used, the number is assumed to be positive. Tiny BASIC stores numbers as 16-bit signed integers. This limits them to the range of +32767 to -32768 inclusive. You can enter numbers outside this range, but they will be truncated modulo 65536 (=2^16). In effect, Tiny BASIC will repetitively add or subtract 65536 to your number until it is between -32768 and +32767 (inclusive). Blanks have no significance within numbers and are ignored. -9- Similarly, leading zeros will be ignored. The following are examples of valid numbers. The comments in parentheses show the effect of truncation for numbers that are too large or too small. 1 123 (assumed positive) +123 -123 1 2 3 (same as 123) 000123 +32767 (the largest positive number) -32768 (the largest negative number) 32768 (32768 - 65536 = -32768) 65600 (65600 - 65536 = 64) -100000 ( -100000 + 65536 + 65536 = 31072) Variables There are 26 variables in Tiny BASIC, each represented by a single capital letter A-Z. Each variable is assigned a 2-byte location in memory. The value of the variable is the contents of that location, which can be any valid number (i.e. an integer from -32768 to +32767). Expressions An Expression is a combination of one or more numbers, variables, and math operators that can be evaluated to a single value. For example, the expression 2+2 evaluates to 4. The math operators are: + add - subtract * multiply / divide Tiny BASIC follows the normal rules of precedence for mathematics. Expressions are evaluated from left to right, performing all multiplications and divisions, and then all additions and subtractions. For example, in the expression: 2+3*4+5 (=29) the multiplication is done first (3*4=12), then the left addition (2+12=14), and finally the right addition (14+5=19). Parentheses may be used to alter the order of evaluation. Anything in parentheses will be evaluated first. Parentheses may be nested as needed. For example, if the above expression was instead written as: (2+3)*(4+5) (=45) then the left addition would be performed first (2+3=5), then the right addition (4+5=9), and the multiplication last (5*9=45). -10- Spaces are ignored in expressions. Tiny BASIC does not check for arithmetic overflows. However, an attempt to divide by zero will result in an error stop. The following are examples of valid expressions: A 123 1+2-3 B-14*C (A+B)/(C+D) -128 / ( -32768 + (E*E) ) (((((Q))))) All expressions are evaluated as modulo 65536 integers. This means that the intermediate results from every addition, subtraction, multiplication, and division are all truncated to 16 bits. Thus an expression like (N/P*P) may not equal N because the remainder following the division is lost. In fact, this characteristic can be used to determine if a number N is an exact multiple of another number P. If so, then N/P*P=N. Any number in the range 32768 to 65535 (2^15 to 2^16-1) becomes a binary number with a sign bit of "1", and so is treated as NEGATIVE by Tiny BASIC, i.e. as if 65536 were subtracted from it. Thus the following expressions all produce the same result: -4096 -4096+65536 -8193/2 15*4096 32768/8 30720+30720 Statements A tiny BASIC statement begins with a keyword, such as REM or LET, indicating the type of statement. The function of the rest of the statement depends on the keyword, as defined below. Some keywords also have abbreviated forms to save typing and save space in memory. The REM statement REM This is a remark The REM statement permits comments to be placed in a BASIC program. Everything from the REM to the end of the line will be ignored. REM statements have no effect on program execution except for the time it takes to skip over it. -11- The LET Statement LET variable=expression variable=expression The keyword LET assigns the value of the expression to the variable. Optionally, the LET may be eliminated entirely to save memory. However, execution is faster if it is included. The following are example of the LET statement: LET X=1 X=1 LET A=(B+C)/2 The PRINT Statement PRINT printlist PR printlist This statement prints the values of the items in the printlist on the user's terminal or output device. PRINT can be abbreviated by PR to save memory. The items in the printlist can be numbers, variables, expressions, or quoted messages, as long as the printed line does not exceed 125 characters. Items in the printlist are separated by ";" (semicolons) or "," (commas). A semicolon between items causes them to be printed with no intervening spaces. If an item is preceded by a comma, it will begin printing at the next "tab stop". Tab stops are set automatically every 8 spaces. The following are examples of valid PRINT statements and the printed output they produce (assuming A=1 and B=2). STATEMENT PRINTED OUTPUT --------- -------------- PRINT (prints a blank line) PRINT 123 123 PR 1,2,3 1 2 3 PR "HELLO" HELLO PR"The answer is ";2+2 The answer is 4 PR "A=";A,"B=";B A=1 B=2 A PRINT statement normally ends with a (Carriage Return and Line Feed) ready for the next line. But if a PRINT statement ends with a comma "," or semicolon ";", the ending sequence is not sent. Subsequent PRINT or INPUT statements (see next section) can then continue printing on the same line. A PRINT statement can also be ended with a colon ":". The colon sends an X-OFF control character (ASCII DC3, code 13 hex, control-S) just before the final sequence. This can be used to control a mass storage device, or to prepare data for later input to other Tiny BASIC programs. -12- The INPUT Statement INPUT inputlist IN inputlist The INPUT statement lets the program get information from the user, and assign it to the variables in the inputlist. It may be abbreviated by IN. Normally, the Tiny BASIC line buffer is empty (i.e. the last keyboard input was fully processed). In this case, INPUT prints a question mark "?", a space, and an X-ON control character (ASCII DC1, code 11 hex, control-Q) to indicate that it is expecting data. The user responds by typing a line of one or more expressions, separated by commas "," and ending with a Carriage Return . BASIC evaluates each expression, and assigns its value to successive variables in the inputlist. Consider the following examples. STATEMENT USER TYPES ACTION --------- ---------- ------ INPUT A ? 2+2 sets A=4 IN A,B,C ? 4,A,A+B sets A=4, B=4, and C=8 If the user enters fewer expressions than there are variables in the inputlist, a new "?" will be printed to ask for more data. If the number of expressions is greater than the number of inputlist variables, the leftover expressions will be saved in the line buffer for subsequent INPUT statements. If there is data in the line buffer when INPUT begins, it uses that information first (before typing a "?"). Each expression is in turn evaluated, removed from the buffer, and assigned to the next inputlist variable as described above. If there are enough expressions to satisfy the inputlist, no "?" prompt will be issued; otherwise a "?" will be printed to request the additional expressions needed. Warning: Misalignment between expressions and inputlist variables can cause program bugs that are very difficult to locate -- match them carefully! STATEMENT USER TYPES ACTION --------- ---------- ------ INPUT A,B ? 2 sets A=2 ? 3 2nd "?" prompt; sets B=3 IN A ? 2,3 sets A=2, save 3 for next IN IN B no "?" prompt; sets B=3 Blanks are ignored as usual within input responses. The Backspace and Cancel functions also work normally for correcting errors as long as they are used before the final . There is no defined escape from an input request, but an invalid expression (such as divide-by-zero, a pair of commas, etc.) will result in an error stop. INPUT operates somewhat differently in the command mode if the inputlist has more than one variable. This is because the line -13- buffer contains BOTH the INPUT statement itself and the expression being input. For example, if you type INPUT A,B in the command mode (no line number), Tiny BASIC first removes the first part of the statement (INPUT A) and executes it. But when it looks at the line buffer again, it finds the rest of the statement (,B). So it evaluates it as input data for the INPUT A statement, and sets A=B. The IF Statement IF expression1 relation expression2 THEN statement IF expression1 relation expression2 statement The IF statement computes the value of the two expressions, and compares them. If the relation specified is TRUE, then the statement is executed. Otherwise, the statement is skipped. The word THEN is optional, and may be omitted. The relation operators are: = equal < less than > greater than <= less than or equal (i.e. not greater than) >= greater than or equal (i.e. not less than) <> or >< not equal (i.e. greater than or less than) Note that the statement following IF can be any valid Tiny BASIC statement, including another IF statement. The following are valid IF statements. IF A=25 THEN LET B=0 IF A>B PRINT A,B IF A>0 THEN IF A<10 PRINT A (prints A only if 1-9) IF N/P*P=N PRINT "NO REMAINDER" -14- The GOTO Statement GOTO expression Tiny BASIC normally executes a program in ascending statement number order. The GOTO statement permits changing this order. The next statement executed after a GOTO is the one specified by the value of the expression. Since the expression can include variables, the new line number can be a computed value. GOTO is quite useful within IF statements to make the program loop or branch. GO TO 100 GOTO 200+A IF A=0 GOTO 100 If the value of the expression is zero, negative, or a non-existent line number, an error stop will result. If a GOTO is typed in the command mode (without a beginning line number), the program will begin executing at the specified line number instead of at the beginning. This is useful for resuming execution of a program halted by an error stop after correcting the error. The GOSBUB Statement GOSUB expression The GOSUB statement is like the GOTO statement, except that the value of the expression in the GOSUB is saved before going to that line number. The next occurrence of a RETURN statement (described below) restores this saved line number, and execution continues with the statement following the GOSUB. The series of statements called by the GOSUB and ending in RETURN is called a "subroutine". Subroutines may include GOSUBs of their own, and such GOSUBs can be nested to any depth, limited only by the available memory. The following examples all call a subroutine starting at line 100. GO SUB 100 GOSUB 50*2 GOSUB A (where A=100) An error stop will result if the line number given by the expression is negative, zero, or does not exist. GOSUB may be typed in the command mode, but may produce an error stop when the corresponding RETURN is executed because there is no line number to return to. -15- The RETURN Statement RETURN RET The RETURN statement (which can be abbreviated as RET) transfers execution to the line following the most recent unused line number saved by a GOSUB statement (see above). If there is no matching GOSUB line number saved, an error stop results. A subroutine is a sub-program which consists of several statements that are used in two or more places in the main program. Rather than duplicating the statements each time they are needed, they are entered only once, and end with a RETURN statement. The subroutine can then be called from any number of places by GOSUBs. The following subroutine is called with a GOSUB 100. It will increment A, print it, and return to the caller. 100 LET A=A+1 110 PRINT A 120 RETURN The END Statement END The END statement should be the last one executed in a program. It halts program execution and returns BASIC to the command mode. There may be as many END statements in the program as desired. The LIST Statement LIST LIST expression LIST expression, expression The LIST statement is used to list part or all of the user program in memory. LIST may used alone, or may be followed by one or two expressions. Used alone, LIST will print the entire program. If one expression is given, it is evaluated to form a line number. LIST then prints this line of the program if it exists. If two expressions are given, they are evaluated and LIST prints the program lines between the two values (inclusive). If the last expression in a LIST statement evaluates to a number for which there is no line, the next line above that line number is listed as the last line. Zero is not a valid line number, and an error stop will result if it is used. The following are valid LIST statements. LIST LIST 100 LIST 50*2 LIST 100,200 (lists lines 100 to 200) LIST 500,400 (lists nothing) -16- LIST is normally used in the command mode (without a line number). It can also be used within a program to list large blocks of text instead of PRINT statements, although it will of course include line numbers. A listing may be terminated early with the BREAK key. The format used by LIST can be recorded on the terminal's mass storage device, and subsequently reloaded by BASIC. The NEW Statement NEW The NEW statement clears the current program from memory, sizes memory, and initializes the CPU registers. It is in effect a "cold start", and should be used before entering a new program. NEW is normally used in command mode (without a line number). If used within a program, the program will commit "suicide" and erase itself when the NEW statement is executed. The RUN Statement RUN RUN, expression The RUN statement is used to begin program execution at the first (lowest) line number. RUN may be followed by one or more expressions, separated by commas. These expressions are saved in the line buffer as the initial input line. When an INPUT statement is executed, it will first check the line buffer; if there is anything in it, it will be used first (see INPUT). RUN RUN,1,2 (line buffer contains "1,2") RUN is normally used in the command mode. If used within a program, RUN works as a GOTO the first line of a program. -17- FUNCTIONS Tiny BASIC has two intrinsic functions: RND for generating a random number, and USR for calling a machine-language subroutine. Each function returns a single value, and can be used in any expression in place of a number or variable. The RND Function RND (lowerlimit, upperlimit) RND generates a positive random number between the specified lowerlimit and upperlimit (inclusive). Both limits can be expressions if desired. The limits must be 0 <= lowerlimit <= upperlimit <= 32767 or an error stop will result. The following examples generate a random number between 1 and 100 (inclusive). PRINT RND(1,100) LET A=RND(1,2*50) The USR Function USR (address) USR (address, expression1) USR (address, expression1, expression2) The USR function calls a machine-language subroutine at the specified address, and optionally passes it the values of one or two expressions. The subroutine can return a 16-bit number, which becomes the value of the USR function. The three arguments in parentheses can be any valid Tiny BASIC expression. A number of pre-defined USR functions are included to read and write data to memory, I/O ports, the keyboard, or the display. The user can also call the machine-level monitor program, IDIOT/4 (described in the next chapter). The monitor can be used to extend Tiny BASIC with additional machine-language USR functions as described in Chapter 8: Internal Operation. USR (6) Read Character Reads one ASCII character from the keyboard or other serial input device, and returns its decimal equivalent. Example: LET C=USR(6) sets C=65 if the user types the letter "A". USR (9,0,n) Print Character Prints the ASCII character specified by "n" to the screen or other serial output device. Only the lower 8 bits of "n" are used. The second expression (=0) is ignored. The value returned to BASIC is always 251. Example: C=C+0*USR(9,C,C) If C=65 (ASCII "A"), this prints an "A" and leaves the value of C unchanged. -18- USR (20,a) Memory Peek Returns the decimal value of the byte in decimal memory address "a". Since the most significant bit of Tiny BASIC numbers is the sign, positive values of "a" are addresses from 0000-7FFF hex, and negative values are addresses from 8000-FFFF hex. Example: PRINT USR(20,12) reads decimal address 12 (=000C hex), which contains the value 192 (=C0 hex); thus this statement prints 192. USR (24,a,b) Memory Poke Writes the decimal value of the lower 8 bits of expression "b" in decimal memory address "a" and returns the value of expression "b". LET A=USR(24,4115,24) writes the ASCII code 24 decimal (=18 hex) into memory address 4115 (=1013 hex), and sets A=24. USR (32) Call IDIOT/4 Monitor Calls the machine-level monitor program. The "*" prompt will be printed, and the monitor commands will then be available. The monitor saves the contents of all CPU registers; you can restore them and return to Tiny BASIC with the monitor command $R23 . USR (35,n,m) Read/Write COSMAC I/O Pins Returns the status of the COSMAC EF1-4 or Q pin selected by "n", and optionally sets or resets Q according to the value of "m". n=0 returns 0 if Q=0, 1 if Q=1 =1 " 0 if EF1=1, 1 if EF1=0 =2 " 0 if EF2=1, 1 if EF2=0 =3 " 0 if EF3=1, 1 if EF3=0 =4 " 0 if EF4=1, 1 if EF4=0 m=0 leaves Q unchanged =1 sets Q=1 =-1 resets Q=0 (m=any value but 0 or 1) Note that the physical EF1-4 pins on the COSMAC are active LOW (a low level on the pin sets the corresponding flag high). Only the lower 8 bits of "m" and "n" are used. Values of "n" other than 0-4 always return 1. Values of "m" other than 0 or 1 will reset Q=0. -19- USR (38,a) Read Input Port For "a"=9 to 15, read the corresponding COSMAC input port (IN1-IN7), and return its decimal value (0-255). The lowest 4 bits of "a" specifies which input port to read according to the following code: a=9 reads IN1 =10 " IN2 =11 " IN3 =12 " IN4 =13 " IN5 =14 " IN6 =15 " IN7 For example: A=USR(38,11) sets A to the decimal value of input port IN3. USR(38,a,b) Write to Output Port For "a"=1 to 7, output the value of the lower 8 bits of expression "b" (0-255) to output port OUT1-OUT7. For example, A=A+0*USR(38,3,10) outputs 10 (0A hex) to output port 3. The value of A is not changed. Note that Tiny BASIC treats all numbers as decimal. Most machine language and hardware devices use hexadecimal or binary notation. Machine language opcodes, memory addresses, and I/O port values in hexadecimal must be converted to decimal for use by Tiny BASIC. For example, to call a machine language subroutine at address 0020 hex, you must use its decimal equivalent, 32. Similarly, address FFB5 hex is 65461 decimal; since 65461 is larger than 32767 (Tiny BASIC's maximum positive integer), subtract 65636 to get -75 (i.e. -75 in Tiny BASIC represents FFB5 in hexadecimal). Single-byte (8-bit) hexadecimal numbers should be represented by positive numbers from 0-255 in decimal. 4-bit numbers 0-F hex are represented by positive numbers from 0-15 decimal. The printable ASCII characters are represented by decimal numbers from 32-127. ASCII control codes include Null=0, Backspace=8, LineFeed=10 (0A hex), and Carriage Return=13 (0D hex). Conversion charts are given for converting between decimal, hexadecimal, and ASCII in Appendix E. -20- CHAPTER 7 THE MACHINE-LEVEL MONITOR While many applications can be programmed completely in Tiny BASIC, there will be some tasks that need higher performance. In such cases, some or all of the program can be written in machine language using the machine-level monitor program IDIOT/4. Machine language offers great flexibility and much faster program execution, at the expense of being much harder to write and debug. To use the monitor properly, you will need a good working knowledge of the COSMAC microprocessor and its instruction set. You should also have a copy of the RCA "User Manual for the CDP1802 COSMAC Microprocessor", publication MPM-201, available from RCA or TMSI. The IDIOT/4 monitor provides direct access to the COSMAC microprocessor and all system memory and I/O. You can examine and change the contents of memory, CPU registers, and I/O bits EF1-4 and Q; load and dump programs to your terminal or mass-storage media (paper tape, cassette, etc.); block move memory contents from one place to another, and run and debug programs with or without breakpoints. The command and data formats are the same as used by RCA's UT4-UT20 series monitor programs. IDIOT/4 can also be used the RCA Editor and Assembler software for more advanced applications. Operation There are three ways to enter the monitor. To enter from Tiny BASIC, use the USR(32) function in a command or program statement; (for example, "PRINT USR(32)". From a machine language program, call the monitor with a "SEP R1" instruction (hex D1). Finally, if interrupts are enabled, you can call the monitor with a hardware interrupt (by pulling the COSMAC's INTERRUPT pin 36 low with a pushbutton switch for example). In each case, the monitor first saves a copy of all CPU registers and I/O bits EF1-4 and Q in RAM. All registers are saved correctly except T (and possibly P and X as described later in the IDIOT Monitor Summary). The monitor then types its "*" prompt and is ready for your commands. Commands consist of a punctuation character (?, !, or $) followed immediately by a letter (M, P, or R). All other characters will be printed on your terminal, but otherwise ignored. This feature lets you type in messages, comments, or text for documentation purposes, or just to check the terminal-to-computer I/O interface. The commands to IDIOT/4 are ?M (examine memory), !M (change memory), ?R (examine registers), $R (run registers), and $P (run program). All numbers are in hexadecimal, and leading zeros are unnecessary. -21- Spaces, line feeds, etc. can be used where not ambiguous to improve readability. If the monitor detects a syntax error, it aborts the command and types a "?" to indicate that it didn't understand it. Commands are executed as they are typed in, so the "rubout" or "backspace" keys cannot be used to correct errors. When a command has been correctly executed, the monitor again types its "*" prompt and is ready for the next command. Examine Memory Command ?Maaaa nnnn The "?M" command lists the contents of "nnnn" bytes of memory starting at address "aaaa". Following the , the monitor types the address as 4 hex digits, and then up to 16 data bytes of memory. The data bytes are paired into 2-byte (4-digit) groups. A new line is started every 16 bytes, with a semicolon ";" at the end of the line to indicate that the listing is continued on the next line. A final "*" indicates the end. Examples: ?M20 3 (user types) 0020 C006 6F (monitor prints) ?M240023 4 (oops! corrected 0024 by typing 0023) 0023 C0 0BFE (monitor prints) ?M26 4Z (syntax error; 4Z isn't hex) ? (monitor prints "?" to indicate error) ?M0000 20 0000 7100 E4C0 0800 C009 40C0 09A4 C006 665F; 0010 1882 8020 97BA 48D5 58D5 0679 1100 0010 All numbers are in hexadecimal. Leading zeros are unnecessary. If more than 4 digits are typed for the address or byte count, only the last 4 are used; thus you can correct an error by simply following it with the correct number. For instance, the second example shows address 0024 was corrected to 0023. A long listing can be aborted by hitting your terminal's BREAK (or any other key repeatedly. The format used by ?M is suitable for saving data on your terminal's mass storage facility (paper tape, cassette, etc.). Before typing the final , turn on your punch or recorder. The monitor will ignore any spaces, nulls, or text you type as a header. Then type the final and the monitor will start outputting data. The resulting tape can then be used by the !M command to load memory. -22- Change Memory Command !Maaaa dd .... dd !Maaaa dd .... dd, comments dd .... dd !Maaaa dd .... dd; comments aaaa dd .... dd The !M command writes data byte pairs "dd" into successive memory locations, starting at address "aaaa". The data bytes are written into memory as soon as they are typed, without waiting for the final . They must come in pairs of hex digits, or a syntax error will occur. Otherwise, nulls, spaces, and other non-hex characters are ignored by the monitor, and can be used to improve readability. A final ends the command. Two optional forms are provided for loading more data than will fit on one line. If you type a comma "," anything up to the final will be ignored, and memory loading will resume on the next line at the next sequential address. Similarly, a semicolon ";" also ignores anything you type up to the final ; memory loading continues on the next line at a new address specified by the first hex number on the line. This allows changing non-sequential bytes of memory. The following examples illustrate the use of the !M command. !M1000 001122 (user types) * (monitor writes 00 to address 1000, 11 to address 1001, and 22 to 1002) !M20031003 3344 (oops! corrected 2003 to 1003) * (monitor writes 33 to 1003, 44 to 1004) !M1005 55 6X (syntax error; 4Z isn't hex) ? (monitor writes 55 to 1005, but then prints "?" to indicate error) !M1006 66 77 88, comma makes it ignore comments 99 AA BB, like these CC (this ends the Change Memory command) * !M100D DD; HERE: ORG 100Dh, SEP 13 semicolons let you 100E EE; DB 0EEh load assembler files with a 100E FF; DB 0EEh new address for each line 1010 (ends command) * ?M1000 10 (use ?M to examine the results) 1000 0011 2233 4455 6677 8899 AABB CCDD EEFF; * As with the ?M command, an erroneous address can be corrected by just following it with the corrected one; only the last 4 digits count. The third example shows a syntax error; the 55 gets written into memory, but the 6X does not -- it had to be re-typed on the following line. The last example shows the contents of memory after this series of !M commands. -23- The !M command will accept data produced by the ?M command. Simply type "!M;" without a final , then turn on your terminal's reader. Everything will be ignored (because of the semicolon) until the first is read from the tape. This should be followed with the first address, and then the data bytes to be loaded. The !M command will also load listings produced by the RCA assembler. Move Memory Command The ?M and !M commands can be used together to move a block of "nnnn" bytes of memory from address "aaaa" to "bbbb". Any size block can be moved, and overlapping blocks can be moved without error. The following examples illustrate the block move. ?M0 10 !M1000 (moves 10 bytes from 0 to 1000) * ?MC00 230024 !M1C00 (oops; corrected byte count to 24) * ?M0 10000 !M1 (move entire memory up 1 byte) * ?M1234 56X (syntax error; 56X is not hex) ? The first example moves 10 hex (16 decimal) bytes starting at address 0000 to address 1000 hex. The addresses and byte count can be corrected using the last-4-digits rule as in the ?M and !M commands. The third example is the largest possible block move, and moves the entire contents of memory up one byte. But, since the IDIOT/4 monitor is in ROM, it is write protected against damaging itself. But the Move Memory command can move anything in RAM, since it uses no RAM itself. Like ?M and !M, spaces can be used freely for readability, but non-hex characters will cause a syntax error. Examine Registers ?R Upon entry, IDIOT/4 saves the state of the COSMAC CPU in RAM. This data can be listed using the ?R command. What actually happens is that ?R supplies the address and byte count, and performs a ?M to list the data. The following example shows the source of the data in each 4-byte pair of bytes in parentheses. ?R 10B8 (ID,T) (DF,D) (IE,Q) (EF1-4); 10C0 (R0) (R1) (R2) (R3) (R4) (R5) (R6) (R7); 10D0 (R8) (R9) (RA) (RB) (RC) (RD) (RE) (RF) * The first number on each line is the starting address for that line of register contents. For example, R1 is in location 10C2 and 10C3. -24- The register contents are interpreted as follows: ID - Identifies what caused the registers to be saved. 00 - power or hardware RESET 10 - hardware or software interrupt, or USR(32) T - Contents of T register. Contains old X and P if entry was via a hardware interrupt DF - Contents of DF flag 00 - DF=0 01 - DF=1 D - Contents of D register (accumulator) IE - Status of Interrupt Enable bit 00 - interrupts disabled 01 - interrupts enabled Q - Status of Q bit 00 - Q=0 01 - Q=1 EF1-4 - Status of external flags about 500 usec after entry 1xxx - EF1=1 (EF1 pin low) 0xxx - EF1=0 (EF1 pin high) x2xx - EF2=1 (EF2 pin low) x0xx - EF2=0 (EF2 pin high) xx3x - EF3=1 (EF3 pin low) xx0x - EF3=0 (EF3 pin high) xxx4 - EF4=1 (EF4 pin low) xxx0 - EF4=0 (EF4 pin high) R0-RF - Contents of registers R0-RF; 4 hex digits each Saving CPU registers is a great aid in debugging machine-language programs. Breakpoints (SEP R1 instructions) can be inserted into a program with the !M command. When executed, the breakpoint saves the registers for analysis with the ?R command. If desired, the register values saved in RAM can be altered with the !M command. These values can then be restored to the registers, and program execution resumed where it left off with the $R command (described below). The COSMAC architecture places certain limitations on the accuracy of the saved registers. The COSMAC itself alters R0, P, X, and IE upon Reset, so their previous contents are lost. In addition, the monitor uses R4 as a pointer to RAM. Thus if the ID code is 00 (Reset), registers R0, P, X, IE, and R4 will not show the actual values at the time of Reset. If the ID code is 10, entry was via a hardware interrupt (COSMAC Interrupt pin low) or a software interrupt (SEP 1 instruction). Register R1 must point to the interrupt handler and R2 must point into RAM with at least 4 free bytes for a stack. When the COSMAC responds to a hardware interrupt, it saves the old values of X and P in the T register; therefore the previous contents of T is lost. Otherwise, all registers are saved correctly. -25- There are two ways to enter the monitor with a software interrupt (SEP 1). You can either save X and P; or T; but not both. To save T, insert a SEP 1 instruction in any machine-language program. To save X and P, insert a MARK and a SEP 1. MARK copies X and P into T, then pushes T onto the stack (via R2). Since MARK affects the stack and R2, the saved register contents should be interpreted accordingly. Other than this, all registers are saved correctly. Run Register Command $R $Rp $Rxp The Run Register command restores all CPU registers (except T) to the values sown by the ?R command, and resumes program execution with these values. An optional value can be specified for X and P; if not specified, 0 is assumed. The following examples illustrate the use of the $R command. $R (restore register, and set X=0, P=0) $R3 (same, but set X=0, P=3) $R23 (same, but set X=2, P=3) Since the Tiny BASIC USR function exits with X=2 and P=3, the last example will return to BASIC and resume execution right where it left off. There are a few precautions to observe when using $R to resume a program that was interrupted by a software interrupt (SEP 1) instruction: 1. Be sure to restore the correct value of X and P. 2. If a byte of the program was replaced by the SEP 1 (to insert a breakpoint), execution will resume AFTER the SEP 1 and the original instruction will not have been executed. You will have to replace the SEP 1 with the original instruction, and decrement the program counter by 1 so this instruction gets executed when you resume. 3. If the 2-byte sequence MARK, SEP 1 were substituted, two bytes will need to be replaced with the original instructions, and the program counter decremented by two to execute them. Also, R2 and M(R2+1) will have to be corrected as well. These details can be fixed by using !M to correct the RAM and register values saved in RAM before using the $R command. -26- Run Program Command $Paaaa The Run Program Command begins execution of the program at address "aaaa" with X=0, P=0, and interrupts disabled (similar to the effect of a hardware reset). If no address is specified, execution begins at 0000. $P100N (syntax error; 100N is not hex) ? $P1000 (runs program at 1000 hex) The address must be a hexadecimal number. As for the ?M and !M commands, only the last 4 digits typed are used for the address. If you make a mistake, simply retype the correct address as the last four digits. -27- CHAPTER 8 INTERNAL OPERATION Although TMSI Tiny BASIC is quite versatile as delivered, you may wish to modify it for special applications. Typical changes may include adding new USR functions, modifying the I/O routines, or saving a BASIC program in ROM. To do these successfully, you will need a good working knowledge of the COSMAC microprocessor and must be familiar with the normal operation of Tiny BASIC and the IDIOT monitor. This chapter will then provide you with the necessary details on memory allocation, register usage, and available subroutines. Memory Allocation TMSI Tiny BASIC is normally supplied in a single 4k byte 27C32 EPROM which is addressed from 0 to 4095 (0000 to 0FFF hex). This ROM contains all the necessary software, including I/O routines. Only the lower 3/4 of the ROM is used, leaving approximately 1k bytes available for expansion or user programs. Refer to the actual source code listing (Appendix G) for the specific beginning and ending addresses in your ROM. Tiny BASIC requires at least 256 bytes of RAM to store its buffers, variables, pointers, and other data. This RAM must be addressed at 4096 to 4351 (1000 to 10FF hex). This RAM is initialized from data in the ROM whenever you answer the "NEW?" prompt with "Y" (for "yes"), or use the BASIC NEW command. Once initialized, Tiny BASIC works only with the data in RAM. Thus, you can temporarily change the way BASIC operates (until the next NEW) by changing values in RAM, or permanently change operation by changing the corresponding values in ROM with an EPROM programmer. Appendix F summarizes the contents of the first page of RAM and the corresponding ROM addresses from which they are initialized. The following sections provide further information on exactly what each of these values does. "NEW" also causes Tiny BASIC to set itself up to use all of the RAM available. It begins searching for RAM at address 4352 (hex 1100); just above the first page of RAM. The search continues upward until the first non-RAM byte is found. The actual contents of RAM is not changed by the test, so any programs or data in RAM are not harmed. Once RAM has been sized, the lower limit (normally 1100 hex) is saved at location 1020-1021 hex, and the upper limit at location 1022-1023 hex. These limits define the amount of memory available for new Tiny BASIC programs. Tiny BASIC needs a "stack" during program execution to store return addresses, GOSUB line numbers, and other temporary data. This stack begins at the upper end of RAM. It grows downward as information is -28- pushed onto it, and shrinks back upward as the information is popped back off again. The contents of location 1017 hex is the "stack reserve", which specifies the number of bytes of RAM reserved for this stack. The stack reserve is normally set to 32 (20 hex), though Tiny BASIC itself only uses about half of this. Increasing the stack reserve gives you more room for nested GOSUBs or machine-language subroutine calls; decreasing the stack reserve gives you a little more room for programs. If you leave too little stack reserve, you may run out of stack space during program execution. If this happens in BASIC, it causes an error stop with the message "!232". If it happens during a machine-language subroutine, it can destroy the last line of the BASIC program. Internal BASIC Program Format New Tiny BASIC programs are stored in RAM, beginning at the lower limit specified in locations 1020-1021 hex and growing upward. The contents of locations 1024-1025 hex is the end-of-program pointer, and points to the last byte of the program plus the stack reserve. When lines are deleted from the program, they are removed from RAM, the rest of the program is shifted down to fill the hole, and the end-of-program pointer is decreased by the appropriate amount. New lines are inserted into the program in ascending numerical order. A hole is created between the appropriate lines by moving the rest of the program up, inserting the new line, and increasing the end-of-program pointer by the right amount. If the insertion would cause the end-of-program plus stack reserve to exceed the upper end of RAM, you have run out of memory and a "!8" message is printed. Since the stack reserve is included in this test, you can run any program you can enter successfully. Once in RAM, each line of a Tiny BASIC program begins with a 2-byte line number (converted to binary), and ends with a carriage return (, 0D hex). The bytes in between contain the remaining ASCII characters in the line, exactly as originally entered and complete with spaces. The end of the program is marked by a 2-byte 0000 after the last line. The following shows a simple BASIC program in RAM: :20 END (enter a 2-line BASIC program) :10 PR A :X=USR(32) (call the monitor to examine it) *?M1017 F (display the BASIC pointers) vv------------------- (stack reserve) 1017 20 0038 1234 0679 0679; 1020 1100 17FF 112E------- (end of program + stack reserve) ^^^^------------ (upper end of RAM) ^^^^----------------- (start of program) *?M1100 F (OK: show the BASIC program) 1100 000A 5052 2041 0D00 1445 4E44 0D00 00 * \ / | | | | | \ /| | | | \ / 10 P R A 20 E N D 00 The lines were sorted into ascending order, the last two bytes were 0000, and the last byte was located at (end of program + stack reserve)-(stack reserve)-(start of program) = 112E-1100-20 = 110E. -29- Saving a BASIC Program in EPROM A BASIC program in RAM will be lost whenever the computer is turned off or loses power. To prevent this, you can save your program in Read-Only Memory (ROM), which retains its contents indefinitely without power. TMSI Tiny BASIC automatically searches for such a program in ROM following power-on or Reset. If found, the ROM program is executed immediately, without other inputs: The initial , "NEW?" message response, and RUN command are not necessary. Thus you can write programs for control systems, test fixtures, and other dedicated applications that "wake up" and run without a person to type commands. In fact, no terminal keyboard or display is needed at all unless your own BASIC program uses PRINT or INPUT statements. In general, any TMSI Tiny BASIC program can be saved in ROM. The ROM version will be located at a different address than its RAM version, but this does not normally cause a problem because Tiny BASIC programs are intrinsically ROM-able and relocatable without change. However, there are a few special requirements that your Tiny BASIC program must meet to be saved in ROM successfully: 1. The Command Mode a. You cannot insert or delete lines from a BASIC program in ROM. The program is permanent, and can't be changed by the computer. b. Likewise, the NEW command cannot clear a program in ROM. 2. The USR Function a. No USR function can alter the BASIC program itself. b. If a USR function reads data within the program itself, it must address the data relative to the start-of-program pointer, not by an absolute address. For example, you could read the 100th byte in a BASIC program in RAM by: 10 LET X=USR(20,100+4352) since programs in RAM always begin at address 4352. But a ROM program will begin at a different address, which depends on where the ROM is addressed. Therefore, calculate the location of the 100th byte by using the start-of-program pointer: 10 LET X=USR(20,100+USR(20,4128)*256+USR(20,4129)) The start-of-program pointer is a 16-bit address, stored at locations 4128-4129. The second USR function reads the upper half of this address (at 4128), multiplies it by 256 to make it the most significant byte of a Tiny BASIC number. The third USR function then reads the lower byte (at 4129) and adds it to produce a single 16-bit Tiny BASIC number. This number points to the start of the BASIC program regardless of whether it is in ROM or RAM. The first USR function can then read the 100th byte in the program by adding 100 to this number. -30- 3. Serial I/O A BASIC program in ROM begins execution with the serial I/O initialized for full duplex operation at 300 baud with a 2 MHz clock. The COSMAC's EF4 pin is the serial input, and must be low (i.e. the idle or "mark" state). If EF4 is high, BASIC will interpret it as a "break" at the end of the first line, and stop execution and return to Command mode. a. If you want your ROM program to adapt itself to the baud rate of the first key typed (as is done for programs in RAM), use the following USR function in your program before the first PRINT or INPUT statement: USR(2302) This function calls TIMALC, a subroutine that waits for the first key typed, and sets the baud rate accordingly. This first key must be a to select full duplex (all inputs echoed to the serial output) or for half duplex (inputs not echoed). b. If you want to set the baud rate to a specific value, refer to the assembly language listing (Appendix G) and change location 08BB hex to the desired value. c. If you will not be using serial inputs at all, either connect the COSMAC's EF4 pin low, or disable the Tiny BASIC "break" test by making this the first line of your program: 1 X=USR(24,4108,252)+USR(24,4109,0)+USR(24,4110,213) This statement changes the "break" vector at address 4108 (100C hex) to ignore EF4 and always return without a break. It does so by writing the following 3-byte program into memory: address data instruction comments ------- ---- ----------- -------- 100C FC00 ADI 0 set DF=0 (no break) 100E D5 SEP 5 return Once your Tiny BASIC program meets these requirements, it will be intrinsically ROM-able and relocatable. You should first load your program into RAM and test it thoroughly to be sure it is correct. The next step is to enter the IDIOT monitor, and examine the Tiny BASIC pointers to find out where the program is in RAM, and how big it is. If you are using a TMSI EPROM programmer, you can then use a block move command to save your program in an EPROM. The new EPROM can then be installed in the system and addressed to begin on any page boundary address (xx00 hex). It will begin execution automatically when the computer is turned on or reset. -31- An example should help make this process clearer. Assume that the following simple Tiny BASIC program is to be saved in ROM. A TMSI EPROM programmer is used, which is memory-mapped to begin at address 8000 hex. Comments are in parentheses. :NEW (clear the BASIC program space) :10 LET X=0 (enter your BASIC program) :20 PRINT X; :30 X=X+1 :40 IF X<10 GOTO 20 :50 END :RUN (now test it) 0123456789 (it works) :PRINT USR(32) (call the monitor) *M1017 F (examine the BASIC pointers) 1017 20 0038 1234 5678 0679; ^^--------------------(stack reserve) 1020 1100 17FF 1156 * ^^^^--------(end-of-program + stack reserve) ^^^^------------------(start-of-program) Now, we know that the program starts at 1100 hex, and that its size is (end-of-program + stack reserve) - (stack reserve) - (start of program). Calculate the program's size (in hexadecimal): (end-of-program + stack reserve) 1156 (stack reserve) -20 ---- 1136 (start-of-program) -1100 ---- 36 (to include both first and last bytes) +1 ---- (total program size) 37 Our example program is thus 37 hex bytes long. We can now use the IDIOT monitor's block move command to program it into an EPROM: *?M1100 37 !M8000 (copy program to EPROM) ^^^^----------(destination in EPROM) ^^-----------------(size of program) ^^^^--------------------(start of program) *$P0 (reset, and run it from EPROM) 0123456789 (it runs without further inputs) : (and returns to BASIC's Command) (mode when it reaches the END) (statement) -32- Register Usage Between Tiny BASIC and the IDIOT monitor, every COSMAC register is used at one time or another. However, register usage conforms to generally-accepted COSMAC programming practices. Several registers are free for use at defined times, such as within machine-language subroutines called by USR functions (see "Adding USR Functions"). Register Usage -------- ----- R0 - Initial program counter after reset; thereafter unused. (Reserved for use as a DMA pointer). R1 - Interrupt handler program counter; initialized to enter the IDIOT monitor, but interrupts are initially disabled. R2 - Stack pointer; stack begins at high end of RAM, and grows downward. The top occupied byte on the stack (TOS) is at the lowest address, and R2 always points to either TOS or TOS-1. R3 - Normal program counter. R4 - BASIC: Program counter for RCA's Standard Call and Return Technique (SCRT) "call". A SEP 4 instruction followed by a 2-byte address calls the subroutine at that address. MONITOR: General-purpose pointer to memory. R5 - BASIC: Program counter for SCRT "return". A subroutine ends with a SEP 5 to return to its caller. MONITOR: Main program counter. R6 - BASIC: Used by SCRT to save calling program's return address to allow for passing inline parameters. R7 - BASIC: Program counter for FECH routine. A SEP 7 followed by a 1-byte address fetches the contents of that address on the 1st page of RAM (10xx hex), & points RD to address (10xx+1). R8 - BASIC: General working register; also used by USR function. R9 - BASIC: Intermediate Language (IL) program counter. Points to the next IL instruction to be executed. RA - BASIC: 16-bit accumulator; also used by USR function. MONITOR: Memory address pointer. RB - BASIC: Points to the next byte in the BASIC program. RC - Program counter for DELAY subroutine, used for serial I/O. RD - BASIC: Pointer to lowest page of RAM (10xx hex). MONITOR: Hex address accumulator. RE - Used for serial I/O: RE.1 holds the baud rate constant and echo flag. RE.0 holds the delay flag. RF - BASIC: General working register. MONITOR: Used to hold the byte being sent via serial I/O. -33- User-Accessible Subroutines TMSI Tiny BASIC includes a number of machine-language subroutines that can be called from BASIC with the USR function, or used with machine language programs. The most commonly-used routines are described in Chapter 6 under "The USR Function". However, there are a few more that may prove useful in certain situations. The following list identifies all of these subroutines, with the emphasis on how they work at the machine language level. The names given are their labels in the assembly listing (Appendix G) which should be consulted for the actual executable code. Unless otherwise noted, subroutines can be called with a Tiny BASIC USR function, and use register R3 as their program counter. Routines with a dedicated program counter other than R3 can only be called from a machine language program: Read the descriptions carefully before you try to use them. Location Name Hex Decimal Description ---- ---- ------- ----------- KEYBD 1006 4102 Read vector: A 3-byte long branch instruction in RAM to the routine to read a key from the user's keyboard. KEYBD normally points to the TTYRED routine. TYPED 1009 4105 Type vector: A 3-byte long branch instruction in RAM to the routine that types a key on the user's terminal or display device. TYPED normally points to TYPE. TBRK 100C 4108 Break vector: A 3-byte long branch instruction in RAM to the routine that tests for a "break" input from the user's keyboard. TBRK normally points to TSTBR. READ 093E 2366 Read a serial character via the COSMAC's EF4 flag input, and return its ASCII code in registers RF.1 and D. The serial input expects 1 start bit, 8 data, and 1 stop bit. The COSMAC EF4 input (pin 21) should be low for a "mark" or stop bit, high for a "space" or start bit. The DELAY routine determines the baud rate. The READ routine uses P=3; alters registers DF, RE, and RF; and returns with a SEP 5. If the least significant bit of register RE.1 is 1, any key received will be echoed on the COSMAC Q output; if this bit is 0, then keys are not echoed. -34- Location Name Hex Decimal Description ---- ---- ------- ----------- TTYRED 0940 2368 Same as READ, but first executes an OUT 7,80 hex instruction to turn on a serial input device such as a tape reader. Once the start bit of a character has begun, an OUT 7,40 hex is executed to turn off the reader after one character. READAH 093B 2363 Same as READ, but if a hexadecimal character is received (0-9, A-F) it is also shifted into the lowest 4 bits of register RD, and DF=1 is returned. If the character is not hex, DF=0 is returned. READAH uses P=3; alters D, DF, RF, RE.0, and returns via a SEP 3 with R3 pointing to the READAH entry point for repeated calls. Note: The READ routines (READ, TTYRED, and READAH) all exit at the beginning of the echoed stop bit, and set register RE.0 > 0 as a delay flag for the TYPE routines. The TYPE routines (TYPE, TYPE2, TYPE5, and TYPE6) check this flag before typing the next byte. If the flag is set, they will first send two stop bits to insure that the previously echoed character is finished. Take care not to reset this flag (by using the DELAY routine or by setting RE.0=0) until enough time has elapsed so no further delay is needed. TYPE5 09A0 2464 Type the byte at the memory location pointed to by register R5, and then increment R5. If the delay flag is set (RE.0>0), then wait 2 bit times for any previous echoed read operation to end, type the byte, and then set the delay flag RE.0=0 so further TYPEs are not delayed. The serial output uses the COSMAC's Q output with 1 start bit, 8 data, and 2 stop bits. A LineFeed (=0A hex) is automatically followed with 3 Nulls (=00) in case the terminal needs time for its operation. Q=0 is a "mark" or Stop bit, and Q=1 is a "space" or Start bit. The DELAY routine determines the baud rate. TYPE uses P=3; alters D, DF, X, RD.0, RE.0, RF.0, and exits with a SEP 5 and leaves R3 pointing at TYPE5 for repeated calls. TYPE6 09A2 2466 Same as TYPE5, but uses and increments R6. TYPE 09A4 2468 Same as TYPE5, but types contents of RF.1. TYPE5D 099C 2460 Same as TYPE5, but always waits 2 bit-times. TYPE2 09AE 2478 Same as TYPE5, but types the 8-bit contents of register RF.1 as two hexadecimal digits (0-9, A-F). -35- Location Name Hex Decimal Description ---- ---- ------- ----------- TSTBR 0666 1638 Test for a "break" condition from the user's keyboard on the COSMAC's EF4 flag input pin. If EF4=1 (i.e. pin 21 is low), TSTBR returns immediately with DF=1; if EF4=0 (pin 21 high), wait until it returns to 1 and then return with DF=0 (the "break" condition) TSTBR uses P=3; alters DF, and returns with a SEP 5. TIMALC 08FE 2302 Calculates the baud rate and sets the echo flag, based on the next serial character received. This character must be either a Carriage Return or Line Feed . selects full duplex, i.e. all serial inputs will be echoed. selects half duplex; serial inputs will not be echoed. TIMALC initializes register RC as a dedicated program counter for the DELAY routine, and loads a constant proportional to the baud rate in the upper 7 bits of RE.1. The least significant bit of RE.1 is the echo flag (0 for echo, 1 for no echo). TIMALC uses P=3; alters D, DF, RC, RE, RF.0; and returns with a SEP 5. DELAY 08EF 2287 Used by the READ and TYPE routines to generate a time delay proportional to the baud rate. The length of the delay (in machine cycles) is specified by: DELAY = 4 + (4 * BAUD * (BITS + 3)) where BAUD is the baud rate constant in the upper 7 bits of RE.1, and BITS is an in-line byte from the calling program. DELAY uses RC as its dedicated program counter, and cannot be called with a USR function. It returns with a SEP 3; with DF=1, D=0, RE.0=0, and RC pointing to the DELAY entry point for repeated calls. PEEK 0014 20 Read the memory location specified by R8, and return its value in D. PEEK uses P=3; alters D, RA.1, R8, and returns with SEP 5. POKE 0018 24 Write the contents of the D register into the memory location specified by R8. Uses P=3; alters nothing, and returns with a SEP 5. -36- Location Name Hex Decimal Description ---- ---- ------- ----------- MONITOR 0020 32 Calls the machine level IDIOT monitor. The contents of all COSMAC registers are saved in RAM so they can be examined, altered, and restored if desired. The monitor itself is entered with a software interrupt; register R1 is initialized to point to the interrupt handler, and a SEP 1 is executed. IOBIT 0023 35 Routine to allow Tiny BASIC to access the COSMAC's EF1-4 flag inputs and Q output. If D=1 on entry, set Q; if D>1, reset Q; if D=0, leave Q unchanged. The lower 3 bits of R8.0 specifies which flag bit to read and return in D; If R8.0=0, read Q; if 1-4 read EF1-4 respectively. Returns D=1 if the selected bit is 1 or true, or D=0 if 0 or false. IOBIT uses P=3; alters D, DF, Q; and returns with a SEP 5. IO 0026 38 Routine to allow Tiny BASIC to access the COSMAC's IN1-7 and OUT1-7 I/O ports. This routine works by the unusual technique of writing a program onto the stack, and then executing it. Register R8.0 specifies the value of N: N=1-7 for OUT1-7; N=9-15 for IN1-7. For an OUT1-7, D holds the byte to be output. For an IN1-7, the byte read is returned in D. IO uses P=3; alters D and RA; and returns indirectly via a SEP 5. INTERUPT 08C5 2245 Interrupt handler for the IDIOT monitor. It saves a copy of the COSMAC registers in RAM and then enters the monitor. A software interrupt (SEP 1 instruction) saves all registers except P and X correctly. A hardware interrupt saves all except T correctly. R2 must point to a stack with at least 4 free bytes to save D and R4. INTERUPT uses P=1 as its dedicated program counter, and cannot be called from BASIC with a USR function. -37- Location Name Hex Decimal Description ---- ---- ------- ----------- CALL 002A 42 CALL subroutine for implementing the RCA Standard Call and Return Technique (SCRT). CALL uses R4 as its dedicated program counter and can't be called from Tiny BASIC with a USR function. A machine language program calls a subroutine with a SEP 4 instruction, followed by the 2-byte address of the subroutine being called. CALL saves the value of register R6 on the stack, saves R3 (the calling program's program counter) in R6, places the address of the subroutine being called in R3, and calls the subroutine with a SEP 3 instruction. CALL preserves D in RF.1, and exits with R4 pointing to the entry point of CALL for repeated calls. RETRN 0030 60 RETURN subroutine for SCRT. RETRN uses R5 as its dedicated program counter, and can't be called from Tiny BASIC with the USR function. On completion, a machine language returns to its caller by executing a SEP 5 instruction. RETRN then moves the calling program's address from register R6 to R3, restores the old value of R6 from the stack, and returns to the caller with a SEP 3 instruction. RETRN preserves the contents of D in RF.1, and exits with R5 pointing to the entry point of RETRN for repeated returns. FETCH 0048 75 Fetches a designated byte from the first page of RAM (10xx hex). FETCH uses R7 as its dedicated program counter and can't be called from Tiny BASIC with the USR function. A machine language program calls FETCH with a SEP 7 instruction, followed by the lower byte of an address on the first page of RAM. FETCH then returns the contents of that address in register D, (address+1) in RD, and X=D. It then exits with a SEP 3 instruction, with R7 pointing to the entry point of FETCH for repeated calls. -38- Adding USR Functions True to its name, Tiny BASIC is not particularly fast or powerful. However, it does provide the USR function for calling machine language subroutines where additional speed or capabilities are needed. USR functions can perform virtually any task that the computer is capable of performing -- the built-in USR functions described in Chapter 6 are only a few examples. New USR functions can be written and tested with the IDIOT monitor, according to the rules given in this section. They can then be called from BASIC just like the existing USR functions. A USR function within a Tiny BASIC statement will take one of the following forms: USR (expression1) USR (expression1, expression2) USR (expression1, expression2, expression3) The first expression is always required, and specifies the address of the machine language subroutine to be called. The second and third expressions are optional, and can be used to pass one or two 16-bit values to the subroutine. When Tiny BASIC encounters any of the above forms, it evaluates each expression normally to produce one, two, or three 16-bit values. Note that Tiny BASIC treats each number as a decimal value, but that the IDIOT monitor and most machine language programs will treat them as hexadecimal numbers. Thus, if you want expression1 to specify the hex address 0020 for example, you must convert it to decimal (=32) and use this value in your USR function. Appendix E provides a hex-to-decimal conversion table to simplify this task. Once the expressions have been evaluated, the machine language subroutine at the address given by expression1 is called. Execution begins with COSMAC register P=3, X=2, and R3=expression1. If a second expression was supplied, R8=expression2. Similarly, if a third expression was supplied, RA=expression3. The stack pointer R2 will be pointing to a free byte on the stack, and R4, R5, R7, and RC will be pointing to the entry points of the CALL, RETRN, FETCH, and DELAY subroutines respectively. Register R0, R1, R8, RA, RD, and RF may be used, but if any other registers will be changed, their contents should first be saved on the stack, and then restored before returning to Tiny BASIC. At the conclusion of your machine language subroutine, you can return a 16-bit number to Tiny BASIC as the value of the USR function; the upper 8 bits of this number should be placed in RA.1, and the lower 8 bits in D. You can then return to Tiny BASIC with a SEP 5 instruction. -39- USR Function Example The chart below shows the COSMAC register contents as they exist as the USR function begins execution of the first instruction of the machine language subroutine: R0 - R1 - X = R2 - stack pointer * P = R3 - value of expression 1 R4 - entry to CALL * R5 - entry to RETRN * R6 - return address to Tiny BASIC * R7 - entry to FETCH * R8 - value of expression 2 R9 - IL program counter * RA - value of expression 3 RB - BASIC program pointer * RC - entry to DELAY * RD - RE - serial I/O variables * RF - D - DF - Q - 0 serial I/O bit * IE - interrupt enable * T - * = Contents should be left alone, or saved and then restored before returning to BASIC. Unlabeled registers are free for use during the machine language subroutine. Let's add a Boolean AND to Tiny BASIC as an example of a new USR function. Given two 16-bit numbers, the AND operation sets each bit of the output to a "1" if and only if the corresponding bits in both numbers are "1"; otherwise the output bit is set to "0". This is done for each of the 16 bits in the numbers to produce a 16-bit result. So, our USR function accepts two numbers (let's call them X and Y), and returns with the value X AND Y. The two numbers will be passed to our machine language routine as expression2 and expression3, so they will be in registers R8 and RA respectively. The COSMAC has an 8-bit AND instruction, so we will have to use it twice; once for each half of the 16-bit numbers. Also, the AND instruction expects one of its operands in D, and the other on the stack. Once the AND has been performed, we'll have to put the results in D and RA.1 where Tiny BASIC expects to find them. Finally, we will have to find a place to put this routine in memory. A convenient location is in the last 32 bytes of the first page of RAM; locations 4320-4351 (10E0-10FF hex). This space is reserved for a DMA buffer, and not used by Tiny BASIC or the IDIOT monitor. So, if you're not using it for DMA, it is free for our AND function. -40- From Tiny BASIC, call the IDIOT monitor with "X=USR(32)" and then type in the following program: !M10E0 98; GHI R8 ..Entry: get upper half of number X 10E1 52; STR R2 .. and put it on the stack (via R2) 10E2 9A; GHI RA ..put the upper half of number Y in D 10E3 F2; AND .."AND" D and stack together 10E4 BA; PHI RA .. and save result in register RA.1 10E5 88; GLO R8 ..get the lower half of number X 10E6 52; STR R2 .. and put it on the stack (via R2) 10E7 8A; GLO RA ..put the lower half of number Y in D 10E8 F2; AND .."AND" D and stack together 10E9 D5; SEP R5 ..return to Tiny BASIC *$R23 You only need to type the first part of each line up to and including the semicolons. However, the monitor will accept the program exactly as shown, ignoring the comments after the semicolons. After the to end the !M command, return to Tiny BASIC with a $R23 command. Then we can test the AND function by typing in the following lines in Command mode: :PRINT "10 AND 3 = "; USR(4320,10,3) 10 AND 3 = 2 : Is this correct? Let's perform the AND operation ourselves in binary Decimal Binary 10 = 0000 0000 0000 1010 3 = 0000 0000 0000 0011 10 AND 3 = 0000 0000 0000 0010 = 2 <-- CORRECT! -41- APPENDIX A SERIAL TERMINAL INTERFACE The following circuit or its equivalent will provide a COSMAC microprocessor with a minimal RS-232 serial interface suitable for TMSI Tiny BASIC. It is capable of operating up to 9600 baud. +5v | | 22K > 25-pin RS-232 Resistor > "D" Connector ____________ > 2N4401 NPN 3.3K | ___ | | Transistor Resistor | EF4 |_21______|______C E__________/\/\/\________TXD | | _\___/_ | pin 2 | | |B _|_ | | | _\_/_ 1N914 | | | | Diode | | _|_ _|_ ____RTS | | = = | pin 4 | | Ground | | | |____CTS | | pin 5 | | +5v | | | | | | | | > (note 1) ____DSR | | 22K > +5 to +15v | pin 6 | | Resistor > | | | | | | |____DTR | | | > pin 20 | | | /E > 1.8K | Q |_4______|/ 2N4403 PNP > Resistor | | B|\ Transistor | | | | \C |_________________RXD |____________| | | /C pin 3 |____________|/ 2N4401 NPN COSMAC | B |\ Transistor Microprocessor | | \E > | _______COMMON > 22K | _|_ pin 7 > Resistor | = | | Ground |_______________| | | -5 to -15v (note 1) Notes: 1. Equal and opposite power supply voltages for RS-232 interface. 2. RTS-CTS and DSR-DTR jumpers may be required by some terminals. A-1 APPENDIX B ASCII CONTROL CODES TMSI Tiny BASIC uses the ASCII code for communicating with the user's terminal. The following list gives the control codes used and their functions. All the remaining control codes are ignored, and simply treated the same as any printable character. Name Decimal Hex Function ---- ------- --- -------- -- -- Break - Holding the serial input in the "space" condition for more than one character time is a "break". It is used to interrupt a BASIC program and return to the Command mode, or to interrupt a long LIST statement. 0 00 Null (control-@) - A do-nothing code that is ignored when received. Nulls are also sent following a to give a printer extra time to perform these functions. 7 07 Bell (control-G) - This code is transmitted by BASIC to ring the terminal's bell if the 72-character input line buffer is full and further keys typed are being ignored. 8 08 Backspace (control-H) - Deletes the previous key from the line buffer and prints an "_" (underline). Further keys keep deleting keys from the buffer until none are left; then further keys are ignored. The code can be changed temporarily (until the next Reset or NEW) by altering RAM location 1013 hex, or permanently by altering EPROM location 000F hex. Any ASCII code can be used except , , , or . 10 0A Line Feed (control-J) - If is the first key received after Reset, it sets the baud rate and selects half duplex operation. In BASIC, receiving an turns off further program output and line prompts until a (control-S) is received, or when BASIC returns to Command mode. This function may be disabled by changing the contents of EPROM address 0012 hex to 00. 13 0D Carriage Return (control-M) - Identifies the end of a line. If is the first key received after Reset, it sets the baud rate and selects full duplex operation. Each received is automatically followed by the sequence in case the printer needs time to complete operation. B-1 Name Decimal Hex Function ---- ------- --- -------- 17 11 X-ON (control-Q) - Output by the INPUT statement following a "?" prompt for data. X-ON can be used to turn on a paper tape reader or cassette recorder for automatic inputs. 19 13 X-OFF (control-S) - Resumes the printing of prompts and program output if it had been disabled by an earlier . Otherwise, is ignored. 24 18 Cancel (control-X) - Cancels the entire line in the line buffer without executing it. The code for can be changed permanently by altering EPROM location 0010 hex, or temporarily (until the next Reset or NEW command) by altering RAM location 1014 hex. Any ASCII code can be used except , , , or . 127 7F Delete (rubout) - A "do nothing" code that is ignored when received. B-2 Appendix C Error Message Summary 0 Break during execution 8 Memory overflow; line not inserted 9 Line number 0 not allowed 11 RUN with no program in memory 33 Improper syntax in GOTO 35 No line number to GOTO 40 LET is missing a variable name 42 LET is missing an = 45 Improper syntax in LET 47 LET is not followed by END 64 Missing close quote in PRINT string 83 Colon in PRINT is not at end of statement 85 PRINT not followed by END 101 IF not followed by END 111 INPUT syntax bad; expects variable name 130 INPUT syntax bad; expects comma 131 INPUT not followed by END 140 RETURN syntax bad 141 RETURN has no matching GOSUB 142 GOSUB not followed by END 147 END syntax bad 179 LIST syntax error; expects comma 189 Can't LIST line number 0 193 LIST not followed by END 198 REM not followed by END 199 Missing or lowercase keyword, or bad line number 201 Mis-spelled statement type keyword 232 GOSUB stack overflow 246 Can't divide by zero 276 Syntax error in expression; expects value 282 RND expects 2 arguments 286 Syntax error; expects ")" 321 IF syntax error; expects relational operator C-1 Appendix D Formal Definition of Tiny BASIC line := statement number statement statement := PRINT printlist PR printlist INPUT varlist LET var = expression var = expression GOTO expression GOSUB expression RETURN IF expression relop expression THEN statement IF expression relop expression statement REM comments NEW RUN RUN exprlist LIST LIST exprlist printlist := printitem printitem : printitem separator printlist printitem := expression "characterstring" varlist := var var , varlist exprlist := expression expression , exprlist expression := unsignedexpr + unsignedexpr - unsignedexpr unsignedexpr := term term + unsignedexpr term - unsignedexpr term := factor factor * term factor / term factor := var number ( expression ) function := RND ( exprlist ) USR ( exprlist ) number := digit digit number separator := , | ; var := A | B | ... Y | Z digit := 0 | 1 | ... 8 | 9 relop := < | > | = | <= | >= | <> | >< where ":=" means "is defined as" and "|" means "or" D-1 Appendix E ASCII / Decimal / Hex Conversions -------------------------- Control Codes ------------------------- DEC HEX KEY NAME ALTERNATE NAME DEC HEX KEY NAME ALTERNATE NAME 0 00 ^@ NUL Null 16 10 ^P DLE Data Link Escape 1 01 ^A SOH Start Of Header 17 11 ^Q DC1 XON, Reader On 2 02 ^B STX Start Of Text 18 12 ^R DC2 Tape, Punch On 3 03 ^C ETX End Of Text 19 13 ^S DC3 XOFF, Reader Off 4 04 ^D EOT End Of Transmit 20 14 ^T DC4 TAPE, Punch Off 5 05 ^E ENQ Enquiry 21 15 ^U NAK Neg.Acknowledge 6 06 ^F ACK Acknowledge 22 16 ^V SYN Synchronous Idle 7 07 ^G BEL Bell 23 17 ^W ETB End Text Buffer 8 08 ^H BS Backspace 24 18 ^X CAN Cancel 9 09 ^I HT Horizontal Tab 25 19 ^Y EM End of Medium 10 0A ^J LF Line Feed 26 1A ^Z SUB Substitute 11 0B ^K VT Vertical Tab 27 1B ^[ ESC Escape 12 0C ^L FF Form Feed 28 1C ^\ FS File Separator 13 0D ^M CR Carriage Return 29 1D ^] GS Group Separator 14 0E ^N SO Shift Out 30 1E ^^ RS Record Separator 15 0F ^O SI Shift In 31 1F ^_ US Unit Separator ----------------------- Printable Characters ---------------------- DEC HEX KEY ALTERNATE DEC HEX KEY ALTERNATE DEC HEX KEY ALTERNATE 32 20 space 64 40 @ 96 60 ` accent 33 21 ! exclamation 65 41 A 97 61 a 34 22 " quote 66 42 B 98 62 b 35 23 # pound 67 43 C 99 63 c 36 24 $ dollar 68 44 D 100 64 d 37 25 % percent 69 45 E 101 65 e 38 26 & ampersand 70 46 F 102 66 f 39 27 ' apostrophe 71 47 G 103 67 g 40 28 ( open paren. 72 48 H 104 68 h 41 29 ) close par. 73 49 I letter I 105 69 i 42 2A * asterisk 74 4A J 106 6A j 43 2B + plus 75 4B K 107 6B k 44 2C , comma 76 4C L 108 6C l lowercase L 45 2D - minus 77 4D M 109 6D m 46 2E . period 78 4E N 110 6E n 47 2F / slash 79 4F O letter O 111 6F o lowercase O 48 30 0 zero 80 50 P 112 70 p 49 31 1 one 81 51 Q 113 71 q 50 32 2 two 82 52 R 114 72 r 51 33 3 three 83 53 S 115 73 s 52 34 4 four 84 54 T 116 74 t 53 35 5 five 85 55 U 117 75 u 54 36 6 six 86 56 V 118 76 v 55 37 7 seven 87 57 W 119 77 w 56 38 8 eight 88 58 X 120 78 x 57 39 9 nine 89 59 Y 121 79 y 58 3A : colon 90 5A Z 122 7A z 59 3B ; semicolon 91 5B [ 123 7B { 60 3C < less than 92 5C \ backslash 124 7C | vertical bar 61 3D = equal 93 5D ] 125 7D } 62 3E > greater 94 5E ^ caret 126 7E ~ tilde 63 3F ? question 95 5F _ underscore 127 7F DEL delete E-1 Hex-Binary and Hex-Decimal Conversions 4th Digit 3rd Digit 2nd Digit 1st Digit HEX BINARY HEX DECIMAL HEX DECIMAL HEX DECIMAL HEX DECIMAL 0 - 0000 0 ----- 0 0 ----- 0 0 ----- 0 0 ----- 0 1 - 0001 1 - 4,096 1 --- 256 1 ---- 16 1 ----- 1 2 - 0010 2 - 8,192 2 --- 512 2 ---- 32 2 ----- 2 3 - 0011 3 12,288 3 --- 768 3 ---- 48 3 ----- 3 4 - 0100 4 16,384 4 - 1,024 4 ---- 64 4 ----- 4 5 - 0101 5 20,480 5 - 1,280 5 ---- 80 5 ----- 5 6 - 0110 6 24,576 6 - 1,536 6 ---- 96 6 ----- 6 7 - 0111 7 28,672 7 - 1,792 7 --- 112 7 ----- 7 8 - 1000 8 32,768 8 - 2,048 8 --- 128 8 ----- 8 9 - 1001 9 36,864 9 - 2,304 9 --- 144 9 ----- 9 A - 1010 A 40,960 A - 2,560 A --- 160 A ---- 10 B - 1011 B 45,056 B - 2,816 B --- 176 B ---- 11 C - 1100 C 49,152 C - 3,072 C --- 192 C ---- 12 D - 1101 D 53,248 D - 3,328 D --- 208 D ---- 13 E - 1110 E 57,344 E - 3,584 E --- 224 E ---- 14 F - 1111 F 61,440 F - 3,840 F --- 240 F ---- 15 To convert a hexadecimal number into decimal, look up the decimal equivalent for each digit in the chart above, and add the decimal values together. For example, to convert 10F8 hex to decimal: 1 0 F 8 hexadecimal ^ ^ ^ ^ | | | |___ 1st digit: 8 hex = 8 decimal | | |_____ 2nd digit: F hex = 240 decimal | |_______ 3rd digit: 0 hex = 0 decimal |_________ 4th digit: 1 hex = 4,096 decimal ----- Total: 4,344 decimal Decimal-Hexadecimal Conversion To convert a decimal number N into hexadecimal; starting with the 4th column in the above Hex-Decimal chart, find the largest decimal number that does not exceed N. The hex digit for this number is the 4th (leftmost) hex digit. Subtract the decimal number from N. Repeat for each of the 4 columns. For example, to convert 4,344 decimal to hexadecimal: N = 4,344 decimal Largest number in 4th column that does not exceed N is 4096 So 4th hex digit is 1. 4344 - 4096 = 248 N = 248 decimal Largest number in 3rd column that does not exceed N is 0 So 3rd hex digit is 0. 248 - 0 = 248 N = 248 decimal Largest number in 2nd column that does not exceed N is 240 So 2nd hex digit is F. 248 - 240 = 8 N = 8 decimal Largest number in 1st column that does not exceed N is 8 So 1st hex digit is 8. 8 - 8 = 0; we're done So 4,344 decimal = 10F8 hex E-2 Appendix E Tiny BASIC Memory Usage Location in ROM Location in RAM hex decimal hex decimal Contents -------- ------- --------- --------- ---------------------------- 1000-1005 4096-4101 Page 0 RAM; 1st 6 bytes free 0006-0008 6-8 1006-1008 4102-4104 LBR to Key Input routine 0009-000B 9-11 1009-100B 4105-4107 LBR to Type output routine 000C-000E 12-14 100C-100E 4108-4110 LBR to Break detect routine 100F-1012 4111-4114 unused 000F 15 1013 4115 Backspace key code 0010 16 1014 4116 Cancel key code 0011 17 1015 4117 Pad char; high 4 bits=1 for , =0 for . Low 4 bits=#pad char after 0012 18 1016 4118 Tape Mode; 0=off, 80h=on 0013 19 1017 4119 Stack Reserve 1018 4120 Execution Mode flag 1019 4121 End of input line buffer 101A 4122 Arithmetic Expression Stack pointer & Input Line Buffer 101B 4123 Print Column (for Tabs), msb = Tape Mode flag 101C-101D 4124-4125 Saved PC for "NXT" 001A-001B 26-27 101E-101F 4126-4127 Start addr of IL interpreter 001C-001D 28-29 1020-1021 4128-4129 Start addr of BASIC program 1022-1023 4130-4131 Highest addr of User RAM 1024-1025 4132-4133 End BASIC prog+Stack Reserve 1026-1027 4134-4135 Top of GOSUB stack 1028-1029 4136-4137 Current BASIC program line# 102A-102D 4138-4141 misc. temporary storage 102E-102F 4142-4143 input line pointer 1030-107F 4144-4223 arithmetic execution stack & input line buffer (80 bytes) 1080-1081 4224-4225 random number generator seed 1082-1083 4226-4227 BASIC variable A 1084-1085 4228-4229 " " B ... ... ... 10B4-10B5 4280-4281 BASIC variable Z 10B6-10B7 4282-4283 unused 10B8 4284 MONITOR Saved Registers ID: 00 if Reset, 10 if Interrupt 10B9 4285 register T 10BA-10BB 4286-4287 " DF, D 10BC 4288 " IE 10BD 4289 " Q 10BE-10BF 4290-4291 flags EF1, EF2, EF3, EF4 10C0-10C1 4292-4293 register R0 10C2-10C3 4294-4295 " R1 ... ... .. 10DE-10DF 4318-4319 " RF 10E0-10FF 4320-4321 unused (reserved for DMA) 1100-Top 4352-Top Start of RAM BASIC program F-1 Appendix G TMSI Tiny BASIC Assembly Listing The following listing is the [last as of 1981] version of TMSI Tiny BASIC distributed. It was assembled with the Avocet XASM18 1802 Cross Assembler, version 1.55M. The Avocet assembler uses a slightly different format than RCA assemblers; the following summary outlines these differences. Each line of assembly code can be broken up into six columns (1-6). The columns are explained below. 00B0 F8B3 COLD: LDI LOW $+3 ; THIS IS A COMMENT \ / \ / \ / \ / \ / \ / 1. 2. 3. 4. 5. 6. 1. ADDRESS: The address (in hex) where the first byte of the opcode assembled on this line is placed, or the value equated to a label on that line. In this example, the code goes in memory address 00B0 hex. 2. OPCODE: The assembled opcode bytes (in hex) of the instruction on this line. RCA assemblers put a semicolon (;) after these bytes, so UT4 and IDIOT monitors can read the listing file and ignore everything on the line after this semicolon. The Avocet assembler has only spaces after the last byte of assembled code. 3. LABEL: An easy-to-remember name for a number or address. Labels can be up to 8 characters long, and can contain letters or numbers, and optionally end with a colon (:). At the end of the listing is an alphabetical list of all labels and the numbers or addresses that have been assigned to them. In this example, the label COLD = 00B0. 4. MNEMONIC or Assembler Directive: Standard RCA 1802 instruction mnemonics (LDI, PHI, SEX, etc.), or assembler directives (DB, DW, ORG, etc.). Example; LDI is the "Load D Immediate" instruction, which assembled to an F8; thus the first OPCODE byte is F8. 5. OPERAND: An expression that gets evaluated to 1 byte, 2 bytes, or a string of bytes. "$" is a LABEL equal to the ADDRESS of this line (00B0 in this example), so "$+3" evaluates to 00B3. The LDI instruction expects a 1-byte operand, so "LOW" takes only the low byte of 00B3, or B3. Thus, the second OPCODE byte is B3. 6. COMMENT: Anything after a semicolon (;) is treated as a comment, and ignored by the assembler. Since you have both the assembly listing and the executable code it produced, you should have little trouble figuring out the assembler syntax. However, here are a few more hints. The assembler assumes numbers are in decimal, unless otherwise marked. A hexadecimal number starts with "$" or ends with "H". A binary number starts with "%" or ends with "B". G-1 Operands must evaluate to a number appropriate for the range of the mnemonic. For example, the operand for INP and OUT instructions must evaluate to 1-7. The operand for register instructions must evaluate to 1-F (hex). The labels R0-RF can also be used (i.e. INC 2 is the same as INC R2). The Avocet assembler has several built-in macros: CALL LABEL is a synonym for SEP R4, DW LABEL EXIT is a synonym for SEP R5 POP is a synonym for LDXA PUSH is a synonym for STXD Additionally, a few instructions were equated to new names to make programs a little more readable: DB LDI0 is a synonym for GHI R7 ; sets D to 0 DB TYPA is a synonym for SEP R3 ; type character DB FECH is a synonym for SEP R7 ; Page 0 subroutine A "DB" directive in the MNEMONIC column assembles bytes, so its operands must evaluate to a single byte. There can be multiple operands, separated by commas; they will each be evaluated and assembled into consecutive bytes. If the operand is a string of characters between single or double quotes (" or '), each character is placed in a consecutive byte. A "DW" directive in the MNEMONIC column assembled words (2 bytes each). The 1802 family places the high byte of a word in the lower address. I would like to thank Tom Pittman of Itty Bitty Computers for writing the original 1802 Tiny BASIC, and allowing me to release the source code for this version, which is a close derivative of his work. G-2 (actual assembler listing continued in next file).