You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1526 lines
54 KiB
1526 lines
54 KiB
/********************************************************************** |
|
* regm_pass2.c |
|
* Convert the buffered pcode to the basic register model with an |
|
* indefinite number of registers (arguments, general, and special |
|
* registers) and with 32-bit immediate size. |
|
* |
|
* 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 "pdefs.h" |
|
#include "pxdefs.h" |
|
#include "pfdefs.h" |
|
#include "pedefs.h" |
|
#include "pofflib.h" |
|
#include "perr.h" |
|
|
|
#include "pinsn32.h" |
|
#include "builtins.h" |
|
|
|
#include "regm.h" |
|
#include "regm_tree.h" |
|
#include "regm_registers2.h" |
|
#include "regm_pass2.h" |
|
|
|
/************************************a********************************* |
|
* Definitions |
|
**********************************************************************/ |
|
|
|
/********************************************************************** |
|
* Private Types |
|
**********************************************************************/ |
|
|
|
struct regm_opmap_s; |
|
|
|
typedef void (*regm_mapper_t)(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, struct procdata_s *pNode); |
|
|
|
struct regm_opmap_s |
|
{ |
|
uint8_t chOpCode; |
|
int8_t chImmediate; |
|
int8_ chSpecial; |
|
regm_mapper_t pMapper; |
|
}; |
|
|
|
/********************************************************************** |
|
* Private Function Prototypes |
|
**********************************************************************/ |
|
|
|
static void regm_NoOperation(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_UnaryOperation(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_BinaryOperation(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_CompareVsZero(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_BinaryComparison(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_LoadImmediate(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_LoadMultiple(uint32_t dwRDest, uint32_t dwRSrc); |
|
static void regm_LoadMultipleImmediate(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_StoreMultiple(uint32_t dwRDest, uint32_t dwRSrc); |
|
static void regm_StoreImmediate(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_StoreMultipleImmediate(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_Duplicate(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_PushImmediate(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_PopSpecial(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_SetDataCount(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_PushSpecial(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_Return(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_LoadOffset(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_LoadMultipleOffset(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_StoreOffset(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_StoreMultipleOffset(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_LoadIndexed(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, struct procdata_s *pNode); |
|
static void regm_LoadMultipleIndexed(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_StoreIndexed(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, struct procdata_s *pNode); |
|
static void regm_StoreMultipleIndexed(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_ConditionalBranchVsZero(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_ConditionalBranchBinary(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_UnconditionalBranch(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_IncrementSpecial(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_LoadAddress(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, struct procdata_s *pNode); |
|
static void regm_LoadAddressIndexed(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_SetupOutArgs(uint32_t nParms, const uint32_t *pwArgSize); |
|
static void regm_MapInRet(uint32_t wRetSize); |
|
static void regm_PCal(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_SysIo(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_LibCall(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_Float(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
static void regm_IllegalPCode(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode); |
|
|
|
static void regm_GenerateRegm(struct procdata_s *pNode, void *pvArg); |
|
static int regm_Pass2Node(struct procdata_s *pNode, void *pvArg); |
|
|
|
/********************************************************************** |
|
* Public Variables |
|
**********************************************************************/ |
|
|
|
/* On the initialize passes, the register number will simply be the offset |
|
* from the top of the stack. The following variable keeps trck of the |
|
* stack offset. |
|
*/ |
|
|
|
uint32_t g_dwStackOffset; |
|
uint32_t g_dwRegisterCount = 0; |
|
int g_bRegisterCountValid = 0; |
|
|
|
/********************************************************************** |
|
* Private Variables |
|
**********************************************************************/ |
|
|
|
static const struct regm_opmap_s vrgOpMap1[64] = |
|
{ |
|
/* 0x00: oNOP */ {0, 0, 0, regm_NoOperation}, |
|
/* 0x01: oNEG */ {rRSBI, 0, 0, regm_UnaryOperation}, |
|
/* 0x02: oABS */ {rRSB, 0, 0, regm_UnaryOperation}, |
|
/* 0x03: oINC */ {rADDI, 1, 0, regm_UnaryOperation}, |
|
/* 0x04: oDEC */ {rSUBI, 1, 0, regm_UnaryOperation}, |
|
/* 0x05: oNOT */ {rMVN, 0, 0, regm_UnaryOperation}, |
|
/* 0x06: oADD */ {rADD, 0, 0, regm_BinaryOperation}, |
|
/* 0x07: oSUB */ {rSUB, 0, 0, regm_BinaryOperation}, |
|
/* 0x08: oMUL */ {rMUL, 0, 0, regm_BinaryOperation}, |
|
/* 0x09: oDIV */ {rDIV, 0, 0, regm_BinaryOperation}, |
|
/* 0x0a: oMOD */ {rMOD, 0, 0, regm_BinaryOperation}, |
|
/* 0x0b: oSLL */ {rSLL, 0, 0, regm_BinaryOperation}, |
|
/* 0x0c: oSRL */ {rSRL, 0, 0, regm_BinaryOperation}, |
|
/* 0x0d: oSRA */ {rSRA, 0, 0, regm_BinaryOperation}, |
|
/* 0x0e: oOR */ {rOR, 0, 0, regm_BinaryOperation}, |
|
/* 0x0f: oAND */ {rAND, 0, 0, regm_BinaryOperation}, |
|
|
|
/* 0x10: oEQUZ */ {rBEQ, 0, 0, regm_CompareVsZero}, |
|
/* 0x11: oNEQZ */ {rBNE, 0, 0, regm_CompareVsZero}, |
|
/* 0x12: oLTZ */ {rBLT, 0, 0, regm_CompareVsZero}, |
|
/* 0x13: oGTEZ */ {rBGTE, 0, 0, regm_CompareVsZero}, |
|
/* 0x14: oGTZ */ {rBGT, 0, 0, regm_CompareVsZero}, |
|
/* 0x15: oLTEZ */ {rBLTE, 0, 0, regm_CompareVsZero}, |
|
/* 0x16: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x17: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x18: oEQU */ {rBEQ, 0, 0, regm_BinaryComparison}, |
|
/* 0x19: oNEQ */ {rBNE, 0, 0, regm_BinaryComparison}, |
|
/* 0x1a: oLT */ {rBLT, 0, 0, regm_BinaryComparison}, |
|
/* 0x1b: oGTE */ {rBGTE, 0, 0, regm_BinaryComparison}, |
|
/* 0x1c: oGT */ {rBGT, 0, 0, regm_BinaryComparison}, |
|
/* 0x1d: oLTE */ {rBLTE, 0, 0, regm_BinaryComparison}, |
|
/* 0x1e: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x1f: oBIT */ {rBEQ, 0, 0, regm_BinaryComparison}, |
|
|
|
/* 0x20: oLDI */ {rLD, 2, SPB, regm_LoadImmediate}, |
|
/* 0x21: oLDIH */ {rLDH, 1, SPB, regm_LoadImmediate}, |
|
/* 0x22: oLDIB */ {rLDB, 0, SPB, regm_LoadImmediate}, |
|
/* 0x23: oLDIM */ {0, 0, SPB, regm_LoadMultipleImmediate}, |
|
/* 0x24: oSTI */ {rST, 2, SPB, regm_StoreImmediate}, |
|
/* 0x25: oSTIH */ {rSTH, 1, SPB, regm_StoreImmediate}, |
|
/* 0x26: oSTIB */ {rSTB, 0, SPB, regm_StoreImmediate}, |
|
/* 0x27: oSTIM */ {0, 0, SPB, regm_StoreMultipleImmediate}, |
|
/* 0x28: oDUP */ {0, 0, 0, regm_Duplicate}, |
|
/* 0x17: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x2a: oPUSHS */ {0, 0, CSP, regm_PushSpecial}, |
|
/* 0x2b: oPOPS */ {0, 0, CSP, regm_PopSpecial}, |
|
/* 0x2c: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x2d: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x2e: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x2f: oRET */ {0, 0, 0, regm_Return}, |
|
|
|
/* 0x30: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x31: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x32: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x33: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x34: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x35: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x36: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x37: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x38: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x39: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x3a: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x3b: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x3c: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x3d: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x3e: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x3f: oEND */ {0, 0, 0, regm_Return} |
|
}; |
|
|
|
static const struct regm_opmap_s vrgOpMap2[64] = |
|
{ |
|
/* 0x80: oLD */ {rLD, 2, SPB, regm_LoadOffset}, |
|
/* 0x81: oLDH */ {rLDH, 1, SPB, regm_LoadOffset}, |
|
/* 0x82: oLDB */ {rLDB, 0, SPB, regm_LoadOffset}, |
|
/* 0x83: oLDM */ {0, 0, SPB, regm_LoadMultipleOffset}, |
|
/* 0x84: oST */ {rST, 2, SPB, regm_StoreOffset}, |
|
/* 0x85: oSTH */ {rSTH, 1, SPB, regm_StoreOffset}, |
|
/* 0x86: oSTB */ {rSTB, 0, SPB, regm_StoreOffset}, |
|
/* 0x87: oSTM */ {0, 0, SPB, regm_StoreMultipleOffset}, |
|
/* 0x88: oLDX */ {rLD, 2, SPB, regm_LoadIndexed}, |
|
/* 0x89: oLDXH */ {rLDH, 1, SPB, regm_LoadIndexed}, |
|
/* 0x8a: oLDXB */ {rLDB, 0, SPB, regm_LoadIndexed}, |
|
/* 0x8b: oLDXM */ {0, 0, SPB, regm_LoadMultipleIndexed}, |
|
/* 0x8c: oSTX */ {rST, 2, SPB, regm_StoreIndexed}, |
|
/* 0x8d: oSTXH */ {rSTH, 1, SPB, regm_StoreIndexed}, |
|
/* 0x8e: oSTXB */ {rSTB, 0, SPB, regm_StoreIndexed}, |
|
/* 0x8f: oSTXM */ {0, 0, SPB, regm_StoreMultipleIndexed}, |
|
|
|
/* 0x90: oJEQUZ */ {rBEQ, 0, 0, regm_ConditionalBranchVsZero}, |
|
/* 0x91: oJNEQZ */ {rBNE, 0, 0, regm_ConditionalBranchVsZero}, |
|
/* 0x92: oJLTZ */ {rBLT, 0, 0, regm_ConditionalBranchVsZero}, |
|
/* 0x93: oJGTEZ */ {rBGTE, 0, 0, regm_ConditionalBranchVsZero}, |
|
/* 0x94: oJGTZ */ {rBGT, 0, 0, regm_ConditionalBranchVsZero}, |
|
/* 0x95: oJLTEZ */ {rBLTE, 0, 0, regm_ConditionalBranchVsZero}, |
|
/* 0x96: oJMP */ {rB, 0, 0, regm_UnconditionalBranch}, |
|
/* 0x97: oPUSH */ {0, 0, 0, regm_PushImmediate}, |
|
/* 0x98: oJEQU */ {rBEQ, 0, 0, regm_ConditionalBranchBinary}, |
|
/* 0x99: oJNEQ */ {rBNE, 0, 0, regm_ConditionalBranchBinary}, |
|
/* 0x9a: oJLT */ {rBLT, 0, 0, regm_ConditionalBranchBinary}, |
|
/* 0x9b: oJGTE */ {rBGTE, 0, 0, regm_ConditionalBranchBinary}, |
|
/* 0x9c: oJGT */ {rBGT, 0, 0, regm_ConditionalBranchBinary}, |
|
/* 0x9d: oJLTE */ {rBLTE, 0, 0, regm_ConditionalBranchBinary}, |
|
/* 0x9e: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0x9f: oINDS */ {0, 0, SP, regm_IncrementSpecial}, |
|
|
|
/* 0xa0: oLDS */ {rLD, 2, LSP, regm_LoadOffset}, |
|
/* 0xa1: oLDSH */ {rLDH, 1, LSP, regm_LoadOffset}, |
|
/* 0xa2: oLDSB */ {rLDB, 0, LSP, regm_LoadOffset}, |
|
/* 0xa3: oLDSM */ {0, 0, LSP, regm_LoadMultipleOffset}, |
|
/* 0xa4: oSTS */ {rST, 2, LSP, regm_StoreOffset}, |
|
/* 0xa5: oSTSH */ {rSTH, 1, LSP, regm_StoreOffset}, |
|
/* 0xa6: oSTSB */ {rSTB, 0, LSP, regm_StoreOffset}, |
|
/* 0xa7: oSTSM */ {0, 0, LSP, regm_StoreMultipleOffset}, |
|
/* 0xa8: oLDSX */ {rLD, 2, LSP, regm_LoadIndexed}, |
|
/* 0xa9: oLDSXH */ {rLDH, 1, LSP, regm_LoadIndexed}, |
|
/* 0xaa: oLDSXB */ {rLDB, 0, LSP, regm_LoadIndexed}, |
|
/* 0xab: oLDSXM */ {0, 0, LSP, regm_LoadMultipleIndexed}, |
|
/* 0xac: oSTSX */ {rST, 2, LSP, regm_StoreIndexed}, |
|
/* 0xad: oSTSXH */ {rSTH, 1, LSP, regm_StoreIndexed}, |
|
/* 0xae: oSTSXB */ {rSTB, 0, LSP, regm_StoreIndexed}, |
|
/* 0xaf: oSTSXM */ {0, 0, LSP, regm_StoreMultipleIndexed}, |
|
|
|
/* 0xb0: oLA */ {0, 0, SPB, regm_LoadAddress}, |
|
/* 0xb1: oLAS */ {0, 0, LSP, regm_LoadAddress}, |
|
/* 0xb2: oLAC */ {0, 0, CSB, regm_LoadAddress}, |
|
/* 0xb3: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0xb4: oLAX */ {0, 0, SPB, regm_LoadAddressIndexed}, |
|
/* 0xb5: oLASX */ {0, 0, LSP, regm_LoadAddressIndexed}, |
|
/* 0xb6: oSLSP */ {0, 0, LSP, regm_PopSpecial}, |
|
/* 0xb7: oSDC */ {0, 0, DC, regm_SetDataCount}, |
|
/* 0xb8: */ {0, 0, 0, regm_IllegalPCode}, |
|
/* 0xb9: oPCAL */ {0, 0, 0, regm_PCal}, |
|
/* 0xba: oSYSIO */ {0, 0, 0, regm_SysIo}, |
|
/* 0xbb: oLIB */ {0, 0, 0, regm_LibCall}, |
|
/* 0xbc: oFLOAT */ {0, 0, 0, regm_Float}, |
|
/* 0xbd: oLABEL */ {0, 0, 0, regm_NoOperation}, |
|
/* 0xbe: oINCLUDE*/ {0, 0, 0, regm_NoOperation}, |
|
/* 0xbf: oLINE */ {0, 0, 0, regm_NoOperation} |
|
}; |
|
|
|
static const struct regm_builtin_s g_rgSysIoBuiltIns[MAX_XOP] = |
|
{ |
|
/* 0x00 */ ILLEGAL_BUILTIN_INIT, xEOF_INIT, |
|
/* 0x02 */ xEOLN_INIT, xRESET_INIT, |
|
/* 0x04 */ xREWRITE_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x06 */ ILLEGAL_BUILTIN_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x08 */ ILLEGAL_BUILTIN_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x0a */ ILLEGAL_BUILTIN_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x0c */ ILLEGAL_BUILTIN_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x0e */ ILLEGAL_BUILTIN_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x10 */ xREADLN_INIT, xREAD_PAGE_INIT, |
|
/* 0x12 */ xREAD_BINARY_INIT, xREAD_INT_INIT, |
|
/* 0x14 */ xREAD_CHAR_INIT, xREAD_STRING_INIT, |
|
/* 0x16 */ xREAD_REAL_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x18 */ ILLEGAL_BUILTIN_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x1a */ ILLEGAL_BUILTIN_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x1c */ ILLEGAL_BUILTIN_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x1e */ ILLEGAL_BUILTIN_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x20 */ xWRITELN_INIT, xWRITE_PAGE_INIT, |
|
/* 0x22 */ xWRITE_BINARY_INIT, xWRITE_INT_INIT, |
|
/* 0x24 */ xWRITE_CHAR_INIT, xWRITE_STRING_INIT, |
|
/* 0x25 */ xWRITE_REAL_INIT |
|
}; |
|
|
|
static const struct regm_builtin_s g_rgLibCallBuiltIns[MAX_LBOP] = |
|
{ |
|
/* 0x00 */ lbGETENV_INIT, lbSTR2STR_INIT, |
|
/* 0x02 */ lbCSTR2STR_INIT, lbSTR2RSTR_INIT, |
|
/* 0x04 */ lbCSTR2RSTR_INIT, lbVAL_INIT, |
|
/* 0x06 */ lbMKSTK_INIT, lbMKSTKSTR_INIT, |
|
/* 0x08 */ lbMKSTKC_INIT, lbSTRCAT_INIT, |
|
/* 0x0a */ lbSTRCATC_INIT, lbSTRCMP_INIT |
|
}; |
|
|
|
static const struct regm_builtin_s g_rgRrFopBuiltIns[MAX_FOP] = |
|
{ |
|
/* 0x00 */ ILLEGAL_BUILTIN_INIT, fpFLOAT_INIT, |
|
/* 0x02 */ fpTRUNC_INIT, fpROUND_INIT, |
|
/* 0x04 */ fpADD_RR_INIT, fpSUB_RR_INIT, |
|
/* 0x06 */ fpMUL_RR_INIT, fpDIV_RR_INIT, |
|
/* 0x00 */ fpMOD_RR_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x0a */ fpEQU_RR_INIT, fpNEQ_RR_INIT, |
|
/* 0x0c */ fpLT_RR_INIT, fpGTE_RR_INIT, |
|
/* 0x0e */ fpGT_RR_INIT, fpLTE_RR_INIT, |
|
/* 0x10 */ fpNEG_R_INIT, fpABS_R_INIT, |
|
/* 0x12 */ fpSQR_R_INIT, fpSQRT_R_INIT, |
|
/* 0x14 */ fpSIN_R_INIT, fpCOS_R_INIT, |
|
/* 0x16 */ fpATAN_R_INIT, fpLN_R_INIT, |
|
/* 0x18 */ fpEXP_R_INIT |
|
}; |
|
|
|
static const struct regm_builtin_s g_rgRiFopBuiltIns[MAX_FOP] = |
|
{ |
|
/* 0x00 */ ILLEGAL_BUILTIN_INIT, fpFLOAT_INIT, |
|
/* 0x02 */ fpTRUNC_INIT, fpROUND_INIT, |
|
/* 0x04 */ fpADD_RI_INIT, fpSUB_RI_INIT, |
|
/* 0x06 */ fpMUL_RI_INIT, fpDIV_RI_INIT, |
|
/* 0x00 */ fpMOD_RI_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x0a */ fpEQU_RI_INIT, fpNEQ_RI_INIT, |
|
/* 0x0c */ fpLT_RI_INIT, fpGTE_RI_INIT, |
|
/* 0x0e */ fpGT_RI_INIT, fpLTE_RI_INIT, |
|
/* 0x10 */ fpNEG_I_INIT, fpABS_I_INIT, |
|
/* 0x12 */ fpSQR_I_INIT, fpSQRT_I_INIT, |
|
/* 0x14 */ fpSIN_I_INIT, fpCOS_I_INIT, |
|
/* 0x16 */ fpATAN_I_INIT, fpLN_I_INIT, |
|
/* 0x18 */ fpEXP_I_INIT |
|
}; |
|
|
|
static const struct regm_builtin_s g_rgIrFopBuiltIns[MAX_FOP] = |
|
{ |
|
/* 0x00 */ ILLEGAL_BUILTIN_INIT, fpFLOAT_INIT, |
|
/* 0x02 */ fpTRUNC_INIT, fpROUND_INIT, |
|
/* 0x04 */ fpADD_IR_INIT, fpSUB_IR_INIT, |
|
/* 0x06 */ fpMUL_IR_INIT, fpDIV_IR_INIT, |
|
/* 0x00 */ fpMOD_IR_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x0a */ fpEQU_IR_INIT, fpNEQ_IR_INIT, |
|
/* 0x0c */ fpLT_IR_INIT, fpGTE_IR_INIT, |
|
/* 0x0e */ fpGT_IR_INIT, fpLTE_IR_INIT, |
|
/* 0x10 */ fpNEG_R_INIT, fpABS_R_INIT, |
|
/* 0x12 */ fpSQR_R_INIT, fpSQRT_R_INIT, |
|
/* 0x14 */ fpSIN_R_INIT, fpCOS_R_INIT, |
|
/* 0x16 */ fpATAN_R_INIT, fpLN_R_INIT, |
|
/* 0x18 */ fpEXP_R_INIT |
|
}; |
|
|
|
static const struct regm_builtin_s g_rgIiFopBuiltIns[MAX_FOP] = |
|
{ |
|
/* 0x00 */ ILLEGAL_BUILTIN_INIT, fpFLOAT_INIT, |
|
/* 0x02 */ fpTRUNC_INIT, fpROUND_INIT, |
|
/* 0x04 */ fpADD_II_INIT, fpSUB_II_INIT, |
|
/* 0x06 */ fpMUL_II_INIT, fpDIV_II_INIT, |
|
/* 0x00 */ fpMOD_II_INIT, ILLEGAL_BUILTIN_INIT, |
|
/* 0x0a */ fpEQU_II_INIT, fpNEQ_II_INIT, |
|
/* 0x0c */ fpLT_II_INIT, fpGTE_II_INIT, |
|
/* 0x0e */ fpGT_II_INIT, fpLTE_II_INIT, |
|
/* 0x10 */ fpNEG_I_INIT, fpABS_I_INIT, |
|
/* 0x12 */ fpSQR_I_INIT, fpSQRT_I_INIT, |
|
/* 0x14 */ fpSIN_I_INIT, fpCOS_I_INIT, |
|
/* 0x16 */ fpATAN_I_INIT, fpLN_I_INIT, |
|
/* 0x18 */ fpEXP_I_INIT |
|
}; |
|
|
|
static const struct regm_builtin_s *g_prgFopBuiltIns[4] = |
|
{ |
|
/* Real - Real */ g_rgRrFopBuiltIns, |
|
/* Integer - Real */ g_rgRiFopBuiltIns, |
|
/* Real - Ingeter */ g_rgIrFopBuiltIns, |
|
/* Integer - Integer */ g_rgIiFopBuiltIns |
|
}; |
|
|
|
/********************************************************************** |
|
* Private Functions |
|
**********************************************************************/ |
|
|
|
/***********************************************************************/ |
|
|
|
static void regm_NoOperation(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, struct procdata_s *pNode) |
|
{ |
|
TRACE(stderr, "[regm_NoOperation]"); |
|
|
|
/* Do nothing */ |
|
} |
|
|
|
/***********************************************************************/ |
|
/* These pcodes are all binary operations in the sense that they take |
|
* one input and produce one output: |
|
* |
|
* INPUT: TOS(0) |
|
* OUTPUT: TOS(0) |
|
* Stack is unchanged. |
|
*/ |
|
|
|
static void regm_UnaryOperation(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, struct procdata_s *pNode) |
|
{ |
|
uint32_t dwUnaryRegister = MKCCREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwCcRegister = MKCCREG(g_dwStackOffset); |
|
|
|
TRACE(stderr, "[regm_UnaryOperation]"); |
|
|
|
switch (GETOP(pOpCode)) |
|
{ |
|
case oABS: |
|
regm_GenerateForm1ICc(rCMPI, dwUnaryRegister, 0, dwCcRegister); |
|
regm_GenerateForm4ICc(rBGTE, 2, dwCcRegister); |
|
|
|
default: |
|
regm_GenerateForm3I(pEntry->chOpCode, dwUnaryRegister, |
|
dwUnaryRegister, pEntry->chImmediate); |
|
break; |
|
} |
|
} |
|
|
|
/***********************************************************************/ |
|
/* These pcodes are all binary operations in the sense that they take |
|
* two input: |
|
* |
|
* INPUT: TOS(0), TOS(-1) |
|
* OUTPUT: TOS(0) |
|
* Stack reduced by one. |
|
* |
|
* These all generate form 3r instructions: |
|
*/ |
|
|
|
static void regm_BinaryOperation(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwROperand1 = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwROperand2 = MKREG(g_dwStackOffset - 2*sINT_SIZE); |
|
uint32_t dwRDest = dwROperand2; |
|
|
|
TRACE(stderr, "[regm_BinaryOperation]"); |
|
|
|
/* Generate the binary operation */ |
|
|
|
regm_GenerateForm3R(pEntry->chOpCode, dwRDest, dwROperand1, dwROperand2); |
|
|
|
/* Reduce stack */ |
|
|
|
g_dwStackOffset -= sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* These pcodes are all boolean unary operations in the sense that |
|
* the pcode form takes one input and generates one output: |
|
* |
|
* INPUT: TOS(0) |
|
* OUTPUT: TOS(0) |
|
* Stack unchanged |
|
* |
|
* The complication is that the resulting boolean is not represented by |
|
* data in the register model but, rather, as a condition code setting. |
|
* For now we can, however, force a large number of condition code |
|
* registers; during a later fixup pass, we can force this to a single |
|
* condition code register. |
|
*/ |
|
|
|
static void regm_CompareVsZero(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwUnaryRegister = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwCcRegister = MKCCREG(g_dwStackOffset); |
|
|
|
TRACE(stderr, "[regm_CompareVsZero]"); |
|
|
|
regm_GenerateForm1ICc(rCMPI, dwUnaryRegister, 0, dwCcRegister); |
|
regm_GenerateForm2I(rMOVI, dwUnaryRegister, 0); |
|
regm_GenerateForm4ICc(pEntry->chOpCode, 2, dwCcRegister); |
|
regm_GenerateForm2I(rMOVI, dwUnaryRegister, 1); |
|
} |
|
|
|
/***********************************************************************/ |
|
/* These pcodes are all boolean binary operations in the sense that |
|
* the pcode form takes two inputs and generates one output: |
|
* |
|
* INPUT: TOS(0), TOS(-1) |
|
* OUTPUT: TOS(0) |
|
* Stack reduced by one. |
|
* |
|
* The complication is that the resulting boolean not represented by |
|
* data in the register model but, rather, as a condition code setting. |
|
* For now we can, however, force a large number of condition code |
|
* registers; during a later fixup pass, we can force this to a single |
|
* condition code register. |
|
*/ |
|
|
|
static void regm_BinaryComparison(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwROperand1 = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwROperand2 = MKREG(g_dwStackOffset - 2*sINT_SIZE); |
|
uint32_t dwRDest = dwROperand2; |
|
uint32_t dwCcRegister = MKCCREG(g_dwStackOffset); |
|
|
|
TRACE(stderr, "[regm_BinaryComparison]"); |
|
|
|
|
|
switch (GETOP(pOpCode)) |
|
{ |
|
case oBIT: |
|
regm_GenerateForm3R(rAND, dwRDest, dwROperand1, dwROperand2); |
|
regm_GenerateForm1ICc(rCMPI, dwRDest, 0, dwCcRegister); |
|
break; |
|
|
|
default: |
|
regm_GenerateForm1RCc(rCMP, dwROperand1, dwROperand2, dwCcRegister); |
|
break; |
|
} |
|
|
|
regm_GenerateForm2I(rMOVI, dwRDest, 0); |
|
regm_GenerateForm4ICc(pEntry->chOpCode, 2, dwCcRegister); |
|
regm_GenerateForm2I(rMOVI, dwRDest, 1); |
|
|
|
/* Reduce stack */ |
|
|
|
g_dwStackOffset -= sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Load from the address on the stack. Stack is unchanged */ |
|
|
|
static void regm_LoadImmediate(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwROperand1 = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwRDest = dwROperand1; |
|
|
|
TRACE(stderr, "[regm_LoadImmediate]"); |
|
|
|
/* Use the immediate value as an index against the SPB/LSP */ |
|
|
|
regm_GenerateForm3R(pEntry->chOpCode, dwRDest, dwROperand1, |
|
MKSPECIAL(pEntry->chSpecial)); |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Generic load multiple logic */ |
|
|
|
static void regm_LoadMultiple(uint32_t dwRDest, uint32_t dwRSrc) |
|
{ |
|
TRACE(stderr, "[regm_LoadMultiple]"); |
|
|
|
if (g_bRegisterCountValid) |
|
{ |
|
regm_GenerateForm3I(rLDM, dwRDest, dwRSrc, g_dwRegisterCount); |
|
|
|
/* Adjust the stack for the g_dwRegisterCount values added to the |
|
* stack. |
|
*/ |
|
|
|
g_dwStackOffset += g_dwRegisterCount * sINT_SIZE; |
|
g_bRegisterCountValid = 0; |
|
} |
|
else |
|
{ |
|
fatal(ePOFFCONFUSION); |
|
} |
|
} |
|
|
|
/***********************************************************************/ |
|
/* SPB/LSP relative source offset is on the stack. Stack increase determined |
|
* by content of DC register. |
|
*/ |
|
|
|
static void regm_LoadMultipleImmediate(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRSrc = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwRDest = dwRSrc; |
|
|
|
TRACE(stderr, "[regm_LoadMultipleImmediate]"); |
|
|
|
/* Adjust the src for the SPB/LSP value and generate the multiple load */ |
|
|
|
regm_GenerateForm3R(rADD, dwRSrc, dwRSrc, MKSPECIAL(pEntry->chSpecial)); |
|
regm_LoadMultiple(dwRSrc, dwRDest); |
|
|
|
/* Stack will be increased by an amount determined by DC in |
|
* regm_LoadMultiple. However, we need to also account for the |
|
* immediate stack value that we consume here. |
|
*/ |
|
|
|
g_dwStackOffset -= sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Store value on stack to address on stack. Stack is reduced by two */ |
|
|
|
static void regm_StoreImmediate(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRSrc = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwROperand1 = MKREG(g_dwStackOffset - 2*sINT_SIZE); |
|
|
|
TRACE(stderr, "[regm_StoreImmediate]"); |
|
|
|
/* Use the immediate value as an index against the SPB/LSP */ |
|
|
|
regm_GenerateForm3R(pEntry->chOpCode, dwRSrc, dwROperand1, |
|
MKSPECIAL(pEntry->chSpecial)); |
|
|
|
/* Reduce stack */ |
|
|
|
g_dwStackOffset -= 2*sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Generic store multiple logic */ |
|
|
|
static void regm_StoreMultiple(uint32_t dwRDest, uint32_t dwRSrc) |
|
{ |
|
TRACE(stderr, "[regm_StoreMultiple]"); |
|
|
|
if (g_bRegisterCountValid) |
|
{ |
|
regm_GenerateForm3I(rSTM, dwRSrc, dwRDest, g_dwRegisterCount); |
|
|
|
/* Adjust the stack for the g_dwRegisterCount values added to the |
|
* stack. |
|
*/ |
|
|
|
g_dwStackOffset -= g_dwRegisterCount * sINT_SIZE; |
|
g_bRegisterCountValid = 0; |
|
} |
|
else |
|
{ |
|
fatal(ePOFFCONFUSION); |
|
} |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Store multiple values on stack to address on stack. Stack is reduced |
|
* by an amount determined by the content of DC. |
|
*/ |
|
|
|
static void regm_StoreMultipleImmediate(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRDest = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwRSrc = MKREG(g_dwStackOffset - (g_dwRegisterCount + 1)*sINT_SIZE); |
|
|
|
TRACE(stderr, "[regm_StoreMultipleImmediate]"); |
|
|
|
/* Adjust the src for the SPB/LSP value and generate the multiple load */ |
|
|
|
regm_GenerateForm3R(rADD, dwRDest, dwRDest, MKSPECIAL(pEntry->chSpecial)); |
|
regm_StoreMultiple(dwRSrc, dwRDest); |
|
|
|
/* Stack will be increased by an amount determined by DC in |
|
* regm_StoreMultiple. However, we need to also account for the |
|
* immediate stack value that we consume here. |
|
*/ |
|
|
|
g_dwStackOffset -= sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Duplicate the TOS. stack increases by one */ |
|
|
|
static void regm_Duplicate(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwROperand1 = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwRDest = MKREG(g_dwStackOffset); |
|
|
|
TRACE(stderr, "[regm_Duplicate]"); |
|
|
|
/* Generate the binary operation */ |
|
|
|
regm_GenerateForm2R(rMOV, dwRDest, dwROperand1); |
|
|
|
/* Increment the stack */ |
|
|
|
g_dwStackOffset += sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Put the immediate value at the top of the stack. Increment stack */ |
|
|
|
static void regm_PushImmediate(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRDest = g_dwStackOffset; |
|
|
|
TRACE(stderr, "[regm_PushImmediate]"); |
|
|
|
/* The value may be too large to represent with a MOVI, but we'll handle |
|
* that later. |
|
*/ |
|
|
|
regm_GenerateForm2I(rMOVI, dwRDest, GETARG(pOpCode)); |
|
|
|
/* Increment the stack */ |
|
|
|
g_dwStackOffset += sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Push the special register onto the stack. Stack increments by one */ |
|
|
|
static void regm_PushSpecial(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRDest = g_dwStackOffset; |
|
|
|
TRACE(stderr, "[regm_PushSpecial]"); |
|
|
|
regm_GenerateForm2R(rMOV, dwRDest, MKSPECIAL(pEntry->chSpecial)); |
|
|
|
/* Increment the stack */ |
|
|
|
g_dwStackOffset += sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Pop the TOS into the special register. Stack decrements by one */ |
|
|
|
static void regm_PopSpecial(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwROperand1 = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
|
|
TRACE(stderr, "[regm_PopSpecial]"); |
|
|
|
regm_GenerateForm2R(rMOV, MKSPECIAL(pEntry->chSpecial), dwROperand1); |
|
|
|
/* Decrement the stack */ |
|
|
|
g_dwStackOffset -= sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Save the immediate value in the data count register */ |
|
|
|
static void regm_SetDataCount(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
/* We don't acutally use the DC register. It is an artifact just |
|
* get here. We save the byte count as a even number of registers. |
|
*/ |
|
|
|
g_dwRegisterCount = (GETARG(pOpCode) + 3) >> 2; |
|
g_bRegisterCountValid = 1; |
|
} |
|
|
|
/***********************************************************************/ |
|
|
|
static void regm_Return(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
TRACE(stderr, "[regm_Return]"); |
|
|
|
/* This should have been processed by the prologue/epilogue logic */ |
|
|
|
fatal(ePOFFCONFUSION); |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Load at offset from SPB/LSP. Stack increases by one */ |
|
|
|
static void regm_LoadOffset(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRDest = g_dwStackOffset; |
|
|
|
TRACE(stderr, "[regm_LoadOffset]"); |
|
|
|
/* Use the immediate value as an index against the SPB/LSP */ |
|
|
|
regm_GenerateForm3I(pEntry->chOpCode, dwRDest, MKSPECIAL(pEntry->chSpecial), |
|
GETARG(pOpCode) >> pEntry->chImmediate); |
|
|
|
/* Increment the stack */ |
|
|
|
g_dwStackOffset += sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Load multiple registgers at offset from SPB/LSP. Stack increase depends |
|
* on value in DC (only) |
|
*/ |
|
|
|
static void regm_LoadMultipleOffset(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRSrc = MKREG(g_dwStackOffset); |
|
uint32_t dwRDest = dwRSrc; |
|
|
|
TRACE(stderr, "[regm_LoadMultipleOffset]"); |
|
|
|
regm_GenerateForm3R(rADD, dwRSrc, MKSPECIAL(pEntry->chSpecial), |
|
GETARG(pOpCode)); |
|
regm_LoadMultiple(dwRSrc, dwRDest); |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Store at offset from SPB/LSP. Stack decreases by one */ |
|
|
|
static void regm_StoreOffset(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRSrc = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
|
|
TRACE(stderr, "[regm_StoreOffset]"); |
|
|
|
/* Use the immediate value as an index against the SPB/LSP */ |
|
|
|
regm_GenerateForm3I(pEntry->chOpCode, dwRSrc, |
|
MKSPECIAL(pEntry->chSpecial), |
|
GETARG(pOpCode) >> pEntry->chImmediate); |
|
|
|
/* Decrement the stack */ |
|
|
|
g_dwStackOffset -= sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Store multiple at offset from SPB/LSP. Stack decreases an amount |
|
* determined by the content of the DC regsiter. |
|
*/ |
|
|
|
static void regm_StoreMultipleOffset(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRSrc = MKREG(g_dwStackOffset - g_dwRegisterCount*sINT_SIZE); |
|
uint32_t dwRDest; |
|
|
|
TRACE(stderr, "[regm_StoreMultipleOffset]"); |
|
|
|
regm_GenerateForm3R(rADD, dwRDest, MKSPECIAL(pEntry->chSpecial), |
|
GETARG(pOpCode)); |
|
regm_StoreMultiple(dwRSrc, dwRDest); |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Load value using index on stack + argument + SPB/LSP. Stack is unchanged */ |
|
|
|
static void regm_LoadIndexed(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRIndex = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwRDest = dwRIndex; |
|
|
|
TRACE(stderr, "[regm_LoadIndexed]"); |
|
|
|
/* Add the SPB/LSP to the index to make it relative to the stack, |
|
* then use this with the immediate values to obtain the data. |
|
*/ |
|
|
|
regm_GenerateForm3R(rADD, dwRIndex, dwRIndex, |
|
MKSPECIAL(pEntry->chSpecial)); |
|
regm_GenerateForm3I(pEntry->chOpCode, dwRDest, dwRDest, |
|
GETARG(pOpCode) >> pEntry->chImmediate); |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Load multiple values using index on stack + argument + SPB/LSP. Stack |
|
* will increase my an amount that depends on the contents of DC. |
|
*/ |
|
|
|
static void regm_LoadMultipleIndexed(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRIndex = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwRSrc = dwRIndex; |
|
uint32_t dwRDest = dwRIndex; |
|
|
|
TRACE(stderr, "[regm_LoadMultipleIndexed]"); |
|
|
|
/* Add the SPB/LSP to the index to make it relative to the stack, |
|
* add the offset, then generate the multple load. |
|
*/ |
|
|
|
regm_GenerateForm3R(rADD, dwRSrc, dwRIndex, |
|
MKSPECIAL(pEntry->chSpecial)); |
|
regm_GenerateForm3I(rADDI, dwRSrc, dwRSrc, GETARG(pOpCode)); |
|
regm_LoadMultiple(dwRSrc, dwRDest); |
|
|
|
/* Stack will be increased by an amount determined by DC in |
|
* regm_LoadMultiple. However, we need to also account for the |
|
* index stack value that we consume here. |
|
*/ |
|
|
|
g_dwStackOffset -= sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Store value at TOS to index + offset + SPB/LSP. Stack decreases by two */ |
|
|
|
static void regm_StoreIndexed(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRSrc = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwRIndex = MKREG(g_dwStackOffset - 2*sINT_SIZE); |
|
|
|
TRACE(stderr, "[regm_StoreIndexed]"); |
|
|
|
/* Add the LSP to the index to make it relative to the stack, |
|
* then use this with the immediate values to obtain the data. |
|
*/ |
|
|
|
regm_GenerateForm3R(rADD, dwRIndex, dwRIndex, |
|
MKSPECIAL(pEntry->chSpecial)); |
|
regm_GenerateForm3I(pEntry->chOpCode, dwRSrc, dwRIndex, |
|
GETARG(pOpCode) >> pEntry->chImmediate); |
|
|
|
/* Decrement the stack */ |
|
|
|
g_dwStackOffset -= 2*sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Store values at TOS to index + offset + SPB/LSP. Stack decreases by |
|
* amount determined by the content of the DC register. |
|
*/ |
|
|
|
static void regm_StoreMultipleIndexed(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRIndex = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwRSrc = MKREG(g_dwStackOffset - (g_dwRegisterCount + 1)*sINT_SIZE); |
|
uint32_t dwRDest; |
|
|
|
TRACE(stderr, "[regm_StoreMultipleIndexed]"); |
|
|
|
/* Adjust the src for the SPB/LSP value and generate the multiple load */ |
|
|
|
regm_GenerateForm3R(rADD, dwRDest, dwRIndex, |
|
MKSPECIAL(pEntry->chSpecial)); |
|
regm_GenerateForm3I(rADDI, dwRDest, dwRDest, GETARG(pOpCode)); |
|
regm_StoreMultiple(dwRSrc, dwRDest); |
|
|
|
/* Stack will be increased by an amount determined by DC in |
|
* regm_StoreMultiple. However, we need to also account for the |
|
* immediate stack value that we consume here. |
|
*/ |
|
|
|
g_dwStackOffset -= sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* These pcodes are all conditional branch operations. The pcode form |
|
* takes one input (that is compared with zero) and branches based |
|
* the result. The stack is decremented by one. |
|
*/ |
|
|
|
static void regm_ConditionalBranchVsZero(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwUnaryRegister = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwCcRegister = MKCCREG(g_dwStackOffset); |
|
|
|
TRACE(stderr, "[regm_ConditionalBranchVsZero]"); |
|
|
|
|
|
regm_GenerateForm1ICc(rCMPI, dwUnaryRegister, 0, dwCcRegister); |
|
regm_GenerateForm4ICc(pEntry->chOpCode, GETARG(pOpCode), dwCcRegister); |
|
|
|
/* Decrement the stack */ |
|
|
|
g_dwStackOffset -= sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* These pcodes are all conditional branch operations. The pcode form |
|
* takes two inputs that are compared. The pcode branches on the result |
|
* of the comparison. The stack is reduced by two. |
|
*/ |
|
|
|
static void regm_ConditionalBranchBinary(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwROperand1 = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwROperand2 = MKREG(g_dwStackOffset - 2*sINT_SIZE); |
|
uint32_t dwCcRegister = MKCCREG(g_dwStackOffset); |
|
|
|
TRACE(stderr, "[regm_BinaryComparison]"); |
|
|
|
/* Generate the compare and branch */ |
|
|
|
regm_GenerateForm1RCc(rCMP, dwROperand1, dwROperand2, dwCcRegister); |
|
regm_GenerateForm4ICc(pEntry->chOpCode, GETARG(pOpCode), dwCcRegister); |
|
|
|
/* Reduce stack */ |
|
|
|
g_dwStackOffset -= 2*sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Branch unconditionally. The stack is not changed */ |
|
|
|
static void regm_UnconditionalBranch(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
TRACE(stderr, "[regm_UnconditionalBranch]"); |
|
regm_GenerateForm4I(rB, GETARG(pOpCode)); |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Add constant value to special register. Stack does not change */ |
|
|
|
static void regm_IncrementSpecial(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
int32_t dwIncrement = (int32_t)(GETOP(pOpCode)); |
|
uint32_t dwRSpecial = MKSPECIAL(pEntry->chSpecial); |
|
TRACE(stderr, "[regm_IncrementSpecial]"); |
|
|
|
/* The value may be too large to represent with a MOVI, but we'll handle |
|
* that later. |
|
*/ |
|
|
|
if (dwIncrement < 0) |
|
{ |
|
regm_GenerateForm3I(rSUBI, dwRSpecial, dwRSpecial, -dwIncrement); |
|
} |
|
else if (dwIncrement > 0) |
|
{ |
|
regm_GenerateForm3I(rADDI, dwRSpecial, dwRSpecial, dwIncrement); |
|
} |
|
|
|
if (pEntry->chSpecial == SP) |
|
{ |
|
g_dwStackOffset += dwIncrement; |
|
} |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Load address at offset from special register. Stack increases by one */ |
|
|
|
static void regm_LoadAddress(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRDest = g_dwStackOffset; |
|
|
|
TRACE(stderr, "[regm_LoadAddress]"); |
|
|
|
/* Use the immediate value as an index against the SPB/LSP */ |
|
|
|
regm_GenerateForm3I(rADD, dwRDest, MKSPECIAL(pEntry->chSpecial), |
|
GETARG(pOpCode)); |
|
|
|
/* Increment the stack */ |
|
|
|
g_dwStackOffset += sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
/* Load address at indexed offset from special register. Stack is unchanged */ |
|
|
|
static void regm_LoadAddressIndexed(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
uint32_t dwRIndex = MKREG(g_dwStackOffset - 1*sINT_SIZE); |
|
uint32_t dwRDest = dwRIndex; |
|
|
|
TRACE(stderr, "[regm_LoadAddressIndexed]"); |
|
|
|
/* Add the LSP or SPB to the index to make it relative to the stack, |
|
* then use this with the immediate values to obtain the data. |
|
*/ |
|
|
|
regm_GenerateForm3R(rADD, dwRIndex, dwRIndex, |
|
MKSPECIAL(pEntry->chSpecial)); |
|
regm_GenerateForm3I(rADD, dwRDest, dwRIndex, GETARG(pOpCode)); |
|
} |
|
|
|
/***********************************************************************/ |
|
|
|
static void regm_SetupOutArgs(uint32_t nParms, const uint32_t *pwArgSize) |
|
{ |
|
int nArgRegs; |
|
int32_t dwOffset; |
|
int i; |
|
|
|
for (i = 0, nArgRegs = 0; i < nParms; i++) |
|
{ |
|
nArgRegs += (pwArgSize[i] + 3) >> 2; |
|
} |
|
|
|
/* Emit move instructions to handle each */ |
|
|
|
dwOffset = g_dwStackOffset - sINT_SIZE; |
|
for (i = 0; i < nArgRegs; i++) |
|
{ |
|
uint32_t dwDest = MKOUTARG(i); |
|
uint32_t dwSrc = MKREG(dwOffset); |
|
|
|
regm_GenerateForm2R(rMOV, dwDest, dwSrc); |
|
dwOffset -= sINT_SIZE; |
|
} |
|
} |
|
|
|
/***********************************************************************/ |
|
|
|
static void regm_MapInRet(uint32_t wRetSize) |
|
{ |
|
int nRetRegs; |
|
int32_t dwOffset; |
|
int i; |
|
|
|
/* Get the number of registers that are returned */ |
|
|
|
nRetRegs += (wRetSize + 3) >> 2; |
|
|
|
/* Emit move instructions to handle each */ |
|
#warning "This offset is not correct" |
|
dwOffset = g_dwStackOffset - sINT_SIZE; |
|
for (i = 0; i < nRetRegs; i++) |
|
{ |
|
uint32_t dwSrc = MKINRET(i); |
|
uint32_t dwDest = MKREG(dwOffset); |
|
|
|
regm_GenerateForm2R(rMOV, dwDest, dwSrc); |
|
dwOffset -= sINT_SIZE; |
|
} |
|
} |
|
|
|
/***********************************************************************/ |
|
|
|
static void regm_PCal(const struct regm_opmap_s *pEntry, OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
poffLibDebugFuncInfo_t *pFuncInfo = pNode->pFuncInfo; |
|
|
|
TRACE(stderr, "[regm_PCal]"); |
|
|
|
if (!pFuncInfo) |
|
{ |
|
fatal(ePOFFCONFUSION); |
|
} |
|
|
|
/* Map the "output" parameter stack to a set of "output" argument |
|
* registers. |
|
*/ |
|
|
|
regm_SetupOutArgs(pFuncInfo->nparms, pFuncInfo->argsize); |
|
|
|
regm_GenerateForm3I(rADDI, MKSPECIAL(SP), MKSPECIAL(SP), 3*sINT_SIZE); |
|
regm_GenerateForm3I(rST, MKSPECIAL(LSP), MKSPECIAL(SP), -3); |
|
regm_GenerateForm3I(rST, MKSPECIAL(BRG), MKSPECIAL(SP), -2); |
|
regm_GenerateForm4I(rBL, GETARG(pOpCode)); |
|
|
|
#warning "This is in the wrong place" |
|
regm_MapInRet(pFuncInfo->retsize); |
|
|
|
/* Increment the stack */ |
|
|
|
g_dwStackOffset += 3*sINT_SIZE; |
|
} |
|
|
|
/***********************************************************************/ |
|
|
|
static void regm_SysIo(const struct regm_opmap_s *pEntry, OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
const struct regm_builtin_s *pBuiltIn; |
|
uint32_t xop; |
|
|
|
TRACE(stderr, "[regm_SysIo]"); |
|
|
|
/* Get the function information for this sysio xop */ |
|
|
|
xop = GETARG(pOpCode); |
|
if (xop >= MAX_XOP) |
|
{ |
|
fatal(ePOFFCONFUSION); |
|
} |
|
|
|
pBuiltIn = &g_rgSysIoBuiltIns[xop]; |
|
|
|
/* Map the "output" parameter stack to a set of "output" argument |
|
* registers. |
|
*/ |
|
|
|
regm_SetupOutArgs(pBuiltIn->nParms, pBuiltIn->wArgSize); |
|
|
|
/* Generate a call to the runtime library */ |
|
|
|
#warning "Not implemented" |
|
|
|
/* Handled returned values */ |
|
|
|
regm_MapInRet(pBuiltIn->wRetSize); |
|
} |
|
|
|
/***********************************************************************/ |
|
|
|
static void regm_LibCall(const struct regm_opmap_s *pEntry, OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
const struct regm_builtin_s *pBuiltIn; |
|
uint32_t lbop; |
|
|
|
TRACE(stderr, "[regm_LibCall]"); |
|
|
|
/* Get the function information for this library op */ |
|
|
|
lbop = GETARG(pOpCode); |
|
if (lbop >= MAX_LBOP) |
|
{ |
|
fatal(ePOFFCONFUSION); |
|
} |
|
|
|
pBuiltIn = &g_rgLibCallBuiltIns[lbop]; |
|
|
|
/* Map the "output" parameter stack to a set of "output" argument |
|
* registers. |
|
*/ |
|
|
|
regm_SetupOutArgs(pBuiltIn->nParms, pBuiltIn->wArgSize); |
|
|
|
/* Generate a call to the runtime library */ |
|
|
|
#warning "Not implemented" |
|
|
|
/* Handled returned values */ |
|
|
|
regm_MapInRet(pBuiltIn->wRetSize); |
|
} |
|
|
|
/***********************************************************************/ |
|
|
|
static void regm_Float(const struct regm_opmap_s *pEntry, OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
static const struct regm_builtin_s *pFopBuiltIns; |
|
const struct regm_builtin_s *pBuiltIn; |
|
uint32_t foptab; |
|
uint32_t fop; |
|
|
|
TRACE(stderr, "[regm_FLoat]"); |
|
|
|
/* Select the correct table for the builtin */ |
|
|
|
foptab = (GETARG(pOpCode) & ~fpMASK) >> fpSHIFT; |
|
pFopBuiltIns = g_prgFopBuiltIns[foptab]; |
|
|
|
/* Select the correct function from the table for this floating |
|
* point operation. |
|
*/ |
|
|
|
fop = GETARG(pOpCode) & fpMASK; |
|
if (fop >= MAX_FOP) |
|
{ |
|
fatal(ePOFFCONFUSION); |
|
} |
|
pBuiltIn = &pFopBuiltIns[fop]; |
|
|
|
/* Map the "output" parameter stack to a set of "output" argument |
|
* registers. |
|
*/ |
|
|
|
regm_SetupOutArgs(pBuiltIn->nParms, pBuiltIn->wArgSize); |
|
|
|
/* Generate a call to the runtime library */ |
|
|
|
#warning "Not implemented" |
|
|
|
/* Handled returned values */ |
|
|
|
regm_MapInRet(pBuiltIn->wRetSize); |
|
} |
|
|
|
/***********************************************************************/ |
|
|
|
static void regm_IllegalPCode(const struct regm_opmap_s *pEntry, |
|
OPTYPE *pOpCode, |
|
struct procdata_s *pNode) |
|
{ |
|
TRACE(stderr, "[regm_IllegalPCode]"); |
|
fatal(eILLEGALOPCODE); |
|
} |
|
|
|
/***********************************************************************/ |
|
|
|
static void regm_GenerateRegm(struct procdata_s *pNode, void *pvArg) |
|
{ |
|
int32_t dwFrameSize = 0; |
|
int i, j; |
|
|
|
TRACE(stderr, "[regm_GenerateRegm]"); |
|
|
|
/* Analyze the proc/func prologue */ |
|
|
|
i = 0; j = pNode->nPCodes; |
|
if (GETOP(&pNode->pPCode[0]) == oINDS) |
|
{ |
|
dwFrameSize = GETARG(&pNode->pPCode[0]); |
|
i++; j--; |
|
} |
|
regm_GeneratePrologue(dwFrameSize); |
|
|
|
/* Set the initial stack offset. Parameters will look like |
|
* negative offsets; local stack will look positive. |
|
*/ |
|
|
|
g_dwStackOffset = dwFrameSize; |
|
|
|
/* Generate regm code for each p-code */ |
|
|
|
for (; i < j; i++) |
|
{ |
|
const struct regm_opmap_s *rgOpMap; |
|
uint8_t chOpCode = GETOP(&pNode->pPCode[i]); |
|
|
|
/* Select the right decode table */ |
|
|
|
if ((chOpCode & o32) != 0) |
|
{ |
|
rgOpMap = vrgOpMap2; |
|
chOpCode &= ~o32; |
|
} |
|
else |
|
{ |
|
rgOpMap = vrgOpMap1; |
|
} |
|
|
|
/* Make sure that the table index is within range */ |
|
|
|
if (chOpCode > 63) |
|
{ |
|
fatal(eBADSHORTINT); |
|
} |
|
|
|
/* Perform the opcode mapping */ |
|
|
|
rgOpMap->pMapper(rgOpMap, &pNode->pPCode[i], pNode); |
|
} |
|
|
|
/* If a frame was obtained at the beginning, make sure that |
|
* there is matching frame release logic at the end. |
|
*/ |
|
|
|
if (dwFrameSize > 0) |
|
{ |
|
if ((GETOP(&pNode->pPCode[i]) != oINDS) || |
|
(dwFrameSize != -(int32_t)GETARG(&pNode->pPCode[i]))) |
|
{ |
|
fatal(ePOFFCONFUSION); |
|
} |
|
i++; |
|
} |
|
|
|
/* Analyze the proc/func epilogue */ |
|
|
|
if ((GETOP(&pNode->pPCode[i]) != oRET) && |
|
(GETOP(&pNode->pPCode[i]) != oEND)) |
|
{ |
|
fatal(ePOFFCONFUSION); |
|
} |
|
regm_GenerateEpilogue(dwFrameSize); |
|
} |
|
|
|
/***********************************************************************/ |
|
|
|
static int regm_Pass2Node(struct procdata_s *pNode, void *pvArg) |
|
{ |
|
TRACE(stderr, "[regm_Pass2Node]"); |
|
|
|
/* Generate code for each child of this proc/func block */ |
|
|
|
if (pNode->child) |
|
{ |
|
(void)regm_ForEachChild(pNode->child, regm_Pass2Node, pvArg); |
|
} |
|
|
|
/* Generate code for this node */ |
|
|
|
regm_GenerateRegm(pNode, pvArg); |
|
|
|
/* Does this node have a peer at the same level? If so, then |
|
* do the same for its peer. |
|
*/ |
|
|
|
if (pNode->peer) |
|
{ |
|
(void)regm_Pass2Node(pNode->peer, pvArg); |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
/********************************************************************** |
|
* Public Functions |
|
**********************************************************************/ |
|
|
|
/***********************************************************************/ |
|
/* Pass 2: Convert the buffered pcode to the basic register model with |
|
* an indefinite number of registers (arguments, general, and special |
|
* registers) and with 32-bit immediate size. |
|
*/ |
|
|
|
void regm_Pass2(poffHandle_t hPoff) |
|
{ |
|
TRACE(stderr, "[regm_Pass2]"); |
|
|
|
/* Initiate traversal at the root node */ |
|
|
|
(void)regm_Pass2Node(regm_GetRootNode(), NULL); |
|
} |
|
|
|
/***********************************************************************/ |
|
|
|
|