OSDN Git Service

tweak last entry
[pf3gnuchains/pf3gnuchains3x.git] / cgen / sid-cpu.scm
1 ; CPU family related simulator generator, excluding decoding and model support.
2 ; Copyright (C) 2000, 2002, 2003, 2005, 2006, 2009 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 #include \"opcode/cgen-bitset.h\"
84
85 namespace @arch@ {
86 \n"
87
88    "// Enums.\n\n"
89    (lambda () (string-map gen-decl (current-enum-list)))
90
91    /gen-attr-decls
92    /gen-insn-attr-decls
93    /gen-mach-params
94
95    "
96 } // end @arch@ namespace
97
98 #endif /* DESC_@ARCH@_H */\n"
99    )
100 )
101 \f
102 ; **********
103 ; cgen-cpu.h
104
105 ; Print out file containing elements to add to cpu class.
106
107 ; Get/set fns for hardware element HW.
108
109 (define (/gen-reg-access-defns hw)
110   (let ((scalar? (hw-scalar? hw))
111         (name (obj:name hw))
112         (getter (hw-getter hw))
113         (setter (hw-setter hw))
114         (isas (bitset-attr->list (obj-attr-value hw 'ISA)))
115         (type (gen-type hw)))
116     (let ((get-code (if getter
117                         (let ((mode (hw-mode hw))
118                               (args (car getter))
119                               (expr (cadr getter)))
120                           (string-append
121                            "return "
122                            (rtl-c++ mode expr
123                                     (if scalar?
124                                         nil
125                                         (list (list (car args) 'UINT "regno")))
126                                     #:rtl-cover-fns? #t)
127                            ";"))
128                         (string-append
129                          "return this->hardware."
130                          (gen-c-symbol name)
131                          (if scalar? "" "[regno]")
132                          ";")))
133           (set-code (if setter
134                         (let ((args (car setter))
135                               (expr (cadr setter)))
136                           (rtl-c++
137                            VOID ; not `mode', sets have mode VOID
138                            expr
139                            (if scalar?
140                                (list (list (car args) (hw-mode hw) "newval"))
141                                (list (list (car args) 'UINT "regno")
142                                      (list (cadr args) (hw-mode hw) "newval")))
143                            #:rtl-cover-fns? #t))
144                         (string-append
145                          "this->hardware."
146                          (gen-c-symbol name)
147                          (if scalar? "" "[regno]")
148                          " = newval;"))))
149       (string-append
150        "  inline " type " "
151        (gen-reg-get-fun-name hw)
152        " ("
153        (if scalar? "" "UINT regno")
154        ") const"
155        " { " get-code " }"
156        "\n"
157        "  inline void "
158        (gen-reg-set-fun-name hw)
159        " ("
160        (if scalar? "" "UINT regno, ")
161        type " newval)"
162        " { " set-code " }"
163        "\n\n")))
164 )
165
166 ; Return a boolean indicating if hardware element HW needs storage allocated
167 ; for it in the SIM_CPU struct.
168
169 (define (hw-need-storage? hw)
170   (and (register? hw)
171        (not (obj-has-attr? hw 'VIRTUAL)))
172 )
173
174 (define (hw-need-write-stack? hw)
175   (and (register? hw) (hw-used-in-delay-rtl? hw))
176 )
177
178 ; Subroutine of /gen-hardware-types to generate the struct containing
179 ; hardware elements of one isa.
180
181 (define (/gen-hardware-struct prefix hw-list)
182   (if (null? hw-list)
183       ; If struct is empty, leave it out to simplify generated code.
184       ""
185       (string-list
186        (if prefix
187            (string-append "  // Hardware elements for " prefix ".\n")
188            "  // Hardware elements.\n")
189        "  struct {\n"
190        (string-list-map gen-decl hw-list)
191        "  } "
192        (if prefix
193            (string-append prefix "_")
194            "")
195        "hardware;\n\n"
196        ))
197 )
198
199 ; Return C type declarations of all of the hardware elements.
200 ; The name of the type is prepended with the cpu family name.
201
202 (define (/gen-hardware-types)
203   (string-list
204    "// CPU state information.\n\n"
205    (/gen-hardware-struct #f (find hw-need-storage? (current-hw-list))))
206 )
207
208 (define (/gen-hw-stream-and-destream-fns) 
209   (let* ((sa string-append)
210          (regs (find hw-need-storage? (current-hw-list)))
211          (stack-regs (find hw-need-write-stack? (current-hw-list)))
212          (reg-dim (lambda (r) 
213                     (let ((dims (/hw-vector-dims r)))
214                       (if (equal? 0 (length dims)) 
215                           "0"
216                           (number->string (car dims))))))
217          (write-stacks 
218           (map (lambda (n) (sa n "_writes"))
219                (append (map (lambda (r) (gen-c-symbol (obj:name r))) stack-regs)
220                        (map (lambda (m) (sa (symbol->string m) "_memory")) write-stack-memory-mode-names))))
221          (stream-reg (lambda (r) 
222                        (let ((rname (sa "hardware." (gen-c-symbol (obj:name r)))))
223                          (if (hw-scalar? r)
224                              (sa "    ost << " rname " << ' ';\n")
225                              (sa "    for (int i = 0; i < " (reg-dim r) 
226                                  "; i++)\n      ost << " rname "[i] << ' ';\n")))))
227          (destream-reg (lambda (r) 
228                          (let ((rname (sa "hardware." (gen-c-symbol (obj:name r)))))
229                            (if (hw-scalar? r)
230                                (sa "    ist >> " rname ";\n")
231                                (sa "    for (int i = 0; i < " (reg-dim r) 
232                                    "; i++)\n      ist >> " rname "[i];\n")))))
233          (stream-stacks (lambda (s) (sa "    stream_stacks ( stacks." s ", ost);\n")))
234          (destream-stacks (lambda (s) (sa "    destream_stacks ( stacks." s ", ist);\n")))
235          (stack-boilerplate
236           (sa
237            "  template <typename ST> \n"
238            "  void stream_stacks (const ST &st, std::ostream &ost) const\n"
239            "  {\n"
240            "    for (int i = 0; i < @prefix@::pipe_sz; i++)\n"
241            "    {\n"
242            "      ost << st[i].t << ' ';\n"
243            "      for (int j = 0; j <= st[i].t; j++)\n"
244            "      {\n"
245            "        ost << st[i].buf[j].pc << ' ';\n"
246            "        ost << st[i].buf[j].val << ' ';\n"
247            "        ost << st[i].buf[j].idx0 << ' ';\n"
248            "      }\n"
249            "    }\n"
250            "  }\n"
251            "  \n"
252            "  template <typename ST> \n"
253            "  void destream_stacks (ST &st, std::istream &ist)\n"
254            "  {\n"
255            "    for (int i = 0; i < @prefix@::pipe_sz; i++)\n"
256            "    {\n"
257            "      ist >> st[i].t;\n"
258            "      for (int j = 0; j <= st[i].t; j++)\n"
259            "      {\n"
260            "        ist >> st[i].buf[j].pc;\n"
261            "        ist >> st[i].buf[j].val;\n"
262            "        ist >> st[i].buf[j].idx0;\n"
263            "      }\n"
264            "    }\n"
265            "  }\n"
266            "  \n")))
267     (sa
268      "  void stream_cgen_hardware (std::ostream &ost) const \n  {\n"
269      (string-map stream-reg regs)
270      "  }\n"
271      "  void destream_cgen_hardware (std::istream &ist) \n  {\n"
272      (string-map destream-reg regs)
273      "  }\n"
274      (if (with-parallel?) 
275          (sa stack-boilerplate
276              "  void stream_cgen_write_stacks (std::ostream &ost, "
277              "const @prefix@::write_stacks &stacks) const \n  {\n"
278              (string-map stream-stacks write-stacks)
279              "  }\n"
280              "  void destream_cgen_write_stacks (std::istream &ist, "
281              "@prefix@::write_stacks &stacks) \n  {\n"
282              (string-map destream-stacks write-stacks)
283              "  }\n")
284          ""))))
285
286
287 ; Generate <cpu>-cpu.h
288
289 (define (cgen-cpu.h)
290   (logit 1 "Generating " (gen-cpu-name) "-cpu.h ...\n")
291   (assert-keep-one)
292
293   ; Turn parallel execution support on if cpu needs it.
294   (set-with-parallel?! (state-parallel-exec?))
295
296   ; Initialize rtl->c generation.
297   (rtl-c-config! #:rtl-cover-fns? #t)
298
299   (string-write
300    (gen-c-copyright "CPU class elements for @cpu@."
301                   copyright-red-hat package-red-hat-simulators)
302    "\
303 // This file is included in the middle of the cpu class struct.
304
305 public:
306 \n"
307
308    /gen-hardware-types
309
310    /gen-hw-stream-and-destream-fns
311
312    "  // C++ register access function templates\n"
313    "#define current_cpu this\n\n"
314    (lambda ()
315      (string-list-map /gen-reg-access-defns
316                       (find register? (current-hw-list))))
317    "#undef current_cpu\n\n"
318    )
319 )
320 \f
321 ; **********
322 ; cgen-defs.h
323
324 ; Print various parameters of the cpu family.
325 ; A "cpu family" here is a collection of variants of a particular architecture
326 ; that share sufficient commonality that they can be handled together.
327
328 (define (/gen-cpu-defines)
329   (string-append
330    "\
331 /* Maximum number of instructions that are fetched at a time.
332    This is for LIW type instructions sets (e.g. m32r).  */\n"
333    "#define @CPU@_MAX_LIW_INSNS " (number->string (cpu-liw-insns (current-cpu))) "\n\n"
334    "/* Maximum number of instructions that can be executed in parallel.  */\n"
335    "#define @CPU@_MAX_PARALLEL_INSNS " (number->string (cpu-parallel-insns (current-cpu))) "\n"
336    "\n"
337 ;   (gen-enum-decl '@prefix@_virtual
338 ;                 "@prefix@ virtual insns"
339 ;                 "@ARCH@_INSN_" ; not @CPU@ to match CGEN_INSN_TYPE in opc.h
340 ;                 '((x-invalid 0)
341 ;                   (x-before -1) (x-after -2)
342 ;                   (x-begin -3) (x-chain -4) (x-cti-chain -5)))
343    )
344 )
345
346 ; Generate type of struct holding model state while executing.
347
348 (define (/gen-model-decls)
349   (logit 2 "Generating model decls ...\n")
350   (string-list
351    (string-list-map
352     (lambda (model)
353       (string-list
354        "typedef struct {\n"
355        (if (null? (model:state model))
356            "  int empty;\n"
357            (string-map (lambda (var)
358                          (string-append "  "
359                                         (mode:c-type (mode:lookup (cadr var)))
360                                         " "
361                                         (gen-c-symbol (car var))
362                                         ";\n"))
363                        (model:state model)))
364        "} " 
365        (if (null? (model:state model)) "BLANK" "@CPU@") "_MODEL_DATA;\n\n"
366        ))
367     (current-model-list))
368    "   
369 typedef int (@CPU@_MODEL_FN) (struct @cpu@_cpu*, void*);
370
371 typedef struct {
372   /* This is an integer that identifies this insn.
373      How this works is up to the target.  */
374   int num;
375
376   /* Function to handle insn-specific profiling.  */
377   @CPU@_MODEL_FN *model_fn;
378
379   /* Array of function units used by this insn.  */
380   UNIT units[MAX_UNITS];
381 } @CPU@_INSN_TIMING;"
382    )
383 )
384
385 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
386 ;;; begin stack-based write schedule
387 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
388
389 (define write-stack-memory-mode-names '())
390
391 (define (/calculated-memory-write-buffer-size)
392   (let* ((is-mem? (lambda (op) (eq? (hw-sem-name (op:type op)) 'h-memory)))
393          (count-mem-writes
394           (lambda (sfmt) (length (find is-mem? (sfmt-out-ops sfmt))))))
395     (apply max (append '(0) (map count-mem-writes (current-sfmt-list))))))
396
397
398 ;; note: this doesn't really correctly approximate the worst case. user-supplied functions
399 ;; might rewrite the pipeline extensively while it's running. 
400 ;(define (/worst-case-number-of-writes-to hw-name)
401 ;  (let* ((sfmts (current-sfmt-list))
402 ;        (out-ops (map sfmt-out-ops sfmts))
403 ;        (pred (lambda (op) (equal? hw-name (gen-c-symbol (obj:name (op:type op))))))
404 ;        (filtered-ops (map (lambda (ops) (find pred ops)) out-ops)))
405 ;    (apply max (cons 0 (map (lambda (ops) (length ops)) filtered-ops)))))
406          
407 (define (/hw-gen-write-stack-decl nm mode)
408   (let* (
409 ; for the time being, we're disabling this size-estimation stuff and just
410 ; requiring the user to supply a parameter WRITE_BUF_SZ before they include -defs.h
411 ;        (pipe-sz (+ 1 (max-delay (cpu-max-delay (current-cpu)))))
412 ;        (sz (* pipe-sz (/worst-case-number-of-writes-to nm))))
413          
414          (mode-pad (spaces (- 4 (string-length (symbol->string mode)))))
415          (stack-name (string-append nm "_writes")))
416     (string-append
417      "  write_stack< write<" (symbol->string mode) "> >" mode-pad "\t" stack-name "\t[pipe_sz];\n")))
418
419
420 (define (/hw-gen-write-struct-decl)
421   (let* ((dims (/worst-case-index-dims))
422          (sa string-append)
423          (ns number->string)
424          (idxs (iota dims))
425          (ctor (sa "write (PCADDR _pc, MODE _val"
426                    (string-map (lambda (x) (sa ", USI _idx" (ns x) "=0")) idxs)
427                    ") : pc(_pc), val(_val)"
428                    (string-map (lambda (x) (sa ", idx" (ns x) "(_idx" (ns x) ")")) idxs)
429                    " {} \n"))
430          (idx-fields (string-map (lambda (x) (sa "    USI idx" (ns x) ";\n")) idxs)))
431     (sa
432      "\n\n"
433      "  template <typename MODE>\n"
434      "  struct write\n"
435      "  {\n"
436      "    USI pc;\n"
437      "    MODE val;\n"
438      idx-fields
439      "    " ctor 
440      "    write() {}\n"
441      "  };\n" )))
442                
443 (define (/hw-vector-dims hw) (elm-get (hw-type hw) 'dimensions))                            
444 (define (/worst-case-index-dims)
445   (apply max
446          (append '(1) ; for memory accesses
447                  (map (lambda (hw) (length (/hw-vector-dims hw))) 
448                       (find (lambda (hw) (not (scalar? hw))) (current-hw-list))))))
449
450
451 (define (/gen-writestacks)
452   (let* ((hw (find hw-need-write-stack? (current-hw-list)))
453          (modes write-stack-memory-mode-names) 
454          (hw-pairs (map (lambda (h) (list (gen-c-symbol (obj:name h))
455                                             (obj:name (hw-mode h)))) 
456                         hw))
457          (mem-pairs (map (lambda (m) (list (string-append (symbol->string m)
458                                                           "_memory") m)) 
459                          modes))
460          (all-pairs (append mem-pairs hw-pairs))
461
462          (h1 "\n\n// write stacks used in parallel execution\n\n  struct write_stacks\n  {\n  // types of stacks\n\n")
463          (wb (string-append
464               "\n\n  // unified writeback function (defined in @prefix@-write.cc)"
465                 "\n  void writeback (int tick, @cpu@::@cpu@_cpu* current_cpu);"
466                 "\n  // unified write-stack clearing function (defined in @prefix@-write.cc)"
467                 "\n  void reset ();"))
468          (zz "\n\n  }; // end struct @prefix@::write_stacks \n\n"))    
469     (string-append      
470      (/hw-gen-write-struct-decl)
471      (foldl (lambda (s pair) (string-append s (apply /hw-gen-write-stack-decl pair))) h1 all-pairs)       
472      wb
473      zz)))
474
475 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
476 ;;; end stack-based write schedule
477 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
478           
479
480 ; Generate the definition of the structure that holds register values, etc.
481 ; for use during parallel execution.  
482
483 (define (gen-write-stack-structure)
484   (let ((membuf-sz (/calculated-memory-write-buffer-size))
485         (max-delay (cpu-max-delay (current-cpu))))
486     (logit 2 "Generating write stack structure ...\n")
487     (string-append
488      "  static const int max_delay = "   
489      (number->string max-delay) ";\n"
490      "  static const int pipe_sz = "     
491      (number->string (+ 1 max-delay)) "; // max_delay + 1\n"
492
493 "
494   template <typename ELT> 
495   struct write_stack 
496   {
497     int t;
498     const int sz;
499     ELT buf[WRITE_BUF_SZ];
500
501     write_stack       ()             : t(-1), sz(WRITE_BUF_SZ) {}
502     inline bool empty ()             { return (t == -1); }
503     inline void clear ()             { t = -1; }
504     inline void pop   ()             { if (t > -1) t--;}
505     inline void push  (const ELT &e) { if (t+1 < sz) buf [++t] = e;}
506     inline ELT &top   ()             { return buf [t>0 ? ( t<sz ? t : sz-1) : 0];}
507   };
508
509   // look ahead for latest write with index = idx, where time of write is
510   // <= dist steps from base (present) in write_stack array st.
511   // returning def if no scheduled write is found.
512
513   template <typename STKS, typename VAL>
514   inline VAL lookahead (int dist, int base, STKS &st, VAL def, int idx=0)
515   {
516     for (; dist > 0; --dist)
517     {
518       write_stack <VAL> &v = st [(base + dist) % pipe_sz];
519       for (int i = v.t; i > 0; --i) 
520           if (v.buf [i].idx0 == idx) return v.buf [i];
521     }
522     return def;
523   }
524
525 "
526  
527      (/gen-writestacks)     
528      )))
529
530 ; Generate the TRACE_RECORD struct definition.
531
532 (define (/gen-trace-record-type)
533   (string-list
534    "\
535 /* Collection of various things for the trace handler to use.  */
536
537 typedef struct @prefix@_trace_record {
538   PCADDR pc;
539   /* FIXME:wip */
540 } @CPU@_TRACE_RECORD;
541 \n"
542    )
543 )
544
545 ; Generate <cpu>-defs.h
546
547 (define (cgen-defs.h)
548   (logit 1 "Generating " (gen-cpu-name) "-defs.h ...\n")
549   (assert-keep-one)
550
551   ; Turn parallel execution support on if cpu needs it.
552   (set-with-parallel?! (state-parallel-exec?))
553
554   ; Initialize rtl->c generation.
555   (rtl-c-config! #:rtl-cover-fns? #t)
556
557   (string-write
558    (gen-c-copyright "CPU family header for @cpu@ / @prefix@."
559                   copyright-red-hat package-red-hat-simulators)
560    "\
561 #ifndef DEFS_@PREFIX@_H
562 #define DEFS_@PREFIX@_H
563
564 ")
565    (if (with-parallel?)
566        (string-write "\
567 #include <stack>
568 #include \"cgen-types.h\"
569
570 // forward declaration\n\n  
571 namespace @cpu@ {
572 struct @cpu@_cpu;
573 }
574
575 namespace @prefix@ {
576
577 using namespace cgen;
578
579 "
580                      gen-write-stack-structure
581                      "\
582 } // end @prefix@ namespace
583 "))
584    (string-write "\
585
586 #endif /* DEFS_@PREFIX@_H */\n"
587    )
588 )
589 \f
590 ; **************
591 ; cgen-write.cxx
592
593 ; This is the other way of implementing parallel execution support.
594 ; Instead of fetching all the input operands first, write all the output
595 ; operands and their addresses to holding variables, and then run a
596 ; post-processing pass to update the cpu state.
597
598 ; Return C code to fetch and save all output operands to instructions with
599 ; <sformat> SFMT.
600
601
602 ; Generate <cpu>-write.cxx.
603
604 (define (/gen-register-writer nm mode dims)
605   (let* ((pad "    ")
606          (sa string-append)
607          (mode (symbol->string mode))
608          (idx-args (string-map (lambda (x) (sa "w.idx" (number->string x) ", ")) 
609                                (iota dims))))
610     (sa pad "while (! " nm "_writes[tick].empty())\n"
611         pad "{\n"
612         pad "  write<" mode "> &w = " nm "_writes[tick].top();\n"
613         pad "  current_cpu->" nm "_set(" idx-args "w.val);\n"
614         pad "  " nm "_writes[tick].pop();\n"
615         pad "}\n\n")))
616
617 (define (/gen-memory-writer nm mode dims)
618   (let* ((pad "    ")
619          (sa string-append)
620          (mode (symbol->string mode))
621          (idx-args (string-map (lambda (x) (sa ", w.idx" (number->string x) "")) 
622                                (iota dims))))
623     (sa pad "while (! " nm "_writes[tick].empty())\n"
624         pad "{\n"
625         pad "  write<" mode "> &w = " nm "_writes[tick].top();\n"
626         pad "  current_cpu->SETMEM" mode " (w.pc" idx-args ", w.val);\n"
627         pad "  " nm "_writes[tick].pop();\n"
628         pad "}\n\n")))
629
630
631 (define (/gen-reset-fn)
632   (let* ((sa string-append)
633          (objs (append (map (lambda (h) (gen-c-symbol (obj:name h))) 
634                             (find hw-need-write-stack? (current-hw-list)))
635                        (map (lambda (m) (sa (symbol->string m) "_memory"))
636                             write-stack-memory-mode-names)))
637          (clr (lambda (elt) (sa "    clear_stacks (" elt "_writes);\n"))))
638     (sa 
639      "  template <typename ST> \n"
640      "  static void clear_stacks (ST &st)\n"
641      "  {\n"
642      "    for (int i = 0; i < @prefix@::pipe_sz; i++)\n"
643      "      st[i].clear();\n"
644      "  }\n\n"
645      "  void @prefix@::write_stacks::reset ()\n  {\n"
646      (string-map clr objs)
647      "  }")))
648
649 (define (/gen-unified-write-fn) 
650   (let* ((hw (find hw-need-write-stack? (current-hw-list)))
651          (modes write-stack-memory-mode-names)  
652          (hw-triples (map (lambda (h) (list (gen-c-symbol (obj:name h))
653                                             (obj:name (hw-mode h))
654                                             (length (/hw-vector-dims h)))) 
655                         hw))
656          (mem-triples (map (lambda (m) (list (string-append (symbol->string m)
657                                                             "_memory")
658                                              m 1)) 
659                          modes)))
660     (logit 2 "Generating writer function ...\n") 
661     (string-append
662      "
663   void @prefix@::write_stacks::writeback (int tick, @cpu@::@cpu@_cpu* current_cpu) 
664   {
665 "
666      "\n    // register writeback loops\n"
667      (string-map (lambda (t) (apply /gen-register-writer t)) hw-triples)
668      "\n    // memory writeback loops\n"
669      (string-map (lambda (t) (apply /gen-memory-writer t)) mem-triples)
670 "
671   }
672 ")))
673
674 (define (cgen-write.cxx)
675   (logit 1 "Generating " (gen-cpu-name) "-write.cxx ...\n")
676   (assert-keep-one)
677
678   (sim-analyze-insns!)
679
680   ; Turn parallel execution support off.
681   (set-with-parallel?! #f)
682
683   ; Tell the rtx->c translator we are the simulator.
684   (rtl-c-config! #:rtl-cover-fns? #t)
685
686   (string-write
687    (gen-c-copyright (string-append "Simulator instruction operand writer for "
688                                    (symbol->string (current-arch-name))
689                                    ".")
690                  copyright-red-hat package-red-hat-simulators)
691    "\
692
693 #include \"@cpu@.h\"
694
695 "
696    /gen-reset-fn
697    /gen-unified-write-fn
698    )
699 )
700 \f
701 ; ******************
702 ; cgen-semantics.cxx
703
704 ; Return C code to perform the semantics of INSN.
705
706 (define (gen-semantic-code insn)
707   ; Indicate generating code for INSN.
708   ; Use the canonical form if available.
709   ; The case when they're not available is for virtual insns. (??? Still true?)
710   (cond ((insn-compiled-semantics insn)
711          => (lambda (sem)
712               (rtl-c++-parsed VOID sem nil
713                               #:for-insn? #t
714                               #:rtl-cover-fns? #t
715                               #:owner insn)))
716         ((insn-canonical-semantics insn)
717          => (lambda (sem)
718               (rtl-c++-parsed VOID sem nil
719                               #:for-insn? #t
720                               #:rtl-cover-fns? #t
721                               #:owner insn)))
722         (else
723          (rtl-c++ VOID (insn-semantics insn) nil
724                   #:for-insn? #t
725                   #:rtl-cover-fns? #t
726                   #:owner insn)))
727 )
728
729 ; Return definition of C function to perform INSN.
730 ; This version handles the with-scache case.
731
732 (define (/gen-scache-semantic-fn insn)
733   (logit 2 "Processing semantics for " (obj:name insn) ": \"" (insn-syntax insn) "\" ...\n")
734   (set! /with-profile? /with-profile-fn?)
735   (let ((cti? (insn-cti? insn))
736         (insn-len (insn-length-bytes insn)))
737     (string-list
738      "// ********** " (obj:name insn) ": " (insn-syntax insn) "\n\n"
739      (if (with-parallel?)
740          "void\n"
741          "sem_status\n")
742      "@prefix@_sem_" (gen-sym insn)
743      (if (with-parallel?)
744          (string-append " (@cpu@_cpu* current_cpu, @prefix@_scache* sem, const int tick, \n\t"
745                         "@prefix@::write_stacks &buf)\n")
746          " (@cpu@_cpu* current_cpu, @prefix@_scache* sem)\n")
747      "{\n"
748      (gen-define-field-macro (insn-sfmt insn))
749      "  sem_status status = SEM_STATUS_NORMAL;\n"
750      "  @prefix@_scache* abuf = sem;\n"
751      ; Unconditionally written operands are not recorded here.
752      (if (or (with-profile?) (with-parallel-write?))
753          "  unsigned long long written = 0;\n"
754          "")
755      ; The address of this insn, needed by extraction and semantic code.
756      ; Note that the address recorded in the cpu state struct is not used.
757      ; For faster engines that copy will be out of date.
758      "  PCADDR pc = abuf->addr;\n"
759      "  PCADDR npc = pc + " (number->string insn-len) ";\n"
760      "\n"
761      (gen-semantic-code insn)
762      "\n"
763      ; Only update what's been written if some are conditionally written.
764      ; Otherwise we know they're all written so there's no point in
765      ; keeping track.
766      (if (or (with-profile?) (with-parallel-write?))
767          (if (/any-cond-written? (insn-sfmt insn))
768              "  abuf->written = written;\n"
769              "")
770          "")
771      (if cti?
772          "  current_cpu->done_cti_insn (npc, status);\n"
773          "  current_cpu->done_insn (npc, status);\n")
774      (if (with-parallel?)
775          ""
776          "  return status;\n")
777      (gen-undef-field-macro (insn-sfmt insn))
778       "}\n\n"
779      ))
780 )
781
782 (define (/gen-all-semantic-fns)
783   (logit 2 "Processing semantics ...\n")
784   (let ((insns (scache-engine-insns)))
785     (if (with-scache?)
786         (string-write-map /gen-scache-semantic-fn insns)
787         (error "must specify `with-scache'")))
788 )
789
790 ; Generate <cpu>-sem.cxx.
791 ; Each instruction is implemented in its own function.
792
793 (define (cgen-semantics.cxx)
794   (logit 1 "Generating " (gen-cpu-name) "-semantics.cxx ...\n")
795   (assert-keep-one)
796
797   (sim-analyze-insns!)
798
799   ; Turn parallel execution support on if cpu needs it.
800   (set-with-parallel?! (state-parallel-exec?))
801
802   ; Tell the rtx->c translator we are the simulator.
803   (rtl-c-config! #:rtl-cover-fns? #t)
804
805   ; Indicate we're currently not generating a pbb engine.
806   (set-current-pbb-engine?! #f)
807
808   (string-write
809    (gen-c-copyright "Simulator instruction semantics for @prefix@."
810                   copyright-red-hat package-red-hat-simulators)
811    "\
812
813 #if HAVE_CONFIG_H
814 #include \"config.h\"
815 #endif
816 #include \"@cpu@.h\"
817
818 using namespace @cpu@; // FIXME: namespace organization still wip\n")
819   (if (with-parallel?)
820       (string-write "\
821 using namespace @prefix@; // FIXME: namespace organization still wip\n"))
822   (string-write "\
823 #define GET_ATTR(name) GET_ATTR_##name ()
824
825 \n"
826
827    /gen-all-semantic-fns
828    )
829 )
830 \f
831 ; *******************
832 ; cgen-sem-switch.cxx
833 ;
834 ; The semantic switch engine has two flavors: one case per insn, and one
835 ; case per "frag" (where each insn is split into one or more fragments).
836
837 ; Utility of /gen-sem-case to return the mask of operands always written
838 ; to in <sformat> SFMT.
839 ; ??? Not currently used.
840
841 (define (/uncond-written-mask sfmt)
842   (apply + (map (lambda (op)
843                   (if (op:cond? op)
844                       0
845                       (logsll 1 (op:num op))))
846                 (sfmt-out-ops sfmt)))
847 )
848
849 ; Utility of /gen-sem-case to return #t if any operand in <sformat> SFMT is
850 ; conditionally written to.
851
852 (define (/any-cond-written? sfmt)
853   (any-true? (map op:cond? (sfmt-out-ops sfmt)))
854 )
855 \f
856 ; One case per insn version.
857
858 ; Generate a switch case to perform INSN.
859
860 (define (/gen-sem-case insn parallel?)
861   (logit 2 "Processing "
862          (if parallel? "parallel " "")
863          "semantic switch case for \"" (insn-syntax insn) "\" ...\n")
864   (set! /with-profile? /with-profile-sw?)
865   (let ((cti? (insn-cti? insn))
866         (insn-len (insn-length-bytes insn)))
867     (string-list
868      ; INSN_ is prepended here and not elsewhere to avoid name collisions
869      ; with symbols like AND, etc.
870      "\
871 // ********** " (insn-syntax insn) "
872
873   CASE (INSN_" (if parallel? "PAR_" "") (string-upcase (gen-sym insn)) "):
874     {
875       @prefix@_scache* abuf = vpc;\n"
876      (if (with-scache?)
877          (gen-define-field-macro (insn-sfmt insn))
878          "")
879      ; Unconditionally written operands are not recorded here.
880      (if (or (with-profile?) (with-parallel-write?))
881          "      unsigned long long written = 0;\n"
882          "")
883      ; The address of this insn, needed by extraction and semantic code.
884      ; Note that the address recorded in the cpu state struct is not used.
885      "      PCADDR pc = abuf->addr;\n"
886      (if (and cti? (not parallel?))
887          (string-append "      PCADDR npc;\n"
888                         "      branch_status br_status = BRANCH_UNTAKEN;\n")
889          "")
890      (string-list "      vpc = vpc + 1;\n")
891      ; Emit setup-semantics code for real insns.
892      (if (and (insn-real? insn)
893               (isa-setup-semantics (current-isa)))
894          (string-append
895           "      "
896           (rtl-c++ VOID (isa-setup-semantics (current-isa)) nil
897                    #:for-insn? #t
898                    #:rtl-cover-fns? #t
899                    #:owner insn))
900          "")
901      "\n"
902      (gen-semantic-code insn)
903      "\n"
904      ; Only update what's been written if some are conditionally written.
905      ; Otherwise we know they're all written so there's no point in
906      ; keeping track.
907      (if (or (with-profile?) (with-parallel-write?))
908          (if (/any-cond-written? (insn-sfmt insn))
909              "        abuf->written = written;\n"
910              "")
911          "")
912      (if (and cti? (not parallel?))
913          (string-append "      pbb_br_npc = npc;\n"
914                         "      pbb_br_status = br_status;\n")
915          "")
916      (if (with-scache?)
917          (gen-undef-field-macro (insn-sfmt insn))
918          "")
919      "    }\n"
920      "    NEXT (vpc);\n\n"
921      ))
922 )
923
924 (define (/gen-sem-switch)
925   (logit 2 "Processing semantic switch ...\n")
926   ; Turn parallel execution support off.
927   (set-with-parallel?! #f)
928   (string-write-map (lambda (insn) (/gen-sem-case insn #f))
929                     (non-multi-insns (non-alias-insns (current-insn-list))))
930 )
931
932 ; Generate the guts of a C switch statement to execute parallel instructions.
933 ; This switch is included after the non-parallel instructions in the semantic
934 ; switch.
935 ;
936 ; ??? We duplicate the writeback case for each insn, even though we only need
937 ; one case per insn format.  The former keeps the code for each insn
938 ; together and might improve cache usage.  On the other hand the latter
939 ; reduces the amount of code, though it is believed that in this particular
940 ; instance the win isn't big enough.
941
942 (define (/gen-parallel-sem-switch)
943   (logit 2 "Processing parallel insn semantic switch ...\n")
944   ; Turn parallel execution support on.
945   (set-with-parallel?! #t)
946   (string-write-map (lambda (insn)
947                       (string-list (/gen-sem-case insn #t)
948                                    (/gen-write-case (insn-sfmt insn) insn)))
949                     (parallel-insns (current-insn-list)))
950 )
951
952 ; Return computed-goto engine.
953
954 (define (/gen-sem-switch-engine)
955   (string-write
956    "\
957 void
958 @cpu@_cpu::@prefix@_pbb_run ()
959 {
960   @cpu@_cpu* current_cpu = this;
961   @prefix@_scache* vpc;
962   // These two are used to pass data from cti insns to the cti-chain insn.
963   PCADDR pbb_br_npc;
964   branch_status pbb_br_status;
965
966 #ifdef __GNUC__
967 {
968   static const struct sem_labels
969     {
970       enum @prefix@_insn_type insn;
971       void *label;
972     }
973   labels[] = 
974     {\n"
975
976    (lambda ()
977      (string-write-map (lambda (insn)
978                          (string-append "      { "
979                                         "@PREFIX@_INSN_"
980                                         (string-upcase (gen-sym insn))
981                                         ", && case_INSN_"
982                                         (string-upcase (gen-sym insn))
983                                         " },\n"))
984                        (non-multi-insns (non-alias-insns (current-insn-list)))))
985
986    (if (state-parallel-exec?)
987        (lambda ()
988          (string-write-map (lambda (insn)
989                              (string-append "      { "
990                                             "@PREFIX@_INSN_PAR_"
991                                             (string-upcase (gen-sym insn))
992                                             ", && case_INSN_PAR_"
993                                             (string-upcase (gen-sym insn))
994                                             " },\n"
995                                             "      { "
996                                             "@PREFIX@_INSN_WRITE_"
997                                             (string-upcase (gen-sym insn))
998                                             ", && case_INSN_WRITE_"
999                                             (string-upcase (gen-sym insn))
1000                                             " },\n"))
1001                            (parallel-insns (current-insn-list))))
1002        "")
1003
1004    "    { (@prefix@_insn_type) 0, 0 }
1005   };
1006
1007   if (! @prefix@_idesc::idesc_table_initialized_p)
1008     {
1009       for (int i=0; labels[i].label != 0; i++)
1010         @prefix@_idesc::idesc_table[labels[i].insn].cgoto.label = labels[i].label; 
1011
1012       // confirm that table is all filled up
1013       for (int i = 0; i <= @PREFIX@_INSN_" (/last-insn) "; i++)
1014         assert (@prefix@_idesc::idesc_table[i].cgoto.label != 0);
1015
1016       // Initialize the compiler virtual insn.
1017       current_cpu->@prefix@_engine.compile_begin_insn (current_cpu);
1018
1019       @prefix@_idesc::idesc_table_initialized_p = true;
1020     }
1021 }
1022 #endif
1023
1024 #ifdef __GNUC__
1025 #define CASE(X) case_##X
1026 // Branch to next handler without going around main loop.
1027 #define NEXT(vpc) goto * vpc->execute.cgoto.label;
1028 // Break out of threaded interpreter and return to \"main loop\".
1029 #define BREAK(vpc) goto end_switch
1030 #else
1031 #define CASE(X) case @PREFIX@_##X
1032 #define NEXT(vpc) goto restart
1033 #define BREAK(vpc) break
1034 #endif
1035
1036   // Get next insn to execute.
1037   vpc = current_cpu->@prefix@_engine.get_next_vpc (current_cpu->h_pc_get ());
1038
1039 restart:
1040 #ifdef __GNUC__
1041   goto * vpc->execute.cgoto.label;
1042 #else
1043   switch (vpc->idesc->sem_index)
1044 #endif
1045
1046   {
1047 "
1048
1049   /gen-sem-switch
1050
1051    (if (state-parallel-exec?)
1052        /gen-parallel-sem-switch
1053        "")
1054
1055 "
1056 #ifdef __GNUC__
1057     end_switch: ;
1058 #else
1059     default: abort();
1060 #endif
1061   }
1062
1063   // Save vpc for next time.
1064   current_cpu->@prefix@_engine.set_next_vpc (vpc);
1065 }
1066 \n"
1067    )
1068 )
1069 \f
1070 ; Semantic frag version.
1071
1072 ; Return declaration of frag enum.
1073
1074 (define (/gen-sfrag-enum-decl frag-list)
1075   (gen-enum-decl "@prefix@_frag_type"
1076                  "semantic fragments in cpu family @prefix@"
1077                  "@PREFIX@_FRAG_"
1078                  (append '((list-end))
1079                          (map (lambda (i)
1080                                 (cons (obj:name i)
1081                                       (cons '-
1082                                             (atlist-attrs (obj-atlist i)))))
1083                               frag-list)
1084                          '((max))))
1085 )
1086
1087 ; Return header file decls for semantic frag threaded engine.
1088
1089 (define (/gen-sfrag-engine-decls)
1090   (string-write
1091    "namespace @cpu@ {\n\n"
1092
1093    ; FIXME: vector->list
1094    (/gen-sfrag-enum-decl (vector->list (sim-sfrag-frag-table)))
1095
1096    "\
1097 struct @prefix@_insn_frag {
1098   @PREFIX@_INSN_TYPE itype;
1099   // 4: header+middle+trailer+delimiter
1100   @PREFIX@_FRAG_TYPE ftype[4];
1101 };
1102
1103 struct @prefix@_pbb_label {
1104   @PREFIX@_FRAG_TYPE frag;
1105   void *label;
1106 };
1107
1108 } // end @cpu@ namespace
1109 \n")
1110 )
1111
1112 ; Return C code to perform the semantics of FRAG.
1113 ; LOCALS is a list of sequence locals made global to all frags.
1114 ; Each element is (symbol <mode> "c-var-name").
1115
1116 (define (/gen-sfrag-code frag locals)
1117   ; Indicate generating code for FRAG.
1118   ; Use the compiled form if available.
1119   ; The case when they're not available is for virtual insns.
1120   (let ((sem (sfrag-compiled-semantics frag))
1121         ; If the frag has one owner, use it.  Otherwise indicate the owner is
1122         ; unknown.  In cases where the owner is needed by the semantics, the
1123         ; frag should have only one owner.  In practice this means that frags
1124         ; with the ref,current-insn rtx cannot be used by multiple insns.
1125         (owner (if (= (length (sfrag-users frag)) 1)
1126                    (car (sfrag-users frag))
1127                    #f))
1128         )
1129     (if sem
1130         (rtl-c++-parsed VOID sem locals
1131                         #:for-insn? #t
1132                         #:rtl-cover-fns? #t
1133                         #:owner owner)
1134         (rtl-c++ VOID (sfrag-semantics frag) locals
1135                  #:for-insn? #t
1136                  #:rtl-cover-fns? #t
1137                  #:owner owner)))
1138 )
1139
1140 ; Generate a switch case to perform FRAG.
1141 ; LOCALS is a list of sequence locals made global to all frags.
1142 ; Each element is (symbol <mode> "c-var-name").
1143
1144 (define (/gen-sfrag-case frag locals)
1145   (set! /with-profile? /with-profile-sw?)
1146   (let ((cti? (sfmt-cti? (sfrag-sfmt frag)))
1147         (parallel? (sfrag-parallel? frag)))
1148     (logit 2 "Processing "
1149            (if parallel? "parallel " "")
1150            "semantic switch case for \"" (obj:name frag) "\" ...\n")
1151     (string-list
1152      ; FRAG_ is prepended here and not elsewhere to avoid name collisions
1153      ; with symbols like AND, etc.
1154      "\
1155 // ********** "
1156      (if (= (length (sfrag-users frag)) 1)
1157          "used only by:"
1158          "used by:")
1159      (string-drop1
1160       (string-map (lambda (user)
1161                     (string-append ", " (obj:str-name user)))
1162                   (sfrag-users frag)))
1163      "
1164
1165   CASE (FRAG_" (string-upcase (gen-sym frag)) "):
1166     {\n"
1167      (if (sfrag-header? frag)
1168          (string-append "      abuf = vpc;\n"
1169                         "      vpc = vpc + 1;\n")
1170          "")
1171      (gen-define-field-macro (sfrag-sfmt frag))
1172      ; Unconditionally written operands are not recorded here.
1173      (if (or (with-profile?) (with-parallel-write?))
1174          "      unsigned long long written = 0;\n"
1175          "")
1176      ; The address of this insn, needed by extraction and semantic code.
1177      ; Note that the address recorded in the cpu state struct is not used.
1178      "      PCADDR pc = abuf->addr;\n"
1179      (if (and cti?
1180               (not parallel?)
1181               (sfrag-header? frag))
1182          (string-append ; "      npc = 0;\n" ??? needed?
1183           "      br_status = BRANCH_UNTAKEN;\n")
1184          "")
1185      ; Emit setup-semantics code for headers of real insns.
1186      (if (and (sfrag-header? frag)
1187               (not (obj-has-attr? frag 'VIRTUAL))
1188               (isa-setup-semantics (current-isa)))
1189          (string-append
1190           "      "
1191           (rtl-c++ VOID (isa-setup-semantics (current-isa)) nil
1192                    #:rtl-cover-fns? #t
1193                    #:owner #f))
1194          "")
1195      "\n"
1196      (/gen-sfrag-code frag locals)
1197      "\n"
1198      ; Only update what's been written if some are conditionally written.
1199      ; Otherwise we know they're all written so there's no point in
1200      ; keeping track.
1201      (if (or (with-profile?) (with-parallel-write?))
1202          (if (/any-cond-written? (sfrag-sfmt frag))
1203              "        abuf->written = written;\n"
1204              "")
1205          "")
1206      (if (and cti?
1207               (not parallel?)
1208               (sfrag-trailer? frag))
1209          (string-append "      pbb_br_npc = npc;\n"
1210                         "      pbb_br_status = br_status;\n")
1211          "")
1212      (gen-undef-field-macro (sfrag-sfmt frag))
1213      "    }\n"
1214      (if (sfrag-trailer? frag)
1215          "    NEXT_INSN (vpc, fragpc);\n"
1216          "    NEXT_FRAG (fragpc);\n")
1217      "\n"
1218      ))
1219 )
1220
1221 ; Convert locals from form computed by sem-find-common-frags to that needed by
1222 ; /gen-sfrag-engine-code (and ultimately rtl-c++).
1223
1224 (define (/frag-convert-c-locals locals)
1225   (map (lambda (local)
1226          (list (car local) (mode:lookup (cadr local))
1227                (gen-c-symbol (car local))))
1228        locals)
1229 )
1230
1231 ; Return definition of insn frag usage table.
1232
1233 (define (/gen-sfrag-engine-frag-table insn-list frag-table frag-usage)
1234   (string-write
1235    "\
1236 // Table of frags used by each insn.
1237
1238 const @prefix@_insn_frag @prefix@_frag_usage[] = {\n"
1239
1240    (lambda ()
1241      (for-each (lambda (insn frag-nums)
1242                  (string-write "  { "
1243                                "@PREFIX@_INSN_"
1244                                (string-upcase (gen-sym insn))
1245                                (string-map (lambda (frag-num)
1246                                              (string-append ", @PREFIX@_FRAG_"
1247                                                             (string-upcase (gen-sym (vector-ref frag-table frag-num)))))
1248                                            frag-nums)
1249                                ", @PREFIX@_FRAG_LIST_END },\n"))
1250                insn-list frag-usage)
1251      "")
1252    "};\n\n")
1253 )
1254
1255 ; Return sfrag computed-goto engine.
1256 ; LOCALS is a list of sequence locals made global to all frags.
1257 ; Each element is (symbol <mode> "c-var-name").
1258
1259 (define (/gen-sfrag-engine-fn frag-table locals)
1260   (string-write
1261    "\
1262 void
1263 @cpu@_cpu::@prefix@_pbb_run ()
1264 {
1265   @cpu@_cpu* current_cpu = this;
1266   @prefix@_scache* vpc;
1267   @prefix@_scache* abuf;
1268 #ifdef __GNUC__
1269   void** fragpc;
1270 #else
1271   ARM_FRAG_TYPE* fragpc;
1272 #endif
1273
1274 #ifdef __GNUC__
1275 {
1276   static const @prefix@_pbb_label labels[] =
1277     {
1278       { @PREFIX@_FRAG_LIST_END, 0 },
1279 "
1280
1281    (lambda ()
1282      (string-write-map (lambda (frag)
1283                          (string-append "      { "
1284                                         "@PREFIX@_FRAG_"
1285                                         (string-upcase (gen-sym frag))
1286                                         ", && case_FRAG_"
1287                                         (string-upcase (gen-sym frag))
1288                                         " },\n"))
1289                        ; FIXME: vector->list
1290                        (vector->list frag-table)))
1291
1292    "\
1293       { @PREFIX@_FRAG_MAX, 0 }
1294     };
1295
1296   if (! @prefix@_idesc::idesc_table_initialized_p)
1297     {
1298       // Several tables are in play here:
1299       // idesc table: const table of misc things for each insn
1300       // frag usage table: const set of frags used by each insn
1301       // frag label table: same as frag usage table, but contains labels
1302       // selected insn frag table: table of pointers to either the frag usage
1303       // table (if !gnuc) or frag label table (if gnuc) for the currently
1304       // selected ISA.  Insns not in the ISA are redirected to the `invalid'
1305       // insn handler.  FIXME: This one isn't implemented yet.
1306
1307       // Allocate frag label table and point idesc table entries at it.
1308       // FIXME: Temporary hack, to be redone.
1309       static void** frag_label_table;
1310       int max_insns = @PREFIX@_INSN_" (/last-insn) " + 1;
1311       int tabsize = max_insns * 4;
1312       frag_label_table = new void* [tabsize];
1313       memset (frag_label_table, 0, sizeof (void*) * tabsize);
1314       int i;
1315       void** v;
1316       for (i = 0, v = frag_label_table; i < max_insns; ++i)
1317         {
1318           @prefix@_idesc::idesc_table[@prefix@_frag_usage[i].itype].cgoto.frags = v;
1319           for (int j = 0; @prefix@_frag_usage[i].ftype[j] != @PREFIX@_FRAG_LIST_END; ++j)
1320             *v++ = labels[@prefix@_frag_usage[i].ftype[j]].label;
1321         }
1322
1323       // Initialize the compiler virtual insn.
1324       // FIXME: Also needed if !gnuc.
1325       current_cpu->@prefix@_engine.compile_begin_insn (current_cpu);
1326
1327       @prefix@_idesc::idesc_table_initialized_p = true;
1328     }
1329 }
1330 #endif
1331
1332 #ifdef __GNUC__
1333 #define CASE(X) case_##X
1334 // Branch to next handler without going around main loop.
1335 #define NEXT_INSN(vpc, fragpc) fragpc = vpc->execute.cgoto.frags; goto * *fragpc
1336 #define NEXT_FRAG(fragpc) ++fragpc; goto * *fragpc
1337 // Break out of threaded interpreter and return to \"main loop\".
1338 #define BREAK(vpc) goto end_switch
1339 #else
1340 #define CASE(X) case @PREFIX@_##X
1341 #define NEXT_INSN(vpc, fragpc) fragpc = vpc->idesc->frags; goto restart
1342 #define NEXT_FRAG(fragpc) ++fragpc; goto restart
1343 #define BREAK(vpc) break
1344 #endif
1345
1346   // Get next insn to execute.
1347   vpc = current_cpu->@prefix@_engine.get_next_vpc (current_cpu->h_pc_get ());
1348
1349   {
1350     // These two are used to pass data from cti insns to the cti-chain insn.
1351     PCADDR pbb_br_npc;
1352     branch_status pbb_br_status;
1353     // These two are used to build up values of the previous two.
1354     PCADDR npc;
1355     branch_status br_status;
1356     // Top level locals moved here so they're usable by multiple fragments.
1357 "
1358
1359    (lambda ()
1360      (string-write-map (lambda (local)
1361                          (string-append "    "
1362                                         (mode:c-type (cadr local))
1363                                         " "
1364                                         (caddr local)
1365                                         ";\n"))
1366                        locals))
1367
1368    "\
1369
1370 restart:
1371 #ifdef __GNUC__
1372   fragpc = vpc->execute.cgoto.frags;
1373   goto * *fragpc;
1374 #else
1375   fragpc = vpc->idesc->frags;
1376   switch (*fragpc)
1377 #endif
1378
1379     {
1380
1381 "
1382
1383    (lambda ()
1384      ; Turn parallel execution support off.
1385      ; ??? Still needed?
1386      (set-with-parallel?! #f)
1387      (string-write-map (lambda (frag)
1388                          (/gen-sfrag-case frag locals))
1389                        ; FIXME: vector->list
1390                        (vector->list frag-table)))
1391
1392    "
1393 #ifdef __GNUC__
1394     end_switch: ;
1395 #else
1396     default: abort ();
1397 #endif
1398     }
1399   }
1400
1401   // Save vpc for next time.
1402   current_cpu->@prefix@_engine.set_next_vpc (vpc);
1403 }
1404 \n")
1405 )
1406
1407 (define (/gen-sfrag-engine)
1408   (string-write
1409    (lambda ()
1410      (/gen-sfrag-engine-frag-table (sim-sfrag-insn-list)
1411                                    (sim-sfrag-frag-table)
1412                                    (sim-sfrag-usage-table)))
1413    (lambda ()
1414      (/gen-sfrag-engine-fn (sim-sfrag-frag-table)
1415                            (/frag-convert-c-locals (sim-sfrag-locals-list))))
1416    )
1417 )
1418 \f
1419 ; Generate sem-switch.cxx.
1420
1421 (define (cgen-sem-switch.cxx)
1422   (logit 1 "Generating " (gen-cpu-name) "-sem-switch.cxx ...\n")
1423
1424   (sim-analyze-insns!)
1425   (if (with-sem-frags?)
1426       (sim-sfrag-analyze-insns!))
1427
1428   ; Turn parallel execution support off.
1429   ; It is later turned on/off when generating the actual semantic code.
1430   (set-with-parallel?! #f)
1431
1432   ; Tell the rtx->c translator we are the simulator.
1433   (rtl-c-config! #:rtl-cover-fns? #t)
1434
1435   ; Indicate we're currently generating a pbb engine.
1436   (set-current-pbb-engine?! #t)
1437
1438   (string-write
1439    (gen-c-copyright "Simulator instruction semantics for @prefix@."
1440                   copyright-red-hat package-red-hat-simulators)
1441    "\
1442
1443 #include \"@cpu@.h\"
1444
1445 using namespace @cpu@; // FIXME: namespace organization still wip
1446
1447 #define GET_ATTR(name) GET_ATTR_##name ()
1448
1449 \n"
1450
1451    (if (with-sem-frags?)
1452        /gen-sfrag-engine-decls
1453        "")
1454
1455    (if (with-sem-frags?)
1456        /gen-sfrag-engine
1457        /gen-sem-switch-engine)
1458    )
1459 )