Calculator Community > Axe

Variable Subroutines

<< < (2/3) > >>

E37:
Here is a subroutine I have thrown together really quickly. I haven't tested it but it should be able to run any program or appvar whose name is passed to it. It needs to be compiled as an app!

:Lbl Execute .Call it like :Execute("prgmNAME")
:Return!If GetCalc(r1,Y1) .Get the variable and return if we can't find it.
:New(E9D95,0,{Y1-2}r-2->r1) .Create space for it to be copied to. Since we don't need the program's name anymore, we can store its size to r1. The -2 is for the program header
:r1:Asm(E5) .Push the value of the program's size. E5 *should* be the code for 'push hl' We need to push it because we don't know if the program we are running will destroy the variable we save it to. You could probably save it to E9D93, but it is safer this way
:Copy(Y1+2,E9D95,r1) .Copy the program to the area of memory we just created. The +2 is to skip over the program header BBh, 6Dh
: (E9D95)() .Run the program
:Asm(E1)->r1 .Get the saved value of size of the program.
:Delete(E9D95,0,r1) .Restore memory to how it was before we copied the program in.
:Return .Done!

Edit: Forgot about the 2 bytes for the program header

Terrav:
That looks good, but I can't do that given my Axe version doesn't have New( and Delete( (and also only supports two-character labels).
However, I think I have this figured out now. What I did was put Lbl A0 at the beginning of my code and Buff(1)→GDB3ND at the very end, and use this little subroutine (I left out a lot of code to make it short:

--- Code: ---.This is my execution subroutine
Lbl X
.Get the program, use X and Y0
Return!If X
If LA0=E9D95
 .We are running in a program
 Return!If {Y0-2}r>EC000-GDB3ND .Too large, can't execute
 Copy(Y0,GDB3ND,{Y0-2}r) .assuming this is a special format
 Goto (GDB3ND) .The program will automatically exit this subroutine
ElseIf LA0/4096=4
 .This is an app, let's just use 9D95!
 Return!If {Y0-2}r>8811 .This is the real limit from 9D95h to BFFFh
 Copy(Y0,E9D95,{Y0-2}r)
 Goto (E9D95)
End .Still haven't bothered working with shells at this point

--- End code ---

Of course, this assumes the executable data begins right with the file.

Deep Toaster:
The program version has the issue I called out earlier, which is that almost all assembly programs will crash if run from any address that's not 9D95h.

A way to get around this would be to copy the shell's code to a safe RAM area, jump there, move the program you want to run to 9D95h, and then call 9D95h.

Regardless, you can't just Copy() code to 9D95h, because there's likely to be variables there which you would be overwriting. (The TI-OS, as well as New() in E37's code, actually move any variables there out of the way so that that space is safe to use.)

E37:

--- Quote from: Terrav on January 05, 2021, 06:08:29 pm ---That looks good, but I can't do that given my Axe version doesn't have New( and Delete( (and also only supports two-character labels).
However, I think I have this figured out now. What I did was put Lbl A0 at the beginning of my code and Buff(1)→GDB3ND at the very end, and use this little subroutine (I left out a lot of code to make it short:

--- Code: ---.This is my execution subroutine
Lbl X
.Get the program, use X and Y0
Return!If X
If LA0=E9D95
 .We are running in a program
 Return!If {Y0-2}r>EC000-GDB3ND .Too large, can't execute
 Copy(Y0,GDB3ND,{Y0-2}r) .assuming this is a special format
 Goto (GDB3ND) .The program will automatically exit this subroutine
ElseIf LA0/4096=4
 .This is an app, let's just use 9D95!
 Return!If {Y0-2}r>8811 .This is the real limit from 9D95h to BFFFh
 Copy(Y0,E9D95,{Y0-2}r)
 Goto (E9D95)
End .Still haven't bothered working with shells at this point

--- End code ---

Of course, this assumes the executable data begins right with the file.

--- End quote ---

To get the New( and Delete( you need to do #Axiom(MEMKIT) assuming you have it installed. If you don't, download Axe again and go to Axe Parser/Tools/Memkit. The tokens are located in the vars menu. When adding axioms, the tokens don't show up as soon as you add the #Axiom( line. You will have to quit and reopen the program to get them to show up.

If you Axe version only supports two character labels you must be using some ancient version. Here, get the current version.

Like Deep Toaster said, you can't just copy code to any location and expect it to run. Your 24k of normal memory starts at 9D95h. There may be a program there already that you are overwriting. Additionally, in the ram version of your program, any kind of complex code won't run from that buffer. If you try to run code that does :Goto (E9D95+20) then it won't goto 20 bytes after the start of its code, but 20 bytes after the start of your code. And then bad things happen.
Additionally the program can be bigger than 8811 bytes large, they just can't have executable code after that. Having data over that limit is fine.


I would also like to pick on your axe code a bit. I get it is going to be messy because you are still trying to get the code to work but I can't help myself. This will just be style and optimization stuff.
First off, you can use up to like 14 upper and lowercase letters for label (and variable) names. No need to make them short like in TI-BASIC.
The first line of your subroutine is Return!If X and X is never used again after that. What's the point?
Your line :If LA0=E9D95 can be turned into a conditional comment. For example:
--- Code: ---:...If LA0=E9D95  .I'm using a conditional comment. Since this will only ever be an app or a program and never swap, why compile the code for the other?
:.Stuff for program version here
:...Else .No need for an ElseIf here. If we aren't a program, we have to be an app.
:.Stuff for app here
:...
--- End code ---
You need parenthesis for  Return!If {Y0-2}r>EC000-GDB3ND. It should look like  ReturnIf {Y0-2}r>(EC000-GDB3ND). Axe has no order of operations and always goes from left to right. I'm not sure why you made it Return!If since you are trying to return if it is greater and not if it isn't.
Again, the ! makes means you are returning when you don't want to and running when you do. Return!If {Y0-2}r>8811 .Why return if it IS less than that size?
In general, it is more efficient to do :!If X-5 instead of :If X=5
You can put the line :[]->GBD3ND at the end of your program instead of Buff(1)->GBD3ND. It gets the pointer to the end of your program just the same and doesn't add that additional byte.

Terrav:
OK, I see. I made a mistake in the code. You're right, it is ReturnIf. However, I tried this and it works! as long as the program is just one byte. I tried it with a program that just returns, and it works fine. But when I compiled a Minesweeper game to run with this, it resets either when the program starts, or shortly after (after user input). There's absolutely no difference each time. To make things weirder, when the calculator resets, it deletes a certain appvar I use. What's weird is the appvar is only ever in the RAM immediately after the program finishes, then goes right back into the archive. (I use this var to keep track of which programs were last run) I thought maybe there's a C9h inserted in the wrong spot (my shell is supposed to add a C9 to the end of a program when it executes it for safety) and the calculator resets when it returns to the app without unsetting Fix 7 (my program uses this).

Navigation

[0] Message Index

[#] Next page

[*] Previous page

Go to full version