OSDN Git Service

Add guile 1.6.4 support.
[pf3gnuchains/sourceware.git] / cgen / sid-cpu.scm
1 ; CPU family related simulator generator, excluding decoding and model support.
2 ; Copyright (C) 2000, 2002 Red Hat, Inc.
3 ; This file is part of CGEN.
4
5 ; ***********
6 ; cgen-desc.h
7
8 (define (-last-insn)
9   (string-upcase (gen-c-symbol (caar (list-take -1
10        (gen-obj-list-enums (non-multi-insns (current-insn-list))))))))
11
12 ; Declare the attributes.
13
14 (define (-gen-attr-decls)
15   (string-list
16    "// Insn attribute indices.\n\n"
17    (gen-attr-enum-decl "cgen_insn" (current-insn-attr-list))
18    "// Attributes.\n\n"
19    (string-list-map gen-decl (current-attr-list))
20    )
21 )
22
23 ; Generate class to hold an instruction's attributes.
24
25 (define (-gen-insn-attr-decls)
26    (let ((attrs (current-insn-attr-list)))
27      (string-append
28       "// Insn attributes.\n\n"
29       ; FIXME: maybe make class, but that'll require a constructor.  Later.
30       "struct @arch@_insn_attr {\n"
31       "  unsigned int bools;\n"
32       (string-map (lambda (attr)
33                     (if (bool-attr? attr)
34                         ""
35                         (string-append "  "
36                                        (gen-attr-type attr)
37                                        " "
38                                        (string-downcase (gen-sym attr))
39                                        ";\n")))
40                   attrs)
41       ;"public:\n"
42       (string-map (lambda (attr)
43                     (string-append
44                      "  inline "
45                      (gen-attr-type attr)
46                      " get_" (string-downcase (gen-sym attr)) "_attr"
47                      " () { return "
48                      (if (bool-attr? attr)
49                          (string-append "(bools & "
50                                         (gen-attr-mask "cgen_insn" (obj:name attr))
51                                         ") != 0")
52                          (string-downcase (gen-sym attr)))
53                      "; }\n"))
54                   attrs)
55                                    
56       "};\n\n"
57       ))
58 )
59
60
61 ; Emit a macro that specifies the word-bitsize for each machine.
62 (define (-gen-mach-params)
63   (string-map (lambda (mach) 
64                 (string-append
65                  "#define MACH_" (string-upcase (gen-sym mach)) "_INSN_CHUNK_BITSIZE "
66                  (number->string (cpu-insn-chunk-bitsize (mach-cpu mach))) "\n"))
67               (current-mach-list))
68 )
69
70
71 ; Generate <cpu>-desc.h.
72
73 (define (cgen-desc.h)
74   (logit 1 "Generating " (gen-cpu-name) " desc.h ...\n")
75
76   (string-write
77    (gen-c-copyright "Misc. entries in the @arch@ description file."
78                   copyright-red-hat package-red-hat-simulators)
79    "\
80 #ifndef DESC_@ARCH@_H
81 #define DESC_@ARCH@_H
82
83 namespace @arch@ {
84 \n"
85
86    "// Enums.\n\n"
87    (lambda () (string-map gen-decl (current-enum-list)))
88
89    -gen-attr-decls
90    -gen-insn-attr-decls
91    -gen-mach-params
92
93    "
94 } // end @arch@ namespace
95
96 #endif /* DESC_@ARCH@_H */\n"
97    )
98 )
99 \f
100 ; **********
101 ; cgen-cpu.h
102
103 ; Print out file containing elements to add to cpu class.
104
105 ; Get/set fns for hardware element HW.
106
107 (define (-gen-reg-access-defns hw)
108   (let ((scalar? (hw-scalar? hw))
109         (name (obj:name hw))
110         (getter (hw-getter hw))
111         (setter (hw-setter hw))
112         (isas (bitset-attr->list (obj-attr-value hw 'ISA)))
113         (type (gen-type hw)))
114     (let ((get-code (if getter
115                         (let ((mode (hw-mode hw))
116                               (args (car getter))
117                               (expr (cadr getter)))
118                           (string-append
119                            "return "
120                            (rtl-c++ mode expr
121                                     (if scalar?
122                                         nil
123                                         (list (list (car args) 'UINT "regno")))
124                                     #:rtl-cover-fns? #t)
125                            ";"))
126                         (string-append
127                          "return this->hardware."
128                          (gen-c-symbol name)
129                          (if scalar? "" "[regno]")
130                          ";")))
131           (set-code (if setter
132                         (let ((args (car setter))
133                               (expr (cadr setter)))
134                           (rtl-c++
135                            VOID ; not `mode', sets have mode VOID
136                            expr
137                            (if scalar?
138                                (list (list (car args) (hw-mode hw) "newval"))
139                                (list (list (car args) 'UINT "regno")
140                                      (list (cadr args) (hw-mode hw) "newval")))
141                            #:rtl-cover-fns? #t))
142                         (string-append
143                          "this->hardware."
144                          (gen-c-symbol name)
145                          (if scalar? "" "[regno]")
146                          " = newval;"))))
147       (string-append
148        "  inline " type " "
149        (gen-reg-get-fun-name hw)
150        " ("
151        (if scalar? "" "UINT regno")
152        ") const"
153        " { " get-code " }"
154        "\n"
155        "  inline void "
156        (gen-reg-set-fun-name hw)
157        " ("
158        (if scalar? "" "UINT regno, ")
159        type " newval)"
160        " { " set-code " }"
161        "\n\n")))
162 )
163
164 ; Return a boolean indicating if hardware element HW needs storage allocated
165 ; for it in the SIM_CPU struct.
166
167 (define (hw-need-storage? hw)
168   (and (register? hw)
169        (not (obj-has-attr? hw 'VIRTUAL)))
170 )
171
172 ; Subroutine of -gen-hardware-types to generate the struct containing
173 ; hardware elements of one isa.
174
175 (define (-gen-hardware-struct prefix hw-list)
176   (if (null? hw-list)
177       ; If struct is empty, leave it out to simplify generated code.
178       ""
179       (string-list
180        (if prefix
181            (string-append "  // Hardware elements for " prefix ".\n")
182            "  // Hardware elements.\n")
183        "  struct {\n"
184        (string-list-map gen-decl hw-list)
185        "  } "
186        (if prefix
187            (string-append prefix "_")
188            "")
189        "hardware;\n\n"
190        ))
191 )
192
193 ; Return C type declarations of all of the hardware elements.
194 ; The name of the type is prepended with the cpu family name.
195
196 (define (-gen-hardware-types)
197   (string-list
198    "// CPU state information.\n\n"
199    (-gen-hardware-struct #f (find hw-need-storage? (current-hw-list))))
200 )
201
202 ; Generate <cpu>-cpu.h
203
204 (define (cgen-cpu.h)
205   (logit 1 "Generating " (gen-cpu-name) " cpu.h ...\n")
206   (assert-keep-one)
207
208   ; Turn parallel execution support on if cpu needs it.
209   (set-with-parallel?! (state-parallel-exec?))
210
211   ; Initialize rtl->c generation.
212   (rtl-c-config! #:rtl-cover-fns? #t)
213
214   (string-write
215    (gen-c-copyright "CPU class elements for @cpu@."
216                   copyright-red-hat package-red-hat-simulators)
217    "\
218 // This file is included in the middle of the cpu class struct.
219
220 public:
221 \n"
222
223    -gen-hardware-types
224
225    "  // C++ register access function templates\n"
226    "#define current_cpu this\n\n"
227    (lambda ()
228      (string-list-map -gen-reg-access-defns
229                       (find register? (current-hw-list))))
230    "#undef current_cpu\n\n"
231    )
232 )
233 \f
234 ; **********
235 ; cgen-defs.h
236
237 ; Print various parameters of the cpu family.
238 ; A "cpu family" here is a collection of variants of a particular architecture
239 ; that share sufficient commonality that they can be handled together.
240
241 (define (-gen-cpu-defines)
242   (string-append
243    "\
244 /* Maximum number of instructions that are fetched at a time.
245    This is for LIW type instructions sets (e.g. m32r).  */\n"
246    "#define @CPU@_MAX_LIW_INSNS " (number->string (cpu-liw-insns (current-cpu))) "\n\n"
247    "/* Maximum number of instructions that can be executed in parallel.  */\n"
248    "#define @CPU@_MAX_PARALLEL_INSNS " (number->string (cpu-parallel-insns (current-cpu))) "\n"
249    "\n"
250 ;   (gen-enum-decl '@prefix@_virtual
251 ;                 "@prefix@ virtual insns"
252 ;                 "@ARCH@_INSN_" ; not @CPU@ to match CGEN_INSN_TYPE in opc.h
253 ;                 '((x-invalid 0)
254 ;                   (x-before -1) (x-after -2)
255 ;                   (x-begin -3) (x-chain -4) (x-cti-chain -5)))
256    )
257 )
258
259 ; Generate type of struct holding model state while executing.
260
261 (define (-gen-model-decls)
262   (logit 2 "Generating model decls ...\n")
263   (string-list
264    (string-list-map
265     (lambda (model)
266       (string-list
267        "typedef struct {\n"
268        (if (null? (model:state model))
269            "  int empty;\n"
270            (string-map (lambda (var)
271                          (string-append "  "
272                                         (mode:c-type (mode:lookup (cadr var)))
273                                         " "
274                                         (gen-c-symbol (car var))
275                                         ";\n"))
276                        (model:state model)))
277        "} " 
278        (if (null? (model:state model)) "BLANK" "@CPU@") "_MODEL_DATA;\n\n"
279        ))
280     (current-model-list))
281    "   
282 typedef int (@CPU@_MODEL_FN) (struct @cpu@_cpu*, void*);
283
284 typedef struct {
285   /* This is an integer that identifies this insn.
286      How this works is up to the target.  */
287   int num;
288
289   /* Function to handle insn-specific profiling.  */
290   @CPU@_MODEL_FN *model_fn;
291
292   /* Array of function units used by this insn.  */
293   UNIT units[MAX_UNITS];
294 } @CPU@_INSN_TIMING;"
295    )
296 )
297
298 ; Utility of gen-parallel-exec-type to generate the definition of one
299 ; structure in PAREXEC.
300 ; SFMT is an <sformat> object.
301
302 (define (gen-parallel-exec-elm sfmt)
303   (string-append
304    "    struct { /* " (obj:comment sfmt) " */\n"
305    (let ((sem-ops
306           ((if (with-parallel-write?) sfmt-out-ops sfmt-in-ops) sfmt)))
307      (if (null? sem-ops)
308          "      int empty;\n"
309          (string-map
310           (lambda (op)
311             (logit 2 "Processing operand " (obj:name op) " of format "
312                    (obj:name sfmt) " ...\n")
313               (if (with-parallel-write?)
314                   (let ((index-type (and (op-save-index? op)
315                                          (gen-index-type op sfmt))))
316                     (string-append "      " (gen-type op)
317                                    " " (gen-sym op) ";\n"
318                                    (if index-type
319                                        (string-append "      " index-type 
320                                                       " " (gen-sym op) "_idx;\n")
321                                        "")))
322                   (string-append "      "
323                                  (gen-type op)
324                                  " "
325                                  (gen-sym op)
326                                  ";\n")))
327           sem-ops)))
328    "    } " (gen-sym sfmt) ";\n"
329    )
330 )
331
332 ; Generate the definition of the structure that holds register values, etc.
333 ; for use during parallel execution.  When instructions are executed parallelly
334 ; either
335 ; - their inputs are read before their outputs are written.  Thus we have to
336 ; fetch the input values of several instructions before executing any of them.
337 ; - or their outputs are queued here first and then written out after all insns
338 ; have executed.
339 ; The fetched/queued values are stored in an array of PAREXEC structs, one
340 ; element per instruction.
341
342 (define (gen-parallel-exec-type)
343   (logit 2 "Generating PAREXEC type ...\n")
344   (string-append
345    (if (with-parallel-write?)
346        "/* Queued output values of an instruction.  */\n"
347        "/* Fetched input values of an instruction.  */\n")
348    "\
349
350 struct @prefix@_parexec {
351   union {\n"
352    (string-map gen-parallel-exec-elm (current-sfmt-list))
353    "\
354   } operands;
355   /* For conditionally written operands, bitmask of which ones were.  */
356   unsigned long long written;
357 };\n\n"
358    )
359 )
360
361 ; Generate the TRACE_RECORD struct definition.
362
363 (define (-gen-trace-record-type)
364   (string-list
365    "\
366 /* Collection of various things for the trace handler to use.  */
367
368 typedef struct @prefix@_trace_record {
369   PCADDR pc;
370   /* FIXME:wip */
371 } @CPU@_TRACE_RECORD;
372 \n"
373    )
374 )
375
376 ; Generate <cpu>-defs.h
377
378 (define (cgen-defs.h)
379   (logit 1 "Generating " (gen-cpu-name) " defs.h ...\n")
380   (assert-keep-one)
381
382   ; Turn parallel execution support on if cpu needs it.
383   (set-with-parallel?! (state-parallel-exec?))
384
385   ; Initialize rtl->c generation.
386   (rtl-c-config! #:rtl-cover-fns? #t)
387
388   (string-write
389    (gen-c-copyright "CPU family header for @cpu@ / @prefix@."
390                   copyright-red-hat package-red-hat-simulators)
391    "\
392 #ifndef DEFS_@PREFIX@_H
393 #define DEFS_@PREFIX@_H
394
395 namespace @cpu@ {
396 \n"
397
398    (if (with-parallel?)
399        gen-parallel-exec-type
400        "")
401
402    "\
403 } // end @cpu@ namespace
404
405 #endif /* DEFS_@PREFIX@_H */\n"
406    )
407 )
408 \f
409 ; **************
410 ; cgen-write.cxx
411
412 ; This is the other way of implementing parallel execution support.
413 ; Instead of fetching all the input operands first, write all the output
414 ; operands and their addresses to holding variables, and then run a
415 ; post-processing pass to update the cpu state.
416
417 ; Return C code to fetch and save all output operands to instructions with
418 ; <sformat> SFMT.
419
420 (define (-gen-write-args sfmt)
421   (string-map (lambda (op) (op:write op sfmt))
422               (sfmt-out-ops sfmt))
423 )
424
425 ; Utility of gen-write-fns to generate a writer function for <sformat> SFMT.
426
427 (define (-gen-write-fn sfmt)
428   (logit 2 "Processing write function for \"" (obj:name sfmt) "\" ...\n")
429   (string-list
430    "\nsem_status\n"
431    (-gen-write-fn-name sfmt) " (@cpu@_cpu* current_cpu, @prefix@_scache* sem, @prefix@_parexec* par_exec)\n"
432    "{\n"
433    (if (with-scache?)
434        (gen-define-field-macro sfmt)
435        "")
436    (gen-define-parallel-operand-macro sfmt)
437    "  @prefix@_scache* abuf = sem;\n"
438    "  unsigned long long written = abuf->written;\n"
439    "  PCADDR pc = abuf->addr;\n"
440    "  PCADDR npc = 0; // dummy value for branches\n"
441    "  sem_status status = SEM_STATUS_NORMAL; // ditto\n"
442    "\n"
443    (-gen-write-args sfmt)
444    "\n"
445    "  return status;\n"
446    (gen-undef-parallel-operand-macro sfmt)
447    (if (with-scache?)
448        (gen-undef-field-macro sfmt)
449        "")
450    "}\n\n")
451 )
452
453 (define (-gen-write-fns)
454   (logit 2 "Processing writer functions ...\n")
455   (string-write-map (lambda (sfmt) (-gen-write-fn sfmt))
456                     (current-sfmt-list))
457 )
458
459
460 ; Generate <cpu>-write.cxx.
461
462 (define (cgen-write.cxx)
463   (logit 1 "Generating " (gen-cpu-name) " write.cxx ...\n")
464   (assert-keep-one)
465
466   (sim-analyze-insns!)
467
468   ; Turn parallel execution support off.
469   (set-with-parallel?! #f)
470
471   ; Tell the rtx->c translator we are the simulator.
472   (rtl-c-config! #:rtl-cover-fns? #t)
473
474   (string-write
475    (gen-c-copyright (string-append "Simulator instruction operand writer for "
476                                    (symbol->string (current-arch-name))
477                                    ".")
478                  copyright-red-hat package-red-hat-simulators)
479    "\
480
481 #include \"@cpu@.h\"
482 using namespace @cpu@;
483
484 "
485    -gen-write-fns
486    )
487 )
488 \f
489 ; ******************
490 ; cgen-semantics.cxx
491
492 ; Return C code to perform the semantics of INSN.
493
494 (define (gen-semantic-code insn)
495   ; Indicate generating code for INSN.
496   ; Use the compiled form if available.
497   ; The case when they're not available is for virtual insns.
498   (let ((sem-c-code
499          (if (insn-compiled-semantics insn)
500              (rtl-c++-parsed VOID (insn-compiled-semantics insn) nil
501                              #:rtl-cover-fns? #t
502                              #:owner insn)
503              (rtl-c++ VOID (insn-semantics insn) nil
504                       #:rtl-cover-fns? #t
505                       #:owner insn)))
506         )
507     sem-c-code)
508 )
509
510 ; Return definition of C function to perform INSN.
511 ; This version handles the with-scache case.
512
513 (define (-gen-scache-semantic-fn insn)
514   (logit 2 "Processing semantics for " (obj:name insn) ": \"" (insn-syntax insn) "\" ...\n")
515   (set! -with-profile? -with-profile-fn?)
516   (let ((cti? (insn-cti? insn))
517         (insn-len (insn-length-bytes insn)))
518     (string-list
519      "// ********** " (obj:name insn) ": " (insn-syntax insn) "\n\n"
520      (if (with-parallel?)
521          "void\n"
522          "sem_status\n")
523      "@prefix@_sem_" (gen-sym insn)
524      (if (with-parallel?)
525          " (@cpu@_cpu* current_cpu, @prefix@_scache* sem, @prefix@_parexec* par_exec)\n"
526          " (@cpu@_cpu* current_cpu, @prefix@_scache* sem)\n")
527      "{\n"
528      (gen-define-field-macro (insn-sfmt insn))
529      (if (with-parallel?)
530          (gen-define-parallel-operand-macro (insn-sfmt insn))
531          "")
532      "  sem_status status = SEM_STATUS_NORMAL;\n"
533      "  @prefix@_scache* abuf = sem;\n"
534      ; Unconditionally written operands are not recorded here.
535      (if (or (with-profile?) (with-parallel-write?))
536          "  unsigned long long written = 0;\n"
537          "")
538      ; The address of this insn, needed by extraction and semantic code.
539      ; Note that the address recorded in the cpu state struct is not used.
540      ; For faster engines that copy will be out of date.
541      "  PCADDR pc = abuf->addr;\n"
542      "  PCADDR npc = pc + " (number->string insn-len) ";\n"
543      "\n"
544      (gen-semantic-code insn)
545      "\n"
546      ; Only update what's been written if some are conditionally written.
547      ; Otherwise we know they're all written so there's no point in
548      ; keeping track.
549      (if (or (with-profile?) (with-parallel-write?))
550          (if (-any-cond-written? (insn-sfmt insn))
551              "  abuf->written = written;\n"
552              "")
553          "")
554      (if cti?
555          "  current_cpu->done_cti_insn (npc, status);\n"
556          "  current_cpu->done_insn (npc, status);\n")
557      (if (with-parallel?)
558          ""
559          "  return status;\n")
560      (if (with-parallel?)
561          (gen-undef-parallel-operand-macro (insn-sfmt insn))
562          "")
563      (gen-undef-field-macro (insn-sfmt insn))
564      "}\n\n"
565      ))
566 )
567
568 (define (-gen-all-semantic-fns)
569   (logit 2 "Processing semantics ...\n")
570   (let ((insns (scache-engine-insns)))
571     (if (with-scache?)
572         (string-write-map -gen-scache-semantic-fn insns)
573         (error "must specify `with-scache'")))
574 )
575
576 ; Generate <cpu>-sem.cxx.
577 ; Each instruction is implemented in its own function.
578
579 (define (cgen-semantics.cxx)
580   (logit 1 "Generating " (gen-cpu-name) " semantics.cxx ...\n")
581   (assert-keep-one)
582
583   (sim-analyze-insns!)
584
585   ; Turn parallel execution support on if cpu needs it.
586   (set-with-parallel?! (state-parallel-exec?))
587
588   ; Tell the rtx->c translator we are the simulator.
589   (rtl-c-config! #:rtl-cover-fns? #t)
590
591   ; Indicate we're currently not generating a pbb engine.
592   (set-current-pbb-engine?! #f)
593
594   (string-write
595    (gen-c-copyright "Simulator instruction semantics for @prefix@."
596                   copyright-red-hat package-red-hat-simulators)
597    "\
598
599 #if HAVE_CONFIG_H
600 #include \"config.h\"
601 #endif
602 #include \"@cpu@.h\"
603
604 using namespace @cpu@; // FIXME: namespace organization still wip
605
606 #define GET_ATTR(name) GET_ATTR_##name ()
607
608 \n"
609
610    -gen-all-semantic-fns
611    )
612 )
613 \f
614 ; *******************
615 ; cgen-sem-switch.cxx
616 ;
617 ; The semantic switch engine has two flavors: one case per insn, and one
618 ; case per "frag" (where each insn is split into one or more fragments).
619
620 ; Utility of -gen-sem-case to return the mask of operands always written
621 ; to in <sformat> SFMT.
622 ; ??? Not currently used.
623
624 (define (-uncond-written-mask sfmt)
625   (apply + (map (lambda (op)
626                   (if (op:cond? op)
627                       0
628                       (logsll 1 (op:num op))))
629                 (sfmt-out-ops sfmt)))
630 )
631
632 ; Utility of -gen-sem-case to return #t if any operand in <sformat> SFMT is
633 ; conditionally written to.
634
635 (define (-any-cond-written? sfmt)
636   (any-true? (map op:cond? (sfmt-out-ops sfmt)))
637 )
638 \f
639 ; One case per insn version.
640
641 ; Generate a switch case to perform INSN.
642
643 (define (-gen-sem-case insn parallel?)
644   (logit 2 "Processing "
645          (if parallel? "parallel " "")
646          "semantic switch case for \"" (insn-syntax insn) "\" ...\n")
647   (set! -with-profile? -with-profile-sw?)
648   (let ((cti? (insn-cti? insn))
649         (insn-len (insn-length-bytes insn)))
650     (string-list
651      ; INSN_ is prepended here and not elsewhere to avoid name collisions
652      ; with symbols like AND, etc.
653      "\
654 // ********** " (insn-syntax insn) "
655
656   CASE (INSN_" (if parallel? "PAR_" "") (string-upcase (gen-sym insn)) "):
657     {
658       @prefix@_scache* abuf = vpc;\n"
659      (if (with-scache?)
660          (gen-define-field-macro (insn-sfmt insn))
661          "")
662      (if parallel?
663          (gen-define-parallel-operand-macro (insn-sfmt insn))
664          "")
665      ; Unconditionally written operands are not recorded here.
666      (if (or (with-profile?) (with-parallel-write?))
667          "      unsigned long long written = 0;\n"
668          "")
669      ; The address of this insn, needed by extraction and semantic code.
670      ; Note that the address recorded in the cpu state struct is not used.
671      "      PCADDR pc = abuf->addr;\n"
672      (if (and cti? (not parallel?))
673          (string-append "      PCADDR npc;\n"
674                         "      branch_status br_status = BRANCH_UNTAKEN;\n")
675          "")
676      (string-list "      vpc = vpc + 1;\n")
677      ; Emit setup-semantics code for real insns.
678      (if (and (insn-real? insn)
679               (isa-setup-semantics (current-isa)))
680          (string-append
681           "      "
682           (rtl-c++ VOID (isa-setup-semantics (current-isa)) nil
683                    #:rtl-cover-fns? #t
684                    #:owner insn))
685          "")
686      "\n"
687      (gen-semantic-code insn)
688      "\n"
689      ; Only update what's been written if some are conditionally written.
690      ; Otherwise we know they're all written so there's no point in
691      ; keeping track.
692      (if (or (with-profile?) (with-parallel-write?))
693          (if (-any-cond-written? (insn-sfmt insn))
694              "        abuf->written = written;\n"
695              "")
696          "")
697      (if (and cti? (not parallel?))
698          (string-append "      pbb_br_npc = npc;\n"
699                         "      pbb_br_status = br_status;\n")
700          "")
701      (if parallel?
702          (gen-undef-parallel-operand-macro (insn-sfmt insn))
703          "")
704      (if (with-scache?)
705          (gen-undef-field-macro (insn-sfmt insn))
706          "")
707      "    }\n"
708      "    NEXT (vpc);\n\n"
709      ))
710 )
711
712 (define (-gen-sem-switch)
713   (logit 2 "Processing semantic switch ...\n")
714   ; Turn parallel execution support off.
715   (set-with-parallel?! #f)
716   (string-write-map (lambda (insn) (-gen-sem-case insn #f))
717                     (non-multi-insns (non-alias-insns (current-insn-list))))
718 )
719
720 ; Generate the guts of a C switch statement to execute parallel instructions.
721 ; This switch is included after the non-parallel instructions in the semantic
722 ; switch.
723 ;
724 ; ??? We duplicate the writeback case for each insn, even though we only need
725 ; one case per insn format.  The former keeps the code for each insn
726 ; together and might improve cache usage.  On the other hand the latter
727 ; reduces the amount of code, though it is believed that in this particular
728 ; instance the win isn't big enough.
729
730 (define (-gen-parallel-sem-switch)
731   (logit 2 "Processing parallel insn semantic switch ...\n")
732   ; Turn parallel execution support on.
733   (set-with-parallel?! #t)
734   (string-write-map (lambda (insn)
735                       (string-list (-gen-sem-case insn #t)
736                                    (-gen-write-case (insn-sfmt insn) insn)))
737                     (parallel-insns (current-insn-list)))
738 )
739
740 ; Return computed-goto engine.
741
742 (define (-gen-sem-switch-engine)
743   (string-write
744    "\
745 void
746 @cpu@_cpu::@prefix@_pbb_run ()
747 {
748   @cpu@_cpu* current_cpu = this;
749   @prefix@_scache* vpc;
750   // These two are used to pass data from cti insns to the cti-chain insn.
751   PCADDR pbb_br_npc;
752   branch_status pbb_br_status;
753
754 #ifdef __GNUC__
755 {
756   static const struct sem_labels
757     {
758       enum @prefix@_insn_type insn;
759       void *label;
760     }
761   labels[] = 
762     {\n"
763
764    (lambda ()
765      (string-write-map (lambda (insn)
766                          (string-append "      { "
767                                         "@PREFIX@_INSN_"
768                                         (string-upcase (gen-sym insn))
769                                         ", && case_INSN_"
770                                         (string-upcase (gen-sym insn))
771                                         " },\n"))
772                        (non-multi-insns (non-alias-insns (current-insn-list)))))
773
774    (if (state-parallel-exec?)
775        (lambda ()
776          (string-write-map (lambda (insn)
777                              (string-append "      { "
778                                             "@PREFIX@_INSN_PAR_"
779                                             (string-upcase (gen-sym insn))
780                                             ", && case_INSN_PAR_"
781                                             (string-upcase (gen-sym insn))
782                                             " },\n"
783                                             "      { "
784                                             "@PREFIX@_INSN_WRITE_"
785                                             (string-upcase (gen-sym insn))
786                                             ", && case_INSN_WRITE_"
787                                             (string-upcase (gen-sym insn))
788                                             " },\n"))
789                            (parallel-insns (current-insn-list))))
790        "")
791
792    "    { (@prefix@_insn_type) 0, 0 }
793   };
794
795   if (! @prefix@_idesc::idesc_table_initialized_p)
796     {
797       for (int i=0; labels[i].label != 0; i++)
798         @prefix@_idesc::idesc_table[labels[i].insn].cgoto.label = labels[i].label; 
799
800       // confirm that table is all filled up
801       for (int i = 0; i <= @PREFIX@_INSN_" (-last-insn) "; i++)
802         assert (@prefix@_idesc::idesc_table[i].cgoto.label != 0);
803
804       // Initialize the compiler virtual insn.
805       current_cpu->@prefix@_engine.compile_begin_insn (current_cpu);
806
807       @prefix@_idesc::idesc_table_initialized_p = true;
808     }
809 }
810 #endif
811
812 #ifdef __GNUC__
813 #define CASE(X) case_##X
814 // Branch to next handler without going around main loop.
815 #define NEXT(vpc) goto * vpc->execute.cgoto.label;
816 // Break out of threaded interpreter and return to \"main loop\".
817 #define BREAK(vpc) goto end_switch
818 #else
819 #define CASE(X) case @PREFIX@_##X
820 #define NEXT(vpc) goto restart
821 #define BREAK(vpc) break
822 #endif
823
824   // Get next insn to execute.
825   vpc = current_cpu->@prefix@_engine.get_next_vpc (current_cpu->h_pc_get ());
826
827 restart:
828 #ifdef __GNUC__
829   goto * vpc->execute.cgoto.label;
830 #else
831   switch (vpc->idesc->sem_index)
832 #endif
833
834   {
835 "
836
837   -gen-sem-switch
838
839    (if (state-parallel-exec?)
840        -gen-parallel-sem-switch
841        "")
842
843 "
844 #ifdef __GNUC__
845     end_switch: ;
846 #else
847     default: abort();
848 #endif
849   }
850
851   // Save vpc for next time.
852   current_cpu->@prefix@_engine.set_next_vpc (vpc);
853 }
854 \n"
855    )
856 )
857 \f
858 ; Semantic frag version.
859
860 ; Return declaration of frag enum.
861
862 (define (-gen-sfrag-enum-decl frag-list)
863   (gen-enum-decl "@prefix@_frag_type"
864                  "semantic fragments in cpu family @prefix@"
865                  "@PREFIX@_FRAG_"
866                  (append '((list-end))
867                          (map (lambda (i)
868                                 (cons (obj:name i)
869                                       (cons '-
870                                             (atlist-attrs (obj-atlist i)))))
871                               frag-list)
872                          '((max))))
873 )
874
875 ; Return header file decls for semantic frag threaded engine.
876
877 (define (-gen-sfrag-engine-decls)
878   (string-write
879    "namespace @cpu@ {\n\n"
880
881    ; FIXME: vector->list
882    (-gen-sfrag-enum-decl (vector->list (sim-sfrag-frag-table)))
883
884    "\
885 struct @prefix@_insn_frag {
886   @PREFIX@_INSN_TYPE itype;
887   // 4: header+middle+trailer+delimiter
888   @PREFIX@_FRAG_TYPE ftype[4];
889 };
890
891 struct @prefix@_pbb_label {
892   @PREFIX@_FRAG_TYPE frag;
893   void *label;
894 };
895
896 } // end @cpu@ namespace
897 \n")
898 )
899
900 ; Return C code to perform the semantics of FRAG.
901 ; LOCALS is a list of sequence locals made global to all frags.
902 ; Each element is (symbol <mode> "c-var-name").
903
904 (define (-gen-sfrag-code frag locals)
905   ; Indicate generating code for FRAG.
906   ; Use the compiled form if available.
907   ; The case when they're not available is for virtual insns.
908   (let ((sem (sfrag-compiled-semantics frag))
909         ; If the frag has one owner, use it.  Otherwise indicate the owner is
910         ; unknown.  In cases where the owner is needed by the semantics, the
911         ; frag should have only one owner.
912         (owner (if (= (length (sfrag-users frag)) 1)
913                    (car (sfrag-users frag))
914                    #f))
915         )
916     (if sem
917         (rtl-c++-parsed VOID sem locals
918                         #:rtl-cover-fns? #t
919                         #:owner owner)
920         (rtl-c++ VOID (sfrag-semantics frag) locals
921                  #:rtl-cover-fns? #t
922                  #:owner owner)))
923 )
924
925 ; Generate a switch case to perform FRAG.
926 ; LOCALS is a list of sequence locals made global to all frags.
927 ; Each element is (symbol <mode> "c-var-name").
928
929 (define (-gen-sfrag-case frag locals)
930   (set! -with-profile? -with-profile-sw?)
931   (let ((cti? (sfmt-cti? (sfrag-sfmt frag)))
932         (parallel? (sfrag-parallel? frag)))
933     (logit 2 "Processing "
934            (if parallel? "parallel " "")
935            "semantic switch case for \"" (obj:name frag) "\" ...\n")
936     (string-list
937      ; FRAG_ is prepended here and not elsewhere to avoid name collisions
938      ; with symbols like AND, etc.
939      "\
940 // ********** "
941      (if (= (length (sfrag-users frag)) 1)
942          "used only by:"
943          "used by:")
944      (string-drop1
945       (string-map (lambda (user)
946                     (string-append ", " (obj:str-name user)))
947                   (sfrag-users frag)))
948      "
949
950   CASE (FRAG_" (string-upcase (gen-sym frag)) "):
951     {\n"
952      (if (sfrag-header? frag)
953          (string-append "      abuf = vpc;\n"
954                         "      vpc = vpc + 1;\n")
955          "")
956      (gen-define-field-macro (sfrag-sfmt frag))
957      (if parallel?
958          (gen-define-parallel-operand-macro (sfrag-sfmt frag))
959          "")
960      ; Unconditionally written operands are not recorded here.
961      (if (or (with-profile?) (with-parallel-write?))
962          "      unsigned long long written = 0;\n"
963          "")
964      ; The address of this insn, needed by extraction and semantic code.
965      ; Note that the address recorded in the cpu state struct is not used.
966      "      PCADDR pc = abuf->addr;\n"
967      (if (and cti?
968               (not parallel?)
969               (sfrag-header? frag))
970          (string-append ; "      npc = 0;\n" ??? needed?
971           "      br_status = BRANCH_UNTAKEN;\n")
972          "")
973      ; Emit setup-semantics code for headers of real insns.
974      (if (and (sfrag-header? frag)
975               (not (obj-has-attr? frag 'VIRTUAL))
976               (isa-setup-semantics (current-isa)))
977          (string-append
978           "      "
979           (rtl-c++ VOID (isa-setup-semantics (current-isa)) nil
980                    #:rtl-cover-fns? #t
981                    #:owner #f))
982          "")
983      "\n"
984      (-gen-sfrag-code frag locals)
985      "\n"
986      ; Only update what's been written if some are conditionally written.
987      ; Otherwise we know they're all written so there's no point in
988      ; keeping track.
989      (if (or (with-profile?) (with-parallel-write?))
990          (if (-any-cond-written? (sfrag-sfmt frag))
991              "        abuf->written = written;\n"
992              "")
993          "")
994      (if (and cti?
995               (not parallel?)
996               (sfrag-trailer? frag))
997          (string-append "      pbb_br_npc = npc;\n"
998                         "      pbb_br_status = br_status;\n")
999          "")
1000      (if parallel?
1001          (gen-undef-parallel-operand-macro (sfrag-sfmt frag))
1002          "")
1003      (gen-undef-field-macro (sfrag-sfmt frag))
1004      "    }\n"
1005      (if (sfrag-trailer? frag)
1006          "    NEXT_INSN (vpc, fragpc);\n"
1007          "    NEXT_FRAG (fragpc);\n")
1008      "\n"
1009      ))
1010 )
1011
1012 ; Convert locals from form computed by sem-find-common-frags to that needed by
1013 ; -gen-sfrag-engine-code (and ultimately rtl-c++).
1014
1015 (define (-frag-convert-c-locals locals)
1016   (map (lambda (local)
1017          (list (car local) (mode:lookup (cadr local))
1018                (gen-c-symbol (car local))))
1019        locals)
1020 )
1021
1022 ; Return definition of insn frag usage table.
1023
1024 (define (-gen-sfrag-engine-frag-table insn-list frag-table frag-usage)
1025   (string-write
1026    "\
1027 // Table of frags used by each insn.
1028
1029 const @prefix@_insn_frag @prefix@_frag_usage[] = {\n"
1030
1031    (lambda ()
1032      (for-each (lambda (insn frag-nums)
1033                  (string-write "  { "
1034                                "@PREFIX@_INSN_"
1035                                (string-upcase (gen-sym insn))
1036                                (string-map (lambda (frag-num)
1037                                              (string-append ", @PREFIX@_FRAG_"
1038                                                             (string-upcase (gen-sym (vector-ref frag-table frag-num)))))
1039                                            frag-nums)
1040                                ", @PREFIX@_FRAG_LIST_END },\n"))
1041                insn-list frag-usage)
1042      "")
1043    "};\n\n")
1044 )
1045
1046 ; Return sfrag computed-goto engine.
1047 ; LOCALS is a list of sequence locals made global to all frags.
1048 ; Each element is (symbol <mode> "c-var-name").
1049
1050 (define (-gen-sfrag-engine-fn frag-table locals)
1051   (string-write
1052    "\
1053 void
1054 @cpu@_cpu::@prefix@_pbb_run ()
1055 {
1056   @cpu@_cpu* current_cpu = this;
1057   @prefix@_scache* vpc;
1058   @prefix@_scache* abuf;
1059 #ifdef __GNUC__
1060   void** fragpc;
1061 #else
1062   ARM_FRAG_TYPE* fragpc;
1063 #endif
1064
1065 #ifdef __GNUC__
1066 {
1067   static const @prefix@_pbb_label labels[] =
1068     {
1069       { @PREFIX@_FRAG_LIST_END, 0 },
1070 "
1071
1072    (lambda ()
1073      (string-write-map (lambda (frag)
1074                          (string-append "      { "
1075                                         "@PREFIX@_FRAG_"
1076                                         (string-upcase (gen-sym frag))
1077                                         ", && case_FRAG_"
1078                                         (string-upcase (gen-sym frag))
1079                                         " },\n"))
1080                        ; FIXME: vector->list
1081                        (vector->list frag-table)))
1082
1083    "\
1084       { @PREFIX@_FRAG_MAX, 0 }
1085     };
1086
1087   if (! @prefix@_idesc::idesc_table_initialized_p)
1088     {
1089       // Several tables are in play here:
1090       // idesc table: const table of misc things for each insn
1091       // frag usage table: const set of frags used by each insn
1092       // frag label table: same as frag usage table, but contains labels
1093       // selected insn frag table: table of pointers to either the frag usage
1094       // table (if !gnuc) or frag label table (if gnuc) for the currently
1095       // selected ISA.  Insns not in the ISA are redirected to the `invalid'
1096       // insn handler.  FIXME: This one isn't implemented yet.
1097
1098       // Allocate frag label table and point idesc table entries at it.
1099       // FIXME: Temporary hack, to be redone.
1100       static void** frag_label_table;
1101       int max_insns = @PREFIX@_INSN_" (-last-insn) " + 1;
1102       int tabsize = max_insns * 4;
1103       frag_label_table = new void* [tabsize];
1104       memset (frag_label_table, 0, sizeof (void*) * tabsize);
1105       int i;
1106       void** v;
1107       for (i = 0, v = frag_label_table; i < max_insns; ++i)
1108         {
1109           @prefix@_idesc::idesc_table[@prefix@_frag_usage[i].itype].cgoto.frags = v;
1110           for (int j = 0; @prefix@_frag_usage[i].ftype[j] != @PREFIX@_FRAG_LIST_END; ++j)
1111             *v++ = labels[@prefix@_frag_usage[i].ftype[j]].label;
1112         }
1113
1114       // Initialize the compiler virtual insn.
1115       // FIXME: Also needed if !gnuc.
1116       current_cpu->@prefix@_engine.compile_begin_insn (current_cpu);
1117
1118       @prefix@_idesc::idesc_table_initialized_p = true;
1119     }
1120 }
1121 #endif
1122
1123 #ifdef __GNUC__
1124 #define CASE(X) case_##X
1125 // Branch to next handler without going around main loop.
1126 #define NEXT_INSN(vpc, fragpc) fragpc = vpc->execute.cgoto.frags; goto * *fragpc
1127 #define NEXT_FRAG(fragpc) ++fragpc; goto * *fragpc
1128 // Break out of threaded interpreter and return to \"main loop\".
1129 #define BREAK(vpc) goto end_switch
1130 #else
1131 #define CASE(X) case @PREFIX@_##X
1132 #define NEXT_INSN(vpc, fragpc) fragpc = vpc->idesc->frags; goto restart
1133 #define NEXT_FRAG(fragpc) ++fragpc; goto restart
1134 #define BREAK(vpc) break
1135 #endif
1136
1137   // Get next insn to execute.
1138   vpc = current_cpu->@prefix@_engine.get_next_vpc (current_cpu->h_pc_get ());
1139
1140   {
1141     // These two are used to pass data from cti insns to the cti-chain insn.
1142     PCADDR pbb_br_npc;
1143     branch_status pbb_br_status;
1144     // These two are used to build up values of the previous two.
1145     PCADDR npc;
1146     branch_status br_status;
1147     // Top level locals moved here so they're usable by multiple fragments.
1148 "
1149
1150    (lambda ()
1151      (string-write-map (lambda (local)
1152                          (string-append "    "
1153                                         (mode:c-type (cadr local))
1154                                         " "
1155                                         (caddr local)
1156                                         ";\n"))
1157                        locals))
1158
1159    "\
1160
1161 restart:
1162 #ifdef __GNUC__
1163   fragpc = vpc->execute.cgoto.frags;
1164   goto * *fragpc;
1165 #else
1166   fragpc = vpc->idesc->frags;
1167   switch (*fragpc)
1168 #endif
1169
1170     {
1171
1172 "
1173
1174    (lambda ()
1175      ; Turn parallel execution support off.
1176      ; ??? Still needed?
1177      (set-with-parallel?! #f)
1178      (string-write-map (lambda (frag)
1179                          (-gen-sfrag-case frag locals))
1180                        ; FIXME: vector->list
1181                        (vector->list frag-table)))
1182
1183    "
1184 #ifdef __GNUC__
1185     end_switch: ;
1186 #else
1187     default: abort ();
1188 #endif
1189     }
1190   }
1191
1192   // Save vpc for next time.
1193   current_cpu->@prefix@_engine.set_next_vpc (vpc);
1194 }
1195 \n")
1196 )
1197
1198 (define (-gen-sfrag-engine)
1199   (string-write
1200    (lambda ()
1201      (-gen-sfrag-engine-frag-table (sim-sfrag-insn-list)
1202                                    (sim-sfrag-frag-table)
1203                                    (sim-sfrag-usage-table)))
1204    (lambda ()
1205      (-gen-sfrag-engine-fn (sim-sfrag-frag-table)
1206                            (-frag-convert-c-locals (sim-sfrag-locals-list))))
1207    )
1208 )
1209 \f
1210 ; Generate sem-switch.cxx.
1211
1212 (define (cgen-sem-switch.cxx)
1213   (logit 1 "Generating " (gen-cpu-name) " sem-switch.cxx ...\n")
1214
1215   (sim-analyze-insns!)
1216   (if (with-sem-frags?)
1217       (sim-sfrag-analyze-insns!))
1218
1219   ; Turn parallel execution support off.
1220   ; It is later turned on/off when generating the actual semantic code.
1221   (set-with-parallel?! #f)
1222
1223   ; Tell the rtx->c translator we are the simulator.
1224   (rtl-c-config! #:rtl-cover-fns? #t)
1225
1226   ; Indicate we're currently generating a pbb engine.
1227   (set-current-pbb-engine?! #t)
1228
1229   (string-write
1230    (gen-c-copyright "Simulator instruction semantics for @prefix@."
1231                   copyright-red-hat package-red-hat-simulators)
1232    "\
1233
1234 #include \"@cpu@.h\"
1235
1236 using namespace @cpu@; // FIXME: namespace organization still wip
1237
1238 #define GET_ATTR(name) GET_ATTR_##name ()
1239
1240 \n"
1241
1242    (if (with-sem-frags?)
1243        -gen-sfrag-engine-decls
1244        "")
1245
1246    (if (with-sem-frags?)
1247        -gen-sfrag-engine
1248        -gen-sem-switch-engine)
1249    )
1250 )