1 ; CPU family related simulator generator, excluding decoding and model support.
2 ; Copyright (C) 2000 Red Hat, Inc.
3 ; This file is part of CGEN.
9 (string-upcase (gen-c-symbol (caar (list-take -1
10 (gen-obj-list-enums (non-multi-insns (current-insn-list))))))))
12 ; Declare the attributes.
14 (define (-gen-attr-decls)
16 "// Insn attribute indices.\n\n"
17 (gen-attr-enum-decl "cgen_insn" (current-insn-attr-list))
19 (string-list-map gen-decl (current-attr-list))
23 ; Generate class to hold an instruction's attributes.
25 (define (-gen-insn-attr-decls)
26 (let ((attrs (current-insn-attr-list)))
28 "// Insn attributes.\n\n"
29 ; FIXME: maybe make class, but that'll require a constructor. Later.
30 "struct @arch@_insn_attr {\n"
31 " unsigned int bools;\n"
32 (string-map (lambda (attr)
38 (string-downcase (gen-sym attr))
42 (string-map (lambda (attr)
46 " get_" (string-downcase (gen-sym attr)) "_attr"
49 (string-append "(bools & "
50 (gen-attr-mask "cgen_insn" (obj:name attr))
52 (string-downcase (gen-sym attr)))
61 ; Emit a macro that specifies the word-bitsize for each machine.
62 (define (-gen-mach-params)
63 (string-map (lambda (mach)
65 "#define MACH_" (string-upcase (gen-sym mach)) "_INSN_CHUNK_BITSIZE "
66 (number->string (cpu-insn-chunk-bitsize (mach-cpu mach))) "\n"))
71 ; Generate <cpu>-desc.h.
74 (logit 1 "Generating " (gen-cpu-name) " desc.h ...\n")
77 (gen-copyright "Misc. entries in the @arch@ description file."
78 copyright-cygnus package-cygnus-simulators)
87 (lambda () (string-map gen-decl (current-enum-list)))
94 } // end @arch@ namespace
96 #endif /* DESC_@ARCH@_H */\n"
103 ; Print out file containing elements to add to cpu class.
105 ; Get/set fns for hardware element HW.
107 (define (-gen-reg-access-defns hw)
108 (let ((scalar? (hw-scalar? hw))
110 (getter (hw-getter hw))
111 (setter (hw-setter hw))
112 (isas (bitset-attr->list (obj-attr-value hw 'ISA)))
113 (type (gen-type hw)))
114 (let ((get-code (if getter
115 (let ((mode (hw-mode hw))
117 (expr (cadr getter)))
123 (list (list (car args) 'UINT "regno")))
127 "return this->hardware."
129 (if scalar? "" "[regno]")
132 (let ((args (car setter))
133 (expr (cadr setter)))
135 VOID ; not `mode', sets have mode VOID
138 (list (list (car args) (hw-mode hw) "newval"))
139 (list (list (car args) 'UINT "regno")
140 (list (cadr args) (hw-mode hw) "newval")))
141 #:rtl-cover-fns? #t))
145 (if scalar? "" "[regno]")
149 (gen-reg-get-fun-name hw)
151 (if scalar? "" "UINT regno")
156 (gen-reg-set-fun-name hw)
158 (if scalar? "" "UINT regno, ")
164 ; Return a boolean indicating if hardware element HW needs storage allocated
165 ; for it in the SIM_CPU struct.
167 (define (hw-need-storage? hw)
169 (not (obj-has-attr? hw 'VIRTUAL)))
172 ; Subroutine of -gen-hardware-types to generate the struct containing
173 ; hardware elements of one isa.
175 (define (-gen-hardware-struct prefix hw-list)
177 ; If struct is empty, leave it out to simplify generated code.
181 (string-append " // Hardware elements for " prefix ".\n")
182 " // Hardware elements.\n")
184 (string-list-map gen-decl hw-list)
187 (string-append prefix "_")
193 ; Return C type declarations of all of the hardware elements.
194 ; The name of the type is prepended with the cpu family name.
196 (define (-gen-hardware-types)
198 "// CPU state information.\n\n"
199 (if (with-multiple-isa?)
200 (let ((keep-isas (current-keep-isa-name-list))
201 (candidates (find hw-need-storage? (current-hw-list))))
203 ; First emit a struct that contains all the common elements.
204 ; A common element is one supported by more than isa.
205 (-gen-hardware-struct #f
210 (obj-attr-value hw 'ISA)))
213 ; Now emit structs for each isa. These contain entries for elements
214 ; supported by exactly one isa.
215 (string-list-map (lambda (isa)
216 (-gen-hardware-struct
222 (obj-attr-value hw 'ISA)))
227 (-gen-hardware-struct #f (find hw-need-storage? (current-hw-list))))
231 ; Generate <cpu>-cpu.h
234 (logit 1 "Generating " (gen-cpu-name) " cpu.h ...\n")
237 ; Turn parallel execution support on if cpu needs it.
238 (set-with-parallel?! (state-parallel-exec?))
240 ; Initialize rtl->c generation.
241 (rtl-c-config! #:rtl-cover-fns? #t)
244 (gen-copyright "CPU class elements for @cpu@."
245 copyright-cygnus package-cygnus-simulators)
247 // This file is included in the middle of the cpu class struct.
254 " // C++ register access function templates\n"
255 "#define current_cpu this\n\n"
257 (string-list-map -gen-reg-access-defns
258 (find register? (current-hw-list))))
259 "#undef current_cpu\n\n"
266 ; Print various parameters of the cpu family.
267 ; A "cpu family" here is a collection of variants of a particular architecture
268 ; that share sufficient commonality that they can be handled together.
270 (define (-gen-cpu-defines)
273 /* Maximum number of instructions that are fetched at a time.
274 This is for LIW type instructions sets (e.g. m32r). */\n"
275 "#define @CPU@_MAX_LIW_INSNS " (number->string (cpu-liw-insns (current-cpu))) "\n\n"
276 "/* Maximum number of instructions that can be executed in parallel. */\n"
277 "#define @CPU@_MAX_PARALLEL_INSNS " (number->string (cpu-parallel-insns (current-cpu))) "\n"
279 ; (gen-enum-decl '@prefix@_virtual
280 ; "@prefix@ virtual insns"
281 ; "@ARCH@_INSN_" ; not @CPU@ to match CGEN_INSN_TYPE in opc.h
283 ; (x-before -1) (x-after -2)
284 ; (x-begin -3) (x-chain -4) (x-cti-chain -5)))
288 ; Generate type of struct holding model state while executing.
290 (define (-gen-model-decls)
291 (logit 2 "Generating model decls ...\n")
297 (if (null? (model:state model))
299 (string-map (lambda (var)
301 (mode:c-type (mode:lookup (cadr var)))
303 (gen-c-symbol (car var))
305 (model:state model)))
307 (if (null? (model:state model)) "BLANK" "@CPU@") "_MODEL_DATA;\n\n"
309 (current-model-list))
311 typedef int (@CPU@_MODEL_FN) (struct @cpu@_cpu*, void*);
314 /* This is an integer that identifies this insn.
315 How this works is up to the target. */
318 /* Function to handle insn-specific profiling. */
319 @CPU@_MODEL_FN *model_fn;
321 /* Array of function units used by this insn. */
322 UNIT units[MAX_UNITS];
323 } @CPU@_INSN_TIMING;"
327 ; Utility of gen-parallel-exec-type to generate the definition of one
328 ; structure in PAREXEC.
329 ; SFMT is an <sformat> object.
331 (define (gen-parallel-exec-elm sfmt)
333 " struct { /* " (obj:comment sfmt) " */\n"
335 ((if (with-parallel-write?) sfmt-out-ops sfmt-in-ops) sfmt)))
340 (logit 2 "Processing operand " (obj:name op) " of format "
341 (obj:name sfmt) " ...\n")
342 (if (with-parallel-write?)
343 (let ((index-type (and (op-save-index? op)
344 (gen-index-type op sfmt))))
345 (string-append " " (gen-type op)
346 " " (gen-sym op) ";\n"
348 (string-append " " index-type
349 " " (gen-sym op) "_idx;\n")
357 " } " (gen-sym sfmt) ";\n"
361 ; Generate the definition of the structure that holds register values, etc.
362 ; for use during parallel execution. When instructions are executed parallelly
364 ; - their inputs are read before their outputs are written. Thus we have to
365 ; fetch the input values of several instructions before executing any of them.
366 ; - or their outputs are queued here first and then written out after all insns
368 ; The fetched/queued values are stored in an array of PAREXEC structs, one
369 ; element per instruction.
371 (define (gen-parallel-exec-type)
372 (logit 2 "Generating PAREXEC type ...\n")
374 (if (with-parallel-write?)
375 "/* Queued output values of an instruction. */\n"
376 "/* Fetched input values of an instruction. */\n")
379 struct @prefix@_parexec {
381 (string-map gen-parallel-exec-elm (current-sfmt-list))
384 /* For conditionally written operands, bitmask of which ones were. */
385 unsigned long long written;
390 ; Generate the TRACE_RECORD struct definition.
392 (define (-gen-trace-record-type)
395 /* Collection of various things for the trace handler to use. */
397 typedef struct @prefix@_trace_record {
400 } @CPU@_TRACE_RECORD;
405 ; Generate <cpu>-defs.h
407 (define (cgen-defs.h)
408 (logit 1 "Generating " (gen-cpu-name) " defs.h ...\n")
411 ; Turn parallel execution support on if cpu needs it.
412 (set-with-parallel?! (state-parallel-exec?))
414 ; Initialize rtl->c generation.
415 (rtl-c-config! #:rtl-cover-fns? #t)
418 (gen-copyright "CPU family header for @cpu@ / @prefix@."
419 copyright-cygnus package-cygnus-simulators)
421 #ifndef DEFS_@PREFIX@_H
422 #define DEFS_@PREFIX@_H
428 gen-parallel-exec-type
432 } // end @cpu@ namespace
434 #endif /* DEFS_@PREFIX@_H */\n"
441 ; This is the other way of implementing parallel execution support.
442 ; Instead of fetching all the input operands first, write all the output
443 ; operands and their addresses to holding variables, and then run a
444 ; post-processing pass to update the cpu state.
446 ; Return C code to fetch and save all output operands to instructions with
449 (define (-gen-write-args sfmt)
450 (string-map (lambda (op) (op:write op sfmt))
454 ; Utility of gen-write-fns to generate a writer function for <sformat> SFMT.
456 (define (-gen-write-fn sfmt)
457 (logit 2 "Processing write function for \"" (obj:name sfmt) "\" ...\n")
460 (-gen-write-fn-name sfmt) " (@cpu@_cpu* current_cpu, @prefix@_scache* sem, @prefix@_parexec* par_exec)\n"
463 (gen-define-field-macro sfmt)
465 (gen-define-parallel-operand-macro sfmt)
466 " @prefix@_scache* abuf = sem;\n"
467 " unsigned long long written = abuf->written;\n"
468 " PCADDR pc = abuf->addr;\n"
469 " PCADDR npc = 0; // dummy value for branches\n"
470 " sem_status status = SEM_STATUS_NORMAL; // ditto\n"
472 (-gen-write-args sfmt)
475 (gen-undef-parallel-operand-macro sfmt)
477 (gen-undef-field-macro sfmt)
482 (define (-gen-write-fns)
483 (logit 2 "Processing writer functions ...\n")
484 (string-write-map (lambda (sfmt) (-gen-write-fn sfmt))
489 ; Generate <cpu>-write.cxx.
491 (define (cgen-write.cxx)
492 (logit 1 "Generating " (gen-cpu-name) " write.cxx ...\n")
497 ; Turn parallel execution support off.
498 (set-with-parallel?! #f)
500 ; Tell the rtx->c translator we are the simulator.
501 (rtl-c-config! #:rtl-cover-fns? #t)
504 (gen-copyright (string-append "Simulator instruction operand writer for "
505 (current-arch-name) ".")
506 copyright-cygnus package-cygnus-simulators)
510 using namespace @cpu@;
520 ; Return C code to perform the semantics of INSN.
522 (define (gen-semantic-code insn)
523 ; Indicate generating code for INSN.
524 ; Use the compiled form if available.
525 ; The case when they're not available is for virtual insns.
527 (if (insn-compiled-semantics insn)
528 (rtl-c++-parsed VOID (insn-compiled-semantics insn) nil
531 (rtl-c++ VOID (insn-semantics insn) nil
538 ; Return definition of C function to perform INSN.
539 ; This version handles the with-scache case.
541 (define (-gen-scache-semantic-fn insn)
542 (logit 2 "Processing semantics for " (obj:name insn) ": \"" (insn-syntax insn) "\" ...\n")
543 (set! -with-profile? -with-profile-fn?)
544 (let ((cti? (insn-cti? insn))
545 (insn-len (insn-length-bytes insn)))
547 "// ********** " (obj:name insn) ": " (insn-syntax insn) "\n\n"
551 "@prefix@_sem_" (gen-sym insn)
553 " (@cpu@_cpu* current_cpu, @prefix@_scache* sem, @prefix@_parexec* par_exec)\n"
554 " (@cpu@_cpu* current_cpu, @prefix@_scache* sem)\n")
556 (gen-define-field-macro (insn-sfmt insn))
558 (gen-define-parallel-operand-macro (insn-sfmt insn))
560 " sem_status status = SEM_STATUS_NORMAL;\n"
561 " @prefix@_scache* abuf = sem;\n"
562 ; Unconditionally written operands are not recorded here.
563 (if (or (with-profile?) (with-parallel-write?))
564 " unsigned long long written = 0;\n"
566 ; The address of this insn, needed by extraction and semantic code.
567 ; Note that the address recorded in the cpu state struct is not used.
568 ; For faster engines that copy will be out of date.
569 " PCADDR pc = abuf->addr;\n"
570 " PCADDR npc = pc + " (number->string insn-len) ";\n"
572 (gen-semantic-code insn)
574 ; Only update what's been written if some are conditionally written.
575 ; Otherwise we know they're all written so there's no point in
577 (if (or (with-profile?) (with-parallel-write?))
578 (if (-any-cond-written? (insn-sfmt insn))
579 " abuf->written = written;\n"
583 " current_cpu->done_cti_insn (npc, status);\n"
584 " current_cpu->done_insn (npc, status);\n")
589 (gen-undef-parallel-operand-macro (insn-sfmt insn))
591 (gen-undef-field-macro (insn-sfmt insn))
596 (define (-gen-all-semantic-fns)
597 (logit 2 "Processing semantics ...\n")
598 (let ((insns (scache-engine-insns)))
600 (string-write-map -gen-scache-semantic-fn insns)
601 (error "must specify `with-scache'")))
604 ; Generate <cpu>-sem.cxx.
605 ; Each instruction is implemented in its own function.
607 (define (cgen-semantics.cxx)
608 (logit 1 "Generating " (gen-cpu-name) " semantics.cxx ...\n")
613 ; Turn parallel execution support on if cpu needs it.
614 (set-with-parallel?! (state-parallel-exec?))
616 ; Tell the rtx->c translator we are the simulator.
617 (rtl-c-config! #:rtl-cover-fns? #t)
619 ; Indicate we're currently not generating a pbb engine.
620 (set-current-pbb-engine?! #f)
623 (gen-copyright "Simulator instruction semantics for @prefix@."
624 copyright-cygnus package-cygnus-simulators)
629 using namespace @cpu@; // FIXME: namespace organization still wip
631 #define GET_ATTR(name) GET_ATTR_##name ()
635 -gen-all-semantic-fns
639 ; *******************
640 ; cgen-sem-switch.cxx
642 ; The semantic switch engine has two flavors: one case per insn, and one
643 ; case per "frag" (where each insn is split into one or more fragments).
645 ; Utility of -gen-sem-case to return the mask of operands always written
646 ; to in <sformat> SFMT.
647 ; ??? Not currently used.
649 (define (-uncond-written-mask sfmt)
650 (apply + (map (lambda (op)
653 (logsll 1 (op:num op))))
654 (sfmt-out-ops sfmt)))
657 ; Utility of -gen-sem-case to return #t if any operand in <sformat> SFMT is
658 ; conditionally written to.
660 (define (-any-cond-written? sfmt)
661 (any-true? (map op:cond? (sfmt-out-ops sfmt)))
664 ; One case per insn version.
666 ; Generate a switch case to perform INSN.
668 (define (-gen-sem-case insn parallel?)
669 (logit 2 "Processing "
670 (if parallel? "parallel " "")
671 "semantic switch case for \"" (insn-syntax insn) "\" ...\n")
672 (set! -with-profile? -with-profile-sw?)
673 (let ((cti? (insn-cti? insn))
674 (insn-len (insn-length-bytes insn)))
676 ; INSN_ is prepended here and not elsewhere to avoid name collisions
677 ; with symbols like AND, etc.
679 // ********** " (insn-syntax insn) "
681 CASE (INSN_" (if parallel? "PAR_" "") (string-upcase (gen-sym insn)) "):
683 @prefix@_scache* abuf = vpc;\n"
685 (gen-define-field-macro (insn-sfmt insn))
688 (gen-define-parallel-operand-macro (insn-sfmt insn))
690 ; Unconditionally written operands are not recorded here.
691 (if (or (with-profile?) (with-parallel-write?))
692 " unsigned long long written = 0;\n"
694 ; The address of this insn, needed by extraction and semantic code.
695 ; Note that the address recorded in the cpu state struct is not used.
696 " PCADDR pc = abuf->addr;\n"
697 (if (and cti? (not parallel?))
698 (string-append " PCADDR npc;\n"
699 " branch_status br_status = BRANCH_UNTAKEN;\n")
701 (string-list " vpc = vpc + 1;\n")
702 ; Emit setup-semantics code for real insns.
703 (if (and (insn-real? insn)
704 (isa-setup-semantics (current-isa)))
707 (rtl-c++ VOID (isa-setup-semantics (current-isa)) nil
712 (gen-semantic-code insn)
714 ; Only update what's been written if some are conditionally written.
715 ; Otherwise we know they're all written so there's no point in
717 (if (or (with-profile?) (with-parallel-write?))
718 (if (-any-cond-written? (insn-sfmt insn))
719 " abuf->written = written;\n"
722 (if (and cti? (not parallel?))
723 (string-append " pbb_br_npc = npc;\n"
724 " pbb_br_status = br_status;\n")
727 (gen-undef-parallel-operand-macro (insn-sfmt insn))
730 (gen-undef-field-macro (insn-sfmt insn))
737 (define (-gen-sem-switch)
738 (logit 2 "Processing semantic switch ...\n")
739 ; Turn parallel execution support off.
740 (set-with-parallel?! #f)
741 (string-write-map (lambda (insn) (-gen-sem-case insn #f))
742 (non-multi-insns (non-alias-insns (current-insn-list))))
745 ; Generate the guts of a C switch statement to execute parallel instructions.
746 ; This switch is included after the non-parallel instructions in the semantic
749 ; ??? We duplicate the writeback case for each insn, even though we only need
750 ; one case per insn format. The former keeps the code for each insn
751 ; together and might improve cache usage. On the other hand the latter
752 ; reduces the amount of code, though it is believed that in this particular
753 ; instance the win isn't big enough.
755 (define (-gen-parallel-sem-switch)
756 (logit 2 "Processing parallel insn semantic switch ...\n")
757 ; Turn parallel execution support on.
758 (set-with-parallel?! #t)
759 (string-write-map (lambda (insn)
760 (string-list (-gen-sem-case insn #t)
761 (-gen-write-case (insn-sfmt insn) insn)))
762 (parallel-insns (current-insn-list)))
765 ; Return computed-goto engine.
767 (define (-gen-sem-switch-engine)
771 @cpu@_cpu::@prefix@_pbb_run ()
773 @cpu@_cpu* current_cpu = this;
774 @prefix@_scache* vpc;
775 // These two are used to pass data from cti insns to the cti-chain insn.
777 branch_status pbb_br_status;
781 static const struct sem_labels
783 enum @prefix@_insn_type insn;
790 (string-write-map (lambda (insn)
793 (string-upcase (gen-sym insn))
795 (string-upcase (gen-sym insn))
797 (non-multi-insns (non-alias-insns (current-insn-list)))))
799 (if (state-parallel-exec?)
801 (string-write-map (lambda (insn)
804 (string-upcase (gen-sym insn))
805 ", && case_INSN_PAR_"
806 (string-upcase (gen-sym insn))
809 "@PREFIX@_INSN_WRITE_"
810 (string-upcase (gen-sym insn))
811 ", && case_INSN_WRITE_"
812 (string-upcase (gen-sym insn))
814 (parallel-insns (current-insn-list))))
817 " { (@prefix@_insn_type) 0, 0 }
820 if (! @prefix@_idesc::idesc_table_initialized_p)
822 for (int i=0; labels[i].label != 0; i++)
823 @prefix@_idesc::idesc_table[labels[i].insn].cgoto.label = labels[i].label;
825 // confirm that table is all filled up
826 for (int i = 0; i <= @PREFIX@_INSN_" (-last-insn) "; i++)
827 assert (@prefix@_idesc::idesc_table[i].cgoto.label != 0);
829 // Initialize the compiler virtual insn.
830 current_cpu->@prefix@_engine.compile_begin_insn (current_cpu);
832 @prefix@_idesc::idesc_table_initialized_p = true;
838 #define CASE(X) case_##X
839 // Branch to next handler without going around main loop.
840 #define NEXT(vpc) goto * vpc->execute.cgoto.label;
841 // Break out of threaded interpreter and return to \"main loop\".
842 #define BREAK(vpc) goto end_switch
844 #define CASE(X) case @PREFIX@_##X
845 #define NEXT(vpc) goto restart
846 #define BREAK(vpc) break
849 // Get next insn to execute.
850 vpc = current_cpu->@prefix@_engine.get_next_vpc (current_cpu->h_pc_get ());
854 goto * vpc->execute.cgoto.label;
856 switch (vpc->idesc->sem_index)
864 (if (state-parallel-exec?)
865 -gen-parallel-sem-switch
876 // Save vpc for next time.
877 current_cpu->@prefix@_engine.set_next_vpc (vpc);
883 ; Semantic frag version.
885 ; Return declaration of frag enum.
887 (define (-gen-sfrag-enum-decl frag-list)
888 (gen-enum-decl "@prefix@_frag_type"
889 "semantic fragments in cpu family @prefix@"
891 (append '((list-end))
895 (atlist-attrs (obj-atlist i)))))
900 ; Return header file decls for semantic frag threaded engine.
902 (define (-gen-sfrag-engine-decls)
904 "namespace @cpu@ {\n\n"
906 ; FIXME: vector->list
907 (-gen-sfrag-enum-decl (vector->list (sim-sfrag-frag-table)))
910 struct @prefix@_insn_frag {
911 @PREFIX@_INSN_TYPE itype;
912 // 4: header+middle+trailer+delimiter
913 @PREFIX@_FRAG_TYPE ftype[4];
916 struct @prefix@_pbb_label {
917 @PREFIX@_FRAG_TYPE frag;
921 } // end @cpu@ namespace
925 ; Return C code to perform the semantics of FRAG.
926 ; LOCALS is a list of sequence locals made global to all frags.
927 ; Each element is (symbol <mode> "c-var-name").
929 (define (-gen-sfrag-code frag locals)
930 ; Indicate generating code for FRAG.
931 ; Use the compiled form if available.
932 ; The case when they're not available is for virtual insns.
933 (let ((sem (sfrag-compiled-semantics frag))
934 ; If the frag has one owner, use it. Otherwise indicate the owner is
935 ; unknown. In cases where the owner is needed by the semantics, the
936 ; frag should have only one owner.
937 (owner (if (= (length (sfrag-users frag)) 1)
938 (car (sfrag-users frag))
942 (rtl-c++-parsed VOID sem locals
945 (rtl-c++ VOID (sfrag-semantics frag) locals
950 ; Generate a switch case to perform FRAG.
951 ; LOCALS is a list of sequence locals made global to all frags.
952 ; Each element is (symbol <mode> "c-var-name").
954 (define (-gen-sfrag-case frag locals)
955 (set! -with-profile? -with-profile-sw?)
956 (let ((cti? (sfmt-cti? (sfrag-sfmt frag)))
957 (parallel? (sfrag-parallel? frag)))
958 (logit 2 "Processing "
959 (if parallel? "parallel " "")
960 "semantic switch case for \"" (obj:name frag) "\" ...\n")
962 ; FRAG_ is prepended here and not elsewhere to avoid name collisions
963 ; with symbols like AND, etc.
966 (if (= (length (sfrag-users frag)) 1)
970 (string-map (lambda (user)
971 (string-append ", " (obj:name user)))
975 CASE (FRAG_" (string-upcase (gen-sym frag)) "):
977 (if (sfrag-header? frag)
978 (string-append " abuf = vpc;\n"
981 (gen-define-field-macro (sfrag-sfmt frag))
983 (gen-define-parallel-operand-macro (sfrag-sfmt frag))
985 ; Unconditionally written operands are not recorded here.
986 (if (or (with-profile?) (with-parallel-write?))
987 " unsigned long long written = 0;\n"
989 ; The address of this insn, needed by extraction and semantic code.
990 ; Note that the address recorded in the cpu state struct is not used.
991 " PCADDR pc = abuf->addr;\n"
994 (sfrag-header? frag))
995 (string-append ; " npc = 0;\n" ??? needed?
996 " br_status = BRANCH_UNTAKEN;\n")
998 ; Emit setup-semantics code for headers of real insns.
999 (if (and (sfrag-header? frag)
1000 (not (obj-has-attr? frag 'VIRTUAL))
1001 (isa-setup-semantics (current-isa)))
1004 (rtl-c++ VOID (isa-setup-semantics (current-isa)) nil
1009 (-gen-sfrag-code frag locals)
1011 ; Only update what's been written if some are conditionally written.
1012 ; Otherwise we know they're all written so there's no point in
1014 (if (or (with-profile?) (with-parallel-write?))
1015 (if (-any-cond-written? (sfrag-sfmt frag))
1016 " abuf->written = written;\n"
1021 (sfrag-trailer? frag))
1022 (string-append " pbb_br_npc = npc;\n"
1023 " pbb_br_status = br_status;\n")
1026 (gen-undef-parallel-operand-macro (sfrag-sfmt frag))
1028 (gen-undef-field-macro (sfrag-sfmt frag))
1030 (if (sfrag-trailer? frag)
1031 " NEXT_INSN (vpc, fragpc);\n"
1032 " NEXT_FRAG (fragpc);\n")
1037 ; Convert locals from form computed by sem-find-common-frags to that needed by
1038 ; -gen-sfrag-engine-code (and ultimately rtl-c++).
1040 (define (-frag-convert-c-locals locals)
1041 (map (lambda (local)
1042 (list (car local) (mode:lookup (cadr local))
1043 (gen-c-symbol (car local))))
1047 ; Return definition of insn frag usage table.
1049 (define (-gen-sfrag-engine-frag-table insn-list frag-table frag-usage)
1052 // Table of frags used by each insn.
1054 const @prefix@_insn_frag @prefix@_frag_usage[] = {\n"
1057 (for-each (lambda (insn frag-nums)
1060 (string-upcase (gen-sym insn))
1061 (string-map (lambda (frag-num)
1062 (string-append ", @PREFIX@_FRAG_"
1063 (string-upcase (gen-sym (vector-ref frag-table frag-num)))))
1065 ", @PREFIX@_FRAG_LIST_END },\n"))
1066 insn-list frag-usage)
1071 ; Return sfrag computed-goto engine.
1072 ; LOCALS is a list of sequence locals made global to all frags.
1073 ; Each element is (symbol <mode> "c-var-name").
1075 (define (-gen-sfrag-engine-fn frag-table locals)
1079 @cpu@_cpu::@prefix@_pbb_run ()
1081 @cpu@_cpu* current_cpu = this;
1082 @prefix@_scache* vpc;
1083 @prefix@_scache* abuf;
1087 ARM_FRAG_TYPE* fragpc;
1092 static const @prefix@_pbb_label labels[] =
1094 { @PREFIX@_FRAG_LIST_END, 0 },
1098 (string-write-map (lambda (frag)
1099 (string-append " { "
1101 (string-upcase (gen-sym frag))
1103 (string-upcase (gen-sym frag))
1105 ; FIXME: vector->list
1106 (vector->list frag-table)))
1109 { @PREFIX@_FRAG_MAX, 0 }
1112 if (! @prefix@_idesc::idesc_table_initialized_p)
1114 // Several tables are in play here:
1115 // idesc table: const table of misc things for each insn
1116 // frag usage table: const set of frags used by each insn
1117 // frag label table: same as frag usage table, but contains labels
1118 // selected insn frag table: table of pointers to either the frag usage
1119 // table (if !gnuc) or frag label table (if gnuc) for the currently
1120 // selected ISA. Insns not in the ISA are redirected to the `invalid'
1121 // insn handler. FIXME: This one isn't implemented yet.
1123 // Allocate frag label table and point idesc table entries at it.
1124 // FIXME: Temporary hack, to be redone.
1125 static void** frag_label_table;
1126 int max_insns = @PREFIX@_INSN_" (-last-insn) " + 1;
1127 int tabsize = max_insns * 4;
1128 frag_label_table = new (void*) [tabsize];
1129 memset (frag_label_table, 0, sizeof (void*) * tabsize);
1132 for (i = 0, v = frag_label_table; i < max_insns; ++i)
1134 @prefix@_idesc::idesc_table[@prefix@_frag_usage[i].itype].cgoto.frags = v;
1135 for (int j = 0; @prefix@_frag_usage[i].ftype[j] != @PREFIX@_FRAG_LIST_END; ++j)
1136 *v++ = labels[@prefix@_frag_usage[i].ftype[j]].label;
1139 // Initialize the compiler virtual insn.
1140 // FIXME: Also needed if !gnuc.
1141 current_cpu->@prefix@_engine.compile_begin_insn (current_cpu);
1143 @prefix@_idesc::idesc_table_initialized_p = true;
1149 #define CASE(X) case_##X
1150 // Branch to next handler without going around main loop.
1151 #define NEXT_INSN(vpc, fragpc) fragpc = vpc->execute.cgoto.frags; goto * *fragpc
1152 #define NEXT_FRAG(fragpc) ++fragpc; goto * *fragpc
1153 // Break out of threaded interpreter and return to \"main loop\".
1154 #define BREAK(vpc) goto end_switch
1156 #define CASE(X) case @PREFIX@_##X
1157 #define NEXT_INSN(vpc, fragpc) fragpc = vpc->idesc->frags; goto restart
1158 #define NEXT_FRAG(fragpc) ++fragpc; goto restart
1159 #define BREAK(vpc) break
1162 // Get next insn to execute.
1163 vpc = current_cpu->@prefix@_engine.get_next_vpc (current_cpu->h_pc_get ());
1166 // These two are used to pass data from cti insns to the cti-chain insn.
1168 branch_status pbb_br_status;
1169 // These two are used to build up values of the previous two.
1171 branch_status br_status;
1172 // Top level locals moved here so they're usable by multiple fragments.
1176 (string-write-map (lambda (local)
1178 (mode:c-type (cadr local))
1188 fragpc = vpc->execute.cgoto.frags;
1191 fragpc = vpc->idesc->frags;
1200 ; Turn parallel execution support off.
1202 (set-with-parallel?! #f)
1203 (string-write-map (lambda (frag)
1204 (-gen-sfrag-case frag locals))
1205 ; FIXME: vector->list
1206 (vector->list frag-table)))
1217 // Save vpc for next time.
1218 current_cpu->@prefix@_engine.set_next_vpc (vpc);
1223 (define (-gen-sfrag-engine)
1226 (-gen-sfrag-engine-frag-table (sim-sfrag-insn-list)
1227 (sim-sfrag-frag-table)
1228 (sim-sfrag-usage-table)))
1230 (-gen-sfrag-engine-fn (sim-sfrag-frag-table)
1231 (-frag-convert-c-locals (sim-sfrag-locals-list))))
1235 ; Generate sem-switch.cxx.
1237 (define (cgen-sem-switch.cxx)
1238 (logit 1 "Generating " (gen-cpu-name) " sem-switch.cxx ...\n")
1240 (sim-analyze-insns!)
1241 (if (with-sem-frags?)
1242 (sim-sfrag-analyze-insns!))
1244 ; Turn parallel execution support off.
1245 ; It is later turned on/off when generating the actual semantic code.
1246 (set-with-parallel?! #f)
1248 ; Tell the rtx->c translator we are the simulator.
1249 (rtl-c-config! #:rtl-cover-fns? #t)
1251 ; Indicate we're currently generating a pbb engine.
1252 (set-current-pbb-engine?! #t)
1255 (gen-copyright "Simulator instruction semantics for @prefix@."
1256 copyright-cygnus package-cygnus-simulators)
1259 #include \"@cpu@.h\"
1261 using namespace @cpu@; // FIXME: namespace organization still wip
1263 #define GET_ATTR(name) GET_ATTR_##name ()
1267 (if (with-sem-frags?)
1268 -gen-sfrag-engine-decls
1271 (if (with-sem-frags?)
1273 -gen-sem-switch-engine)