Jump to content
IGNORED

Assembly on the 99/4A


matthew180

Recommended Posts

 

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

Link to comment
Share on other sites

... 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. :)

Link to comment
Share on other sites

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.

  • Like 3
Link to comment
Share on other sites

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. :)

Link to comment
Share on other sites

  • 4 weeks later...

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 by Airshack
Link to comment
Share on other sites

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

  • Like 1
Link to comment
Share on other sites

 

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

Link to comment
Share on other sites

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

Edited by TheBF
  • Like 1
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

  • Like 1
Link to comment
Share on other sites

Here is how fbForth 2.0 uses Scratchpad RAM (from Chapter 4 of the fbForth 2.0 manual):

 

post-29677-0-80225700-1504584571_thumb.png

 

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

  • Like 2
Link to comment
Share on other sites

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.

  • Like 1
Link to comment
Share on other sites

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.

  • Like 1
Link to comment
Share on other sites

aa4be024af5de03b9aca74c3ff54072d.jpg

 

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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?

  • Like 1
Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...