Asmusr Posted August 12, 2017 Share Posted August 12, 2017 Sure, but the ISR is the one thing to be aware of that might interfere with your program, by trashing your variables in scratch pad or changing the VDP address. I always turn off the ISR. 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 13, 2017 Share Posted August 13, 2017 Well, on the TI-99/4A, I've always used the stack growing in the other direction. To follow your example ... A push is then done with MOV @DATA,,*SP+ and a pop with DECT SP MOV *SP,@DATA A convention in my experience is to have stacks grow downwards from high RAM and memory usage to grow upwards. Not written in stone somewhere, just something I have seen. BF Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted August 13, 2017 Share Posted August 13, 2017 ... my experience is to have stacks grow downwards ... Yes. For my practical use of a stack simply saving and retrieving return addresses. I originally only looked at saving a few bytes and not at CPU cycles used. Growing downwards would need 4 bytes in-line to PUSH and 4 bytes to POP and return. 8 bytes in total. PUSH would consist of 2 lines of instructions, namely DECT and MOV. POP would have MOV and RT. Growing upwards would need 2 bytes in-line to PUSH (1 line is nice and clean) and 6 bytes to POP and return. Also 8 bytes in total. I replaced the in-line POP with a branch which is 4 bytes *). PUSH would consist of 1 line, namely MOV. POP would have 1 line (nice and clean), namely B. The general code to branch to consists of 6 bytes or 3 lines of instructions, namely DECT, MOV and RT. Growing down would use 8 bytes per routine. Growing up would use 6 bytes per routine and one generel chunk of 6 bytes. There's a break-even at 3 routines. 8X = 6X + 6 2X = 6 X = 3 *) Could be optimized and cut to 2 bytes using jump in a very few cases. For fun I now took a look at CPU cycles used according to Classic99. Growing down would use 78 cycles per routine. Growing up without branching use the same cycle count. Growing up with branching would use 130 cycles per routine. Did I get it all right? Hope so. Quote Link to comment Share on other sites More sharing options...
apersson850 Posted August 13, 2017 Share Posted August 13, 2017 If you use it for saving return addresses only, it doesn't matter much. But if the stack is used for other things too, then it's sometimes handy to have the stack pointer actually pointing at the top of stack all the time, not pointing to the next free space above top of stack. With the TMS 9900 you can easily address top of stack in any case, but if you let the stack grow downwards, as I indicated, then top of stack is accessed by *SP. If you let it grow upwards, and want to use autoincrement, then you have to refer to top of stack as @-2(SP). Doable, but slower and consumes more space. When allocating a frame on the stack, i.e. a larger piece of data, then it's also easy to refer to the items in that record by indexing from the stack pointer with positive indexes. You can do the opposite, but at least to me, I find it easier to think in positive terms. You push by AI -ITEMSIZE,SP When you transferred the data to the stack, you reach the top element by *SP and items further down by @OFFSET(SP). You have use for such data on the stack when traversing graphs, for example. 3 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 13, 2017 Share Posted August 13, 2017 This is the way most Forths are implemented for both stacks for all the reasons you state. In CAMEL99 I tried a common optimization and CACHE the top of stack value in a register. This changes where you have to push and pop but on balance it speeds up a Forth system by about 10%. Simple Math operations become: A *SP+,R4 versus A *SP+,*SP Fetching the contents of a variable is: MOV *R4,R4 I like it. Quote Link to comment Share on other sites More sharing options...
Airshack Posted September 5, 2017 Share Posted September 5, 2017 (edited) Just read about the Workspace Pointer being initially set to >83E0 at boot up or Reset by a Level 0 interrupt, as per the ROM Monitor . This seems well placed since the range >83E0 to >83FF is 32-bytes of the 256-byte most efficient 16-bit CPU addressable "scratchpad" RAM. Why would a non-context-switching 99/4 programmer wish move the WP elsewhere? If you routinely do so please explain to where and why? Gratitude Always. -james Edited September 5, 2017 by Airshack Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 5, 2017 Share Posted September 5, 2017 If you never use GPLLNK (WSP = >83E0) or allow the console ISR to run (WSP = >83C0 and switches to/from GPL WS), you are probably safe using the GPL WS. ...lee 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted September 5, 2017 Share Posted September 5, 2017 Well... the TI system is using the workspace at 83E0 and it kind of assumes it owns them. So if you want a full register set for your program, it's available. And if you don't change you have to save at least some of the registers in order to use them. Also it's simpler to let TI-99 keep it's workspace when you call some of the system calls like KSCAN and such. So the good news is there is a nice space at >8300 that is waiting for your program to use as a workspace. Take it and have 16 registers to yourself. B 1 Quote Link to comment Share on other sites More sharing options...
Airshack Posted September 5, 2017 Share Posted September 5, 2017 So the good news is there is a nice space at >8300 that is waiting for your program to use as a workspace. Take it and have 16 registers to yourself. B So you're saying just use BLWP >8300 for your own registers and leave the >83E0 -- >83FF area alone for the Service Routines with LIMI 2. Otherwise, with LIMI 0... use BLWP >8300 and feel free to use >83E0 -- >8300 for anything else, with no worries? Sent from my iPhone using Tapatalk Pro Quote Link to comment Share on other sites More sharing options...
+TheBF Posted September 5, 2017 Share Posted September 5, 2017 (edited) Actually just LWPI >8300That way you wont't pollute R13, R14 and R15 in the Other workspace. And that only guarantees you 8300 to 830F (16 words of memory for registers) Consult the Editor Assembler manual for the usage of the memory at 8300 to 83FF Edited September 5, 2017 by TheBF 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 5, 2017 Share Posted September 5, 2017 And that only guarantees you 8300 to 830F (16 words of memory for registers) Typo there—8300 to 831F. ...lee 1 Quote Link to comment Share on other sites More sharing options...
Airshack Posted September 5, 2017 Share Posted September 5, 2017 Actually just LWPI >8300 That way you wont't pollute R13, R14 and R15 in the Other workspace. And that only guarantees you 8300 to 830F (16 words of memory for registers) Consult the Editor Assembler manual for the usage of the memory at 8300 to 83FF LWPI >8300 is indeed what I meant. I've been reading E/A which seems heavy on facts and especially light on technique. I suppose tonight's question is more of a technique question. Where does everyone put their registers, and why? Seems >8300 is commonly used since it's in the scratchpad. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 5, 2017 Share Posted September 5, 2017 So you're saying just use BLWP >8300 for your own registers and leave the >83E0 -- >83FF area alone for the Service Routines with LIMI 2. >83C0 – >83FF if you use LIMI 2 anywhere in your program. Otherwise, with LIMI 0... use BLWP >8300 and feel free to use >83E0 -- >8300 for anything else, with no worries? Again, as long as you never use LIMI 2. If you do use LIMI 2, you will need to have backed up that WS as it was before you used it so you can restore it before issuing LIMI 2. There are a few values needed by the ISR when it changes from the ISR WS to the GPL WS. I would need to review the ISR routine and the routine(s) it calls, but I think, at times, the ISR also uses values in the GPL WS without BLWP/LWPIing to it ...lee 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 5, 2017 Share Posted September 5, 2017 Here is how fbForth 2.0 uses Scratchpad RAM (from Chapter 4 of the fbForth 2.0 manual): As you can see, >8300 – >831F is the fbForth workspace. The ISR and GPL workspaces are left alone for the most part because the normal state is LIMI 2 in fbForth. The Default Data Stack at >83A0 – >83BF is used by the Floating Point Library for its workspace because the FPL does not use any GPL or XML calls that would use that space. ...lee 2 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted September 5, 2017 Share Posted September 5, 2017 So it depends entirely in which context your program exists. Most efficient programs are a mix of high level and assembly. Thus your assembly programs have to respect the environment they were called from. An assembly procedure called from Pascal can't use more than R0-R7 in the calling workspace, which is at 83C0, without saving what it changes. It's only programs that don't intend to return to anything but a reboot that can roam everywhere in memory. 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted September 5, 2017 Share Posted September 5, 2017 Typo there—8300 to 831F. ...lee Yup, Quote Link to comment Share on other sites More sharing options...
Airshack Posted September 5, 2017 Share Posted September 5, 2017 So it depends entirely in which context your program exists. Most efficient programs are a mix of high level and assembly. Thus your assembly programs have to respect the environment they were called from. An assembly procedure called from Pascal can't use more than R0-R7 in the calling workspace I'm thinking as a beginner in Assembly the Pure-Assembly route introduces less complexity. 1 Quote Link to comment Share on other sites More sharing options...
Airshack Posted September 5, 2017 Share Posted September 5, 2017 >83C0 – >83FF if you use LIMI 2 anywhere in your program. Again, as long as you never use LIMI 2. If you do use LIMI 2, you will need to have backed up that WS as it was before you used it so you can restore it before issuing LIMI 2. Got it! Thx:) Quote Link to comment Share on other sites More sharing options...
Airshack Posted September 5, 2017 Share Posted September 5, 2017 Bob Webb's collection of User Group newsletter Assembly Lessons is especially enjoyable to read. His humor and artwork combine well with an ability to clarify some challenging topics. Today's questions come from Bob's tutorial on the Memory Map. From what I've gathered the 8k area from >6000 to >7FFF is for Command Module memory: GROM and ROM, or in the case of Mini-Memory GROM/ROM and "middle memory" RAM. Q1: This Command Module ROM is either TI's proprietary GROM (auto-incrementing for faster sequential reads) or regular ROM, or both. Correct? Q2: Is it safe to assume using GROM was less about speed and more about controlling developers? Q3: If one wishes to write Assembly code for a cartridge ROM, you're limited to 8k? Q4: How does the console v2.2 ROM lock out GROM-less cartridges? Q5: Are the modern carts sold by Greg on Arcadeshopper unable to run on the v2.2 machine? Thanks guys! Many pieces to this TI 99/4A puzzle! -j Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 5, 2017 Share Posted September 5, 2017 One place to always check is Thierry Nouspikel’s TI-99/4A Tech Pages. That said, re questions 1 and 3, cartridge ROM space is indeed in the CPU address space at >6000 – >7FFF. You can write programs larger than 8 KiB for this space by using bank-switching techniques—fbForth 2.0 uses 32 KiB (4 8-KiB banks). GROM space, however, is not in CPU address space. GROMs are memory-mapped devices with their own address space accessed through 4 CPU address windows for each GROM base. For GROM base >9800, these window addresses are >9800: read data (GROM base) >9802: read address+1 >9C00: write data >9C02: write address Others here will elaborate this topic much better than I can. Re question 2, though proprietary control was part of it, I think it was more about space. You can write a GPL program in a good bit less space than the same program would occupy in Assembly Language. ...lee Quote Link to comment Share on other sites More sharing options...
Asmusr Posted September 5, 2017 Share Posted September 5, 2017 Q3: No, because modern cartridges have many 8K pages. Q4: By not showing them in the menu. Q5: Yes, ROM only cartridges are unable to run on a v2.2 machine, except if you do tricks. 1 Quote Link to comment Share on other sites More sharing options...
Airshack Posted September 5, 2017 Share Posted September 5, 2017 One place to always check is Thierry Nouspikel’s TI-99/4A Tech Pages. ...lee Thank you for this link! This kind of material helps break up the monotony of reading through the E/A manual. -j Quote Link to comment Share on other sites More sharing options...
Airshack Posted September 5, 2017 Share Posted September 5, 2017 Q3: No, because modern cartridges have many 8K pages. Q4: By not showing them in the menu. Q5: Yes, ROM only cartridges are unable to run on a v2.2 machine, except if you do tricks. Q4: So it must look for the GROM in the cartridge address space at RESET? Quote Link to comment Share on other sites More sharing options...
Asmusr Posted September 5, 2017 Share Posted September 5, 2017 Q4: So it must look for the GROM in the cartridge address space at RESET? No, a v2.2 machine doesn't look in the cartridge space at all, but it looks for GROMs in the GROM space. 1 Quote Link to comment Share on other sites More sharing options...
matthew180 Posted September 7, 2017 Author Share Posted September 7, 2017 Answering rather late, sorry. I always put my workspace at >8300. No particular reason other than I have always done it that way and it is out of the way of using the rest of the scratch pad RAM for variable storage. IMO you should *always* use a workspace in the 16-bit scratch pad RAM, otherwise you pay a hefty performance penalty. As others have mentioned, if you are going to use console routines (ROM or GROM) or allow the console ISR to run, then you will need to know and respect the use of scratch pad based on those services. Also, if you are interfacing with XB then I think there are additional constraints. Q1: This Command Module ROM is either TI's proprietary GROM (auto-incrementing for faster sequential reads) or regular ROM, or both. Correct? A command module can contain both ROM and GROM. Q2: Is it safe to assume using GROM was less about speed and more about controlling developers? That would be a good assumption. Secondary assumptions might be cost, component size, or number of pins. Q3: If one wishes to write Assembly code for a cartridge ROM, you're limited to 8k? Without bank-switching, yes, you are limited to 8K. With bank-switching you are limited to 8K at *any single time*. Basically bank-switching gives you an 8K window into the larger memory space. Q4: How does the console v2.2 ROM lock out GROM-less cartridges? I'm not totally up on my console differences, but as others have said I think carts that do not have GROM do not show up on the menu. Also, I think the QI console removed some of the physical connections to the cartridge port, so ROM is not physically possible. I might be wrong about that though, so check the facts. Q5: Are the modern carts sold by Greg on Arcadeshopper unable to run on the v2.2 machine? No idea. Greg? 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.