Basic Speedup Tip

Basic and Machine Language

Moderator: Moderators

Boray
Musical Smurf
Posts: 4064
Joined: Mon May 03, 2004 10:47 am

Basic Speedup Tip

Post by Boray »

Basic Speedup Tip

When programming my 20 line basic game, I discovered something... I don't know if this is well known, but at least I didn't know about it. Here we go...

The variables first used in your program will be the fastest variables throughout the whole program. For example, if your program starts with this:

10 X=36879: F=12 : R=255 : B=45

Then X will be accessed faster than F. F will in turn be faster than R that will be faster than B. In the whole program. So to speedup a program, take a look at the most demanding part of your program to see which variables that are used the most. If you for example see that X, G and T are the ones you use the most, then just add something like this first in your program:

0 X=1:G=1:T=1

And it will speed up!!! For me it made quite a difference...

This must also mean that using as few variables as possible will be the best.

I have also noticed (before) that using variables is faster than using constants. For example:

10 A=2:B=12
20 FOR T=1TO500:Z=RND(1)*A/B:NEXT

is faster than

10 FOR T=1TO500:Z=RND(1)*2/12:NEXT

....as long as you don't use too many variables. So using a few variables (maybe re-use them for different things) and sometimes use variables instead of constants should be things to think about if you want to make a fast program.

Happy basic hacking!

/Anders Persson
http://listen.to/boray
carlsson
Class of '6502
Posts: 5516
Joined: Wed Mar 10, 2004 1:41 am

Post by carlsson »

Yep, using variables is faster than numeric constants on all 8-bit BASICs except the Sinclair Basic (found in ZX81 and ZX Spectrum) where the opposite holds true.

The same thing goes for subroutines and I believe DATA statements; put both as early as possible and in the first line of your program, GOTO down to the main program if it does a lot of subroutine calls.

I guess technically you can fiddle with the interrupt timers (IIRC 37879 is a good one) to let Basic work more without being interrupted, but you should put it back to original values when you require timing, output or otherwise.

I'm looking forward for the next compo, which will be about writing a 256 byte or less machine code routine for use in combination with a Basic program, where one can show great improvements over doing the same work in Basic only.
Anders Carlsson

Image Image Image Image Image
User avatar
Jeff-20
Denial Founder
Posts: 5759
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

Well, I've noticed in my amatuer efforts that GOTO and GOSUB are greatly affected by line order.

I suspect when GOTO is called the computer starts from that position if the destination line number is greater, and starts from the beginning of the program if the number is lower. The computer can only scan in one direction.

I put my main loop as early as possible in games. For example:

1 GOTO 50 (This sends us to the end of the program to set up the screen, variables, etc.)

2 PRINT A$ (this would be my main loop)

3 GOTO 2 (the program is faster because it doesn't have to scan through much to get back to the loop, 3 tokens as opposed to 9 not including the line headers)

50 A$= "Test"


Did that make sense? It is just my suspicion.
High Scores, Links, and Jeff's Basic Games page.
Leeeeee
soldering master
Posts: 396
Joined: Fri Apr 23, 2004 8:14 am

Post by Leeeeee »

When performing GOTO or GOSUB the interpreter can only scan forward through lines as there are no reverse links in the BASIC line structure.

The actual length of the line doesn't matter, a long line will be skipped over as quickly as a short line.

If your main loop is quite long and there is a fair bit of code before it then it may be faster to do something like ..

Code: Select all

.
. [lots of lines]
.
250 FOR A=1 TO -1
.
. [lots of lines]
.
340 A=A-1
350 NEXT A
In this case the loop will never terminate and the start of the loop is pulled off the stack by the NEXT command. This can be much quicker than using a GOTO.

With DATA statements the penalty is only for the first READ after RUN or the first READ after RESTORE, as the interpreter has to search for the first DATA statement from the start of the program.

Other speed ups include..

Don'tusespacesinalineastheytaketimetoskip. 8^)=

Put:as:many:commands:on:each:line:as:possible.

Re-use variables as often as possible.

Don't do repetetive calculations inside loops e.g. don't do ..

Code: Select all

100 FOR A=1 TO 100
110 B(A)=RND(0)*X/Y
120 NEXT
.. do ..

Code: Select all

100 SL=X/Y
110 FOR A=1 TO 100
115 B(A)=RND(0)*SL
120 NEXT
Cheers,

Lee.
User avatar
Jeff-20
Denial Founder
Posts: 5759
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

Here's my favorite one. It's my personal secret.

When you have a solitary zero in a program.

A = 0

replace it with a period.

A = .

It take BASIC slightly longer to search for a zero than a period. It seems silly at first, but if you run a long loop, you can see the difference in time.
My programs are littered with periods. :D
High Scores, Links, and Jeff's Basic Games page.
Boray
Musical Smurf
Posts: 4064
Joined: Mon May 03, 2004 10:47 am

Post by Boray »

Many good tips there! Thanks!

Just wondering.... What will happen if I do this:

10 FORT=1TO100:IFT=40THEN20
15 NEXT
20 ...etc...

If I do this much, will the stack be overflowed or doesn't it matter?

/Anders
carlsson
Class of '6502
Posts: 5516
Joined: Wed Mar 10, 2004 1:41 am

Post by carlsson »

Yes, the stack will be flooded, and you get ?OUT OF MEMORY, just like if you did a lot of GOSUB without RETURN.

Another tips in DATA statements is that if you're reading numerical values, you can omit value completely if you want a zero:

DATA 255,0,0,0,0,0,0,0,255,0,255,0,0,255,0,255

can be written: DATA 255,,,,,,,,255,,255,,,255,,255

I wonder if BASIC really starts scanning from current line number, or always from beginning of program for a GOTO or GOSUB?

By the way, other BASIC implementations have a RESTORE nn syntax, where nn is a line number. It is quite possible to accomplish on the VIC too by POKEing addresses 65/66 IIRC. I can't remember if you should give a line number or the actual address though, but either way it should be divided into low/high byte.
Anders Carlsson

Image Image Image Image Image
Boray
Musical Smurf
Posts: 4064
Joined: Mon May 03, 2004 10:47 am

Post by Boray »

carlsson wrote:Yes, the stack will be flooded, and you get ?OUT OF MEMORY, just like if you did a lot of GOSUB without RETURN.
I think you are wrong there... I just tried this:

10 FORT=1TO10:IFT=3THEN10
20 NEXT

Runs forever.... (it seems)

While this one:

10 GOSUB10

Generates an "OUT OF MEMORY" error message right away...

/Anders
User avatar
Jeff-20
Denial Founder
Posts: 5759
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

carlsson wrote:I wonder if BASIC really starts scanning from current line number, or always from beginning of program for a GOTO or GOSUB?
You could make a dummy program to check. I am 95% sure that it starts from the line rather than the beginning if the number sought is higher.

I also use the comma trick often, but with the contest I avoided doing so just as I avoided abbreviations. It makes it difficult to read the program.
High Scores, Links, and Jeff's Basic Games page.
Leeeeee
soldering master
Posts: 396
Joined: Fri Apr 23, 2004 8:14 am

Post by Leeeeee »

When a GOTO or GOSUB is encountered BASIC does this..

Code: Select all

 Find the start of the next line
 Compare current line number with GOTO(GOSUB) number
 If current >= GOTO(GOSUB) number then
   start from the program beginning
 Else
   start from the next line
 End if
For READ the scan is always initially from the program start.

Lee.
carlsson
Class of '6502
Posts: 5516
Joined: Wed Mar 10, 2004 1:41 am

Post by carlsson »

Ok, I probably was wrong, but I have a strong feeling FOR-NEXT can do stupid things with the stack, in particular in combination with GOSUB.

Here are two examples which you probably wouldn't expect to work, and neither they do:

10 FOR J=1 TO 10
12 IFJ>1 THEN 20
15 GOSUB 50
20 NEXT J
50 PRINT J:GOTO 20

10 GOSUB 50
20 PRINT J:NEXT J
22 END
50 FOR J=1 TO 10
52 IF J>1 THEN 20
55 RETURN

Both GOSUB (RETURN) and FOR (NEXT) will move the stack pointer, but it seems the former combo has higher precedence and will make Basic "forget" about the loop just initiated.

I can see that a variation on at least the first example could show up in a bad program.
Anders Carlsson

Image Image Image Image Image
CurtisP
Vic 20 Dabbler
Posts: 99
Joined: Tue Mar 08, 2005 8:24 pm

Post by CurtisP »

The BASIC Interpreter actually searches the stack for the proper value and throws away everything above it.

So, if you do a GOSUB, then a FOR, then a RETURN, the FOR will be discarded and the RETURN will jump to directly after the GOSUB.

In addition, if a variable is included with the NEXT, the Interpreter searches for that FOR in the stack. If not, then the next FOR is used.

But the most interesting thing it does is when you issue a FOR. Then the interpreter searches the stack for a FOR with the same variable, throws everything on top of it away, and replaces the old FOR with the new one.

That's why your FOR example didn't get an out of memoy error.

:oops: My 6 year old daughter wanted the smiley
User avatar
Jeff-20
Denial Founder
Posts: 5759
Joined: Wed Dec 31, 1969 6:00 pm

Post by Jeff-20 »

Leeeeee wrote:When performing GOTO or GOSUB the interpreter can only scan forward through lines as there are no reverse links in the BASIC line structure.

The actual length of the line doesn't matter, a long line will be skipped over as quickly as a short line.
Lee.
Is this true? I suspect the line length would matter. Can someone elaborate on this.
High Scores, Links, and Jeff's Basic Games page.
bbell
Vic 20 Hobbyist
Posts: 125
Joined: Thu Mar 10, 2005 7:43 am

Post by bbell »

If I recall correctly this is true. Each line of program is stored with a line number, and a pointer to the next line (so essentially it is one big linked list, forward only. I think the pointer was a 8-bit unsigned integer offset, so each line had a maximum of 254 chars).

So to scan for a specific line, the actual length of the line didn't affect the time for the search, but how far the line was from the beginning of the program did.
bbell
Vic 20 Hobbyist
Posts: 125
Joined: Thu Mar 10, 2005 7:43 am

Post by bbell »

Just pulled out my old Mapping the Vic book pg 307

The format of each line of basic in memory is the following:

Link-Field -- Line-number-- Tokenized Basic Line -- byte containing 0 for EOL
LSB MSB LSB MSB

The end of program contains a link field with 0 MSB LSB

So the link pointer is a two byte LSB MSB... So definately line length will not
affect goto or gosub speed.

I seem to remember some basic list protection where the author would
mess with these links to hide code in a program.
Post Reply