Jump to content
IGNORED

CALL SIZE. Program Space question


Bones-69

Recommended Posts

Research and back-ground work continues on my LGB project (which BTW is quickly growing out of hand!).

 

Right now I am working on some of the repetitive subroutines that will be used during the game. One routine in particular is required many times during the game and will be called from a lot of different program line numbers, in fact - it is used everytime a line of text is displayed. This particular subroutine is responsible for reading a text string from DSK1, deciding where to display it, actually displaying the string on the screen (using the CALL HPUT command from RXB), beeping, honking, plus a few other cool functions which also include importing basic graphics to the displayed line when required. Everything is controlled by a single 10 digit variable. A typical example of a variable used would be: S(100)=-1010071012

 

The logical choice was to use a custom SUB routine which I had defined as "CALL T" and used a single parameter list. An example of this would be;

CALL T(S(100))

 

After fooling around with this idea and improving the routine a few times, it became desirable for my SUB routine to also be able to access existing string variables which were used outside of the SUBroutine in the main program (which is not possible without complicating the subroutine with additional parameters and having to specify each everytime CALL T was used OR I found myself in a situation where I was "double handling" information to get around the problem which just slows things down too much). For this reason I have no real choice but to flick my subroutine and call the entire routine using a GOSUB command - which is more freindly when wanting to use variables specified elsewhere in the main program.

 

My main concern with using a GOSUB command in leu of a SUB routine was the additional program space this would incur - especially when it is being repeated many many times during the program. So to get a feel of how much program space I would loose/waste using this method I did the following basic test;

 

100 CALL T(S(100))

Using a SIZE command advised this program line used a total of 21 bytes of program space

 

The alternative GOSUB command would need to be specified as follows;

100 A=S(100) : : GOSUB 1000

 

When listing and compared on screen, the program line with the GOSUB command seems to occupy an 8 additional spaces over the SUBroutine (by spaces I actually mean 8 additional characters). However, when checking this expectation using the CALL SIZE command I was pleasantly surprised to discover that the GOSUB line actually only occupied 1 additional byte of program space.

 

This is really good news for what I need the GOSUB command to do as I am struggling to save every single byte, but it begs the question of what is going on? Why only 1 byte difference between the two lines of code? Obviously my very basic understanding of how the TI stores program data is flawed but I just can't make sense of how two vastly different length lines of program data occupy roughly the same program space.

 

100 A=S(100) :: GOSUB 1000

100 CALL T(S(100))12345678

Link to comment
Share on other sites

Research and back-ground work continues on my LGB project (which BTW is quickly growing out of hand!).

 

Right now I am working on some of the repetitive subroutines that will be used during the game. One routine in particular is required many times during the game and will be called from a lot of different program line numbers, in fact - it is used everytime a line of text is displayed. This particular subroutine is responsible for reading a text string from DSK1, deciding where to display it, actually displaying the string on the screen (using the CALL HPUT command from RXB), beeping, honking, plus a few other cool functions which also include importing basic graphics to the displayed line when required. Everything is controlled by a single 10 digit variable. A typical example of a variable used would be: S(100)=-1010071012

 

The logical choice was to use a custom SUB routine which I had defined as "CALL T" and used a single parameter list. An example of this would be;

CALL T(S(100))

 

After fooling around with this idea and improving the routine a few times, it became desirable for my SUB routine to also be able to access existing string variables which were used outside of the SUBroutine in the main program (which is not possible without complicating the subroutine with additional parameters and having to specify each everytime CALL T was used OR I found myself in a situation where I was "double handling" information to get around the problem which just slows things down too much). For this reason I have no real choice but to flick my subroutine and call the entire routine using a GOSUB command - which is more freindly when wanting to use variables specified elsewhere in the main program.

 

My main concern with using a GOSUB command in leu of a SUB routine was the additional program space this would incur - especially when it is being repeated many many times during the program. So to get a feel of how much program space I would loose/waste using this method I did the following basic test;

 

100 CALL T(S(100))

Using a SIZE command advised this program line used a total of 21 bytes of program space

 

The alternative GOSUB command would need to be specified as follows;

100 A=S(100) : : GOSUB 1000

 

When listing and compared on screen, the program line with the GOSUB command seems to occupy an 8 additional spaces over the SUBroutine (by spaces I actually mean 8 additional characters). However, when checking this expectation using the CALL SIZE command I was pleasantly surprised to discover that the GOSUB line actually only occupied 1 additional byte of program space.

 

This is really good news for what I need the GOSUB command to do as I am struggling to save every single byte, but it begs the question of what is going on? Why only 1 byte difference between the two lines of code? Obviously my very basic understanding of how the TI stores program data is flawed but I just can't make sense of how two vastly different length lines of program data occupy roughly the same program space.

 

100 A=S(100) :: GOSUB 1000

100 CALL T(S(100))12345678

 

BASIC is tokenized into 8-bit tokens. The GOSUB command only occupies a single token. Don't go by the number of characters you see in the listing, trust the size command to know what it's doing.

 

100 characters of parameters? That's a lot of overhead to pass every single time.

 

Keep in mind also that there's some differences in performance using custom subroutines compared to a single GOSUB.

 

Adamantyr

Link to comment
Share on other sites

Call's are the worse in TI's basic. -- They are NOT tokenize, and longer the name, the more space it takes up,

plus branching to a CALL and RETURNing eats up alot more time, then a simple goto or gosub.

 

Also sad, is that alot of useful commands like HCHAR, CLEAR, etc. are all call's, they sure are not spacing saving!

Edited by Gary from OPA
Link to comment
Share on other sites

BASIC is tokenized into 8-bit tokens. The GOSUB command only occupies a single token. Don't go by the number of characters you see in the listing, trust the size command to know what it's doing.

 

100 characters of parameters? That's a lot of overhead to pass every single time.

 

Keep in mind also that there's some differences in performance using custom subroutines compared to a single GOSUB.

OK… Your token comment has answered all. That now makes complete sense! Thank-you.

 

In regards to the 100 characters of parameters… this is not the case. I probably wasn’t clear enough.

 

S(n) actually refers to the screen to be drawn (where n is screen 1). So S(100) is screen 100. Screens can be drawn from scratch or individual sections of the screen can be updated/re-drawn as required. In any case, each instance of S(n) contains enough data to draw 1 or all 32 lines to the screen. S(n) will be defined as part of the program initialization process.

 

In the instance of S(100) where the value is equal to -1010071012, the program will process the data something like the following.

 

* If the value is <0 then graphical processing is required (handled later in routine)

 

* Convert ABS(S(100)) to a string, so A$=”1010071012”

 

* Start splitting string up and allocating values with the following uses;

Value 1010-1000 *First/starting REC (10 in this example), to read from DSK1

Value 07 *Number of Records to read (or number of lines to display). Really just sets up the loop to read and display each rocord/line.

Value 10 *First Row to start HPUT command

Value 1 * HONK (1) or BEEP (2) or NONE (0) after last line displayed on screen

Value 2 * Delay loop after last line displayed. (FOR/NEXT delay where delay loop is value x 320. Value determines seconds. 0 is no delay)

 

Additional graphical information (if required), is flagged by the contents of the record read.

 

Effectively this method allows me to display infinite screens of data (full screens or partial screens), for the price of a single 10 digit variable which only costs me a few bytes of RAM.

 

Not sure if this method is clear but I have found it to be very RAM conservative, occupy very little program space and executes pretty quickly (the slowest part is the time it takes to read each line from DSK1 - not the actual program processing time as variables are only defined and processed once during each new screen). About the only real cost is the data in the DSK1 record which is always 32 characters long. This is resulting in quite a large DSK1 data file but I don't consider this too wasteful.

 

I see this whole idea as working well for my application. In many instances I will be able to set up several screens in a loop (with a CALL KEY between screen draws), while other times I can simply recall a complete screen re-draw or partial update from a single line anywhere in my program by simply specifying the value of the S array and branching to the GOSUB subroutine.

Link to comment
Share on other sites

I read my post again and wasn't completely happy with the clarity so thought an example might be better. Obviously this example is missing much of the backbone and won't work when typed in, but most XB users should be able to get the gist of it. Just going from memory here.. Hope there are no silly mistakes.

 

 

10 READ S(1),S(2), S(3), S(4)

 

100 A=S(2) :: GOSUB 500

110 BLAH BLAH BLAH

120 A=S(1) :: GOSUB 500

130 BLAH BLAH BLAH

140 FOR X=1 TO 4:: A=S(X)::GOSUB 500::NEXT X

150 END

 

500 A$=STR$(A)

510 B=VAL(SEG$(A$,1,4))-1000 !DEFINE STARTING REC NUMBER

510 C=VAL(SEG$(A$,5,2)) !DEFINE NUMBER OF LINES TO READ

520 D=VAL(SEG$(A$,7,2)) !DEFINE STARTING ROW FOR DISPLAY

530 E=VAL(SEG$(A$,9,1)) !DEFINE SOUND

540 F=VAL(SEG$(A$,10,1)) !DEFINE DELAY

 

550 FOR I=B TO B+C :: INPUT #1, REC I:B$ :: CALL HPUT(D+G,1,SEG$(B$,1,32)):: G=G+1 :: NEXT I

560 IF E=1 THEN CALL HONK ELSE IF E=2 THEN CALL BEEP

570 FOR I=1 TO F*320::NEXT I

580 G=0 :: RETURN

 

1000 DATA 1050320100, 1120101019, 1350051200, 1240012419

 

* REC I contains screen data to be displayed on each line

Link to comment
Share on other sites

I read my post again and wasn't completely happy with the clarity so thought an example might be better. Obviously this example is missing much of the backbone and won't work when typed in, but most XB users should be able to get the gist of it. Just going from memory here.. Hope there are no silly mistakes.

 

 

10 READ S(1),S(2), S(3), S(4)

 

100 A=S(2) :: GOSUB 500

110 BLAH BLAH BLAH

120 A=S(1) :: GOSUB 500

130 BLAH BLAH BLAH

140 FOR X=1 TO 4:: A=S(X)::GOSUB 500::NEXT X

150 END

 

500 A$=STR$(A)

510 B=VAL(SEG$(A$,1,4))-1000 !DEFINE STARTING REC NUMBER

510 C=VAL(SEG$(A$,5,2)) !DEFINE NUMBER OF LINES TO READ

520 D=VAL(SEG$(A$,7,2)) !DEFINE STARTING ROW FOR DISPLAY

530 E=VAL(SEG$(A$,9,1)) !DEFINE SOUND

540 F=VAL(SEG$(A$,10,1)) !DEFINE DELAY

 

550 FOR I=B TO B+C :: INPUT #1, REC I:B$ :: CALL HPUT(D+G,1,SEG$(B$,1,32)):: G=G+1 :: NEXT I

560 IF E=1 THEN CALL HONK ELSE IF E=2 THEN CALL BEEP

570 FOR I=1 TO F*320::NEXT I

580 G=0 :: RETURN

 

1000 DATA 1050320100, 1120101019, 1350051200, 1240012419

 

* REC I contains screen data to be displayed on each line

 

Okay, so the array represents data. Why not store the values as straight characters, and use the ASC function to convert them back to numerals?

 

The only limitation there is the 0-255 limit, but otherwise, it works fine.

 

Part of the advantage there is that then you use stack space to store the data arrays, which is generally not in high usage in Extended BASIC. (No high-res graphic mode to use)

 

Adamantyr

Link to comment
Share on other sites

Why not store the values as straight characters, and use the ASC function to convert them back to numerals?

 

The only limitation there is the 0-255 limit, but otherwise, it works fine.

 

Part of the advantage there is that then you use stack space to store the data arrays, which is generally not in high usage in Extended BASIC. (No high-res graphic mode to use)

I have really struggled with memory (stack and program space) since starting this program. Being a rather complex and large adventure game I am demanding a lot from the memory. It's a case of milking every last bit I can. However, from my testing along the way the current method is not at all a bad one.... There is really no compromise in execution speed and I still end up saving some precious memory. In my earlier testing where this data was stored in a strings it was like somebody pulled the plug on my stack space.

Link to comment
Share on other sites

A caution about using any call routines exclusive to RXB or any other non ti xb. Most people don't have RXB while almost everyone has XB.

 

I have 50-60 carts and I don't have RXB for example. I don't even have a Rom of it for the emulator.

 

Strings are a very good way to store data and easy to cut out pieces as needed. In bouncing babies all the path data is stored in strings which are faster them arrays. In worm war the worm info that changes as the worm moves and grows is stored in string so I can easy and fast add to or trim parts. There really is no better way for speed or for indexing info and amending it in basic on the ti.

 

Are the call honk and call beep in you example subs that you wrote or routines in RXB?

Link to comment
Share on other sites

I agree, strings are bloody awesome! I simply can't imagine programming anything now without manipulating these in some form or another.

 

In regards to your RXB comments, I hear what you say but I do believe writing the program with RXB will produce a much better end prouct - in particular I am extensively using;

 

CALL HPUT (simlar to XB DISPLAY AT but allows access to rows 1 & 2 plus 31 & 34)

CALL HGET (which allows you to do screen grabs)

Access to use of characters 143-159

The DOS like functions

 

With a couple of years work already sunk into LGB I have come too far to turn back now. My single use of HPUT would mean having to redesign hundreds of hours of work for example...

 

On the up side, RXB is freely available for WIN99/4a which is what I am writing it with. I realise for many this is not the TI emulator of choice but this was the first one I found and the one I started using from day one.

 

I actually remember in the early days sitting down with RXB, Super XB, Mechatronix XB2 and standard XB (all which were available with WIN99/4a). and going through each additional function trying to work out which BASIC would serve my project best. RXB came out the winner.

 

* CALL HONK & CALL BEEP are built in RXB routines.

Edited by Bones-69
Link to comment
Share on other sites

I agree, strings are bloody awesome! I simply can't imagine programming anything now without manipulating these in some form or another.

 

In regards to your RXB comments, I hear what you say but I do believe writing the program with RXB will produce a much better end prouct - in particular I am extensively using;

 

CALL HPUT (simlar to XB DISPLAY AT but allows access to rows 1 & 2 plus 31 & 34)

CALL HGET (which allows you to do screen grabs)

Access to use of characters 143-159

The DOS like functions

 

With a couple of years work already sunk into LGB I have come too far to turn back now. My single use of HPUT would mean having to redesign hundreds of hours of work for example...

 

On the up side, RXB is freely available for WIN99/4a which is what I am writing it with. I realise for many this is not the TI emulator of choice but this was the first one I found and the one I started using from day one.

 

I actually remember in the early days sitting down with RXB, Super XB, Mechatronix XB2 and standard XB (all which were available with WIN99/4a). and going through each additional function trying to work out which BASIC would serve my project best. RXB came out the winner.

 

* CALL HONK & CALL BEEP are built in RXB routines.

 

 

I guess that the "CALL HPUT" and a few others could be rewritten as assembly language routines to be linked with your program.

That would allow you to run it with regular Extended Basic and 32K memory expansion. Not sure about the use of characters 143-159 though.

Perhaps someone with details on that can chime in ?

Link to comment
Share on other sites

These calls could be hand written to LOAD and LINK to regular XB... You wouldn't even have to change the names of the calls. :) Just define a new SUB as HPUT and then LINK your assembly sub. :) Nice how we have the ability to do that. I'd love to see a couple new screenies or perhaps a short 2-3 screen video of gameplay. :) Im a bit greedy though. Hehehe

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...