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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [cuc/] [cuc.c] - Blame information for rev 193

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

Line No. Rev Author Line
1 19 jeremybenn
/* cuc.c -- OpenRISC Custom Unit Compiler
2
 
3
   Copyright (C) 2002 Marko Mlinar, markom@opencores.org
4
   Copyright (C) 2008 Embecosm Limited
5
 
6
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
7
 
8
   This file is part of OpenRISC 1000 Architectural Simulator.
9
 
10
   This program is free software; you can redistribute it and/or modify it
11
   under the terms of the GNU General Public License as published by the Free
12
   Software Foundation; either version 3 of the License, or (at your option)
13
   any later version.
14
 
15
   This program is distributed in the hope that it will be useful, but WITHOUT
16
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18
   more details.
19
 
20
   You should have received a copy of the GNU General Public License along
21
   with this program.  If not, see <http://www.gnu.org/licenses/>. */
22
 
23
/* This program is commented throughout in a fashion suitable for processing
24
   with Doxygen. */
25
 
26
/* Main file, including code optimization and command prompt */
27
 
28
 
29
/* Autoconf and/or portability configuration */
30
#include "config.h"
31
#include "port.h"
32
 
33
/* System includes */
34
#include <stdlib.h>
35
#include <unistd.h>
36
#include <assert.h>
37
 
38
/* Package includes */
39
#include "cuc.h"
40
#include "sim-config.h"
41
#include "profiler.h"
42
#include "insn.h"
43
#include "opcode/or32.h"
44
#include "parse.h"
45
#include "verilog.h"
46
#include "debug.h"
47
 
48
FILE *flog;
49
int cuc_debug = 0;
50
 
51
/* Last used registers by software convention */
52
/* Note that r11 is caller saved register, and we can destroy it.
53
   Due to CUC architecture we must always return something, even garbage (so that
54
   caller knows, we are finished, when we send acknowledge).
55
   In case r11 was not used (trivial register assignment) we will remove it later,
56
   but if we assigned a value to it, it must not be removed, so caller_saved[11] = 0 */
57
const int caller_saved[MAX_REGS] = {
58
  0, 0, 0, 1, 1, 1, 1, 1,
59
  1, 1, 0, 0, 0, 1, 0, 1,
60
  0, 1, 0, 1, 0, 1, 0, 1,
61
  0, 1, 0, 1, 0, 1, 0, 1,
62
  1, 1
63
};
64
 
65
/* Does all known instruction optimizations */
66
void
67
cuc_optimize (cuc_func * func)
68
{
69
  int modified = 0;
70
  int first = 1;
71
  log ("Optimizing.\n");
72
  do
73
    {
74
      modified = 0;
75
      clean_deps (func);
76
      if (cuc_debug >= 6)
77
        print_cuc_bb (func, "AFTER_CLEAN_DEPS");
78
      if (optimize_cmovs (func))
79
        {
80
          if (cuc_debug >= 6)
81
            print_cuc_bb (func, "AFTER_OPT_CMOVS");
82
          modified = 1;
83
        }
84
      if (cuc_debug)
85
        cuc_check (func);
86
      if (optimize_tree (func))
87
        {
88
          if (cuc_debug >= 6)
89
            print_cuc_bb (func, "AFTER_OPT_TREE1");
90
          modified = 1;
91
        }
92
      if (remove_nops (func))
93
        {
94
          if (cuc_debug >= 6)
95
            print_cuc_bb (func, "NO_NOPS");
96
          modified = 1;
97
        }
98
      if (cuc_debug)
99
        cuc_check (func);
100
      if (remove_dead (func))
101
        {
102
          if (cuc_debug >= 5)
103
            print_cuc_bb (func, "AFTER_DEAD");
104
          modified = 1;
105
        }
106
      if (cuc_debug)
107
        cuc_check (func);
108
      if (cse (func))
109
        {
110
          log ("Common subexpression elimination.\n");
111
          if (cuc_debug >= 3)
112
            print_cuc_bb (func, "AFTER_CSE");
113
          modified = 1;
114
        }
115
      if (first)
116
        {
117
          insert_conditional_facts (func);
118
          if (cuc_debug >= 3)
119
            print_cuc_bb (func, "AFTER_COND_FACT");
120
          if (cuc_debug)
121
            cuc_check (func);
122
          first = 0;
123
        }
124
      if (optimize_bb (func))
125
        {
126
          if (cuc_debug >= 5)
127
            print_cuc_bb (func, "AFTER_OPT_BB");
128
          modified = 1;
129
        }
130
      if (cuc_debug)
131
        cuc_check (func);
132
      if (remove_nops (func))
133
        {
134
          if (cuc_debug >= 6)
135
            print_cuc_bb (func, "NO_NOPS");
136
          modified = 1;
137
        }
138
      if (remove_dead_bb (func))
139
        {
140
          if (cuc_debug >= 5)
141
            print_cuc_bb (func, "AFTER_DEAD_BB");
142
          modified = 1;
143
        }
144
      if (remove_trivial_regs (func))
145
        {
146
          if (cuc_debug >= 2)
147
            print_cuc_bb (func, "AFTER_TRIVIAL");
148
          modified = 1;
149
        }
150
      if (remove_nops (func))
151
        {
152
          if (cuc_debug >= 6)
153
            print_cuc_bb (func, "NO_NOPS");
154
          modified = 1;
155
        }
156
      add_memory_dep (func, func->memory_order);
157
      if (cuc_debug >= 7)
158
        print_cuc_bb (func, "AFTER_MEMORY_DEP");
159
      add_data_dep (func);
160
      if (cuc_debug >= 8)
161
        print_cuc_bb (func, "AFTER_DATA_DEP");
162
      if (schedule_memory (func, func->memory_order))
163
        {
164
          if (cuc_debug >= 7)
165
            print_cuc_bb (func, "AFTER_SCHEDULE_MEM");
166
          modified = 1;
167
        }
168
    }
169
  while (modified);
170
  set_io (func);
171
#if 0
172
  detect_max_values (func);
173
  if (cuc_debug >= 5)
174
    print_cuc_bb (func, "AFTER_MAX_VALUES");
175
#endif
176
}
177
 
178
/* Pre/unrolls basic block and optimizes it */
179
cuc_timings *
180
preunroll_bb (char *bb_filename, cuc_func * f, cuc_timings * timings, int b,
181
              int i, int j)
182
{
183
  cuc_func *func;
184
  cucdebug (2, "BB%i unroll %i times preroll %i times\n", b, j, i);
185
  log ("BB%i unroll %i times preroll %i times\n", b, j, i);
186
  func = preunroll_loop (f, b, i, j, bb_filename);
187
  if (cuc_debug >= 2)
188
    print_cuc_bb (func, "AFTER_PREUNROLL");
189
  cuc_optimize (func);
190
  analyse_timings (func, timings);
191
 
192
  cucdebug (2, "new_time = %i, old_time = %i, size = %f\n",
193
            timings->new_time, func->orig_time, timings->size);
194
  log ("new time = %icyc, old_time = %icyc, size = %.0f gates\n",
195
       timings->new_time, func->orig_time, timings->size);
196
  //output_verilog (func, argv[1]);
197
  free_func (func);
198
  timings->b = b;
199
  timings->unroll = j;
200
  timings->preroll = i;
201
  timings->nshared = 0;
202
  return timings;
203
}
204
 
205
 
206
/* Simple comparison function */
207
int
208
tim_comp (cuc_timings * a, cuc_timings * b)
209
{
210
  if (a->new_time < b->new_time)
211
    return -1;
212
  else if (a->new_time > b->new_time)
213
    return 1;
214
  else
215
    return 0;
216
}
217
 
218
/* Analyses function; done when cuc command is entered in (sim) prompt */
219
cuc_func *
220
analyse_function (char *module_name, long orig_time,
221
                  unsigned long start_addr, unsigned long end_addr,
222
                  int memory_order, int num_runs)
223
{
224
  cuc_timings timings;
225
  cuc_func *func = (cuc_func *) malloc (sizeof (cuc_func));
226
  cuc_func *saved;
227
  int b, i, j;
228
  char tmp1[256];
229
  char tmp2[256];
230
 
231
  func->orig_time = orig_time;
232
  func->start_addr = start_addr;
233
  func->end_addr = end_addr;
234
  func->memory_order = memory_order;
235
  func->nfdeps = 0;
236
  func->fdeps = NULL;
237
  func->num_runs = num_runs;
238
 
239
  sprintf (tmp1, "%s.bin", module_name);
240
  cucdebug (2, "Loading %s.bin\n", module_name);
241
  if (cuc_load (tmp1))
242
    {
243
      free (func);
244
      return NULL;
245
    }
246
 
247
  log ("Detecting basic blocks\n");
248
  detect_bb (func);
249
  if (cuc_debug >= 2)
250
    print_cuc_insns ("WITH_BB_LIMITS", 0);
251
 
252
  //sprintf (tmp1, "%s.bin.mp", module_name);
253
  sprintf (tmp2, "%s.bin.bb", module_name);
254
  generate_bb_seq (func, config.sim.mprof_fn, tmp2);
255
  log ("Assuming %i clk cycle load (%i cyc burst)\n", runtime.cuc.mdelay[0],
256
       runtime.cuc.mdelay[2]);
257
  log ("Assuming %i clk cycle store (%i cyc burst)\n", runtime.cuc.mdelay[1],
258
       runtime.cuc.mdelay[3]);
259
 
260
  build_bb (func);
261
  if (cuc_debug >= 5)
262
    print_cuc_bb (func, "AFTER_BUILD_BB");
263
  reg_dep (func);
264
 
265
  log ("Detecting dependencies\n");
266
  if (cuc_debug >= 2)
267
    print_cuc_bb (func, "AFTER_REG_DEP");
268
  cuc_optimize (func);
269
 
270
#if 0
271
  csm (func);
272
#endif
273
  assert (saved = dup_func (func));
274
 
275
  timings.preroll = timings.unroll = 1;
276
  timings.nshared = 0;
277
 
278
  add_latches (func);
279
  if (cuc_debug >= 1)
280
    print_cuc_bb (func, "AFTER_LATCHES");
281
  analyse_timings (func, &timings);
282
 
283
  free_func (func);
284
  log ("Base option: pre%i,un%i,sha%i: %icyc %.1f\n",
285
       timings.preroll, timings.unroll, timings.nshared, timings.new_time,
286
       timings.size);
287
  saved->timings = timings;
288
 
289
#if 1
290
  /* detect and unroll simple loops */
291
  for (b = 0; b < saved->num_bb; b++)
292
    {
293
      cuc_timings t[MAX_UNROLL * MAX_PREROLL];
294
      cuc_timings *ut;
295
      cuc_timings *cut = &t[0];
296
      int nt = 1;
297
      double csize;
298
      saved->bb[b].selected_tim = -1;
299
 
300
      /* Is it a loop? */
301
      if (saved->bb[b].next[0] != b && saved->bb[b].next[1] != b)
302
        continue;
303
      log ("Found loop at BB%x.  Trying to unroll.\n", b);
304
      t[0] = timings;
305
      t[0].b = b;
306
      t[0].preroll = 1;
307
      t[0].unroll = 1;
308
      t[0].nshared = 0;
309
 
310
      sprintf (tmp1, "%s.bin.bb", module_name);
311
      i = 1;
312
      do
313
        {
314
          cuc_timings *pt;
315
          cuc_timings *cpt = cut;
316
          j = 1;
317
 
318
          do
319
            {
320
              pt = cpt;
321
              cpt = preunroll_bb (tmp1, saved, &t[nt++], b, ++j, i);
322
            }
323
          while (j <= MAX_PREROLL && pt->new_time > cpt->new_time);
324
          i++;
325
          ut = cut;
326
          cut = preunroll_bb (tmp1, saved, &t[nt++], b, 1, i);
327
        }
328
      while (i <= MAX_UNROLL && ut->new_time > cut->new_time);
329
 
330
      /* Sort the timings */
331
#if 0
332
      if (cuc_debug >= 3)
333
        for (i = 0; i < nt; i++)
334
          PRINTF ("%i:%i,%i: %icyc\n",
335
                  t[i].b, t[i].preroll, t[i].unroll, t[i].new_time);
336
#endif
337
 
338
#if HAVE___COMPAR_FN_T
339
      qsort (t, nt, sizeof (cuc_timings),
340
             (__compar_fn_t) tim_comp);
341
#else
342
      qsort (t, nt, sizeof (cuc_timings),
343
             (int (*) (const void *, const void *)) tim_comp);
344
#endif
345
 
346
      /* Delete timings, that have worst time and bigger size than other */
347
      j = 1;
348
      csize = t[0].size;
349
      for (i = 1; i < nt; i++)
350
        if (t[i].size < csize)
351
          t[j++] = t[i];
352
      nt = j;
353
 
354
      cucdebug (1, "Available options\n");
355
      for (i = 0; i < nt; i++)
356
        cucdebug (1, "%i:%i,%i: %icyc %.1f\n",
357
                  t[i].b, t[i].preroll, t[i].unroll, t[i].new_time,
358
                  t[i].size);
359
      /* Add results from CSM */
360
      j = nt;
361
      for (i = 0; i < saved->bb[b].ntim; i++)
362
        {
363
          int i1;
364
          for (i1 = 0; i1 < nt; i1++)
365
            {
366
              t[j] = t[i1];
367
              t[j].size += saved->bb[b].tim[i].size - timings.size;
368
              t[j].new_time +=
369
                saved->bb[b].tim[i].new_time - timings.new_time;
370
              t[j].nshared = saved->bb[b].tim[i].nshared;
371
              t[j].shared = saved->bb[b].tim[i].shared;
372
              if (++j >= MAX_UNROLL * MAX_PREROLL)
373
                goto full;
374
            }
375
        }
376
 
377
    full:
378
      nt = j;
379
 
380
      cucdebug (1, "Available options:\n");
381
      for (i = 0; i < nt; i++)
382
        cucdebug (1, "%i:%i,%i: %icyc %.1f\n",
383
                  t[i].b, t[i].preroll, t[i].unroll, t[i].new_time,
384
                  t[i].size);
385
 
386
      /* Sort again with new timings added */
387
#if HAVE___COMPAR_FN_T
388
      qsort (t, nt, sizeof (cuc_timings),
389
             (__compar_fn_t) tim_comp);
390
#else
391
      qsort (t, nt, sizeof (cuc_timings),
392
             (int (*)(const void *, const void *)) tim_comp);
393
#endif
394
 
395
      /* Delete timings, that have worst time and bigger size than other */
396
      j = 1;
397
      csize = t[0].size;
398
      for (i = 1; i < nt; i++)
399
        if (t[i].size < csize)
400
          t[j++] = t[i];
401
      nt = j;
402
 
403
      cucdebug (1, "Available options:\n");
404
      for (i = 0; i < nt; i++)
405
        cucdebug (1, "%i:%i,%i: %icyc %.1f\n",
406
                  t[i].b, t[i].preroll, t[i].unroll, t[i].new_time,
407
                  t[i].size);
408
 
409
      if (saved->bb[b].ntim)
410
        free (saved->bb[b].tim);
411
      saved->bb[b].ntim = nt;
412
      assert (saved->bb[b].tim =
413
              (cuc_timings *) malloc (sizeof (cuc_timings) * nt));
414
 
415
      /* Copy options in reverse order -- smallest first */
416
      for (i = 0; i < nt; i++)
417
        saved->bb[b].tim[i] = t[nt - 1 - i];
418
 
419
      log ("Available options:\n");
420
      for (i = 0; i < saved->bb[b].ntim; i++)
421
        {
422
          log ("%i:pre%i,un%i,sha%i: %icyc %.1f\n",
423
               saved->bb[b].tim[i].b, saved->bb[b].tim[i].preroll,
424
               saved->bb[b].tim[i].unroll, saved->bb[b].tim[i].nshared,
425
               saved->bb[b].tim[i].new_time, saved->bb[b].tim[i].size);
426
        }
427
    }
428
#endif
429
  return saved;
430
}
431
 
432
/* Utility option formatting functions */
433
static const char *option_char =
434
  "?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
435
 
436
/*static */ char *
437
gen_option (char *s, int bb_no, int f_opt)
438
{
439
  if (bb_no >= 0)
440
    sprintf (s, "%i", bb_no);
441
  assert (f_opt <= strlen (option_char));
442
  sprintf (s, "%s%c", s, option_char[f_opt]);
443
  return s;
444
}
445
 
446
/*static */ void
447
print_option (int bb_no, int f_opt)
448
{
449
  char tmp1[10];
450
  char tmp2[10];
451
  sprintf (tmp2, "%s", gen_option (tmp1, bb_no, f_opt));
452
  PRINTF ("%3s", tmp2);
453
}
454
 
455
static char *
456
format_func_options (char *s, cuc_func * f)
457
{
458
  int b, first = 1;
459
  *s = '\0';
460
  for (b = 0; b < f->num_bb; b++)
461
    if (f->bb[b].selected_tim >= 0)
462
      {
463
        char tmp[10];
464
        sprintf (s, "%s%s%s", s, first ? "" : ",",
465
                 gen_option (tmp, b, f->bb[b].selected_tim));
466
        first = 0;
467
      }
468
  return s;
469
}
470
 
471
static void
472
options_cmd (int func_no, cuc_func * f)
473
{
474
  int b, i;
475
  char tmp[30];
476
  char *name = prof_func[func_no].name;
477
  PRINTF
478
    ("-----------------------------------------------------------------------------\n");
479
  PRINTF ("|%-28s|pre/unrolled|shared|  time  |  gates |old_time|\n",
480
          strstrip (tmp, name, 28));
481
  PRINTF ("|                    BASE    |%4i / %4i | %4i |%8i|%8.f|%8i|\n", 1,
482
          1, 0, f->timings.new_time, f->timings.size, f->orig_time);
483
  for (b = 0; b < f->num_bb; b++)
484
    {
485
      /* Print out results */
486
      for (i = 1; i < f->bb[b].ntim; i++)
487
        {                       /* First one is base option */
488
          int time = f->bb[b].tim[i].new_time - f->timings.new_time;
489
          double size = f->bb[b].tim[i].size - f->timings.size;
490
          PRINTF ("|                   ");
491
          print_option (b, i);
492
          PRINTF ("      |%4i / %4i | %4i |%+8i|%+8.f|        |\n",
493
                  f->bb[b].tim[i].preroll, f->bb[b].tim[i].unroll,
494
                  f->bb[b].tim[i].nshared, time, size);
495
        }
496
    }
497
}
498
 
499
/* Generates a function, based on specified parameters */
500
cuc_func *
501
generate_function (cuc_func * rf, char *name, char *cut_filename)
502
{
503
  int b;
504
  char tmp[256];
505
  cuc_timings tt;
506
  cuc_func *f;
507
  assert (f = dup_func (rf));
508
 
509
  if (cuc_debug >= 2)
510
    print_cuc_bb (f, "BEFORE_GENERATE");
511
  log ("Generating function %s.\n", name);
512
  PRINTF ("Generating function %s.\n", name);
513
 
514
  format_func_options (tmp, rf);
515
  if (strlen (tmp))
516
    PRINTF ("Applying options: %s\n", tmp);
517
  else
518
    PRINTF ("Using basic options.\n");
519
 
520
  /* Generate function as specified by options */
521
  for (b = 0; b < f->num_bb; b++)
522
    {
523
      cuc_timings *st;
524
      if (rf->bb[b].selected_tim < 0)
525
        continue;
526
      st = &rf->bb[b].tim[rf->bb[b].selected_tim];
527
      sprintf (tmp, "%s.bin.bb", name);
528
      preunroll_bb (&tmp[0], f, &tt, b, st->preroll, st->unroll);
529
      if (cuc_debug >= 1)
530
        print_cuc_bb (f, "AFTER_PREUNROLL");
531
    }
532
  for (b = 0; b < f->num_bb; b++)
533
    {
534
      cuc_timings *st;
535
      if (rf->bb[b].selected_tim < 0)
536
        continue;
537
      st = &rf->bb[b].tim[rf->bb[b].selected_tim];
538
      if (!st->nshared)
539
        continue;
540
      assert (0);
541
      //csm_gen (f, rf, st->nshared, st->shared);
542
    }
543
  add_latches (f);
544
  if (cuc_debug >= 1)
545
    print_cuc_bb (f, "AFTER_LATCHES");
546
  analyse_timings (f, &tt);
547
 
548
  sprintf (tmp, "%s%s", cut_filename, name);
549
  output_verilog (f, tmp, name);
550
  return f;
551
}
552
 
553
/* Calculates required time, based on selected options */
554
int
555
calc_cycles (cuc_func * f)
556
{
557
  int b, ntime = f->timings.new_time;
558
  for (b = 0; b < f->num_bb; b++)
559
    if (f->bb[b].selected_tim >= 0)
560
      {
561
        assert (f->bb[b].selected_tim < f->bb[b].ntim);
562
        ntime +=
563
          f->bb[b].tim[f->bb[b].selected_tim].new_time - f->timings.new_time;
564
      }
565
  return ntime;
566
}
567
 
568
/* Calculates required size, based on selected options */
569
double
570
calc_size (cuc_func * f)
571
{
572
  int b;
573
  double size = f->timings.size;
574
  for (b = 0; b < f->num_bb; b++)
575
    if (f->bb[b].selected_tim >= 0)
576
      {
577
        assert (f->bb[b].selected_tim < f->bb[b].ntim);
578
        size += f->bb[b].tim[f->bb[b].selected_tim].size - f->timings.size;
579
      }
580
  return size;
581
}
582
 
583
/* Dumps specified function to file (hex) */
584
unsigned long
585
extract_function (char *out_fn, unsigned long start_addr)
586
{
587
  FILE *fo;
588
  unsigned long a = start_addr;
589
  int x = 0;
590
  assert (fo = fopen (out_fn, "wt+"));
591
 
592
  do
593
    {
594
      unsigned long d = eval_direct32 (a, 0, 0);
595
      int index = insn_decode (d);
596
      assert (index >= 0);
597
      if (x)
598
        x++;
599
      if (strcmp (insn_name (index), "l.jr") == 0)
600
        x = 1;
601
      a += 4;
602
      fprintf (fo, "%08lx\n", d);
603
    }
604
  while (x < 2);
605
 
606
  fclose (fo);
607
  return a - 4;
608
}
609
 
610
static cuc_func *func[MAX_FUNCS];
611
static int func_v[MAX_FUNCS];
612
 
613
/* Detects function dependencies and removes  */
614
static void
615
set_func_deps ()
616
{
617
  int f, b, i, j;
618
restart:
619
  for (f = 0; f < prof_nfuncs - 1; f++)
620
    if (func[f])
621
      {
622
        int fused[MAX_FUNCS] = { 0 };
623
        int c = 0;
624
        for (b = 0; b < func[f]->num_bb; b++)
625
          for (i = 0; i < func[f]->bb[b].ninsn; i++)
626
            {
627
              cuc_insn *ii = &func[f]->bb[b].insn[i];
628
              if (ii->index == II_CALL)
629
                {
630
                  assert (ii->opt[0] == OPT_CONST);
631
                  for (j = 0; j < prof_nfuncs - 1; j++)
632
                    if (func[j] && func[j]->start_addr == ii->op[0])
633
                      break;
634
                  if (j >= prof_nfuncs - 1)
635
                    {
636
                      log ("%s is calling unknown function, address %08lx\n",
637
                           prof_func[f].name, ii->op[0]);
638
                      debug (1,
639
                             "%s is calling unknown function, address %08lx\n",
640
                             prof_func[f].name, ii->op[0]);
641
                      free_func (func[f]);
642
                      func[f] = NULL;
643
                      goto restart;
644
                    }
645
                  else if (f == j)
646
                    {
647
                      log ("%s is recursive, ignoring\n", prof_func[f].name);
648
                      debug (1, "%s is recursive, ignoring\n",
649
                             prof_func[f].name);
650
                      free_func (func[f]);
651
                      func[f] = NULL;
652
                      goto restart;
653
                    }
654
                  else
655
                    fused[j]++;
656
                }
657
            }
658
        for (i = 0; i < MAX_FUNCS; i++)
659
          if (fused[i])
660
            c++;
661
        if (func[f]->nfdeps)
662
          free (func[f]->fdeps);
663
        func[f]->nfdeps = c;
664
        func[f]->fdeps = (cuc_func **) malloc (sizeof (cuc_func *) * c);
665
        for (i = 0, j = 0; i < MAX_FUNCS; i++)
666
          if (fused[i])
667
            func[f]->fdeps[j++] = func[i];
668
      }
669
 
670
  /* Detect loops */
671
  {
672
    int change;
673
    for (f = 0; f < MAX_FUNCS; f++)
674
      if (func[f])
675
        func[f]->tmp = 0;
676
    do
677
      {
678
        change = 0;
679
        for (f = 0; f < MAX_FUNCS; f++)
680
          if (func[f] && !func[f]->tmp)
681
            {
682
              int o = 1;
683
              for (i = 0; i < func[f]->nfdeps; i++)
684
                if (!func[f]->fdeps[i]->tmp)
685
                  {
686
                    o = 0;
687
                    break;
688
                  }
689
              if (o)
690
                {
691
                  func[f]->tmp = 1;
692
                  change = 1;
693
                }
694
            }
695
      }
696
    while (change);
697
 
698
    change = 0;
699
    for (f = 0; f < MAX_FUNCS; f++)
700
      if (func[f] && !func[f]->tmp)
701
        {
702
          free_func (func[f]);
703
          func[f] = NULL;
704
          change = 1;
705
        }
706
    if (change)
707
      goto restart;
708
  }
709
}
710
 
711
void
712
main_cuc (char *filename)
713
{
714
  int i, j;
715
  char tmp1[256];
716
  char filename_cut[256];
717
#if 0                           /* Select prefix, based on binary program name */
718
  for (i = 0; i < sizeof (filename_cut); i++)
719
    {
720
      if (isalpha (filename[i]))
721
        filename_cut[i] = filename[i];
722
      else
723
        {
724
          filename_cut[i] = '\0';
725
          break;
726
        }
727
    }
728
#else
729
  strcpy (filename_cut, "cu");
730
#endif
731
 
732
  PRINTF ("Entering OpenRISC Custom Unit Compiler command prompt\n");
733
  PRINTF ("Using profile file \"%s\" and memory profile file \"%s\".\n",
734
          config.sim.prof_fn, config.sim.mprof_fn);
735
  sprintf (tmp1, "%s.log", filename_cut);
736
  PRINTF ("Analyzing. (log file \"%s\").\n", tmp1);
737
  assert (flog = fopen (tmp1, "wt+"));
738
 
739
  /* Loads in the specified timings table */
740
  PRINTF ("Using timings from \"%s\" at %s\n", config.cuc.timings_fn,
741
          generate_time_pretty (tmp1, config.sim.clkcycle_ps));
742
  load_timing_table (config.cuc.timings_fn);
743
  runtime.cuc.cycle_duration = 1000. * config.sim.clkcycle_ps;
744
  PRINTF ("Multicycle logic %s, bursts %s, %s memory order.\n",
745
          config.cuc.no_multicycle ? "OFF" : "ON",
746
          config.cuc.enable_bursts ? "ON" : "OFF",
747
          config.cuc.memory_order ==
748
          MO_NONE ? "no" : config.cuc.memory_order ==
749
          MO_WEAK ? "weak" : config.cuc.memory_order ==
750
          MO_STRONG ? "strong" : "exact");
751
 
752
  prof_set (1, 0);
753
  assert (prof_acquire (config.sim.prof_fn) == 0);
754
 
755
  if (config.cuc.calling_convention)
756
    PRINTF ("Assuming OpenRISC standard calling convention.\n");
757
 
758
  /* Try all functions except "total" */
759
  for (i = 0; i < prof_nfuncs - 1; i++)
760
    {
761
      long orig_time;
762
      unsigned long start_addr, end_addr;
763
      orig_time = prof_func[i].cum_cycles;
764
      start_addr = prof_func[i].addr;
765
 
766
      /* Extract the function from the binary */
767
      sprintf (tmp1, "%s.bin", prof_func[i].name);
768
      end_addr = extract_function (tmp1, start_addr);
769
 
770
      log ("Testing function %s (%08lx - %08lx)\n", prof_func[i].name,
771
           start_addr, end_addr);
772
      PRINTF ("Testing function %s (%08lx - %08lx)\n", prof_func[i].name,
773
              start_addr, end_addr);
774
      func[i] =
775
        analyse_function (prof_func[i].name, orig_time, start_addr, end_addr,
776
                          config.cuc.memory_order, prof_func[i].calls);
777
      func_v[i] = 0;
778
    }
779
  set_func_deps ();
780
 
781
  while (1)
782
    {
783
      char *s;
784
    wait_command:
785
      PRINTF ("(cuc) ");
786
      fflush (stdout);
787
    wait_command_empty:
788
      s = fgets (tmp1, sizeof tmp1, stdin);
789
      usleep (100);
790
      if (!s)
791
        goto wait_command_empty;
792
      for (s = tmp1; *s != '\0' && *s != '\n' && *s != '\r'; s++);
793
      *s = '\0';
794
 
795
      /* quit command */
796
      if (strcmp (tmp1, "q") == 0 || strcmp (tmp1, "quit") == 0)
797
        {
798
          /* Delete temporary files */
799
          for (i = 0; i < prof_nfuncs - 1; i++)
800
            {
801
              sprintf (tmp1, "%s.bin", prof_func[i].name);
802
              log ("Deleting temporary file %s %s\n", tmp1,
803
                   remove (tmp1) ? "FAILED" : "OK");
804
              sprintf (tmp1, "%s.bin.bb", prof_func[i].name);
805
              log ("Deleting temporary file %s %s\n", tmp1,
806
                   remove (tmp1) ? "FAILED" : "OK");
807
            }
808
          break;
809
 
810
          /* profile command */
811
        }
812
      else if (strcmp (tmp1, "p") == 0 || strcmp (tmp1, "profile") == 0)
813
        {
814
          int ntime = 0;
815
          int size = 0;
816
          PRINTF
817
            ("-----------------------------------------------------------------------------\n");
818
          PRINTF
819
            ("|function name       |calls|avg cycles  |old%%| max. f.  | impr. f.| options |\n");
820
          PRINTF
821
            ("|--------------------+-----+------------+----+----------|---------+---------|\n");
822
          for (j = 0; j < prof_nfuncs; j++)
823
            {
824
              int bestcyc = 0, besti = 0;
825
              char tmp[100];
826
              for (i = 0; i < prof_nfuncs; i++)
827
                if (prof_func[i].cum_cycles > bestcyc)
828
                  {
829
                    bestcyc = prof_func[i].cum_cycles;
830
                    besti = i;
831
                  }
832
              i = besti;
833
              PRINTF ("|%-20s|%5li|%12.1f|%3.0f%%| ",
834
                      strstrip (tmp, prof_func[i].name, 20),
835
                      prof_func[i].calls,
836
                      ((double) prof_func[i].cum_cycles / prof_func[i].calls),
837
                      (100. * prof_func[i].cum_cycles / prof_cycles));
838
              if (func[i])
839
                {
840
                  double f = 1.0;
841
                  if (func_v[i])
842
                    {
843
                      int nt = calc_cycles (func[i]);
844
                      int s = calc_size (func[i]);
845
                      f = 1. * func[i]->orig_time / nt;
846
                      ntime += nt;
847
                      size += s;
848
                    }
849
                  else
850
                    ntime += prof_func[i].cum_cycles;
851
                  PRINTF ("%8.1f |%8.1f | %-8s|\n",
852
                          1.f * prof_func[i].cum_cycles /
853
                          func[i]->timings.new_time, f,
854
                          format_func_options (tmp, func[i]));
855
                }
856
              else
857
                {
858
                  PRINTF ("     N/A |     N/A |     N/A |\n");
859
                  ntime += prof_func[i].cum_cycles;
860
                }
861
              prof_func[i].cum_cycles = -prof_func[i].cum_cycles;
862
            }
863
          for (i = 0; i < prof_nfuncs; i++)
864
            prof_func[i].cum_cycles = -prof_func[i].cum_cycles;
865
          PRINTF
866
            ("-----------------------------------------------------------------------------\n");
867
          PRINTF
868
            ("Total %i cycles (was %i), total added gates = %i. Speed factor %.1f\n",
869
             ntime, prof_cycles, size, 1. * prof_cycles / ntime);
870
 
871
          /* debug command */
872
        }
873
      else if (strncmp (tmp1, "d", 1) == 0 || strncmp (tmp1, "debug", 5) == 0)
874
        {
875
          sscanf (tmp1, "%*s %i", &cuc_debug);
876
          if (cuc_debug < 0)
877
            cuc_debug = 0;
878
          if (cuc_debug > 9)
879
            cuc_debug = 9;
880
 
881
          /* generate command */
882
        }
883
      else if (strcmp (tmp1, "g") == 0 || strcmp (tmp1, "generate") == 0)
884
        {
885
          /* check for function dependencies */
886
          for (i = 0; i < prof_nfuncs; i++)
887
            if (func[i])
888
              func[i]->tmp = func_v[i];
889
          for (i = 0; i < prof_nfuncs; i++)
890
            if (func[i])
891
              for (j = 0; j < func[i]->nfdeps; j++)
892
                if (!func[i]->fdeps[j] || !func[i]->fdeps[j]->tmp)
893
                  {
894
                    PRINTF
895
                      ("Function %s must be selected for translation (required by %s)\n",
896
                       prof_func[j].name, prof_func[i].name);
897
                    goto wait_command;
898
                  }
899
          for (i = 0; i < prof_nfuncs; i++)
900
            if (func[i] && func_v[i])
901
              generate_function (func[i], prof_func[i].name, filename_cut);
902
          generate_main (prof_nfuncs, func, filename_cut);
903
 
904
          /* list command */
905
        }
906
      else if (strcmp (tmp1, "l") == 0 || strcmp (tmp1, "list") == 0)
907
        {
908
          /* check for function dependencies */
909
          for (i = 0; i < prof_nfuncs; i++)
910
            if (func_v[i])
911
              {
912
                PRINTF ("%s\n", prof_func[i].name);
913
              }
914
 
915
          /* selectall command */
916
        }
917
      else if (strcmp (tmp1, "sa") == 0 || strcmp (tmp1, "selectall") == 0)
918
        {
919
          int f;
920
          for (f = 0; f < prof_nfuncs; f++)
921
            if (func[f])
922
              {
923
                func_v[f] = 1;
924
                PRINTF ("Function %s selected for translation.\n",
925
                        prof_func[f].name);
926
              }
927
 
928
          /* select command */
929
        }
930
      else if (strncmp (tmp1, "s", 1) == 0
931
               || strncmp (tmp1, "select", 6) == 0)
932
        {
933
          char tmp[50], ch;
934
          int p, o, b, f;
935
          p = sscanf (tmp1, "%*s %s %i%c", tmp, &b, &ch);
936
          if (p < 1)
937
            PRINTF ("Invalid parameters.\n");
938
          else
939
            {
940
              /* Check if we have valid option */
941
              for (f = 0; f < prof_nfuncs; f++)
942
                if (strcmp (prof_func[f].name, tmp) == 0 && func[f])
943
                  break;
944
              if (f < prof_nfuncs)
945
                {
946
                  if (p == 1)
947
                    {
948
                      if (func[f])
949
                        {
950
                          func_v[f] = 1;
951
                          PRINTF ("Function %s selected for translation.\n",
952
                                  prof_func[f].name);
953
                        }
954
                      else
955
                        PRINTF ("Function %s not suitable for translation.\n",
956
                                prof_func[f].name);
957
                    }
958
                  else
959
                    {
960
                      if (!func_v[f])
961
                        PRINTF
962
                          ("Function %s not yet selected for translation.\n",
963
                           prof_func[f].name);
964
                      if (p < 3)
965
                        goto invalid_option;
966
                      for (o = 0;
967
                           option_char[o] != '\0' && option_char[o] != ch;
968
                           o++);
969
                      if (!option_char[o])
970
                        goto invalid_option;
971
                      if (b < 0 || b >= func[f]->num_bb)
972
                        goto invalid_option;
973
                      if (o < 0 || o >= func[f]->bb[b].ntim)
974
                        goto invalid_option;
975
 
976
                      /* select an option */
977
                      func[f]->bb[b].selected_tim = o;
978
                      if (func[f]->bb[b].tim[o].nshared)
979
                        {
980
                          PRINTF ("Option has shared instructions: ");
981
                          print_shared (func[f], func[f]->bb[b].tim[o].shared,
982
                                        func[f]->bb[b].tim[o].nshared);
983
                          PRINTF ("\n");
984
                        }
985
                      goto wait_command;
986
                    invalid_option:
987
                      PRINTF ("Invalid option.\n");
988
                    }
989
                }
990
              else
991
                PRINTF ("Invalid function.\n");
992
            }
993
 
994
          /* unselect command */
995
        }
996
      else if (strncmp (tmp1, "u", 1) == 0
997
               || strncmp (tmp1, "unselect", 8) == 0)
998
        {
999
          char tmp[50], ch;
1000
          int p, o, b, f;
1001
          p = sscanf (tmp1, "%*s %s %i%c", tmp, &b, &ch);
1002
          if (p < 1)
1003
            PRINTF ("Invalid parameters.\n");
1004
          else
1005
            {
1006
              /* Check if we have valid option */
1007
              for (f = 0; f < prof_nfuncs; f++)
1008
                if (strcmp (prof_func[f].name, tmp) == 0 && func[f])
1009
                  break;
1010
              if (f < prof_nfuncs)
1011
                {
1012
                  if (p == 1)
1013
                    {
1014
                      if (func[f])
1015
                        {
1016
                          func_v[f] = 0;
1017
                          PRINTF ("Function %s unselected for translation.\n",
1018
                                  prof_func[f].name);
1019
                        }
1020
                      else
1021
                        PRINTF ("Function %s not suitable for translation.\n",
1022
                                prof_func[f].name);
1023
                    }
1024
                  else
1025
                    {
1026
                      if (p < 3)
1027
                        goto invalid_option;
1028
                      for (o = 0;
1029
                           option_char[o] != '\0' && option_char[o] != ch;
1030
                           o++);
1031
                      if (!option_char[o])
1032
                        goto invalid_option;
1033
                      if (b < 0 || b >= func[f]->num_bb)
1034
                        goto invalid_option;
1035
                      if (o < 0 || o >= func[f]->bb[b].ntim)
1036
                        goto invalid_option;
1037
 
1038
                      /* select an option */
1039
                      func[f]->bb[b].selected_tim = -1;
1040
                    }
1041
                }
1042
              else
1043
                PRINTF ("Invalid function.\n");
1044
            }
1045
 
1046
          /* options command */
1047
        }
1048
      else if (strcmp (tmp1, "o") == 0 || strcmp (tmp1, "options") == 0)
1049
        {
1050
          int any = 0;
1051
          PRINTF ("Available options:\n");
1052
          for (i = 0; i < prof_nfuncs; i++)
1053
            if (func[i])
1054
              {
1055
                options_cmd (i, func[i]);
1056
                any = 1;
1057
              }
1058
          if (any)
1059
            PRINTF
1060
              ("-----------------------------------------------------------------------------\n");
1061
          else
1062
            PRINTF ("Sorry. No available options.\n");
1063
 
1064
          /* Ignore empty string */
1065
        }
1066
      else if (strcmp (tmp1, "") == 0)
1067
        {
1068
 
1069
          /* help command */
1070
        }
1071
      else
1072
        {
1073
          if (strcmp (tmp1, "h") != 0 && strcmp (tmp1, "help") != 0)
1074
            PRINTF ("Unknown command.\n");
1075
          PRINTF ("OpenRISC Custom Unit Compiler command prompt\n");
1076
          PRINTF ("Available commands:\n");
1077
          PRINTF ("  h | help                   displays this help\n");
1078
          PRINTF ("  q | quit                   returns to or1ksim prompt\n");
1079
          PRINTF
1080
            ("  p | profile                displays function profiling\n");
1081
          PRINTF ("  d | debug #                sets debug level (0-9)\n");
1082
          PRINTF
1083
            ("  o | options                displays available options\n");
1084
          PRINTF
1085
            ("  s | select func [option]   selects an option/function\n");
1086
          PRINTF
1087
            ("  u | unselect func [option] unselects an option/function\n");
1088
          PRINTF ("  g | generate               generates verilog file\n");
1089
          PRINTF
1090
            ("  l | list                   displays selected functions\n");
1091
        }
1092
    }
1093
 
1094
  /* Dispose memory */
1095
  for (i = 0; i < prof_nfuncs - 1; i++)
1096
    if (func[i])
1097
      free_func (func[i]);
1098
 
1099
  fclose (flog);
1100
}
1101
 
1102
/*----------------------------------------------------[ CUC Configuration ]---*/
1103
 
1104
/*---------------------------------------------------------------------------*/
1105
/*!Set the memory order
1106
 
1107
   Value must be one of none, weak, strong or exact. Invalid values are
1108
   ignored with a warning.
1109
 
1110
   @param[in] val  The value to use
1111
   @param[in] dat  The config data structure (not used here)                 */
1112
/*---------------------------------------------------------------------------*/
1113
static void
1114
cuc_memory_order (union param_val val, void *dat)
1115
{
1116
  if (strcasecmp (val.str_val, "none") == 0)
1117
    {
1118
      config.cuc.memory_order = MO_NONE;
1119
    }
1120
  else if (strcasecmp (val.str_val, "weak") == 0)
1121
    {
1122
      config.cuc.memory_order = MO_WEAK;
1123
    }
1124
  else if (strcasecmp (val.str_val, "strong") == 0)
1125
    {
1126
      config.cuc.memory_order = MO_STRONG;
1127
    }
1128
  else if (strcasecmp (val.str_val, "exact") == 0)
1129
    {
1130
      config.cuc.memory_order = MO_EXACT;
1131
    }
1132
  else
1133
    {
1134
      fprintf (stderr, "Warning: CUC memory order invalid. Ignored");
1135
    }
1136
}                               /* cuc_memory_order() */
1137
 
1138
 
1139
static void
1140
cuc_calling_conv (union param_val val, void *dat)
1141
{
1142
  config.cuc.calling_convention = val.int_val;
1143
}
1144
 
1145
static void
1146
cuc_enable_bursts (union param_val val, void *dat)
1147
{
1148
  config.cuc.enable_bursts = val.int_val;
1149
}
1150
 
1151
static void
1152
cuc_no_multicycle (union param_val val, void *dat)
1153
{
1154
  config.cuc.no_multicycle = val.int_val;
1155
}
1156
 
1157
 
1158
/*---------------------------------------------------------------------------*/
1159
/*!Set the timings file
1160
 
1161
   Free any existing string.
1162
 
1163
   @param[in] val  The value to use
1164
   @param[in] dat  The config data structure (not used here)                 */
1165
/*---------------------------------------------------------------------------*/
1166
static void
1167
cuc_timings_fn (union param_val val, void *dat)
1168
{
1169
  if (NULL != config.cuc.timings_fn)
1170
    {
1171
      free (config.cuc.timings_fn);
1172
    }
1173
 
1174
  config.cuc.timings_fn = strdup (val.str_val);
1175
 
1176
}                               /* cuc_timings_fn() */
1177
 
1178
 
1179
void
1180
reg_cuc_sec ()
1181
{
1182
  struct config_section *sec = reg_config_sec ("cuc", NULL, NULL);
1183
 
1184
  reg_config_param (sec, "memory_order", paramt_word, cuc_memory_order);
1185
  reg_config_param (sec, "calling_convention", paramt_int, cuc_calling_conv);
1186
  reg_config_param (sec, "enable_bursts", paramt_int, cuc_enable_bursts);
1187
  reg_config_param (sec, "no_multicycle", paramt_int, cuc_no_multicycle);
1188
  reg_config_param (sec, "timings_file", paramt_str, cuc_timings_fn);
1189
  reg_config_param (sec, "timings_fn", paramt_str, cuc_timings_fn);
1190
}

powered by: WebSVN 2.1.0

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