OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [cpu/] [or32/] [generate.c] - Blame information for rev 193

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 19 jeremybenn
/* generate.c -- generates file execgen.c from instruction set
2
 
3
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
4
   Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org
5
   Copyright (C) 2008 Embecosm Limited
6
 
7
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
8
 
9
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
10
 
11
   This program is free software; you can redistribute it and/or modify it
12
   under the terms of the GNU General Public License as published by the Free
13
   Software Foundation; either version 3 of the License, or (at your option)
14
   any later version.
15
 
16
   This program is distributed in the hope that it will be useful, but WITHOUT
17
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19
   more details.
20
 
21
   You should have received a copy of the GNU General Public License along
22
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
23
 
24
/* This program is commented throughout in a fashion suitable for processing
25
   with Doxygen. */
26
 
27
 
28
/* Autoconf and/or portability configuration */
29
#include "config.h"
30
#include "port.h"
31
 
32
/* System includes */
33
#include <stdlib.h>
34
#include <stdio.h>
35
#include <stdarg.h>
36
 
37
/* Package includes */
38
#include "opcode/or32.h"
39
 
40
static char *in_file;
41
static char *out_file;
42
 
43
/* Whether this instruction stores something in register */
44
static int write_to_reg;
45
 
46
static int out_lines = 0;
47
 
48
static int shift_fprintf(int level, FILE *f, const char *fmt, ...)
49
{
50
  va_list ap;
51
  int i;
52
 
53
  va_start(ap, fmt);
54
  for(i = 0; i < level; i++)
55
    fprintf(f, "  ");
56
 
57
  i = vfprintf(f, fmt, ap);
58
  va_end(ap);
59
 
60
  out_lines++;
61
  return i + (level * 2);
62
}
63
 
64
/* Generates a execute sequence for one instruction */
65
int output_function (FILE *fo, const char *func_name, int level)
66
{
67
  FILE *fi;
68
  int olevel;
69
  int line_num = 0;
70
 
71
  if ((fi = fopen (in_file, "rt")) == NULL) {
72
    printf("could not open file\n");
73
    return 1;
74
  }
75
 
76
  while (!feof (fi)) {
77
    char line[10000], *str = line;
78 82 jeremybenn
    char *res;
79
 
80
    res = fgets (str, sizeof (line), fi);
81
 
82
    if (NULL == res)
83
      {
84 96 jeremybenn
        fclose (fi);                    /* Mark Jarvin patch */
85 82 jeremybenn
        return  1;
86
      }
87
 
88 19 jeremybenn
    line[sizeof (line) - 1] = 0;
89
    line_num++;
90
    if (strncmp (str, "INSTRUCTION (", 13) == 0) {
91
      char *s;
92
      str += 13;
93
      while (isspace (*str)) str++;
94
      s = str;
95
      while (*s && *s != ')') s++;
96
      *s = 0;
97
      while (isspace(*(s - 1))) s--;
98
      *s = 0;
99
      if (strcmp (str, func_name) == 0) {
100
        olevel = 1;
101
        str += strlen (str) + 1;
102
        while (isspace (*str)) str++;
103
        s = str;
104
        while (*s && *s != '\n' && *s != '\r') s++;
105
        *s = 0;
106
        while (isspace(*(s - 1))) s--;
107
        *s = 0;
108
        /*shift_fprintf (level, fo, "#line %i \"%s\"\n", line_num, in_file);*/
109
        shift_fprintf (level, fo, "%s", str);
110
        shift_fprintf (level, fo, "   /* \"%s\" */\n", func_name);
111
        do {
112 82 jeremybenn
          res = fgets (line, sizeof (line), fi);
113
 
114
          if (NULL == res)
115
            {
116 96 jeremybenn
              fclose (fi);
117 82 jeremybenn
              return  1;
118
            }
119
 
120 19 jeremybenn
          line[sizeof(line) - 1] = 0;
121
          for (str = line; *str; str++) {
122
            if (*str == '{') olevel++;
123
            else if (*str == '}') olevel--;
124
          }
125
          shift_fprintf (level, fo, "%s", line);
126
        } while (olevel);
127
        fclose(fi);
128
        /*shift_fprintf (level, fo, "#line %i \"%s\"\n", out_lines, out_file);*/
129
        return 0;
130
      }
131
    }
132
  }
133
  shift_fprintf (level, fo, "%s ();\n", func_name);
134
 
135
  fclose(fi);
136
  return 0;
137
}
138
 
139
/* Parses operands. */
140
 
141
static int
142
gen_eval_operands (FILE *fo, int insn_index, int level)
143
{
144
  struct insn_op_struct *opd = op_start[insn_index];
145
  int i;
146
  int num_ops;
147
  int nbits = 0;
148
  int set_param = 0;
149
  int dis = 0;
150
  int sbit;
151
  int dis_op = -1;
152
 
153
  write_to_reg = 0;
154
 
155
  shift_fprintf (level, fo, "uorreg_t ");
156
 
157
  /* Count number of operands */
158
  for (i = 0, num_ops = 0;; i++) {
159
    if (!(opd[i].type & OPTYPE_OP))
160
      continue;
161
    if (opd[i].type & OPTYPE_DIS)
162
      continue;
163
    if (num_ops)
164
      fprintf(fo, ", ");
165
    fprintf(fo, "%c", 'a' + num_ops);
166
    num_ops++;
167
    if (opd[i].type & OPTYPE_LAST)
168
      break;
169
  }
170
 
171
  fprintf (fo, ";\n");
172
 
173
  shift_fprintf (level, fo, "/* Number of operands: %i */\n", num_ops);
174
 
175
  i = 0;
176
  num_ops = 0;
177
  do {
178
/*
179
    printf("opd[%i].type<last> = %c\n", i, opd->type & OPTYPE_LAST ? '1' : '0');    printf("opd[%i].type<op> = %c\n", i, opd->type & OPTYPE_OP ? '1' : '0');
180
    printf("opd[%i].type<reg> = %c\n", i, opd->type & OPTYPE_REG ? '1' : '0');
181
    printf("opd[%i].type<sig> = %c\n", i, opd->type & OPTYPE_SIG ? '1' : '0');
182
    printf("opd[%i].type<dis> = %c\n", i, opd->type & OPTYPE_DIS ? '1' : '0');
183
    printf("opd[%i].type<shr> = %i\n", i, opd->type & OPTYPE_SHR);
184
    printf("opd[%i].type<sbit> = %i\n", i, (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR);
185
    printf("opd[%i].data = %i\n", i, opd->data);
186
*/
187
 
188
    if (!nbits)
189
      shift_fprintf (level, fo, "%c = (insn >> %i) & 0x%x;\n", 'a' + num_ops,
190
                     opd->type & OPTYPE_SHR, (1 << opd->data) - 1);
191
    else
192
      shift_fprintf (level, fo, "%c |= ((insn >> %i) & 0x%x) << %i;\n",
193
                     'a' + num_ops, opd->type & OPTYPE_SHR,
194
                     (1 << opd->data) - 1, nbits);
195
 
196
    nbits += opd->data;
197
 
198
    if ((opd->type & OPTYPE_DIS) && (opd->type & OPTYPE_OP)) {
199
      sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR;
200
      if (opd->type & OPTYPE_SIG)
201
        shift_fprintf (level, fo, "if(%c & 0x%08x) %c |= 0x%x;\n",
202
                       'a' + num_ops, 1 << sbit, 'a' + num_ops,
203
                       0xffffffff << sbit);
204
      opd++;
205
      shift_fprintf (level, fo, "*(orreg_t *)&%c += (orreg_t)cpu_state.reg[(insn >> %i) & 0x%x];\n",
206
                     'a' + num_ops, opd->type & OPTYPE_SHR,
207
                     (1 << opd->data) - 1);
208
      dis = 1;
209
      dis_op = num_ops;
210
    }
211
 
212
    if (opd->type & OPTYPE_OP) {
213
      sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR;
214
      if (opd->type & OPTYPE_SIG)
215
        shift_fprintf (level, fo, "if(%c & 0x%08x) %c |= 0x%x;\n",
216
                       'a' + num_ops, 1 << sbit, 'a' + num_ops,
217
                       0xffffffff << sbit);
218
      if ((opd->type & OPTYPE_REG) && !dis) {
219
        if(!i) {
220
          shift_fprintf (level, fo, "#define SET_PARAM0(val) cpu_state.reg[a] = val\n");
221 121 jeremybenn
          shift_fprintf (level, fo, "#define REG_PARAM0  a\n");
222 19 jeremybenn
          set_param = 1;
223
        }
224
        shift_fprintf (level, fo, "#define PARAM%i cpu_state.reg[%c]\n", num_ops,
225
                      'a' + num_ops);
226
        if(opd->type & OPTYPE_DST)
227
          write_to_reg = 1;
228
      } else {
229
        shift_fprintf (level, fo, "#define PARAM%i %c\n", num_ops,
230
                       'a' + num_ops);
231
      }
232
      num_ops++;
233
      nbits = 0;
234
      dis = 0;
235
    }
236
 
237
    if ((opd->type & OPTYPE_LAST))
238
      break;
239
    opd++;
240
    i++;
241
  } while (1);
242
 
243
  output_function (fo, or32_opcodes[insn_index].function_name, level);
244
 
245
  if (set_param)
246 121 jeremybenn
    {
247
      shift_fprintf (level, fo, "#undef SET_PARAM0\n");
248
      shift_fprintf (level, fo, "#undef REG_PARAM0\n");
249
    }
250 19 jeremybenn
 
251
  for (i = 0; i < num_ops; i++)
252
    shift_fprintf (level, fo, "#undef PARAM%i\n", i);
253
 
254
  return dis_op;
255
}
256
 
257
/* Generates decode and execute for one instruction instance */
258
static int output_call (FILE *fo, int index, int level)
259
{
260
  int dis_op = -1;
261
 
262
  /*printf ("%i:%s\n", index, insn_name (index));*/
263
 
264
  shift_fprintf (level++, fo, "{\n");
265
 
266
  if (index >= 0)
267
    dis_op = gen_eval_operands (fo, index, level);
268
 
269
  if (index < 0) output_function (fo, "l_invalid", level);
270
 
271
  fprintf (fo, "\n");
272
 
273
  shift_fprintf (level++, fo, "if (do_stats) {\n");
274
 
275
  if (dis_op >= 0)
276
    shift_fprintf (level, fo, "cpu_state.insn_ea = %c;\n", 'a' + dis_op);
277
 
278
  shift_fprintf (level, fo, "current->insn_index = %i;   /* \"%s\" */\n", index,
279
                 insn_name (index));
280
 
281
  shift_fprintf (level, fo, "analysis(current);\n");
282
  shift_fprintf (--level, fo, "}\n");
283
 
284
  if (write_to_reg)
285
    shift_fprintf (level, fo, "cpu_state.reg[0] = 0; /* Repair in case we changed it */\n");
286
  shift_fprintf (--level, fo, "}\n");
287
  return 0;
288
}
289
 
290
/* Generates .c file header */
291
static int generate_header (FILE *fo)
292
{
293
  fprintf (fo, "/* execgen.c -- Automatically generated decoder\n");
294
  fprintf (fo, "\n");
295
  fprintf (fo, "   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org\n");
296
  fprintf (fo, "   Copyright (C) 2008 Embecosm Limited\n");
297
  fprintf (fo, "\n");
298
  fprintf (fo, "   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>\n");
299
  fprintf (fo, "\n");
300
  fprintf (fo, "   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.\n");
301
  fprintf (fo, "\n");
302
  fprintf (fo, "   This program is free software; you can redistribute it and/or modify it\n");
303
  fprintf (fo, "   under the terms of the GNU General Public License as published by the Free\n");
304
  fprintf (fo, "   Software Foundation; either version 3 of the License, or (at your option)\n");
305
  fprintf (fo, "   any later version.\n");
306
  fprintf (fo, "\n");
307
  fprintf (fo, "   This program is distributed in the hope that it will be useful, but WITHOUT\n");
308
  fprintf (fo, "   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n");
309
  fprintf (fo, "   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n");
310
  fprintf (fo, "   more details.\n");
311
  fprintf (fo, "\n");
312
  fprintf (fo, "   You should have received a copy of the GNU General Public License along\n");
313
  fprintf (fo, "   with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
314
  fprintf (fo, "\n");
315
  fprintf (fo, "/* This program is commented throughout in a fashion suitable for processing\n");
316
  fprintf (fo, "   with Doxygen. */\n");
317
  fprintf (fo, "\n");
318
 
319
  fprintf (fo, "/* This file was automatically generated by generate (see\n");
320
  fprintf (fo, "   cpu/or32/generate.c) */\n\n");
321 104 jeremybenn
  fprintf (fo, "#include <math.h>\n\n");
322 118 jeremybenn
  fprintf (fo, "#include <stdint.h>\n\n");
323 100 julius
  fprintf (fo, "typedef union {\n\tfloat fval;\n\tuint32_t hval;\n} FLOAT;\n\n");
324 19 jeremybenn
  fprintf (fo, "static void decode_execute (struct iqueue_entry *current)\n{\n");
325
  fprintf (fo, "  uint32_t insn = current->insn;\n");
326
  out_lines = 5;
327
  return 0;
328
}
329
 
330
/* Generates .c file footer */
331
static int generate_footer (FILE *fo)
332
{
333
  fprintf (fo, "}\n");
334
  return 0;
335
}
336
 
337
/* Decodes all instructions and generates code for that.  This function
338 82 jeremybenn
   is similar to insn_decode, except it decodes all instructions.
339
 
340
   JPB: Added code to generate an illegal instruction exception for invalid
341
   instructions. */
342 19 jeremybenn
static int generate_body (FILE *fo, unsigned long *a, unsigned long cur_mask, int level)
343
{
344
  unsigned long shift = *a;
345
  unsigned long mask;
346
  int i;
347
  int prev_inv = 0;
348
 
349
  if (!(*a & LEAF_FLAG)) {
350
    shift = *a++;
351
    mask = *a++;
352
    shift_fprintf (level, fo, "switch((insn >> %i) & 0x%x) {\n", shift,
353
                   mask);
354
    for (i = 0; i <= mask; i++, a++) {
355
      if (!*a) {
356
        shift_fprintf (level, fo, "case 0x%x:\n", i);
357
        prev_inv = 1;
358
      } else {
359
        if(prev_inv) {
360
          shift_fprintf (++level, fo, "/* Invalid instruction(s) */\n");
361
          shift_fprintf (level--, fo, "break;\n");
362
        }
363
        shift_fprintf (level, fo, "case 0x%x:\n", i);
364
        generate_body (fo, automata + *a, cur_mask | (mask << shift), ++level);
365
        shift_fprintf (level--, fo, "break;\n");
366
        prev_inv = 0;
367
      }
368
    }
369
    if (prev_inv) {
370
      shift_fprintf (++level, fo, "/* Invalid instruction(s) */\n");
371 82 jeremybenn
      shift_fprintf (level, fo,
372
                     "except_handle (EXCEPT_ILLEGAL, cpu_state.pc);\n");
373 19 jeremybenn
      shift_fprintf (level--, fo, "break;\n");
374
    }
375
    shift_fprintf (level, fo, "}\n");
376
  } else {
377
    i = *a & ~LEAF_FLAG;
378
 
379
    /* Final check - do we have direct match?
380
       (based on or32_opcodes this should be the only possibility,
381
       but in case of invalid/missing instruction we must perform a check)  */
382
 
383
    if (ti[i].insn_mask != cur_mask) {
384
      shift_fprintf (level, fo, "/* Not unique: real mask %08lx and current mask %08lx differ - do final check */\n", ti[i].insn_mask, cur_mask);
385
      shift_fprintf (level++, fo, "if((insn & 0x%x) == 0x%x) {\n",
386
                     ti[i].insn_mask, ti[i].insn);
387
    }
388
    shift_fprintf (level, fo, "/* Instruction: %s */\n", or32_opcodes[i].name);
389
 
390
    output_call (fo, i, level);
391
 
392
    if (ti[i].insn_mask != cur_mask) {
393
      shift_fprintf (--level, fo, "} else {\n");
394
      shift_fprintf (++level, fo, "/* Invalid insn */\n");
395
      output_call (fo, -1, level);
396
      shift_fprintf (--level, fo, "}\n");
397
    }
398
  }
399
  return 0;
400
}
401
 
402
/* Main function; it takes two parameters:
403
   input_file(possibly insnset.c) output_file(possibly execgen.c)*/
404
int main (int argc, char *argv[])
405
{
406
  FILE *fo;
407
 
408
  if (argc != 3) {
409
    fprintf (stderr, "USAGE: generate input_file(possibly insnset.c) output_file(possibly execgen.c)\n");
410
    exit (-1);
411
  }
412
 
413
  in_file = argv[1];
414
  out_file = argv[2];
415
  if (!(fo = fopen (argv[2], "wt+"))) {
416
    fprintf (stderr, "Cannot create '%s'.\n", argv[2]);
417
    exit (1);
418
  }
419
 
420
  build_automata ();
421
  if (generate_header (fo)) {
422
    fprintf (stderr, "generate_header\n");
423
    return 1;
424
  }
425
 
426
  if (generate_body (fo, automata, 0, 1)) {
427
    fprintf (stderr, "generate_body\n");
428
    return 1;
429
  }
430
 
431
  if (generate_footer (fo)) {
432
    fprintf (stderr, "generate_footer\n");
433
    return 1;
434
  }
435
 
436
  fclose (fo);
437
  destruct_automata ();
438
  return 0;
439
}
440
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.