forked from Archive/PX4-Autopilot
543 lines
16 KiB
C
543 lines
16 KiB
C
/**********************************************************************
|
|
* regm_registers.c
|
|
* Pass 2 register management functions
|
|
*
|
|
* Copyright (C) 2008-2009 Gregory Nutt. All rights reserved.
|
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
**********************************************************************/
|
|
|
|
/**********************************************************************
|
|
* Included Files
|
|
**********************************************************************/
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#include "keywords.h"
|
|
#include "pofflib.h"
|
|
#include "pedefs.h"
|
|
#include "perr.h"
|
|
|
|
#include "rinsn32.h"
|
|
|
|
#include "regm.h"
|
|
#include "regm_pass2.h"
|
|
#include "regm_registers2.h"
|
|
|
|
/**********************************************************************
|
|
* Definitions
|
|
**********************************************************************/
|
|
|
|
#define INITIAL_RCODE2_ALLOC 150
|
|
#define RCODE2_REALLOC 50
|
|
|
|
/**********************************************************************
|
|
* Private Function Prototypes
|
|
**********************************************************************/
|
|
|
|
/**********************************************************************
|
|
* Public Variables
|
|
**********************************************************************/
|
|
|
|
struct regm_rcode2_s *g_pRCode2 = NULL;
|
|
uint32_t g_nRCode2 = 0;
|
|
|
|
/**********************************************************************
|
|
* Private Variables
|
|
**********************************************************************/
|
|
|
|
static uint32_t g_nRCode2Alloc = 0;
|
|
|
|
static const char * const g_prgReg2Names[NREGISTER_TYPES] =
|
|
{ "Z", "X", "CC", "A", "R", "V", "V", "S" };
|
|
|
|
static const char * const g_prgSpecialReg2Names[NSPECIAL_REGISTERS2] =
|
|
{ "SPB", "SP", "BRG", "LSP", "CSB", "CSP", "PC", "DC", "LR", "CC"};
|
|
|
|
/**********************************************************************
|
|
* Private Functions
|
|
**********************************************************************/
|
|
|
|
/***********************************************************************/
|
|
|
|
static void regm_CheckRCode2Alloc(void)
|
|
{
|
|
/* If the RCode buffer has never been allocated, allocate it now. */
|
|
|
|
if (!g_pRCode2)
|
|
{
|
|
/* Allocate an inital buffer to hold the instructions */
|
|
|
|
g_pRCode2 = (struct regm_rcode2_s*)
|
|
malloc(INITIAL_RCODE2_ALLOC*sizeof(struct regm_rcode2_s));
|
|
if (!g_pRCode2)
|
|
{
|
|
fatal(eNOMEMORY);
|
|
}
|
|
|
|
g_nRCode2Alloc = INITIAL_RCODE2_ALLOC;
|
|
}
|
|
|
|
/* The buffer has already been allocated, is there space for one
|
|
* more RCode?
|
|
*/
|
|
|
|
else if (g_nRCode2 >= g_nRCode2Alloc)
|
|
{
|
|
/* If not, then reallocate the array */
|
|
|
|
g_pRCode2 = (struct regm_rcode2_s*)
|
|
realloc(g_pRCode2, g_nRCode2Alloc*sizeof(struct regm_rcode2_s));
|
|
if (!g_pRCode2)
|
|
{
|
|
fatal(eNOMEMORY);
|
|
}
|
|
|
|
g_nRCode2Alloc += RCODE2_REALLOC;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
struct regm_rcode2_s *regm_AllocateRCode2(void)
|
|
{
|
|
struct regm_rcode2_s *pRetSlot;
|
|
|
|
/* Make sure we have memory allocated in the array for another
|
|
* RCode.
|
|
*/
|
|
|
|
regm_CheckRCode2Alloc();
|
|
|
|
/* Return the reference to the next RCode slot */
|
|
|
|
pRetSlot = &g_pRCode2[g_nRCode2];
|
|
g_nRCode2++;
|
|
return pRetSlot;
|
|
}
|
|
|
|
static void regm_PrintSpecialReg2(FILE *pStream, uint32_t dwRegister)
|
|
{
|
|
int wRegNo = regm_GetRegNo(dwRegister);
|
|
if (wRegNo >= NSPECIAL_REGISTERS2)
|
|
fputc('?', pStream);
|
|
else
|
|
fputs(g_prgSpecialRegNames[wRegNo], pStream);
|
|
}
|
|
|
|
static void regm_PrintReg2(FILE *pStream, uint32_t dwRegister)
|
|
{
|
|
int wKind = regm_GetKind(dwRegister);
|
|
int wRegNo = regm_GetRegNo(dwRegister)
|
|
if (wKind >= REGISTERS_TYPES)
|
|
fprintf(pStream, "?%d", wRegNo);
|
|
else if (wKind == SPECIAL_REG)
|
|
regm_PrintSpecialReg(fg, dwRegister);
|
|
else
|
|
fprintf(pStream, "%s%d", g_prgRegNames[wKind], wRegNo);
|
|
}
|
|
|
|
static void regm_PrintDebugReg(const char *string, uint32_t dwRegister)
|
|
{
|
|
if (vRegmDebug)
|
|
{
|
|
fputs(string, DEBUG_FILE);
|
|
regm_PrintReg2(DEBUG_FILE, dwRegister);
|
|
fputc('\n', DEBUG_FILE);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
static void regm_MarkRegisterUsed(struct regm_rcode2_s *pReg,
|
|
uint32_t dwRegister)
|
|
{
|
|
regm_PrintDebugReg("Register used: ", dwRegister);
|
|
|
|
switch (regm_GetKind(dwRegister))
|
|
{
|
|
case SPECIAL_REG : /* Special "global" registers */
|
|
break; /* (ignored) */
|
|
|
|
case CC_REG : /* Condition code register instance (fake) */
|
|
break;
|
|
|
|
case INARG_REG : /* Volatile register for input arguments */
|
|
/* and output values from/to callee */
|
|
break;
|
|
|
|
case OUTARG_REG : /* Volatile register for output arguments */
|
|
/* and input values to/from called */
|
|
/* function (fake) */
|
|
break;
|
|
|
|
case SCRATCH_REG : /* Volatile register for general usage */
|
|
break;
|
|
|
|
case VOLATILE_REG : /* Volatile registers in general */
|
|
case STATIC_REG : /* Static register */
|
|
default:
|
|
fatal(ePOFFCONFUSION);
|
|
break;
|
|
}
|
|
#warning "Not Implemeted"
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
static void regm_MarkRegisterModified(struct regm_rcode2_s *pReg,
|
|
uint32_t dwRegister)
|
|
{
|
|
regm_PrintDebugReg("Register modified: ", dwRegister);
|
|
|
|
switch (regm_GetKind(dwRegister))
|
|
{
|
|
case SPECIAL_REG : /* Special "global" registers */
|
|
break; /* (ignored) */
|
|
|
|
case CC_REG : /* Condition code register instance (fake) */
|
|
break;
|
|
|
|
case INARG_REG : /* Volatile register for input arguments */
|
|
/* and output values from/to callee */
|
|
break;
|
|
|
|
case OUTARG_REG : /* Volatile register for output arguments */
|
|
/* and input values to/from called */
|
|
/* function (fake) */
|
|
break;
|
|
|
|
case SCRATCH_REG : /* Volatile register for general usage */
|
|
break;
|
|
|
|
case VOLATILE_REG : /* Volatile registers in general */
|
|
case STATIC_REG : /* Static register */
|
|
default:
|
|
fatal(ePOFFCONFUSION);
|
|
break;
|
|
}
|
|
#warning "Not Implemeted"
|
|
}
|
|
|
|
/**********************************************************************
|
|
* Public Functions
|
|
**********************************************************************/
|
|
|
|
/***********************************************************************/
|
|
/* Generate function prologue: Save return address, create stack frame
|
|
* for local variables, and save static registers that till be used.
|
|
*/
|
|
|
|
void regm_GeneratePrologue(uint32_t dwFrameSize)
|
|
{
|
|
#warning "Not implemented"
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* Restore static registers, release stack frame and return */
|
|
|
|
void regm_GenerateEpilogue(uint32_t dwFrameSize)
|
|
{
|
|
#warning "Not implemented"
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* Register-to-register comparisons (e.g., cmp r1, r2)
|
|
*
|
|
* FORM 1R: <op> <roperand1>, <roperand2>
|
|
*/
|
|
|
|
void regm_GenerateForm1RCc(uint8_t chOp, uint32_t dwROperand1,
|
|
uint32_t dwROperand2, uint32_t dwRCc)
|
|
{
|
|
struct regm_rcode2_s *pReg = regm_AllocateRCode2();
|
|
pReg->eForm = eFORM_1RCc;
|
|
pReg->chOp = chOp;
|
|
pReg->u.f1rcc.dwROperand1 = dwROperand1;
|
|
pReg->u.f1rcc.dwROperand2 = dwROperand2;
|
|
pReg->u.f1rcc.dwRCc = dwRCc;
|
|
|
|
regm_MarkRegisterUsed(pReg, dwROperand1);
|
|
regm_MarkRegisterUsed(pReg, dwROperand2);
|
|
regm_MarkRegisterModified(pReg, dwRCc);
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* Register-to-immediate comparisons (e.g., cmpi r1, 1)
|
|
*
|
|
* FORM 1I: <op> <roperand1>, <immediate>
|
|
*/
|
|
|
|
void regm_GenerateForm1ICc(uint8_t chOp, uint32_t dwROperand1,
|
|
uint32_t dwImmediate, uint32_t dwRCc)
|
|
{
|
|
struct regm_rcode2_s *pReg = regm_AllocateRCode2();
|
|
pReg->eForm = eFORM_1ICc;
|
|
pReg->chOp = chOp;
|
|
pReg->u.f1icc.dwROperand1 = dwROperand1;
|
|
pReg->u.f1icc.dwImmediate = dwImmediate;
|
|
pReg->u.f1icc.dwRCc = dwRCc;
|
|
|
|
regm_MarkRegisterUsed(pReg, dwROperand1);
|
|
regm_MarkRegisterModified(pReg, dwRCc);
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* Register-to-register mov instructions (e.g, mov r1, r2)
|
|
*
|
|
* FORM 2R: <op> <rdest>, <roperand2>
|
|
*/
|
|
|
|
void regm_GenerateForm2R(uint8_t chOp, uint32_t dwRDest,
|
|
uint32_t dwROperand2)
|
|
{
|
|
struct regm_rcode2_s *pReg = regm_AllocateRCode2();
|
|
pReg->eForm = eFORM_2R;
|
|
pReg->chOp = chOp;
|
|
pReg->u.f2r.dwRDest = dwRDest;
|
|
pReg->u.f2r.dwROperand2 = dwROperand2;
|
|
|
|
regm_MarkRegisterModified(pReg, dwRDest);
|
|
regm_MarkRegisterUsed(pReg, dwROperand2);
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* Immediate-to-register mov instructions (e.g, movi r1, 1)
|
|
*
|
|
/* FORM 2I: <op> <rdest>, <immediate>
|
|
*/
|
|
|
|
void regm_GenerateForm2I(uint8_t chOp, uint32_t dwRDest,
|
|
uint32_t dwImmediate)
|
|
{
|
|
struct regm_rcode2_s *pReg = regm_AllocateRCode2();
|
|
pReg->eForm = eFORM_2I;
|
|
pReg->chOp = chOp;
|
|
pReg->u.f2i.dwRDest = dwRDest;
|
|
pReg->u.f2i.dwImmediate = dwImmediate;
|
|
|
|
regm_MarkRegisterModified(pReg, dwRDest);
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* Binary operations (e.g., add r0, r1, r2)
|
|
* Load operations (e.g., ld r0, [r1, r2])
|
|
* Store operations (e.g., st r0, [r1, r2])
|
|
*
|
|
* FORM 3R: <op> <rdest>, <roperand1>, <roperand2>
|
|
* <rsrc>, <roperand1>, <roperand2>
|
|
*/
|
|
|
|
void regm_GenerateForm3R(uint8_t chOp, uint32_t dwRSrcDest,
|
|
uint32_t dwROperand1, uint32_t dwROperand2)
|
|
{
|
|
struct regm_rcode2_s *pReg = regm_AllocateRCode2();
|
|
pReg->eForm = eFORM_3R;
|
|
pReg->chOp = chOp;
|
|
pReg->u.f3r.dwRSrcDest = dwRSrcDest;
|
|
pReg->u.f3r.dwROperand1 = dwROperand1;
|
|
pReg->u.f3r.dwROperand2 = dwROperand2;
|
|
|
|
switch (chOp)
|
|
{
|
|
/* FORM 3: Arithmetic and logical operations */
|
|
/* FORM 3: Loads */
|
|
|
|
case rADD :
|
|
case rSUB :
|
|
case rRSB :
|
|
case rMUL :
|
|
case rDIV :
|
|
case rMOD :
|
|
case rSLL :
|
|
case rSRL :
|
|
case rSRA :
|
|
case rOR :
|
|
case rAND :
|
|
case rXOR :
|
|
case rANDN :
|
|
case rLD :
|
|
case rLDH :
|
|
case rLDB :
|
|
regm_MarkRegisterModified(pReg, dwRSrcDest);
|
|
break;
|
|
|
|
/* FORM 3: Loads multiple */
|
|
case rLDM :
|
|
{
|
|
uint32_t dwRDest = dwRSrcDest;
|
|
int i;
|
|
for (i = 0; i < g_dwRegisterCount; i++)
|
|
{
|
|
regm_MarkRegisterModified(pReg, dwRDest);
|
|
dwRDest++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* FORM 3: Stores */
|
|
case rST :
|
|
case rSTH :
|
|
case rSTB :
|
|
regm_MarkRegisterUsed(pReg, dwRSrcDest);
|
|
break;
|
|
|
|
/* FORM 3: Store multipole */
|
|
case rSTM :
|
|
{
|
|
uint32_t dwRSrc = dwRSrcDest;
|
|
int i;
|
|
for (i = 0; i < g_dwRegisterCount; i++)
|
|
{
|
|
regm_MarkRegisterUsed(pReg, dwRSrc);
|
|
dwRSrc++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
fatal(ePOFFCONFUSION);
|
|
}
|
|
|
|
regm_MarkRegisterUsed(pReg, dwROperand1);
|
|
regm_MarkRegisterUsed(pReg, dwROperand2);
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* Binary operations (e.g., addi r0, r1, 1)
|
|
* Load operations (e.g., ldi r0, [r1, 4])
|
|
* Store operations (e.g., sti r0, [r1, 4])
|
|
*
|
|
* FORM 3I: <op> <rdest>, <roperand1>, <immediate>
|
|
* <rsrc>, <roperand1>, <immediate>
|
|
*/
|
|
|
|
void regm_GenerateForm3I(uint8_t chOp, uint32_t dwRSrcDest,
|
|
uint32_t dwROperand1, uint32_t dwImmediate)
|
|
{
|
|
struct regm_rcode2_s *pReg = regm_AllocateRCode2();
|
|
pReg->eForm = eFORM_3I;
|
|
pReg->chOp = chOp;
|
|
pReg->u.f3i.dwRSrcDest = dwRSrcDest;
|
|
pReg->u.f3i.dwROperand1 = dwROperand1;
|
|
pReg->u.f3i.dwImmediate = dwImmediate;
|
|
|
|
switch (chOp)
|
|
{
|
|
/* FORM 3: Arithmetic and logical operations */
|
|
/* FORM 3: Loads */
|
|
|
|
case rADDI :
|
|
case rSUBI :
|
|
case rRSBI :
|
|
case rMULI :
|
|
case rDIVI :
|
|
case rMODI :
|
|
case rSLLI :
|
|
case rSRLI :
|
|
case rSRAI :
|
|
case rORI :
|
|
case rANDI :
|
|
case rXORI :
|
|
case rANDNI :
|
|
case rLDI :
|
|
case rLDIH :
|
|
case rLDIB :
|
|
regm_MarkRegisterModified(pReg, dwRSrcDest);
|
|
break;
|
|
|
|
/* FORM 3: Stores */
|
|
case rSTI :
|
|
case rSTIH :
|
|
case rSTIB :
|
|
regm_MarkRegisterUsed(pReg, dwRSrcDest);
|
|
break;
|
|
|
|
default:
|
|
fatal(ePOFFCONFUSION);
|
|
}
|
|
|
|
regm_MarkRegisterUsed(pReg, dwROperand1);
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* Unconditional branch operations (b offset, bl offset)
|
|
*
|
|
* FORM 4I: <op> <pc-offset>
|
|
*/
|
|
|
|
void regm_GenerateForm4I(uint8_t chOp, uint32_t dwOffset)
|
|
{
|
|
struct regm_rcode2_s *pReg = regm_AllocateRCode2();
|
|
pReg->eForm = eFORM_4I;
|
|
pReg->chOp = chOp;
|
|
pReg->u.f4i.dwOffset = dwOffset;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* Conditional branch operations (e.g., beq offset)
|
|
*
|
|
* FORM 4I: <op> <pc-offset>
|
|
*/
|
|
|
|
void regm_GenerateForm4ICc(uint8_t chOp, uint32_t dwOffset,
|
|
uint32_t dwRCc)
|
|
{
|
|
struct regm_rcode2_s *pReg = regm_AllocateRCode2();
|
|
pReg->eForm = eFORM_4ICc;
|
|
pReg->chOp = chOp;
|
|
pReg->u.f4icc.dwOffset = dwOffset;
|
|
pReg->u.f4icc.dwRCc = dwRCc;
|
|
|
|
regm_MarkRegisterUsed(pReg, dwRCc);
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
int regm_ForEachRCode2(regm_rcode2_node_t pNode, void *arg)
|
|
{
|
|
int ret;
|
|
int i;
|
|
for (i = 0; i < g_nRCode2; i++)
|
|
{
|
|
ret = pNode(&g_pRCode2[i], arg);
|
|
if (ret != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************************/
|