Jump to content
IGNORED

SAMS usage in Assembly


gregallenwarner

Recommended Posts

18 hours ago, apersson850 said:

Ehhm, you can't use the same register as a pointer and counter (R2). MOV also moves two bytes at a a time, so it takes four MOV to move eight bytes.

 

But I understand what you intended to illustrate.

Yeah, yeah, yeah. I don't think I'll debug my code anymore, I'll just post it to the internet. ;)

Link to comment
Share on other sites

  • 1 month later...

Attached is an attempt to explain why an application should modify a SAMS register by writing a WORD and not a BYTE.  It looks like most software is doing that but there still seems to be some questions about it.  My thanks to apersson850 and Stuart for their inputs and edits.  Would also like to thank TheBF and mizapf for good discussion on the subject.

 

 

SAMS registers explained_Srt_AP edits.rtf

  • Like 3
  • Thanks 2
Link to comment
Share on other sites

16 minutes ago, Willsy said:

I just cribbed it all from the original SAMS docs/driver disks ?.

 

...which (the duplication of bytes) only works for SAMS RAM ≤ 1 MiB. For SAMS RAM > 1 MiB, the actual SAMS bank goes into the word (>0345, say) and the bytes are swapped (>4503) before writing the word to a SAMS register.

 

...lee

  • Like 1
Link to comment
Share on other sites

2 hours ago, Lee Stewart said:

 

...which (the duplication of bytes) only works for SAMS RAM ≤ 1 MiB. For SAMS RAM > 1 MiB, the actual SAMS bank goes into the word (>0345, say) and the bytes are swapped (>4503) before writing the word to a SAMS register.

 

...lee

Good point. I'm very rusty. So the best I can say is TF will work for up to 1MB on a 4MB card. I think. It's an easy fix to make it work with 4MB cards. Assuming I have enough bytes free ?

  • Thanks 2
Link to comment
Share on other sites

  • 2 years later...

I am revisiting code for a simple, non-destructive SAMS detection routine.  The Horizon RAMdisk configuration program (CFG) tests for SAMS but it gets tripped up if a previous program modified the mapped pages to something besides the default.  Since SAMS doesn't map memory into the DSR space >4000-5FFF, the new routine reads/writes the corresponding register and if the value doesn't change, I assume SAMs is not present.  Will this routine pose any problems for the larger capacity cards or general usage? 

 

; Non-destructive simple test for SAMS
;
; Copy mapper value for >4000-4FFF bank,
; modify it and if mapper register changes, assume SAMS
; Caller's R0 is modified. 0=no sams, <>0 SAMS
;
H0101  data >0101
SAMSDT DATA PLAYWS,$+2
       clr    @0(R13)
       li    r12,>1E00
       sbo 0
       mov    @>4008,R2      ;save whatever was in the mapper for >4000-4fff
       a      @H0101,@>4008  ;change the value    
       c      r2,@>4008      ;is it still the same? 
       jeq    noams          ;yes. can't be SAMS
       seto   @0(R13)        ;no, assume SAMS
       mov    r2,@>4008      ;restore, for futureproofing
noams  sbz 0 
       rtwp

 

 

Link to comment
Share on other sites

5 hours ago, apersson850 said:

Is there any specific advantage with using CLR @0(R13) and SETO @0(R13) compared to smaller and quicker CLR *R13 and SETO *R13?

None from an execution perspective. It's just an old habit of mine for readability.  When a routine passes info between multiple registers, my eye catches the "@xx(R13)" and helps me to not miss R0 along with other register passing. If I was concerned about space or speed, I would use the *R13 approach or forgo the entire routine and its workspace. 

  • Like 3
Link to comment
Share on other sites

1 hour ago, InsaneMultitasker said:

When a routine passes info between multiple registers, my eye catches the "@xx(R13)" and helps me to not miss R0 along with other register passing. 

That's a good reason. I also see a lot of TI source code that does R2*2(R13)

 

It seems that *R13 would be an easy optimization for an assembler to make.  

Link to comment
Share on other sites

4 hours ago, FarmerPotato said:

That's a good reason. I also see a lot of TI source code that does R2*2(R13).

But there the base address isn't zero, so i does have a meaning. It was the use of the @0(R13) I was curious about, since I could only see disadvantages. Except for the uniform approach, if you compare to accesses like @4(R13) to access register 2. Writing @R2*2(R13) has no execution penalty, since the assembler will make it @4(R13).

 

@FarmerPotato I for sure would not like an assembler to optimize my code. If I don't do it myself it's for a reason.

  • Like 2
Link to comment
Share on other sites

18 hours ago, apersson850 said:

 

 

@FarmerPotato I for sure would not like an assembler to optimize my code. If I don't do it myself it's for a reason.

I agree with what you said. Automatic optimization would disturb me, if I looked at a dis-assembly in debug. (Though I mostly rely on List files.) Especially if it was a timed loop and you don't want it to get faster. 

There are a few optimizations that Ralph's xas99 can do. They can save a few bytes. Nice to know they are there,  when every byte matters. (Things like:

Replace B with JMP

LI R2,-1  with SETO

Share constants )

 

  • Like 2
Link to comment
Share on other sites

RXB was first to support AMS when it was introduced that later became SAMS as I was given a AMS 64K card when it was first shown I first upgraded it to 128K.

To make it work loaded a 12 byte Assembly code from GPL into Scratch Pad RAM to run the routines.

By changing only 4 bytes I could Read/Write/Map/Turn on or off the card and load values.

Bonus was as it was in Scratch Pad and GPL no worries about crashing system by over writing the control program.

 

This is the main issue using the SAMS is where to put the controls that will not be overwritten or changed.

  • Like 2
Link to comment
Share on other sites

20 hours ago, FarmerPotato said:

I agree with what you said. Automatic optimization would disturb me, if I looked at a dis-assembly in debug.

It's very different with a compiler, where you normally don't know exactly what kind of code will be generated anyway. There I don't mind if the compiler will replace a := a+1 with code that's equivalent to inc(a), since it's equivalent and I can't make another use of the constant 1 anyway.

 

Going back to paged memory, I've found that the tactics I used way back, with the TI programmable 59 calculator, works for the 99 too. If I have extra memory (and I do, in my own console), it works fine if it's paged and I have a way to make sure things can stay within a page.

Say I have four pages, each 8 kbytes, of memory expansion instead of the normal 32 kbytes. Assuming assembly programming so I can control everything, then I can run a main program with its global data in one page, have additional data paged in another and call different subroutines in a third. when the call is done I need to keep track of which subroutine page is currently loaded in the subroutine page and switch to a different one if it's too old.

  • Like 2
Link to comment
Share on other sites

On 9/11/2023 at 8:52 AM, InsaneMultitasker said:

"@xx(R13)" ... helps me to not miss R0 along with other register passing. 

I looked through some TI source code and (longtime TI-990 engineer) Dave Pitts' C runtime for 990. It is full of "@R1*2(R13)" type addressing modes. But no "@0(R13)".  It seems like an unspoken rule that R0 shall not be used for parameter passing!  I did not find any *R13 either. 

  • Like 4
Link to comment
Share on other sites

3 hours ago, FarmerPotato said:

I looked through some TI source code and (longtime TI-990 engineer) Dave Pitts' C runtime for 990. It is full of "@R1*2(R13)" type addressing modes. But no "@0(R13)".  It seems like an unspoken rule that R0 shall not be used for parameter passing!  I did not find any *R13 either. 

I've seen various DSR routines and in particular, MDOS, pass error codes and other values via R0.  The "@Rxx*2(R13)" construct is a nice, clear alternative. 

  • Like 3
Link to comment
Share on other sites

To the benefit of those people who aren't seasoned assembly programmers we should perhaps add that the address @Rxx*2(R13) works because the CPU doesn't want to see instructions like INC R4, but really wants INC 4. To make it more readable, the assembler program knows to replace R4 by 4 at assembly time.

In this case, since R13 in the subprogram's workspace is a pointer to R0 in the caller's workspace, we use the symbolic indexed addressing mode in reverse. We let the index be the main address and the symbolic be the index. To reach the caller's R0 we can simply use *R13, but to reach the fourth register (R4) we need to index four registers down. But @4(R13) doesn't work, since each register is two bytes long. So @4*2(R13) works, and can be written as @R4*2(R13). Note that there's no speed penalty when executing @R4*2(R13), since the assembler will do the conversion at assembly time. At execution time the CPU will see @8(R13).

 

When discussing readability for assembly programs, let's also mention that it's sometimes wise to use names for registers, instead of just Rxx. If you need a stack pointer and a frame pointer, you can write

SP    EQU 10

FRAMEP EQU 9

The you can pop the stack by a MOV *SP+,R2 and add the tenth variable in your data frame to the value currently at the top of the stack by A @10*2(FRAMEP),*SP.

 

Don't be afraid of using complicated instructions! The TMS 9900 architecture favors using fewer instructions due to using complex address calculations over a larger number of simpler instructions to accomplish the same thing.

Edited by apersson850
  • Like 9
  • Thanks 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...