Jump to content
IGNORED

Running out of memory in TurboBASIC


Recommended Posts

I have a problem:

 

I have been working on my CIN font editor, and I have found that I am hitting an error-2 before the program can even finish initializing. I am including the basic program on this post and the source code. I am looking for any suggestions as to how I can trim my code, optimise it, and save on RAM.

 

For one thing, I have had to reserve memory for the equivalent of 4 character sets, which is no doubt eating up alot of my ram. I've used alot of variables too, maybe I can eliminate some?

 

I have also tried LIST, NEW, and ENTER to clear up any unused variables, too. One possible savings is in the block font used to display the character grid, I am only really using the first 64 characters of that character set to display the character grid, so I don't need screen codes >65 ... how could I redo this so that I use less memory? the procedure is in CHARINIT where I set up memory for the character sets,

icecin2.zip

Edited by Synthpopalooza
Link to comment
Share on other sites

I have a problem:

 

I have been working on my CIN font editor, and I have found that I am hitting an error-2 before the program can even finish initializing. I am including the basic program on this post and the source code. I am looking for any suggestions as to how I can trim my code, optimise it, and save on RAM.

 

For one thing, I have had to reserve memory for the equivalent of 4 character sets, which is no doubt eating up alot of my ram. I've used alot of variables too, maybe I can eliminate some?

 

I have also tried LIST, NEW, and ENTER to clear up any unused variables, too. One possible savings is in the block font used to display the character grid, I am only really using the first 64 characters of that character set to display the character grid, so I don't need screen codes >65 ... how could I redo this so that I use less memory? the procedure is in CHARINIT where I set up memory for the character sets,

 

I'm having some problems viewing the code (due to some end of line characters) so I will just give some advice from memory rather than what I see. Please note that I haven't programmed in Turbo Basic for 15 years now, so I might get the odd thing wrong.

 

1) Keep variable names short, each extra character is a wasted byte.

2) Keep procedure names short, same reason as above.

3) When using constants, i.e. the number '6', have a variable called 'v6' (set to '6') and reference this instead, I think it uses around 4(?) bytes less. I'm not sure how many variables your program may have.

4) Evaluate every bit of functionality over and over (do I need this?)

 

If I think of anything more, I'll let you know....

Link to comment
Share on other sites

Just fired up The Last Word and had a look at your code: one thing which I'd do straight away is replace all occurences of constants 0, 1, 2 and 3 with %0, %1, %2, and %3 respectively. These built-in integer constants take up less space than a floating point value, and have the advantage of not consuming any more entries in the variable name table. It's a shame that TB doesn't support an actual integer variable type, but all you get are these four hard-coded integer constants.

 

You might find that this alone saves quite a lot of space and solves the problem (snicklin's idea would have done the same, with the overhead of the extra variable definitions). If the constant "0" appears, say, 200 times in the program, replacing each "0" with "%0" will save several hundred bytes.

Edited by flashjazzcat
Link to comment
Share on other sites

Just fired up The Last Word and had a look at your code: one thing which I'd do straight away is replace all occurences of constants 0, 1, 2 and 3 with %0, %1, %2, and %3 respectively. These built-in integer constants take up less space than a floating point value, and have the advantage of not consuming any more entries in the variable name table. It's a shame that TB doesn't support an actual integer variable type, but all you get are these four hard-coded integer constants.

 

You might find that this alone saves quite a lot of space and solves the problem (snicklin's idea would have done the same, with the overhead of the extra variable definitions). If the constant "0" appears, say, 200 times in the program, replacing each "0" with "%0" will save several hundred bytes.

Yes I did this on Gwobby Strikes Back and used ? #N6 instead of ? #6 to gain loads of bytes... not that you'll learn much from my code but you could scan over GSB - there is another thread here that I started a while ago on the same subject worth a gander too :)

Link to comment
Share on other sites

Thanks for that. Also: I am thinking about shortening my variable names (e.g. RV$ instead of REGVAL$) and replacing my EXEC's with GOSUBs. Using an EXEC takes up space in the variable name table, especially more so as the procedure names tend to be longer than most variables. Do you think this will also save memory?

 

I've discovered that shortening the character set really isn't an option. Even though I am only using the first 64 entries in the set, the nature of the character-flip modes I am using requires the whole 2048 bytes for the character set be reserved.

 

I'll go through and redo all the constants and see if there are any other constants I can use.

 

One thing: I hardly ever use ? #6 anymore. I've learned to get by in many cases with POKEs to the screen when it comes to single characters, and just altering the display list from Graphics 0 rather than doing a graphics call.

 

More questions: Instead of using STICK(0) and STRIG(0), would reading the memory locations themselves save any memory in my program? Also, using hex numbers ($00 - $FF and $0000 = $FFFF) for one and two byte values? And how many times does a constant need to be used in a program before it becomes more efficient to replace it with a variable?

Edited by Synthpopalooza
Link to comment
Share on other sites

Stick/strig use the same memory amount as Peek.

 

RND has a dummy argument, so any variable name will do.

 

Putting more statements per line is another way to save RAM. Each new line is something like 3 extra bytes.

 

Character sets are 1024 bytes not 2048. Gr. 1 and 2 chsets are only 512 bytes.

 

 

In my experience, biggest memory saver in general is long lines and using constants instead of numerics.

 

Another huge saver is eliminating duplicate data. Assembler routines are a big culprit there.

 

e.g. rather than having DATA lines where essentially 4-5 bytes are consumed per byte of code, have routines in strings. Downside is they have to be relocatable. Advantage is there's no memory waste other than the 7 bytes or so overhead that a string must have.

 

Where Asm stuff has to be location-specific, load it from file rather than embedding in the program.

 

Initialising variables can be done more efficiently in a big block by reading from DATA. e.g. with your constants:

 

10000 RESTORE 10000:READ V1,V2,V3,V4,V5,V6,V10
100010 DATA 1,2,3,4,5,6,10

Edited by Rybags
Link to comment
Share on other sites

Character sets are 1024 bytes not 2048. Gr. 1 and 2 chsets are only 512 bytes.

 

 

Actually, the block character set I am using is 2048 bytes, as it is a flicker-mode (Super IRG style) double font. I'm actually using 2, one for the block character set, and one for the double-font which is actually being redesigned. 4K required, in total.

 

 

Another idea: What about using NOT X instead of X=0, or IF X instead if IF X<>0 ... would that also save space? Especially for STRIG(0) which only returns 0 or 1

 

 

 

 

 

 

 

 

 

Edited by Synthpopalooza
Link to comment
Share on other sites

Thanks for that. Also: I am thinking about shortening my variable names (e.g. RV$ instead of REGVAL$) and replacing my EXEC's with GOSUBs. Using an EXEC takes up space in the variable name table, especially more so as the procedure names tend to be longer than most variables. Do you think this will also save memory?

Replacing EXECs with GOSUBs will save space in the variable name table (I think I had to resort to this some years back on one project), but naturally it makes the code less readable. In my case, it wasn't so much lack of memory as lack of variable names (since there's a maximum of 256 in TB).

 

I'll echo the point about putting machine code routines in strings. MUCH more space-efficient than using DATA statements. In addition, if the machine code routine is relocatable and is less than about 120 bytes, you can save space by saying:

 

ML_ROUTINE=ADR("<machine code string>")

 

rather than:

 

ML_ROUTINE$="<machine code string>"

 

Using the first method, you're referencing the bytes in the program code directly. If you use the second method (assigning the value to the string), you need a string variable, and twice the storage space. If you embed the code in this way, it's about as compact as loading it from disk (since you need to assign storage for code loaded externally).

Link to comment
Share on other sites

My Contribution:

 


  •  
  • Remove all "TEST REM" statements like
     
    REM DPOKE 1034,560:DPOKE 1036,65535:DPOKE 1038,65535:REM DUMMY VALUES


    The REM statement will take even more space than the code, because its text, not tokens
     

  • Replace READ/DATA but BPUT/BGET
    Put one time initialization like PROC VBISETUP into a separate file which create binary files using "BPUT".
    In the main program use "BGET" instead or READ. If possible, use fixed memory locations to prevent string creation.
    This will save of factor 3-5 per number. For lines 9100ff even more.
     
     

Edited by JAC!
Link to comment
Share on other sites

That "user input" one was a joke.

 

But yes, doing such input from disk would be a memory saver.

 

Another one if the RAM isn't being used could be to have a RAMDisk handler that uses RAM under the OS. Give it NOTE/POINT ability and you can do nice random access.

Link to comment
Share on other sites

For GSB I used a loader program (autorun.tbs) which made use of Page 6 and CASBUF. Reading my assembler books (yes I'm still reading and not coding!) they mentioned using bytes towards the end of the stack's page - risky but they might not all get overwritten by a program :?: :!:

 

Check these threads out too:

 

http://www.atariage.com/forums/topic/155003-memory-use-re-turbo-basic-program/

 

http://www.atariage.com/forums/topic/165281-basic-optimisation/

 

:)

Link to comment
Share on other sites

Another idea: What about using NOT X instead of X=0, or IF X instead if IF X<>0 ... would that also save space? Especially for STRIG(0) which only returns 0 or 1

This one will definitely save some space, exactly 7-8 bytes per every occurence.

 

You can also save 2 bytes when using ON X GOTO Y instead of IF X THEN GOTO Y.

Edited by pseudografx
Link to comment
Share on other sites

ok, I had an idea:

 

It as suggested that instead of using a string, I use free RAM ...

 

I have an undo buffer of 16 bytes which I had been using as UNDO1$(8) and UNDO2$(8). What I want to do is instead use memory locations 713-728 as this buffer. Mapping the Atari says these are free to use, would this be ok? Are there any other unused locations in memory I can make use of? The cassette buffer is out, because I am already using it for the VBI routine, and page 6 is being used for a DLI routine.

 

A quick look through Mapping the Atari has brought back these possibilities:

 

906-999: Printer buffer. Since I am not using a printer, maybe I can use this?

 

1000-1020: Spare buffer area unused by the OS?

 

1152-1279: 128 spare bytes

Edited by Synthpopalooza
Link to comment
Share on other sites

ok, I had an idea:

 

It as suggested that instead of using a string, I use free RAM ...

 

I have an undo buffer of 16 bytes which I had been using as UNDO1$(8) and UNDO2$(8). What I want to do is instead use memory locations 713-728 as this buffer. Mapping the Atari says these are free to use, would this be ok? Are there any other unused locations in memory I can make use of? The cassette buffer is out, because I am already using it for the VBI routine, and page 6 is being used for a DLI routine.

Are you using PM Graphics? There's always unused space there (384 or 768 bytes depending on single or double line mode - always at the start of PMBASE).

Link to comment
Share on other sites

ok, I had an idea:

 

It as suggested that instead of using a string, I use free RAM ...

 

I have an undo buffer of 16 bytes which I had been using as UNDO1$(8) and UNDO2$(8). What I want to do is instead use memory locations 713-728 as this buffer. Mapping the Atari says these are free to use, would this be ok? Are there any other unused locations in memory I can make use of? The cassette buffer is out, because I am already using it for the VBI routine, and page 6 is being used for a DLI routine.

Are you using PM Graphics? There's always unused space there (384 or 768 bytes depending on single or double line mode - always at the start of PMBASE).

 

Not using PM graphics at all ... everything in this editor is character mode-driven.

 

 

 

 

Link to comment
Share on other sites

I seen to have run into a new problem:

 

I am trying to get my font editor to load a special font format I call .ICE, which is made up of the following:

 

Byte #1: Graphics mode (0-19)

then a number of bytes which correspond to color registers, the number varies depending on which graphics mode is used (e.g. Super IRG uses only 5 registers, 708-712, while Super IRG 2 will use 9 different color registers).

 

then two font files, each one 1024 bytes.

 

The problem is, when I go to use a get #1,a in my program, I immediately get an error-136. BGET seems to work fine when reading from this file, but get seems to be no good. I am attaching an ATR containing ICE GTIA, plus the font file TEST.ICE which I am trying to get this program to load. It should (if it were working correctly) automatically load the font, then switch the graphics mode to Super 9 and set two color registers.

 

Here is the code I used for creating and saving the font data:

 

21000 PROC FONTLOAD
21010   EXEC CLEARMENU
21020   POSITION 0,13
21080   EXEC CLEARMENU
21081   POSITION 0,13:? "Load Mask ±, Mask ², ÆN2 or ÉCE file:";
21082   GET KK
21083   IF KK<>ASC("F") AND KK<>ASC("I") AND KK<>ASC("1") AND KK<>ASC("2") AND KK<>27 THEN 21082
21090   POSITION 0,13:? "œInput filespec:";:INPUT #16,FN$
21100   REM TRAP 21140
21110   CLOSE #1:OPEN #1,4,0,FN$
21111   IF KK=49 THEN BGET #1,CHBAS,1024:GOTO 21140
21112   IF KK=50 THEN BGET #1,CHBAS+1024,1024:GOTO 21140
21113   IF KK=ASC("I")
21114 	GET #1,A:GRMODE=A-4:EXEC CYCLEGR
21115 	FOR I=1 TO 15
21116   	IF CREG(A-3,I) THEN GET #1,B:POKE CREG(A-3,I),B
21117 	NEXT I
21118   ENDIF 
21120   BGET #1,CHBAS,2048
21140   CLOSE #1
21150   TRAP 40000
21160 ENDPROC 
21170 PROC FONTSAVE
21180   EXEC CLEARMENU
21181   POSITION 0,13:? "Save Mask ±, Mask ², ÆN2 or ÉCE file:";
21182   GET KK
21183   IF KK<>ASC("F") AND KK<>ASC("I") AND KK<>ASC("1") AND KK<>ASC("2") AND KK<>27 THEN 21182
21190   POSITION 0,13:? "œInput filespec:";:INPUT #16,FN$
21200   TRAP 40000
21210   CLOSE #1:OPEN #1,8,0,FN$
21211   IF KK=49 THEN BPUT #1,CHBAS,1024:GOTO 21240
21212   IF KK=50 THEN BPUT #1,CHBAS+1024,1024:GOTO 21240
21213   IF KK=ASC("I"):TRAP 40000
21214 	PUT #1,GRMODE+3
21215 	FOR I=1 TO 15
21216   	IF CREG(GRMODE,I) THEN PUT #1,CREGVAL(GRMODE,I)
21217 	NEXT I
21218   ENDIF 
21220   BPUT #1,CHBAS,2048
21240   CLOSE #1
21250   TRAP 40000
21998   MENU=0:EXEC CYCLEMENU
21999 ENDPROC

 

To access the save and load functions, use "S" or "L" from the main menu.

 

 

 

 

 

Edited by Synthpopalooza
Link to comment
Share on other sites

The I/O section in the attached program is totally different to the code snippet you posted. Is that intentional?

 

Hmm ... I'll check.

 

I think I found my problem anyway. When I tried running this in Atari800Win it worked properly, however for some reason running this with Altirra generates an error 136 everytime I try to use GET #1,A on any open filename.

 

an updated zip with the new code is attached. Idea is: try running this in Altirra and see if there is an error-136, as opposed to Atari800Win.

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...