Omnimaga
Calculator Community => TI Calculators => Axe => Topic started 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?
-
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.
-
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.
-
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.
-
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.
-
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?
-
I just don't understand how to set up memory to swap in spare RAM. I don't have example code.
-
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?)
-
Yes, it's okay, and thank you :)
That gives me C000 and up as free RAM, correct?
-
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?
-
No, that much should be fine. If I have an app running at 4000h, what happens to it?
-
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.
-
Then the App is switched out. If you run this from an app, you might have a problem.
-
So this only works from a program? And I get 4000-7FFF, assuming I use FillBasePageTable?
-
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+.
-
I have only ever used it from a program or from a spot in RAM not on the page I was swapping out.
-
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.
-
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
<<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:
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
-
No, like this, in asm:
di
in (6), a
out (7), a
jp $+4000h
ld a, 83h
out (6), a
; Business as usual
-
No, like this, in asm:
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.
-
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.
-
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.
-
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
<<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:
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.
-
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.
-
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.)
-
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.
-
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.
-
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 \(^_^)/
-
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!
-
FloppusMaximus: I believe BrandonW has stated that the Nspire's TI-84+SE compatibility layer simulates 128 K of RAM.
-
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.
-
I heard that they were emulated but I don't know if they're accessible as easily as on the 84+.