OSDN Git Service

Updated Russian translation.
[pf3gnuchains/pf3gnuchains3x.git] / cgen / sim-decode.scm
1 ; Decoder generation.
2 ; Copyright (C) 2000, 2001, 2009 Red Hat, Inc.
3 ; This file is part of CGEN.
4
5 ; Names of various global vars.
6
7 ; Name of insn descriptor table var.
8 (define IDESC-TABLE-VAR "@prefix@_insn_data")
9
10 ; Return decode entries for each insn.
11 ; ??? At one point we generated one variable per instruction rather than one
12 ; big array.  It doesn't matter too much (yet).  Generating one big array is
13 ; simpler.
14
15 (define (/gen-decode-insn-globals insn-list)
16   ; Print the higher detailed stuff at higher verbosity.
17   (logit 2 "Processing decode insn globals ...\n")
18
19   (string-write
20
21    (if (and (with-parallel?) (not (with-parallel-only?)))
22        "\
23 /* Insn can't be executed in parallel.
24    Or is that \"do NOt Pass to Air defense Radar\"? :-) */
25 #define NOPAR (-1)
26 \n"
27        "")
28
29    "\
30 /* The instruction descriptor array.
31    This is computed at runtime.  Space for it is not malloc'd to save a
32    teensy bit of cpu in the decoder.  Moving it to malloc space is trivial
33    but won't be done until necessary (we don't currently support the runtime
34    addition of instructions nor an SMP machine with different cpus).  */
35 static IDESC " IDESC-TABLE-VAR "[@PREFIX@_INSN__MAX];
36
37 /* Commas between elements are contained in the macros.
38    Some of these are conditionally compiled out.  */
39
40 static const struct insn_sem @prefix@_insn_sem[] =
41 {\n"
42
43    (string-list-map
44     (lambda (insn)
45       (let ((name (gen-sym insn))
46             (pbb? (obj-has-attr? insn 'PBB))
47             (virtual? (insn-virtual? insn)))
48         (string-list
49          "  { "
50          (if virtual?
51              (string-append "VIRTUAL_INSN_" (string-upcase name) ", ")
52              (string-append "@ARCH@_INSN_" (string-upcase name) ", "))
53          (string-append "@PREFIX@_INSN_" (string-upcase name) ", ")
54          "@PREFIX@_" (/gen-fmt-enum (insn-sfmt insn))
55          (if (and (with-parallel?) (not (with-parallel-only?)))
56              (string-list
57               (if (insn-parallel? insn)
58                   (string-append ", @PREFIX@_INSN_PAR_"
59                                  (string-upcase name)
60                                  ", "
61                                  (if (with-parallel-read?)
62                                      "@PREFIX@_INSN_READ_"
63                                      "@PREFIX@_INSN_WRITE_")
64                                  (string-upcase name))
65                   ", NOPAR, NOPAR "))
66              "")
67          " },\n")))
68     insn-list)
69
70    "\
71 };
72
73 static const struct insn_sem @prefix@_insn_sem_invalid = {
74   VIRTUAL_INSN_X_INVALID, @PREFIX@_INSN_X_INVALID, @PREFIX@_SFMT_EMPTY"
75    (if (and (with-parallel?) (not (with-parallel-only?)))
76        ", NOPAR, NOPAR"
77        "")
78    "
79 };
80 \n"
81    )
82 )
83
84 ; Return enum name of format FMT.
85
86 (define (/gen-fmt-enum fmt)
87   (string-upcase (gen-sym fmt))
88 )
89 \f
90 ; Generate decls for the insn descriptor table type IDESC.
91
92 (define (/gen-idesc-decls)
93   (string-append "\
94 extern const IDESC *@prefix@_decode (SIM_CPU *, IADDR,
95                                   CGEN_INSN_WORD,"
96   (if (adata-integral-insn? CURRENT-ARCH)
97       " CGEN_INSN_WORD,\n"
98       "\n")
99   "\
100                                   ARGBUF *);
101 extern void @prefix@_init_idesc_table (SIM_CPU *);
102 extern void @prefix@_sem_init_idesc_table (SIM_CPU *);
103 extern void @prefix@_semf_init_idesc_table (SIM_CPU *);
104 \n")
105 )
106
107 ; Return definition of C function to initialize the IDESC table.
108 ; @prefix@_init_idesc_table is defined here as it depends on with-parallel?
109 ; and thus can't be defined in sim/common.
110
111 (define (/gen-idesc-init-fn)
112   (string-append "\
113 /* Initialize an IDESC from the compile-time computable parts.  */
114
115 static INLINE void
116 init_idesc (SIM_CPU *cpu, IDESC *id, const struct insn_sem *t)
117 {
118   const CGEN_INSN *insn_table = CGEN_CPU_INSN_TABLE (CPU_CPU_DESC (cpu))->init_entries;
119
120   id->num = t->index;
121   id->sfmt = t->sfmt;
122   if ((int) t->type <= 0)
123     id->idata = & cgen_virtual_insn_table[- (int) t->type];
124   else
125     id->idata = & insn_table[t->type];
126   id->attrs = CGEN_INSN_ATTRS (id->idata);
127   /* Oh my god, a magic number.  */
128   id->length = CGEN_INSN_BITSIZE (id->idata) / 8;
129
130 #if WITH_PROFILE_MODEL_P
131   id->timing = & MODEL_TIMING (CPU_MODEL (cpu)) [t->index];
132   {
133     SIM_DESC sd = CPU_STATE (cpu);
134     SIM_ASSERT (t->index == id->timing->num);
135   }
136 #endif
137
138   /* Semantic pointers are initialized elsewhere.  */
139 }
140
141 /* Initialize the instruction descriptor table.  */
142
143 void
144 @prefix@_init_idesc_table (SIM_CPU *cpu)
145 {
146   IDESC *id,*tabend;
147   const struct insn_sem *t,*tend;
148   int tabsize = @PREFIX@_INSN__MAX;
149   IDESC *table = " IDESC-TABLE-VAR ";
150
151   memset (table, 0, tabsize * sizeof (IDESC));
152
153   /* First set all entries to the `invalid insn'.  */
154   t = & @prefix@_insn_sem_invalid;
155   for (id = table, tabend = table + tabsize; id < tabend; ++id)
156     init_idesc (cpu, id, t);
157
158   /* Now fill in the values for the chosen cpu.  */
159   for (t = @prefix@_insn_sem, tend = t + sizeof (@prefix@_insn_sem) / sizeof (*t);
160        t != tend; ++t)
161     {
162       init_idesc (cpu, & table[t->index], t);\n"
163
164    (if (and (with-parallel?) (not (with-parallel-only?)))
165        "\
166       if (t->par_index != NOPAR)
167         {
168           init_idesc (cpu, &table[t->par_index], t);
169           table[t->index].par_idesc = &table[t->par_index];
170         }\n"
171        "")
172
173    (if (and (with-parallel-write?) (not (with-parallel-only?)))
174        "\
175       if (t->par_index != NOPAR)
176         {
177           init_idesc (cpu, &table[t->write_index], t);
178           table[t->par_index].par_idesc = &table[t->write_index];
179         }\n"
180        "")
181
182    "\
183     }
184
185   /* Link the IDESC table into the cpu.  */
186   CPU_IDESC (cpu) = table;
187 }
188
189 ")
190 )
191 \f
192 ; Instruction field extraction support.
193 ; Two implementations are provided, one for !with-scache and one for
194 ; with-scache.
195 ;
196 ; Extracting ifields is a three phase process.  First the ifields are
197 ; extracted and stored in local variables.  Then any ifields requiring
198 ; additional processing for operands are handled.  Then in the with-scache
199 ; case the results are stored in a struct for later retrieval by the semantic
200 ; code.
201 ;
202 ; The !with-scache case does this processing in the semantic function,
203 ; except it doesn't need the last step (it doesn't need to store the results
204 ; in a struct for later use).
205 ;
206 ; The with-scache case extracts the ifields in the decode function.
207 ; Furthermore, we use <sformat-argbuf> to reduce the quantity of structures
208 ; created (this helps semantic-fragment pbb engines).
209
210 ; Return C code to record <ifield> F for the semantic handler
211 ; in a local variable rather than an ARGBUF struct.
212
213 (define (/gen-record-argbuf-ifld f sfmt)
214   (string-append "  " (gen-ifld-argbuf-ref f)
215                  " = " (gen-extracted-ifld-value f) ";\n")
216 )
217
218 ; Return three of arguments to TRACE:
219 ; string argument to fprintf, character indicating type of third arg, value.
220 ; The type is one of: x.
221
222 (define (/gen-trace-argbuf-ifld f sfmt)
223   (string-append
224    ; FIXME: Add method to return fprintf format string.
225    ", \"" (gen-sym f) " 0x%x\""
226    ", 'x'"
227    ", " (gen-extracted-ifld-value f))
228 )
229 \f
230 ; Instruction field extraction support cont'd.
231 ; Hardware support.
232
233 ; gen-extract method.
234 ; For the default case we use the ifield as is, which is output elsewhere.
235
236 (method-make!
237  <hardware-base> 'gen-extract
238  (lambda (self op sfmt local?)
239    "")
240 )
241
242 ; gen-trace-extract method.
243 ; Return appropriate arguments for TRACE_EXTRACT.
244
245 (method-make!
246  <hardware-base> 'gen-trace-extract
247  (lambda (self op sfmt)
248    "")
249 )
250
251 ; Extract the necessary fields into ARGBUF.
252
253 (method-make!
254  <hw-register> 'gen-extract
255  (lambda (self op sfmt local?)
256    (if (hw-cache-addr? self)
257        (string-append "  "
258                       (if local?
259                           (gen-hw-index-argbuf-name (op:index op))
260                           (gen-hw-index-argbuf-ref (op:index op)))
261                       " = & "
262                       (gen-cpu-ref (gen-sym (op:type op)))
263                       (gen-array-ref (gen-extracted-ifld-value (op-ifield op)))
264                       ";\n")
265        ""))
266 )
267
268 ; Return appropriate arguments for TRACE_EXTRACT.
269
270 (method-make!
271  <hw-register> 'gen-trace-extract
272  (lambda (self op sfmt)
273    (if (hw-cache-addr? self)
274        (string-append
275         ; FIXME: Add method to return fprintf format string.
276         ", \"" (gen-sym op) " 0x%x\""
277         ", 'x'"
278         ", " (gen-extracted-ifld-value (op-ifield op)))
279        ""))
280 )
281
282 ; Extract the necessary fields into ARGBUF.
283
284 (method-make!
285  <hw-address> 'gen-extract
286  (lambda (self op sfmt local?)
287    (string-append "  "
288                   (if local?
289                       (gen-hw-index-argbuf-name (op:index op))
290                       (gen-hw-index-argbuf-ref (op:index op)))
291                   " = "
292                   (gen-extracted-ifld-value (op-ifield op))
293                   ";\n"))
294 )
295
296 ; Return appropriate arguments for TRACE_EXTRACT.
297
298 (method-make!
299  <hw-address> 'gen-trace-extract
300  (lambda (self op sfmt)
301    (string-append
302     ; FIXME: Add method to return fprintf format string.
303     ", \"" (gen-sym op) " 0x%x\""
304     ", 'x'"
305     ", " (gen-extracted-ifld-value (op-ifield op))))
306 )
307 \f
308 ; Instruction field extraction support cont'd.
309 ; Operand support.
310
311 ; Return C code to record the field for the semantic handler.
312 ; In the case of a register, this is usually the address of the register's
313 ; value (if CACHE-ADDR).
314 ; LOCAL? indicates whether to record the value in a local variable or in
315 ; the ARGBUF struct.
316 ; ??? Later allow target to provide an `extract' expression.
317
318 (define (/gen-op-extract op sfmt local?)
319   (send (op:type op) 'gen-extract op sfmt local?)
320 )
321
322 ; Return three of arguments to TRACE_EXTRACT:
323 ; string argument to fprintf, character indicating type of third arg, value.
324 ; The type is one of: x.
325
326 (define (/gen-op-trace-extract op sfmt)
327   (send (op:type op) 'gen-trace-extract op sfmt)
328 )
329
330 ; Return C code to define local vars to hold processed ifield data for
331 ; <sformat> SFMT.
332 ; This is used when !with-scache.
333 ; Definitions of the extracted ifields is handled elsewhere.
334
335 (define (gen-sfmt-op-argbuf-defns sfmt)
336   (let ((operands (sfmt-extracted-operands sfmt)))
337     (string-list-map (lambda (op)
338                        (let ((var-spec (sfmt-op-sbuf-elm op sfmt)))
339                          (if var-spec
340                              (string-append "  "
341                                             (cadr var-spec)
342                                             " "
343                                             (car var-spec)
344                                             ";\n")
345                              "")))
346                      operands))
347 )
348
349 ; Return C code to assign values to the local vars that hold processed ifield
350 ; data for <sformat> SFMT.
351 ; This is used when !with-scache.
352 ; Assignment of the extracted ifields is handled elsewhere.
353
354 (define (gen-sfmt-op-argbuf-assigns sfmt)
355   (let ((operands (sfmt-extracted-operands sfmt)))
356     (string-list-map (lambda (op)
357                        (/gen-op-extract op sfmt #t))
358                      operands))
359 )
360 \f
361 ; Instruction field extraction support cont'd.
362 ; Emit extraction section of decode function.
363
364 ; Return C code to record insn field data for <sformat> SFMT.
365 ; This is used when with-scache.
366
367 (define (/gen-record-args sfmt)
368   (let ((operands (sfmt-extracted-operands sfmt))
369         (iflds (sfmt-needed-iflds sfmt)))
370     (string-list
371      "  /* Record the fields for the semantic handler.  */\n"
372      (string-list-map (lambda (f) (/gen-record-argbuf-ifld f sfmt))
373                       iflds)
374      (string-list-map (lambda (op) (/gen-op-extract op sfmt #f))
375                       operands)
376      "  TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "
377      "\"" (gen-sym sfmt) "\""
378      (string-list-map (lambda (f) (/gen-trace-argbuf-ifld f sfmt))
379                       iflds)
380      (string-list-map (lambda (op) (/gen-op-trace-extract op sfmt))
381                       operands)
382      ", (char *) 0));\n"
383      ))
384 )
385
386 ; Return C code to record insn field data for profiling.
387 ; Also recorded are operands not mentioned in the fields but mentioned
388 ; in the semantic code.
389 ;
390 ; FIXME: Register usage may need to be tracked as an array of longs.
391 ; If there are more than 32 regs, we can't know which until build time.
392 ; ??? For now we only handle reg sets of 32 or less.
393 ;
394 ; ??? The other way to obtain register numbers is to defer computing them
395 ; until they're actually needed.  It will speed up execution when not doing
396 ; profiling, though the speed up is only for the extraction phase.
397 ; On the other hand the current way has one memory reference per register
398 ; number in the profiling routines.  For RISC this can be a lose, though for
399 ; more complicated instruction sets it could be a win as all the computation
400 ; is kept to the extraction phase.  If someone wants to put forth some real
401 ; data, this might then be changed (or at least noted).
402
403 (define (/gen-record-profile-args sfmt)
404   (let ((in-ops (find op-profilable? (sfmt-in-ops sfmt)))
405         (out-ops (find op-profilable? (sfmt-out-ops sfmt)))
406         )
407     (if (and (null? in-ops) (null? out-ops))
408         ""
409         (string-list
410          "#if WITH_PROFILE_MODEL_P\n"
411          "  /* Record the fields for profiling.  */\n"
412          "  if (PROFILE_MODEL_P (current_cpu))\n"
413          "    {\n"
414          (string-list-map (lambda (op) (op:record-profile op sfmt #f))
415                           in-ops)
416          (string-list-map (lambda (op) (op:record-profile op sfmt #t))
417                           out-ops)
418          "    }\n"
419          "#endif\n"
420          )))
421 )
422
423 ; Return C code that extracts the fields of <sformat> SFMT.
424 ;
425 ; Extraction is based on formats to reduce the amount of code generated.
426 ; However, we also need to emit code which records the hardware elements used
427 ; by the semantic code.  This is currently done by recording this information
428 ; with the format.
429
430 (define (/gen-extract-case sfmt)
431   (logit 2 "Processing extractor for \"" (sfmt-key sfmt) "\" ...\n")
432   (string-list
433    " extract_" (gen-sym sfmt) ":\n"
434    "  {\n"
435    "    const IDESC *idesc = &" IDESC-TABLE-VAR "[itype];\n"
436    (if (> (length (sfmt-iflds sfmt)) 0)
437        (string-append
438         "    CGEN_INSN_WORD insn = "
439         (if (adata-integral-insn? CURRENT-ARCH)
440             "entire_insn;\n"
441             "base_insn;\n"))
442        "")
443    (gen-define-field-macro sfmt)
444    (gen-define-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) "    " #f)
445    "\n"
446    (gen-extract-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) "    " #f)
447    "\n"
448    (/gen-record-args sfmt)
449    "\n"
450    (/gen-record-profile-args sfmt)
451    (gen-undef-field-macro sfmt)
452    "    return idesc;\n"
453    "  }\n\n"
454    )
455 )
456
457 ; For each format, return its extraction function.
458
459 (define (/gen-all-extractors)
460   (logit 2 "Processing extractors ...\n")
461   (string-list-map /gen-extract-case (current-sfmt-list))
462 )
463 \f
464 ; Generate top level decoder.
465 ; INITIAL-BITNUMS is a target supplied list of bit numbers to use to
466 ; build the first decode table.  If nil, we compute 8 bits of it (FIXME)
467 ; ourselves.
468 ; LSB0? is non-#f if bit number 0 is the least significant bit.
469
470 (define (/gen-decode-fn insn-list initial-bitnums lsb0?)
471
472   ; Compute the initial DECODE-BITSIZE as the minimum of all insn lengths.
473   ; The caller of @prefix@_decode must fetch and pass exactly this number of bits
474   ; of the instruction.
475   ; ??? Make this a parameter later but only if necessary.
476
477   (let ((decode-bitsize (apply min (map insn-base-mask-length insn-list))))
478
479     ; Compute INITIAL-BITNUMS if not supplied.
480     ; 0 is passed for the start bit (it is independent of lsb0?)
481     (if (null? initial-bitnums)
482         (set! initial-bitnums (decode-get-best-bits insn-list nil
483                                                     0 ; startbit
484                                                     8 ; max
485                                                     decode-bitsize
486                                                     lsb0?)))
487
488     ; All set.  gen-decoder does the hard part, we just print out the result. 
489     (let ((decode-code (gen-decoder insn-list initial-bitnums
490                                     decode-bitsize
491                                     "    " lsb0?
492                                     (current-insn-lookup 'x-invalid #f)
493                                     #f)))
494
495       (string-write
496        "\
497 /* Given an instruction, return a pointer to its IDESC entry.  */
498
499 const IDESC *
500 @prefix@_decode (SIM_CPU *current_cpu, IADDR pc,
501               CGEN_INSN_WORD base_insn,"
502        (if (adata-integral-insn? CURRENT-ARCH)
503            " CGEN_INSN_WORD entire_insn,\n"
504            "\n")
505        "\
506               ARGBUF *abuf)
507 {
508   /* Result of decoder.  */
509   @PREFIX@_INSN_TYPE itype;
510
511   {
512     CGEN_INSN_WORD insn = base_insn;
513 \n"
514
515        decode-code
516
517        "\
518   }
519 \n"
520
521        (if (with-scache?)
522            (string-list "\
523   /* The instruction has been decoded, now extract the fields.  */\n\n"
524             /gen-all-extractors)
525            ; Without the scache, extraction is defered until the semantic code.
526            (string-list "\
527   /* Extraction is defered until the semantic code.  */
528
529  done:
530   return &" IDESC-TABLE-VAR "[itype];\n"))
531
532        "\
533 }\n"
534        )))
535 )
536 \f
537 ; Entry point.  Generate decode.h.
538
539 (define (cgen-decode.h)
540   (logit 1 "Generating " (gen-cpu-name) "'s decode.h ...\n")
541
542   (sim-analyze-insns!)
543
544   ; Turn parallel execution support on if cpu needs it.
545   (set-with-parallel?! (state-parallel-exec?))
546
547   (string-write
548    (gen-c-copyright "Decode header for @prefix@."
549                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
550    "\
551 #ifndef @PREFIX@_DECODE_H
552 #define @PREFIX@_DECODE_H
553
554 "
555    /gen-idesc-decls
556    (lambda () (gen-cpu-insn-enum-decl (current-cpu)
557                                       (non-multi-insns (non-alias-insns (current-insn-list)))))
558    (lambda () (gen-sfmt-enum-decl (current-sfmt-list)))
559    gen-model-fn-decls
560    "#endif /* @PREFIX@_DECODE_H */\n"
561    )
562 )
563 \f
564 ; Entry point.  Generate decode.c.
565
566 (define (cgen-decode.c)
567   (logit 1 "Generating " (gen-cpu-name) "'s decode.c ...\n")
568
569   (sim-analyze-insns!)
570
571   ; Turn parallel execution support on if cpu needs it.
572   (set-with-parallel?! (state-parallel-exec?))
573
574   ; Tell the rtx->c translator we are the simulator.
575   (rtl-c-config! #:rtl-cover-fns? #t)
576
577   (string-write
578    (gen-c-copyright "Simulator instruction decoder for @prefix@."
579                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
580    "\
581 #define WANT_CPU @cpu@
582 #define WANT_CPU_@CPU@
583
584 #include \"sim-main.h\"
585 #include \"sim-assert.h\"\n\n"
586
587    (lambda () (/gen-decode-insn-globals (non-multi-insns (non-alias-insns (current-insn-list)))))
588    /gen-idesc-init-fn
589    (lambda () (/gen-decode-fn (real-insns (current-insn-list))
590                               (state-decode-assist)
591                               (current-arch-insn-lsb0?)))
592    )
593 )