OSDN Git Service

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