/**
  
    Copyright (C) Tektronix, Inc. 1998 - 2001. All rights reserved.
  
    @author Tektronix CTE               @(#) %derived_by: guidod %
    @version %version: bln_mpt1!5.45 %
      (%date_modified: Tue Aug 13 14:56:19 2002 %)
 */
/*@{ */
#if defined(__version_control__) && defined(__GNUC__)
static char * id __attribute__((unused)) =
"@(#) $Id: %full_filespec: main-k12.c~bln_mpt1!5.45:csrc:bln_12xx!2 % $";
#endif

#define _P4_SOURCE 1

#include <pfe/incl-ext.h>

#include <stddef.h> /*offsetof*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include <taskLib.h>
#include <sysLib.h>
#include <time.h>
#include <K12/emul.h>
#include <K12/trace.h>

#include <pfe/main-sub.h>
#include <pfe/main-k12.h>
#include <pfe/term-k12.h>
#include <pfe/logging.h>
#include <pfe/def-restore.h>

#include <pfe/engine-sub.h>
#include <pfe/version-sub.h>
#include <gemapi.h>

#ifdef  CLOCKS_PER_SEC_BUG
#undef  CLOCKS_PER_SEC
#define CLOCKS_PER_SEC sysClkRateGet()
#endif

#ifndef DIM
#define DIM(X) sizeof(X)/sizeof(*X)
#endif
#ifndef _K12_EAGAIN     /* the LEM does not know what to do about EAGAIN */
#define _K12_EAGAIN	K12_GEN_OK
#endif
#ifndef MSC_MAX_VARS             /* user-config */
#define MSC_MAX_VARS   16
#endif
#ifndef MAX_MAX_TIMERS           /* user-config */
#define MSC_MAX_TIMERS 64
#endif

/* definition of enumeral types, for config/query menu */
static k12_emu_enum_t
StatesEnum[] =
{
    
{ "COMP", -1 }
,
{ "EXEC",  0 }
,
{ "COMP",  1 }
, }
;
k12_emu_enum_t
p4_emu_hmsc_action_enum[] =
{
    
{ "NONE", 0 }
,
{ "Start", 1 }
,
{ "Stop", 2 }
,
{ "Continue", 3 }
,
{ "Reload", 4 }
,
{ "Reset", 5 }
, }
;
k12_emu_enum_t
p4_emu_state__k12_enum[] =
{
    
{ "NOT_LOADED", K12_EMU_NOT_LOADED }
,
{ "IDLE"      , K12_EMU_IDLE       }
,
{ "ACTIVE"    , K12_EMU_ACTIVE     }
,
{ "WARNING"   , K12_EMU_WARNING    }
,
{ "ERROR_CASE", K12_EMU_ERROR_CASE }
,
{ "NO_ANSWER" , K12_EMU_NO_ANSWER  }
}
; status_t p4_conftrace (k12_emu_type_t* emulId, u32_t request, u32_t* value, u32_t* addr);
/* BEWARE: called from LEM context */
k12_status_t
p4_emu_state (k12_emu_type_t *emulId,
              u32_t mode,
              u32_t *value,
              s8_t *addr)
{
    p4_emu_t *p4_emu;
    /* NO P4_CALLER_SAVEALL necessary - no forth VM register used */

    if (k12EmuLowBaseGet (emulId, (s8_t **) &p4_emu) != K12_GEN_OK)
    
{
        P4_fatal ("Could not get base!\n");
        return (K12_EMU_LOW_ERROR);
    }
#if 0 /* silently ignore CONFIG */ if (mode & K12_EMU_CONFIG)
{
        if (p4_emu->private.state != K12_EMU_NOT_LOADED /* at the begin */
          && *value != K12_EMU_NOT_LOADED)    /* at the end   */
        
{
            P4_warn ("config of read only value \"state\"\n");
        }
else
{
            p4_emu->state = *value;
        }
return (K12_GEN_OK); }
#endif /* 0 */ if (mode & K12_EMU_QUERY)
{
        *value = p4_emu->private.state;
    }
return (K12_GEN_OK); }
/* BEWARE: called from LEM context */
k12_status_t
p4_emu_state_desc (k12_emu_type_t *emulId,
                   u32_t mode,
                   s8_t *value,
                   s8_t *addr)
{
    p4_emu_t *p4_emu;
    /* NO P4_CALLER_SAVEALL necessary - no forth VM register used */

    if (k12EmuLowBaseGet (emulId, (s8_t **) &p4_emu) != K12_GEN_OK)
    
{
        P4_fatal ("Could not get base!\n");
        return (K12_EMU_LOW_ERROR);
    }
if (mode & K12_EMU_QUERY)
{
        switch (p4_emu->private.state)
        
{
        case K12_EMU_NOT_LOADED:
            /* tell why not ready for action */
            if (! p4_emu->thread.dict)
            
{   /* boot_system not through */
                strcpy (value, "INIT: receiving config options");
            }
else if (! p4_emu->thread.fence)
{   /* boot_system not through */
                strcpy (value, "BOOT: setting up base system");
            }
else if (p4_emu->thread.input.source_id != 0 && p4_emu->thread.input.source_id != -1)
{   /* loading a file, source_id is a p4_File */
                sprintf (value, "LOAD: %.*s : %u", 240,
                         ((p4_File*)p4_emu->thread.input.source_id)->name,
                         ((p4_File*)p4_emu->thread.input.source_id)->n);
            }
else
{
                strcpy (value, "LOAD: - : looking for commands");
            }
break; case K12_EMU_IDLE: strcpy (value, "Forth System Ready"); break; case K12_EMU_ACTIVE: strcpy (value, "Test Manager Active"); break; case K12_EMU_WARNING: strcpy (value, "Warning "); if (p4_emu->private.answerwarning) strcat (value, p4_emu->private.answerbuf); break; case K12_EMU_ERROR_CASE: strcpy (value, "Error "); if (p4_emu->private.answerwarning) strcat (value, p4_emu->private.answerbuf); break; case K12_EMU_NO_ANSWER: strcpy (value, "No Answer"); break; default: strcpy (value, "(not available)"); break; }
}
return (K12_GEN_OK); }
/* BEWARE: called from LEM context */
/* Used outside of pfe.o */
status_t
p4_emu_not_implemented (k12_emu_type_t* pEmul,
                        u32_t Mode,
                        u8_t* pString,
                        s8_t* pAddr)
{
    /* NO P4_CALLER_SAVEALL necessary - no forth VM register used */

    K12LogWarn1("p4 emu call", " '%s' not implemented\n", pAddr);
    /*  return K12_GEN_NOT_IMPLEMENTED; *FIXME:*/
    return K12_GEN_OK;
}
/* BEWARE: called from LEM context */
status_t
p4_emu_ignore (k12_emu_type_t* pEmul,
               u32_t Mode,
               u8_t* pString,
               s8_t* pAddr)
{
    /* NO P4_CALLER_SAVEALL necessary - no forth VM register used */

    /*  return K12_GEN_NOT_IMPLEMENTED; *FIXME:*/
    return K12_GEN_OK;
}
/* BEWARE: called from LEM context */
status_t
p4_emu_version (k12_emu_type_t* emul_id,
		u32_t mode,
		u8_t* str,
		s8_t* addr)
{
    /* <head> */
    register status_t e;
    p4_emu_t* p4;
    /* only partial P4_CALLER_SAVE necessary - just REGTH of the Forth VM */
    P4_REGTH_MKSAVED;

    e=k12EmuLowBaseGet (emul_id, (void*)&p4);
    if (e) return e;
    p4TH = &p4->thread; /* enough of forth context */
    /* <body> */
    
{
	if (mode&K12_EMU_QUERY)
	
{
	    strncpy (str, p4_version_string (), 80); /* << REGTH usage */
	    P4_REGTH_RESTORE; return (K12_GEN_OK);
	}
}
P4_REGTH_RESTORE; return (K12_GEN_OK); }
/** BEWARE: helper function, make sure to save LEM context and setup the
            forth's REGTH (if it uses a cpu register for that).
   this function will create an eventbuffer that will land
   in the term-k12 getevent loop - it will work as if the
   the string has been magically typed on the terminal. It
   can be used to send a string from LEM-context (during a
   config-request) to the PFE-context (in its getevent loop).
   The string will be implicitly terminated with a CR to start
   execution in the engine's interpret_loop.
 */
status_t
p4_emu_sendme_command (k12_emu_type_t* emul_id, const u8_t* str, int len)
{
    register status_t e;
    char* data_buf;
    int k12_sap;
    struct k12_priv* k12p;
    P4_enter2 ("sendme_command: '%.*s'", len, str);

    k12p = P4_K12_PRIV(p4TH);
    if (! FENCE) /* done p4_boot_system ? */
        k12_sap = K12_FORTH_COMMAND_SAP;
    else
        k12_sap = k12p->rx_dataSAP;

    /* send the string as XDAT */

    e=k12EmuLowBufferGet (emul_id,
                          2 + len + sizeof(k12_emu_msg_subhead_t),
                          &data_buf);
    if (e) 
{  P4_returns1 (e, "status %i", e); }
memset (data_buf,0,sizeof(k12_emu_msg_subhead_t)); memcpy (data_buf + sizeof(k12_emu_msg_subhead_t), str, len); memcpy (data_buf + sizeof(k12_emu_msg_subhead_t) + len, " \n", 2); ((k12_emu_msg_subhead_t*)data_buf) ->type = K12_EMU_XDAT_REQ; e=k12EmuLowEventPut (emul_id, k12_sap, data_buf, 2 + len + sizeof (k12_emu_msg_subhead_t), K12_EMU_NOOPT); if (e != K12_GEN_OK && e != K12_EMU_LOW_HIGH_WATER)
{ P4_warn1 ("k12EmuLowEventPut failed (%x) [data not sent]", e); }
# if 0 /* NEW: \n now added above */ /* now send the XDAT-enter command */ e=k12EmuLowBufferGet (emul_id, sizeof(k12_emu_msg_subhead_t), &data_buf); if (e)
{ P4_returns1 (e, "status %i", e); }
memset (data_buf, 0, sizeof(k12_emu_msg_subhead_t)); ((k12_emu_msg_subhead_t*)data_buf) ->type = K12_EMU_XDAT_REQ; e=k12EmuLowEventPut (emul_id, k12_sap, data_buf, sizeof (k12_emu_msg_subhead_t), K12_EMU_NOOPT); if (e != K12_GEN_OK && e != K12_EMU_LOW_HIGH_WATER)
{ P4_warn1 ("k12EmuLowEventPut failed (%x) [enter not sent]", e); }
#endif /* done */ P4_returns1 (e, "status %i", e); }
/* BEWARE: called from LEM context */
status_t
p4_emu_command (k12_emu_type_t* emul_id,
		u32_t mode,
		u8_t* str,
		s8_t* addr)
{
    /* <head> */
    register status_t e;
    p4_emu_t* p4;
    /* only partial P4_CALLER_SAVE necessary - just REGTH of the Forth VM */
    P4_REGTH_MKSAVED;

    e=k12EmuLowBaseGet (emul_id, (void*)&p4);
    if (e) return e;

    p4TH = &p4->thread; /* enough of forth context */
    /* <body> */
    
{
	struct k12_priv* k12p;
	k12p = P4_K12_PRIV(p4TH);

	if (mode&K12_EMU_CONFIG)
	
{
	    if (p4->config_blocked)
	    
{ P4_REGTH_RESTORE; return _K12_EAGAIN; }
e=p4_emu_sendme_command (emul_id, str, strlen(str)); /* REGTH!!*/ P4_REGTH_RESTORE; P4_returns1 (e, "status %i", e); }
if (mode&K12_EMU_QUERY)
{
	    if (FENCE)
	    
{
		P4_enter1 ("get '%s'", k12p->answerbuf);
		memcpy (str, k12p->answerbuf, k12p->answeridx+1);
		str[k12p->answeridx+1] = '\0';
		P4_REGTH_RESTORE; P4_returns (K12_GEN_OK, "done ok");
	    }
else
{
		strcpy (str, "\\ not running");
		P4_REGTH_RESTORE; P4_returns (_K12_EAGAIN, "query ignored");
	    }
}
}
P4_REGTH_RESTORE; P4_returns (K12_GEN_OK, "nothing to do -> return"); }
/* BEWARE: called from LEM context */
status_t
p4_emu_scriptfile (k12_emu_type_t* emul_id,
		   u32_t mode,
		   u8_t* str,
		   s8_t* addr)
{
    char buf [256] = "BOOT-SCRIPT: ";
    /* NO P4_CALLER_SAVEALL necessary - no forth VM register used */

    if (!str || strlen(str) <= 1) return K12_GEN_OK;
    if (mode&K12_EMU_QUERY) return K12_GEN_ILLMODE;

    strncat (buf, str, 256);
    strncat (buf, " BOOT-SCRIPT@ INCLUDED", 256);
    return p4_emu_command (emul_id, mode, buf, addr);
}
/* BEWARE: called from LEM context */
status_t
p4_emu_do_config (k12_emu_type_t* emul_id,
                  u32_t mode,
                  u32_t* pval,
                  s8_t* addr)
{
    /* <head> */
    register status_t e;
    p4_emu_t* p4;
    /* only partial P4_CALLER_SAVE necessary - just REGTH of the Forth VM */
    P4_REGTH_MKSAVED;

    e=k12EmuLowBaseGet (emul_id, (void*)&p4);
    if (e) return e;
    if (mode&K12_EMU_CONFIG && p4->config_blocked)
    
{ P4_REGTH_RESTORE; return _K12_EAGAIN; }
p4TH = &p4->thread; /* enough forth context */ /* <body> */ P4_enter2 ("addr/idx=%x (#'%8s')", addr, 8); /**/ if (!memcmp(addr,"DictLeft",8))
{
        if (mode&K12_EMU_QUERY) *pval = (u32_t)(PFE.dictlimit - PFE.dp);
    }
else if (!memcmp(addr,"sp-depth",8))
{
#    ifndef P4_REGSP
        if (mode&K12_EMU_QUERY) *pval = (u32_t)(PFE.s0 - PFE.sp);
#    else
        if (mode&K12_EMU_QUERY) *pval = -1;
#    endif
    }
else if (!memcmp(addr,"rp-depth",8))
{
#    ifndef P4_REGRP
        if (mode&K12_EMU_QUERY) *pval = (u32_t)(PFE.r0 - PFE.rp);
#    else
        if (mode&K12_EMU_QUERY) *pval = -1;
#    endif
    }
else if (!memcmp(addr,"ttx-base",8))
{
        if (mode&K12_EMU_CONFIG && *pval) PFE.base = *pval;
        if (mode&K12_EMU_QUERY) *pval = (u32_t)(PFE.base);
    }
else if (!memcmp(addr,"p4-state",8))
{
        if (mode&K12_EMU_CONFIG) PFE.state = *pval;
        if (mode&K12_EMU_QUERY) *pval = (u32_t)(PFE.state);
    }
else if (!memcmp(addr, "thr-size",8))
{
        if (mode&K12_EMU_CONFIG) if(!PFE_MEM) PFE.set->total_size = *pval;
        if (mode&K12_EMU_QUERY) *pval = PFE.set->total_size;
    }
else if (!memcmp(addr, "sp-size-",8))
{
        if (mode&K12_EMU_CONFIG) if(!PFE_MEM) PFE.set->stack_size = *pval;
        if (mode&K12_EMU_QUERY) *pval = PFE.set->stack_size;
    }
else if (!memcmp(addr, "rp-size-",8))
{
        if (mode&K12_EMU_CONFIG) if(!PFE_MEM) PFE.set->ret_stack_size = *pval;
        if (mode&K12_EMU_QUERY) *pval = PFE.set->ret_stack_size;
    }
P4_REGTH_RESTORE; if (e)
{
	P4_returns1 (e, "config subcall failed (#'%8s')", addr);
    }
else
{
	P4_returns (K12_GEN_OK, "done");
    }
}
/* ................................................................ */
/* BEWARE: called from LEM context */
status_t
p4_config_msc_int (k12_emu_type_t* emul_id,
                   u32_t mode,
                   u32_t* pval,
                   s8_t* addr)
{
    register status_t e;
    u32_t arg_idx = (u32_t) (void *) (addr);
    p4_emu_t* p4;
    /* NO P4_CALLER_SAVEALL necessary - no forth VM register used */

    if ((e = k12EmuLowBaseGet (emul_id, (void *) &p4)))
        return e;

    if ((mode & K12_EMU_CONFIG) && p4->config_blocked)
        return _K12_EAGAIN;

    if (arg_idx > 0 && arg_idx <= MSC_MAX_VARS)
    
{
        if (mode & K12_EMU_CONFIG)
            p4->msc_vars.msc_ints[arg_idx - 1] = *pval;
        if (mode & K12_EMU_QUERY)
            *pval = p4->msc_vars.msc_ints[arg_idx - 1];
    }
else
{
        P4_warn1 ("Parameter arg_idx out of range (%d)", arg_idx);
    }
return K12_GEN_OK; }
/* BEWARE: called from LEM context */
status_t
p4_config_msc_string (k12_emu_type_t* emul_id,
                      u32_t mode,
                      u8_t* pval,
                      s8_t* addr)
{
    register status_t e;
    u32_t arg_idx = (u32_t) (void *) (addr);
    p4_emu_t* p4;
    /* NO P4_CALLER_SAVEALL necessary - no forth VM register used */

    if ((e = k12EmuLowBaseGet (emul_id, (void *) &p4)))
        return e;

    if ((mode & K12_EMU_CONFIG) && p4->config_blocked)
        return _K12_EAGAIN;

    if (arg_idx > 0 && arg_idx <= MSC_MAX_VARS)
    
{
        if (mode & K12_EMU_CONFIG)
        
{
            int len = pval? strlen (pval): 0;
            memcpy (p4->msc_vars.msc_strings[arg_idx - 1] + 1, pval, len);
            p4->msc_vars.msc_strings[arg_idx - 1][0] = len;
        }
if (mode & K12_EMU_QUERY)
{
            int len = p4->msc_vars.msc_strings[arg_idx - 1][0];
            memcpy (pval, p4->msc_vars.msc_strings[arg_idx - 1] + 1, len);
            pval[len] = '\0';
        }
}
else
{
        P4_warn1 ("Parameter arg_idx out of range (%d)", arg_idx);
    }
return K12_GEN_OK; }
/* BEWARE: called from LEM context */
status_t
p4_config_msc_timer (k12_emu_type_t* emul_id,
                     u32_t mode,
                     u32_t* pval,
                     s8_t* addr)
{
    register status_t e;
    u32_t arg_idx = (u32_t) (void *) (addr);
    p4_emu_t* p4;
    /* NO P4_CALLER_SAVEALL necessary - no forth VM register used */

    if ((e = k12EmuLowBaseGet (emul_id, (void *) &p4)))
        return e;

    if ((mode & K12_EMU_CONFIG) && p4->config_blocked)
        return _K12_EAGAIN;

    if (arg_idx > 0 && arg_idx <= MSC_MAX_TIMERS)
    
{
        if (mode & K12_EMU_CONFIG)
            p4->msc_vars.msc_timers[arg_idx - 1] = *pval;
        if (mode & K12_EMU_QUERY)
            *pval = p4->msc_vars.msc_timers[arg_idx - 1];
    }
else
{
        P4_warn1 ("Parameter arg_idx out of range (%d)", arg_idx);
    }
return K12_GEN_OK; }
#define p4_emu_cpuipcsend p4_emu_ignore #define p4_emu_do_or_tm_config p4_emu_do_config #define p4_emu_hmsc_action p4_emu_ignore #define p4_emu_tm_action p4_emu_ignore #define p4_emu_tm_config p4_emu_do_config #define p4_emu_verdict_action p4_emu_ignore #include <pfe/emu-menu-table.c>
k12_emu_in_out_t p4_emu_inp_tab[] =
{                             /* name and type of inputs */
    
{ "Lower0",   K12_EMU_LOWER }
,
{ "Lower1",   K12_EMU_LOWER }
,
{ "Lower2",   K12_EMU_LOWER }
,
{ "Lower3",   K12_EMU_LOWER }
,
{ "Lower4",   K12_EMU_LOWER }
,
{ "Lower5",   K12_EMU_LOWER }
,
{ "Lower6",   K12_EMU_LOWER }
,
{ "Lower7",   K12_EMU_LOWER }
,
{ "Lower8",   K12_EMU_LOWER }
,
{ "Lower9",   K12_EMU_LOWER }
,
{ "Upper0",   K12_EMU_UPPER }
,
{ "Upper1",   K12_EMU_UPPER }
,
{ "Upper2",   K12_EMU_UPPER }
,
{ "Upper3",   K12_EMU_UPPER }
,
{ "Upper4",   K12_EMU_UPPER }
,
{ "Upper5",   K12_EMU_UPPER }
,
{ "Upper6",   K12_EMU_UPPER }
,
{ "Upper7",   K12_EMU_UPPER }
,
{ "Upper8",   K12_EMU_UPPER }
,
{ "Upper9",   K12_EMU_UPPER }
,
{ "Lower10",  K12_EMU_LOWER }
,
{ "Lower11",  K12_EMU_LOWER }
,
{ "Lower12",  K12_EMU_LOWER }
,
{ "Lower13",  K12_EMU_LOWER }
,
{ "Lower14",  K12_EMU_LOWER }
,
{ "Lower15",  K12_EMU_LOWER }
,
{ "Lower16",  K12_EMU_LOWER }
,
{ "Lower17",  K12_EMU_LOWER }
,
{ "Lower18",  K12_EMU_LOWER }
,
{ "Lower19",  K12_EMU_LOWER }
,
{ "Upper10",  K12_EMU_UPPER }
,
{ "Upper11",  K12_EMU_UPPER }
,
{ "Upper12",  K12_EMU_UPPER }
,
{ "Upper13",  K12_EMU_UPPER }
,
{ "Upper14",  K12_EMU_UPPER }
,
{ "Upper15",  K12_EMU_UPPER }
,
{ "Upper16",  K12_EMU_UPPER }
,
{ "Upper17",  K12_EMU_UPPER }
,
{ "Upper18",  K12_EMU_UPPER }
,
{ "Upper19",  K12_EMU_UPPER }
,
{ "Lower20",  K12_EMU_LOWER }
,
{ "Lower21",  K12_EMU_LOWER }
,
{ "Lower22",  K12_EMU_LOWER }
,
{ "Lower23",  K12_EMU_LOWER }
,
{ "Lower24",  K12_EMU_LOWER }
,
{ "Lower25",  K12_EMU_LOWER }
,
{ "Lower26",  K12_EMU_LOWER }
,
{ "Lower27",  K12_EMU_LOWER }
,
{ "Lower28",  K12_EMU_LOWER }
,
{ "Lower29",  K12_EMU_LOWER }
,
{ "Upper20",  K12_EMU_UPPER }
,
{ "Upper21",  K12_EMU_UPPER }
,
{ "Upper22",  K12_EMU_UPPER }
,
{ "Upper23",  K12_EMU_UPPER }
,
{ "Upper24",  K12_EMU_UPPER }
,
{ "Upper25",  K12_EMU_UPPER }
,
{ "Upper26",  K12_EMU_UPPER }
,
{ "Upper27",  K12_EMU_UPPER }
,
{ "Upper28",  K12_EMU_UPPER }
,
{ "Upper29",  K12_EMU_UPPER }
,
{ "Lower30",  K12_EMU_LOWER }
,
{ "Lower31",  K12_EMU_LOWER }
,
{ "Lower32",  K12_EMU_LOWER }
,
{ "stdin",    K12_EMU_LOWER }
, }
;
k12_emu_in_out_t p4_emu_out_tab[] =
{                             /* name and type of outputs */
    
{ "Lower0",   K12_EMU_LOWER }
,
{ "Lower1",   K12_EMU_LOWER }
,
{ "Lower2",   K12_EMU_LOWER }
,
{ "Lower3",   K12_EMU_LOWER }
,
{ "Lower4",   K12_EMU_LOWER }
,
{ "Lower5",   K12_EMU_LOWER }
,
{ "Lower6",   K12_EMU_LOWER }
,
{ "Lower7",   K12_EMU_LOWER }
,
{ "Lower8",   K12_EMU_LOWER }
,
{ "Lower9",   K12_EMU_LOWER }
,
{ "Upper0",   K12_EMU_UPPER }
,
{ "Upper1",   K12_EMU_UPPER }
,
{ "Upper2",   K12_EMU_UPPER }
,
{ "Upper3",   K12_EMU_UPPER }
,
{ "Upper4",   K12_EMU_UPPER }
,
{ "Upper5",   K12_EMU_UPPER }
,
{ "Upper6",   K12_EMU_UPPER }
,
{ "Upper7",   K12_EMU_UPPER }
,
{ "Upper8",   K12_EMU_UPPER }
,
{ "Upper9",   K12_EMU_UPPER }
,
{ "Lower10",  K12_EMU_LOWER }
,
{ "Lower11",  K12_EMU_LOWER }
,
{ "Lower12",  K12_EMU_LOWER }
,
{ "Lower13",  K12_EMU_LOWER }
,
{ "Lower14",  K12_EMU_LOWER }
,
{ "Lower15",  K12_EMU_LOWER }
,
{ "Lower16",  K12_EMU_LOWER }
,
{ "Lower17",  K12_EMU_LOWER }
,
{ "Lower18",  K12_EMU_LOWER }
,
{ "Lower19",  K12_EMU_LOWER }
,
{ "Upper10",  K12_EMU_UPPER }
,
{ "Upper11",  K12_EMU_UPPER }
,
{ "Upper12",  K12_EMU_UPPER }
,
{ "Upper13",  K12_EMU_UPPER }
,
{ "Upper14",  K12_EMU_UPPER }
,
{ "Upper15",  K12_EMU_UPPER }
,
{ "Upper16",  K12_EMU_UPPER }
,
{ "Upper17",  K12_EMU_UPPER }
,
{ "Upper18",  K12_EMU_UPPER }
,
{ "Upper19",  K12_EMU_UPPER }
,
{ "Lower20",  K12_EMU_LOWER }
,
{ "Lower21",  K12_EMU_LOWER }
,
{ "Lower22",  K12_EMU_LOWER }
,
{ "Lower23",  K12_EMU_LOWER }
,
{ "Lower24",  K12_EMU_LOWER }
,
{ "Lower25",  K12_EMU_LOWER }
,
{ "Lower26",  K12_EMU_LOWER }
,
{ "Lower27",  K12_EMU_LOWER }
,
{ "Lower28",  K12_EMU_LOWER }
,
{ "Lower29",  K12_EMU_LOWER }
,
{ "Upper20",  K12_EMU_UPPER }
,
{ "Upper21",  K12_EMU_UPPER }
,
{ "Upper22",  K12_EMU_UPPER }
,
{ "Upper23",  K12_EMU_UPPER }
,
{ "Upper24",  K12_EMU_UPPER }
,
{ "Upper25",  K12_EMU_UPPER }
,
{ "Upper26",  K12_EMU_UPPER }
,
{ "Upper27",  K12_EMU_UPPER }
,
{ "Upper28",  K12_EMU_UPPER }
,
{ "Upper29",  K12_EMU_UPPER }
,
{ "Lower30",  K12_EMU_LOWER }
,
{ "Lower31",  K12_EMU_LOWER }
,
{ "Lower32",  K12_EMU_LOWER }
,
{ "stdin",    K12_EMU_LOWER }
, }
;
k12_emu_table_t p4_emu_table =
{
    DIM (p4_emu_inp_tab), p4_emu_inp_tab,
    DIM (p4_emu_out_tab), p4_emu_out_tab,
    DIM (p4_emu_menu_tab), p4_emu_menu_tab
}
;
/* This table is needed to connect PFE with another emulation.
   Useful for MSC! */
char* k12_pfe_sap_table[] = 
{
    "Lower0",
    "Lower1",
    "Lower2",
    "Lower3",
    "Lower4",
    "Lower5",
    "Lower6",
    "Lower7",
    "Lower8",
    "Lower9",
    "Upper0",
    "Upper1",
    "Upper2",
    "Upper3",
    "Upper4",
    "Upper5",
    "Upper6",
    "Upper7",
    "Upper8",
    "Upper9",
    "Lower10",
    "Lower11",
    "Lower12",
    "Lower13",
    "Lower14",
    "Lower15",
    "Lower16",
    "Lower17",
    "Lower18",
    "Lower19",
    "Upper10",
    "Upper11",
    "Upper12",
    "Upper13",
    "Upper14",
    "Upper15",
    "Upper16",
    "Upper17",
    "Upper18",
    "Upper19",
    "Lower20",
    "Lower21",
    "Lower22",
    "Lower23",
    "Lower24",
    "Lower25",
    "Lower26",
    "Lower27",
    "Lower28",
    "Lower29",
    "Upper20",
    "Upper21",
    "Upper22",
    "Upper23",
    "Upper24",
    "Upper25",
    "Upper26",
    "Upper27",
    "Upper28",
    "Upper29",
    "Lower30",
    "Lower31",
    "Lower32",
    "stdin",
    NULL }
;
/* ? */
/* ............................................................ */
status_t
emuInit (k12_emu_type_t* emul_id)
{
    register status_t e;
    p4_emu_t* pEmul;
    /* NO P4_CALLER_SAVEALL necessary - no forth VM register used */

# ifdef DEBUG
    K12LogInit(0, 64, K12_LOG_DIRECT);
# endif

    e=k12EmuLowMemGet (emul_id, sizeof (p4_emu_t), (s8_t**) &pEmul);
    if (e) return (K12_GEN_NOMEM);

    memset (pEmul, 0, sizeof (p4_emu_t));
    /* pEmul->private.state = K12_EMU_IDLE; */ /* -> term-k12.c */

    /* must be called *before* TableInd - right ?? */
    p4_SetOptions (&pEmul->session, 0, 1, (char**) &"p4th");

    /* don't forget about prelinked modules, e.g. zchar-ext */
    
{ extern p4Words P4WORDS(internal);
    p4_SetModules (&pEmul->session, &(P4WORDS(internal)));
    }
/* pass table of features - menusystem may write to those vars now ! */ e=k12EmuLowTableInd (emul_id, &p4_emu_table, (s8_t *)pEmul); if (e) return (e); K12LogDebug1(1, "p4.emuInit", "privat data size=%08lX\n", (u32_t)sizeof(p4_emu_t)); pEmul->thread.term = &p4_term_k12; /* the gui interface */ return (K12_GEN_OK); }
status_t
emuDeinit (k12_emu_type_t* emul_id)
{
    register status_t e;
    p4_emu_t* p4_emu;

    e=k12EmuLowBaseGet (emul_id, (void*)&p4_emu);
    if (e) return (e);

    /* p4TH is not enough context IFF calling userspace ATEXIT code */
    
{
        P4_CALLER_SAVEALL;
#      ifdef P4_REGTH
        p4TH = &p4_emu->thread;
#      endif
#      ifdef P4_REGRP
        p4RP = PFE.r0;
#      endif
#      ifdef P4_REGSP
        p4SP = PFE.s0;
#      endif
#      ifdef P4_REGFP
        p4FP = PFE.f0;
#      endif
        if (PFE_MEM)
        
{
            if (FENCE) 
                FX (p4_closeall_files);
            else 
{ P4_warn ("killed before (re)boot complete"); }
PFE.atexit_cleanup (); }
else
{ P4_fail ("killed before boot, bad setup? no ESE connection?");}
P4_CALLER_RESTORE; }
return K12_GEN_OK; }
status_t
emuStart (k12_emu_type_t* emul_id)
{
    register status_t e;
    p4_emu_t* p4_emu;
    /* P4_CALLER_SAVEALL not necessary - it has its own thread-context */

    e=k12EmuLowBaseGet (emul_id, (void*)&p4_emu);
    if (e) return (e);

    if (*p4_emu->includes)
        p4_emu->session.include_file = p4_emu->includes;
    if (!*p4_emu->incpaths)
        strncpy (p4_emu->incpaths, PFE_PKGDATADIR, 254);
    p4_emu->session.incpaths = p4_emu->incpaths;

    p4_emu->session.cpus = 1;
    /*  p4_emu->session.cpu[0] = &p4_emu->thread; */
    p4_emu->thread.set = &p4_emu->session;
    p4_emu->thread.priv = &p4_emu->private;
    p4_emu->private.emu = emul_id;

    p4_emu->private.validation_req = 0;
    
{
        int i = 0;
        k12_emu_event_t ev; k12_emu_msg_subhead_t* msg; u32_t len;
        P4_debug (13, "K12_EMU_VALIDATION_REQ used - set timeout to 200*HZ");
        k12EmuLowTimerStart (emul_id, 0x4e77 /* K12_EMU_VALIDATION_REQ */,
                             200*CLOCKS_PER_SEC);
        while (1)
        
{
            k12EmuLowEventGet(emul_id, &ev, (char**) &msg, &len, 0);
            switch (msg->type)
            
{
            case K12_EMU_MSG_TIMER:
            case 0x4e77:
                P4_warn2 ("0x%x : OOPS validation_req timeout :"
                          " CLOCKS_PER_SEC = %lu",
                          msg->type, ((long) CLOCKS_PER_SEC));
                taskDelay(CLOCKS_PER_SEC);
                if (p4_emu->private.state == K12_EMU_WARNING)
                
{
                    p4_emu->private.state = K12_EMU_ERROR_CASE;
                    P4_debug (13, "set EMU_ERROR - go creeping startup mode");
                }
else
{
                    p4_emu->private.state = K12_EMU_WARNING;
                    P4_debug (13, "set EMU_WARNING -  new timeout 1000*HZ");
                    k12EmuLowTimerStart (emul_id, 0x4e77, 1000*CLOCKS_PER_SEC);
                }
continue; /*NOT fallthrough*/ case K12_EMU_VALIDATION_REQ: k12EmuLowTimerStop(emul_id, 0x4e77 /*K12_EMU_VALIDATION_REQ*/); if (k12EmuLowEventPut(emul_id, ev, (char*) msg, len, K12_EMU_NOOPT) == K12_GEN_OK)
{ p4_emu->private.validation_req ++; }
return p4_Exec(&p4_emu->thread); /* outer-API (SAVEALL) */ default: P4_warn2 ("UNK START MSG type->0x%x len->%u", msg->type, len); /*fallthrough*/ case K12_EMU_XDAT_REQ: /* config-cb to command-msg via xdat-req */ if (++i > 3) P4_warn ("START DELAYED (and requeue message) (HZ/2)"); switch (p4_emu->private.state)
{
                case K12_EMU_ERROR_CASE:
                    taskDelay(CLOCKS_PER_SEC*16); break;
                case K12_EMU_WARNING:
                    taskDelay(CLOCKS_PER_SEC*2); break;
                default:
                    taskDelay(CLOCKS_PER_SEC/2); break;
                }
if (k12EmuLowEventPut(emul_id, ev, (char*) msg, len, K12_EMU_NOOPT))
{ P4_fail ("could not requeue message"); }
continue; }
}
}
}
status_t
p4_conftrace (k12_emu_type_t* emulId,
              u32_t request,
              u32_t* value,
              u32_t* addr)
{
    if (request == K12_EMU_QUERY)
    
{
        *value = (uint32_t) K12EmuTraceLevelGet(emulId);
        return (K12_GEN_OK);
    }
return (K12EmuTraceLevelSet (emulId, *value)); }
/*@} */
/*
   Local variables:
   c-file-style: "stroustrup"
   End:
 */