pci.cc

//*************************************************************************
//  MODULE : PCI - Kernel resident P-code Interpreter for the RCOS system *
//  AUTHOR : Ron Chernich                                                 *
//  PURPOSE: Passed the "context" of an RCOS process, execute the next    *
//           p-code.  Interpereter developed from the stand-alone ANSI C  *
//           version which was modeled after a Pascal version by Kin-Man  *
//           Chung and Herbert Yuen from their October 1978 BYTE article, *
//           "A 'Tiny' Pascal Compiler - Part 1: The p_code Interpereter" *
//  HISTORY:                                                              *
//    19-DEC-92 First ANSI MSC version                                    *
//    24-MAY-93 New p-code "CSP 0/EXEC" added to load & execute programs  *
//    27-MAY-93 Hallelujah - RCOS multi-tasks two "Hello World" programs! *
//    02-JUN-93 Detect and abort on User Break messages from line driver  *
//    06-MAR-94 CSP Semaphore functions added                             *
//    01-APR-94 Force TTY Auto LF mode during CSP *IN executions.         *
//    13-APR-94 Semaphore count initialisation added to SEM_CREATE CSP    *
//    18-APR-94 CSP Shared Memory support added                           *
//    01-SEP-94 CSP File operations added (RunProc now officialy too big) *
//    12-SEP-94 EOF detect added (G'wing lounge, BN-SY delayed again!)    *
//*************************************************************************


#include "pci.hh"
#include "fsiface.hh"


#define BUF_SIZE    64     // Number of integers in buffer for program load

///////////
// local level function protos..
//
static BOOL ValidCode (UINT16, INT16);


///////////////////
// Execute a pcode: Fetch the next pcode and its argument (two 16 bit words)
// Decode and execute, adjusting process IP, SP and BP accordingly.  Begin
// with a Pre-fetch of the 32 bit word at IP (the IP is a 32 bit offset):
//   giving: hhll aaaa
//    where: ll = p-code; hh = base ref; aaaa = immediate argument
//
// If the passed PCB struct has a reply attached, it must be as a result of
// a Read/ReadBlk/SemWait from a CSP pcode, so process that. If not, pre-fetch
// the top-of-stack (just about everything needs that) and parse and execute..
//
//   Lament: This thing is getting bigger than the giant MS Windows case
//           statement from hell that ate Cleaveland!
//
void Exec::RunProc (PCB& pcbx, MCB& mcbx)
{
  char   *cp;
  BOOL    bIsLegal;
  MMU_MSG memXfer;
  UINT16  uFsRet = FS_Ok;
  INT16   nFunc, nFuncBase;
  UINT16  uText[2], uStack[3], uTemp, *pu;
  static  char *pszErr[] = { "\n\rHalted - %s",
    "User Break", "Illegal p-code", "Shared mem violation" };

  memXfer.uLen = 2;
  memXfer.pData = uText;
  memXfer.uOffset = (pcbx.uIP << 1);
  MSG msg(uCurProc, KM_ReadBlk, mcbx.hText, &memXfer);
  pTx->SendMsg(ID_MMU, &msg);
  memXfer.uLen = 1;
  memXfer.pData = uStack;
  memXfer.uOffset = pcbx.uSP;
  msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
  pTx->SendMsg(ID_MMU, &msg);
  pcbx.lCode = (UINT32)uText[0] + ((UINT32)uText[1] << 16);
  pcbx.uTos = uStack[0];
  nFunc = (INT16)(uText[0] & 0xff);
  nFuncBase = (INT16)(0xff & (uText[0] >> 8));
  bIsLegal = ValidCode(uText[0], uText[1]);
  msg = message(ID_Kernel, ANI_UPDAT_PCB);
  pTx->SendMsg(ID_ANIM, &msg);
  if (!bIsLegal) {
    pcbx.uStatus = PS_Illegal;
    if (pcbx.pDev) {
      char str[64];
      sprintf(str, pszErr[0], pszErr[2]);
      msg = message(pcbx.uPid, KM_WriteBlk, strlen(str), str);
      pTx->SendMsg(ID_LNDRV + pcbx.uPid, &msg);
    }
    return;
  }
  pcbx.uIP++;
  if (pcbx.pReply) {
    if (pcbx.pReply->wMsgType == KM_Break) {
      delete pcbx.pReply;
      pcbx.pReply = NULL;
      pcbx.uStatus = PS_Halted;
      char str[64];
      sprintf(str, pszErr[0], pszErr[1]);
      msg = message(pcbx.uPid, KM_WriteBlk, strlen(str), str);
      pTx->SendMsg(ID_LNDRV + pcbx.uPid, &msg);
      return;
    }
    if (nFunc == CSP) 
      if ((F_ALLOC <= uText[1]) && (uText[1] <= F_WRITE)) {
	uFsRet = pcbx.pReply->wMsgType;
	delete pcbx.pReply;
	pcbx.pReply = NULL;
      }
      else {
	if (uText[1] == 0)
	  uStack[0] = pcbx.pReply->wParam;
	else
	  if (pcbx.pReply->wMsgType != KM_Signal) {
	    cp = new char[pcbx.pReply->wParam + 1];
	    strncpy(cp, (char*)pcbx.pReply->pBody, pcbx.pReply->wParam);
	    cp[pcbx.pReply->wParam] = '\0';
	    sscanf(cp, ((uText[1] == HEXIN) ? "%x" : "%d"), &uStack[0]);
	    DELETE_ARRAY pcbx.pReply->pBody;
	    DELETE_ARRAY cp;
	    msg = message(uCurProc, KM_IoCtrl, DM_GetMode);
	    pTx->SendMsg(pcbx.uPid + ID_LNDRV, &msg);
	    uTemp = msg.wParam & ~TTY_AutoLF;
	    msg = message(uCurProc, KM_IoCtrl, DM_SetMode, &uTemp);
	    pTx->SendMsg(pcbx.uPid + ID_LNDRV, &msg);
	  }
	delete pcbx.pReply;
	pcbx.pReply = NULL;
	memXfer.pData = &uStack[0];
	memXfer.uOffset = ++pcbx.uSP;
	MSG msg(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	pTx->SendMsg(ID_MMU, &msg);
	return;
      }
  }
  switch (nFunc) {
    case INT:
      pcbx.uSP += uText[1];
      break;
    case JMP:
      pcbx.uIP = uText[1];
      break;
    case JPC:
      msg = message(uCurProc, KM_Read, mcbx.hStack, &memXfer);
      pTx->SendMsg(ID_MMU, &msg);
      if (uStack[0] == (UINT16)nFuncBase)
	pcbx.uIP = uText[1];
      pcbx.uSP--;
      break;
    case LIT:
      memXfer.pData = &uText[1];
      memXfer.uOffset = ++pcbx.uSP;
      msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
      pTx->SendMsg(ID_MMU, &msg);
      break;
    case LOD:
    case LODX:
      if (nFunc == LODX)
	uText[1] += uStack[0];
      else
      ++pcbx.uSP;
      memXfer.pData = &uStack[0];
      memXfer.uOffset = pcbx.uBP;
      msg = message(uCurProc, KM_Read, mcbx.hStack, &memXfer);
      while (nFuncBase--) {
	pTx->SendMsg(ID_MMU, &msg);
	memXfer.uOffset = uStack[0];
      }
      memXfer.uOffset += uText[1];
      msg = message(uCurProc, KM_Read, mcbx.hStack, &memXfer);
      pTx->SendMsg(ID_MMU, &msg);
      memXfer.uOffset = pcbx.uSP;
      msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
      pTx->SendMsg(ID_MMU, &msg);
      break;
    case STO:
    case STOX:
      uStack[1] = uStack[0];
      if (nFunc == STOX) {
	memXfer.uOffset = pcbx.uSP - 1;
	msg = message(uCurProc, KM_Read, mcbx.hStack, &memXfer);
	pTx->SendMsg(ID_MMU, &msg);
	uText[1] += uStack[0];
      }
      memXfer.pData = &uStack[0];
      memXfer.uOffset = pcbx.uBP;
      msg = message(uCurProc, KM_Read, mcbx.hStack, &memXfer);
      while (nFuncBase--) {
	pTx->SendMsg(ID_MMU, &msg);
	memXfer.uOffset = uStack[0];
      }
      memXfer.uOffset += uText[1];
      memXfer.pData = &uStack[1];
      msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
      pTx->SendMsg(ID_MMU, &msg);
      pcbx.uSP -= ((nFunc == STOX) ? 2 : 1);
      break;
    case CAL:
      msg = message(uCurProc, KM_Read, mcbx.hStack, &memXfer);
      memXfer.pData = &uStack[0];
      memXfer.uOffset = pcbx.uBP;
      while (nFuncBase--) {
	pTx->SendMsg(ID_MMU, &msg);
	memXfer.uOffset = uStack[0];
      }
      uStack[0] = memXfer.uOffset;
      uStack[1] = pcbx.uBP;
      uStack[2] = pcbx.uIP;
      memXfer.uLen = 3;
      memXfer.uOffset = pcbx.uSP + 1;
      msg = message(uCurProc, KM_WriteBlk, mcbx.hStack, &memXfer);
      pTx->SendMsg(ID_MMU, &msg);
      pcbx.uIP = uText[1];
      pcbx.uBP = pcbx.uSP + 1;
      break;
    case OPR:
      switch (uText[1]) {
	case _RET:
	  pcbx.uSP = pcbx.uBP - 1;
	  memXfer.uLen = 2;
	  memXfer.pData = uStack;
	  memXfer.uOffset = pcbx.uSP + 2;
	  msg = message(pcbx.uPid, KM_ReadBlk, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);
	  pcbx.uBP = uStack[0];
	  pcbx.uIP = uStack[1];
	  if ((INT16)pcbx.uBP < 0) {
	    pcbx.uStatus = PS_Halted;
	    if (pcbx.pDev) {
	      char str[16];
	      strcpy(str, "\n\rHalted - Ok");
	      msg = message(pcbx.uPid, KM_WriteBlk, strlen(str), str);
	      pTx->SendMsg(ID_LNDRV + pcbx.uPid, &msg);
	    }
	  }
	  break;
	case _NEG:
	  uStack[0] = (UINT16)(0 - (INT16)uStack[0]);
	  break;
	case _CPY:
	  pcbx.uSP++;
	  break;
	case _NOT:
	  uStack[0] = ~uStack[0];
	  break;
	case _INC:
	  ++uStack[0];
	  break;
	case _DEC:
	  --uStack[0];
	  break;
	case _LOW:
	  uStack[0] &= 1;
	  break;
	default:
	  uStack[1] = uStack[0];
	  memXfer.uOffset = --pcbx.uSP;
	  msg = message(uCurProc, KM_Read, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);
	  switch (uText[1]) {
	    case _ADD:
	      uStack[0] = (UINT16)((INT16)uStack[0] + (INT16)uStack[1]);
	      break;
	    case _SUB:
	      uStack[0] = (UINT16)((INT16)uStack[0] - (INT16)uStack[1]);
	      break;
	    case _MUL:
	      uStack[0] = (UINT16)((INT16)uStack[0] * (INT16)uStack[1]);
	      break;
	    case _DIV:
	      uStack[0] = (UINT16)((INT16)uStack[0] / (INT16)uStack[1]);
	      break;
	    case _MOD:
	      uStack[0] = (UINT16)((INT16)uStack[0] % (INT16)uStack[1]);
	      break;
	    case _AND:
	      uStack[0] &= uStack[1];
	      break;
	    case _OR:
	      uStack[0] |= uStack[1];
	      break;
	    case _XOR:
	      uStack[0] ^= uStack[1];
	      break;
	    case _SHR:
	      uStack[0] >>= uStack[1];
	      break;
	    case _SHL:
	      uStack[0] <<= uStack[1];
	      break;
	    case _EQ:
	      uStack[0] = (uStack[0] == uStack[1]) ? 1 : 0;
	      break;
	    case _NE:
	      uStack[0] = (uStack[0] != uStack[1]) ? 1 : 0;
	      break;
	    case _LT:
	      uStack[0] = ((INT16)uStack[0] < (INT16)uStack[1]) ? 1 : 0;
	      break;
	    case _GT:
	      uStack[0] = ((INT16)uStack[0] > (INT16)uStack[1]) ? 1 : 0;
	      break;
	    case _LE:
	      uStack[0] = ((INT16)uStack[0] <= (INT16)uStack[1]) ? 1 : 0;
	      break;
	    case _GE:
	      uStack[0] = ((INT16)uStack[0] >= (INT16)uStack[1]) ? 1 : 0;
	      break;
	  }
	  break;
      }
      if (uText[1] != _RET) {
	memXfer.uOffset = pcbx.uSP;
	msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	pTx->SendMsg(ID_MMU, &msg);
      }
      break;
    case CSP:
      switch (uText[1]) {
	case CHIN:
	case NUMIN:
	case HEXIN:
	  pcbx.uIP--;
	  msg = message(uCurProc, KM_IoCtrl, DM_GetMode);
	  pTx->SendMsg(pcbx.uPid + ID_LNDRV, &msg);
	  uTemp = msg.wParam | TTY_AutoLF;
	  msg = message(uCurProc, KM_IoCtrl, DM_SetMode, &uTemp);
	  pTx->SendMsg(pcbx.uPid + ID_LNDRV, &msg);
	  msg = message(uCurProc,((uText[1] == CHIN) ? KM_Read : KM_ReadBlk));
	  pTx->PostMsg(pcbx.uPid + ID_LNDRV, &msg);
	  break;
	case CHOUT:
	  msg = message(uCurProc, KM_Write, uStack[0]);
	  pTx->SendMsg(pcbx.uPid + ID_LNDRV, &msg);
	  pcbx.uSP--;
	  break;
	case NUMOUT:
	  if (cp = new char[8]) {
	    sprintf(cp, " %d", uStack[0]);
	    msg = message(uCurProc, KM_WriteBlk, strlen(cp), (void*)cp);
	    pTx->SendMsg(pcbx.uPid + ID_LNDRV, &msg);
	    DELETE_ARRAY cp;
	  }
	  pcbx.uSP--;
	  break;
	case HEXOUT:
	  if (cp = new char[8]) {
	    sprintf(cp, " %x", uStack[0]);
	    msg = message(uCurProc, KM_WriteBlk, strlen(cp), (void*)cp);
	    pTx->SendMsg(pcbx.uPid + ID_LNDRV, &msg);
	    DELETE_ARRAY cp;
	  }
	  pcbx.uSP--;
	  break;
	case STROUT:
	  if (pu = new UINT16[uStack[0]]) {
	    memXfer.pData = pu;
	    memXfer.uLen = uStack[0];
	    memXfer.uOffset = pcbx.uSP - uStack[0];
	    msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
	    pTx->SendMsg(ID_MMU, &msg);
	    if (cp = new char[uStack[0]]) {
	      for (INT16 i = 0; i < (INT16)uStack[0]; i++)
		cp[i] = (char)pu[i];
	      msg = message(uCurProc, KM_WriteBlk, uStack[0], cp);
	      pTx->SendMsg(pcbx.uPid + ID_LNDRV, &msg);
	      DELETE_ARRAY cp;
	    }
	    DELETE_ARRAY pu;
	  }
	  pcbx.uSP -= (uStack[0] + 1);
	  break;
	case FORK:
	  uStack[0] = Fork();
	  memXfer.uLen = 1;
	  memXfer.pData = uStack;
	  memXfer.uOffset = pcbx.uSP;
	  msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);
	  if (uStack[0] != NO_PROC) {
	    msg = message(uStack[0], KM_ReadBlk, mcbx.hStack, &memXfer);
	    uStack[0] = 0;
	    pTx->SendMsg(ID_MMU, &msg);
	  }
	  break;
	case EXEC:
	  if (pu = new UINT16[uStack[0]]) {
	    memXfer.pData = pu;
	    memXfer.uLen = uStack[0];
	    memXfer.uOffset = pcbx.uSP - uStack[0];
	    msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
	    pTx->SendMsg(ID_MMU, &msg);
	    if (cp = new char[uStack[0] + 1]) {
	      for (INT16 i = 0; i < (INT16)uStack[0]; i++)
		cp[i] = (char)pu[i];
	      cp[i] = '\0';
	      FILE *ipf = fopen(cp, "rb");
	      if (ipf) {
		UINT16 uBuf[BUF_SIZE];
		memXfer.uLen = BUF_SIZE;
		memXfer.uOffset = 0;
		memXfer.pData = uBuf;
		msg = message(uCurProc, KM_WriteBlk, mcbx.hText, &memXfer);
		while (fread(uBuf, sizeof(UINT16), BUF_SIZE, ipf)) {
		  pTx->SendMsg(ID_MMU, &msg);
		  memXfer.uOffset += BUF_SIZE;
		}
		fclose(ipf);
	      }
	      DELETE_ARRAY cp;
	    }
	    DELETE_ARRAY pu;
	  }
	  pcbx.uBP = 1;
	  pcbx.uIP = pcbx.uSP = 0;
	  msg = message(uCurProc, KM_WriteBlk, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);
	  //
	  // ************ 
	  // TEMP MEASURE
	  // ************
	  //
	  pcbx.pDev =
	    new LnDrv(pcbx.uPid, ID_LNDRV + pcbx.uPid, pTx);
	  break;
	case SEM_CREATE:
	  uTemp = uStack[0];
	  pcbx.uSP--;
	  memXfer.uLen = 1;
	  memXfer.pData = uStack;
	  memXfer.uOffset = pcbx.uSP;
	  msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);

  if (nFuncBase)
	    if (pu = new UINT16[uStack[0]]) {
	      UINT16 uSid;
	      memXfer.pData = pu;
	      memXfer.uLen = uStack[0];
	      memXfer.uOffset = pcbx.uSP - uStack[0];
	      msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
	      pTx->SendMsg(ID_MMU, &msg);
	      if (cp = new char[uStack[0]+1]) {
		for (INT16 i = 0; i < (INT16)uStack[0]; i++)
		  cp[i] = (char)pu[i];
		*(cp+uStack[0]) = '\0';
		uSid = ((uText[1]==SEM_OPEN) ? IpcOpen(cp) : IpcAlloc(cp, uTemp));
		DELETE_ARRAY cp;
	      }
	      DELETE_ARRAY pu;
	      pcbx.uSP -= (uStack[0]);
	      uStack[0] = uSid;
	    }
	  memXfer.uLen = 1;
	  memXfer.pData = &uStack[0];
	  memXfer.uOffset = pcbx.uSP;
	  msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);


	  //??????
	  break;
	case SEM_OPEN:
	  if (nFuncBase)
	    if (pu = new UINT16[uStack[0]]) {
	      UINT16 uSid;
	      memXfer.pData = pu;
	      memXfer.uLen = uStack[0];
	      memXfer.uOffset = pcbx.uSP - uStack[0];
	      msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
	      pTx->SendMsg(ID_MMU, &msg);
	      if (cp = new char[uStack[0]+1]) {
		for (INT16 i = 0; i < (INT16)uStack[0]; i++)
		  cp[i] = (char)pu[i];
		*(cp+uStack[0]) = '\0';
		uSid = ((uText[1]==SEM_OPEN) ? IpcOpen(cp) : IpcAlloc(cp, uTemp));
		DELETE_ARRAY cp;
	      }
	      DELETE_ARRAY pu;
	      pcbx.uSP -= (uStack[0]);
	      uStack[0] = uSid;
	    }
	  memXfer.uLen = 1;
	  memXfer.pData = &uStack[0];
	  memXfer.uOffset = pcbx.uSP;
	  msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);
	  break;
	case SEM_CLOSE:
	  IpcClose(uCurProc, uStack[0]);
	  break;
	case SEM_SIGNAL:
	  IpcSignal(uCurProc, uStack[0]);
	  break;
	case SEM_WAIT:
	  uTemp = (UINT16)IpcWait(uCurProc, uStack[0]);
	  if (uTemp == 0)
	    --pcbx.uIP;
	  else {
	    uStack[0] = uTemp;
	    memXfer.uLen = 1;
	    memXfer.pData = &uStack[0];
	    memXfer.uOffset = pcbx.uSP;
	    msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	    pTx->SendMsg(ID_MMU, &msg);
	  }
	  break;
	case SHR_CLOSE:
	  uStack[0] = SmClose(uCurProc, uStack[0]);
	  memXfer.uLen = 1;
	  memXfer.pData = &uStack[0];
	  memXfer.uOffset = pcbx.uSP;
	  msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);
	  break;
	case SHR_CREATE:
	  uTemp = uStack[0];
	  pcbx.uSP--;
	  memXfer.uLen = 1;
	  memXfer.pData = uStack;
	  memXfer.uOffset = pcbx.uSP;
	  msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);

	  if (pu = new UINT16[uStack[0]]) {
	    UINT16 uId;
	    memXfer.pData = pu;
	    memXfer.uLen = uStack[0];
	    memXfer.uOffset = pcbx.uSP - uStack[0];
	    msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
	    pTx->SendMsg(ID_MMU, &msg);
	    if (cp = new char[uStack[0]+1]) {
	      for (INT16 i = 0; i < (INT16)uStack[0]; i++)
		cp[i] = (char)pu[i];
	      *(cp+uStack[0]) = '\0';
	      uId = ((uText[1]==SHR_OPEN) ? SmOpen(cp) : SmCreate(cp, (INT16)uTemp));
	      DELETE_ARRAY cp;
	    }
	    DELETE_ARRAY pu;
	    pcbx.uSP -= (uStack[0]);
	    uStack[0] = uId;
	  }
	  memXfer.uLen = 1;
	  memXfer.pData = &uStack[0];
	  memXfer.uOffset = pcbx.uSP;
	  msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);


	  //????
	  break;
	case SHR_OPEN:
	  if (pu = new UINT16[uStack[0]]) {
	    UINT16 uId;
	    memXfer.pData = pu;
	    memXfer.uLen = uStack[0];
	    memXfer.uOffset = pcbx.uSP - uStack[0];
	    msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
	    pTx->SendMsg(ID_MMU, &msg);
	    if (cp = new char[uStack[0]+1]) {
	      for (INT16 i = 0; i < (INT16)uStack[0]; i++)
		cp[i] = (char)pu[i];
	      *(cp+uStack[0]) = '\0';
	      uId = ((uText[1]==SHR_OPEN) ? SmOpen(cp) : SmCreate(cp, (INT16)uTemp));
	      DELETE_ARRAY cp;
	    }
	    DELETE_ARRAY pu;
	    pcbx.uSP -= (uStack[0]);
	    uStack[0] = uId;
	  }
	  memXfer.uLen = 1;
	  memXfer.pData = &uStack[0];
	  memXfer.uOffset = pcbx.uSP;
	  msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);
	  break;
	case SHR_SIZE:
	  uStack[0] = SmLength(uStack[0]);
	  memXfer.uLen = 1;
	  memXfer.pData = &uStack[0];
	  memXfer.uOffset = pcbx.uSP;
	  msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);
	  break;
	case SHR_READ:
	  pcbx.uSP--;
	  memXfer.uLen = 1;
	  memXfer.pData = &uStack[1];
	  memXfer.uOffset = pcbx.uSP;
	  msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);
	  if (SmRead(uStack[1], uStack[0], (INT16*)&uStack[2])) {
	    memXfer.uLen = 1;
	    memXfer.pData = &uStack[2];
	    memXfer.uOffset = pcbx.uSP;
	    msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	    pTx->SendMsg(ID_MMU, &msg);
	  }
	  else {
	    pcbx.uStatus = PS_Illegal;
	    if (pcbx.pDev) {
	      char str[64];
	      sprintf(str, pszErr[0], pszErr[3]);
	      msg = message(pcbx.uPid, KM_WriteBlk, strlen(str), str);
	      pTx->SendMsg(ID_LNDRV + pcbx.uPid, &msg);
	    }
	  }
	  break;
	case SHR_WRITE:
	  pcbx.uSP -= 2;
	  memXfer.uLen = 3;
	  memXfer.pData = uStack;
	  memXfer.uOffset = pcbx.uSP;
	  msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);
	  if (SmWrite(uStack[0], uStack[1], (INT16*)&uStack[2])) {
	    memXfer.uLen = 1;
	    memXfer.pData = &uStack[2];
	    memXfer.uOffset = pcbx.uSP;
	    msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	    pTx->SendMsg(ID_MMU, &msg);
	  }
	  else {
	    pcbx.uStatus = PS_Illegal;
	    if (pcbx.pDev) {
	      char str[64];
	      sprintf(str, pszErr[0], pszErr[3]);
	      msg = message(pcbx.uPid, KM_WriteBlk, strlen(str), str);
	      pTx->SendMsg(ID_LNDRV + pcbx.uPid, &msg);
	    }
	  }
	  break;
	case F_ALLOC:
	  if (NULL == pcbx.pFile) {
	    pcbx.pFile = new FsIface(uCurProc, pTx);
	    if (NULL == pcbx.pFile) {
	      pcbx.uStatus = PS_Illegal;
	      return;
	    }
	  }
	  if (pu = new UINT16[uStack[0]]) {
	    HANDLE hFile;
	    memXfer.pData = pu;
	    memXfer.uLen = uStack[0];
	    memXfer.uOffset = pcbx.uSP - uStack[0];
	    msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
	    pTx->SendMsg(ID_MMU, &msg);
	    if (cp = new char[uStack[0]+1]) {
	      for (INT16 i = 0; i < (INT16)uStack[0]; i++)
		cp[i] = (char)pu[i];
	      *(cp+uStack[0]) = '\0';
	      if (FS_Ok != pcbx.pFile->Allocate(hFile, cp))
		pcbx.uStatus = PS_Illegal;
	      DELETE_ARRAY cp;
	    }
	    DELETE_ARRAY pu;
	    pcbx.uSP -= (uStack[0]);
	    uStack[0] = (UINT16)hFile;
	  }
	  memXfer.uLen = 1;
	  memXfer.pData = &uStack[0];
	  memXfer.uOffset = pcbx.uSP;
	  msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	  pTx->SendMsg(ID_MMU, &msg);
	  break;
	case F_DEL:
	case F_OPEN:
	case F_CREAT:
	case F_CLOSE:
	  if (NULL == pcbx.pFile)
	    pcbx.uStatus = PS_Illegal;
	  else {
	    INT16 nRes;
	    switch (uText[1]) {
	      case F_DEL:   nRes = pcbx.pFile->Delete(uStack[0], uFsRet); break;
	      case F_OPEN:  nRes = pcbx.pFile->Open(uStack[0],   uFsRet); break;
	      case F_CREAT: nRes = pcbx.pFile->Creat(uStack[0],  uFsRet); break;
	      case F_CLOSE: nRes = pcbx.pFile->Close(uStack[0],  uFsRet); break;
	    }              
	    switch (nRes) {
	      case FS_Busy:
		pcbx.uIP--;
		pcbx.uStatus &= ~PS_Ready;
		pcbx.uStatus |= PS_Blocked;
		break;
	      case FS_NotFound:
		if (F_DEL == uText[1])
		  break;
	      case FS_DiskFull:
		pcbx.uStatus = PS_Illegal;
		break;
	      case FS_Ok:
		break;
	    }
	  }
	  break;
	case F_READ:
	  if (NULL == pcbx.pFile)
	    pcbx.uStatus = PS_Illegal;
	  else {
	    char  ch;
	    INT16 nRes = pcbx.pFile->Read(uStack[0], ch, uFsRet);
	    if (FS_Busy == nRes) {
	      pcbx.uIP--;
	      pcbx.uStatus &= ~PS_Ready;
	      pcbx.uStatus |= PS_Blocked;
	    }
	    else {
	      uStack[0] = (UINT16)ch;
	      memXfer.uLen = 1;
	      memXfer.pData = &uStack[0];
	      memXfer.uOffset = pcbx.uSP;
	      msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	      pTx->SendMsg(ID_MMU, &msg);
	    }
	  }
	  break;
	case F_WRITE:
	  if (NULL == pcbx.pFile)
	    pcbx.uStatus = PS_Illegal;
	  else {
	    INT16 nRes, nFrame = 2;
	    memXfer.uLen = 2;
	    memXfer.pData = &uStack[0];
	    memXfer.uOffset = pcbx.uSP - 1;
	    msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
	    pTx->SendMsg(ID_MMU, &msg);
	    switch (nFuncBase) {
	      case 0:
		nRes = pcbx.pFile->Write(uStack[1], (char)uStack[0], uFsRet);
		break;
	      case 1:
		if (cp = new char[8]) {
		  sprintf(cp, "%d", uStack[0]);
		  nRes = pcbx.pFile->Write(uStack[1], cp, uFsRet);
		  DELETE_ARRAY cp;
		}
		break;
	      case 2:
		if (cp = new char[8]) {
		  sprintf(cp, "%04X", uStack[0]);
		  nRes = pcbx.pFile->Write(uStack[1], cp, uFsRet);
		  DELETE_ARRAY cp;
		}
		break;
	      case 3:
		nFrame += uStack[0];
		if (pu = new UINT16[uStack[0]]) {
		  memXfer.pData = pu;
		  memXfer.uLen = uStack[0];
		  memXfer.uOffset = pcbx.uSP - nFrame + 1;
		  msg = message(uCurProc, KM_ReadBlk, mcbx.hStack, &memXfer);
		  pTx->SendMsg(ID_MMU, &msg);
		  if (cp = new char[uStack[0]+1]) {
		    for (INT16 i = 0; i < (INT16)uStack[0]; i++)
		      cp[i] = (char)pu[i];
		    *(cp+uStack[0]) = '\0';
		    nRes = pcbx.pFile->Write(uStack[1], cp, uFsRet);
		    DELETE_ARRAY cp;
		  }
		  DELETE_ARRAY pu;
		}
		break;
	    default:
	      pcbx.uStatus = PS_Illegal;
	    }
	    switch (nRes) {
	      case FS_Ok :
		pcbx.uSP -= nFrame;
		break;
	      case FS_Busy:
		pcbx.uIP--;
		pcbx.uStatus &= ~PS_Ready;
		pcbx.uStatus |= PS_Blocked;
		break;
	    default:
	      pcbx.uStatus = PS_Illegal;
	    }
	  }
	  break;
	case F_EOF:
	  if (NULL == pcbx.pFile)
	    pcbx.uStatus = PS_Illegal;
	  else {
	    uStack[0] = (FS_EOF == pcbx.pFile->IsEof(uStack[0])) ? 0xffff : 0;
	    memXfer.uLen = 1;
	    memXfer.pData = &uStack[0];
	    memXfer.uOffset = pcbx.uSP;
	    msg = message(uCurProc, KM_Write, mcbx.hStack, &memXfer);
	    pTx->SendMsg(ID_MMU, &msg);
	  }
	  break;
      }
  }
}

//////////////////////
// Decode the passed opcode and argument into the passed string
//
void Exec::DeCode (UINT32 lCode, char *pstr)
{
  INT16  wOper, wArg, k1, k2, k3;
  static char *stMn[] = {
    "LIT", "OPR", "LOD", "STO",  "CAL",  "INT",
    "JMP", "JPC", "CSP", "LODX", "STOX", "???"
  };
  static char *OPRarg[] = {
    "RET", "NEG", "ADD", "SUB", "MUL",
    "DIV", "LOW", "MOD", "EQ",  "NE",  "LT",
    "GE",  "GT",  "LE",  "OR",  "AND", "XOR",
    "NOT", "SHL", "SHR", "INC", "DEC", "CPY", "???"
  };
  static char *CSParg[] = {
    "GETC", "PUTC", "GETN", "PUTN", "GETH", "PUTH",
    "EXEC", "FORK", "PUTS",
    "SCLO", "SCRE", "SOPN", "SSIG", "SWAIT",
    "MCLO", "MCRE", "MOPN", "MGET", "MPUT", "MLEN",
    "ALOC", "OPEN", "CREA", "CLOS", "EOF",  "DEL",
    "READ", "WRIT",
    "????"
  };

  k2 = k3 = 0;
  wOper = (INT16)(lCode & 0xff);
  wArg = (INT16)(lCode >> 16);
  k1 = ((wOper >= LIT)  && (wOper <= CSP))  ?  wOper      :
       ((wOper == LODX) || (wOper == STOX)) ? (wOper - 9) : ILLEGAL_PCD;
  sprintf(pstr, "%s %2X,", stMn[k1], (INT16)((lCode >> 8) & 0xff));
  switch (k1) {
    case OPR:
      k2 = ((wArg >= _RET) && (wArg < ILLEGAL_OPR_ARG)) ? wArg : ILLEGAL_OPR_ARG;
      strcat(pstr, OPRarg[k2]);
      break;
    case CSP:
      k3 = ((wArg >= CHIN) && (wArg < ILLEGAL_CSP_ARG)) ? wArg : ILLEGAL_CSP_ARG;
      strcat(pstr, CSParg[k3]);
      break;
    default:
      if ((k1 == LIT) && (wArg > 0))
	sprintf(pstr+strlen(pstr), "0x%02X ", wArg);
      else
	sprintf(pstr+strlen(pstr), "%2d", wArg);
      break;
  }
}

/////////////
// very similar to the above func, but only validates
// RETURNS: TRUE  .. good code
//          FALSE .. Illegal - process must terminate
//
static BOOL ValidCode (UINT16 uInst, INT16 wArg)
{
  INT16  oper, k1, k2, k3;

  k2 = k3 = 0;
  oper = (INT16)(uInst & 0xff);
  k1 = ((oper >= LIT)  && (oper <= CSP))  ?  oper      :
       ((oper == LODX) || (oper == STOX)) ? (oper - 9) : ILLEGAL_PCD;
  switch (k1) {
    case OPR:
      k2 = ((wArg >= _RET) && (wArg < ILLEGAL_OPR_ARG)) ? wArg : ILLEGAL_OPR_ARG;
      break;
    case CSP:
      k3 = ((wArg >= CHIN) && (wArg < ILLEGAL_CSP_ARG)) ? wArg : ILLEGAL_CSP_ARG;
      break;
  }
  return (((k1 == ILLEGAL_PCD) ||
       (k2 == ILLEGAL_OPR_ARG) ||
       (k3 == ILLEGAL_CSP_ARG)) ? FALSE : TRUE);
}

/////////////////////////////////// eof ////////////////////////////////////