OSDN Git Service

* mach.scm (<derived-arch-data>): New member large-insn-word?.
[pf3gnuchains/pf3gnuchains4x.git] / cgen / sim-cpu.scm
1 ; CPU family related simulator generator, excluding decoding and model support.
2 ; Copyright (C) 2000, 2001, 2009 Red Hat, Inc.
3 ; This file is part of CGEN.
4
5 ; Notes:
6 ; - Add support to generate copies of semantic code and perform constant
7 ;   folding based on selected mach.  This would collapse out untaken branches
8 ;   of tests on (current-mach).
9
10 ; Utilities of cgen-cpu.h.
11
12 ; Print various parameters of the cpu family.
13 ; A "cpu family" here is a collection of variants of a particular architecture
14 ; that share sufficient commonality that they can be handled together.
15
16 (define (/gen-cpu-defines)
17   (string-append
18    "\
19 /* Maximum number of instructions that are fetched at a time.
20    This is for LIW type instructions sets (e.g. m32r).  */
21 #define MAX_LIW_INSNS " (number->string (state-liw-insns))
22    "\n\
23
24 /* Maximum number of instructions that can be executed in parallel.  */
25 #define MAX_PARALLEL_INSNS " (number->string (state-parallel-insns))
26    "\n\
27
28 /* The size of an \"int\" needed to hold an instruction word.
29    This is usually 32 bits, but some architectures needs 64 bits.  */
30 typedef "
31    (if (adata-large-insn-word? CURRENT-ARCH)
32        "CGEN_INSN_LGUINT"
33        "CGEN_INSN_INT")
34    " CGEN_INSN_WORD;\n\n"
35 ;   (gen-enum-decl '@cpu@_virtual
36 ;                 "@cpu@ virtual insns"
37 ;                 "@ARCH@_INSN_" ; not @CPU@ to match CGEN_INSN_TYPE in opc.h
38 ;                 '((x-invalid 0)
39 ;                   (x-before -1) (x-after -2)
40 ;                   (x-begin -3) (x-chain -4) (x-cti-chain -5)))
41    )
42 )
43
44 ; Return a boolean indicating if hardware element HW needs storage allocated
45 ; for it in the SIM_CPU struct.
46
47 (define (hw-need-storage? hw)
48   (and (register? hw) (not (obj-has-attr? hw 'VIRTUAL)))
49 )
50
51 ; Subroutine of /gen-hardware-types to generate the struct containing
52 ; hardware elements of one isa.
53
54 (define (/gen-hardware-struct hw-list)
55   (if (null? hw-list)
56       ; If struct is empty, leave it out to simplify generated code.
57       ""
58       (string-list-map (lambda (hw)
59                          (string-list
60                           (gen-defn hw)
61                           (gen-obj-sanitize hw
62                                             (string-list
63                                              (send hw 'gen-get-macro)
64                                              (send hw 'gen-set-macro)))))
65                        (find hw-need-storage? hw-list)))
66   )
67
68 ; Return C type declarations of all of the hardware elements.
69 ; The name of the type is prepended with the cpu family name.
70
71 (define (/gen-hardware-types)
72   (string-list
73    "/* CPU state information.  */\n"
74    "typedef struct {\n"
75    "  /* Hardware elements.  */\n"
76    "  struct {\n"
77    (/gen-hardware-struct 
78     (find (lambda (hw)
79             (or (not (with-multiple-isa?))
80                 (>= (count-common
81                      (current-keep-isa-name-list)
82                      (obj-attr-value hw 'ISA))
83                     1)))
84           (current-hw-list))
85     )
86    "  } hardware;\n"
87    "#define CPU_CGEN_HW(cpu) (& (cpu)->cpu_data.hardware)\n"
88    ;"  /* CPU profiling state information.  */\n"
89    ;"  struct {\n"
90    ;(string-list-map (lambda (hw) (send hw 'gen-profile-decl))
91    ;                (find hw-profilable? (current-hw-list)))
92    ;"  } profile;\n"
93    ;"#define CPU_CGEN_PROFILE(cpu) (& (cpu)->cpu_data.profile)\n"
94    "} @CPU@_CPU_DATA;\n\n"
95    ; If there are any virtual regs, output get/set macros for them.
96    (let ((virtual-regs (find (lambda (hw)
97                                (and (register? hw)
98                                     (obj-has-attr? hw 'VIRTUAL)))
99                              (current-hw-list)))
100          (orig-with-parallel? (with-parallel?))
101          (result ""))
102      (set-with-parallel?! #f)
103      (if (not (null? virtual-regs))
104          (set! result
105                (string-list
106                 "/* Virtual regs.  */\n\n"
107                 (string-list-map (lambda (hw)
108                                    (logit 3 "Generating get/set for " (obj:name hw)
109                                           " ...\n")
110                                    (gen-obj-sanitize hw
111                                                      (string-list
112                                                       (send hw 'gen-get-macro)
113                                                       (send hw 'gen-set-macro))))
114                                  virtual-regs)
115                 "\n"
116                 )))
117      (set-with-parallel?! orig-with-parallel?)
118      result)
119    )
120 )
121
122 ; Return the declaration of register access functions.
123
124 (define (/gen-cpu-reg-access-decls)
125   (string-list
126    "/* Cover fns for register access.  */\n"
127    (string-list-map (lambda (hw)
128                       (gen-reg-access-decl hw
129                                            "@cpu@"
130                                            (gen-type hw)
131                                            (hw-scalar? hw)))
132                     (find register? (current-hw-list)))
133    "\n"
134    "/* These must be hand-written.  */\n"
135    "extern CPUREG_FETCH_FN @cpu@_fetch_register;\n"
136    "extern CPUREG_STORE_FN @cpu@_store_register;\n"
137    "\n")
138 )
139
140 ; Generate type of struct holding model state while executing.
141
142 (define (/gen-model-decls)
143   (logit 2 "Generating model decls ...\n")
144   (string-list
145    (string-list-map
146     (lambda (model)
147       (string-list
148        "typedef struct {\n"
149        (if (null? (model:state model))
150            "  int empty;\n" ; ensure struct isn't empty so it compiles
151            (string-map (lambda (var)
152                          (string-append "  "
153                                         (mode:c-type (mode:lookup (cadr var)))
154                                         " "
155                                         (gen-c-symbol (car var))
156                                         ";\n"))
157                        (model:state model)))
158        "} MODEL_" (string-upcase (gen-sym model)) "_DATA;\n\n"
159        ))
160     (current-model-list))
161    )
162 )
163
164 ; Utility of /gen-extract-macros to generate a macro to define the local
165 ; vars to contain extracted field values and the code to assign them
166 ; for <iformat> IFMT.
167
168 (define (/gen-extract-ifmt-macro ifmt)
169   (logit 2 "Processing format " (obj:name ifmt) " ...\n")
170   (string-list
171    (gen-define-ifmt-ifields ifmt "" #t #f)
172    (gen-extract-ifmt-ifields ifmt "" #t #f)
173    ; We don't need an extra blank line here as gen-extract-ifields adds one.
174    )
175 )
176
177 ; Generate macros to extract instruction fields.
178
179 (define (/gen-extract-macros)
180   (logit 2 "Generating extraction macros ...\n")
181   (string-list
182    "\
183 /* Macros to simplify extraction, reading and semantic code.
184    These define and assign the local vars that contain the insn's fields.  */
185 \n"
186    (string-list-map /gen-extract-ifmt-macro (current-ifmt-list))
187    )
188 )
189
190 ; Utility of /gen-parallel-exec-type to generate the definition of one
191 ; structure in PAREXEC.
192 ; SFMT is an <sformat> object.
193
194 (define (/gen-parallel-exec-elm sfmt)
195   (string-append
196    "    struct { /* " (obj:comment sfmt) " */\n"
197    (let ((sem-ops
198           ((if (with-parallel-write?) sfmt-out-ops sfmt-in-ops) sfmt)))
199      (if (null? sem-ops)
200          "      int empty;\n" ; ensure struct isn't empty so it compiles
201          (string-map
202           (lambda (op)
203             (logit 2 "Processing operand " (obj:name op) " of format "
204                    (obj:name sfmt) " ...\n")
205               (if (with-parallel-write?)
206                   (let ((index-type (and (op-save-index? op)
207                                          (gen-index-type op sfmt))))
208                     (string-append "      " (gen-type op)
209                                    " " (gen-sym op) ";\n"
210                                    (if index-type
211                                        (string-append "      " index-type 
212                                                       " " (gen-sym op) "_idx;\n")
213                                        "")))
214                   (string-append "      "
215                                  (gen-type op)
216                                  " "
217                                  (gen-sym op)
218                                  ";\n")))
219           sem-ops)))
220    "    } " (gen-sym sfmt) ";\n"
221    )
222 )
223
224 ; Generate the definition of the structure that holds register values, etc.
225 ; for use during parallel execution.  When instructions are executed parallelly
226 ; either
227 ; - their inputs are read before their outputs are written.  Thus we have to
228 ; fetch the input values of several instructions before executing any of them.
229 ; - or their outputs are queued here first and then written out after all insns
230 ; have executed.
231 ; The fetched/queued values are stored in an array of PAREXEC structs, one
232 ; element per instruction.
233
234 (define (/gen-parallel-exec-type)
235   (logit 2 "Generating PAREXEC type ...\n")
236   (string-append
237    (if (with-parallel-write?)
238        "/* Queued output values of an instruction.  */\n"
239        "/* Fetched input values of an instruction.  */\n")
240    "\
241
242 struct parexec {
243   union {\n"
244    (string-map /gen-parallel-exec-elm (current-sfmt-list))
245    "\
246   } operands;
247   /* For conditionally written operands, bitmask of which ones were.  */
248   int written;
249 };\n\n"
250    )
251 )
252
253 ; Generate the TRACE_RECORD struct definition.
254 ; This struct will hold all necessary data for doing tracing and profiling
255 ; (e.g. register numbers).  The goal is to remove all tracing code from the
256 ; semantic code.  Then the fast/full distinction needn't use conditionals to
257 ; discard/include the tracing/profiling code.
258
259 (define (/gen-trace-record-type)
260   (string-list
261    "\
262 /* Collection of various things for the trace handler to use.  */
263
264 typedef struct trace_record {
265   IADDR pc;
266   /* FIXME:wip */
267 } TRACE_RECORD;
268 \n"
269    )
270 )
271 \f
272 ; Utilities of cgen-cpu.c
273
274 ; Get/set fns for every register.
275
276 (define (/gen-cpu-reg-access-defns)
277   (string-list-map
278    (lambda (hw)
279      (let ((scalar? (hw-scalar? hw))
280            (name (obj:name hw))
281            (getter (hw-getter hw))
282            (setter (hw-setter hw)))
283        (gen-reg-access-defn hw
284                             "@cpu@"
285                             (gen-type hw)
286                             scalar?
287                             (if getter
288                                 (string-append
289                                  "  return GET_"
290                                  (string-upcase (gen-c-symbol name))
291                                  " ("
292                                  (if scalar? "" "regno")
293                                  ");\n")
294                                 (string-append
295                                  "  return CPU ("
296                                  (gen-c-symbol name)
297                                  (if scalar? "" "[regno]")
298                                  ");\n"))
299                             (if setter
300                                 (string-append
301                                  "  SET_"
302                                  (string-upcase (gen-c-symbol name))
303                                  " ("
304                                  (if scalar? "" "regno, ")
305                                  "newval);\n")
306                                 (string-append
307                                  "  CPU ("
308                                  (gen-c-symbol name)
309                                  (if scalar? "" "[regno]")
310                                  ") = newval;\n")))))
311    (find (lambda (hw) (register? hw))
312          (current-hw-list)))
313 )
314
315 ; Generate a function to record trace results in a trace record.
316
317 (define (/gen-cpu-record-results)
318   (string-list
319    "\
320 /* Record trace results for INSN.  */
321
322 void
323 @cpu@_record_trace_results (SIM_CPU *current_cpu, CGEN_INSN *insn,
324                             int *indices, TRACE_RECORD *tr)
325 {\n"
326    "}\n"
327    )
328 )
329 \f
330 ; Utilities of cgen-read.c.
331 ; Parallel-read support is not currently used by any port and this code
332 ; has been left to bitrot.  Don't delete it just yet.
333
334 ; Return C code to fetch and save all input operands to instructions with
335 ; <sformat> SFMT.
336
337 (define (/gen-read-args sfmt)
338   (string-map (lambda (op) (op:read op sfmt))
339               (sfmt-in-ops sfmt))
340 )
341
342 ; Utility of /gen-read-switch to generate a switch case for <sformat> SFMT.
343
344 (define (/gen-read-case sfmt)
345   (logit 2 "Processing read switch case for \"" (obj:name sfmt) "\" ...\n")
346   (string-list
347    "    CASE (read, READ_" (string-upcase (gen-sym sfmt)) ") : "
348    "/* " (obj:comment sfmt) " */\n"
349    "    {\n"
350    (gen-define-field-macro (if (with-scache?) sfmt #f))
351    (gen-define-parallel-operand-macro sfmt)
352    (gen-define-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) "      " #f)
353    (gen-extract-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) "      " #f)
354    (/gen-read-args sfmt)
355    (gen-undef-parallel-operand-macro sfmt)
356    (gen-undef-field-macro sfmt)
357    "    }\n"
358    "    BREAK (read);\n\n"
359    )
360 )
361
362 ; Generate the guts of a C switch statement to read insn operands.
363 ; The switch is based on instruction formats.
364
365 (define (/gen-read-switch)
366   (logit 2 "Processing readers ...\n")
367   (string-write-map /gen-read-case (current-sfmt-list))
368 )
369 \f
370 ; Utilities of cgen-write.c.
371
372 ; This is the other way of implementing parallel execution support.
373 ; Instead of fetching all the input operands first, write all the output
374 ; operands and their addresses to holding variables, and then run a
375 ; post-processing pass to update the cpu state.
376 ;
377 ; There are separate implementations for semantics as functions and semantics
378 ; as one big switch.  For the function case we create a function that is a
379 ; switch on each semantic format and loops writing each insn's results back.
380 ; For the switch case we add cases to the switch to handle the write back,
381 ; and it is up to the pbb compiler to include them in the generated "code".
382
383 ; Return C code to fetch and save all output operands to instructions with
384 ; <sformat> SFMT.
385
386 (define (/gen-write-args sfmt)
387   (string-map (lambda (op) (op:write op sfmt))
388               (sfmt-out-ops sfmt))
389 )
390
391 ; Utility of gen-write-switch to generate a switch case for <sformat> SFMT.
392 ; If INSN is non-#f, it is the <insn> object of the insn in which case
393 ; the case is named after the insn not the format.  This is done because
394 ; current sem-switch support emits one handler per insn instead of per sfmt.
395
396 (define (/gen-write-case sfmt insn)
397   (logit 2 "Processing write switch case for \"" (obj:name sfmt) "\" ...\n")
398   (string-list
399    (if insn
400        (string-list /indent
401                     "CASE (sem, INSN_WRITE_"
402                     (string-upcase (gen-sym insn)) ") : ")
403        (string-list /indent
404                     "case @CPU@_"
405                     (string-upcase (gen-sym sfmt)) " : "))
406    "/* "
407    (if insn
408        (string-list (insn-syntax insn))
409        (obj:comment sfmt))
410    " */\n"
411    /indent "  {\n"
412    (if insn
413        (string-list
414         /indent
415         "    SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);\n"
416         /indent
417         "    const ARGBUF *abuf = SEM_ARGBUF (sem_arg)->fields.write.abuf;\n")
418        "")
419    (gen-define-field-macro (if (with-scache?) sfmt #f))
420    (gen-define-parallel-operand-macro sfmt)
421    /indent
422    "    int UNUSED written = abuf->written;\n"
423    ;(gen-define-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) "  " #f) - used by cgen-read.c
424    ;(gen-extract-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) "  " #f) - used by cgen-read.c
425    (if insn
426        (string-list /indent "    IADDR UNUSED pc = abuf->addr;\n")
427        "")
428    (if (and insn (insn-cti? insn))
429        (string-list /indent
430                     "    SEM_BRANCH_INIT\n") ; no trailing `;' on purpose
431        "")
432    (if insn
433        (string-list /indent "    vpc = SEM_NEXT_VPC (sem_arg, pc, 0);\n")
434        "")
435    "\n"
436    (/indent-add 4)
437    (/gen-write-args sfmt)
438    (/indent-add -4)
439    "\n"
440    (if (and insn (insn-cti? insn))
441        (string-list /indent "  SEM_BRANCH_FINI (vpc);\n")
442        "")
443    (gen-undef-parallel-operand-macro sfmt)
444    (gen-undef-field-macro sfmt)
445    /indent "  }\n"
446    (if insn
447        (string-list /indent "  NEXT (vpc);\n")
448        (string-list /indent "  break;\n"))
449    "\n"
450    )
451 )
452
453 ; Generate the guts of a C switch statement to write insn operands.
454 ; The switch is based on instruction formats.
455 ; ??? This will generate cases for formats that don't need it.
456 ; E.g. on the m32r all 32 bit insns can't be executed in parallel.
457 ; It's easier to generate the code anyway so we do.
458
459 (define (/gen-write-switch)
460   (logit 2 "Processing writers ...\n")
461   (string-write-map (lambda (sfmt)
462                       (/gen-write-case sfmt #f))
463                     (current-sfmt-list))
464 )
465 \f
466 ; Utilities of cgen-semantics.c.
467
468 ; Return name of semantic fn for INSN.
469
470 (define (/gen-sem-fn-name insn)
471   ;(string-append "sem_" (gen-sym insn))
472   (gen-sym insn)
473 )
474
475 ; Return semantic fn table entry for INSN.
476
477 (define (/gen-sem-fn-table-entry insn)
478   (string-list
479    "  { "
480    "@PREFIX@_INSN_"
481    (string-upcase (gen-sym insn))
482    ", "
483    "SEM_FN_NAME (@prefix@," (/gen-sem-fn-name insn) ")"
484    " },\n"
485    )
486 )
487
488 ; Return C code to define a table of all semantic fns and a function to
489 ; add the info to the insn descriptor table.
490
491 (define (/gen-semantic-fn-table)
492   (string-write
493    "\
494 /* Table of all semantic fns.  */
495
496 static const struct sem_fn_desc sem_fns[] = {\n"
497
498    (lambda ()
499      (string-write-map /gen-sem-fn-table-entry
500                        (non-alias-insns (current-insn-list))))
501
502    "\
503   { 0, 0 }
504 };
505
506 /* Add the semantic fns to IDESC_TABLE.  */
507
508 void
509 SEM_FN_NAME (@prefix@,init_idesc_table) (SIM_CPU *current_cpu)
510 {
511   IDESC *idesc_table = CPU_IDESC (current_cpu);
512   const struct sem_fn_desc *sf;
513   int mach_num = MACH_NUM (CPU_MACH (current_cpu));
514
515   for (sf = &sem_fns[0]; sf->fn != 0; ++sf)
516     {
517       const CGEN_INSN *insn = idesc_table[sf->index].idata;
518       int valid_p = (CGEN_INSN_VIRTUAL_P (insn)
519                      || CGEN_INSN_MACH_HAS_P (insn, mach_num));
520 #if FAST_P
521       if (valid_p)
522         idesc_table[sf->index].sem_fast = sf->fn;
523       else
524         idesc_table[sf->index].sem_fast = SEM_FN_NAME (@prefix@,x_invalid);
525 #else
526       if (valid_p)
527         idesc_table[sf->index].sem_full = sf->fn;
528       else
529         idesc_table[sf->index].sem_full = SEM_FN_NAME (@prefix@,x_invalid);
530 #endif
531     }
532 }
533 \n"
534    )
535 )
536
537 ; Return C code to perform the semantics of INSN.
538
539 (define (gen-semantic-code insn)
540   (string-append
541    (if (and (insn-real? insn)
542             (isa-setup-semantics (current-isa)))
543        (string-append
544         "  "
545         (rtl-c VOID (obj-isa-list insn) nil
546                (isa-setup-semantics (current-isa))
547                #:for-insn? #t
548                #:rtl-cover-fns? #t
549                #:owner insn)
550         "\n")
551        "")
552
553    ; Indicate generating code for INSN.
554    ; Use the compiled form if available.
555    ; The case when they're not available is for virtual insns. xxx Still true?
556    (cond ((insn-compiled-semantics insn)
557           => (lambda (sem)
558                (rtl-c-parsed VOID sem
559                              #:for-insn? #t
560                              #:rtl-cover-fns? #t
561                              #:owner insn)))
562          ((insn-canonical-semantics insn)
563           => (lambda (sem)
564                (rtl-c-parsed VOID sem
565                              #:for-insn? #t
566                              #:rtl-cover-fns? #t
567                              #:owner insn)))
568          (else
569           (context-error (make-obj-context insn #f)
570                          "While generating semantic code"
571                          "semantics of insn are not canonicalized"))))
572 )
573
574 ; Return definition of C function to perform INSN.
575 ; This version handles the with-scache case.
576
577 (define (/gen-scache-semantic-fn insn)
578   (logit 2 "Processing semantics for " (obj:name insn) ": \"" (insn-syntax insn) "\" ...\n")
579   (set! /with-profile? /with-profile-fn?)
580   (let ((profile? (and (with-profile?)
581                        (not (obj-has-attr? insn 'VIRTUAL))))
582         (parallel? (with-parallel?))
583         (cti? (insn-cti? insn))
584         (insn-len (insn-length-bytes insn)))
585     (string-list
586      "/* " (obj:str-name insn) ": " (insn-syntax insn) " */\n\n"
587      "static SEM_PC\n"
588      "SEM_FN_NAME (@prefix@," (gen-sym insn) ")"
589      (if (and parallel? (not (with-generic-write?)))
590          " (SIM_CPU *current_cpu, SEM_ARG sem_arg, PAREXEC *par_exec)\n"
591          " (SIM_CPU *current_cpu, SEM_ARG sem_arg)\n")
592      "{\n"
593      (gen-define-field-macro (insn-sfmt insn))
594      (if (and parallel? (not (with-generic-write?)))
595          (gen-define-parallel-operand-macro (insn-sfmt insn))
596          "")
597      "  ARGBUF *abuf = SEM_ARGBUF (sem_arg);\n"
598      ; Unconditionally written operands are not recorded here.
599      "  int UNUSED written = 0;\n"
600      ; The address of this insn, needed by extraction and semantic code.
601      ; Note that the address recorded in the cpu state struct is not used.
602      ; For faster engines that copy will be out of date.
603      "  IADDR UNUSED pc = abuf->addr;\n"
604      (if (and cti? (not parallel?))
605          "  SEM_BRANCH_INIT\n" ; no trailing `;' on purpose
606          "")
607      (string-list "  SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, "
608                   (number->string insn-len)
609                   ");\n")
610      "\n"
611      (gen-semantic-code insn) "\n"
612      ; Only update what's been written if some are conditionally written.
613      ; Otherwise we know they're all written so there's no point in
614      ; keeping track.
615      (if (/any-cond-written? (insn-sfmt insn))
616          "  abuf->written = written;\n"
617          "")
618      (if (and cti? (not parallel?))
619          "  SEM_BRANCH_FINI (vpc);\n"
620          "")
621      "  return vpc;\n"
622      (if (and parallel? (not (with-generic-write?)))
623          (gen-undef-parallel-operand-macro (insn-sfmt insn))
624          "")
625      (gen-undef-field-macro (insn-sfmt insn))
626      "}\n\n"
627      ))
628 )
629
630 ; Return definition of C function to perform INSN.
631 ; This version handles the without-scache case.
632 ; ??? TODO: multiword insns.
633
634 (define (/gen-no-scache-semantic-fn insn)
635   (logit 2 "Processing semantics for " (obj:name insn) ": \"" (insn-syntax insn) "\" ...\n")
636   (set! /with-profile? /with-profile-fn?)
637   (let ((profile? (and (with-profile?)
638                        (not (obj-has-attr? insn 'VIRTUAL))))
639         (parallel? (with-parallel?))
640         (cti? (insn-cti? insn))
641         (insn-len (insn-length-bytes insn)))
642     (string-list
643      "/* " (obj:str-name insn) ": " (insn-syntax insn) " */\n\n"
644      "static SEM_STATUS\n"
645      "SEM_FN_NAME (@prefix@," (gen-sym insn) ")"
646      (if (and parallel? (not (with-generic-write?)))
647          " (SIM_CPU *current_cpu, SEM_ARG sem_arg, PAREXEC *par_exec, CGEN_INSN_WORD insn)\n"
648          " (SIM_CPU *current_cpu, SEM_ARG sem_arg, CGEN_INSN_WORD insn)\n")
649      "{\n"
650      (if (and parallel? (not (with-generic-write?)))
651          (gen-define-parallel-operand-macro (insn-sfmt insn))
652          "")
653      "  SEM_STATUS status = 0;\n" ; ??? wip
654      "  ARGBUF *abuf = SEM_ARGBUF (sem_arg);\n"
655      (gen-define-field-macro (if (with-scache?) (insn-sfmt insn) #f))
656      ; Unconditionally written operands are not recorded here.
657      "  int UNUSED written = 0;\n"
658      "  IADDR UNUSED pc = GET_H_PC ();\n"
659      (if (and cti? (not parallel?))
660          "  SEM_BRANCH_INIT\n" ; no trailing `;' on purpose
661          "")
662      (string-list "  SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, "
663                   (number->string insn-len)
664                   ");\n")
665      (string-list (gen-define-ifmt-ifields (insn-ifmt insn) "  " #f #t)
666                   (gen-sfmt-op-argbuf-defns (insn-sfmt insn))
667                   (gen-extract-ifmt-ifields (insn-ifmt insn) "  " #f #t)
668                   (gen-sfmt-op-argbuf-assigns (insn-sfmt insn)))
669      "\n"
670      (gen-semantic-code insn) "\n"
671      ; Only update what's been written if some are conditionally written.
672      ; Otherwise we know they're all written so there's no point in
673      ; keeping track.
674      (if (/any-cond-written? (insn-sfmt insn))
675          "  abuf->written = written;\n"
676          "")
677      ; SEM_{,N}BRANCH_FINI are user-supplied macros.
678      (if (not parallel?)
679          (string-list
680           (if cti?
681               "  SEM_BRANCH_FINI (vpc, "
682               "  SEM_NBRANCH_FINI (vpc, ")
683           (gen-bool-attrs (obj-atlist insn) gen-attr-mask)
684           ");\n")
685          "")
686      (gen-undef-field-macro (insn-sfmt insn))
687      "  return status;\n"
688      (if (and parallel? (not (with-generic-write?)))
689          (gen-undef-parallel-operand-macro (insn-sfmt insn))
690          "")
691      "}\n\n"
692      ))
693 )
694
695 (define (/gen-all-semantic-fns)
696   (logit 2 "Processing semantics ...\n")
697   (let ((insns (non-alias-insns (current-insn-list))))
698     (if (with-scache?)
699         (string-write-map /gen-scache-semantic-fn insns)
700         (string-write-map /gen-no-scache-semantic-fn insns)))
701 )
702
703 ; Utility of /gen-sem-case to return the mask of operands always written
704 ; to in <sformat> SFMT.
705 ; ??? Not currently used.
706
707 (define (/uncond-written-mask sfmt)
708   (apply + (map (lambda (op)
709                   (if (op:cond? op)
710                       0
711                       (logsll 1 (op:num op))))
712                 (sfmt-out-ops sfmt)))
713 )
714
715 ; Utility of /gen-sem-case to return #t if any operand in <sformat> SFMT is
716 ; conditionally written to.
717
718 (define (/any-cond-written? sfmt)
719   (any-true? (map op:cond? (sfmt-out-ops sfmt)))
720 )
721
722 ; Generate a switch case to perform INSN.
723
724 (define (/gen-sem-case insn parallel?)
725   (logit 2 "Processing "
726          (if parallel? "parallel " "")
727          "semantic switch case for " (obj:name insn) ": \""
728          (insn-syntax insn) "\" ...\n")
729   (set! /with-profile? /with-profile-sw?)
730   (let ((cti? (insn-cti? insn))
731         (insn-len (insn-length-bytes insn)))
732     (string-list
733      ; INSN_ is prepended here and not elsewhere to avoid name collisions
734      ; with symbols like AND, etc.
735      "  CASE (sem, "
736      "INSN_"
737      (if parallel? "PAR_" "")
738      (string-upcase (gen-sym insn)) ") : "
739      "/* " (insn-syntax insn) " */\n"
740      "{\n"
741      "  SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);\n"
742      "  ARGBUF *abuf = SEM_ARGBUF (sem_arg);\n"
743      (gen-define-field-macro (if (with-scache?) (insn-sfmt insn) #f))
744      (if (and parallel? (not (with-generic-write?)))
745          (gen-define-parallel-operand-macro (insn-sfmt insn))
746          "")
747      ; Unconditionally written operands are not recorded here.
748      "  int UNUSED written = 0;\n"
749      ; The address of this insn, needed by extraction and semantic code.
750      ; Note that the address recorded in the cpu state struct is not used.
751      "  IADDR UNUSED pc = abuf->addr;\n"
752      (if (and cti? (not parallel?))
753          "  SEM_BRANCH_INIT\n" ; no trailing `;' on purpose
754          "")
755      (if (with-scache?)
756          ""
757          (string-list (gen-define-ifmt-ifields (insn-ifmt insn) "  " #f #t)
758                       (gen-extract-ifmt-ifields (insn-ifmt insn) "  " #f #t)
759                       "\n"))
760      (string-list "  vpc = SEM_NEXT_VPC (sem_arg, pc, "
761                   (number->string insn-len)
762                   ");\n")
763      "\n"
764      (gen-semantic-code insn) "\n"
765      ; Only update what's been written if some are conditionally written.
766      ; Otherwise we know they're all written so there's no point in
767      ; keeping track.
768      (if (/any-cond-written? (insn-sfmt insn))
769          "  abuf->written = written;\n"
770          "")
771      (if (and cti? (not parallel?))
772          "  SEM_BRANCH_FINI (vpc);\n"
773          "")
774      (if (and parallel? (not (with-generic-write?)))
775          (gen-undef-parallel-operand-macro (insn-sfmt insn))
776          "")
777      (gen-undef-field-macro (insn-sfmt insn))
778      "}\n"
779      "  NEXT (vpc);\n\n"
780      ))
781 )
782
783 (define (/gen-sem-switch)
784   (logit 2 "Processing semantic switch ...\n")
785   ; Turn parallel execution support off.
786   (let ((orig-with-parallel? (with-parallel?)))
787     (set-with-parallel?! #f)
788     (let ((result
789            (string-write-map (lambda (insn) (/gen-sem-case insn #f))
790                              (non-alias-insns (current-insn-list)))))
791       (set-with-parallel?! orig-with-parallel?)
792       result))
793 )
794
795 ; Generate the guts of a C switch statement to execute parallel instructions.
796 ; This switch is included after the non-parallel instructions in the semantic
797 ; switch.
798 ;
799 ; ??? We duplicate the writeback case for each insn, even though we only need
800 ; one case per insn format.  The former keeps the code for each insn
801 ; together and might improve cache usage.  On the other hand the latter
802 ; reduces the amount of code, though it is believed that in this particular
803 ; instance the win isn't big enough.
804
805 (define (/gen-parallel-sem-switch)
806   (logit 2 "Processing parallel insn semantic switch ...\n")
807   ; Turn parallel execution support on.
808   (let ((orig-with-parallel? (with-parallel?)))
809     (set-with-parallel?! #t)
810     (let ((result
811            (string-write-map (lambda (insn)
812                                (string-list (/gen-sem-case insn #t)
813                                             (/gen-write-case (insn-sfmt insn) insn)))
814                              (parallel-insns (current-insn-list)))))
815       (set-with-parallel?! orig-with-parallel?)
816       result))
817 )
818 \f
819 ; Top level file generators.
820
821 ; Generate cpu-<cpu>.h
822
823 (define (cgen-cpu.h)
824   (logit 1 "Generating " (gen-cpu-name) "'s cpu.h ...\n")
825
826   (sim-analyze-insns!)
827
828   ; Turn parallel execution support on if cpu needs it.
829   (set-with-parallel?! (state-parallel-exec?))
830
831   ; Tell the rtl->c translator we're not the simulator.
832   ; ??? Minimizes changes in generated code until this is changed.
833   ; RTL->C happens for field decoding.
834   (rtl-c-config! #:rtl-cover-fns? #f)
835
836   (string-write
837    (gen-c-copyright "CPU family header for @cpu@."
838                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
839    "\
840 #ifndef CPU_@CPU@_H
841 #define CPU_@CPU@_H
842
843 "
844    /gen-cpu-defines
845    ;; After CGEN_INSN_WORD is defined we can include cgen-engine.h.
846    ;; We need to include it here (or thereabouts) because cgen-engine.h
847    ;; needs CGEN_INSN_WORD and parts of the remainder of this file need
848    ;; cgen-engine.h.
849    "/* cgen-engine.h needs CGEN_INSN_WORD that we just defined.  */\n"
850    "#include \"cgen-engine.h\"\n\n"
851    /gen-hardware-types
852    /gen-cpu-reg-access-decls
853    /gen-model-decls
854
855    (if (not (with-multiple-isa?))
856      (string-list
857        (lambda () (gen-argbuf-type #t))
858        (lambda () (gen-scache-type #t))
859        /gen-extract-macros)
860      "")
861
862    (if (and (with-parallel?) (not (with-generic-write?)))
863        /gen-parallel-exec-type
864        "")
865    /gen-trace-record-type
866    "#endif /* CPU_@CPU@_H */\n"
867    )
868 )
869
870 ; Generate defs-<isa>.h.
871
872 (define (cgen-defs.h)
873   (logit 1 "Generating " (obj:name (current-isa)) "'s defs.h ...\n")
874
875   (sim-analyze-insns!)
876
877   ; Tell the rtl->c translator we're not the simulator.
878   ; ??? Minimizes changes in generated code until this is changed.
879   ; RTL->C happens for field decoding.
880   (rtl-c-config! #:rtl-cover-fns? #f)
881
882   (string-write
883    (gen-c-copyright (string-append
884                   "ISA definitions header for "
885                   (obj:str-name (current-isa))
886                   ".")
887                  CURRENT-COPYRIGHT CURRENT-PACKAGE)
888    "\
889 #ifndef DEFS_@PREFIX@_H
890 #define DEFS_@PREFIX@_H
891
892 "
893    (lambda () (gen-argbuf-type #t))
894    (lambda () (gen-scache-type #t))
895    /gen-extract-macros
896
897    "#endif /* DEFS_@PREFIX@_H */\n"
898    )
899 )
900
901 ; Generate cpu-<cpu>.c
902
903 (define (cgen-cpu.c)
904   (logit 1 "Generating " (gen-cpu-name) "'s cpu.c ...\n")
905
906   (sim-analyze-insns!)
907
908   ; Turn parallel execution support on if cpu needs it.
909   (set-with-parallel?! (state-parallel-exec?))
910
911   ; Initialize rtl generation.
912   (rtl-c-config! #:rtl-cover-fns? #t)
913
914   (string-write
915    (gen-c-copyright "Misc. support for CPU family @cpu@."
916                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
917    "\
918 #define WANT_CPU @cpu@
919 #define WANT_CPU_@CPU@
920
921 #include \"sim-main.h\"
922 #include \"cgen-ops.h\"
923
924 "
925    /gen-cpu-reg-access-defns
926    /gen-cpu-record-results
927    )
928 )
929
930 ; Generate read.c
931
932 (define (cgen-read.c)
933   (logit 1 "Generating " (gen-cpu-name) "'s read.c ...\n")
934
935   (sim-analyze-insns!)
936
937   ; Turn parallel execution support off.
938   (set-with-parallel?! #f)
939
940   ; Tell the rtx->c translator we are the simulator.
941   (rtl-c-config! #:rtl-cover-fns? #t)
942
943   (string-write
944    (gen-c-copyright (string-append "Simulator instruction operand reader for "
945                                    (symbol->string (current-arch-name)) ".")
946                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
947    "\
948 #ifdef DEFINE_LABELS
949
950   /* The labels have the case they have because the enum of insn types
951      is all uppercase and in the non-stdc case the fmt symbol is built
952      into the enum name.  */
953
954   static struct {
955     int index;
956     void *label;
957   } labels[] = {\n"
958
959    (lambda ()
960      (string-write-map (lambda (insn)
961                          (string-append "    { "
962                                         "@PREFIX@_INSN_"
963                                         (string-upcase (gen-sym insn))
964                                         ", && case_read_READ_"
965                                         (string-upcase (gen-sym (insn-sfmt insn)))
966                                         " },\n"))
967                        (non-alias-insns (current-insn-list))))
968
969    "    { 0, 0 }
970   };
971   int i;
972
973   for (i = 0; labels[i].label != 0; ++i)
974     CPU_IDESC (current_cpu) [labels[i].index].read = labels[i].label;
975
976 #undef DEFINE_LABELS
977 #endif /* DEFINE_LABELS */
978
979 #ifdef DEFINE_SWITCH
980
981 {\n"
982    (if (with-scache?)
983        "\
984   SEM_ARG sem_arg = sc;
985   ARGBUF *abuf = SEM_ARGBUF (sem_arg);
986
987   SWITCH (read, sem_arg->read)\n"
988        "\
989   SWITCH (read, decode->read)\n")
990    "\
991     {
992
993 "
994
995    /gen-read-switch
996
997    "\
998     }
999   ENDSWITCH (read) /* End of read switch.  */
1000 }
1001
1002 #undef DEFINE_SWITCH
1003 #endif /* DEFINE_SWITCH */
1004 "
1005    )
1006 )
1007
1008 ; Generate write.c
1009
1010 (define (cgen-write.c)
1011   (logit 1 "Generating " (gen-cpu-name) "'s write.c ...\n")
1012
1013   (sim-analyze-insns!)
1014
1015   ; Turn parallel execution support off.
1016   (set-with-parallel?! #f)
1017
1018   ; Tell the rtx->c translator we are the simulator.
1019   (rtl-c-config! #:rtl-cover-fns? #t)
1020
1021   (string-write
1022    (gen-c-copyright (string-append "Simulator instruction operand writer for "
1023                                    (symbol->string (current-arch-name)) ".")
1024                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
1025    "\
1026 /* Write cached results of 1 or more insns executed in parallel.  */
1027
1028 void
1029 @cpu@_parallel_write (SIM_CPU *cpu, SCACHE *sbufs, PAREXEC *pbufs, int ninsns)
1030 {\n"
1031    (if (with-scache?)
1032        "\
1033   SEM_ARG sem_arg = sc;
1034   ARGBUF *abuf = SEM_ARGBUF (sem_arg);\n"
1035        "")
1036    "\
1037
1038   do
1039     {
1040       ARGBUF *abuf = SEM_ARGBUF (sbufs);
1041
1042       switch (abuf->idesc->write)
1043         {
1044 \n"
1045
1046    ;(/indent-add 8)
1047    /gen-write-switch
1048    ;(/indent-add -8)
1049
1050    "\
1051         }
1052     }
1053   while (--ninsns > 0);
1054 }
1055 "
1056    )
1057 )
1058
1059 ; Generate semantics.c
1060 ; Each instruction is implemented in its own function.
1061
1062 (define (cgen-semantics.c)
1063   (logit 1 "Generating " (gen-cpu-name) "'s semantics.c ...\n")
1064
1065   (sim-analyze-insns!)
1066
1067   ; Turn parallel execution support on if cpu needs it.
1068   (set-with-parallel?! (state-parallel-exec?))
1069
1070   ; Tell the rtx->c translator we are the simulator.
1071   (rtl-c-config! #:rtl-cover-fns? #t)
1072
1073   (string-write
1074    (gen-c-copyright "Simulator instruction semantics for @cpu@."
1075                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
1076    "\
1077 #define WANT_CPU @cpu@
1078 #define WANT_CPU_@CPU@
1079
1080 #include \"sim-main.h\"
1081 #include \"cgen-mem.h\"
1082 #include \"cgen-ops.h\"
1083
1084 #undef GET_ATTR
1085 "
1086    (gen-define-with-symcat "GET_ATTR(cpu, num, attr) \
1087 CGEN_ATTR_VALUE (NULL, abuf->idesc->attrs, CGEN_INSN_" "attr)")
1088 "
1089 /* This is used so that we can compile two copies of the semantic code,
1090    one with full feature support and one without that runs fast(er).
1091    FAST_P, when desired, is defined on the command line, -DFAST_P=1.  */
1092 #if FAST_P
1093 #define SEM_FN_NAME(cpu,fn) XCONCAT3 (cpu,_semf_,fn)
1094 #undef TRACE_RESULT
1095 #define TRACE_RESULT(cpu, abuf, name, type, val)
1096 #else
1097 #define SEM_FN_NAME(cpu,fn) XCONCAT3 (cpu,_sem_,fn)
1098 #endif
1099 \n"
1100
1101    /gen-all-semantic-fns
1102    ; Put the table at the end so we don't have to declare all the sem fns.
1103    /gen-semantic-fn-table
1104    )
1105 )
1106
1107 ; Generate sem-switch.c.
1108 ; Each instruction is a case in a switch().
1109 ; This file consists of just the switch().  It is included by mainloop.c.
1110
1111 (define (cgen-sem-switch.c)
1112   (logit 1 "Generating " (gen-cpu-name) "'s sem-switch.c ...\n")
1113
1114   (sim-analyze-insns!)
1115
1116   ; Turn parallel execution support off.
1117   ; It is later turned on/off when generating the actual semantic code.
1118   (set-with-parallel?! #f)
1119
1120   ; Tell the rtx->c translator we are the simulator.
1121   (rtl-c-config! #:rtl-cover-fns? #t)
1122
1123   (string-write
1124    (gen-c-copyright "Simulator instruction semantics for @cpu@."
1125                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
1126
1127    "\
1128 #ifdef DEFINE_LABELS
1129
1130   /* The labels have the case they have because the enum of insn types
1131      is all uppercase and in the non-stdc case the insn symbol is built
1132      into the enum name.  */
1133
1134   static struct {
1135     int index;
1136     void *label;
1137   } labels[] = {\n"
1138
1139    (lambda ()
1140      (string-write-map (lambda (insn)
1141                          (string-append "    { "
1142                                         "@PREFIX@_INSN_"
1143                                         (string-upcase (gen-sym insn))
1144                                         ", && case_sem_INSN_"
1145                                         (string-upcase (gen-sym insn))
1146                                         " },\n"))
1147                        (non-alias-insns (current-insn-list))))
1148
1149    (if (state-parallel-exec?)
1150        (lambda ()
1151          (string-write-map (lambda (insn)
1152                              (string-append "    { "
1153                                             "@CPU@_INSN_PAR_"
1154                                             (string-upcase (gen-sym insn))
1155                                             ", && case_sem_INSN_PAR_"
1156                                             (string-upcase (gen-sym insn))
1157                                             " },\n"
1158                                             "    { "
1159                                             "@CPU@_INSN_WRITE_"
1160                                             (string-upcase (gen-sym insn))
1161                                             ", && case_sem_INSN_WRITE_"
1162                                             (string-upcase (gen-sym insn))
1163                                             " },\n"))
1164                            (parallel-insns (current-insn-list))))
1165        "")
1166
1167    "    { 0, 0 }
1168   };
1169   int i;
1170
1171   for (i = 0; labels[i].label != 0; ++i)
1172     {
1173 #if FAST_P
1174       CPU_IDESC (current_cpu) [labels[i].index].sem_fast_lab = labels[i].label;
1175 #else
1176       CPU_IDESC (current_cpu) [labels[i].index].sem_full_lab = labels[i].label;
1177 #endif
1178     }
1179
1180 #undef DEFINE_LABELS
1181 #endif /* DEFINE_LABELS */
1182
1183 #ifdef DEFINE_SWITCH
1184
1185 /* If hyper-fast [well not unnecessarily slow] execution is selected, turn
1186    off frills like tracing and profiling.  */
1187 /* FIXME: A better way would be to have TRACE_RESULT check for something
1188    that can cause it to be optimized out.  Another way would be to emit
1189    special handlers into the instruction \"stream\".  */
1190
1191 #if FAST_P
1192 #undef TRACE_RESULT
1193 #define TRACE_RESULT(cpu, abuf, name, type, val)
1194 #endif
1195
1196 #undef GET_ATTR
1197 "
1198    (gen-define-with-symcat "GET_ATTR(cpu, num, attr) \
1199 CGEN_ATTR_VALUE (NULL, abuf->idesc->attrs, CGEN_INSN_" "attr)")
1200 "
1201 {
1202
1203 #if WITH_SCACHE_PBB
1204
1205 /* Branch to next handler without going around main loop.  */
1206 #define NEXT(vpc) goto * SEM_ARGBUF (vpc) -> semantic.sem_case
1207 SWITCH (sem, SEM_ARGBUF (vpc) -> semantic.sem_case)
1208
1209 #else /* ! WITH_SCACHE_PBB */
1210
1211 #define NEXT(vpc) BREAK (sem)
1212 #ifdef __GNUC__
1213 #if FAST_P
1214   SWITCH (sem, SEM_ARGBUF (sc) -> idesc->sem_fast_lab)
1215 #else
1216   SWITCH (sem, SEM_ARGBUF (sc) -> idesc->sem_full_lab)
1217 #endif
1218 #else
1219   SWITCH (sem, SEM_ARGBUF (sc) -> idesc->num)
1220 #endif
1221
1222 #endif /* ! WITH_SCACHE_PBB */
1223
1224     {
1225
1226 "
1227
1228    /gen-sem-switch
1229
1230    (if (state-parallel-exec?)
1231        /gen-parallel-sem-switch
1232        "")
1233
1234    "
1235     }
1236   ENDSWITCH (sem) /* End of semantic switch.  */
1237
1238   /* At this point `vpc' contains the next insn to execute.  */
1239 }
1240
1241 #undef DEFINE_SWITCH
1242 #endif /* DEFINE_SWITCH */
1243 "
1244    )
1245 )
1246
1247 ; Generate mainloop.in.
1248 ; ??? Not currently used.
1249
1250 (define (cgen-mainloop.in)
1251   (logit 1 "Generating mainloop.in ...\n")
1252
1253   (string-write
1254    "cat <<EOF >/dev/null\n"
1255    (gen-c-copyright "Simulator main loop for @arch@."
1256                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
1257    "EOF\n"
1258    "\
1259
1260 # Syntax:
1261 # /bin/sh mainloop.in init|support|{full,fast}-{extract,exec}-{scache,nocache}
1262
1263 # ??? There's lots of conditional compilation here.
1264 # After a few more ports are done, revisit.
1265
1266 case \"x$1\" in
1267
1268 xsupport)
1269
1270 cat <<EOF
1271 /*xsupport*/
1272 EOF
1273
1274 ;;
1275
1276 xinit)
1277
1278 cat <<EOF
1279 /*xinit*/
1280 EOF
1281
1282 ;;
1283
1284 xfull-extract-* | xfast-extract-*)
1285
1286 cat <<EOF
1287 {
1288 "
1289    (rtl-c VOID #f nil insn-extract #:rtl-cover-fns? #t)
1290 "}
1291 EOF
1292
1293 ;;
1294
1295 xfull-exec-* | xfast-exec-*)
1296
1297 cat <<EOF
1298 {
1299 "
1300    (rtl-c VOID #f nil insn-execute #:rtl-cover-fns? #t)
1301 "}
1302 EOF
1303
1304 ;;
1305
1306 *)
1307   echo \"Invalid argument to mainloop.in: $1\" >&2
1308   exit 1
1309   ;;
1310
1311 esac
1312 "
1313    )
1314 )