OSDN Git Service

gdb/testsuite/
[pf3gnuchains/pf3gnuchains3x.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    "#include \"cgen-engine.h\"\n\n"
850    /gen-hardware-types
851    /gen-cpu-reg-access-decls
852    /gen-model-decls
853
854    (if (not (with-multiple-isa?))
855      (string-list
856        (lambda () (gen-argbuf-type #t))
857        (lambda () (gen-scache-type #t))
858        /gen-extract-macros)
859      "")
860
861    (if (and (with-parallel?) (not (with-generic-write?)))
862        /gen-parallel-exec-type
863        "")
864    /gen-trace-record-type
865    "#endif /* CPU_@CPU@_H */\n"
866    )
867 )
868
869 ; Generate defs-<isa>.h.
870
871 (define (cgen-defs.h)
872   (logit 1 "Generating " (obj:name (current-isa)) "'s defs.h ...\n")
873
874   (sim-analyze-insns!)
875
876   ; Tell the rtl->c translator we're not the simulator.
877   ; ??? Minimizes changes in generated code until this is changed.
878   ; RTL->C happens for field decoding.
879   (rtl-c-config! #:rtl-cover-fns? #f)
880
881   (string-write
882    (gen-c-copyright (string-append
883                   "ISA definitions header for "
884                   (obj:str-name (current-isa))
885                   ".")
886                  CURRENT-COPYRIGHT CURRENT-PACKAGE)
887    "\
888 #ifndef DEFS_@PREFIX@_H
889 #define DEFS_@PREFIX@_H
890
891 "
892    (lambda () (gen-argbuf-type #t))
893    (lambda () (gen-scache-type #t))
894    /gen-extract-macros
895
896    "#endif /* DEFS_@PREFIX@_H */\n"
897    )
898 )
899
900 ; Generate cpu-<cpu>.c
901
902 (define (cgen-cpu.c)
903   (logit 1 "Generating " (gen-cpu-name) "'s cpu.c ...\n")
904
905   (sim-analyze-insns!)
906
907   ; Turn parallel execution support on if cpu needs it.
908   (set-with-parallel?! (state-parallel-exec?))
909
910   ; Initialize rtl generation.
911   (rtl-c-config! #:rtl-cover-fns? #t)
912
913   (string-write
914    (gen-c-copyright "Misc. support for CPU family @cpu@."
915                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
916    "\
917 #define WANT_CPU @cpu@
918 #define WANT_CPU_@CPU@
919
920 #include \"sim-main.h\"
921 #include \"cgen-ops.h\"
922
923 "
924    /gen-cpu-reg-access-defns
925    /gen-cpu-record-results
926    )
927 )
928
929 ; Generate read.c
930
931 (define (cgen-read.c)
932   (logit 1 "Generating " (gen-cpu-name) "'s read.c ...\n")
933
934   (sim-analyze-insns!)
935
936   ; Turn parallel execution support off.
937   (set-with-parallel?! #f)
938
939   ; Tell the rtx->c translator we are the simulator.
940   (rtl-c-config! #:rtl-cover-fns? #t)
941
942   (string-write
943    (gen-c-copyright (string-append "Simulator instruction operand reader for "
944                                    (symbol->string (current-arch-name)) ".")
945                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
946    "\
947 #ifdef DEFINE_LABELS
948
949   /* The labels have the case they have because the enum of insn types
950      is all uppercase and in the non-stdc case the fmt symbol is built
951      into the enum name.  */
952
953   static struct {
954     int index;
955     void *label;
956   } labels[] = {\n"
957
958    (lambda ()
959      (string-write-map (lambda (insn)
960                          (string-append "    { "
961                                         "@PREFIX@_INSN_"
962                                         (string-upcase (gen-sym insn))
963                                         ", && case_read_READ_"
964                                         (string-upcase (gen-sym (insn-sfmt insn)))
965                                         " },\n"))
966                        (non-alias-insns (current-insn-list))))
967
968    "    { 0, 0 }
969   };
970   int i;
971
972   for (i = 0; labels[i].label != 0; ++i)
973     CPU_IDESC (current_cpu) [labels[i].index].read = labels[i].label;
974
975 #undef DEFINE_LABELS
976 #endif /* DEFINE_LABELS */
977
978 #ifdef DEFINE_SWITCH
979
980 {\n"
981    (if (with-scache?)
982        "\
983   SEM_ARG sem_arg = sc;
984   ARGBUF *abuf = SEM_ARGBUF (sem_arg);
985
986   SWITCH (read, sem_arg->read)\n"
987        "\
988   SWITCH (read, decode->read)\n")
989    "\
990     {
991
992 "
993
994    /gen-read-switch
995
996    "\
997     }
998   ENDSWITCH (read) /* End of read switch.  */
999 }
1000
1001 #undef DEFINE_SWITCH
1002 #endif /* DEFINE_SWITCH */
1003 "
1004    )
1005 )
1006
1007 ; Generate write.c
1008
1009 (define (cgen-write.c)
1010   (logit 1 "Generating " (gen-cpu-name) "'s write.c ...\n")
1011
1012   (sim-analyze-insns!)
1013
1014   ; Turn parallel execution support off.
1015   (set-with-parallel?! #f)
1016
1017   ; Tell the rtx->c translator we are the simulator.
1018   (rtl-c-config! #:rtl-cover-fns? #t)
1019
1020   (string-write
1021    (gen-c-copyright (string-append "Simulator instruction operand writer for "
1022                                    (symbol->string (current-arch-name)) ".")
1023                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
1024    "\
1025 /* Write cached results of 1 or more insns executed in parallel.  */
1026
1027 void
1028 @cpu@_parallel_write (SIM_CPU *cpu, SCACHE *sbufs, PAREXEC *pbufs, int ninsns)
1029 {\n"
1030    (if (with-scache?)
1031        "\
1032   SEM_ARG sem_arg = sc;
1033   ARGBUF *abuf = SEM_ARGBUF (sem_arg);\n"
1034        "")
1035    "\
1036
1037   do
1038     {
1039       ARGBUF *abuf = SEM_ARGBUF (sbufs);
1040
1041       switch (abuf->idesc->write)
1042         {
1043 \n"
1044
1045    ;(/indent-add 8)
1046    /gen-write-switch
1047    ;(/indent-add -8)
1048
1049    "\
1050         }
1051     }
1052   while (--ninsns > 0);
1053 }
1054 "
1055    )
1056 )
1057
1058 ; Generate semantics.c
1059 ; Each instruction is implemented in its own function.
1060
1061 (define (cgen-semantics.c)
1062   (logit 1 "Generating " (gen-cpu-name) "'s semantics.c ...\n")
1063
1064   (sim-analyze-insns!)
1065
1066   ; Turn parallel execution support on if cpu needs it.
1067   (set-with-parallel?! (state-parallel-exec?))
1068
1069   ; Tell the rtx->c translator we are the simulator.
1070   (rtl-c-config! #:rtl-cover-fns? #t)
1071
1072   (string-write
1073    (gen-c-copyright "Simulator instruction semantics for @cpu@."
1074                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
1075    "\
1076 #define WANT_CPU @cpu@
1077 #define WANT_CPU_@CPU@
1078
1079 #include \"sim-main.h\"
1080 #include \"cgen-mem.h\"
1081 #include \"cgen-ops.h\"
1082
1083 #undef GET_ATTR
1084 "
1085    (gen-define-with-symcat "GET_ATTR(cpu, num, attr) \
1086 CGEN_ATTR_VALUE (NULL, abuf->idesc->attrs, CGEN_INSN_" "attr)")
1087 "
1088 /* This is used so that we can compile two copies of the semantic code,
1089    one with full feature support and one without that runs fast(er).
1090    FAST_P, when desired, is defined on the command line, -DFAST_P=1.  */
1091 #if FAST_P
1092 #define SEM_FN_NAME(cpu,fn) XCONCAT3 (cpu,_semf_,fn)
1093 #undef TRACE_RESULT
1094 #define TRACE_RESULT(cpu, abuf, name, type, val)
1095 #else
1096 #define SEM_FN_NAME(cpu,fn) XCONCAT3 (cpu,_sem_,fn)
1097 #endif
1098 \n"
1099
1100    /gen-all-semantic-fns
1101    ; Put the table at the end so we don't have to declare all the sem fns.
1102    /gen-semantic-fn-table
1103    )
1104 )
1105
1106 ; Generate sem-switch.c.
1107 ; Each instruction is a case in a switch().
1108 ; This file consists of just the switch().  It is included by mainloop.c.
1109
1110 (define (cgen-sem-switch.c)
1111   (logit 1 "Generating " (gen-cpu-name) "'s sem-switch.c ...\n")
1112
1113   (sim-analyze-insns!)
1114
1115   ; Turn parallel execution support off.
1116   ; It is later turned on/off when generating the actual semantic code.
1117   (set-with-parallel?! #f)
1118
1119   ; Tell the rtx->c translator we are the simulator.
1120   (rtl-c-config! #:rtl-cover-fns? #t)
1121
1122   (string-write
1123    (gen-c-copyright "Simulator instruction semantics for @cpu@."
1124                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
1125
1126    "\
1127 #ifdef DEFINE_LABELS
1128
1129   /* The labels have the case they have because the enum of insn types
1130      is all uppercase and in the non-stdc case the insn symbol is built
1131      into the enum name.  */
1132
1133   static struct {
1134     int index;
1135     void *label;
1136   } labels[] = {\n"
1137
1138    (lambda ()
1139      (string-write-map (lambda (insn)
1140                          (string-append "    { "
1141                                         "@PREFIX@_INSN_"
1142                                         (string-upcase (gen-sym insn))
1143                                         ", && case_sem_INSN_"
1144                                         (string-upcase (gen-sym insn))
1145                                         " },\n"))
1146                        (non-alias-insns (current-insn-list))))
1147
1148    (if (state-parallel-exec?)
1149        (lambda ()
1150          (string-write-map (lambda (insn)
1151                              (string-append "    { "
1152                                             "@CPU@_INSN_PAR_"
1153                                             (string-upcase (gen-sym insn))
1154                                             ", && case_sem_INSN_PAR_"
1155                                             (string-upcase (gen-sym insn))
1156                                             " },\n"
1157                                             "    { "
1158                                             "@CPU@_INSN_WRITE_"
1159                                             (string-upcase (gen-sym insn))
1160                                             ", && case_sem_INSN_WRITE_"
1161                                             (string-upcase (gen-sym insn))
1162                                             " },\n"))
1163                            (parallel-insns (current-insn-list))))
1164        "")
1165
1166    "    { 0, 0 }
1167   };
1168   int i;
1169
1170   for (i = 0; labels[i].label != 0; ++i)
1171     {
1172 #if FAST_P
1173       CPU_IDESC (current_cpu) [labels[i].index].sem_fast_lab = labels[i].label;
1174 #else
1175       CPU_IDESC (current_cpu) [labels[i].index].sem_full_lab = labels[i].label;
1176 #endif
1177     }
1178
1179 #undef DEFINE_LABELS
1180 #endif /* DEFINE_LABELS */
1181
1182 #ifdef DEFINE_SWITCH
1183
1184 /* If hyper-fast [well not unnecessarily slow] execution is selected, turn
1185    off frills like tracing and profiling.  */
1186 /* FIXME: A better way would be to have TRACE_RESULT check for something
1187    that can cause it to be optimized out.  Another way would be to emit
1188    special handlers into the instruction \"stream\".  */
1189
1190 #if FAST_P
1191 #undef TRACE_RESULT
1192 #define TRACE_RESULT(cpu, abuf, name, type, val)
1193 #endif
1194
1195 #undef GET_ATTR
1196 "
1197    (gen-define-with-symcat "GET_ATTR(cpu, num, attr) \
1198 CGEN_ATTR_VALUE (NULL, abuf->idesc->attrs, CGEN_INSN_" "attr)")
1199 "
1200 {
1201
1202 #if WITH_SCACHE_PBB
1203
1204 /* Branch to next handler without going around main loop.  */
1205 #define NEXT(vpc) goto * SEM_ARGBUF (vpc) -> semantic.sem_case
1206 SWITCH (sem, SEM_ARGBUF (vpc) -> semantic.sem_case)
1207
1208 #else /* ! WITH_SCACHE_PBB */
1209
1210 #define NEXT(vpc) BREAK (sem)
1211 #ifdef __GNUC__
1212 #if FAST_P
1213   SWITCH (sem, SEM_ARGBUF (sc) -> idesc->sem_fast_lab)
1214 #else
1215   SWITCH (sem, SEM_ARGBUF (sc) -> idesc->sem_full_lab)
1216 #endif
1217 #else
1218   SWITCH (sem, SEM_ARGBUF (sc) -> idesc->num)
1219 #endif
1220
1221 #endif /* ! WITH_SCACHE_PBB */
1222
1223     {
1224
1225 "
1226
1227    /gen-sem-switch
1228
1229    (if (state-parallel-exec?)
1230        /gen-parallel-sem-switch
1231        "")
1232
1233    "
1234     }
1235   ENDSWITCH (sem) /* End of semantic switch.  */
1236
1237   /* At this point `vpc' contains the next insn to execute.  */
1238 }
1239
1240 #undef DEFINE_SWITCH
1241 #endif /* DEFINE_SWITCH */
1242 "
1243    )
1244 )
1245
1246 ; Generate mainloop.in.
1247 ; ??? Not currently used.
1248
1249 (define (cgen-mainloop.in)
1250   (logit 1 "Generating mainloop.in ...\n")
1251
1252   (string-write
1253    "cat <<EOF >/dev/null\n"
1254    (gen-c-copyright "Simulator main loop for @arch@."
1255                   CURRENT-COPYRIGHT CURRENT-PACKAGE)
1256    "EOF\n"
1257    "\
1258
1259 # Syntax:
1260 # /bin/sh mainloop.in init|support|{full,fast}-{extract,exec}-{scache,nocache}
1261
1262 # ??? There's lots of conditional compilation here.
1263 # After a few more ports are done, revisit.
1264
1265 case \"x$1\" in
1266
1267 xsupport)
1268
1269 cat <<EOF
1270 /*xsupport*/
1271 EOF
1272
1273 ;;
1274
1275 xinit)
1276
1277 cat <<EOF
1278 /*xinit*/
1279 EOF
1280
1281 ;;
1282
1283 xfull-extract-* | xfast-extract-*)
1284
1285 cat <<EOF
1286 {
1287 "
1288    (rtl-c VOID #f nil insn-extract #:rtl-cover-fns? #t)
1289 "}
1290 EOF
1291
1292 ;;
1293
1294 xfull-exec-* | xfast-exec-*)
1295
1296 cat <<EOF
1297 {
1298 "
1299    (rtl-c VOID #f nil insn-execute #:rtl-cover-fns? #t)
1300 "}
1301 EOF
1302
1303 ;;
1304
1305 *)
1306   echo \"Invalid argument to mainloop.in: $1\" >&2
1307   exit 1
1308   ;;
1309
1310 esac
1311 "
1312    )
1313 )