OSDN Git Service

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