OSDN Git Service

* better support multiple-isa devices.
[pf3gnuchains/pf3gnuchains3x.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-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-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-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-copyright (string-append "Simulator instruction operand writer for "
476                                 (current-arch-name) ".")
477                  copyright-red-hat package-red-hat-simulators)
478    "\
479
480 #include \"@cpu@.h\"
481 using namespace @cpu@;
482
483 "
484    -gen-write-fns
485    )
486 )
487 \f
488 ; ******************
489 ; cgen-semantics.cxx
490
491 ; Return C code to perform the semantics of INSN.
492
493 (define (gen-semantic-code insn)
494   ; Indicate generating code for INSN.
495   ; Use the compiled form if available.
496   ; The case when they're not available is for virtual insns.
497   (let ((sem-c-code
498          (if (insn-compiled-semantics insn)
499              (rtl-c++-parsed VOID (insn-compiled-semantics insn) nil
500                              #:rtl-cover-fns? #t
501                              #:owner insn)
502              (rtl-c++ VOID (insn-semantics insn) nil
503                       #:rtl-cover-fns? #t
504                       #:owner insn)))
505         )
506     sem-c-code)
507 )
508
509 ; Return definition of C function to perform INSN.
510 ; This version handles the with-scache case.
511
512 (define (-gen-scache-semantic-fn insn)
513   (logit 2 "Processing semantics for " (obj:name insn) ": \"" (insn-syntax insn) "\" ...\n")
514   (set! -with-profile? -with-profile-fn?)
515   (let ((cti? (insn-cti? insn))
516         (insn-len (insn-length-bytes insn)))
517     (string-list
518      "// ********** " (obj:name insn) ": " (insn-syntax insn) "\n\n"
519      (if (with-parallel?)
520          "void\n"
521          "sem_status\n")
522      "@prefix@_sem_" (gen-sym insn)
523      (if (with-parallel?)
524          " (@cpu@_cpu* current_cpu, @prefix@_scache* sem, @prefix@_parexec* par_exec)\n"
525          " (@cpu@_cpu* current_cpu, @prefix@_scache* sem)\n")
526      "{\n"
527      (gen-define-field-macro (insn-sfmt insn))
528      (if (with-parallel?)
529          (gen-define-parallel-operand-macro (insn-sfmt insn))
530          "")
531      "  sem_status status = SEM_STATUS_NORMAL;\n"
532      "  @prefix@_scache* abuf = sem;\n"
533      ; Unconditionally written operands are not recorded here.
534      (if (or (with-profile?) (with-parallel-write?))
535          "  unsigned long long written = 0;\n"
536          "")
537      ; The address of this insn, needed by extraction and semantic code.
538      ; Note that the address recorded in the cpu state struct is not used.
539      ; For faster engines that copy will be out of date.
540      "  PCADDR pc = abuf->addr;\n"
541      "  PCADDR npc = pc + " (number->string insn-len) ";\n"
542      "\n"
543      (gen-semantic-code insn)
544      "\n"
545      ; Only update what's been written if some are conditionally written.
546      ; Otherwise we know they're all written so there's no point in
547      ; keeping track.
548      (if (or (with-profile?) (with-parallel-write?))
549          (if (-any-cond-written? (insn-sfmt insn))
550              "  abuf->written = written;\n"
551              "")
552          "")
553      (if cti?
554          "  current_cpu->done_cti_insn (npc, status);\n"
555          "  current_cpu->done_insn (npc, status);\n")
556      (if (with-parallel?)
557          ""
558          "  return status;\n")
559      (if (with-parallel?)
560          (gen-undef-parallel-operand-macro (insn-sfmt insn))
561          "")
562      (gen-undef-field-macro (insn-sfmt insn))
563      "}\n\n"
564      ))
565 )
566
567 (define (-gen-all-semantic-fns)
568   (logit 2 "Processing semantics ...\n")
569   (let ((insns (scache-engine-insns)))
570     (if (with-scache?)
571         (string-write-map -gen-scache-semantic-fn insns)
572         (error "must specify `with-scache'")))
573 )
574
575 ; Generate <cpu>-sem.cxx.
576 ; Each instruction is implemented in its own function.
577
578 (define (cgen-semantics.cxx)
579   (logit 1 "Generating " (gen-cpu-name) " semantics.cxx ...\n")
580   (assert-keep-one)
581
582   (sim-analyze-insns!)
583
584   ; Turn parallel execution support on if cpu needs it.
585   (set-with-parallel?! (state-parallel-exec?))
586
587   ; Tell the rtx->c translator we are the simulator.
588   (rtl-c-config! #:rtl-cover-fns? #t)
589
590   ; Indicate we're currently not generating a pbb engine.
591   (set-current-pbb-engine?! #f)
592
593   (string-write
594    (gen-copyright "Simulator instruction semantics for @prefix@."
595                   copyright-red-hat package-red-hat-simulators)
596    "\
597
598 #include \"@cpu@.h\"
599
600 using namespace @cpu@; // FIXME: namespace organization still wip
601
602 #define GET_ATTR(name) GET_ATTR_##name ()
603
604 \n"
605
606    -gen-all-semantic-fns
607    )
608 )
609 \f
610 ; *******************
611 ; cgen-sem-switch.cxx
612 ;
613 ; The semantic switch engine has two flavors: one case per insn, and one
614 ; case per "frag" (where each insn is split into one or more fragments).
615
616 ; Utility of -gen-sem-case to return the mask of operands always written
617 ; to in <sformat> SFMT.
618 ; ??? Not currently used.
619
620 (define (-uncond-written-mask sfmt)
621   (apply + (map (lambda (op)
622                   (if (op:cond? op)
623                       0
624                       (logsll 1 (op:num op))))
625                 (sfmt-out-ops sfmt)))
626 )
627
628 ; Utility of -gen-sem-case to return #t if any operand in <sformat> SFMT is
629 ; conditionally written to.
630
631 (define (-any-cond-written? sfmt)
632   (any-true? (map op:cond? (sfmt-out-ops sfmt)))
633 )
634 \f
635 ; One case per insn version.
636
637 ; Generate a switch case to perform INSN.
638
639 (define (-gen-sem-case insn parallel?)
640   (logit 2 "Processing "
641          (if parallel? "parallel " "")
642          "semantic switch case for \"" (insn-syntax insn) "\" ...\n")
643   (set! -with-profile? -with-profile-sw?)
644   (let ((cti? (insn-cti? insn))
645         (insn-len (insn-length-bytes insn)))
646     (string-list
647      ; INSN_ is prepended here and not elsewhere to avoid name collisions
648      ; with symbols like AND, etc.
649      "\
650 // ********** " (insn-syntax insn) "
651
652   CASE (INSN_" (if parallel? "PAR_" "") (string-upcase (gen-sym insn)) "):
653     {
654       @prefix@_scache* abuf = vpc;\n"
655      (if (with-scache?)
656          (gen-define-field-macro (insn-sfmt insn))
657          "")
658      (if parallel?
659          (gen-define-parallel-operand-macro (insn-sfmt insn))
660          "")
661      ; Unconditionally written operands are not recorded here.
662      (if (or (with-profile?) (with-parallel-write?))
663          "      unsigned long long written = 0;\n"
664          "")
665      ; The address of this insn, needed by extraction and semantic code.
666      ; Note that the address recorded in the cpu state struct is not used.
667      "      PCADDR pc = abuf->addr;\n"
668      (if (and cti? (not parallel?))
669          (string-append "      PCADDR npc;\n"
670                         "      branch_status br_status = BRANCH_UNTAKEN;\n")
671          "")
672      (string-list "      vpc = vpc + 1;\n")
673      ; Emit setup-semantics code for real insns.
674      (if (and (insn-real? insn)
675               (isa-setup-semantics (current-isa)))
676          (string-append
677           "      "
678           (rtl-c++ VOID (isa-setup-semantics (current-isa)) nil
679                    #:rtl-cover-fns? #t
680                    #:owner insn))
681          "")
682      "\n"
683      (gen-semantic-code insn)
684      "\n"
685      ; Only update what's been written if some are conditionally written.
686      ; Otherwise we know they're all written so there's no point in
687      ; keeping track.
688      (if (or (with-profile?) (with-parallel-write?))
689          (if (-any-cond-written? (insn-sfmt insn))
690              "        abuf->written = written;\n"
691              "")
692          "")
693      (if (and cti? (not parallel?))
694          (string-append "      pbb_br_npc = npc;\n"
695                         "      pbb_br_status = br_status;\n")
696          "")
697      (if parallel?
698          (gen-undef-parallel-operand-macro (insn-sfmt insn))
699          "")
700      (if (with-scache?)
701          (gen-undef-field-macro (insn-sfmt insn))
702          "")
703      "    }\n"
704      "    NEXT (vpc);\n\n"
705      ))
706 )
707
708 (define (-gen-sem-switch)
709   (logit 2 "Processing semantic switch ...\n")
710   ; Turn parallel execution support off.
711   (set-with-parallel?! #f)
712   (string-write-map (lambda (insn) (-gen-sem-case insn #f))
713                     (non-multi-insns (non-alias-insns (current-insn-list))))
714 )
715
716 ; Generate the guts of a C switch statement to execute parallel instructions.
717 ; This switch is included after the non-parallel instructions in the semantic
718 ; switch.
719 ;
720 ; ??? We duplicate the writeback case for each insn, even though we only need
721 ; one case per insn format.  The former keeps the code for each insn
722 ; together and might improve cache usage.  On the other hand the latter
723 ; reduces the amount of code, though it is believed that in this particular
724 ; instance the win isn't big enough.
725
726 (define (-gen-parallel-sem-switch)
727   (logit 2 "Processing parallel insn semantic switch ...\n")
728   ; Turn parallel execution support on.
729   (set-with-parallel?! #t)
730   (string-write-map (lambda (insn)
731                       (string-list (-gen-sem-case insn #t)
732                                    (-gen-write-case (insn-sfmt insn) insn)))
733                     (parallel-insns (current-insn-list)))
734 )
735
736 ; Return computed-goto engine.
737
738 (define (-gen-sem-switch-engine)
739   (string-write
740    "\
741 void
742 @cpu@_cpu::@prefix@_pbb_run ()
743 {
744   @cpu@_cpu* current_cpu = this;
745   @prefix@_scache* vpc;
746   // These two are used to pass data from cti insns to the cti-chain insn.
747   PCADDR pbb_br_npc;
748   branch_status pbb_br_status;
749
750 #ifdef __GNUC__
751 {
752   static const struct sem_labels
753     {
754       enum @prefix@_insn_type insn;
755       void *label;
756     }
757   labels[] = 
758     {\n"
759
760    (lambda ()
761      (string-write-map (lambda (insn)
762                          (string-append "      { "
763                                         "@PREFIX@_INSN_"
764                                         (string-upcase (gen-sym insn))
765                                         ", && case_INSN_"
766                                         (string-upcase (gen-sym insn))
767                                         " },\n"))
768                        (non-multi-insns (non-alias-insns (current-insn-list)))))
769
770    (if (state-parallel-exec?)
771        (lambda ()
772          (string-write-map (lambda (insn)
773                              (string-append "      { "
774                                             "@PREFIX@_INSN_PAR_"
775                                             (string-upcase (gen-sym insn))
776                                             ", && case_INSN_PAR_"
777                                             (string-upcase (gen-sym insn))
778                                             " },\n"
779                                             "      { "
780                                             "@PREFIX@_INSN_WRITE_"
781                                             (string-upcase (gen-sym insn))
782                                             ", && case_INSN_WRITE_"
783                                             (string-upcase (gen-sym insn))
784                                             " },\n"))
785                            (parallel-insns (current-insn-list))))
786        "")
787
788    "    { (@prefix@_insn_type) 0, 0 }
789   };
790
791   if (! @prefix@_idesc::idesc_table_initialized_p)
792     {
793       for (int i=0; labels[i].label != 0; i++)
794         @prefix@_idesc::idesc_table[labels[i].insn].cgoto.label = labels[i].label; 
795
796       // confirm that table is all filled up
797       for (int i = 0; i <= @PREFIX@_INSN_" (-last-insn) "; i++)
798         assert (@prefix@_idesc::idesc_table[i].cgoto.label != 0);
799
800       // Initialize the compiler virtual insn.
801       current_cpu->@prefix@_engine.compile_begin_insn (current_cpu);
802
803       @prefix@_idesc::idesc_table_initialized_p = true;
804     }
805 }
806 #endif
807
808 #ifdef __GNUC__
809 #define CASE(X) case_##X
810 // Branch to next handler without going around main loop.
811 #define NEXT(vpc) goto * vpc->execute.cgoto.label;
812 // Break out of threaded interpreter and return to \"main loop\".
813 #define BREAK(vpc) goto end_switch
814 #else
815 #define CASE(X) case @PREFIX@_##X
816 #define NEXT(vpc) goto restart
817 #define BREAK(vpc) break
818 #endif
819
820   // Get next insn to execute.
821   vpc = current_cpu->@prefix@_engine.get_next_vpc (current_cpu->h_pc_get ());
822
823 restart:
824 #ifdef __GNUC__
825   goto * vpc->execute.cgoto.label;
826 #else
827   switch (vpc->idesc->sem_index)
828 #endif
829
830   {
831 "
832
833   -gen-sem-switch
834
835    (if (state-parallel-exec?)
836        -gen-parallel-sem-switch
837        "")
838
839 "
840 #ifdef __GNUC__
841     end_switch: ;
842 #else
843     default: abort();
844 #endif
845   }
846
847   // Save vpc for next time.
848   current_cpu->@prefix@_engine.set_next_vpc (vpc);
849 }
850 \n"
851    )
852 )
853 \f
854 ; Semantic frag version.
855
856 ; Return declaration of frag enum.
857
858 (define (-gen-sfrag-enum-decl frag-list)
859   (gen-enum-decl "@prefix@_frag_type"
860                  "semantic fragments in cpu family @prefix@"
861                  "@PREFIX@_FRAG_"
862                  (append '((list-end))
863                          (map (lambda (i)
864                                 (cons (obj:name i)
865                                       (cons '-
866                                             (atlist-attrs (obj-atlist i)))))
867                               frag-list)
868                          '((max))))
869 )
870
871 ; Return header file decls for semantic frag threaded engine.
872
873 (define (-gen-sfrag-engine-decls)
874   (string-write
875    "namespace @cpu@ {\n\n"
876
877    ; FIXME: vector->list
878    (-gen-sfrag-enum-decl (vector->list (sim-sfrag-frag-table)))
879
880    "\
881 struct @prefix@_insn_frag {
882   @PREFIX@_INSN_TYPE itype;
883   // 4: header+middle+trailer+delimiter
884   @PREFIX@_FRAG_TYPE ftype[4];
885 };
886
887 struct @prefix@_pbb_label {
888   @PREFIX@_FRAG_TYPE frag;
889   void *label;
890 };
891
892 } // end @cpu@ namespace
893 \n")
894 )
895
896 ; Return C code to perform the semantics of FRAG.
897 ; LOCALS is a list of sequence locals made global to all frags.
898 ; Each element is (symbol <mode> "c-var-name").
899
900 (define (-gen-sfrag-code frag locals)
901   ; Indicate generating code for FRAG.
902   ; Use the compiled form if available.
903   ; The case when they're not available is for virtual insns.
904   (let ((sem (sfrag-compiled-semantics frag))
905         ; If the frag has one owner, use it.  Otherwise indicate the owner is
906         ; unknown.  In cases where the owner is needed by the semantics, the
907         ; frag should have only one owner.
908         (owner (if (= (length (sfrag-users frag)) 1)
909                    (car (sfrag-users frag))
910                    #f))
911         )
912     (if sem
913         (rtl-c++-parsed VOID sem locals
914                         #:rtl-cover-fns? #t
915                         #:owner owner)
916         (rtl-c++ VOID (sfrag-semantics frag) locals
917                  #:rtl-cover-fns? #t
918                  #:owner owner)))
919 )
920
921 ; Generate a switch case to perform FRAG.
922 ; LOCALS is a list of sequence locals made global to all frags.
923 ; Each element is (symbol <mode> "c-var-name").
924
925 (define (-gen-sfrag-case frag locals)
926   (set! -with-profile? -with-profile-sw?)
927   (let ((cti? (sfmt-cti? (sfrag-sfmt frag)))
928         (parallel? (sfrag-parallel? frag)))
929     (logit 2 "Processing "
930            (if parallel? "parallel " "")
931            "semantic switch case for \"" (obj:name frag) "\" ...\n")
932     (string-list
933      ; FRAG_ is prepended here and not elsewhere to avoid name collisions
934      ; with symbols like AND, etc.
935      "\
936 // ********** "
937      (if (= (length (sfrag-users frag)) 1)
938          "used only by:"
939          "used by:")
940      (string-drop1
941       (string-map (lambda (user)
942                     (string-append ", " (obj:name user)))
943                   (sfrag-users frag)))
944      "
945
946   CASE (FRAG_" (string-upcase (gen-sym frag)) "):
947     {\n"
948      (if (sfrag-header? frag)
949          (string-append "      abuf = vpc;\n"
950                         "      vpc = vpc + 1;\n")
951          "")
952      (gen-define-field-macro (sfrag-sfmt frag))
953      (if parallel?
954          (gen-define-parallel-operand-macro (sfrag-sfmt frag))
955          "")
956      ; Unconditionally written operands are not recorded here.
957      (if (or (with-profile?) (with-parallel-write?))
958          "      unsigned long long written = 0;\n"
959          "")
960      ; The address of this insn, needed by extraction and semantic code.
961      ; Note that the address recorded in the cpu state struct is not used.
962      "      PCADDR pc = abuf->addr;\n"
963      (if (and cti?
964               (not parallel?)
965               (sfrag-header? frag))
966          (string-append ; "      npc = 0;\n" ??? needed?
967           "      br_status = BRANCH_UNTAKEN;\n")
968          "")
969      ; Emit setup-semantics code for headers of real insns.
970      (if (and (sfrag-header? frag)
971               (not (obj-has-attr? frag 'VIRTUAL))
972               (isa-setup-semantics (current-isa)))
973          (string-append
974           "      "
975           (rtl-c++ VOID (isa-setup-semantics (current-isa)) nil
976                    #:rtl-cover-fns? #t
977                    #:owner #f))
978          "")
979      "\n"
980      (-gen-sfrag-code frag locals)
981      "\n"
982      ; Only update what's been written if some are conditionally written.
983      ; Otherwise we know they're all written so there's no point in
984      ; keeping track.
985      (if (or (with-profile?) (with-parallel-write?))
986          (if (-any-cond-written? (sfrag-sfmt frag))
987              "        abuf->written = written;\n"
988              "")
989          "")
990      (if (and cti?
991               (not parallel?)
992               (sfrag-trailer? frag))
993          (string-append "      pbb_br_npc = npc;\n"
994                         "      pbb_br_status = br_status;\n")
995          "")
996      (if parallel?
997          (gen-undef-parallel-operand-macro (sfrag-sfmt frag))
998          "")
999      (gen-undef-field-macro (sfrag-sfmt frag))
1000      "    }\n"
1001      (if (sfrag-trailer? frag)
1002          "    NEXT_INSN (vpc, fragpc);\n"
1003          "    NEXT_FRAG (fragpc);\n")
1004      "\n"
1005      ))
1006 )
1007
1008 ; Convert locals from form computed by sem-find-common-frags to that needed by
1009 ; -gen-sfrag-engine-code (and ultimately rtl-c++).
1010
1011 (define (-frag-convert-c-locals locals)
1012   (map (lambda (local)
1013          (list (car local) (mode:lookup (cadr local))
1014                (gen-c-symbol (car local))))
1015        locals)
1016 )
1017
1018 ; Return definition of insn frag usage table.
1019
1020 (define (-gen-sfrag-engine-frag-table insn-list frag-table frag-usage)
1021   (string-write
1022    "\
1023 // Table of frags used by each insn.
1024
1025 const @prefix@_insn_frag @prefix@_frag_usage[] = {\n"
1026
1027    (lambda ()
1028      (for-each (lambda (insn frag-nums)
1029                  (string-write "  { "
1030                                "@PREFIX@_INSN_"
1031                                (string-upcase (gen-sym insn))
1032                                (string-map (lambda (frag-num)
1033                                              (string-append ", @PREFIX@_FRAG_"
1034                                                             (string-upcase (gen-sym (vector-ref frag-table frag-num)))))
1035                                            frag-nums)
1036                                ", @PREFIX@_FRAG_LIST_END },\n"))
1037                insn-list frag-usage)
1038      "")
1039    "};\n\n")
1040 )
1041
1042 ; Return sfrag computed-goto engine.
1043 ; LOCALS is a list of sequence locals made global to all frags.
1044 ; Each element is (symbol <mode> "c-var-name").
1045
1046 (define (-gen-sfrag-engine-fn frag-table locals)
1047   (string-write
1048    "\
1049 void
1050 @cpu@_cpu::@prefix@_pbb_run ()
1051 {
1052   @cpu@_cpu* current_cpu = this;
1053   @prefix@_scache* vpc;
1054   @prefix@_scache* abuf;
1055 #ifdef __GNUC__
1056   void** fragpc;
1057 #else
1058   ARM_FRAG_TYPE* fragpc;
1059 #endif
1060
1061 #ifdef __GNUC__
1062 {
1063   static const @prefix@_pbb_label labels[] =
1064     {
1065       { @PREFIX@_FRAG_LIST_END, 0 },
1066 "
1067
1068    (lambda ()
1069      (string-write-map (lambda (frag)
1070                          (string-append "      { "
1071                                         "@PREFIX@_FRAG_"
1072                                         (string-upcase (gen-sym frag))
1073                                         ", && case_FRAG_"
1074                                         (string-upcase (gen-sym frag))
1075                                         " },\n"))
1076                        ; FIXME: vector->list
1077                        (vector->list frag-table)))
1078
1079    "\
1080       { @PREFIX@_FRAG_MAX, 0 }
1081     };
1082
1083   if (! @prefix@_idesc::idesc_table_initialized_p)
1084     {
1085       // Several tables are in play here:
1086       // idesc table: const table of misc things for each insn
1087       // frag usage table: const set of frags used by each insn
1088       // frag label table: same as frag usage table, but contains labels
1089       // selected insn frag table: table of pointers to either the frag usage
1090       // table (if !gnuc) or frag label table (if gnuc) for the currently
1091       // selected ISA.  Insns not in the ISA are redirected to the `invalid'
1092       // insn handler.  FIXME: This one isn't implemented yet.
1093
1094       // Allocate frag label table and point idesc table entries at it.
1095       // FIXME: Temporary hack, to be redone.
1096       static void** frag_label_table;
1097       int max_insns = @PREFIX@_INSN_" (-last-insn) " + 1;
1098       int tabsize = max_insns * 4;
1099       frag_label_table = new (void*) [tabsize];
1100       memset (frag_label_table, 0, sizeof (void*) * tabsize);
1101       int i;
1102       void** v;
1103       for (i = 0, v = frag_label_table; i < max_insns; ++i)
1104         {
1105           @prefix@_idesc::idesc_table[@prefix@_frag_usage[i].itype].cgoto.frags = v;
1106           for (int j = 0; @prefix@_frag_usage[i].ftype[j] != @PREFIX@_FRAG_LIST_END; ++j)
1107             *v++ = labels[@prefix@_frag_usage[i].ftype[j]].label;
1108         }
1109
1110       // Initialize the compiler virtual insn.
1111       // FIXME: Also needed if !gnuc.
1112       current_cpu->@prefix@_engine.compile_begin_insn (current_cpu);
1113
1114       @prefix@_idesc::idesc_table_initialized_p = true;
1115     }
1116 }
1117 #endif
1118
1119 #ifdef __GNUC__
1120 #define CASE(X) case_##X
1121 // Branch to next handler without going around main loop.
1122 #define NEXT_INSN(vpc, fragpc) fragpc = vpc->execute.cgoto.frags; goto * *fragpc
1123 #define NEXT_FRAG(fragpc) ++fragpc; goto * *fragpc
1124 // Break out of threaded interpreter and return to \"main loop\".
1125 #define BREAK(vpc) goto end_switch
1126 #else
1127 #define CASE(X) case @PREFIX@_##X
1128 #define NEXT_INSN(vpc, fragpc) fragpc = vpc->idesc->frags; goto restart
1129 #define NEXT_FRAG(fragpc) ++fragpc; goto restart
1130 #define BREAK(vpc) break
1131 #endif
1132
1133   // Get next insn to execute.
1134   vpc = current_cpu->@prefix@_engine.get_next_vpc (current_cpu->h_pc_get ());
1135
1136   {
1137     // These two are used to pass data from cti insns to the cti-chain insn.
1138     PCADDR pbb_br_npc;
1139     branch_status pbb_br_status;
1140     // These two are used to build up values of the previous two.
1141     PCADDR npc;
1142     branch_status br_status;
1143     // Top level locals moved here so they're usable by multiple fragments.
1144 "
1145
1146    (lambda ()
1147      (string-write-map (lambda (local)
1148                          (string-append "    "
1149                                         (mode:c-type (cadr local))
1150                                         " "
1151                                         (caddr local)
1152                                         ";\n"))
1153                        locals))
1154
1155    "\
1156
1157 restart:
1158 #ifdef __GNUC__
1159   fragpc = vpc->execute.cgoto.frags;
1160   goto * *fragpc;
1161 #else
1162   fragpc = vpc->idesc->frags;
1163   switch (*fragpc)
1164 #endif
1165
1166     {
1167
1168 "
1169
1170    (lambda ()
1171      ; Turn parallel execution support off.
1172      ; ??? Still needed?
1173      (set-with-parallel?! #f)
1174      (string-write-map (lambda (frag)
1175                          (-gen-sfrag-case frag locals))
1176                        ; FIXME: vector->list
1177                        (vector->list frag-table)))
1178
1179    "
1180 #ifdef __GNUC__
1181     end_switch: ;
1182 #else
1183     default: abort ();
1184 #endif
1185     }
1186   }
1187
1188   // Save vpc for next time.
1189   current_cpu->@prefix@_engine.set_next_vpc (vpc);
1190 }
1191 \n")
1192 )
1193
1194 (define (-gen-sfrag-engine)
1195   (string-write
1196    (lambda ()
1197      (-gen-sfrag-engine-frag-table (sim-sfrag-insn-list)
1198                                    (sim-sfrag-frag-table)
1199                                    (sim-sfrag-usage-table)))
1200    (lambda ()
1201      (-gen-sfrag-engine-fn (sim-sfrag-frag-table)
1202                            (-frag-convert-c-locals (sim-sfrag-locals-list))))
1203    )
1204 )
1205 \f
1206 ; Generate sem-switch.cxx.
1207
1208 (define (cgen-sem-switch.cxx)
1209   (logit 1 "Generating " (gen-cpu-name) " sem-switch.cxx ...\n")
1210
1211   (sim-analyze-insns!)
1212   (if (with-sem-frags?)
1213       (sim-sfrag-analyze-insns!))
1214
1215   ; Turn parallel execution support off.
1216   ; It is later turned on/off when generating the actual semantic code.
1217   (set-with-parallel?! #f)
1218
1219   ; Tell the rtx->c translator we are the simulator.
1220   (rtl-c-config! #:rtl-cover-fns? #t)
1221
1222   ; Indicate we're currently generating a pbb engine.
1223   (set-current-pbb-engine?! #t)
1224
1225   (string-write
1226    (gen-copyright "Simulator instruction semantics for @prefix@."
1227                   copyright-red-hat package-red-hat-simulators)
1228    "\
1229
1230 #include \"@cpu@.h\"
1231
1232 using namespace @cpu@; // FIXME: namespace organization still wip
1233
1234 #define GET_ATTR(name) GET_ATTR_##name ()
1235
1236 \n"
1237
1238    (if (with-sem-frags?)
1239        -gen-sfrag-engine-decls
1240        "")
1241
1242    (if (with-sem-frags?)
1243        -gen-sfrag-engine
1244        -gen-sem-switch-engine)
1245    )
1246 )