Shop OBEX P1 Docs P2 Docs Learn Events
SX/B: Considerations for Maximal RAM Utilization — Parallax Forums

SX/B: Considerations for Maximal RAM Utilization

Sparks-R-FunSparks-R-Fun Posts: 388
edited 2007-03-30 17:04 in General Discussion
It seems like I should probably know the answer to this question but I have been unable to find a concise explanation. Can someone explain to me, “Which SX/B operations can be performed with array elements and which ones require general purpose variables for use?” It seems I have run out of general purpose variables in my SX/B program while trying to add Bean's background UART code.

In trying to understand the difference myself between using array variables vs. general purpose variables I came across several threads discussing Bank Switching. The most helpful thread I was able to find was this one discussing an SX/B RAM Banking Scheme. It made it sound like I can create a variable array along with some aliases then issue a Bank (something) statement before I attempt to use them followed by a Bank 0 statement when I am done. Is this correct? If so, what happens if an interrupt occurs and/or I use Bank statements within the interrupt? What precautions do I need to take to insure each code segment is always looking at the correct memory bank?

My long-term goal is to understand how to make the best use of the SX RAM space even beyond the general purpose variable space that (I think) resides in Bank 1. My short term goal is to add Bean's interrupt based UART to my existing program given that I have no more general purpose variables left!

I do not know how to tell which (if any) of my existing variables can be moved to an array. There have been a few discussions before mentioning a few specific commands but if this is plainly stated somewhere for all the commands I have somehow managed to overlook it.

Thanks in advance for the help that I know will come. smile.gif

- Sparks


P.S. The following threads seemed relevant to this topic:
Simultaneous serial send and receive using only 1 interrupt routine.
SX/B Compiler Variables Limits
SX/B RAM Banking Scheme
Variable Space & Lookup Table
More than 24 VAR BYTE declarations in SX/B

Comments

  • BeanBean Posts: 8,129
    edited 2007-03-21 14:58
    Sparks,
    In general array elements cannot be used as the control variable in a "FOR...NEXT" loop. Or as the index to an array.
    There may be a couple other places and/or commands that don't allow them, but that should be rare.

    You can also use array elements to save and restore the value of·normal·variables.
    save(0) = idx
    FOR idx = 1 TO 10
      myArray(idx) = GetValue
    NEXT
    idx = save(0)
    
    


    Bean.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    "Educate your children to self-control, to the habit of holding passion and prejudice and evil tendencies subject to an upright and reasoning will, and you have done much to abolish misery from their future and crimes from society"

    Benjamin Franklin
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Cheap used 4-digit LED display with driver IC·www.hc4led.com
    Low power SD Data Logger www.sddatalogger.com
    SX-Video Display Modules www.sxvm.com
    Coming soon! Propeller based OSD module www.hittconsulting.com
    ·
  • JonnyMacJonnyMac Posts: 9,214
    edited 2007-03-21 15:34
    If you're going to do ISR-based serial I think it best to use assembly and switch banks manually; the code is very trim and will consume less time in the ISR. SX/B wants to point to bank 0 for normal variables so by putting your serial variables into an array (which forces them into something beyond bank 0) you end up preserving your "normal" variable space. I lifted the serial routines from Al Williams' book and use them all the time in my SX/B programs when I need background serial. I've attached my UART VP work file that you can experiment with. Just set your ISR to 1/4 the fastest bit time you expect. The program that's attached has bit settings for 2400 to 57.6K baud.

    Note, too, that flags and tix variables are assigned first -- there's a reason for this: If you look at the list file you'll see that the first three bytes of an SX28 program will make it into the global space ($00-$0F) so this means these variables can be accessed without concern of the current bank setting.
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-03-21 18:19
    Ok. Good stuff!

    I'll watch for FOR... NEXT loops and indexes into arrays. I was worried about IF... THEN, DO... WHILE and other comparison statements. If those have no difficulties using array variables I should be able to reallocate plenty of space!

    Q: Is it safe to assume that the compiler will generate an error if I ever encounter one of those rare “other places and/or commands?”


    I think I understand JonnyMac's comments about the first three SX/B variables being globally accessible on the SX28. But just to see if I have correctly grasped this let me ask about the 'tix' variable. In the example program given, can the variable 'tix' be placed into the serial array without affecting the program operation? I ask because it seems to me that it could. (My thinking is that since the start of the ISR and the MS_WAIT routines are written in SX/B rather than assembly code they would still be able to find and access the 'tix' variable even if it was moved into the serial array.) If it can not be placed in the serial array then I still have not understood something.

    Actually, aside from assembly language routines, FOR... NEXT loops and indexes into arrays, do I even need to worry about bank switching? It seems like SX/B is automatically handling most of that for me.

    Finally, in the RX_BYTE subroutine provided by JonnyMac it seems to me that a 'BANK serial' statement has been left out but should immediately follow the 'ASM' statement.

    It now seems that I am not certain if I am confused or not... which must mean that I still am, at least slightly.

    - Sparks
  • BeanBean Posts: 8,129
    edited 2007-03-21 18:31
    Yes, the compiler should give you an "invalid parameter" error if you try to use an array element where it's not allowed.

    I wouldn't count on those first three variables being in global memory. The beta version of the compiler uses at least one of these (depending on if you use a certain feature). Also the beta version does allow an array element as a "FOR...NEXT" loop.

    Bean.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    "Educate your children to self-control, to the habit of holding passion and prejudice and evil tendencies subject to an upright and reasoning will, and you have done much to abolish misery from their future and crimes from society"

    Benjamin Franklin
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Cheap used 4-digit LED display with driver IC·www.hc4led.com
    Low power SD Data Logger www.sddatalogger.com
    SX-Video Display Modules www.sxvm.com
    Coming soon! Propeller based OSD module www.hittconsulting.com
    ·
  • JonnyMacJonnyMac Posts: 9,214
    edited 2007-03-21 19:16
    Bean is right, you shouldn't count on those variables being global. Since the NOPRESERVE option is used instead of NOCODE there is a BANK 0 instruction inserted at the head of the ISR so this works fine for the program as it is.

    Yes, you can move the tix timer to the serial bank, but there are implications: you can't declare a word in the array so you have to declare two bytes; tix_LSB and tix_MSB. Then update the top of the ISR like this:

    Check_Timer:
      ASM
        BANK serial
        CJA  tix_MSB, #0, Check_Timer_Done
        CJA  tix_LSB, #0, Check_Timer_Done
    
    Update_Timer:
        SUB  tix_LSB, #1
        SUBB tix_MSB, /C
    
    Check_Timer_Done:
        BANK 0
      ENDASM
    



    This replaces the SX/B code that was there (it's actually a small modification of the compiler output). Then you have to adjust the WAIT_MS subroutine:

    ' Use: WAIT_MS mSecs
    
    WAIT_MS:
      IF __PARAMCNT = 1 THEN
        tmpW1 = __PARAM1                            ' get byte parameter
      ELSE
        tmpW1 = __WPARAM12                          ' get word parameter
      ENDIF
    
      DO WHILE tmpW1 > 0
        tix_MSB = 0
        tix_LSB = 230
        
    MS_Hold:
        IF tix_LSB > 0 THEN MS_Hold                 ' is tix zero?
        IF tix_MSB > 0 THEN MS_Hold
        DEC tmpW1                                   ' yes 
      LOOP 
      RETURN
    



    This routine could be optimized so that you're only using a byte (for tix); the word was used so that you could create custom delays based on ISR ticks elsewhere in the program.
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-03-21 19:53
    Bean,
    Thanks for the warning that variable space might change with compiler versions.
    Ahhh... Dreaming of the beta version of SX/B! turn.gif *drools*

    JonnyMac,
    I see and understand now the changes required for moving 'tix' into an array. I totally overlooked the fact that it was a word variable! That would have kept me busy for a while.

    - Sparks
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-03-22 22:27
    It looks like I found found one of those rare instances where a command expects to see a general byte and not one that is part of an array.

    Using the following definitions:
    Temp1                    VAR BYTE        ' Common temporary storage variable.
    System            VAR    BYTE(16)
    SystemStatus            VAR    System(12)        ' Track various states of the System Status
      I2CAck                VAR    SystemStatus.2    ' I2C Acknowledgment flag
    


    The command
    I2CSend    SDA, Temp1, I2CAck        ' Send the address of the I2C device.
    


    Generates a Bit Variable Expected “I2CAck” error.

    Defining SystemStatus as a byte (as shown below) compiles cleanly.
    Temp1                    VAR BYTE        ' Common temporary storage variable.
    SystemStatus            VAR BYTE        ' Track various states of the System Status
      I2CAck                VAR    SystemStatus.2    ' I2C Acknowledgment flag
    


    This is not a problem I seek to have fixed as changing the variable definition offers a solution. I just wanted to document it add to the information in the thread.

    - Sparks
  • BeanBean Posts: 8,129
    edited 2007-03-22 22:42
    Sparks,
    I2CAck is called a "array element bit" and those are quite unique and NOT widely supported by commands.

    Bean.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    "Educate your children to self-control, to the habit of holding passion and prejudice and evil tendencies subject to an upright and reasoning will, and you have done much to abolish misery from their future and crimes from society"

    Benjamin Franklin
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Cheap used 4-digit LED display with driver IC·www.hc4led.com
    Low power SD Data Logger www.sddatalogger.com
    SX-Video Display Modules www.sxvm.com
    Coming soon! Propeller based OSD module www.hittconsulting.com
    ·
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-03-30 17:04
    I found another operator that does not accept a byte from an array: __RAM()
    I realize this falls under the “pointer into an array” category but I realized it only after I had a problem with it! So I wanted to document it in case it is not obvious to someone reading this thread later that you must also use a general-purpose variable with the __RAM() statement.

    Presently I am using the format
    GenPurpTempVar = ArrayVar
    __RAM(GenPurpTempVar) = Value
    

    as a simple workaround.


    - Sparks
Sign In or Register to comment.