Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
[sparc v9] need atomic operations in assemly help
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Gentoo on Sparc
View previous topic :: View next topic  
Author Message
goanuj
Tux's lil' helper
Tux's lil' helper


Joined: 13 Jul 2002
Posts: 125
Location: California

PostPosted: Thu Oct 16, 2003 7:27 am    Post subject: [sparc v9] need atomic operations in assemly help Reply with quote

Does anyone have any sample assembly for Sparc V9 atomic operations such as atomic increment, atomic decrement? I understand that these can be different for each memory model (RMO,PSO,TSO), I understand how to implement certain assembly instructions, however, I need to see some examples where people use atomic add and have actually tested it on a SMP machine. Anyone? :)

I need to make sure that our team is implementing our atomic operations properly. I have looked at linux kernel code, but the kernel's usage is quite different from what I want to implement.

For atomic increments, I would probably do something like this:
Code:
!
! atomic add in assembly
!
MEMBAR #StoreLoad

my exported "C" function would look like this
Code:
void atomicincrement(long *addr)
{
  ++(*addr);
   # force other processors to see it
}

Basically I just want to implement this in SparcV9 assembly. Has anyone done anything like this before?
Back to top
View user's profile Send private message
Ferris
Retired Dev
Retired Dev


Joined: 13 Jan 2003
Posts: 426
Location: N. Virginia (USA)

PostPosted: Thu Oct 16, 2003 3:29 pm    Post subject: Reply with quote

OK, here goes. Here is some assembly-in-C code which works on sparc-v9
SMP. (It is a direct steal from David Miller's kernel code found at
/usr/src/linux/arch/sparc64/lib/atomic.S, or wherever you keep your
kernel sources.)

This is a sample header file (and little demonstration) to include in anything
requiring the atomic operations.

Code:



/* ==Id: atomic.S,v 1.4 2001/11/18 00:12:56 davem Exp ==
 * atomic.S: These things are too big to do inline.
 *
 * Copyright (C) 1999 David S. Miller (davem@redhat.com)
 */
/* Recreated as
 * $Id: Atomic.h,v 1.9 2003/10/16 15:15:56 fmccor Exp $
 * for general use or as an example.
 *
 * Build with
 * gcc -mcpu=v9  -fomit-frame-pointer -O2 [...]
 *
 * (-and-, #define __DEFINE_ATOMIC_HERE__
 * in the module where you actually want them defined.)
 * ((go down a few lines for that check for the actual code for these))
 *
 *
 */

#ifndef _Atomic_h_
#define _Atomic_h_


typedef struct {volatile int counter;} atomic_t;
#define atomic_set(v,i) (((v)->counter) = i)
#define atomic_read(v)  ((v)->counter)
/*
  Do everything in our power to keep from inlining!!!
*/
extern int atomic_add(int, atomic_t*)              __attribute__ ((noinline)) ;
extern int atomic_sub(int, atomic_t*)              __attribute__ ((noinline)) ;
extern int atomic_exchange_and_add(atomic_t*, int) __attribute__ ((noinline)) ;


/*  Narrative:
 *  This is the linux kernel code for atomic add, atomic subtract on sparc-v9.
 *  They actually return the result of their operation.
 *
 *  The exchange_and_add is like add, except that it returns the original
 *  value of the counter (instead of the new one), and for some reason, ** THE
 *  ORDER OF ITS ARGUMENTS IS REVERSED! **
 *
 *  do {
 * A.   g5  <- value;
 * B.   g7  <- g5 [+/-] delta;
 * C.   if  (value == g5) swap(g7, value);
 * D.   } while (g5 != g7);     // g5 was original value, g7 is swapped from original value
 *                            // if they are not the same, someone changed the memory
 *                            // copy before the swap, so we start over with a new value
 * E.   Synchronize_memory_and_data_cache;
 * F.   return [value+delta | value - delta | value] depending on add/sub/exchange_add.
 *
 *  Notice that step -C.- is an indivisible operation, so everything is good coming
 *  out.  The entire operation can be retried of between -A.- and start of -C.- someone
 *  else changes the counter variable.  The point is that you get a -coherent- result
 *  (which is to say, you don't operate on a stale counter value, and so replace it
 *  with something wrong for everyone).  You might not be operating on the values
 *  at call.  To do that, put global Mutex around the call itself.
 *
 *  WARNINGS:
 *  Do NOT put these in a header file for inlining.  You will get bus errors,
 *  or the results will be wrong if you don't (get the bus errors).
 *  That's why we force the __attribute__ ((noinline)) in this header!
 *
 *  Do NOT use these on Sparc 2, 5, 10, 20 etc.  The instructions are
 *  sparc-version 9.
 *
 * These are written for sparc(v9)-linux-gcc.  I have no idea what they will do
 * with Solaris or with other compilers. (Logic will work, because that's what
 * the instructions do.  I cannot speak to other compilers, though.)
 *
 *
 *
 * --
 *  Ferris McCormick <fmccor@inforead.com>
 *  06.iii.03
 */

#ifdef __DEFINE_ATOMIC_HERE__

int
atomic_add(int i, atomic_t* v) {
    __asm__ __volatile__ (
"1:     lduw    [%o1], %g5\n"
"       add     %g5, %o0, %g7\n"
"       cas     [%o1], %g5, %g7\n"
"       cmp     %g5, %g7\n"
"       bne,pn  %icc, 1b\n"
"       membar  #StoreLoad | #StoreStore\n"
"       retl\n"
"       add     %g7, %o0, %o0\n"
        );
    return; /* Not Reached */
}

int
atomic_sub(int i, atomic_t *v) {
    __asm__ __volatile__ (
"1:     lduw    [%o1], %g5\n"
"       sub     %g5, %o0, %g7\n"
"       cas     [%o1], %g5, %g7\n"
"       cmp     %g5, %g7\n"
"       bne,pn  %icc, 1b\n"
"        membar #StoreLoad | #StoreStore\n"
"       retl\n"
"        sub    %g7, %o0, %o0\n"
        );
  return; /* Not Reached */
}

int
atomic_exchange_and_add(atomic_t *v, int i) {
        __asm__ __volatile__ (
"1:     lduw    [%o0], %g5\n"
"       add     %g5, %o1, %g7\n"
"       cas     [%o0], %g5, %g7\n"
"       cmp     %g5, %g7\n"
"       bne,pn  %icc, 1b\n"
"       membar  #StoreLoad | #StoreStore\n"
"       retl\n"
"       mov     %g7, %o0\n"
        );
        return; /* Not Reached */
}

#endif /* __DEFINE_ATOMIC_HERE__ */

#endif /* _Atomic_h_ */




And, here is a little program to show how it is used.

Code:

#define __DEFINE_ATOMIC_HERE__
#include "Atomic.h"
#include <stdio.h>
int
main(int argc, char * argv[]) {
    atomic_t* a_t;
    int a_t_before, a_t_after;
    a_t = (atomic_t*) malloc(sizeof(atomic_t));
    if(a_t == NULL) {
        fprintf(stderr,"Can't allocate %d bytes for atomic_t\n", sizeof(atomic_t));
        return (-1);
    }
    atomic_set(a_t, 43);
    a_t_before = atomic_exchange_and_add(a_t, (-4));
    a_t_after  = atomic_read(a_t);
    printf("Set a_t=43, exchange-add(-4) returns %d, and atomic_item now is %d\n",
           a_t_before, a_t_after);
    return 0;
}


Hope this gives you an idea.
Back to top
View user's profile Send private message
goanuj
Tux's lil' helper
Tux's lil' helper


Joined: 13 Jul 2002
Posts: 125
Location: California

PostPosted: Thu Oct 16, 2003 11:28 pm    Post subject: thanks! Reply with quote

Thanks for you help,

I was confused because I was looking at the wrong file:

arch/sparc/lib/atomic.S

Can you clue me onto the difference between sparc and sparc64, is 'sparc64' just the 64 bit extension of sparc? or are they fundamentally different architectures?

Also, I am assuming most current machines are sparc64 right?

And do you have familiarity with the Solaris compiler?

CC - Sun WorkShop C++ Compiler 5.0

That is what I have to use to compile my assembly! I am not sure how to compile assembly on Solaris, I have to read up on fbe
Back to top
View user's profile Send private message
Ferris
Retired Dev
Retired Dev


Joined: 13 Jan 2003
Posts: 426
Location: N. Virginia (USA)

PostPosted: Fri Oct 17, 2003 12:13 pm    Post subject: Reply with quote

For our purposes, I think we can use sparc64, UltraSparc, and -v9
interchangeably. It is a proper superset of -v8:

  • The very short answer is that sparc-v9 (sparc64) is an extension of sparc-v8. In
    your example, -v9 has the compare-and-swap atomic instruction (cas) which
    does exactly what you want. -v8 (SS20, SS10, etc) does not. Hence,
    the two different kernel implementations.

    Anything built for -v8 should run on -v9, but the converse is not the case. (Case in point: by accident I
    forced a -v9 program to try to run on a SS20, and it took several reboots
    to get the hardware to recover completely. Among other things, it killed
    the lance ethernet card.)

    The compiler's -mcpu=... flag controls which architecture you are
    building for, and to get at the atomic instructions, you must specify
    "-mcpu=v9" or (equivalently) "-mcpu=ultrasparc".

  • The longer answer includes the observation that when the kernel is talking
    about sparc64, it is refering to "kernel for the -v9" architecture because
    it needs 64-bit addressing (Note to kernel people: Correct my description
    here) even though linux for sparc does not currently support 64-bit
    addresses in user space. (But see the thread on this topic in this forum.)

  • Even longer answer. The SPARC Architecture Manual, Version 9 is
    available from Prentice Hall, or on-line for free download (pdf) at
    <http://www.sparc.com/standards/V9-R1.4.7.pdf>, and it explains
    the differences between -v8 and -v9. While you are at it, Sun's UltraSPARC
    User's Manual is available on-line (only); it was part number 802-7220-02,
    but seems to have been superceded. See below for current.
    Also, the Assembly manual is available on-line from Sun: 806-3774.

    Try <http://www.sun.com/processors/manuals/805-0087.pdf> (which you
    get to from <http://www.sun.com/processors/documentation.html>) for
    current Sun UltraSparc-ii information,
    and <http://docs.sun.com/db/doc/806-3774?a=load> to download an
    assembly manual. (The assembly manuals change with Solaris versions,
    and are useful mostly as a reference to go along with the architecture
    manual from sparc.com.)



As to the Solaris compiler: I have never seen it. We do have a couple
Sparc systems running Solaris (U10, Solaris 8; SS20, Solaris 2.5.1),
but we use gcc on both of them. Last I knew, the native compiler(s)
for Solaris were too expensive for us to consider.

Hope this helps.

Regards,
Back to top
View user's profile Send private message
Ferris
Retired Dev
Retired Dev


Joined: 13 Jan 2003
Posts: 426
Location: N. Virginia (USA)

PostPosted: Fri Oct 17, 2003 2:29 pm    Post subject: Reply with quote

And, for completeness, let me add that on the <http://www.sparc.com>
Resources page, you will find Implementation Characteristics of Current SPARC-V9 -based
Products.
This booklet collects the specific characteristics of both the
Sun and the not-Sun Sparc-v9 implementations in one convenient spot.
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Gentoo on Sparc All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum