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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [or1ksim/] [cuc/] [cuc.c] - Blame information for rev 1778

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
 
3 1748 jeremybenn
   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 1244 hpanther
/* Main file, including code optimization and command prompt */
27
 
28 1308 phoenix
 
29 1748 jeremybenn
/* Autoconf and/or portability configuration */
30 1350 nogj
#include "config.h"
31 1748 jeremybenn
#include "port.h"
32 1350 nogj
 
33 1748 jeremybenn
/* System includes */
34
#include <stdlib.h>
35
#include <unistd.h>
36
#include <assert.h>
37 1350 nogj
 
38 1748 jeremybenn
/* Package includes */
39
#include "cuc.h"
40 1244 hpanther
#include "sim-config.h"
41 1748 jeremybenn
#include "profiler.h"
42 1244 hpanther
#include "insn.h"
43
#include "opcode/or32.h"
44
#include "parse.h"
45 1748 jeremybenn
#include "verilog.h"
46 1308 phoenix
#include "debug.h"
47 1244 hpanther
 
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 1748 jeremybenn
  1, 1
63
};
64 1244 hpanther
 
65
/* Does all known instruction optimizations */
66 1748 jeremybenn
void
67
cuc_optimize (cuc_func * func)
68 1244 hpanther
{
69
  int modified = 0;
70
  int first = 1;
71
  log ("Optimizing.\n");
72 1748 jeremybenn
  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 1244 hpanther
    }
169 1748 jeremybenn
  while (modified);
170 1244 hpanther
  set_io (func);
171
#if 0
172
  detect_max_values (func);
173 1748 jeremybenn
  if (cuc_debug >= 5)
174
    print_cuc_bb (func, "AFTER_MAX_VALUES");
175 1244 hpanther
#endif
176
}
177
 
178
/* Pre/unrolls basic block and optimizes it */
179 1748 jeremybenn
cuc_timings *
180
preunroll_bb (char *bb_filename, cuc_func * f, cuc_timings * timings, int b,
181
              int i, int j)
182 1244 hpanther
{
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 1748 jeremybenn
  if (cuc_debug >= 2)
188
    print_cuc_bb (func, "AFTER_PREUNROLL");
189 1244 hpanther
  cuc_optimize (func);
190
  analyse_timings (func, timings);
191
 
192
  cucdebug (2, "new_time = %i, old_time = %i, size = %f\n",
193 1748 jeremybenn
            timings->new_time, func->orig_time, timings->size);
194 1244 hpanther
  log ("new time = %icyc, old_time = %icyc, size = %.0f gates\n",
195 1748 jeremybenn
       timings->new_time, func->orig_time, timings->size);
196 1244 hpanther
  //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 1751 jeremybenn
 
206 1244 hpanther
/* Simple comparison function */
207 1748 jeremybenn
int
208
tim_comp (cuc_timings * a, cuc_timings * b)
209 1244 hpanther
{
210 1748 jeremybenn
  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 1244 hpanther
}
217
 
218
/* Analyses function; done when cuc command is entered in (sim) prompt */
219 1748 jeremybenn
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 1244 hpanther
{
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 1748 jeremybenn
  if (cuc_load (tmp1))
242
    {
243
      free (func);
244
      return NULL;
245
    }
246 1244 hpanther
 
247
  log ("Detecting basic blocks\n");
248
  detect_bb (func);
249 1748 jeremybenn
  if (cuc_debug >= 2)
250
    print_cuc_insns ("WITH_BB_LIMITS", 0);
251 1244 hpanther
 
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 1748 jeremybenn
  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 1244 hpanther
  build_bb (func);
261 1748 jeremybenn
  if (cuc_debug >= 5)
262
    print_cuc_bb (func, "AFTER_BUILD_BB");
263 1244 hpanther
  reg_dep (func);
264
 
265
  log ("Detecting dependencies\n");
266 1748 jeremybenn
  if (cuc_debug >= 2)
267
    print_cuc_bb (func, "AFTER_REG_DEP");
268 1244 hpanther
  cuc_optimize (func);
269 1748 jeremybenn
 
270 1244 hpanther
#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 1748 jeremybenn
  if (cuc_debug >= 1)
280
    print_cuc_bb (func, "AFTER_LATCHES");
281 1244 hpanther
  analyse_timings (func, &timings);
282
 
283
  free_func (func);
284
  log ("Base option: pre%i,un%i,sha%i: %icyc %.1f\n",
285 1748 jeremybenn
       timings.preroll, timings.unroll, timings.nshared, timings.new_time,
286
       timings.size);
287 1244 hpanther
  saved->timings = timings;
288 1748 jeremybenn
 
289 1244 hpanther
#if 1
290
  /* detect and unroll simple loops */
291 1748 jeremybenn
  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 1244 hpanther
 
300 1748 jeremybenn
      /* 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 1244 hpanther
 
310 1748 jeremybenn
      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 1244 hpanther
 
318 1748 jeremybenn
          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 1244 hpanther
#if 0
332 1748 jeremybenn
      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 1244 hpanther
#endif
337
 
338 1751 jeremybenn
#if HAVE___COMPAR_FN_T
339 1748 jeremybenn
      qsort (t, nt, sizeof (cuc_timings),
340 1751 jeremybenn
             (__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 1244 hpanther
 
346 1748 jeremybenn
      /* 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 1244 hpanther
 
354 1748 jeremybenn
      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 1244 hpanther
 
377 1748 jeremybenn
    full:
378
      nt = j;
379 1244 hpanther
 
380 1748 jeremybenn
      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 1244 hpanther
 
386 1748 jeremybenn
      /* Sort again with new timings added */
387 1751 jeremybenn
#if HAVE___COMPAR_FN_T
388 1748 jeremybenn
      qsort (t, nt, sizeof (cuc_timings),
389 1751 jeremybenn
             (__compar_fn_t) tim_comp);
390
#else
391
      qsort (t, nt, sizeof (cuc_timings),
392 1748 jeremybenn
             (int (*)(const void *, const void *)) tim_comp);
393 1751 jeremybenn
#endif
394 1244 hpanther
 
395 1748 jeremybenn
      /* 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 1244 hpanther
 
403 1748 jeremybenn
      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 1244 hpanther
 
409 1748 jeremybenn
      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 1244 hpanther
    }
428
#endif
429
  return saved;
430
}
431
 
432
/* Utility option formatting functions */
433 1748 jeremybenn
static const char *option_char =
434
  "?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
435 1244 hpanther
 
436 1748 jeremybenn
/*static */ char *
437
gen_option (char *s, int bb_no, int f_opt)
438 1244 hpanther
{
439 1748 jeremybenn
  if (bb_no >= 0)
440
    sprintf (s, "%i", bb_no);
441 1244 hpanther
  assert (f_opt <= strlen (option_char));
442
  sprintf (s, "%s%c", s, option_char[f_opt]);
443
  return s;
444
}
445
 
446 1748 jeremybenn
/*static */ void
447
print_option (int bb_no, int f_opt)
448 1244 hpanther
{
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 1748 jeremybenn
static char *
456
format_func_options (char *s, cuc_func * f)
457 1244 hpanther
{
458
  int b, first = 1;
459
  *s = '\0';
460
  for (b = 0; b < f->num_bb; b++)
461 1748 jeremybenn
    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 1244 hpanther
  return s;
469
}
470
 
471 1748 jeremybenn
static void
472
options_cmd (int func_no, cuc_func * f)
473 1244 hpanther
{
474
  int b, i;
475
  char tmp[30];
476
  char *name = prof_func[func_no].name;
477 1748 jeremybenn
  PRINTF
478
    ("-----------------------------------------------------------------------------\n");
479 1244 hpanther
  PRINTF ("|%-28s|pre/unrolled|shared|  time  |  gates |old_time|\n",
480 1748 jeremybenn
          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 1244 hpanther
    }
497
}
498
 
499
/* Generates a function, based on specified parameters */
500 1748 jeremybenn
cuc_func *
501
generate_function (cuc_func * rf, char *name, char *cut_filename)
502 1244 hpanther
{
503 1308 phoenix
  int b;
504 1244 hpanther
  char tmp[256];
505
  cuc_timings tt;
506
  cuc_func *f;
507
  assert (f = dup_func (rf));
508
 
509 1748 jeremybenn
  if (cuc_debug >= 2)
510
    print_cuc_bb (f, "BEFORE_GENERATE");
511 1244 hpanther
  log ("Generating function %s.\n", name);
512
  PRINTF ("Generating function %s.\n", name);
513
 
514
  format_func_options (tmp, rf);
515 1748 jeremybenn
  if (strlen (tmp))
516
    PRINTF ("Applying options: %s\n", tmp);
517
  else
518
    PRINTF ("Using basic options.\n");
519 1244 hpanther
 
520
  /* Generate function as specified by options */
521 1748 jeremybenn
  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 1244 hpanther
  add_latches (f);
544 1748 jeremybenn
  if (cuc_debug >= 1)
545
    print_cuc_bb (f, "AFTER_LATCHES");
546 1244 hpanther
  analyse_timings (f, &tt);
547 1748 jeremybenn
 
548 1244 hpanther
  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 1748 jeremybenn
int
555
calc_cycles (cuc_func * f)
556 1244 hpanther
{
557 1308 phoenix
  int b, ntime = f->timings.new_time;
558 1244 hpanther
  for (b = 0; b < f->num_bb; b++)
559 1748 jeremybenn
    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 1244 hpanther
  return ntime;
566
}
567
 
568
/* Calculates required size, based on selected options */
569 1748 jeremybenn
double
570
calc_size (cuc_func * f)
571 1244 hpanther
{
572 1308 phoenix
  int b;
573 1244 hpanther
  double size = f->timings.size;
574
  for (b = 0; b < f->num_bb; b++)
575 1748 jeremybenn
    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 1244 hpanther
  return size;
581
}
582
 
583
/* Dumps specified function to file (hex) */
584 1748 jeremybenn
unsigned long
585
extract_function (char *out_fn, unsigned long start_addr)
586 1244 hpanther
{
587
  FILE *fo;
588
  unsigned long a = start_addr;
589
  int x = 0;
590
  assert (fo = fopen (out_fn, "wt+"));
591
 
592 1748 jeremybenn
  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 1244 hpanther
 
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 1748 jeremybenn
static void
615
set_func_deps ()
616 1244 hpanther
{
617
  int f, b, i, j;
618
restart:
619 1748 jeremybenn
  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 1244 hpanther
      }
669
 
670
  /* Detect loops */
671
  {
672
    int change;
673 1748 jeremybenn
    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 1244 hpanther
      }
696 1748 jeremybenn
    while (change);
697
 
698 1244 hpanther
    change = 0;
699 1748 jeremybenn
    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 1244 hpanther
  }
709
}
710
 
711 1748 jeremybenn
void
712
main_cuc (char *filename)
713 1244 hpanther
{
714
  int i, j;
715
  char tmp1[256];
716
  char filename_cut[256];
717 1748 jeremybenn
#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 1244 hpanther
    }
728
#else
729
  strcpy (filename_cut, "cu");
730
#endif
731
 
732
  PRINTF ("Entering OpenRISC Custom Unit Compiler command prompt\n");
733 1748 jeremybenn
  PRINTF ("Using profile file \"%s\" and memory profile file \"%s\".\n",
734
          config.sim.prof_fn, config.sim.mprof_fn);
735 1244 hpanther
  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 1748 jeremybenn
  PRINTF ("Using timings from \"%s\" at %s\n", config.cuc.timings_fn,
741
          generate_time_pretty (tmp1, config.sim.clkcycle_ps));
742 1244 hpanther
  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 1748 jeremybenn
          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 1244 hpanther
 
752
  prof_set (1, 0);
753
  assert (prof_acquire (config.sim.prof_fn) == 0);
754 1748 jeremybenn
 
755 1244 hpanther
  if (config.cuc.calling_convention)
756
    PRINTF ("Assuming OpenRISC standard calling convention.\n");
757
 
758 1748 jeremybenn
  /* 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 1244 hpanther
  set_func_deps ();
780
 
781 1748 jeremybenn
  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 1244 hpanther
      /* quit command */
796 1748 jeremybenn
      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 1244 hpanther
 
810 1748 jeremybenn
          /* 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 1244 hpanther
 
871 1748 jeremybenn
          /* 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 1244 hpanther
 
881 1748 jeremybenn
          /* 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 1244 hpanther
 
904 1748 jeremybenn
          /* 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 1244 hpanther
 
915 1748 jeremybenn
          /* 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 1244 hpanther
 
928 1748 jeremybenn
          /* 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 1244 hpanther
    }
1093
 
1094
  /* Dispose memory */
1095 1748 jeremybenn
  for (i = 0; i < prof_nfuncs - 1; i++)
1096
    if (func[i])
1097
      free_func (func[i]);
1098 1244 hpanther
 
1099
  fclose (flog);
1100
}
1101
 
1102 1358 nogj
/*----------------------------------------------------[ CUC Configuration ]---*/
1103 1748 jeremybenn
 
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 1358 nogj
{
1116 1748 jeremybenn
  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 1358 nogj
  config.cuc.calling_convention = val.int_val;
1143
}
1144
 
1145 1748 jeremybenn
static void
1146
cuc_enable_bursts (union param_val val, void *dat)
1147 1358 nogj
{
1148
  config.cuc.enable_bursts = val.int_val;
1149
}
1150
 
1151 1748 jeremybenn
static void
1152
cuc_no_multicycle (union param_val val, void *dat)
1153 1358 nogj
{
1154
  config.cuc.no_multicycle = val.int_val;
1155
}
1156
 
1157
 
1158 1748 jeremybenn
/*---------------------------------------------------------------------------*/
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 1358 nogj
{
1169 1748 jeremybenn
  if (NULL != config.cuc.timings_fn)
1170
    {
1171
      free (config.cuc.timings_fn);
1172
    }
1173 1358 nogj
 
1174 1748 jeremybenn
  config.cuc.timings_fn = strdup (val.str_val);
1175
 
1176
}                               /* cuc_timings_fn() */
1177
 
1178
 
1179
void
1180
reg_cuc_sec ()
1181 1358 nogj
{
1182 1748 jeremybenn
  struct config_section *sec = reg_config_sec ("cuc", NULL, NULL);
1183 1358 nogj
 
1184 1748 jeremybenn
  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 1358 nogj
}

powered by: WebSVN 2.1.0

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