erichenneke Posted December 13, 2014 Share Posted December 13, 2014 What's the best way to "self delete" code after it has been used and won't be needed again ( to free memory during execution)? I have a program that has a LOT of lines of DATA to load. However, once it is loaded it is never referenced again. So, in Turbo Basic XL I just added a DEL 20000,32000 to the code in-line after the DATA reads are completed. Works like a charm in Turbo Basic XL. However, I want this program to be Compiled for speed with Turbo Basic XL Compiler. The Compiler chokes on the DEL 20000,32000 statement. So, I am forced to remove that before I can compile. Does anybody have suggestions on ways to accomplish this in the Compiled version as well? Thanks! -Eric Quote Link to comment Share on other sites More sharing options...
snicklin Posted December 13, 2014 Share Posted December 13, 2014 I believe that the compiler will not be able to work with self deleting code like you use because your "del" command is referencing lines of code, which do not exist when it is compiled. On compilation, they will be individual values in memory locations. I would copy the data from somewhere into your buffer. That somewhere that it comes from will probably be better off compressed somewhere, perhaps on disk and then loaded into your buffer as it is required. You may not want to compress it, that is up to you. You'll need to allocate some known free memory for your buffer. 1 Quote Link to comment Share on other sites More sharing options...
+David_P Posted December 14, 2014 Share Posted December 14, 2014 Create a file that will contain the data, then have your TB program load the data where required. Quote Link to comment Share on other sites More sharing options...
Rybags Posted December 14, 2014 Share Posted December 14, 2014 I imagine a compiled program has no provision for insertion, moving or deletion of parts of the program. The best bet is probably to have data resources in external files, read them into arrays, strings, memory, <whatever> in the most efficient format possible, e.g. 2 byte integers rather than floating point to save memory. Alternate might be to have variables declared to static strings within the program. Whether it works, unsure, and it'd be more suited to string data than numeric. e.g. 1000 A(1) = ADR ("Text line 1") 1010 A(2) = ADR("Text line 2") In that form, the strings only exist once and can be referred by memory addresses that are put into the array. You can even change bytes within the string but of course need to take care with not going out of bounds and trashing something else. Quote Link to comment Share on other sites More sharing options...
erichenneke Posted December 14, 2014 Author Share Posted December 14, 2014 I thought about having the data in an external file but I was hoping to keep it all self contained. I might need to load it from separate file in the end. I guess that isn't a big deal. Quote Link to comment Share on other sites More sharing options...
erichenneke Posted December 14, 2014 Author Share Posted December 14, 2014 I imagine a compiled program has no provision for insertion, moving or deletion of parts of the program. The best bet is probably to have data resources in external files, read them into arrays, strings, memory, <whatever> in the most efficient format possible, e.g. 2 byte integers rather than floating point to save memory. Alternate might be to have variables declared to static strings within the program. Whether it works, unsure, and it'd be more suited to string data than numeric. e.g. 1000 A(1) = ADR ("Text line 1") 1010 A(2) = ADR("Text line 2") In that form, the strings only exist once and can be referred by memory addresses that are put into the array. You can even change bytes within the string but of course need to take care with not going out of bounds and trashing something else. Rybags, this is really interesting. I have never used the ADR function on a string that way. How would this be used to access the data by memory address after it is stored then? Can you show another simple example? Thanks so much. -Eric Quote Link to comment Share on other sites More sharing options...
Rybags Posted December 14, 2014 Share Posted December 14, 2014 ADR is often just used as calling address for a USR function. In the mentioned way though, the assembly routines are limited in size to ~ 100 bytes as well as having to be location independant. Whether it would work with a compiled program - unknown. Compiling will usually generate code that's to execute in a fixed location so no reason it shouldn't. Other often use for ADR is parameter for USR, in this embedded string situation you might want to alter what's in the string or just use the whole string as a temporary work area. Quote Link to comment Share on other sites More sharing options...
ricortes Posted December 14, 2014 Share Posted December 14, 2014 Not really a Turbo BASIC programmer. Assuming it works similar to Atari BASiC I would say convert all data statements to strings and use Rybag's technique for text because of the way Atari BASIC works: All numbers are stored as floats with a few other tips. ? FRE(0) 32130 Ready 10 DATA 65,66,67,68,69,70,71,72,73 20 ? FRE(0) RUN 32083 Ready 10 A=ADR("ABCDEFGHI") 20 ? FRE(0) RUN 32093 Not sure where the break even point occurs, maybe ~5 data statements. IOW: No benefit if you have less then 4-5ish data statements. I haven't checked it out, but you would probably be better off using string assignments over arrays for the same floating point reasons. A(1)=ADR("ABCDEFGHI") Stores the address of the string as a 6 byte floating point number where A1$="ABCDEFGHI" Stores it as a 2 byte variable. I think I have seen people use the same string variable for huge strings. May have even been me! You can use 64k strings<or is it 32k?> in Atari BASIC so you can just keep building the string with a simple string assignment i.e. 10 DIM A1$(11) 20 A1$(1)="HELLO" 30 A1$(6)=" WORLD" 40 ? A1$ RUN HELLO WORLD There were a number of programs to squeeze every oz out of Atari BASIC. I think Mr. White with Atari wrote several that would reduce the length of variable names to two characters and maximize line length. Ditto for utilities that would take DATA statements and put them into strings. Quote Link to comment Share on other sites More sharing options...
snicklin Posted December 14, 2014 Share Posted December 14, 2014 I think Mr. White with Atari wrote several that would reduce the length of variable names to two characters and maximize line length. Ditto for utilities that would take DATA statements and put them into strings. I'm somewhat rusty with my Turbo Basic, but wasn't it that you could assign a value for a number to save bytes...? i.e. 10 N6=6 And then every time you want to use the value '6' in your program, used use N6 as your reference to save 4 bytes from the 6 normally used to reference 6 As for long strings, there are all the big long strings used in type in listings which were inside BASIC but were machine language programs. That might be useful in this case... Perhaps (if the compiler is ok with it), you could use : RESTORE 1000+(10*LEVELNUMBER) to point to the data that you want.... Is that possible when line numbers are stripped out?? Perhaps not... Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted December 14, 2014 Share Posted December 14, 2014 TBXL has constants %0-%3, which are tokens for integers 0-3. Worth using, since variable names soon become precious if you have a lot of PROCs. Quote Link to comment Share on other sites More sharing options...
analmux Posted December 14, 2014 Share Posted December 14, 2014 (edited) ... I have a program that has a LOT of lines of DATA to load. However, once it is loaded it is never referenced again. ... Do you use a DOS? If your DATA lines contain values between 0 and 255, then maybe it suffices when you safe them to 8bits binary data files first. Why deleting before overwriting data area during the next file read? After compile/runtime I think it's easy to load and access the data files: DATA0001.BIN DATA0002.BIN DATA0003.BIN ... Edited December 14, 2014 by analmux Quote Link to comment Share on other sites More sharing options...
Xuel Posted December 14, 2014 Share Posted December 14, 2014 Rybags, this is really interesting. I have never used the ADR function on a string that way. How would this be used to access the data by memory address after it is stored then? Can you show another simple example? Thanks so much. -Eric The ADR function gives you back the address of the string as its stored in your program. You can use this address with PEEK to get back the first byte of the string. You can add 1 to the address and PEEK that to get the second byte of the string, etc. 10 X=ADR("0123456789") 20 FOR I=0 TO 9 30 PRINT PEEK(X+I) 40 NEXT I That will print the ATASCII codes for the numbers 0-9, i.e. 48-57 decimal. You can use the string data in-place as you would with data that you POKEd, or you could move it somewhere else if alignment is important. For example, you could encode a position independent assembly language routines in ATASCII: 10 X=ADR("XXXXXXXXX") 20 D=USR(X) You could encode your display list in ATASCII but display lists can't cross a 1K boundary and you can't be sure where the string will end up in memory so you can use MOVE to copy the data from the location of the string in your program to some location in high memory with the correct alignment: 10 MOVE ADR("XXXXXXXXX"),$A000,20 20 DPOKE $230,$A000 Here "20" would be the length of the display list in bytes. I used the above technique in my Cavern 10 entry into the Basic Ten-Liners contest earlier this year. I used ADR("") to store the display list, the font, the screen data, etc. in lz4 compressed form. I used MOVE to copy the data into continuous high memory and then decompressed it into higher memory with the correct alignment. It sounds like this probably wouldn't help you though if you have a lot of code since there's probably not enough memory to have a copy of the data as strings in your code and another copy in high memory. In this case, probably better to load the data from disk directly into high memory as others have suggested. Though perhaps there is an easy way to link the executable generated by Turbo Basic Compiler with an object file containing the data. If that were the case, then whenever you ran the new executable it would automatically load the data into place exactly where you want it without requiring any disk I/O within your program itself. 1 Quote Link to comment Share on other sites More sharing options...
Rybags Posted December 15, 2014 Share Posted December 15, 2014 DATA statements just store in raw Ascii. The problem with data is you waste memory if storing lots of small items since each comma uses a byte but isn't contributing to useful data. Also you're replicating information, unless in an uncompiled situation you read the items then delete the data lines. Quote Link to comment Share on other sites More sharing options...
ricortes Posted December 15, 2014 Share Posted December 15, 2014 I'm somewhat rusty with my Turbo Basic, but wasn't it that you could assign a value for a number to save bytes...? i.e. 10 N6=6 And then every time you want to use the value '6' in your program, used use N6 as your reference to save 4 bytes from the 6 normally used to reference 6 As for long strings, there are all the big long strings used in type in listings which were inside BASIC but were machine language programs. That might be useful in this case... <snip> Ohhhh that brings back painful memories! I think several telecommunication programs like AMIS and AMODEM 4.2 did exactly that to save a few bytes for a bigger buffer. Some of the other programs being discussed now like Temple of Asphai did the same thing. Made it even more difficult to sort through the spaghetti code. I think the longest string I ever encoded was something like three Microillustrator screens for an animation. Had to have been one of the worlds worst ideas. 23k of string with 8k of memory used for display. I think it only left a few bytes for the program. I keep telling myself "it's a hobby." I really should start programming in BASIC again. After a few decades of structured programs I think I could actually write programs that could be followed by a skilled programmer. Quote Link to comment Share on other sites More sharing options...
Rybags Posted December 15, 2014 Share Posted December 15, 2014 I used to do that a lot. You can save memory in the first place by putting the constants into Data statements. And since numeric vars are zero at first usage you don't need to worry about N0. 1000 READ N1,N2,N3,N5,N10 : DATA 1,2,3,5,10 Quote Link to comment Share on other sites More sharing options...
erichenneke Posted December 15, 2014 Author Share Posted December 15, 2014 The ADR function gives you back the address of the string as its stored in your program. You can use this address with PEEK to get back the first byte of the string. You can add 1 to the address and PEEK that to get the second byte of the string, etc. 10 X=ADR("0123456789") 20 FOR I=0 TO 9 30 PRINT PEEK(X+I) 40 NEXT I That will print the ATASCII codes for the numbers 0-9, i.e. 48-57 decimal. You can use the string data in-place as you would with data that you POKEd, or you could move it somewhere else if alignment is important. For example, you could encode a position independent assembly language routines in ATASCII: 10 X=ADR("XXXXXXXXX") 20 D=USR(X) You could encode your display list in ATASCII but display lists can't cross a 1K boundary and you can't be sure where the string will end up in memory so you can use MOVE to copy the data from the location of the string in your program to some location in high memory with the correct alignment: 10 MOVE ADR("XXXXXXXXX"),$A000,20 20 DPOKE $230,$A000 Here "20" would be the length of the display list in bytes. I used the above technique in my Cavern 10 entry into the Basic Ten-Liners contest earlier this year. I used ADR("") to store the display list, the font, the screen data, etc. in lz4 compressed form. I used MOVE to copy the data into continuous high memory and then decompressed it into higher memory with the correct alignment. It sounds like this probably wouldn't help you though if you have a lot of code since there's probably not enough memory to have a copy of the data as strings in your code and another copy in high memory. In this case, probably better to load the data from disk directly into high memory as others have suggested. Though perhaps there is an easy way to link the executable generated by Turbo Basic Compiler with an object file containing the data. If that were the case, then whenever you ran the new executable it would automatically load the data into place exactly where you want it without requiring any disk I/O within your program itself. These are all really great suggestions and give me lot to work with. I am thinking it i put all of my data into a long hard-coded string, then move that into higher memory at execution, then I could just reset the long strong to null and avoid the duplicate memory issue. Regardless, many new approaches for me to experiment with, which was exactly what I was looking for! Thanks!!! Quote Link to comment Share on other sites More sharing options...
erichenneke Posted December 15, 2014 Author Share Posted December 15, 2014 I used to do that a lot. You can save memory in the first place by putting the constants into Data statements. And since numeric vars are zero at first usage you don't need to worry about N0. 1000 READ N1,N2,N3,N5,N10 : DATA 1,2,3,5,10 i didn't realize that would be more efficient, this should help me quite a bit from a memory standpoint. Nice. Quote Link to comment Share on other sites More sharing options...
Synthpopalooza Posted December 15, 2014 Share Posted December 15, 2014 (edited) There is this trick, which I used a variant of when coding my TurboBASIC game Sky Scraper. Let's say you wanted to delete lines 1000-2000 from your code after you executed them. try this: 1000 REM This Line Will Be Deleted 2000 REM So Will this 3000 POSITION 0,2:? "DEL 1000,2000:POKE 842,12:CONT 3010 POSITION 0,0:POKE 842,13:STOP 3020 REM rest of program here POKE 842,13 forces the computer into forced-read mode, it automatically presses RETURN continuously. Any statements it encounters on screen will be treated as being in immediate mode. So, you place the statements on screen with PRINT statements, making sure to put in a POKE 842,12:CONT in there so that the program resumes afterwards. Then position your cursor at 0,0 and execute a STOP command. My use for this method in Sky Scraper, was to "ENTER" new game levels from disk everytime you finish a level. ENTER will not work during program execution because it stops the program, so you have to use the forced read method in this case. Needless to say, this method will not work with compiled programs, of course. Edited December 15, 2014 by Synthpopalooza Quote Link to comment Share on other sites More sharing options...
+Stephen Posted December 15, 2014 Share Posted December 15, 2014 I really should start programming in BASIC again. After a few decades of structured programs I think I could actually write programs that could be followed by a skilled programmer. I've thougt about this myself, but come to a different conclusion. I've been doing structured programming on very large systems for so long, I don't think I could go back Quote Link to comment Share on other sites More sharing options...
snicklin Posted December 15, 2014 Share Posted December 15, 2014 I've thougt about this myself, but come to a different conclusion. I've been doing structured programming on very large systems for so long, I don't think I could go back I've been doing the same as you for the last few years and then I went back the other week to take a look at some of my old Turbo Basic code. Admittedly it was a bit of a shock but I understood it (once read through) and could add to it. You have to do it with one eye shut though! Go on, grin and bear it! Quote Link to comment Share on other sites More sharing options...
+Stephen Posted December 16, 2014 Share Posted December 16, 2014 I've been doing the same as you for the last few years and then I went back the other week to take a look at some of my old Turbo Basic code. Admittedly it was a bit of a shock but I understood it (once read through) and could add to it. You have to do it with one eye shut though! Go on, grin and bear it! I am - but I am now bearing it doing pure 6502 code Quote Link to comment Share on other sites More sharing options...
Kyle22 Posted January 9, 2015 Share Posted January 9, 2015 How about compiling and linking it to an executable file, then appending a segment that loads the data at a specific address? I'm not in front of an Atari now, but I don't see why it wouldn't work. Quote Link to comment Share on other sites More sharing options...
+JAC! Posted January 10, 2015 Share Posted January 10, 2015 That actually is the best way of combining pure data with a program (be it written in ASM or TB and then compiled). The data segment has to be added before the XEX part and you're done. Of course you have to make sure that the memory location is safe. TB Compiler copies stuff around quite a bit in the memory when the executable starts. Quote Link to comment Share on other sites More sharing options...
erichenneke Posted September 26, 2015 Author Share Posted September 26, 2015 How about compiling and linking it to an executable file, then appending a segment that loads the data at a specific address? I'm not in front of an Atari now, but I don't see why it wouldn't work. Coming back to this suggestion... how do I go about doing this for a compiled TBXL program? Right now I have a program that uses a BGET to load data from a separate XEX file. When I compile it everything works fine as long as I have the separate XEX file available in the right location. I'd prefer to ultimately have everything in one single executable file. I know I can use TBLINKER to pull the runtime and the .CTB file together into one executable, but at this point I still have to have a separate XEX file with my data. Is there a way to do ALL of this within a single file, including what i currently have in the separate XEX/data file? Quote Link to comment Share on other sites More sharing options...
+JAC! Posted September 26, 2015 Share Posted September 26, 2015 A simple way might be to just link the data as segment at the begin of AUTORUN.SYS (runtime). I check the segments and the area $8000.... appears to be unused. A short test also worked. AUTORUN.SYS:<your segment starting at $8000><original content of autorun.sys) 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.