Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
isa_decode_gen.cxx
Go to the documentation of this file.
00001 /*
00002 
00003   Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.
00004 
00005   This program is free software; you can redistribute it and/or modify it
00006   under the terms of version 2 of the GNU General Public License as
00007   published by the Free Software Foundation.
00008 
00009   This program is distributed in the hope that it would be useful, but
00010   WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013   Further, this software is distributed without any warranty that it is
00014   free of the rightful claim of any third person regarding infringement 
00015   or the like.  Any license provided herein, whether implied or 
00016   otherwise, applies only to this software file.  Patent licenses, if 
00017   any, provided herein do not apply to combinations of this program with 
00018   other software, or any other product whatsoever.  
00019 
00020   You should have received a copy of the GNU General Public License along
00021   with this program; if not, write the Free Software Foundation, Inc., 59
00022   Temple Place - Suite 330, Boston MA 02111-1307, USA.
00023 
00024   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00025   Mountain View, CA 94043, or:
00026 
00027   http://www.sgi.com
00028 
00029   For further information regarding this notice, see:
00030 
00031   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00032 
00033 */
00034 
00035 
00036 // isa_decode_gen.cxx
00038 //
00039 //  Generate an interface for decoding instructions.
00040 //
00042 //
00043 
00044 #include <stddef.h>
00045 #include <stdlib.h>
00046 #include <stdarg.h>
00047 #include <string.h>
00048 #include <stdio.h>
00049 #include <assert.h>
00050 #include <alloca.h>
00051 
00052 #include <list>
00053 
00054 using namespace std;
00055 
00056 #include "topcode.h"
00057 #include "gen_util.h"
00058 #include "isa_decode_gen.h"
00059 
00060 typedef enum { INST_STATE, UNIT_STATE } STATE_TYPE;
00061 
00062 typedef enum {
00063   VISIT_UNVISITED,
00064   VISIT_GEN_DATA,
00065   VISIT_GEN_CODE
00066 } VISIT_KIND;
00067 
00068 /* This struct is used to hold the information that describes
00069  * a state. The information is dependent on whether or not the
00070  * state is a final state or not.
00071  *
00072  * Final states are described completely by a topcode.
00073  *
00074  * Intermediate states, have one or more transitions to new states,
00075  * and a bitfield description of an instruction being decoded,
00076  * that determines which transition is taken.
00077  */
00078 struct state {
00079   bool is_final;
00080   VISIT_KIND visit;
00081   union {
00082     TOP final;          // final state
00083     struct {            // intermediate state
00084       const char *tag;
00085       int idx;
00086       int pos;
00087       int width;
00088       STATE *transition;
00089       STATE_TYPE stype;
00090       int casenum;
00091     } i;
00092   } u;
00093 };
00094 
00095 static STATE initial_state;
00096 static list <STATE> all_states;
00097 
00098 static const char * const interface[] = {
00099   "/* ====================================================================",
00100   " * ====================================================================",
00101   " *",
00102   " * Description:",
00103   " *",
00104   " *   Utilities for decoding binary instructions. The following",
00105   " *   are exported:",
00106   " *",
00107   " *   TOP ISA_Decode_Inst(const ISA_PACK_INST *pinst, ISA_EXEC_UNIT unit)",
00108   " *       Decode the instruction pointed to by <pinst> in execution unit",
00109   " *       <unit> and return its opcode by function return value.",
00110   " *",
00111   " * ====================================================================",
00112   " * ====================================================================",
00113   " */",
00114   NULL
00115 };
00116 
00117 
00119 void ISA_Decode_Begin(const char * /* name */)
00121 //  See interface description.
00123 {
00124 }
00125 
00127 STATE Create_Unit_State(const char *tag, int pos, int width)
00129 //  See interface description.
00131 {
00132   int i;
00133   STATE state = new struct state;
00134   state->is_final = false;
00135   state->visit = VISIT_UNVISITED;
00136   state->u.i.tag = tag;
00137   state->u.i.idx = 0;
00138   state->u.i.pos = pos;
00139   state->u.i.width = width;  
00140   state->u.i.transition = new STATE[1 << width];
00141   for (i = 0; i < (1 << width); ++i) state->u.i.transition[i] = NULL;
00142   state->u.i.stype = UNIT_STATE;
00143   all_states.push_back(state);
00144   return state;
00145 }
00146 
00148 STATE Create_Inst_State(const char *tag, int idx, int pos, int width)
00150 //  See interface description.
00152 {
00153   int i;
00154   STATE state = new struct state;
00155   state->is_final = false;
00156   state->visit = VISIT_UNVISITED;
00157   state->u.i.tag = tag;
00158   state->u.i.idx = idx;
00159   state->u.i.pos = pos;
00160   state->u.i.width = width;  
00161   state->u.i.transition = new STATE[1 << width];
00162   for (i = 0; i < (1 << width); ++i) state->u.i.transition[i] = NULL;
00163   state->u.i.stype = INST_STATE;
00164   all_states.push_back(state);
00165   return state;
00166 }
00167 
00169 void Transitions(STATE state, ...)
00171 //  See interface description.
00173 {
00174   int n;
00175   va_list ap;
00176   STATE transition;
00177 
00178   if (state->is_final) {
00179     fprintf(stderr, "### Error: can't specify transistions for a final state\n");
00180     exit(EXIT_FAILURE);
00181   }
00182 
00183   va_start(ap, state);
00184   while ((n = va_arg(ap, int)) != END_TRANSITIONS) {
00185     if (n < 0 || n >= (1 << state->u.i.width)) {
00186       fprintf(stderr, "### Error: transition %d of %s is out-of-range\n",
00187                       n, state->u.i.tag);
00188       exit(EXIT_FAILURE);
00189     }
00190     if (state->u.i.transition[n]) {
00191       fprintf(stderr, "### Error: transition %d of %s multiply specified\n",
00192                       n, state->u.i.tag);
00193       exit(EXIT_FAILURE);
00194     }
00195     transition = va_arg(ap, STATE);
00196     if ((unsigned long)transition < TOP_count) {
00197       fprintf(stderr, "### Error: transition %d of %s looks like it should be Final()\n",
00198                       n, state->u.i.tag);
00199       exit(EXIT_FAILURE);
00200     }
00201     state->u.i.transition[n] = transition;
00202   }
00203   va_end(ap);
00204 }
00205 
00207 void Initial_State(STATE state)
00209 //  See interface description.
00211 {
00212   initial_state = state;
00213 }
00214 
00216 STATE Final(TOP topcode)
00218 //  See interface description.
00220 {
00221   STATE state = new struct state;
00222   state->is_final = true;
00223   state->u.final = topcode;
00224   all_states.push_back(state);
00225   return state;
00226 }
00227 
00229 static int Compare_NonFinals(const void *p1, const void *p2)
00231 //  
00233 {
00234   STATE s1 = *(STATE *)p1;
00235   STATE s2 = *(STATE *)p2;
00236 
00237   return strcmp(s1->u.i.tag, s2->u.i.tag);
00238 }
00239 
00241 static void Visit_State(STATE state, FILE *f, VISIT_KIND vk)
00243 //  Visit <state> and the states it leads to and perform the
00244 //  actions necessary for the kind of visitation specified by <vk>.
00246 {
00247   static int indent;
00248   int i;
00249   int ntrans;
00250   int max_top;
00251   STATE *nonfinals;
00252   int n_nonfinals;
00253 
00254   assert(!state->is_final);
00255 
00256   /* If we've been here, then for data, just return so we
00257    * don't generate the same data twice. For code, we emit
00258    * the whole thing again. Alternatively we could have
00259    * generated a label on the first state and then just
00260    * goto it here.
00261    */
00262   if (state->visit == vk && vk == VISIT_GEN_DATA) return;
00263   state->visit = vk;
00264 
00265   indent += 2;
00266   ntrans = 1 << state->u.i.width;
00267 
00268   nonfinals = (STATE *)alloca(sizeof(struct state) * ntrans);
00269   n_nonfinals = 0;
00270   for (i = 0; i < ntrans; ++i) {
00271     STATE newstate = state->u.i.transition[i];
00272     if (newstate) {
00273       if (!newstate->is_final) {
00274         nonfinals[n_nonfinals++] = newstate;
00275       } else {
00276         newstate->visit = vk;  // only used for unused state detection
00277       }
00278     }
00279   }
00280   qsort(nonfinals, n_nonfinals, sizeof(STATE *), Compare_NonFinals);
00281 
00282   if (vk == VISIT_GEN_CODE) {
00283     fprintf(f, "%*sopc = (", indent, "");
00284     if (state->u.i.stype == INST_STATE) {
00285       fprintf(f, "pinst[%d]", state->u.i.idx);
00286     } else {
00287       fprintf(f, "unit");
00288     }
00289     fprintf(f, " >> %d) & 0x%x;\n", state->u.i.pos, ntrans - 1);
00290 
00291     fprintf(f, "%*stop = state_%s_tab[opc];\n", indent, "", state->u.i.tag);
00292     if (n_nonfinals) fprintf(f, "%*sswitch (top) {\n", indent, "");
00293   }
00294 
00295   max_top = TOP_UNDEFINED;
00296   for (i = 0; i < n_nonfinals; ++i) {
00297     STATE newstate = nonfinals[i];
00298     ++max_top;
00299     newstate->u.i.casenum = max_top;
00300     if (vk == VISIT_GEN_CODE) {
00301       fprintf(f, "%*scase %3d: /* %s */\n",
00302                  indent, "",
00303                  max_top,
00304                  newstate->u.i.tag);
00305     } 
00306     if (   i + 1 == n_nonfinals 
00307         || strcmp(newstate->u.i.tag, nonfinals[i+1]->u.i.tag))
00308     {
00309       Visit_State(newstate, f, vk);
00310       if (vk == VISIT_GEN_CODE) fprintf(f, "%*sbreak;\n", indent + 2, "");
00311     }
00312   }
00313 
00314   if (vk == VISIT_GEN_DATA) {
00315     int col;
00316     const char *top_type;
00317     if (max_top < 256) {
00318       top_type = "mUINT8";
00319     } else if (max_top < 65536) {
00320       top_type = "mUINT16";
00321     } else {
00322       top_type = "mUINT32";
00323     }
00324     fprintf(f, "\nstatic const %s state_%s_tab[%d] = {",
00325                top_type,
00326                state->u.i.tag, 
00327                ntrans);
00328     col = 8;
00329     for (i = 0; i < ntrans; ++i) {
00330       STATE newstate = state->u.i.transition[i];
00331       if (col == 8) {
00332         fprintf(f, "\n ");
00333         col = 0;
00334       }
00335       if (newstate == NULL) {
00336         fprintf(f, " %4d,", TOP_UNDEFINED);
00337       } else if (newstate->is_final) {
00338         fprintf(f, " %4d,", newstate->u.final);
00339       } else {
00340         fprintf(f, " %4d,", newstate->u.i.casenum);
00341       }
00342 
00343       ++col;
00344     }
00345 
00346     fprintf(f, "\n};\n");
00347   } else if (vk == VISIT_GEN_CODE) {
00348     if (n_nonfinals) fprintf(f, "%*s}\n", indent, "");
00349   }
00350   indent -= 2;
00351 }
00352 
00354 void ISA_Decode_End(void)
00356 //  See interface description.
00358 {
00359   list <STATE>::iterator state_iter;
00360   char buf[1000];
00361 #define FNAME "targ_isa_decode"
00362   sprintf (buf, "%s.h", FNAME);
00363   FILE* hfile = fopen(buf, "w");
00364   sprintf (buf, "%s.c", FNAME);
00365   FILE* cfile = fopen(buf, "w");
00366   sprintf (buf, "%s.Exported", FNAME);
00367   FILE* efile = fopen(buf, "w");
00368 
00369   fprintf(cfile, "#include \"topcode.h\"\n"
00370                  "#include \"targ_isa_bundle.h\"\n"
00371                          "#include \"targ_isa_pack.h\"\n"
00372          "#include \"%s.h\"\n\n", FNAME);
00373 
00374   sprintf (buf, "%s", FNAME);
00375   Emit_Header (hfile, buf, interface);
00376   fprintf(hfile, "#include \"topcode.h\"\n"
00377                  "#include \"targ_isa_bundle.h\"\n"
00378                  "#include \"targ_isa_pack.h\"\n");
00379 
00380   if (initial_state == NULL) {
00381     fprintf(stderr, "### Error: no initial decode state specified\n");
00382     exit(EXIT_FAILURE);
00383   }
00384 
00385   Visit_State(initial_state, cfile, VISIT_GEN_DATA);
00386 
00387   fprintf(efile, "ISA_Decode_Inst\n");
00388 
00389   fprintf(hfile, "\nextern TOP ISA_Decode_Inst(const ISA_PACK_INST *pinst, ISA_EXEC_UNIT unit);\n");
00390 
00391   fprintf(cfile, "\nTOP ISA_Decode_Inst(const ISA_PACK_INST *pinst, ISA_EXEC_UNIT unit)\n"
00392                  "{\n"
00393                  "  INT top;\n"
00394                  "  INT opc;\n");
00395   Visit_State(initial_state, cfile, VISIT_GEN_CODE);
00396   fprintf(cfile, "  return (TOP)top;\n"
00397                  "}\n");
00398 
00399   for (state_iter = all_states.begin();
00400        state_iter != all_states.end();
00401        ++state_iter)
00402   {
00403     STATE state = *state_iter;
00404     if (state->visit == VISIT_UNVISITED) {
00405       if (state->is_final) {
00406         fprintf(stderr, "### Warning: final state \"%s\" is unused\n",
00407                 TOP_Name(state->u.final));
00408       } else {
00409         fprintf(stderr, "### Warning: intermediate state \"%s\" is unused\n",
00410                 state->u.i.tag);
00411       }
00412     }
00413   }
00414 
00415   Emit_Footer (hfile);
00416 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines