Skip to content

Migrating APEX Header

Preface

ARChitect2 tool generates a special header file when APEX instructions are specified/selected in ARChitect. Here is an example:

/* **** DO NOT EDIT - this file is generated by ARChitect2 ****
 *
 * Description: Header file declaring the compiler extensions for apex components
 */

#ifndef _apexextensions_H_
#define _apexextensions_H_

#define APEX_EXT_CORE_REGS_EXT_CORE_REGS_PRESENT        1

// User extension aux register auxreg0
#define AR_AUXREG0 0xfffff800
#pragma Aux_register(0xfffff800, name=>"auxreg0")

// User extension aux register auxreg1
#define AR_AUXREG1 0xfffff801
#pragma Aux_register(0xfffff801, name=>"auxreg1")

// User extension core register r32
#define CR_R32 32
#pragma Core_register(32, name=>"r32")

// User extension core register r33
#define CR_R33 33
#pragma Core_register(33, name=>"r33")

// User extension core register r34
#define CR_R34 34
#pragma Core_register(34, name=>"r34")

// User extension core register r35
#define CR_R35 35
#pragma Core_register(35, name=>"r35")

// User extension instruction insn1
extern long insn1(long,long);
#pragma intrinsic(insn1,opcode=>7,sub_opcode=>5, effects=>"reg=32:is_read:is_written; reg=33:is_read:is_written; reg=34:is_read:is_written; reg=35:is_read:is_written; auxreg=0xfffff800:is_read:is_written; auxreg=0xfffff801:is_read:is_written")

// User extension instruction insn2
extern long insn2(long);
#pragma intrinsic(insn2,opcode=>7,sub_opcode=>1, effects=>"reg=32:is_read:is_written; reg=33:is_read:is_written; reg=34:is_read:is_written; reg=35:is_read:is_written; auxreg=0xfffff800:is_read:is_written; auxreg=0xfffff801:is_read:is_written")

#endif

Auxiliary Registers

// User extension aux register auxreg0
#define AR_AUXREG0 0xfffff800
#pragma Aux_register(0xfffff800, name=>"auxreg0")

MetaWare compiler accepts the definition of various extension features via pragmas. However, this is not the case for GNU. In this case, we need to use inline assembly to make the toolchain aware of the added functionality. Thus, to handle auxiliary register definition at C-level, we may need to define this:

#define Aux_register(ADDR, NAME)                \
    asm (".extAuxRegister " NAME ", " #ADDR ", r|w")

Instantiate the register:

Aux_register (0xfffff800, "auxreg0");

Extension Core Registers

// User extension core register r32
#define CR_R32 32
#pragma Core_register(32, name=>"r32")

Usually, GNU recognizes all the extension core registers as r32-r57. Thus, it is not necessary to define a core register which has the same name as in GNU.

Extension Instructions

// User extension instruction insn1
extern long insn1(long,long);
#pragma intrinsic(insn1,opcode=>7,sub_opcode=>5, effects=>"reg=32:is_read:is_written; reg=33:is_read:is_written; reg=34:is_read:is_written; reg=35:is_read:is_written; auxreg=0xfffff800:is_read:is_written; auxreg=0xfffff801:is_read:is_written")

MetaWare format uses the function insn1 declaration to select the instruction syntax, while pragma defines MOP, SOP and sides effects of the instruction. Thus, for our example, insn1 must use SYNTAX_3OP:

#define intrinsic_3OP(NAME, MOP, SOP)           \
    asm (".extInstruction " NAME "," #MOP ","   \
    #SOP ",SUFFIX_NONE, SYNTAX_3OP\n\t")

intrinsic_3OP ("insn1", 7, 5);

__extension__ static __inline int32_t __attribute__ ((__always_inline__))
insn1 (int32_t __a, int32_t __b)
{
    int32_t __dst;
    __asm__ ("insn1 %0, %1, %2\n\t"
            : "=r" (__dst)
            : "r" (__a), "rCal" (__b)
            : "r32", "r33", "r34", "r35");
    return __dst;
}

A list of clobber registers may be ignored as the compiler does not handle r32-r56 registers. However, to be safe, it is good to mention them. As for auxiliary register, one can ignore or just add memory to the clobber list as AUX registers is memory.

Final Header File

#ifndef _apexextensions_H_
#define _apexextensions_H_

#include <stdint.h>

#define Aux_register(ADDR, NAME)                \
  asm (".extAuxRegister " NAME ", " #ADDR ", r|w")

#define intrinsic_3OP(NAME, MOP, SOP)           \
  asm (".extInstruction " NAME "," #MOP ","             \
  #SOP ",SUFFIX_NONE, SYNTAX_3OP\n\t")

#define intrinsic_2OP(NAME, MOP, SOP)           \
  asm (".extInstruction " NAME "," #MOP ","             \
  #SOP ",SUFFIX_NONE, SYNTAX_2OP\n\t")

Aux_register (0xfffff800, "auxreg0");
Aux_register (0xfffff801, "auxreg1");

intrinsic_3OP ("insn1", 7, 5);
intrinsic_2OP ("insn2", 7, 1);

__extension__ static __inline int32_t __attribute__ ((__always_inline__))
insn1 (int32_t __a, int32_t __b)
{
  int32_t __dst;
  __asm__ ("insn1 %0, %1, %2\n\t"
                : "=r" (__dst)
                : "r" (__a), "rCal" (__b)
                : "r32", "r33", "r34", "r35", "memory");
  return __dst;
}

__extension__ static __inline int32_t __attribute__ ((__always_inline__))
insn2 (int32_t __a)
{
  int32_t __dst;
  __asm__ ("insn2 %0, %1\n\t"
                : "=r" (__dst)
                : "rCal" (__a)
                : "r32", "r33", "r34", "r35", "memory");
  return __dst;
}

#endif