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 1484

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 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 1484 nogj
    int breakpoint;
486
    unsigned long d = eval_direct32 (a, &breakpoint, 0, 0);
487 1244 hpanther
    int index = insn_decode (d);
488
    assert (index >= 0);
489
    if (x) x++;
490
    if (strcmp (insn_name (index), "l.jr") == 0) x = 1;
491
    a += 4;
492 1308 phoenix
    fprintf (fo, "%08lx\n", d);
493 1244 hpanther
  } while (x < 2);
494
 
495
  fclose (fo);
496
  return a - 4;
497
}
498
 
499
static cuc_func *func[MAX_FUNCS];
500
static int func_v[MAX_FUNCS];
501
 
502
/* Detects function dependencies and removes  */
503
static void set_func_deps ()
504
{
505
  int f, b, i, j;
506
restart:
507
  for (f = 0; f < prof_nfuncs - 1; f++) if (func[f]) {
508
    int fused[MAX_FUNCS] = {0};
509
    int c;
510
    for (b = 0; b < func[f]->num_bb; b++)
511
      for (i = 0; i < func[f]->bb[b].ninsn; i++) {
512
        cuc_insn *ii = &func[f]->bb[b].insn[i];
513
        if (ii->index == II_CALL) {
514
          assert (ii->opt[0] == OPT_CONST);
515
          for (j = 0; j < prof_nfuncs - 1; j++)
516
            if (func[j] && func[j]->start_addr == ii->op[0]) break;
517
          if (j >= prof_nfuncs - 1) {
518 1308 phoenix
            log ("%s is calling unknown function, address %08lx\n",
519 1244 hpanther
                            prof_func[f].name, ii->op[0]);
520 1350 nogj
            debug (1, "%s is calling unknown function, address %08lx\n",
521 1244 hpanther
                            prof_func[f].name, ii->op[0]);
522
            free_func (func[f]);
523
            func[f] = NULL;
524
            goto restart;
525
          } else if (f == j) {
526
            log ("%s is recursive, ignoring\n", prof_func[f].name);
527
            debug (1, "%s is recursive, ignoring\n", prof_func[f].name);
528
            free_func (func[f]);
529
            func[f] = NULL;
530
            goto restart;
531
          } else fused[j]++;
532
        }
533
      }
534
    for (i = 0; i < MAX_FUNCS; i++) if (fused[i]) c++;
535
    if (func[f]->nfdeps) free (func[f]->fdeps);
536
    func[f]->nfdeps = c;
537
    func[f]->fdeps = (cuc_func **) malloc (sizeof (cuc_func *) * c);
538
    for (i = 0, j = 0; i < MAX_FUNCS; i++)
539
      if (fused[i]) func[f]->fdeps[j++] = func[i];
540
  }
541
 
542
  /* Detect loops */
543
  {
544
    int change;
545
    for (f = 0; f < MAX_FUNCS; f++) if (func[f]) func[f]->tmp = 0;
546
    do {
547
      change = 0;
548
      for (f = 0; f < MAX_FUNCS; f++) if (func[f] && !func[f]->tmp) {
549
        int o = 1;
550
        for (i = 0; i < func[f]->nfdeps; i++)
551
          if (!func[f]->fdeps[i]->tmp) {o = 0; break;}
552
        if (o) {
553
          func[f]->tmp = 1;
554
          change = 1;
555
        }
556
      }
557
    } while (change);
558
 
559
    change = 0;
560
    for (f = 0; f < MAX_FUNCS; f++) if (func[f] && !func[f]->tmp) {
561
      free_func (func[f]);
562
      func[f] = NULL;
563
      change = 1;
564
    }
565
    if (change) goto restart;
566
  }
567
}
568
 
569
void main_cuc (char *filename)
570
{
571
  int i, j;
572
  char tmp1[256];
573
  char filename_cut[256];
574
#if 0 /* Select prefix, based on binary program name */
575
  for (i = 0; i < sizeof (filename_cut); i++) {
576
    if (isalpha(filename[i])) filename_cut[i] = filename[i];
577
    else {
578
      filename_cut[i] = '\0';
579
      break;
580
    }
581
  }
582
#else
583
  strcpy (filename_cut, "cu");
584
#endif
585
 
586
  PRINTF ("Entering OpenRISC Custom Unit Compiler command prompt\n");
587
  PRINTF ("Using profile file \"%s\" and memory profile file \"%s\".\n", config.sim.prof_fn, config.sim.mprof_fn);
588
  sprintf (tmp1, "%s.log", filename_cut);
589
  PRINTF ("Analyzing. (log file \"%s\").\n", tmp1);
590
  assert (flog = fopen (tmp1, "wt+"));
591
 
592
  /* Loads in the specified timings table */
593
  PRINTF ("Using timings from \"%s\" at %s\n",config.cuc.timings_fn,
594
                 generate_time_pretty (tmp1, config.sim.clkcycle_ps));
595
  load_timing_table (config.cuc.timings_fn);
596
  runtime.cuc.cycle_duration = 1000. * config.sim.clkcycle_ps;
597
  PRINTF ("Multicycle logic %s, bursts %s, %s memory order.\n",
598
    config.cuc.no_multicycle ? "OFF" : "ON", config.cuc.enable_bursts ? "ON" : "OFF",
599
    config.cuc.memory_order == MO_NONE ? "no" : config.cuc.memory_order == MO_WEAK ? "weak" :
600
    config.cuc.memory_order == MO_STRONG ? "strong" : "exact");
601
 
602
  prof_set (1, 0);
603
  assert (prof_acquire (config.sim.prof_fn) == 0);
604
 
605
  if (config.cuc.calling_convention)
606
    PRINTF ("Assuming OpenRISC standard calling convention.\n");
607
 
608
  /* Try all functions except "total" */
609
  for (i = 0; i < prof_nfuncs - 1; i++) {
610
    long orig_time;
611
    unsigned long start_addr, end_addr;
612
    orig_time = prof_func[i].cum_cycles;
613
    start_addr = prof_func[i].addr;
614
 
615
    /* Extract the function from the binary */
616
    sprintf (tmp1, "%s.bin", prof_func[i].name);
617
    end_addr = extract_function (tmp1, start_addr);
618
 
619 1308 phoenix
    log ("Testing function %s (%08lx - %08lx)\n", prof_func[i].name, start_addr,
620
         end_addr);
621
    PRINTF ("Testing function %s (%08lx - %08lx)\n", prof_func[i].name,
622
            start_addr, end_addr);
623 1244 hpanther
    func[i] = analyse_function (prof_func[i].name, orig_time, start_addr,
624
                   end_addr, config.cuc.memory_order, prof_func[i].calls);
625
    func_v[i] = 0;
626
  }
627
  set_func_deps ();
628
 
629
  while (1) {
630
    char *s;
631
wait_command:
632
    PRINTF ("(cuc) ");
633
    fflush (stdout);
634
wait_command_empty:
635
    s = fgets(tmp1, sizeof tmp1, stdin);
636
    usleep (100);
637
    if (!s) goto wait_command_empty;
638
    for (s = tmp1; *s != '\0' && *s != '\n' && *s != '\r'; s++);
639
    *s = '\0';
640
 
641
      /* quit command */
642
    if (strcmp (tmp1, "q") == 0 || strcmp (tmp1, "quit") == 0) {
643
      /* Delete temporary files */
644
      for (i = 0; i < prof_nfuncs - 1; i++) {
645
        sprintf (tmp1, "%s.bin", prof_func[i].name);
646
        log ("Deleting temporary file %s %s\n", tmp1, remove (tmp1) ? "FAILED" : "OK");
647
        sprintf (tmp1, "%s.bin.bb", prof_func[i].name);
648
        log ("Deleting temporary file %s %s\n", tmp1, remove (tmp1) ? "FAILED" : "OK");
649
      }
650
      break;
651
 
652
      /* profile command */
653
    } else if (strcmp (tmp1, "p") == 0 || strcmp (tmp1, "profile") == 0) {
654
      int ntime = 0;
655
      int size = 0;
656
      PRINTF ("-----------------------------------------------------------------------------\n");
657 1308 phoenix
      PRINTF ("|function name       |calls|avg cycles  |old%%| max. f.  | impr. f.| options |\n");
658 1244 hpanther
      PRINTF ("|--------------------+-----+------------+----+----------|---------+---------|\n");
659
      for (j = 0; j < prof_nfuncs; j++) {
660
        int bestcyc = 0, besti = 0;
661
        char tmp[100];
662
        for (i = 0; i < prof_nfuncs; i++)
663
          if (prof_func[i].cum_cycles > bestcyc) {
664
            bestcyc = prof_func[i].cum_cycles;
665
            besti = i;
666
          }
667
        i = besti;
668 1308 phoenix
        PRINTF ("|%-20s|%5li|%12.1f|%3.0f%%| ",
669 1244 hpanther
                strstrip (tmp, prof_func[i].name, 20),  prof_func[i].calls,
670
                ((double)prof_func[i].cum_cycles / prof_func[i].calls),
671
                (100. * prof_func[i].cum_cycles / prof_cycles));
672
        if (func[i]) {
673
          double f = 1.0;
674
          if (func_v[i]) {
675
            int nt = calc_cycles (func[i]);
676
            int s = calc_size (func[i]);
677
            f = 1. * func[i]->orig_time / nt;
678
            ntime += nt;
679
            size += s;
680
          } else ntime += prof_func[i].cum_cycles;
681
          PRINTF ("%8.1f |%8.1f | %-8s|\n", 1.f * prof_func[i].cum_cycles
682
                          / func[i]->timings.new_time, f, format_func_options (tmp, func[i]));
683
        } else {
684
          PRINTF ("     N/A |     N/A |     N/A |\n");
685
          ntime += prof_func[i].cum_cycles;
686
        }
687
        prof_func[i].cum_cycles = -prof_func[i].cum_cycles;
688
      }
689
      for (i = 0; i < prof_nfuncs; i++)
690
        prof_func[i].cum_cycles = -prof_func[i].cum_cycles;
691
      PRINTF ("-----------------------------------------------------------------------------\n");
692
      PRINTF ("Total %i cycles (was %i), total added gates = %i. Speed factor %.1f\n",
693
                      ntime, prof_cycles, size, 1. * prof_cycles / ntime);
694
 
695
      /* debug command */
696
    } else if (strncmp (tmp1, "d", 1) == 0 || strncmp (tmp1, "debug", 5) == 0) {
697
      sscanf (tmp1, "%*s %i", &cuc_debug);
698
      if (cuc_debug < 0) cuc_debug = 0;
699
      if (cuc_debug > 9) cuc_debug = 9;
700
 
701
      /* generate command */
702
    } else if (strcmp (tmp1, "g") == 0 || strcmp (tmp1, "generate") == 0) {
703
      /* check for function dependencies */
704
      for (i = 0; i < prof_nfuncs; i++)
705
        if (func[i]) func[i]->tmp = func_v[i];
706
      for (i = 0; i < prof_nfuncs; i++) if (func[i])
707
        for (j = 0; j < func[i]->nfdeps; j++)
708
          if (!func[i]->fdeps[j] || !func[i]->fdeps[j]->tmp) {
709
            PRINTF ("Function %s must be selected for translation (required by %s)\n",
710
                    prof_func[j].name, prof_func[i].name);
711
            goto wait_command;
712
          }
713
      for (i = 0; i < prof_nfuncs; i++)
714
        if (func[i] && func_v[i]) generate_function (func[i], prof_func[i].name, filename_cut);
715
      generate_main (prof_nfuncs, func, filename_cut);
716
 
717
      /* list command */
718
    } else if (strcmp (tmp1, "l") == 0 || strcmp (tmp1, "list") == 0) {
719
      /* check for function dependencies */
720
      for (i = 0; i < prof_nfuncs; i++)
721
        if (func_v[i]) {
722
          PRINTF ("%s\n", prof_func[j].name);
723
        }
724
 
725
      /* selectall command */
726
    } else if (strcmp (tmp1, "sa") == 0 || strcmp (tmp1, "selectall") == 0) {
727 1308 phoenix
      int f;
728 1244 hpanther
      for (f = 0; f < prof_nfuncs; f++) if (func[f]) {
729
        func_v[f] = 1;
730
        PRINTF ("Function %s selected for translation.\n", prof_func[f].name);
731
      }
732
 
733
      /* select command */
734
    } else if (strncmp (tmp1, "s", 1) == 0 || strncmp (tmp1, "select", 6) == 0) {
735
      char tmp[50], ch;
736
      int p, o, b, f;
737
      p = sscanf (tmp1, "%*s %s %i%c", tmp, &b, &ch);
738
      if (p < 1) PRINTF ("Invalid parameters.\n");
739
      else {
740
        /* Check if we have valid option */
741
        for (f = 0; f < prof_nfuncs; f++)
742
          if (strcmp (prof_func[f].name, tmp) == 0 && func[f]) break;
743
        if (f < prof_nfuncs) {
744
          if (p == 1) {
745
            if (func[f]) {
746
              func_v[f] = 1;
747
              PRINTF ("Function %s selected for translation.\n", prof_func[f].name);
748
            } else PRINTF ("Function %s not suitable for translation.\n", prof_func[f].name);
749
          } else {
750
            if (!func_v[f])
751
              PRINTF ("Function %s not yet selected for translation.\n", prof_func[f].name);
752
            if (p < 3) goto invalid_option;
753
            for (o = 0; option_char[o] != '\0' && option_char[o] != ch; o++);
754
            if (!option_char[o]) goto invalid_option;
755
            if (b < 0 || b >= func[f]->num_bb) goto invalid_option;
756
            if (o < 0 || o >= func[f]->bb[b].ntim) goto invalid_option;
757
 
758
            /* select an option */
759
            func[f]->bb[b].selected_tim = o;
760
            if (func[f]->bb[b].tim[o].nshared) {
761
              PRINTF ("Option has shared instructions: ");
762
              print_shared (func[f], func[f]->bb[b].tim[o].shared, func[f]->bb[b].tim[o].nshared);
763
              PRINTF ("\n");
764
            }
765
            goto wait_command;
766
invalid_option:
767
            PRINTF ("Invalid option.\n");
768
          }
769
        } else PRINTF ("Invalid function.\n");
770
      }
771
 
772
      /* unselect command */
773
    } else if (strncmp (tmp1, "u", 1) == 0 || strncmp (tmp1, "unselect", 8) == 0) {
774
      char tmp[50], ch;
775
      int p, o, b, f;
776
      p = sscanf (tmp1, "%*s %s %i%c", tmp, &b, &ch);
777
      if (p < 1) PRINTF ("Invalid parameters.\n");
778
      else {
779
        /* Check if we have valid option */
780
        for (f = 0; f < prof_nfuncs; f++)
781
          if (strcmp (prof_func[f].name, tmp) == 0 && func[f]) break;
782
        if (f < prof_nfuncs) {
783
          if (p == 1) {
784
            if (func[f]) {
785
              func_v[f] = 0;
786
              PRINTF ("Function %s unselected for translation.\n", prof_func[f].name);
787
            } else PRINTF ("Function %s not suitable for translation.\n", prof_func[f].name);
788
          } else {
789
            if (p < 3) goto invalid_option;
790
            for (o = 0; option_char[o] != '\0' && option_char[o] != ch; o++);
791
            if (!option_char[o]) goto invalid_option;
792
            if (b < 0 || b >= func[f]->num_bb) goto invalid_option;
793
            if (o < 0 || o >= func[f]->bb[b].ntim) goto invalid_option;
794
 
795
            /* select an option */
796
            func[f]->bb[b].selected_tim = -1;
797
          }
798
        } else PRINTF ("Invalid function.\n");
799
      }
800
 
801
      /* options command */
802
    } else if (strcmp (tmp1, "o") == 0 || strcmp (tmp1, "options") == 0) {
803
      int any = 0;
804
      PRINTF ("Available options:\n");
805
      for (i = 0; i < prof_nfuncs; i++)
806
        if (func[i]) {
807
          options_cmd (i, func[i]);
808
          any = 1;
809
        }
810
      if (any) PRINTF ("-----------------------------------------------------------------------------\n");
811
      else PRINTF ("Sorry. No available options.\n");
812
 
813
      /* Ignore empty string */
814
    } else if (strcmp (tmp1, "") == 0) {
815
 
816
      /* help command */
817
    } else {
818
      if (strcmp (tmp1, "h") != 0 && strcmp (tmp1, "help") != 0)
819
        PRINTF ("Unknown command.\n");
820
      PRINTF ("OpenRISC Custom Unit Compiler command prompt\n");
821
      PRINTF ("Available commands:\n");
822
      PRINTF ("  h | help                   displays this help\n");
823
      PRINTF ("  q | quit                   returns to or1ksim prompt\n");
824
      PRINTF ("  p | profile                displays function profiling\n");
825
      PRINTF ("  d | debug #                sets debug level (0-9)\n");
826
      PRINTF ("  o | options                displays available options\n");
827
      PRINTF ("  s | select func [option]   selects an option/function\n");
828
      PRINTF ("  u | unselect func [option] unselects an option/function\n");
829
      PRINTF ("  g | generate               generates verilog file\n");
830
      PRINTF ("  l | list                   displays selected functions\n");
831
    }
832
  }
833
 
834
  /* Dispose memory */
835
  for (i = 0; i < prof_nfuncs -1; i++)
836
    if (func[i]) free_func (func[i]);
837
 
838
  fclose (flog);
839
}
840
 
841 1358 nogj
/*----------------------------------------------------[ CUC Configuration ]---*/
842
void cuc_calling_convention(union param_val val, void *dat)
843
{
844
  config.cuc.calling_convention = val.int_val;
845
}
846
 
847
void cuc_enable_bursts(union param_val val, void *dat)
848
{
849
  config.cuc.enable_bursts = val.int_val;
850
}
851
 
852
void cuc_no_multicycle(union param_val val, void *dat)
853
{
854
  config.cuc.no_multicycle = val.int_val;
855
}
856
 
857
void cuc_memory_order(union param_val val, void *dat)
858
{
859
  if (strcmp (val.str_val, "none") == 0)
860
    config.cuc.memory_order = MO_NONE;
861
  else if (strcmp (val.str_val, "weak") == 0)
862
    config.cuc.memory_order = MO_WEAK;
863
  else if (strcmp (val.str_val, "strong") == 0)
864
    config.cuc.memory_order = MO_STRONG;
865
  else if (strcmp (val.str_val, "exact") == 0) {
866
    config.cuc.memory_order = MO_EXACT;
867
  } else {
868
    char tmp[200];
869
    sprintf (tmp, "invalid memory order '%s'.\n", val.str_val);
870
    CONFIG_ERROR(tmp);
871
  }
872
}
873
 
874
void cuc_timings_fn(union param_val val, void *dat)
875
{
876
  strcpy(config.cuc.timings_fn, val.str_val);
877
}
878
 
879
void reg_cuc_sec(void)
880
{
881
  struct config_section *sec = reg_config_sec("cuc", NULL, NULL);
882
 
883
  reg_config_param(sec, "calling_convention", paramt_int, cuc_calling_convention);
884
  reg_config_param(sec, "enable_bursts", paramt_int, cuc_enable_bursts);
885
  reg_config_param(sec, "no_multicycle", paramt_int, cuc_no_multicycle);
886
  reg_config_param(sec, "memory_order", paramt_word, cuc_memory_order);
887
  reg_config_param(sec, "timings_fn", paramt_str, cuc_timings_fn);
888
}

powered by: WebSVN 2.1.0

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