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

powered by: WebSVN 2.1.0

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