px4-firmware/misc/pascal/insn16/prun/pexec.c

2376 lines
61 KiB
C
Raw Normal View History

/****************************************************************************
* pexec.c
*
* Copyright (C) 200-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 <sys/types.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "keywords.h"
#include "pdefs.h"
#include "pinsn16.h"
#include "pfdefs.h"
#include "pxdefs.h"
#include "pedefs.h"
#include "paslib.h"
#include "pexec.h"
#ifdef CONFIG_HAVE_LIBM
#include <math.h>
#endif
/****************************************************************************
* Definitions
****************************************************************************/
#define PTRUE ((ustack_t)-1)
#define PFALSE ((ustack_t) 0)
/****************************************************************************
* Macros
****************************************************************************/
/* Remove the value from the top of the stack */
#define POP(st, dest) \
do { \
dest = (st)->dstack.i[BTOISTACK((st)->sp)]; \
(st)->sp -= BPERI; \
} while (0)
/* Add the value to top of the stack */
#define PUSH(st, src) \
do { \
(st)->sp += BPERI; \
(st)->dstack.i[BTOISTACK((st)->sp)] = src; \
} while (0)
/* Return an rvalue for the (word) offset from the top of the stack */
#define TOS(st, off) \
(st)->dstack.i[BTOISTACK((st)->sp)-(off)]
/* Save the src (word) at the dest (word) stack position */
#define PUTSTACK(st, src, dest) \
do { \
(st)->dstack.i[BTOISTACK(dest)] = src; \
} while (0)
/* Return an rvalue for the (word) from the absolute stack position */
#define GETSTACK(st, src) \
(st)->dstack.i[BTOISTACK(src)]
/* Store a byte to an absolute (byte) stack position */
#define PUTBSTACK(st, src,dest) \
do { \
(st)->dstack.b[dest] = dest; \
} while (0)
/* Return an rvalue for the absolute (byte) stack position */
#define GETBSTACK(st, src) \
(st)->dstack.b[src]
/* Return the address for an absolute (byte) stack position. */
#define ATSTACK(st, src) \
&(st)->dstack.b[src]
/* Discard n words from the top of the stack */
#define DISCARD(st, n) \
do { \
(st)->sp -= BPERI*(n); \
} while (0)
/* Release a C string */
#define free_cstring(a) \
free(a)
/****************************************************************************
* Private Type Definitions
****************************************************************************/
union fparg_u
{
double f;
uint16_t hw[4];
};
typedef union fparg_u fparg_t;
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static uint16_t pexec_sysio(struct pexec_s *st, uint8_t fno, uint16_t subfunc);
static uint16_t pexec_libcall(struct pexec_s *st, uint16_t subfunc);
static uint16_t pexec_execfp(struct pexec_s *st, uint8_t fpop);
static void pexec_getfparguments(struct pexec_s *st, uint8_t fpop, fparg_t *arg1, fparg_t *arg2);
static ustack_t pexec_readinteger(uint8_t *ioptr);
static void pexec_readreal(uint16_t *dest, uint8_t *ioptr);
static ustack_t pexec_getbaseaddress(struct pexec_s *st, level_t leveloffset);
static uint8_t *pexec_mkcstring(uint8_t *buffer, int buflen);
/****************************************************************************
* Private Variables
****************************************************************************/
static uint8_t ioline[LINE_SIZE+1];
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: pexec_sysio
*
* Description:
* This function process a system I/O operation.
*
****************************************************************************/
static uint16_t pexec_sysio(struct pexec_s *st, uint8_t fno, uint16_t subfunc)
{
ustack_t uparm1;
fparg_t fp;
uint8_t *ptr;
switch (subfunc)
{
case xEOF :
/* FINISH ME -- > */
break;
case xEOLN :
/* FINISH ME -- > */
break;
case xRESET :
/* FINISH ME -- > */
break;
case xREWRITE :
/* FINISH ME -- > */
break;
case xREADLN :
/* FINISH ME -- > */
break;
case xREAD_BINARY :
/* FINISH ME -- > */
break;
/* xREAD_INT:
* STACK INPUTS: TOS(st, 0) = address to store integer */
case xREAD_INT :
(void)fgets((char*)ioline, LINE_SIZE, stdin);
PUTSTACK(st, pexec_readinteger(ioline),TOS(st, 0));
break;
/* xREAD_CHAR:
* STACK INPUTS: TOS(st, 0) = address to store integer */
case xREAD_CHAR:
(void)fgets((char*)ioline, LINE_SIZE, stdin);
PUTBSTACK(st, ioline[0],TOS(st, 0));
break;
/* XREAD_STRING:
* STACK INPUTS:
* TOS = Number of bytes to read
* TOS-1 = Address to store byte(s) */
case xREAD_STRING :
(void)fgets((char*)ATSTACK(st, TOS(st, 1)), TOS(st, 0), stdin);
break;
/* xREAD_REAL:
* STACK INPUTS: TOS = address to store REAL */
case xREAD_REAL :
(void)fgets((char*)ioline, LINE_SIZE, stdin);
pexec_readreal((uint16_t*)ATSTACK(st, TOS(st, 0)), ioline);
break;
case xWRITELN :
putchar('\n');
break;
case xWRITE_PAGE :
putchar('\f');
break;
case xWRITE_BINARY :
/* FINISH ME -- > */
break;
/* xWRITE_INT:
* STACK INPUTS: TOS = integer value to write. */
case xWRITE_INT :
printf("%ld", signExtend16(TOS(st, 0)));
break;
/* xWRITE_CHAR:
* STACK INPUTS: TOS = char value to write. */
case xWRITE_CHAR :
putchar(TOS(st, 0));
break;
/* xWRITE_STRING:
* STACK INPUTS:
* TOS = Number of bytes to write
* TOS-1 = Address of src data */
case xWRITE_STRING :
uparm1 = TOS(st, 0);
for (ptr = (uint8_t*)ATSTACK(st, TOS(st, 1)); uparm1; uparm1--, ptr++)
putchar(*ptr);
break;
/* xWRITE_REAL:
* STACK INPUTS: TOS = value of double */
case xWRITE_REAL :
fp.hw[0] = TOS(st, 3);
fp.hw[1] = TOS(st, 2);
fp.hw[2] = TOS(st, 1);
fp.hw[3] = TOS(st, 0);;
printf("%f", fp.f);
break;
default :
return eBADSYSIOFUNC;
}
return eNOERROR;
} /* end pexec_sysio */
/****************************************************************************
* Name: pexec_libcall
*
* Description:
* This function process a system I/O operation
*
****************************************************************************/
static uint16_t pexec_libcall(struct pexec_s *st, uint16_t subfunc)
{
ustack_t uparm1;
ustack_t uparm2;
paddr_t addr1;
paddr_t addr2;
uint16_t *tmp;
uint16_t *ref;
uint8_t *src;
uint8_t *dest;
uint8_t *name;
int len;
int32_t value;
switch (subfunc)
{
/* Get the value of an environment string
*
* ON INPUT:
* TOS(st, 0) = Number of bytes in environment identifier string
* TOS(st, 1) = Address environment identifier string
* ON RETURN (above replaced with):
* TOS(st, 0) = MS 16-bits of 32-bit C string pointer
* TOS(st, 1) = LS 16-bits of 32-bit C string pointer
*/
case lbGETENV :
len = TOS(st, 0); /* Number of bytes in string */
src = (uint8_t*)&GETSTACK(st, TOS(st, 1)); /* Pointer to string */
/* Make a C string out of the pascal string */
name = pexec_mkcstring(src, len);
if (name == NULL)
{
return eNOMEMORY;
}
/* Make the C-library call and free the string copy */
src = (uint8_t*)getenv((char*)name);
free_cstring(name);
/* Save the returned pointer in the stack */
TOS(st, 0) = (ustack_t)((uint32_t)src >> 16);
TOS(st, 1) = (ustack_t)((uint32_t)src & 0x0000ffff);
break;
/* Copy pascal string to a pascal string
*
* ON INPUT:
* TOS(st, 0) = address of dest string hdr
* TOS(st, 1) = length of source string
* TOS(st, 2) = pointer to source string
* ON RETURN (input consumed):
*/
case lbSTR2STR :
/* "Pop" in the input parameters from the stack */
POP(st, addr1); /* addr of dest string header */
POP(st, uparm1); /* length of source data */
POP(st, addr2); /* addr of source string data */
/* Do nothing if the source and destinations are the same
* string. This happens normally on cases like:
* string name;
* char c;
* name := name + c;
*/
if (addr1 != addr2)
{
/* The source and destination strings are different.
* Make sure that the string length will fit into the destination.
*/
if (uparm1 >= sSTRING_MAX_SIZE)
{
/* Clip to the maximum size */
uparm1 = sSTRING_MAX_SIZE;
len = sSTRING_MAX_SIZE;
}
else
{
/* We have space */
len = (int)uparm1;
}
/* Get proper string pointers */
dest = ATSTACK(st, addr1);
src = ATSTACK(st, addr2);
/* Transfer the (16-bit) string length (must be aligned!) */
tmp = (uint16_t*)dest;
*tmp++ = uparm1;
dest = (uint8_t*)tmp;
/* Then transfer the string contents */
memcpy(dest, src, len);
}
break;
/* Copy C string to a pascal string
*
* ON INPUT:
* TOS(st, 0) = address of dest hdr
* TOS(st, 1) = MS 16-bits of 32-bit C string pointer
* TOS(st, 2) = LS 16-bits of 32-bit C string pointer
* ON RETURN (input consumed):
*/
case lbCSTR2STR :
/* "Pop" in the input parameters from the stack */
POP(st, addr1); /* addr of dest string header */
POP(st, uparm1); /* MS 16-bits of 32-bit C string pointer */
POP(st, uparm2); /* LS 16-bits of 32-bit C string pointer */
/* Get proper string pointers */
dest = ATSTACK(st, addr1);
src = (uint8_t*)((unsigned long)uparm1 << 16 | (unsigned long)uparm2);
/* Handle null src pointer */
if (src == NULL)
{
*dest = 0;
}
else
{
/* Get the length of the string */
uparm1 = strlen((char*)src);
/* Make sure that the string length will fit into the
* destination. */
if (uparm1 >= sSTRING_MAX_SIZE)
{
/* Clip to the maximum size */
uparm1 = sSTRING_MAX_SIZE;
len = sSTRING_MAX_SIZE;
}
else
{
/* We have space */
len = (int)uparm1;
}
/* Transfer the (16-bit) string length (must be aligned!) */
tmp = (uint16_t*)dest;
*tmp++ = uparm1;
dest = (uint8_t*)tmp;
/* Then transfer the string contents */
memcpy(dest, src, len);
}
break;
/* Copy pascal string to a pascal string reference
* procedure str2rstr(src : string; var dest : rstring)
* ON INPUT:
* TOS(st, 0)=address of dest string reference
* TOS(st, 1)=length of source string
* TOS(st, 2)=pointer to source string
* ON RETURN: actual parameters released.
*/
case lbSTR2RSTR :
/* "Pop" in the input parameters from the stack */
POP(st, addr1); /* addr of dest string reference */
POP(st, uparm1); /* length of source data */
POP(st, addr2); /* addr of source string data */
/* Make sure that the string length will fit into the destination. */
if (uparm1 >= sSTRING_MAX_SIZE)
{
return eSTRSTKOVERFLOW;
}
/* Get a pointer to the destination reference */
ref = (uint16_t*)ATSTACK(st, addr1);
/* Get proper string pointers */
dest = ATSTACK(st, ref[0] - 2);
src = ATSTACK(st, addr2);
/* Transfer the (16-bit) string length (must be aligned!) */
tmp = (uint16_t*)dest;
*tmp++ = uparm1;
dest = (uint8_t*)tmp;
/* Then transfer the string contents and save the new size */
memcpy(dest, src, uparm1);
ref[1] = uparm1;
break;
/* Copy C string to a pascal string reference
* procedure cstr2str(src : cstring; var dest : string)
* ON INPUT:
* TOS(st, 0)=address of dest string reference
* TOS(st, 0)=MS 16-bits of 32-bit C source string pointer
* TOS(st, 1)=LS 16-bits of 32-bit C source string pointer
* ON RETURN: actual parameters released
*/
case lbCSTR2RSTR :
/* "Pop" in the input parameters from the stack */
POP(st, addr1); /* addr of dest string reference */
POP(st, uparm1); /* MS 16-bits of 32-bit C string pointer */
POP(st, uparm2); /* LS 16-bits of 32-bit C string pointer */
/* Get a pointer to the destination reference */
ref = (uint16_t*)ATSTACK(st, addr1);
/* Get proper string pointers */
dest = ATSTACK(st, ref[0] - 2);
src = (uint8_t*)((unsigned long)uparm1 << 16 | (unsigned long)uparm2);
/* Handle null src pointer */
if (src == NULL)
{
*dest = 0;
}
else
{
/* Get the length of the string */
uparm1 = strlen((char*)src);
/* Make sure that the string length will fit into the
* destination. */
if (uparm1 >= sSTRING_MAX_SIZE)
{
return eSTRSTKOVERFLOW;
}
/* Transfer the (16-bit) string length (must be aligned!) */
tmp = (uint16_t*)dest;
*tmp++ = uparm1;
dest = (uint8_t*)tmp;
/* Then transfer the string contents */
memcpy(dest, src, uparm1);
ref[1] = uparm1;
}
break;
/* Convert a string to a numeric value
* procedure val(const s : string; var v; var code : word);
*
* Description:
* val() converts the value represented in the string S to a numerical
* value, and stores this value in the variable V, which can be of type
* Longint, Real and Byte. If the conversion isn't succesfull, then the
* parameter Code contains the index of the character in S which
* prevented the conversion. The string S is allowed to contain spaces
* in the beginning.
*
* The string S can contain a number in decimal, hexadecimal, binary or
* octal format, as described in the language reference.
*
* Errors:
* If the conversion doesn¡Çt succeed, the value of Code indicates the
* position where the conversion went wrong.
*
* ON INPUT
* TOS(st, 0)=address of code
* TOS(st, 1)=address of value
* TOS(st, 2)=length of source string
* TOS(st, 3)=pointer to source string
* ON RETURN: actual parameters released
*/
case lbVAL :
/* Get the string information */
len = TOS(st, 2); /* Number of bytes in string */
src = (uint8_t*)&GETSTACK(st, TOS(st, 3)); /* Pointer to string */
/* Make a C string out of the pascal string */
name = pexec_mkcstring(src, len);
if (name == NULL)
{
return eNOMEMORY;
}
/* Convert the string to an integer */
value = atoi((char*)name);
if ((value < MININT) || (value > MAXINT))
{
return eINTEGEROVERFLOW;
}
PUTSTACK(st, TOS(st, 0), 0);
PUTSTACK(st, TOS(st, 1), value);
DISCARD(st, 4);
break;
/* Create an empty string
* function mkstk : string;
* ON INPUT
* ON RETURN
* TOS(st, 0)=length of new string
* TOS(st, 1)=pointer to new string
*/
case lbMKSTK :
/* Allocate space on the string stack for the new string
* FIXME: This logic does not handle strings with other than the
* default size!
*/
addr1 = ((st->csp + 1) & ~1);
st->csp += sSTRING_SIZE; /* Allocate max size */
/* Save the length at the beginning of the copy */
tmp = (uint16_t*)&GETSTACK(st, addr1); /* Pointer to new string */
*tmp++ = 0; /* Save current size */
/* Update the stack content */
PUSH(st, addr1 + sSTRING_HDR_SIZE); /* Pointer to new string */
PUSH(st, 0); /* Current size */
break;
/* Replace a string with a duplicate string residing in allocated
* string stack.
* function mkstkstr(name : string) : string;
* ON INPUT
* TOS(st, 0)=length of original string
* TOS(st, 1)=pointer to original string data
* ON RETURN
* TOS(st, 0)=length of new string (unchanged)
* TOS(st, 1)=pointer to new string data
*/
case lbMKSTKSTR :
/* Get the parameters from the stack (leaving the string reference
* in place.
*/
uparm1 = TOS(st, 0); /* Original string size */
addr1 = TOS(st, 1); /* Original string data pointer */
/* Check if there is space on the string stack for the new string
* FIXME: This logic does not handle strings with other than the
* default size!
*/
if (st->csp + sSTRING_SIZE >= st->spb)
{
return eSTRSTKOVERFLOW;
}
/* Allocate space on the string stack for the new string */
addr2 = ((st->csp + 1) & ~1);
st->csp += sSTRING_SIZE; /* Allocate max size */
/* Save the length at the beginning of the copy */
tmp = (uint16_t*)&GETSTACK(st, addr2); /* Pointer to new string */
*tmp++ = uparm1; /* Save current size */
dest = (uint8_t*)tmp; /* Pointer to string data */
/* Copy the string into the string stack */
src = (uint8_t*)&GETSTACK(st, addr1); /* Pointer to original string */
memcpy(dest, src, uparm1);
/* Update the stack content */
TOS(st, 1) = addr2 + sSTRING_HDR_SIZE;
break;
/* Replace a character with a string residing in allocated string stack.
* function mkstkc(c : char) : string;
* ON INPUT
* TOS(st, 0)=Character value
* ON RETURN
* TOS(st, 0)=length of new string
* TOS(st, 1)=pointer to new string
*/
case lbMKSTKC :
/* Check if there is space on the string stack for the new string
* FIXME: This logic does not handle strings with other than the
* default size!
*/
if (st->csp + sSTRING_SIZE >= st->spb)
{
return eSTRSTKOVERFLOW;
}
/* Allocate space on the string stack for the new string */
addr2 = ((st->csp + 1) & ~1);
st->csp += sSTRING_SIZE; /* Allocate max size */
/* Save the length at the beginning of the copy */
tmp = (uint16_t*)&GETSTACK(st, addr2); /* Pointer to new string */
*tmp++ = 1; /* Save initial size */
dest = (uint8_t*)tmp; /* Pointer to string data */
/* Copy the character into the string stack */
*dest++ = TOS(st, 0); /* Save character as string */
/* Update the stack content */
TOS(st, 0) = addr2 + sSTRING_HDR_SIZE; /* String address */
PUSH(st, 1); /* String length */
break;
/* Concatenate a string to the end of a string.
* function strcat(name : string, c : char) : string;
*
* ON INPUT
* TOS(st, 0)=length of string1
* TOS(st, 1)=pointer to string1 data
* TOS(st, 2)=length of string2
* TOS(st, 3)=pointer to string2 data
* ON OUTPUT
* TOS(st, 1)=new length of string2
* TOS(st, 2)=pointer to string2
*/
case lbSTRCAT :
/* Get the parameters from the stack (leaving the string reference
* in place.
*/
POP(st, uparm1); /* string1 size */
POP(st, addr1); /* string1 data stack addr */
uparm2 = TOS(st, 0); /* string2 size */
/* Check for string overflow. FIXME: This logic does not handle
* strings with other than the default size!
*/
if (uparm1 + uparm2 > sSTRING_MAX_SIZE)
return eSTRSTKOVERFLOW;
else
{
/* Get a pointer to string1 data */
src = ATSTACK(st, addr1);
/* Get a pointer to string2 header, set new size then, get
* a pointer to string2 data.
*/
tmp = ((uint16_t*)&GETSTACK(st, TOS(st, 1))) - 1;
*tmp++ = uparm1 + uparm2;
dest = (uint8_t*)tmp;
memcpy(&dest[uparm2], src, uparm1); /* cat strings */
TOS(st, 0) = uparm1 + uparm2; /* Save new size */
}
break;
/* Concatenate a character to the end of a string.
* function strcatc(name : string, c : char) : string;
*
* ON INPUT
* TOS(st, 0)=character to concatenate
* TOS(st, 1)=length of string
* TOS(st, 2)=pointer to string
* ON OUTPUT
* TOS(st, 1)=new length of string
* TOS(st, 2)=pointer to string
*/
case lbSTRCATC :
/* Get the parameters from the stack (leaving the string reference
* in place.
*/
POP(st, uparm1); /* Character to concatenate */
uparm2 = TOS(st, 0); /* Current length of string */
/* Check for string overflow. FIXME: This logic does not handle
* strings with other than the default size!
*/
if (uparm2 >= sSTRING_MAX_SIZE)
return eSTRSTKOVERFLOW;
else
{
/* Get a pointer to string header, set size new size then, get
* a pointer to string data.
*/
tmp = ((uint16_t*)&GETSTACK(st, TOS(st, 1))) - 1;
*tmp++ = uparm2 + 1;
dest = (uint8_t*)tmp;
/* Add the new charcter */
dest[uparm2] = (uint8_t)uparm1;
/* Save the new string size */
TOS(st, 0) = uparm2 + 1;
}
break;
/* Compare two pascal strings
* function strcmp(name1 : string, name2 : string) : integer;
* ON INPUT
* TOS(st, 1)=length of string2
* TOS(st, 2)=address of string2 data
* TOS(st, 3)=length of string1
* TOS(st, 4)=address of string1 data
* ON OUTPUT
* TOS(st, 0)=(-1=less than, 0=equal, 1=greater than}
*/
case lbSTRCMP :
{
int result;
/* Get the parameters from the stack (leaving space for the
* return value);
*/
POP(st, uparm2); /* length of string2 */
POP(st, addr2); /* address of string2 data */
POP(st, uparm1); /* length of string1 */
addr1 = TOS(st, 0); /* address of string1 data */
/* Get full address */
dest = ATSTACK(st, addr1);
src = ATSTACK(st, addr2);
/* If name1 is shorter than name2, then we can only return
* -1 (less than) or +1 greater than. If the substrings
* of length of name1 are equal, then we return less than.
*/
if (uparm1 < uparm2)
{
result = memcmp(dest, src, uparm1);
if (result == 0) result = -1;
}
/* If name1 is longer than name2, then we can only return
* -1 (less than) or +1 greater than. If the substrings
* of length of name2 are equal, then we return greater than.
*/
else if (uparm1 > uparm2)
{
result = memcmp(dest, src, uparm2);
if (result == 0) result = 1;
}
/* The strings are of equal length. Return the result of
* the comparison.
*/
else
{
result = memcmp(dest, src, uparm1);
}
TOS(st, 0) = result;
}
break;
default :
return eBADSYSLIBCALL;
}
return eNOERROR;
} /* end pexec_libcall */
/****************************************************************************
* Name: pexec_execfp
*
* Description:
* This function processes a floating point operation.
*
****************************************************************************/
static uint16_t pexec_execfp(struct pexec_s *st, uint8_t fpop)
{
int16_t intValue;
fparg_t arg1;
fparg_t arg2;
fparg_t result;
switch (fpop & fpMASK)
{
/* Floating Pointer Conversions (On stack argument: FP or Integer) */
case fpFLOAT :
POP(st, intValue);
result.f = (double)intValue;
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
case fpTRUNC :
case fpROUND :
pexec_getfparguments(st, fpop, &arg1, NULL);
intValue = (int16_t)arg1.f;
PUSH(st, intValue);
break;
/* Floating Point arithmetic instructions (Two FP stack arguments) */
case fpADD :
pexec_getfparguments(st, fpop, &arg1, &arg2);
result.f = arg1.f + arg2.f;
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
case fpSUB :
pexec_getfparguments(st, fpop, &arg1, &arg2);
result.f = arg1.f - arg2.f;
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
case fpMUL :
pexec_getfparguments(st, fpop, &arg1, &arg2);
result.f = arg1.f * arg2.f;
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
case fpDIV :
pexec_getfparguments(st, fpop, &arg1, &arg2);
result.f = arg1.f / arg2.f;
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
case fpMOD :
return eBADFPOPCODE;
#if 0 /* Not yet */
pexec_getfparguments(st, fpop, &arg1, &arg2);
result.f = arg1.f % arg2.f;
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
#endif
/* Floating Point Comparisons (Two FP stack arguments) */
case fpEQU :
pexec_getfparguments(st, fpop, &arg1, &arg2);
intValue = PFALSE;
if (arg1.f == arg2.f)
intValue = PTRUE;
PUSH(st, intValue);
break;
case fpNEQ :
pexec_getfparguments(st, fpop, &arg1, &arg2);
intValue = PFALSE;
if (arg1.f != arg2.f)
intValue = PTRUE;
PUSH(st, intValue);
break;
case fpLT :
pexec_getfparguments(st, fpop, &arg1, &arg2);
intValue = PFALSE;
if (arg1.f < arg2.f)
intValue = PTRUE;
PUSH(st, intValue);
break;
case fpGTE :
pexec_getfparguments(st, fpop, &arg1, &arg2);
intValue = PFALSE;
if (arg1.f >= arg2.f)
intValue = PTRUE;
PUSH(st, intValue);
break;
case fpGT :
pexec_getfparguments(st, fpop, &arg1, &arg2);
intValue = PFALSE;
if (arg1.f > arg2.f)
intValue = PTRUE;
PUSH(st, intValue);
break;
case fpLTE :
pexec_getfparguments(st, fpop, &arg1, &arg2);
intValue = PFALSE;
if (arg1.f <= arg2.f)
intValue = PTRUE;
PUSH(st, intValue);
break;
/* Floating Point arithmetic instructions (One FP stack arguments) */
case fpNEG :
pexec_getfparguments(st, fpop, &arg1, NULL);
result.f = -arg1.f;
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
#ifdef CONFIG_HAVE_LIBM
case fpABS :
pexec_getfparguments(st, fpop, &arg1, NULL);
result.f = fabs(arg1.f);
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
#endif
case fpSQR :
pexec_getfparguments(st, fpop, &arg1, NULL);
result.f = arg1.f * arg1.f;
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
#ifdef CONFIG_HAVE_LIBM
case fpSQRT :
pexec_getfparguments(st, fpop, &arg1, NULL);
result.f = sqrt(arg1.f);
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
case fpSIN :
pexec_getfparguments(st, fpop, &arg1, NULL);
result.f = sin(arg1.f);
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
case fpCOS :
pexec_getfparguments(st, fpop, &arg1, NULL);
result.f = cos(arg1.f);
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
case fpATAN :
pexec_getfparguments(st, fpop, &arg1, NULL);
result.f = atan(arg1.f);
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
case fpLN :
pexec_getfparguments(st, fpop, &arg1, NULL);
result.f = log(arg1.f);
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
case fpEXP :
pexec_getfparguments(st, fpop, &arg1, NULL);
result.f = exp(arg1.f);
PUSH(st, result.hw[0]);
PUSH(st, result.hw[1]);
PUSH(st, result.hw[2]);
PUSH(st, result.hw[3]);
break;
#endif
default :
return eBADFPOPCODE;
}
return eNOERROR;
} /* end pexec_execfp */
/****************************************************************************
* Name: pexec_getfparguments
*
* Description:
* This function retrieves the floating point arguments and performs
* integer to REAL conversions as necessary
*
****************************************************************************/
static void pexec_getfparguments(struct pexec_s *st, uint8_t fpop, fparg_t *arg1, fparg_t *arg2)
{
int16_t sparm;
/* Extract arg2 from the stack */
if (arg2)
{
/* Convert an integer argument to type REAL */
if ((fpop & fpARG2) != 0)
{
POP(st, sparm);
arg2->f = (double)sparm;
}
else
{
POP(st, arg2->hw[3]);
POP(st, arg2->hw[2]);
POP(st, arg2->hw[1]);
POP(st, arg2->hw[0]);
}
}
/* Extract arg1 from the stack */
if (arg1)
{
/* Convert an integer argument to type REAL */
if ((fpop & fpARG1) != 0)
{
POP(st, sparm);
arg1->f = (double)sparm;
}
else
{
POP(st, arg1->hw[3]);
POP(st, arg1->hw[2]);
POP(st, arg1->hw[1]);
POP(st, arg1->hw[0]);
}
}
} /* end pexec_getfparguments */
/****************************************************************************
* Name: pexec_readinteger
*
* Description:
* This function parses a decimal integer from ioptr
****************************************************************************/
static ustack_t pexec_readinteger(uint8_t *ioptr)
{
sstack_t value = 0;
while (isspace(*ioptr)) ioptr++;
while ((*ioptr >= '0') && (*ioptr <= '9'))
{
value = 10*value
+ (sstack_t)(*ioptr)
- (sstack_t)'0';
ioptr++;
}
return (ustack_t)value;
} /* end pexec_readinteger */
/****************************************************************************
* Name: pexec_readreal
*
* Description:
* This function parses a decimal integer from ioptr.
*
****************************************************************************/
static void pexec_readreal(uint16_t *dest, uint8_t *inPtr)
{
int32_t intpart;
fparg_t result;
double fraction;
uint8_t unaryop;
intpart = 0;
unaryop = '+';
/* Check for a leading unary - */
if ((*inPtr == '-') || (*inPtr == '+'))
unaryop = *inPtr++;
/* Get the integer part of the real */
while ((*inPtr >= '0') && (*inPtr <= '9'))
intpart = 10*intpart + ((int32_t)*inPtr++) - ((int32_t)'0');
result.f = ((double)intpart);
/* Check for the a fractional part */
if (*inPtr == '.')
{
inPtr++;
fraction = 0.1;
while ((*inPtr >= '0') && (*inPtr <= '9'))
{
result.f += fraction * (double)(((int32_t)*inPtr++) - ((int32_t)'0'));
fraction /= 10.0;
}
}
/* Correct the sign of the result */
if (unaryop == '-')
result.f = -result.f;
/* Return the value into the P-Machine stack */
*dest++ = result.hw[0];
*dest++ = result.hw[1];
*dest++ = result.hw[2];
*dest = result.hw[3];
} /* end pexec_readreal */
/****************************************************************************
* Name: pexec_getbaseaddress
*
* Description:
* This function binds the base address corresponding to a given level
* offset.
*
****************************************************************************/
static ustack_t pexec_getbaseaddress(struct pexec_s *st, level_t leveloffset)
{
/* Start with the base register of the current frame */
ustack_t baseAddress = st->fp;
/* Search backware "leveloffset" frames until the correct frame is
* found
*/
while (leveloffset > 0)
{
baseAddress = st->dstack.i[BTOISTACK(baseAddress)];
leveloffset--;
}
/* Offset that value by two words (one for the st->fp and one for the
* return value
*/
return baseAddress + 2*BPERI;
} /* end pexec_getbaseaddress */
/****************************************************************************
* Name: pexec_mkcstring
****************************************************************************/
static uint8_t *pexec_mkcstring(uint8_t *buffer, int buflen)
{
uint8_t *string;
string = malloc(buflen + 1);
if (string != NULL)
{
memcpy(string, buffer, buflen);
string[buflen] = '\0';
}
return string;
}
/****************************************************************************
* Name: pexec8
*
* Descripton:
* Handle 8-bit instructions with no immediate data
*
****************************************************************************/
static inline int pexec8(FAR struct pexec_s *st, uint8_t opcode)
{
sstack_t sparm;
ustack_t uparm1;
ustack_t uparm2;
ustack_t uparm3;
switch (opcode)
{
/* Arithmetic & logical & and integer conversions (One stack argument) */
case oNEG :
TOS(st, 0) = (ustack_t)(-(sstack_t)TOS(st, 0));
break;
case oABS :
if (signExtend16(TOS(st, 0)) < 0)
{
TOS(st, 0) = (ustack_t)(-signExtend16(TOS(st, 0)));
}
break;
case oINC :
TOS(st, 0)++;
break;
case oDEC :
TOS(st, 0)--;
break;
case oNOT :
TOS(st, 0) = ~TOS(st, 0);
break;
/* Arithmetic & logical (Two stack arguments) */
case oADD :
POP(st, sparm);
TOS(st, 0) = (ustack_t)(((sstack_t)TOS(st, 0)) + sparm);
break;
case oSUB :
POP(st, sparm);
TOS(st, 0) = (ustack_t)(((sstack_t)TOS(st, 0)) - sparm);
break;
case oMUL :
POP(st, sparm);
TOS(st, 0) = (ustack_t)(((sstack_t)TOS(st, 0)) * sparm);
break;
case oDIV :
POP(st, sparm);
TOS(st, 0) = (ustack_t)(((sstack_t)TOS(st, 0)) / sparm);
break;
case oMOD :
POP(st, sparm);
TOS(st, 0) = (ustack_t)(((sstack_t)TOS(st, 0)) % sparm);
break;
case oSLL :
POP(st, sparm);
TOS(st, 0) = (ustack_t)(((sstack_t)TOS(st, 0)) << sparm);
break;
case oSRL :
POP(st, sparm);
TOS(st, 0) = (TOS(st, 0) >> sparm);
break;
case oSRA :
POP(st, sparm);
TOS(st, 0) = (ustack_t)(((sstack_t)TOS(st, 0)) >> sparm);
break;
case oOR :
POP(st, uparm1);
TOS(st, 0) = (TOS(st, 0) | uparm1);
break;
case oAND :
POP(st, uparm1);
TOS(st, 0) = (TOS(st, 0) & uparm1);
break;
case oBIT :
POP(st, uparm1);
uparm2 = TOS(st, 0);
if ((uparm1 & (1 << uparm2)) != 0)
{
TOS(st, 0) = PTRUE;
}
else
{
TOS(st, 0) = PFALSE;
}
break;
/* Comparisons (One stack argument) */
case oEQUZ :
POP(st, sparm);
uparm1 = PFALSE;
if (sparm == 0)
{
uparm1 = PTRUE;
}
PUSH(st, uparm1);
break;
case oNEQZ :
POP(st, sparm);
uparm1 = PFALSE;
if (sparm != 0)
{
uparm1 = PTRUE;
}
PUSH(st, uparm1);
break;
case oLTZ :
POP(st, sparm);
uparm1 = PFALSE;
if (sparm < 0)
{
uparm1 = PTRUE;
}
PUSH(st, uparm1);
break;
case oGTEZ :
POP(st, sparm);
uparm1 = PFALSE;
if (sparm >= 0)
{
uparm1 = PTRUE;
}
PUSH(st, uparm1);
break;
case oGTZ :
POP(st, sparm);
uparm1 = PFALSE;
if (sparm > 0)
{
uparm1 = PTRUE;
}
PUSH(st, uparm1);
break;
case oLTEZ :
POP(st, sparm);
uparm1 = PFALSE;
if (sparm <= 0)
{
uparm1 = PTRUE;
}
PUSH(st, uparm1);
break;
/* Comparisons (Two stack arguments) */
case oEQU :
POP(st, sparm);
uparm1 = PFALSE;
if (sparm == (sstack_t)TOS(st, 0))
{
uparm1 = PTRUE;
}
TOS(st, 0) = uparm1;
break;
case oNEQ :
POP(st, sparm);
uparm1 = PFALSE;
if (sparm != (sstack_t)TOS(st, 0))
{
uparm1 = PTRUE;
}
TOS(st, 0) = uparm1;
break;
case oLT :
POP(st, sparm);
uparm1 = PFALSE;
if (sparm < (sstack_t)TOS(st, 0))
{
uparm1 = PTRUE;
}
TOS(st, 0) = uparm1;
break;
case oGTE :
POP(st, sparm);
uparm1 = PFALSE;
if (sparm >= (sstack_t)TOS(st, 0))
{
uparm1 = PTRUE;
}
TOS(st, 0) = uparm1;
break;
case oGT :
POP(st, sparm);
uparm1 = PFALSE;
if (sparm > (sstack_t)TOS(st, 0))
{
uparm1 = PTRUE;
}
TOS(st, 0) = uparm1;
break;
case oLTE :
POP(st, sparm);
uparm1 = PFALSE;
if (sparm <= (sstack_t)TOS(st, 0))
{
uparm1 = PTRUE;
}
TOS(st, 0) = uparm1;
break;
/* Load (One stack argument) */
case oLDI :
POP(st, uparm1); /* Address */
PUSH(st, GETSTACK(st, uparm1));
PUSH(st, GETSTACK(st, uparm1 + BPERI));
break;
case oLDIH :
TOS(st, 0) = GETSTACK(st, TOS(st, 0));
break;
case oLDIB :
TOS(st, 0) = GETBSTACK(st, TOS(st, 0));
break;
case oLDIM :
/* FIX ME --> Need to handle the unaligned case */
POP(st, uparm1); /* Size */
POP(st, uparm2); /* Stack offset */
while (uparm1 > 0)
{
if (uparm1 >= BPERI)
{
PUSH(st, GETSTACK(st, uparm2));
uparm2 += BPERI;
uparm1 -= BPERI;
}
else
{
PUSH(st, GETBSTACK(st, uparm2));
uparm2++;
uparm1--;
}
}
break;
case oDUP :
uparm1 = TOS(st, 0);
uparm2 = TOS(st, 1);
PUSH(st, uparm2);
PUSH(st, uparm1);
break;
case oDUPH :
uparm1 = TOS(st, 0);
PUSH(st, uparm1);
break;
case oPUSHS :
PUSH(st, st->csp);
break;
case oPOPS :
POP(st, st->csp);
break;
/* Store (Two stack arguments) */
case oSTIH :
POP(st, uparm1);
POP(st, uparm2);
PUTSTACK(st, uparm1,uparm2);
break;
case oSTIB :
POP(st, uparm1);
POP(st, uparm2);
PUTBSTACK(st, uparm1, uparm2);
break;
case oSTIM :
/* FIX ME --> Need to handle the unaligned case */
POP(st, uparm1); /* Size in bytes */
uparm3 = uparm1; /* Save for stack discard */
sparm = ROUNDBTOI(uparm1); /* Size in words */
uparm2 = TOS(st, sparm); /* Stack offset */
sparm--;
while (uparm1 > 0)
{
if (uparm1 >= BPERI)
{
PUTSTACK(st, TOS(st, sparm), uparm2);
uparm2 += BPERI;
uparm1 -= BPERI;
sparm--;
}
else
{
PUTBSTACK(st, TOS(st, sparm), uparm2);
uparm2++;
uparm1--;
}
}
/* Discard the stored data + the stack offset */
DISCARD(st, (ROUNDBTOI(uparm3) + 1));
break;
/* Program control (No stack arguments) */
case oNOP :
break;
case oRET :
POP(st, st->pc);
POP(st, st->fp);
DISCARD(st, 1);
return eNOERROR;
/* System Functions (No stack arguments) */
case oEND :
return eEXIT;
default :
return eILLEGALOPCODE;
}
st->pc += 1;
return eNOERROR;
}
/****************************************************************************
* Name: pexec16
*
* Descripton:
* Handle 16-bit instructions with 8-bits of immediate data (imm8)
*
****************************************************************************/
static inline int pexec16(FAR struct pexec_s *st, uint8_t opcode, uint8_t imm8)
{
int ret = eNOERROR;
st->pc += 2;
switch (opcode)
{
/* Data stack: imm8 = 8 bit unsigned data (no stack arguments) */
case oPUSHB :
PUSH(st, imm8);
break;
/* Floating Point: imm8 = FP op-code (varying number of stack arguments) */
case oFLOAT :
ret = pexec_execfp(st, imm8);
break;
default :
ret = eILLEGALOPCODE;
break;
}
return ret;
}
/****************************************************************************
* Name: pexec24
*
* Descripton:
* Handle 24-bit instructions with 16-bits of immediate data (imm16)
*
****************************************************************************/
static inline int pexec24(FAR struct pexec_s *st, uint8_t opcode, uint16_t imm16)
{
sstack_t sparm1;
sstack_t sparm2;
ustack_t uparm1;
ustack_t uparm2;
ustack_t uparm3;
int ret = eNOERROR;
switch (opcode)
{
/* Program control: imm16 = unsigned label (no stack arguments) */
case oJMP :
goto branch_out;
/* Program control: imm16 = unsigned label (One stack argument) */
case oJEQUZ :
POP(st, sparm1);
if (sparm1 == 0)
{
goto branch_out;
}
break;
case oJNEQZ :
POP(st, sparm1);
if (sparm1 != 0)
{
goto branch_out;
}
break;
case oJLTZ :
POP(st, sparm1);
if (sparm1 < 0)
{
goto branch_out;
}
break;
case oJGTEZ :
POP(st, sparm1);
if (sparm1 >= 0)
{
goto branch_out;
}
break;
case oJGTZ :
POP(st, sparm1);
if (sparm1 > 0)
{
goto branch_out;
}
break;
case oJLTEZ :
POP(st, sparm1);
if (sparm1 <= 0)
{
goto branch_out;
}
break;
/* Program control: imm16 = unsigned label (Two stack arguments) */
case oJEQU :
POP(st, sparm1);
POP(st, sparm2);
if (sparm2 == sparm1)
{
goto branch_out;
}
break;
case oJNEQ :
POP(st, sparm1);
POP(st, sparm2);
if (sparm2 != sparm1)
{
goto branch_out;
}
break;
case oJLT :
POP(st, sparm1);
POP(st, sparm2);
if (sparm2 < sparm1)
{
goto branch_out;
}
break;
case oJGTE :
POP(st, sparm1);
POP(st, sparm2);
if (sparm2 >= sparm1)
{
goto branch_out;
}
break;
case oJGT :
POP(st, sparm1);
POP(st, sparm2);
if (sparm2 > sparm1)
{
goto branch_out;
}
break;
case oJLTE :
POP(st, sparm1);
POP(st, sparm2);
if (sparm2 <= sparm1)
{
goto branch_out;
}
break;
/* Load: imm16 = usigned offset (no stack arguments) */
case oLD :
uparm1 = st->spb + imm16;
PUSH(st, GETSTACK(st, uparm1));
PUSH(st, GETSTACK(st, uparm1 + BPERI));
break;
case oLDH :
uparm1 = st->spb + imm16;
PUSH(st, GETSTACK(st, uparm1));
break;
case oLDB :
uparm1 = st->spb + imm16;
PUSH(st, GETBSTACK(st, uparm1));
break;
case oLDM :
/* FIX ME --> Need to handle the unaligned case */
POP(st, uparm1);
uparm2 = st->spb + imm16;
while (uparm1 > 0)
{
if (uparm1 >= BPERI)
{
PUSH(st, GETSTACK(st, uparm2));
uparm2 += BPERI;
uparm1 -= BPERI;
}
else
{
PUSH(st, GETBSTACK(st, uparm2));
uparm2++;
uparm1--;
}
}
break;
/* Load & store: imm16 = unsigned base offset (One stack argument) */
case oST :
uparm1 = st->spb + imm16;
POP(st, uparm2);
PUTSTACK(st, uparm2, uparm1 + BPERI);
POP(st, uparm2);
PUTSTACK(st, uparm2, uparm1);
break;
case oSTH :
uparm1 = st->spb + imm16;
POP(st, uparm2);
PUTSTACK(st, uparm2, uparm1);
break;
case oSTB :
uparm1 = st->spb + imm16;
POP(st, uparm2);
PUTBSTACK(st, uparm2, uparm1);
break;
case oSTM :
/* FIX ME --> Need to handle the unaligned case */
POP(st, uparm1); /* Size */
uparm3 = uparm1; /* Save for stack discard */
uparm2 = st->spb + imm16;
sparm1 = ROUNDBTOI(uparm1) - 1;
while (uparm1 > 0)
{
if (uparm1 >= BPERI)
{
PUTSTACK(st, TOS(st, sparm1), uparm2);
uparm2 += BPERI;
uparm1 -= BPERI;
sparm1--;
}
else
{
PUTBSTACK(st, TOS(st, sparm1), uparm2);
uparm2++;
uparm1--;
}
}
/* Discard the stored data */
DISCARD(st, ROUNDBTOI(uparm3));
break;
case oLDX :
uparm1 = st->spb + imm16 + TOS(st, 0);
TOS(st, 0) = GETSTACK(st, uparm1);
PUSH(st, GETSTACK(st, uparm1 + BPERI));
break;
case oLDXH :
uparm1 = st->spb + imm16 + TOS(st, 0);
TOS(st, 0) = GETSTACK(st, uparm1);
break;
case oLDXB :
uparm1 = st->spb + imm16 + TOS(st, 0);
TOS(st, 0) = GETBSTACK(st, uparm1);
break;
case oLDXM :
/* FIX ME --> Need to handle the unaligned case */
POP(st, uparm1);
POP(st, uparm2);
uparm2 += st->spb + imm16;
while (uparm1 > 0)
{
if (uparm1 >= BPERI)
{
PUSH(st, GETSTACK(st, uparm2));
uparm2 += BPERI;
uparm1 -= BPERI;
}
else
{
PUSH(st, GETBSTACK(st, uparm2));
uparm2++;
uparm1--;
}
}
break;
/* Store: imm16 = unsigned base offset (Two stack arguments) */
case oSTXH :
POP(st, uparm1);
POP(st, uparm2);
uparm2 += st->spb + imm16;
PUTSTACK(st, uparm1,uparm2);
break;
case oSTXB :
POP(st, uparm1);
POP(st, uparm2);
uparm2 += st->spb + imm16;
PUTBSTACK(st, uparm1, uparm2);
break;
case oSTXM :
/* FIX ME --> Need to handle the unaligned case */
POP(st, uparm1); /* Size */
uparm3 = uparm1; /* Save for stack discard */
sparm1 = ROUNDBTOI(uparm1); /* Size in 16-bit words */
uparm2 = TOS(st, sparm1); /* index */
sparm1--;
uparm2 += st->spb + imm16;
while (uparm1 > 0)
{
if (uparm1 >= BPERI)
{
PUTSTACK(st, TOS(st, sparm1), uparm2);
uparm2 += BPERI;
uparm1 -= BPERI;
sparm1--;
}
else
{
PUTBSTACK(st, TOS(st, sparm1), uparm2);
uparm2++;
uparm1--;
}
}
/* Discard the stored data + the index */
DISCARD(st, (ROUNDBTOI(uparm3) + 1));
break;
case oLA :
uparm1 = st->spb + imm16;
PUSH(st, uparm1);
break;
case oLAX :
TOS(st, 0) = st->spb + imm16 + TOS(st, 0);
break;
/* Data stack: imm16 = 16 bit signed data (no stack arguments) */
case oPUSH :
PUSH(st, imm16);
break;
case oINDS :
st->sp += signExtend16(imm16);
break;
/* System Functions:
* For LIB: imm16 = sub-function code
*/
case oLIB :
ret = pexec_libcall(st, imm16);
break;
/* Program control: imm16 = unsigned label (no stack arguments) */
case oLAC :
uparm1 = imm16 + st->rop;
PUSH(st, uparm1);
break;
case oLABEL :
default:
ret = eILLEGALOPCODE;
break;
}
st->pc += 3;
return ret;
branch_out:
st->pc = (paddr_t)imm16;
return ret;
}
/****************************************************************************
* Name: pexec32
*
* Descripton:
* Handle 32-bit instructions with 24-bits of immediate data (imm8+imm16)
*
****************************************************************************/
static int pexec32(FAR struct pexec_s *st, uint8_t opcode, uint8_t imm8, uint16_t imm16)
{
sstack_t sparm;
ustack_t uparm1;
ustack_t uparm2;
ustack_t uparm3;
int ret = eNOERROR;
switch (opcode)
{
/* Load: imm8 = level; imm16 = signed frame offset (no stack arguments) */
case oLDS :
uparm1 = pexec_getbaseaddress(st, imm8) + signExtend16(imm16);
PUSH(st, GETSTACK(st, uparm1));
PUSH(st, GETSTACK(st, uparm1 + BPERI));
break;
case oLDSH :
uparm1 = pexec_getbaseaddress(st, imm8) + signExtend16(imm16);
PUSH(st, GETSTACK(st, uparm1));
break;
case oLDSB :
uparm1 = pexec_getbaseaddress(st, imm8) + signExtend16(imm16);
PUSH(st, GETBSTACK(st, uparm1));
break;
case oLDSM :
/* FIX ME --> Need to handle the unaligned case */
POP(st, uparm1);
uparm2 = pexec_getbaseaddress(st, imm8) + signExtend16(imm16);
while (uparm1 > 0)
{
if (uparm1 >= BPERI)
{
PUSH(st, GETSTACK(st, uparm2));
uparm2 += BPERI;
uparm1 -= BPERI;
}
else
{
PUSH(st, GETBSTACK(st, uparm2));
uparm2++;
uparm1--;
}
}
break;
/* Load & store: imm8 = level; imm16 = signed frame offset (One stack argument) */
case oSTSH :
uparm1 = pexec_getbaseaddress(st, imm8) + signExtend16(imm16);
POP(st, uparm2);
PUTSTACK(st, uparm2, uparm1);
break;
case oSTSB :
uparm1 = pexec_getbaseaddress(st, imm8) + signExtend16(imm16);
POP(st, uparm2);
PUTBSTACK(st, uparm2, uparm1);
break;
case oSTSM :
/* FIX ME --> Need to handle the unaligned case */
POP(st, uparm1); /* Size */
uparm3 = uparm1; /* Save for stack discard */
uparm2 = pexec_getbaseaddress(st, imm8) + signExtend16(imm16);
sparm = ROUNDBTOI(uparm1) - 1;
while (uparm1 > 0)
{
if (uparm1 >= BPERI)
{
PUTSTACK(st, TOS(st, sparm), uparm2);
uparm2 += BPERI;
uparm1 -= BPERI;
sparm--;
}
else
{
PUTBSTACK(st, TOS(st, sparm), uparm2);
uparm2++;
uparm1--;
}
}
/* Discard the stored data */
DISCARD(st, ROUNDBTOI(uparm3));
break;
case oLDSX :
uparm1 = pexec_getbaseaddress(st, imm8) + signExtend16(imm16) + TOS(st, 0);
TOS(st, 0) = GETSTACK(st, uparm1);
PUSH(st, GETSTACK(st, uparm1 + BPERI));
break;
case oLDSXH :
uparm1 = pexec_getbaseaddress(st, imm8) + signExtend16(imm16) + TOS(st, 0);
TOS(st, 0) = GETSTACK(st, uparm1);
break;
case oLDSXB :
uparm1 = pexec_getbaseaddress(st, imm8) + signExtend16(imm16) + TOS(st, 0);
TOS(st, 0) = GETBSTACK(st, uparm1);
break;
case oLDSXM :
/* FIX ME --> Need to handle the unaligned case */
POP(st, uparm1);
POP(st, uparm2);
uparm2 += pexec_getbaseaddress(st, imm8) + signExtend16(imm16);
while (uparm1 > 0)
{
if (uparm1 >= BPERI)
{
PUSH(st, GETSTACK(st, uparm2));
uparm2 += BPERI;
uparm1 -= BPERI;
}
else
{
PUSH(st, GETBSTACK(st, uparm2));
uparm2++;
uparm1--;
}
}
break;
/* Store: imm8 = level; imm16 = signed frame offset (Two stack arguments) */
case oSTSXH :
POP(st, uparm1);
POP(st, uparm2);
uparm2 += pexec_getbaseaddress(st, imm8) + signExtend16(imm16);
PUTSTACK(st, uparm1,uparm2);
break;
case oSTSXB :
POP(st, uparm1);
POP(st, uparm2);
uparm2 += pexec_getbaseaddress(st, imm8) + signExtend16(imm16);
PUTBSTACK(st, uparm1, uparm2);
break;
case oSTSXM :
/* FIX ME --> Need to handle the unaligned case */
POP(st, uparm1); /* Size */
uparm3 = uparm1; /* Save for stack discard */
sparm = ROUNDBTOI(uparm1); /* Size in 16-bit words */
uparm2 = TOS(st, sparm); /* index */
sparm--;
uparm2 += pexec_getbaseaddress(st, imm8) + signExtend16(imm16);
while (uparm1 > 0)
{
if (uparm1 >= BPERI)
{
PUTSTACK(st, TOS(st, sparm), uparm2);
uparm2 += BPERI;
uparm1 -= BPERI;
sparm--;
}
else
{
PUTBSTACK(st, TOS(st, sparm), uparm2);
uparm2++;
uparm1--;
}
}
/* Discard the stored data + the index */
DISCARD(st, (ROUNDBTOI(uparm3) + 1));
break;
case oLAS :
uparm1 = pexec_getbaseaddress(st, imm8) + signExtend16(imm16);
PUSH(st, uparm1);
break;
case oLASX :
TOS(st, 0) = pexec_getbaseaddress(st, imm8) + signExtend16(imm16) + TOS(st, 0);
break;
/* Program Control: imm8 = level; imm16 = unsigned label (No
* stack arguments)
*/
case oPCAL :
PUSH(st, pexec_getbaseaddress(st, imm8));
PUSH(st, st->fp);
uparm1 = st->sp;
PUSH(st, st->pc + 4);
st->fp = uparm1;
st->pc = (paddr_t)imm16;
return eNOERROR;
/* System Functions:
* For SYSIO: imm8 = file number; imm16 = sub-function code
*/
case oSYSIO :
ret = pexec_sysio(st, imm8, imm16);
break;
/* Psuedo-operations: (No stack arguments)
* For LINE: imm8 = file number; imm16 = line number
*/
case oLINE :
default :
ret = eILLEGALOPCODE;
break;
}
st->pc += 4;
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: pexec_init
****************************************************************************/
FAR struct pexec_s *pexec_init(struct pexec_attr_s *attr)
{
struct pexec_s *st;
paddr_t stacksize;
paddr_t adjusted_rosize;
/* Allocate the p-machine state stucture */
st = (struct pexec_s *)malloc(sizeof(struct pexec_s));
if (!st)
{
return NULL;
}
/* Set up I-Space */
st->ispace = attr->ispace;
st->maxpc = attr->maxpc;
/* Align size of read-only data to 16-bit boundary. */
adjusted_rosize = (attr->rosize + 1) & ~1;
/* Allocate the pascal stack. Organization is string stack, then
* constant data, then "normal" pascal stack.
*/
stacksize = attr->varsize + adjusted_rosize + attr->strsize;
st->dstack.b = (uint8_t*)malloc(stacksize);
if (!st->dstack.b)
{
free(st);
return NULL;
}
/* Copy the rodata into the stack */
if (attr->rodata && attr->rosize)
{
memcpy(&st->dstack.b[attr->strsize], attr->rodata, attr->rosize);
}
/* Set up info needed to perform a simulated reset */
st->strsize = attr->strsize;
st->rosize = adjusted_rosize;
st->entry = attr->entry;
st->stacksize = stacksize;
/* Then perform a simulated reset */
pexec_reset(st);
return st;
}
/****************************************************************************
* Name: pexec
****************************************************************************/
int pexec(FAR struct pexec_s *st)
{
uint8_t opcode;
int ret;
/* Make sure that the program counter is within range */
if (st->pc >= st->maxpc)
{
ret = eBADPC;
}
else
{
/* Get the instruction to execute */
opcode = st->ispace[st->pc];
if ((opcode & o8) != 0)
{
/* Get the immediate, 8-bit value */
uint8_t imm8 = st->ispace[st->pc + 1];
if ((opcode & o16) != 0)
{
/* Get the immediate, big-endian 16-bit value */
uint16_t imm16 = ((st->ispace[st->pc + 2]) << 8) | st->ispace[st->pc + 3];
/* Handle 32 bit instructions */
ret = pexec32(st, opcode, imm8, imm16);
}
else
{
/* Handle 16-bit instructions */
ret = pexec16(st, opcode, imm8);
}
}
else if ((opcode & o16) != 0)
{
/* Get the immediate, big-endian 16-bit value */
uint16_t imm16 = ((st->ispace[st->pc + 1]) << 8) | st->ispace[st->pc + 2];
/* Handle 24-bit instructions */
ret = pexec24(st, opcode, imm16);
}
else
{
/* Handle 8-bit instructions */
ret = pexec8(st, opcode);
}
}
return ret;
}
/****************************************************************************
* Name: pexec_reset
****************************************************************************/
void pexec_reset(struct pexec_s *st)
{
int dndx;
/* Setup the bottom of the "normal" pascal stack */
st->rop = st->strsize;
st->spb = st->strsize + st->rosize;
/* Initialize the emulated P-Machine registers */
st->csp = 0;
st->sp = st->spb + 2*BPERI;
st->fp = st->spb + BPERI;
st->pc = st->entry;
/* Initialize the P-Machine stack */
dndx = BTOISTACK(st->spb);
st->dstack.i[dndx] = 0;
st->dstack.i[dndx+1] = 0;
st->dstack.i[dndx+2] = -1;
}
/****************************************************************************
* Name: pexec_release
****************************************************************************/
void pexec_release(struct pexec_s *st)
{
if (st)
{
if (st->dstack.i)
{
free(st->dstack.i);
}
if (st->ispace)
{
free(st->ispace);
}
free(st);
}
}