/****************************************************************************
**
**  Name:  CPUTAB.C
**
**  Description:
**     CPU table read routines.
**
**  Status:  TESTED
**
**  $Log:   S:/tbird/mt2_68k/cpu/cputab.c_v  $
** 
**    Rev 1.0   13 Feb 1997 08:44:48   gene
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 10:10:44   gene
** Initial revision.
** 
**    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_68k/cpu/cputab.c_v   1.0   13 Feb 1997 08:44:48   gene  $
**
**  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  0x3f  /* 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];

   if ((err = ProcInsertCpu("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;

    /* 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", rname, &rsize, &nFlags, &line)
           != 4) 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;
    }

    /*
    ** 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;

    /* 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) {
        if (sscanf(cline, "%10s", sname) != 1)
            continue;
        strcpy(signalTable[i].signalName, sname);
        signalTable[i++].sdDesc = NULL;
        if (i == nSignals)
            break;
    }
    if (ret == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
    return (GOOD);

}  /* BuildSignalTable */


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