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

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_34/] [or1ksim/] [cuc/] [timings.c] - Blame information for rev 879

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

Line No. Rev Author Line
1 879 markom
/* timings.c -- OpenRISC Custom Unit Compiler, timing and size estimation
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
#include <stdio.h>
21
#include <stdlib.h>
22
#include <stdarg.h>
23
#include <assert.h>
24
#include <math.h>
25
#include "cuc.h"
26
#include "insn.h"
27
 
28
/* average memory delays in cycles {read single, read burst, write single, write burst} */
29
static const int mdelay[4] = {4, 1, 3, 1};
30
 
31
double cycle_duration;
32
double max_bb_delay;
33
 
34
static cuc_timing_table *timing_table;
35
 
36
static double insn_time (cuc_insn *ii)
37
{
38
  if (ii->opt[2] & OPT_CONST)
39
    return timing_table[ii->index].delayi;
40
  else return timing_table[ii->index].delay;
41
}
42
 
43
/* Returns dataflow tree height in cycles */
44
static double max_delay (cuc_func *f, int b)
45
{
46
  double max_d = 0.;
47
  double *d;
48
  cuc_bb *bb = &f->bb[b];
49
  int i, j;
50
  d = (double *) malloc (sizeof (double) * bb->ninsn);
51
  for (i = 0; i < bb->ninsn; i++) {
52
    double md = 0.;
53
    for (j = 0; j < MAX_OPERANDS; j++) {
54
      int op = bb->insn[i].op[j];
55
      if (bb->insn[i].opt[j] & OPT_REF && op >= 0 && REF_BB (op) == b && REF_I (op) < i) {
56
        double t = d[REF_I (op)];
57
        if (t > md) md = t;
58
      }
59
    }
60
    d[i] = md + insn_time (&bb->insn[i]);
61
    if (d[i] > max_d) max_d = d[i];
62
  }
63
  free (d);
64
  //printf ("max_d%i=%f\n", b, max_d);
65
  return max_d;
66
}
67
 
68
/* Calculates memory delay of a single run of a basic block */
69
static int memory_delay (cuc_func *f, int b)
70
{
71
  int i;
72
  int d = 0;
73
  for (i = 0; i < f->nmsched; i++)
74
    if (REF_BB (f->msched[i]) == b) {
75
      if (f->mtype[i] & MT_WRITE) {
76
        if (!(f->mtype[i] & MT_BURST) || f->mtype[i] & MT_BURSTE) d += mdelay[2];
77
        else d += mdelay[3];
78
      } else {
79
        if (!(f->mtype[i] & MT_BURST) || f->mtype[i] & MT_BURSTE) d += mdelay[0];
80
        else d += mdelay[1];
81
      }
82
    }
83
  //printf ("md%i=%i\n", b, d);
84
  return d;
85
}
86
 
87
/* Cuts the tree and marks registers */
88
void cut_tree (cuc_func *f, int b, double sd)
89
{
90
  int i, j;
91
  double *depths;
92
  cuc_bb *bb = &f->bb[b];
93
  depths = (double *) malloc (sizeof (double) * bb->ninsn);
94
 
95
  for (i = 0; i < bb->ninsn; i++) {
96
    double md = 0.;
97
    int mg = 0;
98
    for (j = 0; j < MAX_OPERANDS; j++) {
99
      int op = bb->insn[i].op[j];
100
      if (bb->insn[i].opt[j] & OPT_REF && op >= 0 && REF_BB (op) == b && REF_I (op) < i) {
101
        double t = depths[REF_I (op)];
102
        if (f->INSN(op).type & IT_CUT) {
103
          if (f->INSN(op).tmp + 1 >= mg) {
104
            if (f->INSN(op).tmp + 1 > mg) md = 0.;
105
            mg = f->INSN(op).tmp + 1;
106
            if (t > md) md = t;
107
          }
108
        } else {
109
          if (f->INSN(op).tmp >= mg) {
110
            if (f->INSN(op).tmp > mg) md = 0.;
111
            mg = f->INSN(op).tmp;
112
            if (t > md) md = t;
113
          }
114
        }
115
      }
116
    }
117
    //printf ("%2x md%.1f ", i, md);
118
    md += insn_time (&bb->insn[i]);
119
    //printf ("md%.1f mg%i %.1f\n", md, mg, sd);
120
    bb->insn[i].tmp = mg;
121
    if (md > sd) {
122
      bb->insn[i].type |= IT_CUT;
123
      if (md > cycle_duration)
124
        log ("WARNING: operation t%x_%x may need to be registered inbetween\n", b, i);
125
      depths[i] = 0.;
126
    } else depths[i] = md;
127
  }
128
  free (depths);
129
}
130
 
131
/* How many cycles we need now to get through the BB */
132
static int new_bb_cycles (cuc_func *f, int b, int cut)
133
{
134
  long d;
135
  double x = max_delay (f, b);
136
  d = ceil (x / cycle_duration);
137
  if (d < 1) d = 1;
138
  if (cut && x > cycle_duration) cut_tree (f, b, x / d);
139
 
140
  if (x / d > max_bb_delay) max_bb_delay = x / d;
141
  return memory_delay (f, b) + d;
142
}
143
 
144
/* Cuts the tree and marks registers */
145
void mark_cut (cuc_func *f)
146
{
147
  int b, i;
148
  for (b = 0; b < f->num_bb; b++)
149
    for (i = 0; i < f->bb[b].ninsn; i++)
150
      f->bb[b].insn[i].tmp = 0; /* Set starting groups */
151
  if (no_multicycle)
152
    for (b = 0; b < f->num_bb; b++)
153
      new_bb_cycles (f, b, 1);
154
}
155
 
156
/* Returns basic block circuit area */
157
static double bb_size (cuc_bb *bb)
158
{
159
  int i;
160
  double d = 0.;
161
  for (i = 0; i < bb->ninsn; i++) {
162
    if (bb->insn[i].opt[2] & OPT_CONST)
163
      d = d + timing_table[bb->insn[i].index].sizei;
164
    else d = d + timing_table[bb->insn[i].index].size;
165
  }
166
  return d;
167
}
168
 
169
/* Recalculates bb[].cnt values, based on generated profile file */
170
void recalc_cnts (cuc_func *f, char *bb_filename)
171
{
172
  int i, r, b, prevbb = -1, prevcnt = 0;
173
  int buf[256];
174
  const int bufsize = 256;
175
  FILE *fi = fopen (bb_filename, "rb");
176
 
177
  assert (fi);
178
 
179
  /* initialize counts */
180
  for (b = 0; b < f->num_bb; b++) f->bb[b].cnt = 0;
181
 
182
  /* read control flow from file and set counts */
183
  do {
184
    r = fread (buf, sizeof (int), bufsize, fi);
185
    for (i = 0; i < r; i++) {
186
      b = f->init_bb_reloc[buf[i]];
187
      if (b < 0) continue;
188
      /* Were we in the loop? */
189
      if (b == prevbb) {
190
        prevcnt++;
191
      } else {
192
        /* End the block */
193
        if (prevbb >= 0) f->bb[prevbb].cnt += prevcnt / f->bb[prevbb].unrolled + 1;
194
        prevcnt = 0;
195
        prevbb = b;
196
      }
197
    }
198
  } while (r == bufsize);
199
 
200
  fclose (fi);
201
}
202
 
203
/* Analizes current version of design and places results into timings structure */
204
void analyse_timings (cuc_func *f, cuc_timings *timings)
205
{
206
  long new_time = 0;
207
  double size = 0.;
208
  int b;
209
 
210
  max_bb_delay = 0.;
211
  for (b = 0; b < f->num_bb; b++) {
212
    new_time += new_bb_cycles (f, b, 0) * f->bb[b].cnt;
213
    size = size + bb_size (&f->bb[b]);
214
  }
215
  timings->new_time = new_time;
216
  timings->size = size;
217
  log ("Max circuit delay %.2fns; max circuit clock speed %.1fMHz\n",
218
                  max_bb_delay, 1000. / max_bb_delay);
219
}
220
 
221
/* Loads in the specified timings table */
222
void load_timing_table (char *filename)
223
{
224
  int i;
225
  FILE *fi;
226
 
227
  log ("Loading timings from %s\n", filename);
228
  log ("Using clock delay %.2fns (frequency %.0fMHz)\n", cycle_duration, 1000. / cycle_duration);
229
  assert (fi = fopen (filename, "rt"));
230
 
231
  timing_table = (cuc_timing_table *)malloc ((II_LAST + 1) * sizeof (cuc_timing_table));
232
  assert (timing_table);
233
  for (i = 0; i <= II_LAST; i++) {
234
    timing_table[i].size = -1.;
235
    timing_table[i].sizei = -1.;
236
    timing_table[i].delay = -1.;
237
    timing_table[i].delayi = -1.;
238
  }
239
 
240
  while (!feof(fi)) {
241
    char tmp[256];
242
    int index;
243
    double a[4];
244
    char c;
245
    if (fscanf (fi, "%s", tmp) != 1) break;
246
    if (tmp[0] == '#') {
247
      while (!feof (fi) && fgetc (fi) != '\n');
248
      continue;
249
    }
250
    for (i = 0; i <= II_LAST; i++)
251
      if (strcmp (known[i].name, tmp) == 0) {
252
        index = i;
253
        break;
254
      }
255
    assert (index <= II_LAST);
256
    i = index;
257
    if (fscanf (fi, "%lf%lf%lf%lf\n", &timing_table[i].size,
258
                &timing_table[i].sizei, &timing_table[i].delay, &timing_table[i].delayi) != 4) break;
259
    /*printf ("!%s size %f,%f delay %f,%f\n", known[i].name, timing_table[i].size,
260
                    timing_table[i].sizei, timing_table[i].delay, timing_table[i].delayi);*/
261
  }
262
 
263
  /* Was everything initialized? */
264
  for (i = 0; i <= II_LAST; i++) {
265
    assert (timing_table[i].size >= 0 && timing_table[i].sizei >= 0
266
     && timing_table[i].delay >= 0 && timing_table[i].delayi >= 0);
267
    /*printf ("%s size %f,%f delay %f,%f\n", known[i], timing_table[i].size,
268
                    timing_table[i].sizei, timing_table[i].delay, timing_table[i].delayi);*/
269
  }
270
 
271
  fclose (fi);
272
}
273
 

powered by: WebSVN 2.1.0

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