OSDN Git Service

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