Level II Tips and Tricks – Menu
General:
- System Status/ID
- Reset Button Pokes
- Break Key Pokes
- Keyboard Tips and Tricks
- Video Tips and Tricks
- Routing between Video and Line Printer
- Cause a TRS-80 to Reset
- Determine Time and Date via PEEK
- Model 4 Speed-Up
- Printer Tips and Tricks
- Input/Output Tips and Tricks
- Misc. Tips and Tricks
SYSTEM TAPE Tips and Tricks:
BASIC Tips and Tricks:
- Finding the START and END of a BASIC Program
- Finding the current line number being executed in a BASIC Program
- Finding the current cursor location
- Finding the current cursor character
- Set MEMORY SIZE from BASIC
- Key Word Tips and Tricks
- Rescue a Program after typing NEW
- Append Two Programs Together in Level II BASIC
- Get your 48K if your Expansion Interface was Off
- Change the Cursor in Non-DOS BASIC (AWFUL)
- Renumbering a BASIC Program
- Poking above 32767
Miscellaneous Routines:
- Screen Print Routines
- Voice Control
- Super Sorting (by TR Dettman)
- Level I Keyword Abbreviations
- Set a USR Routine for DOS and Level II
System Status/ID
What Model TRS-80 Is It
What Peripherals/Mods Are Attached/Status
PRINT PEEK (15360)
PRINT PEEK (15360)
Other
Reset Button Pokes
NOTE: These pokes will work only if there is no expansion interface connected.
POKE 16831, 73
POKE 16832, 27
POKE 16832, 30
POKE 16832, 2
- Load machine language program
- At second *? hit break
- POKE 16830, 195
POKE 16831, PEEK(16607)
POKE 16832, PEEK(16608)
POKE 16392,MSB of Program
20 Q=VARPTR(QQ$):Q1=PEEK(Q+1):Q2=PEEK(Q+2)
30 POKE16812,195:POKE16813,Q1:POKE16814,Q2
40 RETURN’ 4007H-LSB,4008H-MSB
Break Key Pokes
POKE 17171, 201
POKE 17171, 164
(or 147 or 223)
Keyboard Tips and Tricks
DISABLED: POKE 119,(PEEK(119) AND &H7F)
PEEK(14400) = 16 for down
PEEK(14400) = 32 for left
PEEK(14537) = 2 for CLEAR
PEEK(14537) = 4 for BREAK
PEEK(14537) = 8 for up
PEEK(14537) = 16 for down
PEEK(14537) = 32 for left
PEEK(14537) = 64 for right
PEEK(14537) = 128 for SPACE.
Video Tips and Tricks
NOTE: 16413 is 401D in Hex which is the beginning the of Video DCB.
OFF: POKE &HB94,(PEEK(&HB94) AND 247)
OFF: POKE &HB94,( PEEK(0) AND 8 )
Determine DATE and TIME via PEEK
To determine MM/DD/YY HH:MN:SS on a Model I, PEEK the following locations:
- MM – 16454
- DD – 16453
- YY – 16452
- HH – 16451
- MN – 16450
- SS – 16449
To determine MM/DD/YY HH:MN:SS on a Model III, PEEK the following locations:
- MM – 16924
- DD – 16923
- YY – 16922
- HH – 16921
- MN – 16920
- SS – 16919
Model 4 Speed-Up
To speed up the Model 4, issue the following commands from basic:
X=PEEK(16912)
X=X OR 64
POKE 16912,X
OUT 235,X
Printer Tips and Tricks
= Lines per Page + 1 (so normal return is 67)
PEEK (14312) = 255 (Printer is off)
PEEK (14312)= 191 (Printer Buffer is Full)
PEEK (14312) = 223 or =233 (Out of Paper or offline)
PEEK (14312) > 127 (NOT ready)
POKE 16422,41 (Turn it on/Reset It)
Key Word Tips and Tricks
AUTO Command
POKE 16613, 0
LIST Command
POKE 16864, 25
POKE 16865, 26
POKE 16864, 114
POKE 16865, 0
NOTE: 16863 is 41DF in Hex.
LLIST Command
POKE 16423, 00
RND Function
POKE 16555, 10
POKE 16556, 15
NOTE: 16544 is 40AA in Hex. This is the ROM location for the 3 byte random seed number.
TRON Command
NOTE: 16667 is 411B in Hex. This is the ROM location for the TRON Flag; 0 is off, 175 is on.
Misc
SYSTEM
* / 11395
LIST
NOTE: 17130 is 42EA in Hex which is 1 above the normal start of BASIC program.
11395 is 2C83 in Hex.
DO NOT INVOKE THE EDIT COMMAND AFTER DOING THIS.
POKE 16608, MSB
Level I Keyword Shortcuts
Input/Output Tips and Tricks
while reading or writing data.
1,2,3 for drive 0,1, and 0+1 respectivly
to the lineprinter to be sent to the video
POKE 16423, 4
POKE 16423, 5
to the video sent to the lineprinter, use:
POKE 16415, 5
POKE 16415, 4
NOTE: 14308 is 37E4 in Hex. 37E4 is the Model I cassette 1 or 2 select (0 or 1).
NOTE: 14308 is 37E4 in Hex. 37E4 is the Model I cassette 1 or 2 select (0 or 1).
Set MEMORY SIZE from BASIC
To set MEMORY SIZE from BASIC:
- Set your MEMORY SIZE as normal.
- PEEK 16562 and 16561 and note their values
- Add a line in your program that POKEs those values into those corresponding locations
- Add a more command after the POKEs that says CLEAR0:CLEAR50
From now on your basic program will set its own MEMORY SIZE. Be sure to put the pokes and clears at the beginning of the program.
For a more visual method, the following program might be useful:
10 ME = xxxxxxx : ' This is your desired memory size
20 MS = INT (ME / 256) : ' This will get the MSB of the Memory Size
30 LS = ME - (MS * 256) : ' This will get the LSB of the Memory Size
40 POKE 16561, LS : POKE 16562, MS
50 CLEAR : RESTORE
NOTE: 16561 is 40B1 in Hex. 40B1 and 40B2 are the pointers to highest address available for string storage (set by MEMORY SIZE).
Another way …
10 POKE 16561,LSB : POKE 16562,MSB 20 CLEAR 50 30 END
Set a USR Routine for DOS and Level II
10 A=PEEK(16396):IF A = 195 THEN AD=23316 ELSE AD=16526 20 POKE AD,LSB:POKE AD+1,MSB
Cause a TRS-80 to Reset
Note: 16415 is 410F in Hex. 410FH is the second of a two-byte video driver vector which normally points to 0458H which is the video driver for Model I (the 2 peeks are 88 and 4 which is 1112 in Decimal or 0458 in Hex).
When changing the 88 and 4 to 88 and 5 you change the jump from 0458H to 0558H. I don’t know what that means, but it is apparently bad.
Routing between Video and Line Printer
POKE 16423, 4
NOTE: 16422 is 4026 in Hex. 4026H is the two byte printer driver vector.
88 and 4 is the LSB/MSB of 1112 which is 0458 in Hex. 0458H is the video driver for Model I.
POKE 16423, 5
NOTE: 16422 is 4026 in Hex. 4026H is the two byte printer driver vector.
141 and 5 is the LSB/MSB of 1421 which is 058D in Hex. 058DH is the line printer driver for Model I.
POKE 16415, 5
NOTE: 16414 is 401E in Hex. 401EH is the two byte video driver vector.
141 and 5 is the LSB/MSB of 1421 which is 058D in Hex. 058DH is the line printer driver for Model I.
POKE 16415, 4
NOTE: 16414 is 401E in Hex. 401EH is the two byte video driver vector.
88 and 4 is the LSB/MSB of 1112 which is 0458 in Hex. 0458H is the video driver for Model I.
Rescue a Program after typing NEW
To bring back a program after NEW has been typed:
- POKE 17130, 1
- SYSTEM / 11395
DO NOT INVOKE THE EDIT COMMAND AFTER DOING THIS.
Renumbering a BASIC Program
Simple Renumbering
P=17129 FOR L = 1 TO 9000 IF PEEK(P+1) > 0 THEN POKE P+3,PEEK(P+3)+125 : P = PEEK (P) + 256 * PEEK (P+1) : NEXT
NOTE: 17129 is 42E9 in Hex. 42E9H is the memory location of the start of a BASIC program.
Another Example
10000 L = 10 10010 C = 17129 10020 N = PEEK (C) 10030 N = N + (PEEK(C+1) * 256) 10040 POKE C+2, L 10050 POKE C+3, H 10060 L = L + 10 10070 IF L > 250 THEN L = 0 : H = H + 1 10080 IF H = 255 THEN PRINT "TOO MANY LINES" : END 10090 C = N 10100 GOTO 10020
NOTE: Start by doing a RUN 10000, but since it will renumber itself, the routine will end in a ?UL Error. Only line numbers are changed; GOTOs and GOSUBs remain as they were.
Poking above 32767
If you try to POKE 65535,0 you will get an overflow error. This is because the PEEK and POKE commands require an integer argument for the memory address. The secret is that you must convert any address above 32767 by subtracting 65536 from the number. Therefore, the proper command to poke zero into the highest address of a 48K TRS-80 is POKE–1,0. To look at the contents of the top byte in a 48K TRS-80, your program can use, PRINT PEEK(-1).
If your program will be doing a lot of peeking and poking to high memory (above 32767), you may want to include the function calls listed below. They let your program handle memory addresses in single precision format so that you don’t have to worry about overflow errors.
To allow peeking or poking any address in the range 0 to 65535, define the following function early in your program:
DEFFNSI%(S1)=-((S!>32767)*(S!-65536))-((S1<32768)*S!)
Then you can PEEK FNSI%(#####) and POKE FNSI%(xxxx),xx
Change the Cursor in Non-DOS Basic (AWFUL)
This nasty little routine will change the cursor in non-DOS BASIC. It will ALSO have the designated cursor character end each line on the screen, but rather than toss this fairly useless code, here it is …
10 REMEMBER TO CHANGE XX IN LINE 50 WITH THE ASCII VALUE OF WHAT YOU WANT 20 FOR X = 32512 TO 32522 : READ A : POKE X, A : NEXT 30 POKE 16414, 0 : POKE 16415, 127 40 DATA 205, 88, 4, 229, 42, 32, 64, 54 50 DATA XX 60 DATA 225, 201
Append Two Programs Together in Level II BASIC
To append two programs together in LEVEL II BASIC, do the following steps:
- CLOAD the first program
- Note the PEEK values of 16633 and 16634
- If PEEK(16633) > 1 then subtract 2 from it
- If PEEK(16633) less than or equal to 1 then add 254 to it and subtract 1 from the PEEK(16634)
- POKE the modified PEEK(16633) number into 16548
- POKE the modified PEEK(16634) number into 16549
- CLOAD the second program
- POKE 16548,233
- POKE 16549,66
Jim Swenson explains how this works:
16548 (40A4H) points to the first line of the program in memory, which will be 17129 (42E9H) by default.
16633 (40F9H) will point 1 byte past the end of the program. If you run NEW you will find it will be 17131 (42EBH).
With:
40A4: E9 42 (start of program)
Say your BASIC program is the following:
10 PRINT "HELLO" 20 GOTO 10
In memory, this will actually look like the following:
42E9: F7 42 0A 00 B2 20 22 48 45 4C 4C 4F 22 00 42F7: 00 43 14 00 8D 20 31 30 00 4300: 00 00 4302: ... 40F9: 02 43 (end of program)
The end of program is one byte past the 00 ending at 4301H, so it is 4302H. The TRS-80 ROM puts things LSB (least significant byte) then MSB (most significant byte), so 4302H would be represented as 02 43.
In memory, a line of a BASIC program is stored as follows:
- 2 bytes: address of the next line
- 2 bytes: the line number
- n bytes: the line itself, with reserved words replaced by a single byte code. For example “PRINT” is B2, “GOTO” is 8D
- 1 byte: 00
Taking the line 10 PRINT “HELLO” as an example:
42E9: F7 42 0A 00 B2 20 22 48 45 4C 4C 4F 22 00
42F7 (in LSB, MSB order) is the address of the next line in memory (i.e. for line 20)
000A is the line number (10, which is 0A in hexidecimal)
B2 20 22 48 45 4C 4C 4F 22 is the line of code:
B2 – PRINT
20 – space
22 – “
48 – H
45 – E
4C – L
4C – L
4F – O
22 – “
00 being the end of the line
The indication of the end of the program is when the address of the next line is 00 00. And 16633 (40F9H) will point 1 byte after that.
CLOAD will start loading data wherever 16548 (40A4H) points. So if you set it to (16633)-2 (which is (40F9H)-2), you’re pointing it to that 00 00 in memory. They when CLOAD completes and you restore the value in memory at 16548 (40A4H), you’re restoring the start of the program to its original value.
Finding the START and END of a BASIC Program
NOTE: 16548 is 40A4 in Hex. 40A4H is the start of BASIC program pointer. Normally it would be 42E9H
NOTE: 16633 is 40F9 in Hex. 40F9H is the top of BASIC program plus 1
Finding the current line number being executed in a BASIC Program
Finding the current cursor location
Finding the current cursor character
Easy Way to Load a SYSTEM Tape
When loading a system program one normally must enter the proper embedded filename at the first prompt, or the program will not load. However, this is not (entirely) necessary!
Instead, if you type only the first letter of the program you are loading, it will work.
As an example, if the program name is “CLONE” you can enter C, CL, CLO, CLON, or CLONE after the *? and ALL OF THEM WILL WORK.
However, if you enter CLA it will not work. Why? The computer only checks for as many characters of the name as you type in after the *? but loads only in if the same length of characters match. You must enter at least 1 character name.
Get your 48K if your Expansion Interface was Off:
If your expansion interface is off and you suddenly wish it had been on when you started doing whatever you were doing, and you need the RAM it has right now without restarting your computer and losing what you have, do the following:
- Turn on the expansion interface
- POKE 16561, 255
- POKE 16562, 255
- CLEAR 50
That’s it … you should have your RAM.
Note: George Philips has advised that it is very very bad to turn on your E/I while your Model I is powered on. He also advised that the reason this works is that when the machine starts it decides how much RAM it has by stepping through all possible RAM addresses and seeing if RAM is there by writing a test value or two and seeing that you get the result back. If you don’t get what you wrote, there’s no RAM there (or it is faulty). That highest available RAM location is stored in 16561, 16562.
If you boot without the E/I then it will look to BASIC as if you only have 16K. Poking in the 255’s makes it think you have 48K because 255 * 256 + 255 == 65535 which is the highest possible address on the TRS-80 Model I. Note that this won’t work if your E/I has only 16K in it as you’ll have 32K total and the machine will crash trying to access the uninitialized memory.
The “CLEAR 50” is important because BASIC keeps track of another pointer and that command serves to update it. You need to give it the “50” (or some other parameter) so that it makes the change. Otherwise it will just reset your BASIC program’s variables and do nothing else.
Misc. Tips and Tricks
The X and Y are Y=3*INT(P/64) : X=2*(P-64*Y/3)
/ 20992
NOTE: 1740 is 06CC in Hex. 06CCH is an alternative address for entering BASIC.
Screen Print Routines
Jay Reso of Metairie, La. suggests the following routine for printing the contents of the video display to a lineprinter:
1000 DIM S$(15) 1010 FOR T=0 TO 15 1020 S$(T) = "" 1030 POKE VARPTR(S$(T)),64 1040 POKE VARPTR(S$(T))+1, (T*64 + 15360) AND 255 1050 POKE VARPTR(S$(T))+2, (T*64 + 15360) / 256 1060 NEXT T 1100 FOR T=0 TO 15 : LPRINT S$(T) : NEXT
Line 1020 establishes S$(T) with a location in memory. Line 1030 sets the length of the string to 64 bytes. Lines 1040 and 1050 set the string pointer to the location of the first byte of a video line.
Once you have executed lines 1000-1060, you can execute 1100 at any time and you will get a printed copy of the screen. Remember that you cannot print graphic characters to a lineprinter. One other caution is that you may not ASSIGN values to the strings S$(T). If you try to as-sign values to these strings, you will reset the pointers and you will have to rerun lines 1000-1060.
Print the Concents of the Screen on a Line Printer
10 CLS 20 CLEAR 500 : DIM S$(15) 30 FOR T = 0 TO 15 : S$(T)="" 40 POKE VARPTR(S$(T)),64 50 POKE VARPTR(S$(T))+1,(T*64+15360) AND 255 60 POKE VARPTR(S$(T))+2,(T*64+15360) / 256 70 NEXT T 80 FOR T = 0 TO 15 : LPRINT S$(T) : NEXT 90 INPUT A$ 100 GOTO 80
M. Thorpe’s Screen Graphics Hard Copy Generator
3000 ' SCREEN GRAPHICS HARD COPY GENERATOR 3010 ' 3020 FOR X =15360 TO 16383 STEP 64 3030 A=1: B=2: C=1 3040 FOR K=X TO X+63 3050 IF ((PEEK(K)-128) AND A) = A THEN LPRINT"#";:GOTO 3070 3060 LPRINT" "; 3070 IF PEEK(K) =32 GOTO 3090 3080 IF ((PEEK(K)-128) AND B) = B THEN LPRINT"#";:GOTO 3100 3090 LPRINT " "; 3100 NEXT K 3110 LPRINT " " 3120 ON C GOTO 3130,3140,3150 3130 A=4: B=8: C=2: GOTO 3040 3140 A=16 : B=32: C=3: GOTO 3040 3150 NEXT X 3160 RETURN
If you need a sample program to test this with, try the following:
10 DEFINT I,J 20 CLS 30 FOR I = 0 TO 33 40 FOR J = 0 TO 50 50 A=INT(RND(0)+.5) 60 IF A=1 THEN SET(J,I) 70 NEXT J,I 80 GOSUB 3000 90 END
Voice Control – by Phillip Case
Recently the latest rage in programming has been the use of sound effects in games. In this issue of SoftSide is a program titled SONIC TORPEDOS which has a unique method of permitting you to control the program by voice Input. This article will show you how to use this technique in your programs.
Believe it or not, this technique was accidentally discovered by myself and Chris Freund (familiar name among SoftSide readers) while working on another program.
First, a microphone is required for voice input. It is to be plugged into the MIC jack of your cassette recorder. Then unplug both the AUX and REM plugs and leave them loose. When this is done, depress the tab sensor in the cassette bay, the RECORD and the PLAY keys all together.
The program commands themselves are relatively simple.
The microphone causes the value of the cassette to change whenever sound is sensed. To check the value of the cassette port use the INP(255) command. This will give you a value to work with in your program. The value of the port will be 255, if sound has been detected, and 127 if not. Use the INP(255) function as you would the INKEY$, i.e., within a loop.
Once sound has been detected, the value of the cassette port will remain at 255 until you either clear the screen (CLS) or home the cursor (PRINTCHR$(28)). This must be done to reset the cassette port for receiving sound. It is suggested that this be done just prior to checking the port so that no background sound be picked up.
There is a little problem that arises if you are in the character mode and you are trying to use this technique. Because the 32 character mode is controlled via the same port as the cassette recorder, the values of the port are different when you are in that mode. For the same reason it is possible to get double size letters on Level I with a little work.
Below is a table showing the various values under different conditions.
Here are two examples of how to use the sound input in your programs.
The following program will print ‘SOUND!!!’ in the upper-left hand corner of your screen whenever the computer is picking up input from the microphone.
10 CLS: PRINT CHR$(28) : IF INP(255) = 255 THEN PRINT “SOUND!!!” : GOTO 10 ELSE 10
The following program will display a graphic representation of your voice:
10 CLS : FOR X = 0 to 127 : PRINT CHR$(28): IF INP (255)=255 THEN Y=22 ELSE Y=23
20 SET (X,Y): NEXT : RUN
Super Sorting – by TR Dettman
Introduction
The next time you sort a list of items in your computer, try this experiment. Put an AM radio next to the computer, tuned away from any station. With this, you can actually hear the computer ‘think’.
If you try this, you will find that during the sort, a large amount of time will be spent doing something which changes the pattern of the sound completely. This change is the bane of most sorting techniques on the TRS-80, and it is called “Memory Management”.
Memory Management
To understand memory management, we have to look at how the computer stores information. For numbers this is simple since each variable is assigned space in memory for its value, resetting it doesn’t change where it is.
However, strings are handled differently. When we read in strings, the computer stores them starting at the top of free string memory (remember CLEAR N, it sets aside N bites for strings. RUN automatically does a CLEAR 50). The beginning of each string is recorded along with the length of the string in a location in memory provided for this. The VARPTR function gives you that location
If you have a string in memory called A$, its location is given by:
PEEK(VARPTR(A$)+1) + PEEK(VARPTR(A$)+2)*256
(see the Level II Reference Manual. p8/9).
The length of the string is:
PEEK (VARPTR(A$))
As you add strings into string space, they are added one after another as shown in the diagram.
When you reset the value of a string, the pointers to the string in memory are reset to their new values by the interpreter. But this is not all, since the string is treated as a new string and the old location of the string is not recovered.
A typical statement in a sorting program which changes one string for another is:
TS=A$(I):A$(l)=A$(J):A$(J)=TS
Even though the strings are already occupying space in memory, this statement generates THREE NEW STRINGS and adds them into the string space at the bottom.
When you fill up the string space (which will happen very quickly), the computer pauses to reorganize the memory and compact the string space by getting rid of unused space. During this time, your program just waits.
Even with the best sorting algorithm, as much as 90% of the computing time for the sort will be in memory management. In order to get efficient sorts we have to get rid of this wasted time.
Sorting with VARPTR
A significant improvement in sorting time (from 4 hrs to 8 minutes, for 450 items), is gained by redoing the program statement above that swaps strings as follows:
I1= PEEK (VARPTR(A$(I))): I2= PEEK (VARPTR(A$(I))+1): I3= PEEK (VARPTR(A$(I))+2) J1=PEEK (VARPTR(A$(J))): J2=PEEK (VARPTR(A$(J))+1): J3=PEEK (VARPTR(A$(J))+2) POKE (VARPTR(A$(I))),J1: POKE (VARPTR(A$(I))+1),J2: POKE (VARPTR(A$(I))+2),J3 POKE (VARPTR(A$(J))),I1: POKE (VARPTR(A$(J))+1 ),I2: POKE (VARPTR(A$(J))+2),I3
This set of statements creates no new strings in memory. It only changes the pointers to the strings. On large sorts, the improvement by using this technique is phenomenal. On a sort of 450 items in a mailing list, we had an improvement from 4 hours without this technique, to 8� minutes with it. This sort has now been included in our own mailing list program as well as Peripheral People’s Mailroom.
As this is being typed up for publication, we have seen an article elsewhere giving essentially the same sorting technique. We discovered only one minor problem with the way that it accomplishes the switch.
It uses the following statements to switch the pointers:
T1=VARPTR(A$(I)) T2=VARPTR(A$(J)) FOR Z=0 TO 2 A1=PEEK(T1 + Z) A2=PEEK(T2 + Z) POKE (T1+Z),A2 POKE (T2+Z),A1 NEXT Z
I found that the technique works well on long sorts, but that the pointers were dynamically allocated (a 25 cent buzzword for saying that they can move) on short sorts, say less than 10 items.
For short sorts, setting the values T1 and T2 resulted in not getting the pointer correctly. This has disastrous results since the pointers become random and you soon find that your strings begin to take on a funny look.
On one sort, some of the pointers actually wound up saying that the strings they referred to were in Level II ROM! In order to prevent this, the statements can be changed to be equivalent with mine.
FOR Z = 0 TO 2 Al = PEEK(VARPTR(A$(I))+Z) A2 = PEEK(VARPTR(A$(J))+Z) POKE (VARPTR(A$(I)) + Z), A2 POKE (VARPTR(A$(J)) + Z), A1 NEXT Z
Further Improvements
Still another improvement comes from changing all of the variables in the program to integers, except those that must be real or string variables.
Automatically Execute Your Machine Language Program on Tape Load
To automatically execute your machine language program once the tape finishes loading, do the following:
ORG 41BEH JP 7000H ORG 7000H START .... .... ;First Instruction .... .... END START
The key is that you have a 3 byte instruction following the ORG 41BEH.