/****************************************************************************
**
**  Name:  CPUTAB.C
**
**  Description:
**     CPU table read routines.
**
**  Status:  TESTED
**
**  $Log:   S:/tbird/mt2_186/cpu/cputab.c_v  $
** 
**    Rev 1.0   16 Dec 1996 16:01:56   Judy
** Initial revision.
** 
**    Rev 1.11   22 Sep 1994 08:54:12   marilyn
** Extended the size of the register table to hold all the hidden
** segment registers.
** 
**    Rev 1.10   24 Jun 1994 08:20:24   dennis
** Added support for registers AX, AH, AL, BX, BH, BL, CX, CH, CL, DX, DH,
** DL, DI, SI, IP, SP, BP.
** 
**    Rev 1.9   19 May 1994 16:11:56   dennis
** Added two fields in the cpu"proc".cfg file. The first field is the offset
** from the base register value found in sdprobe.h (SD_REG00). This allows the
** .cfg file to have non-contiguous registers. The second field is a visible
** field, 1 = show in CPU window, 0 = do not show in CPU window. This is to
** support 386 stuff.
** 
**    Rev 1.8   18 May 1994 08:42:10   dennis
** Added a parameter after the signal name in the cpu"proc".cfg file. This
** code dealt with reading the cpu.cfg file. This parameter is an index
** from the base signal register value (SD_SIG00).
** 
**    Rev 1.7   16 Jul 1993 11:49:14   ernie
** Removed error.h include.  All errors now in errcodec.h
** 
**    Rev 1.6   13 Jul 1993 19:16:08   doug
** Change error name to avoid conflict with other module
** 
**    Rev 1.5   30 Jun 1993 10:21:34   steveh
** Changed CPU_NO to NO_CPU
** 
**    Rev 1.4   31 Mar 1993 13:41:32   ernie
** 1. Changed logic to avoid hardcoding configuration file names.  Now
**    calls ProcInsertCpu() to create a filename of the form "cpu%s.cfg",
**    where %s is replaced by the cpu name ("cpu16" or "cpu32").  This
**    avoids changes to this file when new cpu families are implemented.
** 2. Changed logic for displaying error when the configuration file
**    cannot be opened.  Now uses ErrDisplayString() so that the filename
**    is part of the error message.
** 
**    Rev 1.3   30 Mar 1993 08:32:14   ernie
** 1. Heavy cleanup to conform to Microtek coding standards.
** 2. Changed format and name of config file to allow generic presenter.
** 
**    Rev 1.2   31 Jul 1992 09:39:12   doug
** change name of configuration file to be consistent with others
** 
**    Rev 1.1   21 Jul 1992 08:12:50   doug
** a) no aliases
** b) removed nitems to get rid of warning
** 
**    Rev 1.0   14 Jul 1992 12:18:28   courtney
** Initial revision.
** 
**  $Header:   S:/tbird/mt2_186/cpu/cputab.c_v   1.0   16 Dec 1996 16:01:56   Judy  $
**
**  Copyright (C) 1992 Microtek International.  All rights reserved.
**
*****************************************************************************/

		       /****************************
			*                          *
						*       INCLUDE FILES      *
						*                          *
						****************************/
#include <stdio.h>
#include <string.h>
#ifndef _CPU_
#include "cpu.h"        /* CPU Server */
#endif
#ifndef _CPUCLI_
#include "cpucli.h"     /* CPU Server cli and Internal data structures */
#endif
#ifndef _CPUERR_
#include "cpuerr.h"
#endif
#ifndef _HEAP_
#include "heap.h"
#endif
#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif
#ifndef _PROC_
#include "proc.h"
#endif

					/****************************
					*                           *
					*     LOCAL PROTOTYPES      *
					*                           *
					****************************/

RETCODE PRIVATE BuildRegTable(VOID);
RETCODE PRIVATE BuildSignalTable(VOID);

					/****************************
					*                           *
					*     LOCAL DEFINITIONS     *
					*                           *
					****************************/


#define PATHLEN  128  /* Dos specific */
#define MAX_LINE  80

#define MAX_CPU_REGISTERS  0x4f  /* max 64 ? supported by firmware */
#define MAX_CPU_SIGNALS    0x0f  /* max 16 signals supported by firmware */

static FILE *ifp;  /* cpu configuration file */
static S8 cline[MAX_LINE];

					/****************************
					*                           *
					*    EXTERNAL VARIABLES     *
					*                           *
					****************************/

extern REGISTER_ENTRY *regTable;
extern SIGNAL_ENTRY *signalTable;
extern U16 nRegisters;
extern U16 nSignals;
extern REG_ID regSP;

					/****************************
					*                           *
					*      EXECUTABLE CODE      *
					*                           *
					*****************************/


RETCODE EXPORT BuildTables() {
   RETCODE err;
   S8 cpuConfigFilename[32];

  /* Changed the ProcInsertCpu call to the new ProcInsertSpecificCpu  */
  /* call so that 80386 could be supported. There are three different */
  /* .cfg files for the 80386 to support different signals for the EX,*/
  /* CX and DX/SX versions. These are cpu386ex.cfg, cpu386cx.cfg and  */
  /* cpu386.cfg respectively.                                         */
   if ((err = ProcInsertSpecificProcessor("cpu%s.cfg",cpuConfigFilename)) 
       != GOOD) return(err);

   if ((ifp = fopen(cpuConfigFilename, "r")) == NULL) {
      err = ER_NO_CPU_CONFIG_FILE;
      ErrDisplayString(err, cpuConfigFilename, FORCE_POPUP);
      return (err);
   }

   if ((err = BuildRegTable()) != GOOD) {
      fclose(ifp);
      nRegisters=0;
      return (err);
   }
   if ((err = BuildSignalTable()) != GOOD) {
      fclose(ifp);
      nSignals=0;
      return (err);
   }
   fclose(ifp);
   return (GOOD);
}  /* BuildTables */

/* see _BuildXlate in lxlate.c */
RETCODE PRIVATE BuildRegTable(VOID) {
    static char rname[10];  /* register name */
    U16 rsize, nFlags, line;
    S16 i;  /* register index */
    static char item[20];
    U16 nsize;
	 U16 regIndex, visible;
    U16 multiplexed, startBit;

    /* skip ahead to nRegs line in config file */
    do {
       if (fgets(cline, MAX_LINE, ifp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
    } while (strstr(cline, "nRegs") == NULL);
    
    /* read in number of registers */
    sscanf(cline, "%5s = %d", item, &nRegisters);
    if (nRegisters > MAX_CPU_REGISTERS) nRegisters = MAX_CPU_REGISTERS;

    nsize = nRegisters*sizeof(REGISTER_ENTRY);
    if ((regTable = (REGISTER_ENTRY *)TMalloc(nsize)) == NULL)
	return (ER_NO_MEM);

    /*
    ** Register table format:
    **   register name
    **   number of bits
    **   type of display (0=hex, 1=flags)
    **   line number in cpu presenter window (top line is 0)
    */ 
    for (i=0; i<nRegisters; i++) {
	if (fgets(cline, MAX_LINE, ifp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
	if (sscanf(cline, "%10s %d %d %d %d %d %d %d", rname, &rsize, &nFlags, &line,
		   &regIndex, &visible, &multiplexed, &startBit)
	   != 8) return(ER_CPU_CONFIG_FILE_FORMAT);
	strcpy(regTable[i].regName, rname);
	regTable[i].regWidth = rsize;
	regTable[i].numberOfFlags = min(32,nFlags);
	regTable[i].presenterLine = line;
	regTable[i].flagTable = NULL;
	regTable[i].sdDesc = NULL;

	/* Added by Dennis Lamb May 19, 1994 to support 386 stuff. */
		/* The address server needs to have LDTBASE, LDTLIMIT,     */
		/* GDTBASE, GDTLIMIT and CS3 registers. The old code used  */
		/* to have to have the registers in the cpu"proc".cfg file */
		/* in the same order that the register names were defined  */
		/* in the sdprobe.h file. The regIndex value is the offset */
		/* from the register base value (SD_REG00), visible tells  */
		/* the presenter whether or not to include this register   */
		/* in the list to display.                                 */
		regTable[i].regIndex = regIndex;
		regTable[i].visible = visible;

	/* Added by Dennis Lamb June 22, 1994 to support 386 stuff. */
		/* This is to support Intel registers AX, AH, AL. The start */
      /* bit determines what bits are affected in the main reg    */
      /* (EAX). The multiplexed flag indicates that this register */
      /* is part of a main register.                              */
		regTable[i].startBit = startBit;
		regTable[i].multiplexed = (multiplexed == 1);
    }

    /*
    ** For each register indicated as displayAsFlags, find the flag bit
    ** description in the file and load into that register's flagTable.
    */
    for (i=0; i<nRegisters; i++) if (regTable[i].numberOfFlags > 0) {
       U16 field,aChar,nChar,type,shift;
       U32 mask;
       do {
	  if (fgets(cline, MAX_LINE, ifp) == NULL)
	     return(ER_CPU_CONFIG_FILE_FORMAT);
       } while (strstr(cline, regTable[i].regName) == NULL);

       nsize = nRegisters*sizeof(REGISTER_ENTRY);
       if ((regTable[i].flagTable = (FLAG_TABLE *)
	      TMalloc(regTable[i].numberOfFlags*sizeof(FLAG_TABLE))) == NULL)
	  return (ER_NO_MEM);
       for (field=0; field<regTable[i].numberOfFlags; field++) {
	  if (fgets(cline, MAX_LINE, ifp) == NULL)
	     return(ER_CPU_CONFIG_FILE_FORMAT);
	  if (sscanf(cline, "%c %c %d %lx", &aChar, &nChar, &type, &mask) != 4)
	     return(ER_CPU_CONFIG_FILE_FORMAT);
	  regTable[i].flagTable[field].assertedChar = aChar;
	  regTable[i].flagTable[field].negatedChar = nChar;
	  regTable[i].flagTable[field].displayAsChar = (type == 1);
	  regTable[i].flagTable[field].mask = mask;
	  for (shift=0; (mask&1L)==0; shift++) mask>>=1;  /*find lsb of field*/
	  regTable[i].flagTable[field].shift = shift;
       }
    }
    return(GOOD);
}  /* BuildRegTable */

RETCODE PRIVATE BuildSignalTable(VOID) {
    static char sname[10];  /* signal name */
    S16 i;  /* signal index */
    static char item[20];
    U16 nsize;
    char *ret;
    S8 sigVal; /* offset from SDPROBE.H SDN_SIG00 value */
 
    /* fill signalTable from values in cpu configuration file */
    /* read in nSignals from first item in cpucfg.xxx file */
    while ((ret = fgets(cline, MAX_LINE, ifp)) != NULL) {
	if (strstr(cline, "nSigs") != NULL)
	    break;
    }
    if (ret == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);

    sscanf(cline, "%5s = %d", item, &nSignals);
    /* check value for validity */
    if (nSignals > MAX_CPU_SIGNALS)
	nSignals = MAX_CPU_SIGNALS;

    nsize = nRegisters*sizeof(SIGNAL_ENTRY);
    if ((signalTable = (SIGNAL_ENTRY *)TMalloc(nsize)) == NULL)
	return (ER_NO_MEM);

    i = 0;
    while ((ret = fgets(cline, MAX_LINE, ifp)) != NULL) {
	    /*********** Changed by Dennis Lamb, April 11, 1994 **********/
	/* Modifed the code to get the .sigVal from the CPU.cfg file */
	/*       if (sscanf(cline, "%10s", sname) != 1)              */

	if (sscanf(cline, "%10s%d", sname, &sigVal) != 2)
	    continue;
	strcpy(signalTable[i].signalName, sname);

		/************ Added by Dennis Lamb April 11, 1994 ***************/
	/* Set the offset value from SDN_SIG00, read from CPU.cfg file. */
	signalTable[i].sigVal = sigVal;

	signalTable[i++].sdDesc = NULL;
	if (i == nSignals)
	    break;
    }
    if (ret == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
    return (GOOD);

}  /* BuildSignalTable */


/******************************** E O F ***********************************/
