Omnimaga

Calculator Community => TI Calculators => Axe => Topic started by: SirCmpwn on December 06, 2010, 04:46:15 pm

Title: RAM
Post by: SirCmpwn on December 06, 2010, 04:46:15 pm
Hello,
How would I go about setting up an Axe application with a different page of RAM so that I have more space?  Also, would it work on newer models?
Title: Re: RAM
Post by: jnesselr on December 06, 2010, 06:14:04 pm
What do you mean setting it up with a different page of ram? As in copying it into another ram page, or running it from a ram page?

The only way, that I can think of, is to use port 6 and 7, and copy 0x4000 to 0x8000.  But messing with port 7 is hard. Also, you could just allocate enough space for an appvar, copy it, then copy it to a ram page.  Not sure if it is runnable, though.
Title: Re: RAM
Post by: SirCmpwn on December 06, 2010, 06:14:52 pm
I just want to have a lot of free RAM that I can just use.  I figure swapping in a different RAM page would do this, but I don't know how.
Title: Re: RAM
Post by: FloppusMaximus on December 06, 2010, 09:13:46 pm
Well, first off, how much RAM do you really need?  Could you stick to using the main RAM, and keep compatibility with the 83+ BE?

Hardware-wise, the Z80 address space is divided into 4 "banks", which each hold one 16k memory page.  The first bank is always used for Flash page zero; the second two ("A" and "B") can be mapped to any page you like, and the fourth ("C") is always used for RAM page zero on the 83+ BE, but can be mapped to any RAM page on the 83+ SE and 84+.

Now, all of that said, you should realize that you can't usually change the pages mapped in banks B and C, unless you're very careful about it; bank C contains your program's stack, and bank B contains your program's code and variables.  Bank B - RAM page 1 - also contains lots of variables that are used by system routines, including the system interrupt service routine.

So that leaves bank A.  In a RAM assembly program, you can change bank A whenever you like (unless it's a shell program and you're using shell library routines), but you also have to be sure to restore the original page to bank A when your program finishes.  This might be a plausible strategy for Axe programs (correct me if I'm wrong, but I don't think Axe programs use any shell library routines), but it wouldn't work for Flash applications.  And of course it does break compatibility with the 83+ BE.

As far as what pages you can use: newer 84+es have only 1 extra page of RAM, whereas older 84+es, 83+ SEs, and (I believe) Nspire-84+es have 6 extra pages.  Of RAM page 3 (or, on newer calculators, the single extra page), a small amount of memory is used by the OS for storing application base pages (so if you overwrite that area, you have to call FillBasePageTable to restore it), and a further area (about a kilobyte, as I recall) is used as scratch space for USB operations.

Perhaps it would be useful for Axe to provide an "allocate temporary buffer" function, which could be implemented in various ways depending on the calculator model and the type of program (RAM versus application) you're compiling.
Title: Re: RAM
Post by: SirCmpwn on December 06, 2010, 11:31:45 pm
Thank you, but I know quite well about how the banks and all work.  If I didn't, I really shouldn't be writing KnightOS.  I just want to know how to swap in an extra RAM page, because I can never seem to get this particular part working.
Title: Re: RAM
Post by: FloppusMaximus on December 06, 2010, 11:56:02 pm
Right, sorry.  In that case, I'm not sure what exactly you're asking.  Could you post an example of code you've tried that doesn't work the way you expect?
Title: Re: RAM
Post by: SirCmpwn on December 06, 2010, 11:57:09 pm
I just don't understand how to set up memory to swap in spare RAM.  I don't have example code.
Title: Re: RAM
Post by: FloppusMaximus on December 07, 2010, 12:17:44 am
I guess you would do something like "in a,(6) / push af / ld a, 83h / out (6),a" (Asm(DB06F53E83D306)) to set the mapping, and "pop af / out (6),a" (Asm(F1D306)) to restore it.  (Is it OK to use pushes and pops in inline assembly like that?)
Title: Re: RAM
Post by: SirCmpwn on December 07, 2010, 12:19:58 am
Yes, it's okay, and thank you :)
That gives me C000 and up as free RAM, correct?
Title: Re: RAM
Post by: Xeda112358 on December 07, 2010, 12:20:38 am
There shouldn't be a problem with that, I use that all the time for when I switch out pages. It won't pose a problem at all unless his code uses a "pop" without another "push."

EDIT: Ninja!

No, all it does is swap out 4000h to 7FFFh to the RAM page leaving the rest intact. Are you trying to make use of all of the RAM at once?
Title: Re: RAM
Post by: SirCmpwn on December 07, 2010, 12:23:22 am
No, that much should be fine.  If I have an app running at 4000h, what happens to it?
Title: Re: RAM
Post by: FloppusMaximus on December 07, 2010, 12:25:30 am
Yes, it's okay, and thank you :)
That gives me C000 and up as free RAM, correct?
No, that's port 6, which controls the 4000-7FFF area.  And if you want to use the area from 4000h to 4080h, you should also add a B_CALL FillBasePageTable (that's EF1150) to clean up when you're done.
Title: Re: RAM
Post by: Xeda112358 on December 07, 2010, 12:26:10 am
Then the App is switched out. If you run this from an app, you might have a problem.
Title: Re: RAM
Post by: SirCmpwn on December 07, 2010, 12:26:58 am
So this only works from a program?  And I get 4000-7FFF, assuming I use FillBasePageTable?
Title: Re: RAM
Post by: FloppusMaximus on December 07, 2010, 12:29:08 am
Right.

If you want to write an app that does this, it becomes much more complicated.

Oh, and you should also add a check at the start of your program, to be sure you're running on an SE/84+.
Title: Re: RAM
Post by: Xeda112358 on December 07, 2010, 12:29:48 am
I have only ever used it from a program or from a spot in RAM not on the page I was swapping out.
Title: Re: RAM
Post by: SirCmpwn on December 07, 2010, 12:42:14 am
So if I have an app, could I read in the page I'm running on, then swap it into bank 2 and jump to bank 2, where I then swap in the RAM?  Probably tough to pull off in Axe, but I have a few ideas.
Title: Re: RAM
Post by: Xeda112358 on December 07, 2010, 12:42:24 am
So, I've never made a multi page APP before... Would it be that I could make a code like this:

This heads both pages
Code: [Select]
<<Header>>
1803          This skips the next 3 bytes
DB06          This changes the flash page to whatever was in a
C9            This is executed on the next page, pops the value into PC and picks up the code from there
Continuing code to some part on the next page:
Code: [Select]
DB06          This gets the current flash page in a
3C            This increase a
21****        This is the address to jump to on the next page
E5            This pushes HL
C38240         This jumps to 2 bytes after the header
Title: Re: RAM
Post by: SirCmpwn on December 07, 2010, 12:47:55 am
No, like this, in asm:
Code: [Select]
di
in (6), a
out (7), a
jp $+4000h
ld a, 83h
out (6), a
; Business as usual
Title: Re: RAM
Post by: Xeda112358 on December 07, 2010, 12:50:40 am
No, like this, in asm:
Code: [Select]
di
in (6), a
out (7), a
jp $+4000h
ld a, 83h
out (6), a
; Business as usual
Hehe, sorry, my post came like 8 seconds after yours, I was asking Floppus
Yours is probably the way to go if you are running from the app page.
Title: Re: RAM
Post by: FloppusMaximus on December 07, 2010, 12:53:04 am
So if I have an app, could I read in the page I'm running on, then swap it into bank 2 and jump to bank 2, where I then swap in the RAM?  Probably tough to pull off in Axe, but I have a few ideas.
That would work in assembly language - as you say, it might be tricky in Axe - but you'd want to be sure interrupts are disabled.  Like I said before, the OS doesn't like it if you change port 7, and that includes the system interrupt service routine.  And remember that stuff like the screen buffers and A-Z variables are all stored in that area as well.

Another option, with the same caveats, would be to simply leave your app mapped in the 4000-7FFF slot, and temporarily map whichever RAM page you're interested in in the 8000-BFFF slot.
Title: Re: RAM
Post by: Xeda112358 on December 07, 2010, 12:54:58 am
Another option, with the same caveats, would be to simply leave your app mapped in the 4000-7FFF slot, and temporarily map whichever RAM page you're interested in in the 8000-BFFF slot.
Hehe, that might be more useful. I am glad I'm not doing the thinking 'round here.
Title: Re: RAM
Post by: FloppusMaximus on December 07, 2010, 01:04:18 am
So, I've never made a multi page APP before... Would it be that I could make a code like this:

This heads both pages
Code: [Select]
<<Header>>
1803          This skips the next 3 bytes
DB06          This changes the flash page to whatever was in a
C9            This is executed on the next page, pops the value into PC and picks up the code from there
Continuing code to some part on the next page:
Code: [Select]
DB06          This gets the current flash page in a
3C            This increase a
21****        This is the address to jump to on the next page
E5            This pushes HL
C38240         This jumps to 2 bytes after the header

Yes, that will work, I think.  In other words, you use the routine at 4082 (which is present at the same address on both pages) to switch from one page to the other.  The 84+ boot code uses a similar technique.

Another option is to use application B_CALLs and B_JUMPs.  You can make a table of addresses and page numbers on the first (or "base") page of your app, and then use a B_CALL instruction to call those routines from anywhere in your app.  For instance, if you have a routine at address 4567 on the second page, and you write the bytes 674501 at address 4083 on the first page, then (from either page) you can call that routine using a B_CALL 0083h (EF8300), or jump to it using a B_JUMP 0083h (CD50008300).  This is much slower than the method you're suggesting, but also takes less space.
Title: Re: RAM
Post by: Xeda112358 on December 07, 2010, 01:07:34 am
Cool! Now, I was actually wondering about the B_Call thing... What happens during the B_Call? Like, which pages get swapped where? I wanted to try something for fun that is like what you are talking about (making a jump table for B_Call), except in a RAM program.
Title: Re: RAM
Post by: FloppusMaximus on December 07, 2010, 01:32:46 am
Well, first off, for normal system B_CALLs, between 4000 and 7FFF, the B_CALL handler first looks on page 1B (or 3B or 7B, depending on the model), where there's a table of all the system routine addresses and page numbers.  So for instance, if you do a B_CALL GetKey (4972h), it looks at the 3 bytes stored at address 4972 on page 1B - in OS 1.19, that's 8B 49 06, i.e., address 498B on page 6.  The OS then pushes your original page number on the stack, as well as the address of a handler routine (on page zero).  It then loads page 6 in the 4000h bank and jumps to 498B.  When the GetKey routine returns, it returns to the handler, which pops the original page number off the stack, restores that value to port 6, and returns to your program.

Boot B_CALLs are provided by the boot code, not the OS.  They work exactly the same way, except that you use an "address" between 8000 and BFFF; the B_CALL handler subtracts 4000h from that value, then looks up the address to call on page 1F (instead of 1B.)

And finally we have application B_CALLs, like I mentioned above.  In this case, you use an "address" between 0000 and 3FFF; the B_CALL handler adds 4000h to that value, and looks up the address to call on the first ("base") page of whatever application is currently loaded in port 6.  In this case, the page number listed in the table is relative to that base page (so if your app is stored on pages 15 and 14, a value of 00 in the table corresponds to page 15, and 01 corresponds to page 14.)

(B_JUMP does the same thing as B_CALL, except that it doesn't save the original page number or push the extra handler on the stack.  You almost never want to B_JUMP to a system routine, but you may sometimes want to B_JUMP to routines within your app.)
Title: Re: RAM
Post by: Xeda112358 on December 07, 2010, 01:36:30 am
So, if I use a value between C000 and FFFF what happens? Could I then use a piece of RAM as a jump table? I'm really just curious; I know it would just be a waste of speed.
Title: Re: RAM
Post by: FloppusMaximus on December 07, 2010, 01:46:15 am
I'm not sure.  It looks like it would subtract 4000h from that value, so it would look for a jump address in RAM between 8000 and BFFF.  That might not work on all OS versions, though.
Title: Re: RAM
Post by: Xeda112358 on December 07, 2010, 01:48:17 am
Okee, I think I'll give it a try. Meanwhile, I just had a brilliant idea with an interrupt, if only I could manage it in my head. It will be my first interrupt \(^_^)/
Title: Re: RAM
Post by: FloppusMaximus on December 07, 2010, 01:51:33 am
Okee, I think I'll give it a try. Meanwhile, I just had a brilliant idea with an interrupt, if only I could manage it in my head. It will be my first interrupt \(^_^)/
Sounds scary. :)  I'm still amazed at how you can program the way you do.  Good luck!
Title: Re: RAM
Post by: DrDnar on December 07, 2010, 02:38:15 am
FloppusMaximus: I believe BrandonW has stated that the Nspire's TI-84+SE compatibility layer simulates 128 K of RAM.
Title: Re: RAM
Post by: JosJuice on December 07, 2010, 10:28:46 am
FloppusMaximus: I believe BrandonW has stated that the Nspire's TI-84+SE compatibility layer simulates 128 K of RAM.
I believe the Nspire only emulates the pages that the OS needs.
Title: Re: RAM
Post by: DJ Omnimaga on December 07, 2010, 02:51:32 pm
I heard that they were emulated but I don't know if they're accessible as easily as on the 84+.