[PATCH 11] SPARC: added libcpu lowlevel access and byteorder routines/definitions
Daniel Hellstrom
daniel at gaisler.com
Wed Feb 8 12:04:09 UTC 2012
On 02/06/2012 07:31 PM, Joel Sherrill wrote:
> On 02/06/2012 10:35 AM, Daniel Hellstrom wrote:
>> On 02/06/2012 05:13 PM, Joel Sherrill wrote:
>>> Why are these assembly instead of inline asm macros?
>> In some code I need to have a function pointer, then inlining is no good. That is the difference between byteorder.h and access.h.
>>
>> If you mean the implementation of access.S could have been made like in access_le.c, then I have not good answer, personally I thought it was better this way. I can change access.S into access.c
>> implementing them with inlining, but it still has to be functions.
>>
>> This was the only way I know how to make one function have two names, for example:
>> +SYM(_ld_be32):
>> +SYM(_ld32):
>> + retl
>> + ld [%o0], %o0
>>
>>
> If you truly need both symbols in the .a, then yes, it's that or implement
> one macro and two real bodies. This is less code and less duplication
> if you want both those entry points in the .a.
Yes that is what I want.
>
> But if you just want both available at the C programming level, then
> inlining them and having one "call" the other is OK.
>
> But I recall that the PCI code sets up a structure of function pointers
> so you need real bodies for that to work. Assembly language makes
> sense. Probably worth a comment as to why it is in assembly for
> future readers. I would hate to recreate this logic stream in ten years. :>
So I let it be in assembly but I will add comments at top of the file.
And I will updated according to Gedare's input (64-bit fix) and resubmit the patch.
Thanks for reviewing
>>> On 02/06/2012 10:00 AM, Daniel Hellstrom wrote:
>>>> On 02/06/2012 04:33 PM, Gedare Bloom wrote:
>>>>> On Mon, Feb 6, 2012 at 9:15 AM, Daniel Hellstrom<daniel at gaisler.com> wrote:
>>>>>> The low level routines can be used in different occasions, it will be
>>>>>> required when accessing PCI.
>>>>>>
>>>>>> Signed-off-by: Daniel Hellstrom<daniel at gaisler.com>
>>>>>> ---
>>>>>> c/src/lib/libbsp/sparc/erc32/Makefile.am | 4 +-
>>>>>> c/src/lib/libbsp/sparc/leon2/Makefile.am | 1 +
>>>>>> c/src/lib/libbsp/sparc/leon3/Makefile.am | 4 +-
>>>>>> c/src/lib/libcpu/sparc/Makefile.am | 7 ++
>>>>>> c/src/lib/libcpu/sparc/access/access.S | 65 ++++++++++++++++++++
>>>>>> c/src/lib/libcpu/sparc/access/access_le.c | 32 ++++++++++
>>>>>> c/src/lib/libcpu/sparc/include/libcpu/access.h | 48 +++++++++++++++
>>>>>> c/src/lib/libcpu/sparc/include/libcpu/byteorder.h | 66 +++++++++++++++++++++
>>>>>> c/src/lib/libcpu/sparc/preinstall.am | 8 +++
>>>>>> 9 files changed, 233 insertions(+), 2 deletions(-)
>>>>>> create mode 100644 c/src/lib/libcpu/sparc/access/access.S
>>>>>> create mode 100644 c/src/lib/libcpu/sparc/access/access_le.c
>>>>>> create mode 100644 c/src/lib/libcpu/sparc/include/libcpu/access.h
>>>>>> create mode 100644 c/src/lib/libcpu/sparc/include/libcpu/byteorder.h
>>>>>>
>>>>>> diff --git a/c/src/lib/libbsp/sparc/erc32/Makefile.am b/c/src/lib/libbsp/sparc/erc32/Makefile.am
>>>>>> index abe44c3..cecfe14 100644
>>>>>> --- a/c/src/lib/libbsp/sparc/erc32/Makefile.am
>>>>>> +++ b/c/src/lib/libbsp/sparc/erc32/Makefile.am
>>>>>> @@ -68,7 +68,9 @@ erc32sonic_rel_CPPFLAGS = $(AM_CPPFLAGS) $(erc32sonic_CPPFLAGS)
>>>>>> erc32sonic_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
>>>>>> endif
>>>>>>
>>>>>> -libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/cache.rel \
>>>>>> +libbsp_a_LIBADD = \
>>>>>> + ../../../libcpu/@RTEMS_CPU@/access.rel \
>>>>>> + ../../../libcpu/@RTEMS_CPU@/cache.rel \
>>>>>> ../../../libcpu/@RTEMS_CPU@/reg_win.rel \
>>>>>> ../../../libcpu/@RTEMS_CPU@/syscall.rel
>>>>>> if HAS_NETWORKING
>>>>>> diff --git a/c/src/lib/libbsp/sparc/leon2/Makefile.am b/c/src/lib/libbsp/sparc/leon2/Makefile.am
>>>>>> index 9c7819c..9df3c7d 100644
>>>>>> --- a/c/src/lib/libbsp/sparc/leon2/Makefile.am
>>>>>> +++ b/c/src/lib/libbsp/sparc/leon2/Makefile.am
>>>>>> @@ -118,6 +118,7 @@ leon_open_eth_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
>>>>>> endif
>>>>>>
>>>>>> libbsp_a_LIBADD = \
>>>>>> + ../../../libcpu/@RTEMS_CPU@/access.rel \
>>>>>> ../../../libcpu/@RTEMS_CPU@/cache.rel \
>>>>>> ../../../libcpu/@RTEMS_CPU@/reg_win.rel \
>>>>>> ../../../libcpu/@RTEMS_CPU@/syscall.rel
>>>>>> diff --git a/c/src/lib/libbsp/sparc/leon3/Makefile.am b/c/src/lib/libbsp/sparc/leon3/Makefile.am
>>>>>> index 5edbe9d..8eae306 100644
>>>>>> --- a/c/src/lib/libbsp/sparc/leon3/Makefile.am
>>>>>> +++ b/c/src/lib/libbsp/sparc/leon3/Makefile.am
>>>>>> @@ -126,7 +126,9 @@ libbsp_a_SOURCES += shmsupp/addrconv.c shmsupp/getcfg.c shmsupp/lock.c \
>>>>>> shmsupp/mpisr.c
>>>>>> endif
>>>>>>
>>>>>> -libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/cache.rel \
>>>>>> +libbsp_a_LIBADD = \
>>>>>> + ../../../libcpu/@RTEMS_CPU@/access.rel \
>>>>>> + ../../../libcpu/@RTEMS_CPU@/cache.rel \
>>>>>> ../../../libcpu/@RTEMS_CPU@/reg_win.rel \
>>>>>> ../../../libcpu/@RTEMS_CPU@/syscall.rel
>>>>>>
>>>>>> diff --git a/c/src/lib/libcpu/sparc/Makefile.am b/c/src/lib/libcpu/sparc/Makefile.am
>>>>>> index 7bebd94..711d6b1 100644
>>>>>> --- a/c/src/lib/libcpu/sparc/Makefile.am
>>>>>> +++ b/c/src/lib/libcpu/sparc/Makefile.am
>>>>>> @@ -10,6 +10,8 @@ noinst_PROGRAMS =
>>>>>>
>>>>>> include_libcpudir = $(includedir)/libcpu
>>>>>> include_libcpu_HEADERS = ../shared/include/cache.h
>>>>>> +include_libcpu_HEADERS += include/libcpu/byteorder.h
>>>>>> +include_libcpu_HEADERS += include/libcpu/access.h
>>>>>>
>>>>>> noinst_PROGRAMS += cache.rel
>>>>>> cache_rel_SOURCES = cache/cache.c cache/cache_.h \
>>>>>> @@ -31,5 +33,10 @@ reg_win_rel_SOURCES = reg_win/window.S
>>>>>> reg_win_rel_CPPFLAGS = $(AM_CPPFLAGS)
>>>>>> reg_win_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
>>>>>>
>>>>>> +noinst_PROGRAMS += access.rel
>>>>>> +access_rel_SOURCES = access/access.S access/access_le.c
>>>>>> +access_rel_CPPFLAGS = $(AM_CPPFLAGS)
>>>>>> +access_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
>>>>>> +
>>>>>> include $(srcdir)/preinstall.am
>>>>>> include $(top_srcdir)/../../../automake/local.am
>>>>>> diff --git a/c/src/lib/libcpu/sparc/access/access.S b/c/src/lib/libcpu/sparc/access/access.S
>>>>>> new file mode 100644
>>>>>> index 0000000..7e69f64
>>>>>> --- /dev/null
>>>>>> +++ b/c/src/lib/libcpu/sparc/access/access.S
>>>>>> @@ -0,0 +1,65 @@
>>>>>> +/*
>>>>>> + * Access routines for SPARC
>>>>>> + *
>>>>>> + * COPYRIGHT (c) 2011
>>>>>> + * Aeroflex Gaisler.
>>>>>> + *
>>>>>> + * The license and distribution terms for this file may be
>>>>>> + * found in the file LICENSE in this distribution or at
>>>>>> + * http://www.rtems.com/license/LICENSE.
>>>>>> + */
>>>>>> +
>>>>>> +#include<rtems/asm.h>
>>>>>> +
>>>>>> + .align 4
>>>>>> + .seg "text"
>>>>>> + PUBLIC(_ld8)
>>>>>> + PUBLIC(_ld16)
>>>>>> + PUBLIC(_ld32)
>>>>>> + PUBLIC(_ld64)
>>>>>> + PUBLIC(_st8)
>>>>>> + PUBLIC(_st16)
>>>>>> + PUBLIC(_st32)
>>>>>> + PUBLIC(_st64)
>>>>>> + PUBLIC(_ld_be16)
>>>>>> + PUBLIC(_ld_be32)
>>>>>> + PUBLIC(_st_be16)
>>>>>> + PUBLIC(_st_be32)
>>>>>> +
>>>>>> +SYM(_ld8):
>>>>>> + retl
>>>>>> + ldub [%o0], %o0
>>>>>> +
>>>>>> +SYM(_ld_be16):
>>>>>> +SYM(_ld16):
>>>>>> + retl
>>>>>> + lduh [%o0], %o0
>>>>>> +
>>>>>> +SYM(_ld_be32):
>>>>>> +SYM(_ld32):
>>>>>> + retl
>>>>>> + ld [%o0], %o0
>>>>>> +
>>>>>> +SYM(_ld_be64):
>>>>>> +SYM(_ld64):
>>>>>> + retl
>>>>>> + ldd [%o0], %o0
>>>>>> +
>>>>>> +SYM(_st8):
>>>>>> + retl
>>>>>> + stub %o1, [%o0]
>>>>>> +
>>>>>> +SYM(_st_be16):
>>>>>> +SYM(_st16):
>>>>>> + retl
>>>>>> + stuh %o1, [%o0]
>>>>>> +
>>>>>> +SYM(_st_be32):
>>>>>> +SYM(_st32):
>>>>>> + retl
>>>>>> + st %o1, [%o0]
>>>>>> +
>>>>>> +SYM(_st_be64):
>>>>>> +SYM(_st64):
>>>>>> + retl
>>>>>> + std %o1, [%o0]
>>>>> Do these functions get used somewhere I don't see?
>>>> No they are not called until I submit my PCI patches. Perhaps it would have been better to wait with this code?
>>>>> Do we need these defined in assembly language, maybe at least inline
>>>>> assembly would be better to get some kind of type-checking assist from
>>>>> the compiler?
>>>> One can access inline functions from byteorder.h. The point with the functions is that they are the fastest way to access a specific size, using the C-compiler would make these functions be
>>>> different
>>>> with different compiler flags. I think they are the simplest ASM functions there are, even so I managed to make a copy-paste bug on the 64bit case :)
>>>>> I suspect something is wrong with the _st64/_st_be64 function, because
>>>>> sparc uses paired registers to store a 64-bit number the compiler will
>>>>> pack the arguments differently and probably as o0/o1 or o2/o3.
>>>> My bad, the 64-bit macros/code has never been executed since there as been no use-case. Thanks for reviewing! Perhaps one should remove the 64-bit access routines, however they are supported by
>>>> hardware.
>>>>
>>>> +SYM(_st_be64):
>>>> +SYM(_st64):
>>>> + mov %o2, %o3
>>>> + mov %o1, %o2
>>>> + retl
>>>> + std %o2, [%o0]
>>>>
>>>>
>>>> I will resubmit patch.
>>>>
>>>>>> diff --git a/c/src/lib/libcpu/sparc/access/access_le.c b/c/src/lib/libcpu/sparc/access/access_le.c
>>>>>> new file mode 100644
>>>>>> index 0000000..15031cc
>>>>>> --- /dev/null
>>>>>> +++ b/c/src/lib/libcpu/sparc/access/access_le.c
>>>>>> @@ -0,0 +1,32 @@
>>>>>> +/*
>>>>>> + * Little-endian access routines for SPARC
>>>>>> + *
>>>>>> + * COPYRIGHT (c) 2011
>>>>>> + * Aeroflex Gaisler.
>>>>>> + *
>>>>>> + * The license and distribution terms for this file may be
>>>>>> + * found in the file LICENSE in this distribution or at
>>>>>> + * http://www.rtems.com/license/LICENSE.
>>>>>> + */
>>>>>> +
>>>>>> +#include<libcpu/byteorder.h>
>>>>>> +
>>>>>> +uint16_t _ld_le16(uint16_t *addr)
>>>>>> +{
>>>>>> + return ld_le16(addr);
>>>>>> +}
>>>>>> +
>>>>>> +void _st_le16(uint16_t *addr, uint16_t val)
>>>>>> +{
>>>>>> + st_le16(addr, val);
>>>>>> +}
>>>>>> +
>>>>>> +uint32_t _ld_le32(uint32_t *addr)
>>>>>> +{
>>>>>> + return ld_le32(addr);
>>>>>> +}
>>>>>> +
>>>>>> +void _st_le32(uint32_t *addr, uint32_t val)
>>>>>> +{
>>>>>> + st_le32(addr, val);
>>>>>> +}
>>>>>> diff --git a/c/src/lib/libcpu/sparc/include/libcpu/access.h b/c/src/lib/libcpu/sparc/include/libcpu/access.h
>>>>>> new file mode 100644
>>>>>> index 0000000..2d87c2a
>>>>>> --- /dev/null
>>>>>> +++ b/c/src/lib/libcpu/sparc/include/libcpu/access.h
>>>>>> @@ -0,0 +1,48 @@
>>>>>> +/*
>>>>>> + * access.h - access routines for SPARC. SPARC is big endian only.
>>>>>> + *
>>>>>> + * COPYRIGHT (c) 2011
>>>>>> + * Aeroflex Gaisler.
>>>>>> + *
>>>>>> + * The license and distribution terms for this file may be
>>>>>> + * found in the file LICENSE in this distribution or at
>>>>>> + * http://www.rtems.com/license/LICENSE.
>>>>>> + */
>>>>>> +
>>>>>> +#ifndef _LIBCPU_ACCESS_H
>>>>>> +#define _LIBCPU_ACCESS_H
>>>>>> +
>>>>>> +#include<rtems/system.h>
>>>>>> +#include<rtems/score/cpu.h>
>>>>>> +
>>>>>> +#ifdef __cplusplus
>>>>>> +extern "C" {
>>>>>> +#endif
>>>>>> +
>>>>>> +/* "Raw" access */
>>>>>> +extern uint8_t _ld8(uint8_t *addr);
>>>>>> +extern void _st8(uint8_t *addr, uint8_t val);
>>>>>> +extern uint16_t _ld16(uint16_t *addr);
>>>>>> +extern void _st16(uint16_t *addr, uint16_t val);
>>>>>> +extern uint32_t _ld32(uint32_t *addr);
>>>>>> +extern void _st32(uint32_t *addr, uint32_t val);
>>>>>> +extern uint64_t _ld64(uint64_t *addr);
>>>>>> +extern void _st64(uint64_t *addr, uint64_t val);
>>>>>> +
>>>>>> +/* Aliases for Big Endian */
>>>>>> +extern uint16_t _ld_be16(uint16_t *addr);
>>>>>> +extern void _st_be16(uint16_t *addr, uint16_t val);
>>>>>> +extern uint32_t _ld_be32(uint32_t *addr);
>>>>>> +extern void _st_be32(uint32_t *addr, uint32_t val);
>>>>>> +
>>>>>> +/* Little endian */
>>>>>> +extern uint16_t _ld_le16(uint16_t *addr);
>>>>>> +extern void _st_le16(uint16_t *addr, uint16_t val);
>>>>>> +extern uint32_t _ld_le32(uint32_t *addr);
>>>>>> +extern void _st_le32(uint32_t *addr, uint32_t val);
>>>>>> +
>>>>>> +#ifdef __cplusplus
>>>>>> +}
>>>>>> +#endif
>>>>>> +
>>>>>> +#endif
>>>>>> diff --git a/c/src/lib/libcpu/sparc/include/libcpu/byteorder.h b/c/src/lib/libcpu/sparc/include/libcpu/byteorder.h
>>>>>> new file mode 100644
>>>>>> index 0000000..d626f28
>>>>>> --- /dev/null
>>>>>> +++ b/c/src/lib/libcpu/sparc/include/libcpu/byteorder.h
>>>>>> @@ -0,0 +1,66 @@
>>>>>> +/*
>>>>>> + * byteorder.h - Endian conversion for SPARC. SPARC is big endian only.
>>>>>> + *
>>>>>> + * COPYRIGHT (c) 2011
>>>>>> + * Aeroflex Gaisler.
>>>>>> + *
>>>>>> + * The license and distribution terms for this file may be
>>>>>> + * found in the file LICENSE in this distribution or at
>>>>>> + * http://www.rtems.com/license/LICENSE.
>>>>>> + */
>>>>>> +
>>>>>> +#ifndef _LIBCPU_BYTEORDER_H
>>>>>> +#define _LIBCPU_BYTEORDER_H
>>>>>> +
>>>>>> +#include<rtems/system.h>
>>>>>> +#include<rtems/score/cpu.h>
>>>>>> +
>>>>>> +#ifdef __cplusplus
>>>>>> +extern "C" {
>>>>>> +#endif
>>>>>> +
>>>>>> +RTEMS_INLINE_ROUTINE uint16_t ld_le16(volatile uint16_t *addr)
>>>>>> +{
>>>>>> + return CPU_swap_u16(*addr);
>>>>>> +}
>>>>>> +
>>>>>> +RTEMS_INLINE_ROUTINE void st_le16(volatile uint16_t *addr, uint16_t val)
>>>>>> +{
>>>>>> + *addr = CPU_swap_u16(val);
>>>>>> +}
>>>>>> +
>>>>>> +RTEMS_INLINE_ROUTINE uint32_t ld_le32(volatile uint32_t *addr)
>>>>>> +{
>>>>>> + return CPU_swap_u32(*addr);
>>>>>> +}
>>>>>> +
>>>>>> +RTEMS_INLINE_ROUTINE void st_le32(volatile uint32_t *addr, uint32_t val)
>>>>>> +{
>>>>>> + *addr = CPU_swap_u32(val);
>>>>>> +}
>>>>>> +
>>>>>> +RTEMS_INLINE_ROUTINE uint16_t ld_be16(volatile uint16_t *addr)
>>>>>> +{
>>>>>> + return *addr;
>>>>>> +}
>>>>>> +
>>>>>> +RTEMS_INLINE_ROUTINE void st_be16(volatile uint16_t *addr, uint16_t val)
>>>>>> +{
>>>>>> + *addr = val;
>>>>>> +}
>>>>>> +
>>>>>> +RTEMS_INLINE_ROUTINE uint32_t ld_be32(volatile uint32_t *addr)
>>>>>> +{
>>>>>> + return *addr;
>>>>>> +}
>>>>>> +
>>>>>> +RTEMS_INLINE_ROUTINE void st_be32(volatile uint32_t *addr, uint32_t val)
>>>>>> +{
>>>>>> + *addr = val;
>>>>>> +}
>>>>> Is there a reason for the addr argument to be volatile to these functions?
>>>> Yes, I followed the way powerpc implemented PCI access routines. They use volatile, and I beleive it is correct since one is accessing a register, somehow the compiler must not optimize away the
>>>> access. Please see c/src/lib/libcpu/powerpc/shared/include/byteorder.h
>>>>
>>>>> Why not use the functions defined above in access.h?
>>>> access.h define functions named _FUNC, whereas byteorder.h define inline functions named FUNC.
>>>>
>>>> Sometimes we need to refer to access routines by function pointers and sometimes we want to optimize the code as much as possible with inlining. Bear in mind that these functions are accessed very
>>>> often, every time a register is accessed.
>>>>
>>>>>> +
>>>>>> +#ifdef __cplusplus
>>>>>> +}
>>>>>> +#endif
>>>>>> +
>>>>>> +#endif
>>>>>> diff --git a/c/src/lib/libcpu/sparc/preinstall.am b/c/src/lib/libcpu/sparc/preinstall.am
>>>>>> index 412b683..2efe38b 100644
>>>>>> --- a/c/src/lib/libcpu/sparc/preinstall.am
>>>>>> +++ b/c/src/lib/libcpu/sparc/preinstall.am
>>>>>> @@ -22,3 +22,11 @@ $(PROJECT_INCLUDE)/libcpu/cache.h: ../shared/include/cache.h $(PROJECT_INCLUDE)/
>>>>>> $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/cache.h
>>>>>> PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/cache.h
>>>>>>
>>>>>> +$(PROJECT_INCLUDE)/libcpu/byteorder.h: include/libcpu/byteorder.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp)
>>>>>> + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/byteorder.h
>>>>>> +PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/byteorder.h
>>>>>> +
>>>>>> +$(PROJECT_INCLUDE)/libcpu/access.h: include/libcpu/access.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp)
>>>>>> + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/access.h
>>>>>> +PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/access.h
>>>>>> +
>>>>>> --
>>>>>> 1.7.0.4
>>>>>>
>>>>>> _______________________________________________
>>>>>> rtems-devel mailing list
>>>>>> rtems-devel at rtems.org
>>>>>> http://www.rtems.org/mailman/listinfo/rtems-devel
>>>> _______________________________________________
>>>> rtems-devel mailing list
>>>> rtems-devel at rtems.org
>>>> http://www.rtems.org/mailman/listinfo/rtems-devel
>>>
>> _______________________________________________
>> rtems-devel mailing list
>> rtems-devel at rtems.org
>> http://www.rtems.org/mailman/listinfo/rtems-devel
>
>
More information about the devel
mailing list