Jump to content
gregallenwarner

SAMS usage in Assembly

Recommended Posts

1. two different SAMS "windows" in your RAM space, switch in source and destination SAMS pages and copy from one to the other.

yeah, that's what I'm doing, I'm using unpaged >E000->EFFF to write temporary data to and read from.

I thought about using 4K of supercart space, but I think it's slower from what I remember hearing a while back, but I have the availability in >E000. So I'll continue with that until I start to eat that space with program code I suppose.

Unless I dabble into another Sam's page. Which I don't feel comfortable doing yet.

Ill watch my program length, even though I watch it anyway, but I'll be cautiously alert.

Writing and reading from disk, nahh 

Ill be ok with this.

And right now my program for doing all this Sam's paging is AORG at 6000 so I'll be watching that I don't go over 4k in that as well, I don't think I'll get 4K of code built to do this at all.

Again, I didn't use supercart space for my buffer because I heard it was slower and I really didn't know how slow or if was really a big deal, but I went ahead and coded as if it were a slow area. But again, does it matter now, since my code is actually in >6000 anyway..so duh.. hahaha

 

Thx

 

 

Edited by GDMike

Share this post


Link to post
Share on other sites
3 hours ago, Lee Stewart said:

Yeah, BLWP is slower than BL is slower than inline. Of course, inline code takes the most space.

True, but if you need to start saving data from registers, when you do a BL to a subroutine, or even if you run inline, for that matter, then a BLWP accomplishes both the subroutine call and the register bank switch at the same time. RTWP also restores the status register, a fact you can take advantage of to send a boolean parameter back to the calling program.

 

Like this stub, to select a bank number given by R0, and then getting the Equal bit set if it was successful.

LI   R0,desired_bank_number
BLWP @select_bank
JNE  bank_select_failed

 

  • Like 1

Share this post


Link to post
Share on other sites

Edit. Nope, this didn't work like I thought.

-------

Hmm, to get to my anybank, I just throw a number in r6 and increment to it in a loop and jump out, I have an ADPG routine in the middle that adds 1 to the existing bank number. 

 

Edited by GDMike

Share this post


Link to post
Share on other sites
2 hours ago, apersson850 said:

RTWP also restores the status register, a fact you can take advantage of to send a boolean parameter back to the calling program.

 

Same thing** happens with any branch instruction, only faster. RTWP is the only one that restores status ((along with 2 other registers). The other returns leave status alone, making it possible to test it upon return. The only thing that would screw that up with a BL or B instruction is restoring a saved return. That is one reason I save a second level return to a free register and return by branching through that register:

       BL   @SUBRTN
       JNE  RPTERR
       ...
RPTERR <handle error>
       ...
SUBRTN MOV  R11,R7 <---save return because we might trash it with another BL
       <do stuff>
       B    *R7    <---	return through “return saved” register

Of course, if a register is unavailable, you would need to do time-consuming things to preserve status. At that point the BLWP=RTWP mechanism definitely makes more sense.

—————

** Well, not exactly per your comment. You would not be able to pass back anything else but the actual status of the last instruction changing the status register.

 

...lee

Edited by Lee Stewart
correction
  • Like 1

Share this post


Link to post
Share on other sites

I find it's really hard make big performance differences with the 9900 in the nestable sub-routine area.

If you build a little stack it takes ~28 clocks to push R11 onto a stack and 12 to BL (no wait-state comparisons here) 

So thats 30 and another 12 to return so total overhead is 42.

 

BLWP/RTWP is  26+14= 40 :( 

If you have to pass any data back and forth to and from different workspaces you lose more time, where as pushing R11 lets you share registers.

Of course if you need to push a few registers with a stack model the 9900 will kill you. 

You really have to work it through for every situation or just bite the bullet and take the penalty in exchange for a consistent calling convention.

 

It reminds me of a song my grandfather sang after a suitable number of drinks. "Gone are the days when free lunches came with beer..." :) 

  • Like 2
  • Haha 1

Share this post


Link to post
Share on other sites
10 hours ago, GDMike said:

1. two different SAMS "windows" in your RAM space, switch in source and destination SAMS pages and copy from one to the other.

yeah, that's what I'm doing, I'm using unpaged >E000->EFFF to write temporary data to and read from.

 

 

 

I think this is my option 2 because you are copying SAMS data from a window in CPU RAM (?) , to "unpaged" >E000..>EFFF.

Am I understanding what you are doing correctly?

 

Option1 means you have 2 - 4K windows say at >3000   and >E000.  You set the source SAMS bank to say >3000 , the destination bank to >E000 and copy 4KBYTES  from >3000 to >E000. 

That is a SAMS-to-SAMS transfer.

Share this post


Link to post
Share on other sites

Nahh.. Change of plans...I'm using 8K in the supercart for buffer space afterall. 

I didn't have enough ram for straight 4K. And my program is reaching >E000 already as I moved onward.  But this is working, using sc ram.

Edited by GDMike

Share this post


Link to post
Share on other sites
10 hours ago, Lee Stewart said:

The other returns leave status alone, making it possible to test it upon return.

The status of the caller is stored in the subprogram's R15. What I meant is that the called procedure can modify R15 before returning. Thus you can set/reset a bit in that regisiter, and after RTWP it will be the status for the caller. So by modifying the saved status on purpose, you can kind of return a boolean to the caller, making the procedure a function instead.

Since you can access the caller's registers via R13 (MOV @6(R13),R0 will fetch what's in the caller's R3, for example), parameter passing is reasonably efficient. You can access inline data via R14 (MOV *R14+,R0 will fetch data in the word after the BLWP instruction), so that's just as easy as it is with a BL instruction.

Remember that adding more complexity, like advanced addressing modes, to one instruction is usually more efficient than adding more instructions to solve the problem in a different way. Both speed- and memory-wise. If you look at the timing of BLWP, you'll find it's almost identical to one BL and one MOV. So if you, as a precaution, always save the return register (R11) somewhere else, when entering a subroutine called with BL, then you could just as well use BLWP and have a register set on your own. If you then have to do just one single instruction extra inside the BL-subroutine, bacause of the shared registers, you've neutralized the advantage that B *R11 is faster than RTWP. The difference is just a single instruction, so it's enough that you don't have a register free to move the return address too, but have to first MOV R11,@SAVRTN, then later MOV @SAVRTN,R11 and B *R11. If you have to do that, then BLWP - RTWP is just as fast as a call with BL, but much more flexible.

 

What you often lose on a standard machine is the ability to use fast RAM for the registers. Personally, I don't have to bother, since my console has fast RAM everywhere, from >0000 to >FFFF, if I want it to. Also, if you write a program that's assembly only, you can usually at least allocate a couple of register sets in the fast RAM, not only one.

When I compare the speed of my machine to a standard one, and have both code and registers in the 32 K RAM expansion, my machine is slightly more than twice as fast.

  • Like 1
  • Thanks 2

Share this post


Link to post
Share on other sites

While all of this, is wonderful and true...

BuLlWhiP needs/uses-up 3 words to call and 3 registers to return...  Requires planning of a vector/vector table.

 

I can only recall using it once.
Later I ended up re-writing that code and worked around it instead.:ponder:

  • Thanks 1

Share this post


Link to post
Share on other sites

Yes, you have to set up the call vector (two words). The BLWP call itself consumes as much space as a BL instruction. It also requires 16 words for its own workspace, out of which three are used for parameter passing, return linkage and status. If you are very tight on memory, that could be a drawback.

But the general opinion seems to be that it's slow. Which it is, if you look at one single instruction, but may not be, if you widen your view to see what it actually accomplishes. One of the bigger advantages is that it's pretty easy to make it independent of the caller, which is a huge advantage if you are building software libraries, with functions that are supposed to be useful from different programs. Page switching expanded memory seems to be a very likely candidate for such a library, in my opinion.

That's what I wanted to point out.

  • Like 4

Share this post


Link to post
Share on other sites

The other thing that workspaces are very good for is context switching. 

If you initialize a group of workspaces as if they were called by BLWP, in a circle, ( A calls B, B calls C, C calls A) you can change tasks with just RTWP.  That's is pretty cool!.

 

 

  • Like 2

Share this post


Link to post
Share on other sites

Yes, I used the same philosophy when I wrote a scheduler for a multi-tasking program. The scheduler calls a task by setting up the WS and then RTWP, so that it "calls" a task by "returning" to something it kind of never left...

  • Like 1

Share this post


Link to post
Share on other sites

 

   STILL STUCK in sams >3000 (bank 1)

 

still grappling with SAMs memory card.

I understand how to turn the card on/off.

And how to map, for example the

>3000->3FFF area. 

 

I can write data to that 4K area and I can read it, turn off the mapper and revert back.

And turn the mapper on and my data is there.

 

But my question is, how can I add another bank of >3000->3FFF

As bank 2 ? And again, and so on.and still be able to go back and forth from 1-240?

If this is somewhere, I'd sure like to know because I've seen examples and docs, and I'm not seeing how to do this.

 

Note:

I was confused and thought that adding a "1" to the MSB of  >4006 would give me another bank of >3000->3FFF, But I guess I'm way off in that!

Sorry if this was discussed previously, as I've not seen it. 

 

Thx all.

 

 

Share this post


Link to post
Share on other sites

Using the register at >4006 you can select safely any SAMS page from >10 .. >FF

 

So that means you can have 240 different 4K blocks living in your memory at >3000, but only one at a time.

 

To select SAMS block >10   put the number into >4006  with the bytes reversed, so >10 must be stored as >1000

>11 must be stored as >1100 

The code would look something like this: 

 

(Maybe you have not turned on the mapper?)

 

NOT TESTED!!!

**************************************************************
* To actually use the memory you turn on the "mapper"
**************************************************************
        LI R12,1E00   * set the SAMS card CRU address
        SBO 1         * turn on the mapper with CRU bit 1
* now the page in >4006 will appear in your memory at >3000..>3FFF

* setup to select a SAMS page to appear at >3000
        LI R0,>4006   * R0 will hold the SAMS control register
        LI R1,>1000   * R1 has the page in the low byte

        LI R12,1E00   * set the SAMS card CRU address
        SBO 0         * turn on the card (not the mapper)
        MOV R1,*R1    * put the data into SAMS register >4006
        SBZ 0         * turn off the card (mapper remains on)

* loop thru the banks down to zero
        LI R12,1E00   * set the SAMS card CRU address
        SBO 0         * turn on the card
        LI  R1, FF00
LOOP1   MOV R1,*R1    * put the data into SAMS register >4006
        AI  R1,-0100  * subtract 1 from the low byte!
        JNE LOOP1
        SBZ 0         * turn off the card





 

  • Like 2

Share this post


Link to post
Share on other sites
2 hours ago, GDMike said:

I was confused and thought that adding a "1" to the MSB of  >4006 would give me another bank of >3000->3FFF, But I guess I'm way off in that!

Sorry if this was discussed previously, as I've not seen it. 

Actually, This sounds to be, about right!

 

Though SAMS' functions are very simple ...I know first hand, that the explanations are anything but!

 

SAMS has 256 pages, >00 thru >FF.

 

The default BANK/PAGE that appears at >3000->3FFF, is BANK/PAGE >03(>4006=>0300).

 

The default for making "mapping changes" is "OFF"(CRU>1E00=0)(SBZ 0), NO CHANGES.

 

By turning the mapper ON(CRU>1E00=>01)(SBO 0). You can, both "see" and change the value at >4006, which in turn changes what BANK/PAGE appears at >3000->3FFF.

 

NOW, adding a "1" to the byte at >4006(not >4007), will change it's value from >0300, to >0400(>4006/7=>0400), which in turn will change what BANK/PAGE appears at >3000->3FFF, from BANK/PAGE >03, to >04.

 

Subtracting "1" from a mapper address, such as >4006, will bring you back to the preceeding BANK/PAGE(in this case >03).

 

This is "OK" to do, since BANK/PAGE >04 is by default mapped to >4000->4FFF, which is useless/nonfunctional!

 

However, it is possible to map the same BANK/PAGE to different (functional)BLOCKs of address ranges simultaneously.

 

So, for instance, if you change both >4006 and >4004 to >04, BANK/PAGE >04 will appear at both address ranges >3000->3FFF, and >2000->2FFF. Than making changes to either range of addresses will change the values in both ranges(mirror effect).

 

The defaualt MODE, seems to be MAPPING(CRU>1E02=1)(SBO 1). I would recommend to avoid changing this to TRANSPARENT(CRU>1E02=0)(SBZ 1), until you have mastered BANK/PAGE switching. As this adds yet another way to change, what appears where. Trying to figure out both methods, together, will likely add to any uncertainties. Ouch!

 

UHOH, I need a break now!:sleep:

  • Like 1
  • Haha 1

Share this post


Link to post
Share on other sites
1 hour ago, TheBF said:

Using the register at >4006 you can select safely any SAMS page from >10 .. >FF.  So that means you can have 240 different 4K blocks living in your memory at >3000, but only one at a time.

 

To select SAMS block >10   put the number into >4006  with the bytes reversed, so >10 must be stored as >1000, >11 must be stored as >1100 

The code would look something like this:      (Maybe you have not turned on the mapper?)    NOT TESTED!!!

Spoiler

**************************************************************
* To actually use the memory you turn on the "mapper"
**************************************************************
        LI R12,1E00   * set the SAMS card CRU address
        SBO 1         * turn on the mapper with CRU bit 1
* now the page in >4006 will appear in your memory at >3000..>3FFF

* setup to select a SAMS page to appear at >3000
        LI R0,>4006   * R0 will hold the SAMS control register
        LI R1,>1000   * R1 has the page in the low byte

        LI R12,1E00   * set the SAMS card CRU address
        SBO 0         * turn on the card (not the mapper)
        MOV R1,*R1    * put the data into SAMS register >4006
        SBZ 0         * turn off the card (mapper remains on)

* loop thru the banks down to zero
        LI R12,1E00   * set the SAMS card CRU address
        SBO 0         * turn on the card
        LI  R1, FF00
LOOP1   MOV R1,*R1    * put the data into SAMS register >4006
        AI  R1,-0100  * subtract 1 from the low byte!
        JNE LOOP1
        SBZ 0         * turn off the card

 

 

A couple of typos, I think. The two places you have

       MOV  R1, *R1

should be

       MOV  R1, *R0

 

Also, I am not sure I see the point of the loop. When it is done, SAMS page 0 will be visible at >3000 – >3FFF, which is probably not what you wanted.

 

...lee

  • Like 2

Share this post


Link to post
Share on other sites
1 hour ago, TheBF said:

 

AI R1,-0100 * subtract 1 from the low byte!

I counted five lines, including the one above, where there is a missing ">" in front of the hexadecimal value.  I know this is untested code so I'm only mentioning it because the one omission above would be the hardest to detect.

  • Like 2

Share this post


Link to post
Share on other sites
5 hours ago, Lee Stewart said:

A couple of typos, I think. The two places you have

       MOV  R1, *R1

should be

       MOV  R1, *R0

 

Also, I am not sure I see the point of the loop. When it is done, SAMS page 0 will be visible at >3000 – >3FFF, which is probably not what you wanted.

 

...lee

 Thank you for the correction.

 

Purpose is purely demonstration to show how GDMike could select different pages.

  • Like 2

Share this post


Link to post
Share on other sites
5 hours ago, InsaneMultitasker said:

I counted five lines, including the one above, where there is a missing ">" in front of the hexadecimal value.  I know this is untested code so I'm only mentioning it because the one omission above would be the hardest to detect.

You'd think I never use TI Assembler and you'd be correct.

  • Like 1

Share this post


Link to post
Share on other sites

"NOW, adding a "1" to the byte at >4006(not >4007), will change it's value from >0300, to >0400(>4006/7=>0400), which in turn will change what BANK/PAGE appears at >3000->3FFF, from BANK/PAGE >03, to >04".

Mapper on:

I believe this, above,  is what I've been doing.

And my data was always the same during my test of incrementing banks, and it's should not have been.

I purposely wrote to a loop and I turned off Sam's, turned on and looped to 1 then to 2 and finally 10 banks higher, and my data was always the same. So I powered off the card, console and got same results.

I'll paste my code in a while after getting kids to school. Thx so much, I knew I was doing this as it was supposed to work. Hmm

Maybe we can determine what is going on.

 

Edited by GDMike

Share this post


Link to post
Share on other sites

 

I Know there's a lot of information regarding how to use this card.

And the docs with example is good too, but it wasn't really explaining in a "simplistic" way, as the author just assumed ti artist was a good example of using odd/even frames and the comment saying, "clear as mud" was right on.

Pretty easy to turn on/off the card, and mapping, but I ended up stuck without moving the bank # above 0

 

Here's what ive been working with in my test

 

after making the bank a high number, as in the last section of the program, Im still getting the same data presented to me, as if my "ADPG" is not really incrementing a Bank.

 

***** turn off SAMS Mapper
SAMOFF  MOV R11,@SAVRTN
     LI R12,>1E00
     SBZ 0
     SBZ 1
     MOV @SAVRTN,R11
     RT

***** turn on Mapper and set for >3000->3FFF

SAMON    MOV  R11,@SAVRTN
    LI   R12,>1E00
    SBO  0
    LI   R1,>0300
    LI   R3,>4006
    MOV  R1,*R3+     * not sure if the "plus" is actually needed
    SBZ  0
    MOV @SAVRTN,R11
    RT


**** set to BANK 1

SBZ    MOV  R11,@SAVRTN
    LI   R12,>1E00
    SBO  0
    LI   R3,>4006
    LI   R1,>0100
    MOVB R1,*R3
        SBZ  0          * not sure this is needed
    MOV  @SAVRTN,R11
    RT

***** ADD A BANK
    
ADPG    MOV  R11,@SAVRTN
    LI   R12,>1E00
    SBO  0
    LI   R3,>4006
    MOV  *R3,R1
    AI   R1,>0100
    MOV  R1,*R3
    SBZ  0                  * not sure if this is needed

    RT

***************************
PROGRAM

TEST    BL    @SAMON
    BL      @SBZ
    CLR     R5
    CLR     R4
INC1    BL    @ADPG
    INC    R5
    CI      R5,10
    JLT     INC1
    LI    R3,>3000
    LI    R1,>4142
INC2    MOV    R1,*R3+
    INC    R4
    CI    R4,>2046     * this may NOT be accurate. but its testing
    JLT    INC2

    BL    @SAMOFF
    BL    @SAMON
    BL    @SBZ
    CLR    R4
    CLR    R5
    
INC3    BL    @ADPG
    INC    R5
    CI    R5,12
    JLT    INC3    
    LI    R0,0
    LI    R3,>3000
INC4    MOV    *R3+,R1
    BLWP    @VSBW
    INC    R0
    CI    R0,960
    JLT    INC4    
    BL    @SAMOFF
    B     @STOP

**********************
STOP    LIMI 2
    LIMI 0
    JMP  STOP

 

Edited by GDMike

Share this post


Link to post
Share on other sites

"Using the register at >4006 you can select safely any SAMS page from >10 .. >FF"

"So that means you can have 240 different 4K blocks living in your memory at >3000, but only one at a time".

 

Well, ok from 10-240. I didn't really know if that system 32k came in at the top or bottom, so now I know it's at the bottom side. So I'll need to make bank 1 start at 10 instead of 1. When I'm creating banks, Right?

 

 

 

 

Share this post


Link to post
Share on other sites
16 minutes ago, GDMike said:

"Using the register at >4006 you can select safely any SAMS page from >10 .. >FF"

"So that means you can have 240 different 4K blocks living in your memory at >3000, but only one at a time".

 

Well, ok from 10-240. I didn't really know if that system 32k came in at the top or bottom, so now I know it's at the bottom side. So I'll need to make bank 1 start at 10 instead of 1. When I'm creating banks, Right?

Actually from HEX 10 ... HEX FF   which is  DECIMAL 16 to 255

The lower 64K bytes of SAMS , pages 0 to 15, are the default RAM pages when you start up the computer. In other words that's your 32K expansion RAM.

That's why I just avoid them.  It's not mandatory, it's just simpler.

So start at page HEX 10  ( decimal 16) and you never step on something unintended.

 

"So I'll need to make bank 1 start at 10 instead of 1. When I'm creating banks, Right?"

I do.

 

 

 

  • Like 1

Share this post


Link to post
Share on other sites
26 minutes ago, GDMike said:

"Using the register at >4006 you can select safely any SAMS page from >10 .. >FF"

"So that means you can have 240 different 4K blocks living in your memory at >3000, but only one at a time".

 

Well, ok from 10-240. I didn't really know if that system 32k came in at the top or bottom, so now I know it's at the bottom side. So I'll need to make bank 1 start at 10 instead of 1. When I'm creating banks, Right?

You should not assume anything about the state that the SAMS starts up in. If you want to start with bank 2 mapping to >2000, bank 3 mapping to >3000 and so on that's up to you. If you don't set up the start up stage yourself you will get in trouble.

Edited by Asmusr
  • Like 1

Share this post


Link to post
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.

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