inline assembly for "c" Simple Tools Toggle function translation

ShawnaShawna Posts: 472
edited 2020-02-02 - 15:41:30 in Propeller 1
I am trying to convert some basic C code to inline assembly. I am using simpleIDE for my C programming. I realize that there are some programs that will do this but I have not found the courage to leave simpleIDE yet or the simple tools library.

I am trying to convert the simpletools toggle function into inline assembly. This should be a trivial task but I am having problems with it.

The C toggle code is.
unsigned int toggle(int pin)                  // toggle function definition
{
  int mask = 1 << pin;
  OUTA ^= mask;
  DIRA |= mask;
  return (OUTA >> pin) & 1;
}

I believe I have the OUTA and DIRA working but I can't figure out the Shift Left portion. I am ditching the return portion.

Here is one of my attempts at the shift left portion.
#include "simpletools.h"                      

int main()                                    
{
  int mask = 1;
  int pin = 3;

  printi("mask = %d ", mask); 

   __asm__ volatile (  
  "shl %[mask],%[pin]\n\t"  
  
  :/*outputs (+inputs)*/ 
    [mask] "=r" (mask)  
  :/*inputs */ 
    [pin] "r" (pin)    
  );

  printi("mask = %d ", mask); 
}

Here are the values for the mask variable at the last printi command based upon initial pin values.

pin = 0 mask = 0
pin = 1 mask = 2
pin = 2 mask = 8
pin = 3 mask = 24
pin = 4 mask = 64

I am not sure what i am doing wrong.

My only references for this are the propeller manual and this link.
https://sites.google.com/site/propellergcc/documentation/tutorials/inline-asm-basics

Thanks
Shawn A

Comments

  • A couple of things.

    In the project manager window you can right click on your file and in the drop down box is show assemble. This is a good way to see the generated assembly code although very ugly to read.

    Here is my attempt at your code:
    unsigned int toggle1(int);
    unsigned int toggle2(int);
    
    int main()
    {
      toggle1(0);
      toggle2(1);
      
      while(1)
      {
        pause(1000);
        
      }  
    }
    
    unsigned int toggle1(int pin)
    {
      int mask = 1 << pin;
      
      OUTA ^= mask;
      DIRA |= mask;
      return (OUTA >> pin) & 1;
    }
    
    unsigned int toggle2(int pin)
    {
      int mask;
      
      __asm__ volatile (
      "   mov %[_mask], #1        \n\t"
      "   shl %[_mask], %[_pin]   \n\t"
      "   xor outa, %[_mask]      \n\t"
      "   or  dira, %[_mask]      \n\t"
      "   mov %[_mask], outa      \n\t"
      "   shr %[_mask], %[_pin]   \n\t"
      "   and %[_pin], #1         \n\t"
          :[_mask] "+r" (mask),
           [_pin] "+r" (pin)
        );
      
      return pin;
    }
    

    You will notice that r0-r15 are general purpose registers that are used to pass values back and forth and are used for calculations.
    So in standard C code they use the stack and push these values on the stack and these values are then accessed right off the stack. Not the case here. If you pass 5 values they will be passed in r0 - r4 and then the returned value will be in r0.

    Mike
  • ShawnaShawna Posts: 472
    edited 2020-02-02 - 13:36:54
    Thanks for the help Mike!

    Your example works to toggle a pin. I had to modify the return portion of your code, it was always returning a 1. I know I said I was going to ditch that part but......... anyways.

    To make the function return the right value I modified these 2 lines.

    Original
    "   and %[_pin], #1         \n\t"
    
    return pin;
    

    Modified
    "   and %[_mask], #1         \n\t"
    
    return mask;
    

    The pin number will not change, but the OUTA Reg will change. So we want to MOV OUTA into Mask, SHR Mask with Pin and then AND Mask with 1. And finally Return Mask to show status of the pin output.
    Edited 2-2-20

    iseries wrote: »
    In the project manager window you can right click on your file and in the drop down box is show assemble. This is a good way to see the generated assembly code although very ugly to read.

    I have tried this but it is extremely hard to understand.


    I noticed that you added an underscore to the first portion of your variables during there declaration in the Assembly code. Is this necessary?
    :[_mask] "+r" (mask),
     [_pin] "+r" (pin)
    

    I kind of like it, it makes the Assembly a little easier to read.


    Shawn A
  • If you're at the point of doing inline assembly, I strongly encourage you to step away from the Simple library. That doesn't have to all at once - it can and probably should be done in baby steps - but as you do, don't feel burdened by the same API that Simple uses.

    By this, what I really mean is: don't use values 0-31 or 1-32 to address pins, but instead, just use the actual bit masks. Define an enum or use a bunch of #define's and set the values to the appropriate bit masks. Then each of your pin functions are one assembly instruction each.
Sign In or Register to comment.