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

Subversion Repositories or1k

[/] [or1k/] [branches/] [stable_0_2_x/] [or1ksim/] [cuc/] [cuc.c] - Blame information for rev 1308

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

powered by: WebSVN 2.1.0

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