[TI-ASM] Memory allocation and management

Got questions? Got answers? Go here for both.

Moderator: MaxCoderz Staff

User avatar
qarnos
Maxcoderz Staff
Posts: 227
Joined: Thu 01 Dec, 2005 9:04 am
Location: Melbourne, Australia

[TI-ASM] Memory allocation and management

Post by qarnos »

I'm not too up to speed on the way TI-OS handles memory, so maybe one of the gurus can help me out with this one.

I'm porting Aether to run as a flash library, and I'd like to be able to allocate the ~1kb I need for dynamically generated tables, etc, rather than forcing the program to do it to avoid redundant code in every program.

The obvious way is to create an AppVar and InsertMem as needed, but if the user program calls a CreateXXXX routine (eg - to save a game) will this invalidate my pointers? What if the program InsertMem's into itself?

As I understand it, shells move the program to the start of UserMem before running to give the maximum executable space. This means my AppVar will have a higher address and be pushed out of the way, right? So my pointers get blown to heck.

I've also noticed in the SDK a "temporary RAM" area, which would be much better suited to my purpose, but it would suffer from the same problem.

Is there a way I can find the variable of the running program an InsertMem into the end of it without potentially wrecking any code in the program that might also use InsertMem as a hard-coded address?

Maybe I need to re-think the way I am approaching this? Any help is greatly appreciated. I'd like to avoid forcing the programmer to take care of memory management.
"I don't know why a refrigerator is now involved, but put that aside for now". - Jim e on unitedti.org

avatar courtesy of driesguldolf.
User avatar
Dwedit
Maxcoderz Staff
Posts: 579
Joined: Wed 15 Dec, 2004 6:06 am
Location: Chicago!
Contact:

Post by Dwedit »

You need 1k of contiguous memory? Then you'll have to make an appvar.

The way shells move memory around varies. There's the Ashell/SOS method, the Ion/MirageOS method, and the Venus/CrunchyOS method.

Ashell/SOS just swapped memory directly, so you have no clue if anything outside the program is valid or not, and that introduced crazy hacks like an 'Install' program for SOS libs.

Ion/MirageOS moves the program to the start of user memory using repeated calls to insertmem/delmem, but does not change or move the size bytes. So the size bytes are sitting in memory somewhere, the VAT corectly points to the size bytes, but the memory block specified by the size bytes overlaps the other variables. While inside a Ion/MirageOS program, it's safe to create, resize, and delete other variables, just not the running program. I haven't followed newer MirageOS development, did they ever fix that later?

Venus/CrunchyOS move the size bytes too, so the VAT and program (including sizebytes) are always consistent. However, CrunchyOS has to modify the program to remove the first two bytes, then it can repair the program if it gets interrupted.

Because it's safe to create and use other variables in all the TI83+ shells, just do it.

to answer the question...
I think pointers may be invalidated when the user program creates a variable. Not completely sure, I think it might only become invalid if they resize a variable that occurs before your new variable.

On the other hand, if you don't need 1024 contiguous bytes, reserve some block of memory, like say Appbackupscreen, then tell the programmer not to touch it. Then also use something like the 560 free bytes at 8000 (I think they're free, the first 256 are definitely free for use)




I haven't touched TI83 development in a very long time... I'm amazed I still remember all this stuff.
You know your hexadecimal output routine is broken when it displays the character 'G'.
User avatar
qarnos
Maxcoderz Staff
Posts: 227
Joined: Thu 01 Dec, 2005 9:04 am
Location: Melbourne, Australia

Post by qarnos »

Unfortunately, yes - it needs to be contiguous. Actually, it also needs to be 256 byte aligned, so 255 times out of 256 I'll have to allocate even more than that :P

I might just add a routine the user can call to valid the ram if they muck around with vars, and it can update its internal pointers as needed.

Thanks for the info.
"I don't know why a refrigerator is now involved, but put that aside for now". - Jim e on unitedti.org

avatar courtesy of driesguldolf.
User avatar
Dwedit
Maxcoderz Staff
Posts: 579
Joined: Wed 15 Dec, 2004 6:06 am
Location: Chicago!
Contact:

Post by Dwedit »

So then, allocate 1024+256 bytes, then have the Update routine just move the data, or should it just recalculate the data?
You know your hexadecimal output routine is broken when it displays the character 'G'.
User avatar
qarnos
Maxcoderz Staff
Posts: 227
Joined: Thu 01 Dec, 2005 9:04 am
Location: Melbourne, Australia

Post by qarnos »

Dwedit wrote:So then, allocate 1024+256 bytes, then have the Update routine just move the data, or should it just recalculate the data?
I have it check where the memory was allocated and then it InsertMem's any required padding bytes.

Moving/recalculating is trivial enough - this is not something which is time critical, since it will only be needed during game saves, etc.

One other question - I remember reading somewhere that variable names shouldn't have numbers in them. Is this really true? I can't see what problems it would cause. Maybe I'm misremembering, but I'm sure I saw that somewhere.
"I don't know why a refrigerator is now involved, but put that aside for now". - Jim e on unitedti.org

avatar courtesy of driesguldolf.
User avatar
Dwedit
Maxcoderz Staff
Posts: 579
Joined: Wed 15 Dec, 2004 6:06 am
Location: Chicago!
Contact:

Post by Dwedit »

TIOS lets you use numbers in program names.
You know your hexadecimal output routine is broken when it displays the character 'G'.
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

As far as I've seen, you can use any character you wish in a program name apart from NUL.

Problems arise if you try and use the program from the TI-OS user interface (not using its internal routines for variable management). For example, you cannot paste the name of a program with lowercase characters in it onto the homescreen (it'll treat the name as if it was tokenised rather than plain text), and if the first character of a variable is outside a particular range (I'm not entirely sure what the range is, but numbers and lowercase characters aren't allowed) the variable won't show up in the TI-OS menus at all.
brandonw
New Member
Posts: 17
Joined: Thu 21 Jun, 2007 1:11 pm

Post by brandonw »

I have no idea what this thread's about, but there is 1087 bytes of contiguous scratch memory at 8000h, as long as you're careful. I wouldn't rely on this for some sort of really generic library that others can use, if I read you correctly, but it's there if you _really_ need contiguous memory.
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

What is that memory for, then, if anything?

I assume the TI-OS would use it for something, though I've probably got a little bit more faith in them then you do. :)
User avatar
qarnos
Maxcoderz Staff
Posts: 227
Joined: Thu 01 Dec, 2005 9:04 am
Location: Melbourne, Australia

Post by qarnos »

benryves wrote:What is that memory for, then, if anything?

I assume the TI-OS would use it for something, though I've probably got a little bit more faith in them then you do. :)
I was wondering the same thing myself. It just seems too convenient!

This is from ti83plus.inc:

Code: Select all

ramStart             EQU  8000h
appData              EQU  8000h
ramCode              EQU  8100h
ramCodeEnd           EQU  822Fh
baseAppBrTab         EQU  8230h
bootTemp             EQU  8251h
appSearchPage        EQU  82A3h
tempSwapArea         EQU  82A5h
appID                EQU  838Dh
ramReturnData        EQU  83EDh
arcInfo              EQU  83EEh
savedArcInfo         EQU  8406h
appInfo              EQU  8432h
appBank_jump         EQU  843Ch
appPage              EQU  843Eh
kbdScanCode          EQU  843Fh
Seems to be a lot of "app" stuff in there, so maybe it's used during app execution. That would mean don't touch it when running an application or from within an app shell.

It isn't really an issue for me now - I have it all sorted out. I am allocating an appvar and have a routine (alCheckRAM) which must be called after any mucking around with TI-OS variables so I can check if anything is out of alignment and fix it up.

I'm also now using it for the extra buffers needed for all the 3D stuff. It's actually kinda cool stepping through it in PTI and watching it do it's business when the buffers need to change size. Or maybe I'm just easily entertained. ;)

Thanks for the help, everyone! :)
"I don't know why a refrigerator is now involved, but put that aside for now". - Jim e on unitedti.org

avatar courtesy of driesguldolf.
brandonw
New Member
Posts: 17
Joined: Thu 21 Jun, 2007 1:11 pm

Post by brandonw »

qarnos wrote:

Code: Select all

ramStart             EQU  8000h
appData              EQU  8000h
ramCode              EQU  8100h
ramCodeEnd           EQU  822Fh
baseAppBrTab         EQU  8230h
bootTemp             EQU  8251h
appSearchPage        EQU  82A3h
tempSwapArea         EQU  82A5h
appID                EQU  838Dh
ramReturnData        EQU  83EDh
arcInfo              EQU  83EEh
savedArcInfo         EQU  8406h
appInfo              EQU  8432h
appBank_jump         EQU  843Ch
appPage              EQU  843Eh
kbdScanCode          EQU  843Fh
It's all used, of course, you can just get away with it as long as you don't rely too heavily on the OS.

ramStart is just an equate.

appData is used by the OS when receiving the OS, reading/copying Flash application headers, the OS header, and lots of other things. It's also used as scratch space by the small edit buffer routines, table and menu routines, etc. As long as you're not relinquishing control to the OS for some kind of edit, and you're not running applications or anything, this is going to be okay to use.

ramCode to ramCodeEnd is used as scratch space where code that needs to be executed from RAM is copied. Examples of this are all the boot code routines that deal with reading from or writing to Flash. And this is going to happen when you archive/unarchive stuff, mess around in some parts of the OS, or call any routine that could potentially use the Flash.

baseAppBrTab is the app base page table, which the OS uses to find the base page of an application. On the 83+SE, it's broken up into two parts, because there are many more potential base pages on it than the original 83+. The second half is at 9C06h, which is way off from here. You can overwrite this however you like, but it's going to mess with calling routines on other pages in multipage applications. If that's not an issue for you, fine...if so, rebuild it using BCALL 5011h (FillBasePageTable). The base page table on the 84+ and 84+SE is stored on RAM page 3, so there's no need to worry if you're just writing for those.

bootTemp is used by the boot code, particularly in the MD5 calculation routines. If you're not messing with MD5 routines, you don't need to worry.

appSearchPage is used by a lot of OS routines as the page it's searching from, or the page it found. If you're not using one of those routines, don't worry.

tempSwapArea is used by the OS as temp space for moving around Flash when messing with it. The reason why it's 232 bytes is because that's the size of the non-field part of the certificate, which is its primary purpose. I'd just be careful not to mess with Flash with this.

appID is also used by the OS and boot code like appSearchPage is, also for big integers.

ramReturnData is the same.

arcInfo is used heavily by archiving/unarchiving and garbage collecting, don't do that and you're fine. Same with savedArcInfo, and appInfo.

appBank_jump and appPage is used when jumping to off-page routines like hooks.

So most of it's when dealing with Flash or MD5 stuff. Don't be a multipage application, don't archive or write to Flash and stuff, and BCALL 5011h when you're done...that's pretty much it to use all that.
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Cheers for the explanation. :-)

I suppose that if you are running an application, memory from userMem/$9D95 is "free"; is there a way to tell the TI-OS that you're using space there? (I assume there would be from the way that the memory bcalls report less memory than the total when a program is running, and the variable manipulation bcalls work without interfering with the space).
brandonw
New Member
Posts: 17
Joined: Thu 21 Jun, 2007 1:11 pm

Post by brandonw »

You can steal space from there using _InsertMem and _DelMem. But don't return back to the OS like that...create a variable and use its space or delete what you insert before you quit.

You can never guarantee how much user RAM is available, though...a user can run a Flash application (from the OS) with only 50 bytes free (it does check to make sure 50 is free for some reason).
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Ah. I need a 768 bytes of RAM that resides on a 256 byte boundary, and its address can only be decided at compile time. I had thought that - provided I checked that there was sufficient free RAM to start with - I could claim, say, 9D95 to A0FF and locate my scratch buffer at 9E00.

This would be from a multi-page application that would also need to be using the variable creation and editing OS calls at runtime.

I'm not sure if this is any different from a shell copying a program to 9D95 to run it?
brandonw
New Member
Posts: 17
Joined: Thu 21 Jun, 2007 1:11 pm

Post by brandonw »

Shells can pull this off with virtually no memory left because they swap the contents of the program from wherever it is to 9D95h in pieces (768-byte pieces, conveniently the size of one of the screen buffer saferam areas). What you'd be doing is requiring that much user RAM be free.

If you're dead set on that, you COULD just find a variable that's at least 768 bytes big, copy its contents to a saferam area (and its VAT entry), and delete it...then you can _InsertMem 768 bytes to userMem, then do what you like, and then _DelMem those same 768 bytes from userMem, then recreate the variable from the contents of saferam and the VAT entry. That's also guaranteeing there's a variable on the calculator that's at least 768 bytes big, but you could put some logic in to take lots of small variables, too. Not the cleanest thing in the world, but it'd work.
Post Reply