[ Go to Stephen's Entry Page ]
[ TI99/4a Articles index |    TI Book front page |    TI Resources Page |   PC99 Programs ||    TI*MES 37 || TI*MES 39 ]
contact - please use subject="pc99 page" to avoid spam trap!

Jump to:
Basic: Easy math program |   Date Formats |   Graphics: Attractors |   Games Review: Mancala
TI Writer: Lower Case file names |   Algorithms |   Assembly Language Part 1

This web page contains the text of articles for owners of the TI-99/4a from Issue 38 TI*MES (Autumn 1992). It is of use to users of the TI-99/4a emulators.

Items from TI*MES Issue 38 Autumn 1992

It was announced that "Stephen Shaw has become an honorary life member of TIUG(UK). Stephen was a founder member of the group and has been a great servant to the TI community and I'm sure that you would all want to join me in thanking him for his invaluable contribution to the group."

Article by Stephen Shaw

This is a fractal program which works on the basis of attraction, which we have covered before - the pattern is drawn in an apparently haphazard manner (watch it form) but after many dots have been plotted, there IS a pattern. as the plotted dots are "attracted" to the final pattern.

The program is short, but as many dots are required, it has been left as a closed loop. Using The Missing Link, it is possible to dump to printer irom the running program, and if you BREAK, you can save it in Artist format from command mode.

Other pixel-based languages can of course be used, but in the absense of interrupt driven dumps and the ability to retain a graphic after BREAK, you may need to insert a key test routine.

For those mathematically inclined the routine is based on the formula


In the program the variable M represents the number of sides in the final outer envelope, with a minimum of 3. 6 works well, but not 4 or 8. Odd values seen to be all OK - as the value gets higher so the shape tends to a circle.

Variables A and C always have the same sign (- or +) which always differs from the sign of variable L. The pattern can zoom off to infinity (easily tested) or very quickly settle into a small stable area or two stable areas, quickly apparrent watching the screen.

symmetric attractors 100 READ A,B,C,M,L,SC,X0
110 DATA 1,0,0.5,3,-1.804,80,80
130 ! functions with symmetric attractors
140 ! uwe quasthnff, leipzig
150 ! fracta1 report #21 June 1992
150 ! for ti99/4a + TML by
170 ! stephen shaw uk 6/92
180 !
190 X,Y=0.01
200 U=X*X+Y*Y
210 XX=1
220 YY=0
230 FOR I=1 TO M-1
250 YY=XX*Y+X*YY
260 XX=XXN
270 NEXT I
280 V=XX*X-YY*Y
290 X=(A*U+B*V+L)*X+C*XX
300 Y= (A*U+B*V+L) *Y-C*YY
320 GOTO 200
340 END

In order to investigate other variable values, I have amended the program as below, to produce random numbers within a range which TEND to produce results...

30 M=INT(RND*7+3) :: IF M=4 OR M=8 THEN 30
100 A=INT (RND*6-RND*6)
101 C=RND*1.1*SGN(A)
102 IF ABS(C)<0.3 THEN 101
110 B=2*RND :: L=1.2+RND*1.6 :: L=L*-SGN(A)
115 SC=95 :: X0=96
205 IF U>1E12 THEN RUN

Or try these data values in line 110:
DATA 2,-0.2,1.0,3,-1.75,140,80
DATA -1,0.1,0.8,3,1.520,80,110
DATA -2,0.0,-0.5,5,2.60,75,105
DATA -1,0.1,-0.8,5,1.30,100,100
DATA 5,2.0,1.0,6,-2.7,120,100
DATA 5,2.0,1.0,6,-2.585,130,100
DATA 1,0.04,0.1,7,-2.065,80,100
DATA 4,2.0,1.0,9,-2.6,100,100
DATA -4,1.32,-0.51,9,2.64,95,95

There are some very fine details to be found by taking a closer view (the same as using a higher definition) but this takes a great deal longer - if the image was plotted to 1200 x 1200 pixels you would need to plot around half a million dots to get the detail.

Go to top of page


The superb never released module is available from the library and includes some docs by myself. Here is a discovery, which is to be credited to my 8 year old son George Shaw: Mancala has a HELP mode, very like the old Chess module.

Whether you play two players or against the computer, when it is your turn, and you are stuck press AID, then select the level of aid you require (from genius, 5 levels). The computer will then move the oversize cursor to the pit it suggests you empty. To select the pit just press fire or Q. If another move is immediately possible, you can again select AID or play on your own.

You are not obligated to play the suggested move.

This program was evidently ready for release, as it is in a very well finished state. Highly recommended!

TI Writer TI Writer Tip:

Should you ever wish to load or save a text file with a lower case filename, you may have noticed that TI WRITER and its clones will only allow the use of upper case characters in the command line.

If you really want lower case, then use Funlweb which allows you to convert upper case to lower case by passing over the upper case letters pressing CTRL and the semi colon key together (that's a ";"- just to the left of ENTER).

Fun Maths A simple Basic program for young maths wizards...

Here is another listing, keyed in by my 8 year old son, so no excuses about it being too long for you...

120 TED=5+INT(10*RND)
130 DIFF=2+INT(8*RND)
150 DISPLAY AT(7,1):"Dave is";DIFF;" years older than Ted"
160 DISPLAY AT(9,2):"The sum of their ages is";
170 DISPLAY AT(11,5):DIFF+(2*TED)
180 DISPLAY AT(13,1):"How old is Ted?"
190 INPUT "Age? ":ANSWER
210 DISPLAY AT(17,10):"Sorry, that's wrong"
220 DISPLAY AT(18,5):"The correct answer is: "
230 DISPLAY AT(19,12):TED
240 FOR I=1 TO 2000 :: NEXT I
250 GOTO 110
260 DISPLAY AT(23,1):"CORRECT! Well done!"
270 FOR N=1 TO 5 :: CALL SOUND(-200,110+N*5,8):: NEXT N
280 FOR T=1 T0 200 :: NEXT T
290 GOTO 110
300 END
Program credited to David and Michael Curl for Spectrum computer
from The Book of Classic Puzzles and Word Games by Gyles Brandreth,
Chancellor Press, 1992. ISBN 1 85152 114 3

Date Format DATE 890305


There are many conventions used to represent the date, but I have found one to he more useful for computer applications. The format which I use is YYMMDD, such as 890305 for March 5, 1989. Below are some of the ways to represent this date:
March 5, 1989
Mar. 5, 1989
5 Mar 89

The March 5, 1989 format has the least possible confusion over meaning, but is also the least efficient for use by a computer. The length of the notation depends upon the specific date, for example December 31, 1989 takes more characters than March 5, 1989. With the format 890305, there are always six characters for the date.

The input can be read as either a numeric field or as an alphanumeric (string) field. When sorted, the dates will be in proper date sequence. If you sort a format such as 3-5-89, then the month and day sort properly, but there is a problem with 12-22-88 coming after 3-5-89 instead of before. Some programs get around this by changing the representation of the date internally for calculations, but then presenting the date in a format such as 5 MAR 89 for the user.

I am sure you will continue to use the date format which is most convenient for your particular application, but now you have at least one more format to consider, and one which you will find useful for computer applications.

Go to top of page

What comes next? Algorithm Design

Garry J Christensen
Brisbane User Group, Australia

ALGORITHM - a systematic procedure for solving a problem or accomplishing some end.

Programming some tasks on the computer is easy. Many short programmes can be written quickly and with little fore-thought. This is not always the case. The more complicated the problem, the more involved the solution. There cones a stage when the programmer must sit down and work out both how he will approach the problem and how the programme will work.

An ALGORITHM is usually the result of this work. The algorithm is probably the most important part of any programme yet it is so often ignored.

Once the algorithm has been written, the programme is much easier to write and frequently will have fewer bugs. That does not mean that algorithms only apply to computing. An algorithm can apply to any situation where a result is required. Consider the algorithm for finding the partner of your dreams using a dating service:

Send money
Wait for reply from dating service
Contact date
Go out with selected partner
Repeat until suitable partner is found
This process is far from perfect as you may go broke before getting married but the algorithm still exists.

The first part of algorithm design is the analysis of the problem. In simple cases, the answer is obvious but sometimes it may require some thought to determine the solution. Consider also that the solution may not be unique. There may be other ways of doing the same thing. Before even touching the keyboard, try to determine that the method you have chosen is the best.

The second part is to determine the steps that will lead to the solution. This part involves a method called top-down developement or step wise refinement.

Start with the steps written in very broad terms (generally using English) then refine each step into a series of more detailed steps. Each of these steps can then be further refined, and so on until the steps are close enough to the programming language to allow easy conversion. Don't start to write programme code in your algorithm until the very last step. `

Let's consider the algorithm necessary to instruct a robot to make a cup of coffee. The solution is simple so lets define it in broad terms.
1 Boil the water
2 Put coffee in the cup
3 Put water in the cup

There are two types of traps that I should point out at this stage. The first is called the "first catch your rabit bug"- we have so far assumed that there is a kettle for the robot to use and that there is a tap available. Nowhere have we told the robot to "Find a kettle" or "go to the tap".

The second trap is called the "initial state of things bug". What will the robot do if the water is already turned on. when told to "turn on the tap" it may screw it out of the wall.

The secret to writing an algorithm is to keep the following in mind
1. Start at high levels (use English to express very broad steps)
2. Concentrate on refining one step at a time
3. Don't start writinq programme code until the steps are approaching the level of the programming statements

Lets now work through a couple of examples

I will use the selection of all the prime numbers between 1 and 100 as an example. (A prime number cannot be evenly divided by any number other than 1 and itself, eg 7).

Problem: How do I determine whether a number is prime.

The simplest answer is to divide it by all the numbers less than the number in question and see if any produce a whole result. That is a valid method but not very efficient.

If the number is 50, dividing it by any number greater than 25 cannot produce a whole result (50/26 = 1.something). If the number is called N, we need only divide by all the numbers up to N/2.

To test all the numbers from l to 100, we need to test them all in this method. The algorithm development follows:
1 Set N to 1
2 Is it prime?
3 If so then print it
4 Add 1 to N
5 Go to step 2 if N is not greater that 100

Steps 1, 4, and 5 are very close to a basic statement so the next step refinement will convert them to code. The others need a little work.

1 FOR N=1 TO 100
2 Is N prime?
  2.1 Set D to 2
  2.2 Is N/D a whole number?
  2.3 If so, go to step 4 (not prime)
  2.4 If not, add 1 to D
  2.5 If D is less than half of N, then go to step 2.2
3 PRINT N (this step is jumped over if not prime)

Further refinement is not needed

FOR N=1 TO 100
2 Is N prime?
  2.1 FOR D=2 TO N/2
  2.2 IF N/D=INT(N/D) THEN Step 4
  2.4 NEXT D

The programme:
100 FOR N=1 TO 100
110 FOR D=2 T0 N/2
120 IF N/D=INT(N/D) THEN 150
130 NEXT D
150 NEXT N

While this algorithm demonstrates the best way to build up an algorithm, it falls short in one point. The approach to the problem is not necessarily the best. Stop reading here and try to find a more efficient way to find prime numbers.

Did you think of one? Follow the next algorithm through. You will notice that I have used indenting to seperate the levels of detail. If you want only brief outline, read the parts of the algorithm that are not indented. The further indented, the more detailed.

REM This method sets up an array of flags for each number between 1 and 100.

1 Initialize the array
  1.1 Dimension array
  1.2 Set array pointer to 1
  1.3 Set array element to 0
  1.4 Increment the pointer
  1.5 Repeat until pointer in greater than 100
2 Remove the non-prime numbers
  2.1 Set N to 2
  2.2 Remove all multiples of N up to 100
    2.2.1 Set pointer to value of N
    2.2.2 Check that this value has not been removed by a previous pass
    2.2.3 If it has then go to step 2.4
    2.2.4 Add N to value of pointer
    2.2.5 Set array element to 1
    2.2.6 Go to 2.2.4 and repeat until pointer is greater than 100
  2.3 Increment N
  2.4 Repeat until N is qreater than 50 (100/2)
3 Print the remaining numbers
  3.1 Set pointer to 1
  3.2 Does the flag indicate that the number is prime?
  3.3 If not then go to step 3.5
  3.4 Print the value of the pointer
  3.5 Increment the pointer
  3.6 Repeat until end of array

The programme will look like this
100 DIM FLAGS(100)
110 FOR I=1 TO 100
120 FLAGS(I)=0
130 NEXT I
140 FOR N=2 TO 50
150 IF FLAGS(N)=1 THEN 190
160 FOR I=2*N TO 100 STEP N
170 FLAGS(I)=1
180 NEXT I
190 NEXT N
200 FOR I=1 TO 100
210 IF FLAGS(I)=1 THEN 240
230 NEXT I

As you can see, the algorithm is easy to follow and you will have to believe me when I say that it made the programming much easier. I tried it first without an algorithm and the result was both longer and less efficient

It seems that the computer science proverb is correct: 'The sooner you start coding, the longer it will take to write a programme that is correct'

Go to top of page

Assembly Language The Art of Assembly Part 1 by Bruce Harrison

Frustrated with Extended Basic? Tired of waiting for C? Fed up with Forth? P. O.'d at Pascal? The answer to your problems is the "Native Language" of your computer's heart, Assembly Language.

Many programmers today shun this language as being unnecessary, antiquated, and obsolete. We who do our programming in Assembly believe that it's the most valuable of all computer languages. There are three things that make Assembly worth while:
(1) It maximizes the speed of execution of any operation we're trying to perform;
(2) It can minimize the memory required to perform any given tasks; and,
(3) Through Assembly we gain access to all the facilities and capabilities the computer has to offer.
No other language can make those three things true at the same time.

From the programmer's viewpoint, there are two major drawbacks to Assembly:
(1) It is very labor-intensive. A simple "Accept At" function may require two pages of source code to implement;
(2) It requires a much more intimate knowledge of what really goes on in the computer. Such knowledge takes lots of study, and much trial and error plodding to acquire.

This series of articles is based upon years of experience, much of it painful, in exploring the capabilities and limitations of the TI-99/4A through Assembly programming. It is not designed as a beginner's course. For that, we recommend Ralph Molesworth's excellent book Introduction to Assembly Language Programming on the TI-99/4A from Steve Davis publishing. Available as a 14MB download from TI Books.

In this first installment, we'll cover some general topics as background for the programmer who's ready to move beyond the beginner stage, but is not quite sure how to proceed. We'll cover the topics of Structure and Memory mapping. This will be very general coverage, just to give you the "feel" of thinking through your programming efforts. In later installments, we'll get into the more detailed aspects so you can become comfortable in programming with Assembly.

Structure is your servant! We say that deliberately. For many programmers the relationship becomes the wrong way around, as they slavishly "structure" far beyond any logical reason or necessity. Structure in your programming effort should help you to keep your efforts organized and focused, and in some cases will help minimize the memory required to hold your programs and data. It must not be allowed to become an end unto itself.

Perhaps a small example will help illustrate my point. In a book on PC Assembly Language, the author put together a whole book of subroutines which, for the most part, could be lifted directly and used in PC programs. In some instances, however, he went overboard with structure. He gave a subroutine to place a single character on the screen. To use the subroutine, one would place the desired character's ASCII value in a register, then call the subroutine to display that character. He presented another subroutine to place a space on the screen. That subroutine simply placed ASCII 32 in the register, then called the "display a character" subroutine.

What's wrong with that process is mainly that there's twice as much "overhead" in both time and memory usage to print a space that way. The main program could put any character, including a space, in the register, then call the "display character" subroutine, rather than involve two levels of subroutine to perform the same function.

That kind of thinking is rampant in the PC Community, and is one of the reasons PC owners need Megabytes of memory to run commercial software packages. On the TI, with its limited memory capacity, we can't afford that kind of thinking. Again, structure is useful only so long as it serves the programmer.

I'll cite just one other example of structure gone amok, from a TI Basic program I once examined. (I won't name the program or the author.) This program used a menu selection to execute its functions. Each function was organized as a subroutine. Not one of those subroutines was called from more than one place in the main program. A simple ON-GOTO to branch directly to the desired section of the code would have done nicely, with a GOTO at the end of each function to return to the menu. In later installments of this series we'll show an efficient and effective way to perform branching from a menu-select situation, using an Assembly version of the ON-GOTO function.

So how does one sensibly apply structure without going overboard? There are two approaches which we use here at Harrison in combination. They're called Top Down and Bottom Up. From the Top Down, we recommend that some kind of overall flow chart be constructed early in the "thinking" stage of the program. For many programmers, it will help to actually draw a chart of the flow through the program's major functions.

In some cases, a physical chart won't be required, but there should be at least a mental image of what the major functions are and how they should relate to one another. On occasion in my programming experience, I've ignored my own advice on this matter, and in all such cases have gone through endless agonizing revisions and re-writings of code because I omitted that first step.

Once the major functions are identified, the Top Down approach proceeds to break those into smaller and smaller subdivisions of what needs to be done. From this a pattern will emerge, showing that many places in the main stream program will need the same primitive operations performed. This is where the idea of subroutines becomes a powerful tool, and it's also where the Bottom-Up idea can be useful.

In Bottom-Up programming, we start with simple functions, such as getting keystrokes from the keyboard, or placing characters on the screen, then build a program structure to optimize the use of these "primitive" tools.

Good programs need the influence of both these approaches at the same time.

Once the overall structure is broken down a couple of levels, we should have a clear view of what kinds of subroutines we'll need, and how to use them in building upward to bigger structures like menu drivers, input screens, and so on. Experienced Assembly programmers usually have a stable of existing subroutines developed as part of other efforts, so they can use those, usually with minor modifications, in the new program. In future articles, we'll present actual source code for subroutines we've found useful.

Memory is your Master! Now let's move on to the subject of Memory. There isn't much, so we must be careful how we use it. That starts with a knowledge of what we can use. There are two major blocks of memory available to the Assembly programmer. In Low Memory, from >2000 thru >3FFF, there are about 6K bytes that we can safely use, reserving the space at the beginning for the E/A utilities, and space at the end for the REF/DEF table.

In High Memory, there is lots of space, about 24K bytes from >A000 through >FFE6. In a normal E/A 3 program, only this 24K byte section will be open for your use as program storage. There are ways to make effective use of the low memory part as well as the high memory part, but these require techniques such as AORG, which we're not ready to cover just yet. Just to give you a hint, virtually every program we write here at Harrison involves use of AORG to give us maximum use of the available memory.

One frequently overlooked memory resource is the memory associated with the Video Display Processor, also known as VDP RAM. This can't be used directly for executable code, but can be used for a kind of "auxiliary" data storage. In most modes of VDP operation, there are about 10K bytes of VDP RAM that can be safely used to stash data.

In this series of articles, we'll show many techniques for saving memory in performing various functions.

In our next article, we'll start from the bottom up with some primitive subroutines that we've used. Along with that, we'll show the techniques for minimizing use of memory and maximizing speed of execution. When the series is done, we'll offer the whole series on disk as D/V 80 files to make them easier to access.

Go to top of page

[ TI Book front page    |    TI Resources Page    |   PC99 Review    |   PC99 Programs ]