GBASIC and MONitor Keywords

Whither the great unknown? Plunge in henceforth, brave adventurer. There be dragons here.

Updates and corrections are gratefully accepted. Last modify 20 January 2003.

Back to "How To Program In GBASIC" | Back to "Programming the Tomy Tutor" | Back to the main page

[Tutti GBASIC]
Tomy GBASIC, as shown in Tutti.

Historically, the major problem has been no surviving significant documentation of GBASIC (that we know of), so there's no comprehensive description of its keywords and capabilities available. This incomplete treatise is based solely upon experimentation and derivation from the manual's sparse GBASIC programming examples.


MONitor Commands

I guess you could call this direct mode ... ?

All MONitor commands are four characters long. Any trailing characters are ignored (e.g., GBASIC == GBAS).

Command Description
BASI Switches to regular Tomy BASIC mode (on those machines [American Tutors and upgraded Grandstand Tutors] that support it).
DIRC Undocumented and does not seem to work on English GBASIC systems, but early Japanese GBASIC had a katakana command 'oshiete' ('listing'). Junya notes this command in his table, but it does not work on either of my American systems.
EDIT Enters the GBASIC editor, keeping any program in memory resident.
GBAS Enters the GBASIC editor and clears any program in memory.
GRAP Exits the monitor. This seems to clear any program in memory, so save it first.
GRUN Starts a program in memory (if one does not exist, it generates a COMD ERR).
LOAD Loads a file from tape. You are prompted for the filename.
MENU Returns to the main menu.
SAVE Saves a file to tape. You are prompted for the filename. This saves screen, sprite and GBASIC data, all in one piece.
STEP Undocumented. Enables step-by-step traced execution. Each line is displayed in green one line up from the bottom. Step through the code with the RT key.
VERI Verifies a file on tape. You are prompted for the filename.

Keyword List

Token values are currently not known for these keywords.

Certain keywords share a common 16(?)-byte work area in VDP RAM for their manipulations. CELL uses the last eight bytes for the 8x8 bit pattern of the referenced cell, and the first eight bytes for the colour pattern. String assignments use up to the first eight bytes, depending on the string length. POST and integer operations require a minimum of two bytes (additional bytes are used if more complicated expressions are evaluated). This is important not only from an interference point of view, but it also indirectly allows more direct control over screen data (see CELL for an example).

In these descriptions, LSB and MSB refer to least and most significant byte (low and high byte to you 6502 freaks) of a 16-bit quantity, respectively. The 9995 is big-endian, so the MSB is the lower of the two byte addresses of a 16-bit word.

In general, entering an expression or an unexpected or out-of-range value where a literal is expected causes an entry error.

Keyword Token Description
ANIM a? When used on the right side of an assignment (i.e., LET ...=ANIM ...), it returns a 16-bit quantity corresponding to the X (LSB) and Y (MSB) position of sprite number a (1-4). When used on the left, it acts as a variable reference to one of the same four sprites. (ANIM expr is illegal and causes an entry error; a must be an integer literal.)

This can be used to grab a sprite location e.g. LET X=ANIM 3 or to put two sprites at the same place e.g. LET ANIM 3=ANIM 4 or to put a sprite at a particular position using the POST operator e.g. LET ANIM 4=POST(Y,X) to specify an ordered pair. This program moves sprites 3 and 4 together (based on page 44 of the manual):

5 LET X=1
6 LET Y=41
210 KEY 1 J,K
220 IF J=0 THEN GOTO 210
230 IF J>5 THEN GOTO 260
240 LET X=X+1
250 GOTO 270
260 LET X=X-1
270 LET ANIM 4=POST(Y,X)
280 LET ANIM 3=ANIM 4
290 GOTO 210
1000 END
Expressions like ANIM 4=3+(X*3) are legal (though, oddly, ANIM 4=(X*3) causes a runtime error), as is ANIM 4=POST(3,4)+2 (puts the sprite at 6,3), and it can also be used on the right-hand side X=(ANIM 3)+4*5 of an expression as well.

See the POST operator for how the sprite coordinate system works.

CELL(a)? When used on the right side of an assignment (i.e., LET ...=CELL(...)), it loads the 16(?)-byte image of 8x8 screen cell a (1-768) into the workspace. The last eight bytes consist of the bit pattern in the cell, and the first eight consist of the colour data. a may be an expression. When used on the left side, it acts as a reference for that same screen cell. (If a is less than one or a is greater than 768, a blank black cell is returned.)

The documented use in the manual is for simple copying of screen data using assignment operations LET CELL(5)=CELL(6), such as this loop which makes all cells the same as cell 1:

10 FOR 30 A=2 TO 768
20 CELL(A)=CELL(1)
30 NEXT
1000 END
However, clever manipulation of the workspace means we're not limited to simply copying what's on screen already. Because string and integer operations affect only part of the workspace area, they can be thus used to change portions of a screen cell independently. To wit,
10 X=CELL(5)
20 E$="ABCDEFGH"
30 CELL(6)=E$
1000 END
This code fragment copies the bit pattern from cell 5 (X is just thrown away), but replaces its colour data with the colour set represented by the ASCII values of string E$, and copies the hybrid cell to cell 6.

When a CELL value is assigned to an integer variable, the 16-bit quantity corresponding to its first two colour bytes is returned; when assigned to a string variable, all eight colour bytes are assigned.

Cells cannot be compared in IF-THEN using the CELL operator overtly (e.g., IF CELL(5)=X and IF CELL(5)=CELL(6) both cause entry errors). While using CELL in an expression like A=CELL(85)+3 causes no entry error, it causes a runtime error.

END? Standard BASIC, with the added side effect of terminating the editor and returning to the MONitor when this command is entered as a program statement. If you just want to enter a command to halt the program's execution and are not finished in the editor, try STOP.
FOR next var=from TO to STEP step, NEXT? Standard BASIC, with the addition of the next parameter, which tells GBASIC the line number where the NEXT is for this loop, e.g. (same as the initial CELL example),
10 FOR 30 A=2 TO 768
20 LET CELL(A)=CELL(1)
30 NEXT
1000 END
Note that the next parameter isn't for compile mode, but rather for entry mode. If you enter a NEXT on a line that hadn't been previously declared as a NEXT in a preceding FOR statement, an entry error results (so NEXT-w/o-FOR is thus handled during entry mode, not runtime mode).

Loops are nestable. Unlike most BASICs, however, NEXT never takes a variable as an argument (entry error).

from, to and step must all be integer literals: expressions generate an entry error.

STEP doesn't seem to be a real keyword, as it never appears in listings (and probably has no token either). However, when listed out, every FOR has a step value listed at the end (it simply defaults to 1). It is optional during entry.

GOTO? Standard BASIC. Serious undocumented crash bug: a GOTO pointing to a non-existent line number causes the computer to lock up during compile mode!!! There is no runtime error for undef'ed statement error because GBASIC never gets that far! This bug is also present in GSUB and THEN.

Calculated branches (GOTO A, GOSUB A, etc.) cause entry errors.

GSUB, RTN? Same as GOSUB and RETURN in standard BASIC. Serious undocumented crash bug in all branching instructions; see GOTO!! RTN-w/o-GSUB causes a runtime error.
HORZ(a)? Undocumented. Returns the X coordinate of a 16-bit sprite position quantity (e.g., HORZ(ANIM 3) gives the X position of sprite 3). See POST for the sprite coordinate system. a can be an expression, and HORZ can be used in expressions too (basically a rapid equivalent to taking the LSB of a 16-bit integer).
IF, THEN? Standard BASIC, but with a limited comparison syntax; IF can only compare variables with variables, or one literal with one variable (IF 5=3, bizarrely, generates an entry error). Worse, you cannot do string comparisons (either literal vs. variable, or variable vs. variable). However, IF is the only keyword that can read the current value of a timer (see TIME). Comparators are limited to = > < <> >= and <= as all others generate an entry error.

THEN can only branch (e.g., IF A=5 THEN PRNT 3, "OK" generates an entry error); you can say THEN GOTO but the superfluous GOTO is (perspicaciously) dropped. There is no ELSE. Serious undocumented crash bug in all branching instructions; see GOTO!!

KEY a b,c? Reads controller a (1 or 2) and places the joystick direction value into variable b and the button value into variable c. See ANIM for an example. a must be an integer literal, and unlike BASIC, you cannot use KEY 0 to read the keyboard (bummer); both generate entry errors. With a single joystick, it is read using controller 1.

The directional values are arranged clockwise 1-8, starting with 1 for North, and ending at 8 for NW. The button values are 1 for SR, 2 for SL and 3 for both. Zero in either indicates no button and/or direction.

The keyboard situation is not a total loss, as some keys can be read on controller 1; L is read as 5, semicolon as 7, comma as 1 and period as three in the direction variable and O as 2 and P as 1 in the button variable. You can also determine if multiple keys are down (experiment, the values are quite logical :-).

LET? Assignment of expressions to variables. LET is optional and in fact does not seem to be a real keyword or have a token, as it never appears in listings even when explicitly entered.

For integer variables, LET works fairly close to standard BASIC. For string variables, however, LET only allows direct assignment and no manipulation (either A$="12345678" or A$=B$). There seems to be no concatenation operator (both A$+B$ and A$&B$ cause entry errors). Strangely, A$=A$B$ is accepted, but it sets A$ to B$, not A$+B$.

You can assign integer quantities to string variables, but this doesn't act like BASIC STR$; rather, the 16-bit quantity actually sets the ASCII values of the first two characters of the string. Keep in mind that the 9995 is big-endian, so something like A$=16961 would set A$ to "BA" ($4241, which would be represented as $41 $42 on little-endian CPUs like the 6502). This means a code fragment like B$=65 actually would make the first character of B$ into a null ($0041).

Assigning string literals to integer variables causes an entry error.

OVFL [ON/OFF]? Undocumented. This enables runtime math errors (what a pleasant, uh, feature ...), which default to OFF on each GRUN. When enabled with OVFL ON, math operations that would cause a math overflow (such as 65535+1 or 1/0) now generate a runtime error instead of being silently ignored and/or wrapping. This program generates a runtime error on line 3:
1 OVFL ON
2 A=65535
3 A=A+1
4 END
POST(y,x)? Turns an ordered pair (x,y) into a 16-bit quantity (note that the Y-coordinate is specified first) which can used directly in calculations, or be passed to ANIM to set a sprite position (see ANIM for an example). x and y may be regular integer expressions, and POST can be used itself in expressions (e.g. ANIM 4=POST(3,4)+2 is legal and executable). POST uses at a minimum the first two bytes of the workspace region as a scratch pad.

As mentioned under ANIM, sprite positions are held in a 16-bit quantity with Y in the MSB and X in the LSB. x and y are not range checked and only their LSBs are used in calculations (the MSBs are thrown away); they are loaded into the first two bytes of the workspace (Y first; remember, the 9995 is big-endian), and then worked with further or assigned. So, POST can also be used to fuse two bytes into a 16-bit number very quickly without an expensive multiply operation.

The sprite coordinate system is a little strange and does not seem to match up fully with documented 9918A behaviour. As expected from 9918A documentation, a Y of 0 is on the second scan line from the top, 1 on the third, 2 on the fourth, etc., down to 192 which is now fully off-screen. 255 is exactly on the top scan line, 254 moves it up one into the border so the top sprite pixels are off-screen, 253 moves it up two, 252 moves it up three, and so on until it is completely obscured at 224 in the border. X, however, is not standard. An X coordinate of zero alwayts hides the sprite, no matter what the Y coordinate is. There is no support for the Early Clock bit, so an X of 1 is at the left hand side, though the sprite may be scrolled into the right hand border (up to 255).

Thus, after all that, in GBASIC the upper left hand corner is at POST(255,1) and the lower right corner is at POST(191,255).

PRNT a,b? Prints b to cell position a (1-761); e.g., PRNT 44,"GBASIC" prints the string GBASIC at cell position 44.

b must either be a string literal (no longer than eight characters), an integer variable, or a string variable (entry error otherwise). Strangely, integer literals are not accepted and cause entry errors, but PRNT 1, ANIM 4 is accepted (! -- but it causes a runtime error). a can be a variable or integer literal, but it cannot be an expression (entry error).

Strings are left justified; integers are right justified.

PRNT always affects eight entire screen cells starting at the specified position. The actual printing is done with white text on a light blue background (no matter what colours were there in the first place, so if colour coordination is important to you, plan accordingly :-). PRNTing to cells 0 or >761 causes no error, but nothing is printed, either.

RAND(a)? Returns a random number between 0 and a, inclusive. a may be an expression, and RAND may be used in expressions itself (e.g. A=(4*RAND(Q)-3) is legal). There is no RANDOMIZE.
STOP? Standard BASIC, but when entered as a keyword (unlike END), the editor is not terminated. During runtime, when a STOP is found, the line is displayed, and execution halts.
TIME a {ON}? When used with the optional ON parameter, enables one of the built-in timers, of which five are documented but seven appear to exist, specified by a (e.g., TIME 5 ON enables timer 5). a must be a literal (1-7); otherwise, an entry error occurs. Each timer counts up by one every 1/100 sec, up to a maximum value of 4000.

Irritatingly, the actual value of the timer cannot be directly referenced (let alone altered) in expressions (X=TIME 1 generates an entry error); only IF can see the value of a timer e.g., IF TIME 1>20 THEN 50 and nothing else! (IF TIME 1=X, i.e., comparing timers with variables is legal.)

There is no way to reset the timers except to stop the program, and TIME 1 OFF causes an entry error. TIME 1 ON can be specified repeatedly, but it does not reset the timer each time.

TONE NOa? Plays predefined sound a (1-4). Note that there is no space between NO and the a parameter -- it's TONE NO1 and not TONE NO 1 as it occasionally appears or at least looks like in the manual. a must be an integer literal; otherwise, an entry error occurs.

Tone 1 is the key beep; tone 2 is the error buzz; tone 3 is the 'da da da' three-tone acknowledge sound; and tone 4 is the buzz'n'hiss crash sound (like the one you get from biffing it in Traffic Jam). Playback is asynchronous and goes in the background; a new TONE will cancel and replace any currently playing sound.

VERT(a)? Undocumented. Returns the Y coordinate of a 16-bit sprite position quantity (e.g., VERT(ANIM 3) gives the Y position of sprite 3). See POST for the sprite coordinate system. a can be an expression, and VERT can be used in expressions too (basically a rapid equivalent to taking the MSB of a 16-bit integer).

Back to the top | Back to "How To Program In GBASIC" | Back to "Programming The Tomy Tutor"