OSDN Git Service

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