Bones-69 Posted August 12, 2010 Share Posted August 12, 2010 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 Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted August 12, 2010 Share Posted August 12, 2010 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 Quote Link to comment Share on other sites More sharing options...
Gary from OPA Posted August 12, 2010 Share Posted August 12, 2010 (edited) 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 August 12, 2010 by Gary from OPA Quote Link to comment Share on other sites More sharing options...
Bones-69 Posted August 12, 2010 Author Share Posted August 12, 2010 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. Quote Link to comment Share on other sites More sharing options...
Bones-69 Posted August 12, 2010 Author Share Posted August 12, 2010 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 Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted August 12, 2010 Share Posted August 12, 2010 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 Quote Link to comment Share on other sites More sharing options...
Bones-69 Posted August 12, 2010 Author Share Posted August 12, 2010 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. Quote Link to comment Share on other sites More sharing options...
jchase1970 Posted August 12, 2010 Share Posted August 12, 2010 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? Quote Link to comment Share on other sites More sharing options...
Bones-69 Posted August 12, 2010 Author Share Posted August 12, 2010 (edited) 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 August 12, 2010 by Bones-69 Quote Link to comment Share on other sites More sharing options...
+retroclouds Posted August 13, 2010 Share Posted August 13, 2010 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 ? Quote Link to comment Share on other sites More sharing options...
Opry99er Posted August 17, 2010 Share Posted August 17, 2010 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 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.