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

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_70/] [or1ksim/] [cuc/] [cuc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1244 hpanther
/* cuc.c -- OpenRISC Custom Unit Compiler
2
 *    Copyright (C) 2002 Marko Mlinar, markom@opencores.org
3
 *
4
 *    This file is part of OpenRISC 1000 Architectural Simulator.
5
 *
6
 *    This program is free software; you can redistribute it and/or modify
7
 *    it under the terms of the GNU General Public License as published by
8
 *    the Free Software Foundation; either version 2 of the License, or
9
 *    (at your option) any later version.
10
 *
11
 *    This program is distributed in the hope that it will be useful,
12
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *    GNU General Public License for more details.
15
 *
16
 *    You should have received a copy of the GNU General Public License
17
 *    along with this program; if not, write to the Free Software
18
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
 
20
/* Main file, including code optimization and command prompt */
21
 
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <stdarg.h>
25
#include <assert.h>
26
#include <ctype.h>
27 1308 phoenix
#include <string.h>
28
#include <unistd.h>
29
 
30 1350 nogj
#include "config.h"
31
 
32
#ifdef HAVE_INTTYPES_H
33
#include <inttypes.h>
34
#endif
35
 
36
#include "port.h"
37
#include "arch.h"
38 1308 phoenix
#include "abstract.h"
39 1244 hpanther
#include "sim-config.h"
40
#include "cuc.h"
41
#include "insn.h"
42
#include "profiler.h"
43
#include "opcode/or32.h"
44
#include "parse.h"
45 1308 phoenix
#include "debug.h"
46 1244 hpanther
 
47
FILE *flog;
48
int cuc_debug = 0;
49
 
50
/* Last used registers by software convention */
51
/* Note that r11 is caller saved register, and we can destroy it.
52
   Due to CUC architecture we must always return something, even garbage (so that
53
   caller knows, we are finished, when we send acknowledge).
54
   In case r11 was not used (trivial register assignment) we will remove it later,
55
   but if we assigned a value to it, it must not be removed, so caller_saved[11] = 0 */
56
const int caller_saved[MAX_REGS] = {
57
  0, 0, 0, 1, 1, 1, 1, 1,
58
  1, 1, 0, 0, 0, 1, 0, 1,
59
  0, 1, 0, 1, 0, 1, 0, 1,
60
  0, 1, 0, 1, 0, 1, 0, 1,
61
  1, 1};
62
 
63
/* returns log2(x) */
64
/* Call this log2_int, because there is a library function named log2 */
65
int log2_int (unsigned long x)
66
{
67
  int c = 0;
68
  assert (x >= 0);
69
  if (!x) return 0; /* not by the book, but practical */
70
  while (x != 1) x >>= 1, c++;
71
  return c;
72
}
73
 
74
/* Does all known instruction optimizations */
75
void cuc_optimize (cuc_func *func)
76
{
77
  int modified = 0;
78
  int first = 1;
79
  log ("Optimizing.\n");
80
  do {
81
    modified = 0;
82
    clean_deps (func);
83
    if (cuc_debug >= 6) print_cuc_bb (func, "AFTER_CLEAN_DEPS");
84
    if (optimize_cmovs (func)) {
85
      if (cuc_debug >= 6) print_cuc_bb (func, "AFTER_OPT_CMOVS");
86
      modified = 1;
87
    }
88
    if (cuc_debug) cuc_check (func);
89
    if (optimize_tree (func)) {
90
      if (cuc_debug >= 6) print_cuc_bb (func, "AFTER_OPT_TREE1");
91
      modified = 1;
92
    }
93
    if (remove_nops (func)) {
94
      if (cuc_debug >= 6) print_cuc_bb (func, "NO_NOPS");
95
      modified = 1;
96
    }
97
    if (cuc_debug) cuc_check (func);
98
    if (remove_dead (func)) {
99
      if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_DEAD");
100
      modified = 1;
101
    }
102
    if (cuc_debug) cuc_check (func);
103
    if (cse (func)) {
104
      log ("Common subexpression elimination.\n");
105
      if (cuc_debug >= 3) print_cuc_bb (func, "AFTER_CSE");
106
      modified = 1;
107
    }
108
    if (first) {
109
      insert_conditional_facts (func);
110
      if (cuc_debug >= 3) print_cuc_bb (func, "AFTER_COND_FACT");
111
      if (cuc_debug) cuc_check (func);
112
      first = 0;
113
    }
114
    if (optimize_bb (func)) {
115
      if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_OPT_BB");
116
      modified = 1;
117
    }
118
    if (cuc_debug) cuc_check (func);
119
    if (remove_nops (func)) {
120
      if (cuc_debug >= 6) print_cuc_bb (func, "NO_NOPS");
121
      modified = 1;
122
    }
123
    if (remove_dead_bb (func)) {
124
      if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_DEAD_BB");
125
      modified = 1;
126
    }
127
    if (remove_trivial_regs (func)) {
128
      if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_TRIVIAL");
129
      modified = 1;
130
    }
131
    if (remove_nops (func)) {
132
      if (cuc_debug >= 6) print_cuc_bb (func, "NO_NOPS");
133
      modified = 1;
134
    }
135
    add_memory_dep (func, func->memory_order);
136
    if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_MEMORY_DEP");
137
    add_data_dep (func);
138
    if (cuc_debug >= 8) print_cuc_bb (func, "AFTER_DATA_DEP");
139
    if (schedule_memory (func, func->memory_order)) {
140
      if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_SCHEDULE_MEM");
141
      modified = 1;
142
    }
143
  } while (modified);
144
  set_io (func);
145
#if 0
146
  detect_max_values (func);
147
  if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_MAX_VALUES");
148
#endif
149
}
150
 
151
/* Pre/unrolls basic block and optimizes it */
152
cuc_timings *preunroll_bb (char *bb_filename, cuc_func *f, cuc_timings *timings, int b, int i, int j)
153
{
154
  cuc_func *func;
155
  cucdebug (2, "BB%i unroll %i times preroll %i times\n", b, j, i);
156
  log ("BB%i unroll %i times preroll %i times\n", b, j, i);
157
  func = preunroll_loop (f, b, i, j, bb_filename);
158
  if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_PREUNROLL");
159
  cuc_optimize (func);
160
  analyse_timings (func, timings);
161
 
162
  cucdebug (2, "new_time = %i, old_time = %i, size = %f\n",
163
           timings->new_time, func->orig_time, timings->size);
164
  log ("new time = %icyc, old_time = %icyc, size = %.0f gates\n",
165
         timings->new_time, func->orig_time, timings->size);
166
  //output_verilog (func, argv[1]);
167
  free_func (func);
168
  timings->b = b;
169
  timings->unroll = j;
170
  timings->preroll = i;
171
  timings->nshared = 0;
172
  return timings;
173
}
174
 
175
/* Simple comparison function */
176
int tim_comp (cuc_timings *a, cuc_timings *b)
177
{
178
  if (a->new_time < b->new_time) return -1;
179
  else if (a->new_time > b->new_time) return 1;
180
  else return 0;
181
}
182
 
183
/* Analyses function; done when cuc command is entered in (sim) prompt */
184
cuc_func *analyse_function (char *module_name, long orig_time,
185
                unsigned long start_addr, unsigned long end_addr,
186
                int memory_order, int num_runs)
187
{
188
  cuc_timings timings;
189
  cuc_func *func = (cuc_func *) malloc (sizeof (cuc_func));
190
  cuc_func *saved;
191
  int b, i, j;
192
  char tmp1[256];
193
  char tmp2[256];
194
 
195
  func->orig_time = orig_time;
196
  func->start_addr = start_addr;
197
  func->end_addr = end_addr;
198
  func->memory_order = memory_order;
199
  func->nfdeps = 0;
200
  func->fdeps = NULL;
201
  func->num_runs = num_runs;
202
 
203
  sprintf (tmp1, "%s.bin", module_name);
204
  cucdebug (2, "Loading %s.bin\n", module_name);
205
  if (cuc_load (tmp1)) {
206
    free (func);
207
    return NULL;
208
  }
209
 
210
  log ("Detecting basic blocks\n");
211
  detect_bb (func);
212
  if (cuc_debug >= 2) print_cuc_insns ("WITH_BB_LIMITS", 0);
213
 
214
  //sprintf (tmp1, "%s.bin.mp", module_name);
215
  sprintf (tmp2, "%s.bin.bb", module_name);
216
  generate_bb_seq (func, config.sim.mprof_fn, tmp2);
217
  log ("Assuming %i clk cycle load (%i cyc burst)\n", runtime.cuc.mdelay[0], runtime.cuc.mdelay[2]);
218
  log ("Assuming %i clk cycle store (%i cyc burst)\n", runtime.cuc.mdelay[1], runtime.cuc.mdelay[3]);
219
 
220
  build_bb (func);
221
  if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_BUILD_BB");
222
  reg_dep (func);
223
 
224
  log ("Detecting dependencies\n");
225
  if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_REG_DEP");
226
  cuc_optimize (func);
227
 
228
#if 0
229
  csm (func);
230
#endif
231
  assert (saved = dup_func (func));
232
 
233
  timings.preroll = timings.unroll = 1;
234
  timings.nshared = 0;
235
 
236
  add_latches (func);
237
  if (cuc_debug >= 1) print_cuc_bb (func, "AFTER_LATCHES");
238
  analyse_timings (func, &timings);
239
 
240
  free_func (func);
241
  log ("Base option: pre%i,un%i,sha%i: %icyc %.1f\n",
242
        timings.preroll, timings.unroll, timings.nshared, timings.new_time, timings.size);
243
  saved->timings = timings;
244
 
245
#if 1
246
  /* detect and unroll simple loops */
247
  for (b = 0; b < saved->num_bb; b++) {
248
    cuc_timings t[MAX_UNROLL * MAX_PREROLL];
249
    cuc_timings *ut;
250
    cuc_timings *cut = &t[0];
251
    int nt = 1;
252
    double csize;
253
    saved->bb[b].selected_tim = -1;
254
 
255
    /* Is it a loop? */
256
    if (saved->bb[b].next[0] != b && saved->bb[b].next[1] != b) continue;
257
    log ("Found loop at BB%x.  Trying to unroll.\n", b);
258
    t[0] = timings;
259
    t[0].b = b;
260
    t[0].preroll = 1;
261
    t[0].unroll = 1;
262
    t[0].nshared = 0;
263
 
264
    sprintf (tmp1, "%s.bin.bb", module_name);
265
    i = 1;
266
    do {
267
      cuc_timings *pt;
268
      cuc_timings *cpt = cut;
269
      j = 1;
270
 
271
      do {
272
        pt = cpt;
273
        cpt = preunroll_bb (tmp1, saved, &t[nt++], b, ++j, i);
274
      } while (j <= MAX_PREROLL && pt->new_time > cpt->new_time);
275
      i++;
276
      ut = cut;
277
      cut = preunroll_bb (tmp1, saved, &t[nt++], b, 1, i);
278
    } while (i <= MAX_UNROLL && ut->new_time > cut->new_time);
279
 
280
    /* Sort the timings */
281
#if 0
282
    if (cuc_debug >= 3)
283
    for (i = 0; i < nt; i++) PRINTF ("%i:%i,%i: %icyc\n",
284
                    t[i].b, t[i].preroll, t[i].unroll, t[i].new_time);
285
#endif
286
 
287
    qsort (t, nt, sizeof (cuc_timings), (int (*)(const void *, const void *))tim_comp);
288
 
289
    /* Delete timings, that have worst time and bigger size than other */
290
    j = 1;
291
    csize = t[0].size;
292
    for (i = 1; i < nt; i++)
293
      if (t[i].size < csize) t[j++] = t[i];
294
    nt = j;
295
 
296
    cucdebug (1, "Available options\n");
297
    for (i = 0; i < nt; i++) cucdebug (1, "%i:%i,%i: %icyc %.1f\n",
298
        t[i].b, t[i].preroll, t[i].unroll, t[i].new_time, t[i].size);
299
    /* Add results from CSM */
300
    j = nt;
301
    for (i = 0; i < saved->bb[b].ntim; i++) {
302
      int i1;
303
      for (i1 = 0; i1 < nt; i1++) {
304
        t[j] = t[i1];
305
        t[j].size += saved->bb[b].tim[i].size - timings.size;
306
        t[j].new_time += saved->bb[b].tim[i].new_time - timings.new_time;
307
        t[j].nshared = saved->bb[b].tim[i].nshared;
308
        t[j].shared = saved->bb[b].tim[i].shared;
309
        if (++j >= MAX_UNROLL * MAX_PREROLL) goto full;
310
      }
311
    }
312
 
313
full:
314
    nt = j;
315
 
316
    cucdebug (1, "Available options:\n");
317
    for (i = 0; i < nt; i++) cucdebug (1, "%i:%i,%i: %icyc %.1f\n",
318
        t[i].b, t[i].preroll, t[i].unroll, t[i].new_time, t[i].size);
319
 
320
    /* Sort again with new timings added */
321
    qsort (t, nt, sizeof (cuc_timings), (int (*)(const void *, const void *))tim_comp);
322
 
323
    /* Delete timings, that have worst time and bigger size than other */
324
    j = 1;
325
    csize = t[0].size;
326
    for (i = 1; i < nt; i++)
327
      if (t[i].size < csize) t[j++] = t[i];
328
    nt = j;
329
 
330
    cucdebug (1, "Available options:\n");
331
    for (i = 0; i < nt; i++) cucdebug (1, "%i:%i,%i: %icyc %.1f\n",
332
                               t[i].b, t[i].preroll, t[i].unroll, t[i].new_time, t[i].size);
333
 
334
    if (saved->bb[b].ntim) free (saved->bb[b].tim);
335
    saved->bb[b].ntim = nt;
336
    assert (saved->bb[b].tim = (cuc_timings *) malloc (sizeof (cuc_timings) * nt));
337
 
338
    /* Copy options in reverse order -- smallest first */
339
    for (i = 0; i < nt; i++) saved->bb[b].tim[i] = t[nt - 1 - i];
340
 
341
    log ("Available options:\n");
342
    for (i = 0; i < saved->bb[b].ntim; i++) {
343
      log ("%i:pre%i,un%i,sha%i: %icyc %.1f\n",
344
        saved->bb[b].tim[i].b, saved->bb[b].tim[i].preroll, saved->bb[b].tim[i].unroll,
345
        saved->bb[b].tim[i].nshared, saved->bb[b].tim[i].new_time, saved->bb[b].tim[i].size);
346
    }
347
  }
348
#endif
349
  return saved;
350
}
351
 
352
/* Utility option formatting functions */
353
static const char *option_char = "?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
354
 
355
/*static */char *gen_option (char *s, int bb_no, int f_opt)
356
{
357
  if (bb_no >= 0) sprintf (s, "%i", bb_no);
358
  assert (f_opt <= strlen (option_char));
359
  sprintf (s, "%s%c", s, option_char[f_opt]);
360
  return s;
361
}
362
 
363
/*static */void print_option (int bb_no, int f_opt)
364
{
365
  char tmp1[10];
366
  char tmp2[10];
367
  sprintf (tmp2, "%s", gen_option (tmp1, bb_no, f_opt));
368
  PRINTF ("%3s", tmp2);
369
}
370
 
371
static char *format_func_options (char *s, cuc_func *f)
372
{
373
  int b, first = 1;
374
  *s = '\0';
375
  for (b = 0; b < f->num_bb; b++)
376
    if (f->bb[b].selected_tim >= 0) {
377
      char tmp[10];
378
      sprintf (s, "%s%s%s", s, first ? "" : ",", gen_option (tmp, b, f->bb[b].selected_tim));
379
      first = 0;
380
    }
381
  return s;
382
}
383
 
384
static void options_cmd (int func_no, cuc_func *f)
385
{
386
  int b, i;
387
  char tmp[30];
388
  char *name = prof_func[func_no].name;
389
  PRINTF ("-----------------------------------------------------------------------------\n");
390
  PRINTF ("|%-28s|pre/unrolled|shared|  time  |  gates |old_time|\n",
391
            strstrip (tmp, name, 28));
392
  PRINTF ("|                    BASE    |%4i / %4i | %4i |%8i|%8.f|%8i|\n", 1, 1, 0,
393
          f->timings.new_time, f->timings.size, f->orig_time);
394
  for (b = 0; b < f->num_bb; b++) {
395
    /* Print out results */
396
    for (i = 1; i < f->bb[b].ntim; i++) { /* First one is base option */
397
      int time = f->bb[b].tim[i].new_time - f->timings.new_time;
398
      double size = f->bb[b].tim[i].size - f->timings.size;
399
      PRINTF ("|                   ");
400
      print_option (b, i);
401
      PRINTF ("      |%4i / %4i | %4i |%+8i|%+8.f|        |\n",
402
        f->bb[b].tim[i].preroll, f->bb[b].tim[i].unroll, f->bb[b].tim[i].nshared,
403
        time, size);
404
    }
405
  }
406
}
407
 
408
/* Generates a function, based on specified parameters */
409
cuc_func *generate_function (cuc_func *rf, char *name, char *cut_filename)
410
{
411 1308 phoenix
  int b;
412 1244 hpanther
  char tmp[256];
413
  cuc_timings tt;
414
  cuc_func *f;
415
  assert (f = dup_func (rf));
416
 
417
  if (cuc_debug >= 2) print_cuc_bb (f, "BEFORE_GENERATE");
418
  log ("Generating function %s.\n", name);
419
  PRINTF ("Generating function %s.\n", name);
420
 
421
  format_func_options (tmp, rf);
422
  if (strlen (tmp)) PRINTF ("Applying options: %s\n", tmp);
423
  else PRINTF ("Using basic options.\n");
424
 
425
  /* Generate function as specified by options */
426
  for (b = 0; b < f->num_bb; b++) {
427
    cuc_timings *st;
428
    if (rf->bb[b].selected_tim < 0) continue;
429
    st = &rf->bb[b].tim[rf->bb[b].selected_tim];
430
    sprintf (tmp, "%s.bin.bb", name);
431
    preunroll_bb (&tmp[0], f, &tt, b, st->preroll, st->unroll);
432
    if (cuc_debug >= 1) print_cuc_bb (f, "AFTER_PREUNROLL");
433
  }
434
  for (b = 0; b < f->num_bb; b++) {
435
    cuc_timings *st;
436
    if (rf->bb[b].selected_tim < 0) continue;
437
    st = &rf->bb[b].tim[rf->bb[b].selected_tim];
438
    if (!st->nshared) continue;
439
    assert (0);
440
    //csm_gen (f, rf, st->nshared, st->shared);
441
  }
442
  add_latches (f);
443
  if (cuc_debug >= 1) print_cuc_bb (f, "AFTER_LATCHES");
444
  analyse_timings (f, &tt);
445
 
446
  sprintf (tmp, "%s%s", cut_filename, name);
447
  output_verilog (f, tmp, name);
448
  return f;
449
}
450
 
451
/* Calculates required time, based on selected options */
452
int calc_cycles (cuc_func *f)
453
{
454 1308 phoenix
  int b, ntime = f->timings.new_time;
455 1244 hpanther
  for (b = 0; b < f->num_bb; b++)
456
    if (f->bb[b].selected_tim >= 0) {
457
      assert (f->bb[b].selected_tim < f->bb[b].ntim);
458
      ntime += f->bb[b].tim[f->bb[b].selected_tim].new_time - f->timings.new_time;
459
    }
460
  return ntime;
461
}
462
 
463
/* Calculates required size, based on selected options */
464
double calc_size (cuc_func *f)
465
{
466 1308 phoenix
  int b;
467 1244 hpanther
  double size = f->timings.size;
468
  for (b = 0; b < f->num_bb; b++)
469
    if (f->bb[b].selected_tim >= 0) {
470
      assert (f->bb[b].selected_tim < f->bb[b].ntim);
471
      size += f->bb[b].tim[f->bb[b].selected_tim].size - f->timings.size;
472
    }
473
  return size;
474
}
475
 
476
/* Dumps specified function to file (hex) */
477
unsigned long extract_function (char *out_fn, unsigned long start_addr)
478
{
479
  FILE *fo;
480
  unsigned long a = start_addr;
481
  int x = 0;
482
  assert (fo = fopen (out_fn, "wt+"));
483
 
484
  do {
485
    unsigned long d = evalsim_mem32 (a);
486
    int index = insn_decode (d);
487
    assert (index >= 0);
488
    if (x) x++;
489
    if (strcmp (insn_name (index), "l.jr") == 0) x = 1;
490
    a += 4;
491 1308 phoenix
    fprintf (fo, "%08lx\n", d);
492 1244 hpanther
  } while (x < 2);
493
 
494
  fclose (fo);
495
  return a - 4;
496
}
497
 
498
static cuc_func *func[MAX_FUNCS];
499
static int func_v[MAX_FUNCS];
500
 
501
/* Detects function dependencies and removes  */
502
static void set_func_deps ()
503
{
504
  int f, b, i, j;
505
restart:
506
  for (f = 0; f < prof_nfuncs - 1; f++) if (func[f]) {
507
    int fused[MAX_FUNCS] = {0};
508
    int c;
509
    for (b = 0; b < func[f]->num_bb; b++)
510
      for (i = 0; i < func[f]->bb[b].ninsn; i++) {
511
        cuc_insn *ii = &func[f]->bb[b].insn[i];
512
        if (ii->index == II_CALL) {
513
          assert (ii->opt[0] == OPT_CONST);
514
          for (j = 0; j < prof_nfuncs - 1; j++)
515
            if (func[j] && func[j]->start_addr == ii->op[0]) break;
516
          if (j >= prof_nfuncs - 1) {
517 1308 phoenix
            log ("%s is calling unknown function, address %08lx\n",
518 1244 hpanther
                            prof_func[f].name, ii->op[0]);
519 1350 nogj
            debug (1, "%s is calling unknown function, address %08lx\n",
520 1244 hpanther
                            prof_func[f].name, ii->op[0]);
521
            free_func (func[f]);
522
            func[f] = NULL;
523
            goto restart;
524
          } else if (f == j) {
525
            log ("%s is recursive, ignoring\n", prof_func[f].name);
526
            debug (1, "%s is recursive, ignoring\n", prof_func[f].name);
527
            free_func (func[f]);
528
            func[f] = NULL;
529
            goto restart;
530
          } else fused[j]++;
531
        }
532
      }
533
    for (i = 0; i < MAX_FUNCS; i++) if (fused[i]) c++;
534
    if (func[f]->nfdeps) free (func[f]->fdeps);
535
    func[f]->nfdeps = c;
536
    func[f]->fdeps = (cuc_func **) malloc (sizeof (cuc_func *) * c);
537
    for (i = 0, j = 0; i < MAX_FUNCS; i++)
538
      if (fused[i]) func[f]->fdeps[j++] = func[i];
539
  }
540
 
541
  /* Detect loops */
542
  {
543
    int change;
544
    for (f = 0; f < MAX_FUNCS; f++) if (func[f]) func[f]->tmp = 0;
545
    do {
546
      change = 0;
547
      for (f = 0; f < MAX_FUNCS; f++) if (func[f] && !func[f]->tmp) {
548
        int o = 1;
549
        for (i = 0; i < func[f]->nfdeps; i++)
550
          if (!func[f]->fdeps[i]->tmp) {o = 0; break;}
551
        if (o) {
552
          func[f]->tmp = 1;
553
          change = 1;
554
        }
555
      }
556
    } while (change);
557
 
558
    change = 0;
559
    for (f = 0; f < MAX_FUNCS; f++) if (func[f] && !func[f]->tmp) {
560
      free_func (func[f]);
561
      func[f] = NULL;
562
      change = 1;
563
    }
564
    if (change) goto restart;
565
  }
566
}
567
 
568
void main_cuc (char *filename)
569
{
570
  int i, j;
571
  char tmp1[256];
572
  char filename_cut[256];
573
#if 0 /* Select prefix, based on binary program name */
574
  for (i = 0; i < sizeof (filename_cut); i++) {
575
    if (isalpha(filename[i])) filename_cut[i] = filename[i];
576
    else {
577
      filename_cut[i] = '\0';
578
      break;
579
    }
580
  }
581
#else
582
  strcpy (filename_cut, "cu");
583
#endif
584
 
585
  PRINTF ("Entering OpenRISC Custom Unit Compiler command prompt\n");
586
  PRINTF ("Using profile file \"%s\" and memory profile file \"%s\".\n", config.sim.prof_fn, config.sim.mprof_fn);
587
  sprintf (tmp1, "%s.log", filename_cut);
588
  PRINTF ("Analyzing. (log file \"%s\").\n", tmp1);
589
  assert (flog = fopen (tmp1, "wt+"));
590
 
591
  /* Loads in the specified timings table */
592
  PRINTF ("Using timings from \"%s\" at %s\n",config.cuc.timings_fn,
593
                 generate_time_pretty (tmp1, config.sim.clkcycle_ps));
594
  load_timing_table (config.cuc.timings_fn);
595
  runtime.cuc.cycle_duration = 1000. * config.sim.clkcycle_ps;
596
  PRINTF ("Multicycle logic %s, bursts %s, %s memory order.\n",
597
    config.cuc.no_multicycle ? "OFF" : "ON", config.cuc.enable_bursts ? "ON" : "OFF",
598
    config.cuc.memory_order == MO_NONE ? "no" : config.cuc.memory_order == MO_WEAK ? "weak" :
599
    config.cuc.memory_order == MO_STRONG ? "strong" : "exact");
600
 
601
  prof_set (1, 0);
602
  assert (prof_acquire (config.sim.prof_fn) == 0);
603
 
604
  if (config.cuc.calling_convention)
605
    PRINTF ("Assuming OpenRISC standard calling convention.\n");
606
 
607
  /* Try all functions except "total" */
608
  for (i = 0; i < prof_nfuncs - 1; i++) {
609
    long orig_time;
610
    unsigned long start_addr, end_addr;
611
    orig_time = prof_func[i].cum_cycles;
612
    start_addr = prof_func[i].addr;
613
 
614
    /* Extract the function from the binary */
615
    sprintf (tmp1, "%s.bin", prof_func[i].name);
616
    end_addr = extract_function (tmp1, start_addr);
617
 
618 1308 phoenix
    log ("Testing function %s (%08lx - %08lx)\n", prof_func[i].name, start_addr,
619
         end_addr);
620
    PRINTF ("Testing function %s (%08lx - %08lx)\n", prof_func[i].name,
621
            start_addr, end_addr);
622 1244 hpanther
    func[i] = analyse_function (prof_func[i].name, orig_time, start_addr,
623
                   end_addr, config.cuc.memory_order, prof_func[i].calls);
624
    func_v[i] = 0;
625
  }
626
  set_func_deps ();
627
 
628
  while (1) {
629
    char *s;
630
wait_command:
631
    PRINTF ("(cuc) ");
632
    fflush (stdout);
633
wait_command_empty:
634
    s = fgets(tmp1, sizeof tmp1, stdin);
635
    usleep (100);
636
    if (!s) goto wait_command_empty;
637
    for (s = tmp1; *s != '\0' && *s != '\n' && *s != '\r'; s++);
638
    *s = '\0';
639
 
640
      /* quit command */
641
    if (strcmp (tmp1, "q") == 0 || strcmp (tmp1, "quit") == 0) {
642
      /* Delete temporary files */
643
      for (i = 0; i < prof_nfuncs - 1; i++) {
644
        sprintf (tmp1, "%s.bin", prof_func[i].name);
645
        log ("Deleting temporary file %s %s\n", tmp1, remove (tmp1) ? "FAILED" : "OK");
646
        sprintf (tmp1, "%s.bin.bb", prof_func[i].name);
647
        log ("Deleting temporary file %s %s\n", tmp1, remove (tmp1) ? "FAILED" : "OK");
648
      }
649
      break;
650
 
651
      /* profile command */
652
    } else if (strcmp (tmp1, "p") == 0 || strcmp (tmp1, "profile") == 0) {
653
      int ntime = 0;
654
      int size = 0;
655
      PRINTF ("-----------------------------------------------------------------------------\n");
656 1308 phoenix
      PRINTF ("|function name       |calls|avg cycles  |old%%| max. f.  | impr. f.| options |\n");
657 1244 hpanther
      PRINTF ("|--------------------+-----+------------+----+----------|---------+---------|\n");
658
      for (j = 0; j < prof_nfuncs; j++) {
659
        int bestcyc = 0, besti = 0;
660
        char tmp[100];
661
        for (i = 0; i < prof_nfuncs; i++)
662
          if (prof_func[i].cum_cycles > bestcyc) {
663
            bestcyc = prof_func[i].cum_cycles;
664
            besti = i;
665
          }
666
        i = besti;
667 1308 phoenix
        PRINTF ("|%-20s|%5li|%12.1f|%3.0f%%| ",
668 1244 hpanther
                strstrip (tmp, prof_func[i].name, 20),  prof_func[i].calls,
669
                ((double)prof_func[i].cum_cycles / prof_func[i].calls),
670
                (100. * prof_func[i].cum_cycles / prof_cycles));
671
        if (func[i]) {
672
          double f = 1.0;
673
          if (func_v[i]) {
674
            int nt = calc_cycles (func[i]);
675
            int s = calc_size (func[i]);
676
            f = 1. * func[i]->orig_time / nt;
677
            ntime += nt;
678
            size += s;
679
          } else ntime += prof_func[i].cum_cycles;
680
          PRINTF ("%8.1f |%8.1f | %-8s|\n", 1.f * prof_func[i].cum_cycles
681
                          / func[i]->timings.new_time, f, format_func_options (tmp, func[i]));
682
        } else {
683
          PRINTF ("     N/A |     N/A |     N/A |\n");
684
          ntime += prof_func[i].cum_cycles;
685
        }
686
        prof_func[i].cum_cycles = -prof_func[i].cum_cycles;
687
      }
688
      for (i = 0; i < prof_nfuncs; i++)
689
        prof_func[i].cum_cycles = -prof_func[i].cum_cycles;
690
      PRINTF ("-----------------------------------------------------------------------------\n");
691
      PRINTF ("Total %i cycles (was %i), total added gates = %i. Speed factor %.1f\n",
692
                      ntime, prof_cycles, size, 1. * prof_cycles / ntime);
693
 
694
      /* debug command */
695
    } else if (strncmp (tmp1, "d", 1) == 0 || strncmp (tmp1, "debug", 5) == 0) {
696
      sscanf (tmp1, "%*s %i", &cuc_debug);
697
      if (cuc_debug < 0) cuc_debug = 0;
698
      if (cuc_debug > 9) cuc_debug = 9;
699
 
700
      /* generate command */
701
    } else if (strcmp (tmp1, "g") == 0 || strcmp (tmp1, "generate") == 0) {
702
      /* check for function dependencies */
703
      for (i = 0; i < prof_nfuncs; i++)
704
        if (func[i]) func[i]->tmp = func_v[i];
705
      for (i = 0; i < prof_nfuncs; i++) if (func[i])
706
        for (j = 0; j < func[i]->nfdeps; j++)
707
          if (!func[i]->fdeps[j] || !func[i]->fdeps[j]->tmp) {
708
            PRINTF ("Function %s must be selected for translation (required by %s)\n",
709
                    prof_func[j].name, prof_func[i].name);
710
            goto wait_command;
711
          }
712
      for (i = 0; i < prof_nfuncs; i++)
713
        if (func[i] && func_v[i]) generate_function (func[i], prof_func[i].name, filename_cut);
714
      generate_main (prof_nfuncs, func, filename_cut);
715
 
716
      /* list command */
717
    } else if (strcmp (tmp1, "l") == 0 || strcmp (tmp1, "list") == 0) {
718
      /* check for function dependencies */
719
      for (i = 0; i < prof_nfuncs; i++)
720
        if (func_v[i]) {
721
          PRINTF ("%s\n", prof_func[j].name);
722
        }
723
 
724
      /* selectall command */
725
    } else if (strcmp (tmp1, "sa") == 0 || strcmp (tmp1, "selectall") == 0) {
726 1308 phoenix
      int f;
727 1244 hpanther
      for (f = 0; f < prof_nfuncs; f++) if (func[f]) {
728
        func_v[f] = 1;
729
        PRINTF ("Function %s selected for translation.\n", prof_func[f].name);
730
      }
731
 
732
      /* select command */
733
    } else if (strncmp (tmp1, "s", 1) == 0 || strncmp (tmp1, "select", 6) == 0) {
734
      char tmp[50], ch;
735
      int p, o, b, f;
736
      p = sscanf (tmp1, "%*s %s %i%c", tmp, &b, &ch);
737
      if (p < 1) PRINTF ("Invalid parameters.\n");
738
      else {
739
        /* Check if we have valid option */
740
        for (f = 0; f < prof_nfuncs; f++)
741
          if (strcmp (prof_func[f].name, tmp) == 0 && func[f]) break;
742
        if (f < prof_nfuncs) {
743
          if (p == 1) {
744
            if (func[f]) {
745
              func_v[f] = 1;
746
              PRINTF ("Function %s selected for translation.\n", prof_func[f].name);
747
            } else PRINTF ("Function %s not suitable for translation.\n", prof_func[f].name);
748
          } else {
749
            if (!func_v[f])
750
              PRINTF ("Function %s not yet selected for translation.\n", prof_func[f].name);
751
            if (p < 3) goto invalid_option;
752
            for (o = 0; option_char[o] != '\0' && option_char[o] != ch; o++);
753
            if (!option_char[o]) goto invalid_option;
754
            if (b < 0 || b >= func[f]->num_bb) goto invalid_option;
755
            if (o < 0 || o >= func[f]->bb[b].ntim) goto invalid_option;
756
 
757
            /* select an option */
758
            func[f]->bb[b].selected_tim = o;
759
            if (func[f]->bb[b].tim[o].nshared) {
760
              PRINTF ("Option has shared instructions: ");
761
              print_shared (func[f], func[f]->bb[b].tim[o].shared, func[f]->bb[b].tim[o].nshared);
762
              PRINTF ("\n");
763
            }
764
            goto wait_command;
765
invalid_option:
766
            PRINTF ("Invalid option.\n");
767
          }
768
        } else PRINTF ("Invalid function.\n");
769
      }
770
 
771
      /* unselect command */
772
    } else if (strncmp (tmp1, "u", 1) == 0 || strncmp (tmp1, "unselect", 8) == 0) {
773
      char tmp[50], ch;
774
      int p, o, b, f;
775
      p = sscanf (tmp1, "%*s %s %i%c", tmp, &b, &ch);
776
      if (p < 1) PRINTF ("Invalid parameters.\n");
777
      else {
778
        /* Check if we have valid option */
779
        for (f = 0; f < prof_nfuncs; f++)
780
          if (strcmp (prof_func[f].name, tmp) == 0 && func[f]) break;
781
        if (f < prof_nfuncs) {
782
          if (p == 1) {
783
            if (func[f]) {
784
              func_v[f] = 0;
785
              PRINTF ("Function %s unselected for translation.\n", prof_func[f].name);
786
            } else PRINTF ("Function %s not suitable for translation.\n", prof_func[f].name);
787
          } else {
788
            if (p < 3) goto invalid_option;
789
            for (o = 0; option_char[o] != '\0' && option_char[o] != ch; o++);
790
            if (!option_char[o]) goto invalid_option;
791
            if (b < 0 || b >= func[f]->num_bb) goto invalid_option;
792
            if (o < 0 || o >= func[f]->bb[b].ntim) goto invalid_option;
793
 
794
            /* select an option */
795
            func[f]->bb[b].selected_tim = -1;
796
          }
797
        } else PRINTF ("Invalid function.\n");
798
      }
799
 
800
      /* options command */
801
    } else if (strcmp (tmp1, "o") == 0 || strcmp (tmp1, "options") == 0) {
802
      int any = 0;
803
      PRINTF ("Available options:\n");
804
      for (i = 0; i < prof_nfuncs; i++)
805
        if (func[i]) {
806
          options_cmd (i, func[i]);
807
          any = 1;
808
        }
809
      if (any) PRINTF ("-----------------------------------------------------------------------------\n");
810
      else PRINTF ("Sorry. No available options.\n");
811
 
812
      /* Ignore empty string */
813
    } else if (strcmp (tmp1, "") == 0) {
814
 
815
      /* help command */
816
    } else {
817
      if (strcmp (tmp1, "h") != 0 && strcmp (tmp1, "help") != 0)
818
        PRINTF ("Unknown command.\n");
819
      PRINTF ("OpenRISC Custom Unit Compiler command prompt\n");
820
      PRINTF ("Available commands:\n");
821
      PRINTF ("  h | help                   displays this help\n");
822
      PRINTF ("  q | quit                   returns to or1ksim prompt\n");
823
      PRINTF ("  p | profile                displays function profiling\n");
824
      PRINTF ("  d | debug #                sets debug level (0-9)\n");
825
      PRINTF ("  o | options                displays available options\n");
826
      PRINTF ("  s | select func [option]   selects an option/function\n");
827
      PRINTF ("  u | unselect func [option] unselects an option/function\n");
828
      PRINTF ("  g | generate               generates verilog file\n");
829
      PRINTF ("  l | list                   displays selected functions\n");
830
    }
831
  }
832
 
833
  /* Dispose memory */
834
  for (i = 0; i < prof_nfuncs -1; i++)
835
    if (func[i]) free_func (func[i]);
836
 
837
  fclose (flog);
838
}
839
 
840 1358 nogj
/*----------------------------------------------------[ CUC Configuration ]---*/
841
void cuc_calling_convention(union param_val val, void *dat)
842
{
843
  config.cuc.calling_convention = val.int_val;
844
}
845
 
846
void cuc_enable_bursts(union param_val val, void *dat)
847
{
848
  config.cuc.enable_bursts = val.int_val;
849
}
850
 
851
void cuc_no_multicycle(union param_val val, void *dat)
852
{
853
  config.cuc.no_multicycle = val.int_val;
854
}
855
 
856
void cuc_memory_order(union param_val val, void *dat)
857
{
858
  if (strcmp (val.str_val, "none") == 0)
859
    config.cuc.memory_order = MO_NONE;
860
  else if (strcmp (val.str_val, "weak") == 0)
861
    config.cuc.memory_order = MO_WEAK;
862
  else if (strcmp (val.str_val, "strong") == 0)
863
    config.cuc.memory_order = MO_STRONG;
864
  else if (strcmp (val.str_val, "exact") == 0) {
865
    config.cuc.memory_order = MO_EXACT;
866
  } else {
867
    char tmp[200];
868
    sprintf (tmp, "invalid memory order '%s'.\n", val.str_val);
869
    CONFIG_ERROR(tmp);
870
  }
871
}
872
 
873
void cuc_timings_fn(union param_val val, void *dat)
874
{
875
  strcpy(config.cuc.timings_fn, val.str_val);
876
}
877
 
878
void reg_cuc_sec(void)
879
{
880
  struct config_section *sec = reg_config_sec("cuc", NULL, NULL);
881
 
882
  reg_config_param(sec, "calling_convention", paramt_int, cuc_calling_convention);
883
  reg_config_param(sec, "enable_bursts", paramt_int, cuc_enable_bursts);
884
  reg_config_param(sec, "no_multicycle", paramt_int, cuc_no_multicycle);
885
  reg_config_param(sec, "memory_order", paramt_word, cuc_memory_order);
886
  reg_config_param(sec, "timings_fn", paramt_str, cuc_timings_fn);
887
}

powered by: WebSVN 2.1.0

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