Migrating ARChitect APEX generated header to GNU
================================================

.. highlight:: c

The ARChitect2 tool generates a special header file when APEX instructions are
specified/selected in ARChitect. Such an example can be:

.. code-block:: c

	/* **** 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


MWDT specific header analysis


Let us take each element of the autogenerated header and analyse it.


The Auxiliary registers
^^^^^^^^^^^^^^^^^^^^^^^

.. code-block:: c

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

The MWDT 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::

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

Having this instantiation::

	Aux_register (0xfffff800, "auxreg0");


The extension core registers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code-block:: c

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

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


User extension instructions
^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code-block:: c

	// 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")

MWDT format is using the function _insn1_ declaration to select the instruction
syntax, while the pragma is defining the MOP, SOP and sides effects of the
instruction. Thus, for our example, _insn1_ is using SYNTAX_3OP leading to::

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

	intrinsic_3OP ("insn1", 7, 5);

for instruction declaration, and::

	__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;
	}

to be used in C.

The list of clobber registers can be ignored as the compiler does not handle
the r32 to r56 register. However, to be safe, it is good to inform it about
them. As for auxiliary register, one can ignore or just add "memory" to the
clobber list as AUX registers are memory.

GNU header
----------

.. code-block:: c

	#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
