1 ; CPU family related simulator generator, excluding decoding and model support.
2 ; Copyright (C) 2000, 2002, 2003, 2005, 2006, 2009 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-c-copyright "Misc. entries in the @arch@ description file."
78 copyright-red-hat package-red-hat-simulators)
83 #include \"cgen/bitset.h\"
89 (lambda () (string-map gen-decl (current-enum-list)))
96 } // end @arch@ namespace
98 #endif /* DESC_@ARCH@_H */\n"
105 ; Print out file containing elements to add to cpu class.
107 ; Get/set fns for hardware element HW.
109 (define (/gen-reg-access-defns hw)
110 (let ((scalar? (hw-scalar? hw))
112 (getter (hw-getter hw))
113 (setter (hw-setter hw))
114 (type (gen-type hw)))
115 (let ((get-code (if getter
116 (let ((mode (hw-mode hw))
118 (expr (cadr getter)))
122 #f ;; h/w is not ISA-specific
125 (list (list (car args) 'UINT "regno")))
130 "return this->hardware."
132 (if scalar? "" "[regno]")
135 (let ((args (car setter))
136 (expr (cadr setter)))
138 VOID ; not `mode', sets have mode VOID
139 #f ;; h/w is not ISA-specific
141 (list (list (car args) (hw-mode hw) "newval"))
142 (list (list (car args) 'UINT "regno")
143 (list (cadr args) (hw-mode hw) "newval")))
145 #:rtl-cover-fns? #t))
149 (if scalar? "" "[regno]")
153 (gen-reg-get-fun-name hw)
155 (if scalar? "" "UINT regno")
160 (gen-reg-set-fun-name hw)
162 (if scalar? "" "UINT regno, ")
168 ; Return a boolean indicating if hardware element HW needs storage allocated
169 ; for it in the SIM_CPU struct.
171 (define (hw-need-storage? hw)
173 (not (obj-has-attr? hw 'VIRTUAL)))
176 (define (hw-need-write-stack? hw)
177 (and (register? hw) (hw-used-in-delay-rtl? hw))
180 ; Subroutine of /gen-hardware-types to generate the struct containing
181 ; hardware elements of one isa.
183 (define (/gen-hardware-struct prefix hw-list)
185 ; If struct is empty, leave it out to simplify generated code.
189 (string-append " // Hardware elements for " prefix ".\n")
190 " // Hardware elements.\n")
192 (string-list-map gen-defn hw-list)
195 (string-append prefix "_")
201 ; Return C type declarations of all of the hardware elements.
202 ; The name of the type is prepended with the cpu family name.
204 (define (/gen-hardware-types)
206 "// CPU state information.\n\n"
207 (/gen-hardware-struct #f (find hw-need-storage? (current-hw-list))))
210 (define (/gen-hw-stream-and-destream-fns)
211 (let* ((sa string-append)
212 (regs (find hw-need-storage? (current-hw-list)))
213 (stack-regs (find hw-need-write-stack? (current-hw-list)))
215 (let ((dims (/hw-vector-dims r)))
216 (if (equal? 0 (length dims))
218 (number->string (car dims))))))
220 (map (lambda (n) (sa n "_writes"))
221 (append (map (lambda (r) (gen-c-symbol (obj:name r))) stack-regs)
222 (map (lambda (m) (sa (symbol->string m) "_memory")) write-stack-memory-mode-names))))
223 (stream-reg (lambda (r)
224 (let ((rname (sa "hardware." (gen-c-symbol (obj:name r)))))
226 (sa " ost << " rname " << ' ';\n")
227 (sa " for (int i = 0; i < " (reg-dim r)
228 "; i++)\n ost << " rname "[i] << ' ';\n")))))
229 (destream-reg (lambda (r)
230 (let ((rname (sa "hardware." (gen-c-symbol (obj:name r)))))
232 (sa " ist >> " rname ";\n")
233 (sa " for (int i = 0; i < " (reg-dim r)
234 "; i++)\n ist >> " rname "[i];\n")))))
235 (stream-stacks (lambda (s) (sa " stream_stacks ( stacks." s ", ost);\n")))
236 (destream-stacks (lambda (s) (sa " destream_stacks ( stacks." s ", ist);\n")))
239 " template <typename ST> \n"
240 " void stream_stacks (const ST &st, std::ostream &ost) const\n"
242 " for (int i = 0; i < @prefix@::pipe_sz; i++)\n"
244 " ost << st[i].t << ' ';\n"
245 " for (int j = 0; j <= st[i].t; j++)\n"
247 " ost << st[i].buf[j].pc << ' ';\n"
248 " ost << st[i].buf[j].val << ' ';\n"
249 " ost << st[i].buf[j].idx0 << ' ';\n"
254 " template <typename ST> \n"
255 " void destream_stacks (ST &st, std::istream &ist)\n"
257 " for (int i = 0; i < @prefix@::pipe_sz; i++)\n"
260 " for (int j = 0; j <= st[i].t; j++)\n"
262 " ist >> st[i].buf[j].pc;\n"
263 " ist >> st[i].buf[j].val;\n"
264 " ist >> st[i].buf[j].idx0;\n"
270 " void stream_cgen_hardware (std::ostream &ost) const \n {\n"
271 (string-map stream-reg regs)
273 " void destream_cgen_hardware (std::istream &ist) \n {\n"
274 (string-map destream-reg regs)
277 (sa stack-boilerplate
278 " void stream_cgen_write_stacks (std::ostream &ost, "
279 "const @prefix@::write_stacks &stacks) const \n {\n"
280 (string-map stream-stacks write-stacks)
282 " void destream_cgen_write_stacks (std::istream &ist, "
283 "@prefix@::write_stacks &stacks) \n {\n"
284 (string-map destream-stacks write-stacks)
289 ; Generate <cpu>-cpu.h
292 (logit 1 "Generating " (gen-cpu-name) "-cpu.h ...\n")
295 ; Turn parallel execution support on if cpu needs it.
296 (set-with-parallel?! (state-parallel-exec?))
298 ; Initialize rtl->c generation.
299 (rtl-c-config! #:rtl-cover-fns? #t)
302 (gen-c-copyright "CPU class elements for @cpu@."
303 copyright-red-hat package-red-hat-simulators)
305 // This file is included in the middle of the cpu class struct.
312 /gen-hw-stream-and-destream-fns
314 " // C++ register access function templates\n"
315 "#define current_cpu this\n\n"
317 (string-list-map /gen-reg-access-defns
318 (find register? (current-hw-list))))
319 "#undef current_cpu\n\n"
326 ; Print various parameters of the cpu family.
327 ; A "cpu family" here is a collection of variants of a particular architecture
328 ; that share sufficient commonality that they can be handled together.
330 (define (/gen-cpu-defines)
333 /* Maximum number of instructions that are fetched at a time.
334 This is for LIW type instructions sets (e.g. m32r). */\n"
335 "#define @CPU@_MAX_LIW_INSNS " (number->string (cpu-liw-insns (current-cpu))) "\n\n"
336 "/* Maximum number of instructions that can be executed in parallel. */\n"
337 "#define @CPU@_MAX_PARALLEL_INSNS " (number->string (cpu-parallel-insns (current-cpu))) "\n"
339 ; (gen-enum-decl '@prefix@_virtual
340 ; "@prefix@ virtual insns"
341 ; "@ARCH@_INSN_" ; not @CPU@ to match CGEN_INSN_TYPE in opc.h
343 ; (x-before -1) (x-after -2)
344 ; (x-begin -3) (x-chain -4) (x-cti-chain -5)))
348 ; Generate type of struct holding model state while executing.
350 (define (/gen-model-decls)
351 (logit 2 "Generating model decls ...\n")
357 (if (null? (model:state model))
359 (string-map (lambda (var)
361 (mode:c-type (mode:lookup (cadr var)))
363 (gen-c-symbol (car var))
365 (model:state model)))
367 (if (null? (model:state model)) "BLANK" "@CPU@") "_MODEL_DATA;\n\n"
369 (current-model-list))
371 typedef int (@CPU@_MODEL_FN) (struct @cpu@_cpu*, void*);
374 /* This is an integer that identifies this insn.
375 How this works is up to the target. */
378 /* Function to handle insn-specific profiling. */
379 @CPU@_MODEL_FN *model_fn;
381 /* Array of function units used by this insn. */
382 UNIT units[MAX_UNITS];
383 } @CPU@_INSN_TIMING;"
387 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
388 ;;; begin stack-based write schedule
389 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
391 (define write-stack-memory-mode-names '())
393 (define (/calculated-memory-write-buffer-size)
394 (let* ((is-mem? (lambda (op) (eq? (hw-sem-name (op:type op)) 'h-memory)))
396 (lambda (sfmt) (length (find is-mem? (sfmt-out-ops sfmt))))))
397 (apply max (append '(0) (map count-mem-writes (current-sfmt-list))))))
400 ;; note: this doesn't really correctly approximate the worst case. user-supplied functions
401 ;; might rewrite the pipeline extensively while it's running.
402 ;(define (/worst-case-number-of-writes-to hw-name)
403 ; (let* ((sfmts (current-sfmt-list))
404 ; (out-ops (map sfmt-out-ops sfmts))
405 ; (pred (lambda (op) (equal? hw-name (gen-c-symbol (obj:name (op:type op))))))
406 ; (filtered-ops (map (lambda (ops) (find pred ops)) out-ops)))
407 ; (apply max (cons 0 (map (lambda (ops) (length ops)) filtered-ops)))))
409 (define (/hw-gen-write-stack-decl nm mode)
411 ; for the time being, we're disabling this size-estimation stuff and just
412 ; requiring the user to supply a parameter WRITE_BUF_SZ before they include -defs.h
413 ; (pipe-sz (+ 1 (max-delay (cpu-max-delay (current-cpu)))))
414 ; (sz (* pipe-sz (/worst-case-number-of-writes-to nm))))
416 (mode-pad (spaces (- 4 (string-length (symbol->string mode)))))
417 (stack-name (string-append nm "_writes")))
419 " write_stack< write<" (symbol->string mode) "> >" mode-pad "\t" stack-name "\t[pipe_sz];\n")))
422 (define (/hw-gen-write-struct-decl)
423 (let* ((dims (/worst-case-index-dims))
427 (ctor (sa "write (PCADDR _pc, MODE _val"
428 (string-map (lambda (x) (sa ", USI _idx" (ns x) "=0")) idxs)
429 ") : pc(_pc), val(_val)"
430 (string-map (lambda (x) (sa ", idx" (ns x) "(_idx" (ns x) ")")) idxs)
432 (idx-fields (string-map (lambda (x) (sa " USI idx" (ns x) ";\n")) idxs)))
435 " template <typename MODE>\n"
445 (define (/hw-vector-dims hw) (elm-get (hw-type hw) 'dimensions))
446 (define (/worst-case-index-dims)
448 (append '(1) ; for memory accesses
449 (map (lambda (hw) (length (/hw-vector-dims hw)))
450 (find (lambda (hw) (not (scalar? hw))) (current-hw-list))))))
453 (define (/gen-writestacks)
454 (let* ((hw (find hw-need-write-stack? (current-hw-list)))
455 (modes write-stack-memory-mode-names)
456 (hw-pairs (map (lambda (h) (list (gen-c-symbol (obj:name h))
457 (obj:name (hw-mode h))))
459 (mem-pairs (map (lambda (m) (list (string-append (symbol->string m)
462 (all-pairs (append mem-pairs hw-pairs))
464 (h1 "\n\n// write stacks used in parallel execution\n\n struct write_stacks\n {\n // types of stacks\n\n")
466 "\n\n // unified writeback function (defined in @prefix@-write.cc)"
467 "\n void writeback (int tick, @cpu@::@cpu@_cpu* current_cpu);"
468 "\n // unified write-stack clearing function (defined in @prefix@-write.cc)"
469 "\n void reset ();"))
470 (zz "\n\n }; // end struct @prefix@::write_stacks \n\n"))
472 (/hw-gen-write-struct-decl)
473 (foldl (lambda (s pair) (string-append s (apply /hw-gen-write-stack-decl pair))) h1 all-pairs)
477 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
478 ;;; end stack-based write schedule
479 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
482 ; Generate the definition of the structure that holds register values, etc.
483 ; for use during parallel execution.
485 (define (gen-write-stack-structure)
486 (let ((membuf-sz (/calculated-memory-write-buffer-size))
487 (max-delay (cpu-max-delay (current-cpu))))
488 (logit 2 "Generating write stack structure ...\n")
490 " static const int max_delay = "
491 (number->string max-delay) ";\n"
492 " static const int pipe_sz = "
493 (number->string (+ 1 max-delay)) "; // max_delay + 1\n"
496 template <typename ELT>
501 ELT buf[WRITE_BUF_SZ];
503 write_stack () : t(-1), sz(WRITE_BUF_SZ) {}
504 inline bool empty () { return (t == -1); }
505 inline void clear () { t = -1; }
506 inline void pop () { if (t > -1) t--;}
507 inline void push (const ELT &e) { if (t+1 < sz) buf [++t] = e;}
508 inline ELT &top () { return buf [t>0 ? ( t<sz ? t : sz-1) : 0];}
511 // look ahead for latest write with index = idx, where time of write is
512 // <= dist steps from base (present) in write_stack array st.
513 // returning def if no scheduled write is found.
515 template <typename STKS, typename VAL>
516 inline VAL lookahead (int dist, int base, STKS &st, VAL def, int idx=0)
518 for (; dist > 0; --dist)
520 write_stack <VAL> &v = st [(base + dist) % pipe_sz];
521 for (int i = v.t; i > 0; --i)
522 if (v.buf [i].idx0 == idx) return v.buf [i];
532 ; Generate the TRACE_RECORD struct definition.
534 (define (/gen-trace-record-type)
537 /* Collection of various things for the trace handler to use. */
539 typedef struct @prefix@_trace_record {
542 } @CPU@_TRACE_RECORD;
547 ; Generate <cpu>-defs.h
549 (define (cgen-defs.h)
550 (logit 1 "Generating " (gen-cpu-name) "-defs.h ...\n")
553 ; Turn parallel execution support on if cpu needs it.
554 (set-with-parallel?! (state-parallel-exec?))
556 ; Initialize rtl->c generation.
557 (rtl-c-config! #:rtl-cover-fns? #t)
560 (gen-c-copyright "CPU family header for @cpu@ / @prefix@."
561 copyright-red-hat package-red-hat-simulators)
563 #ifndef DEFS_@PREFIX@_H
564 #define DEFS_@PREFIX@_H
570 #include \"cgen-types.h\"
572 // forward declaration\n\n
579 using namespace cgen;
582 gen-write-stack-structure
584 } // end @prefix@ namespace
588 #endif /* DEFS_@PREFIX@_H */\n"
595 ; This is the other way of implementing parallel execution support.
596 ; Instead of fetching all the input operands first, write all the output
597 ; operands and their addresses to holding variables, and then run a
598 ; post-processing pass to update the cpu state.
600 ; Return C code to fetch and save all output operands to instructions with
604 ; Generate <cpu>-write.cxx.
606 (define (/gen-register-writer nm mode dims)
609 (mode (symbol->string mode))
610 (idx-args (string-map (lambda (x) (sa "w.idx" (number->string x) ", "))
612 (sa pad "while (! " nm "_writes[tick].empty())\n"
614 pad " write<" mode "> &w = " nm "_writes[tick].top();\n"
615 pad " current_cpu->" nm "_set(" idx-args "w.val);\n"
616 pad " " nm "_writes[tick].pop();\n"
619 (define (/gen-memory-writer nm mode dims)
622 (mode (symbol->string mode))
623 (idx-args (string-map (lambda (x) (sa ", w.idx" (number->string x) ""))
625 (sa pad "while (! " nm "_writes[tick].empty())\n"
627 pad " write<" mode "> &w = " nm "_writes[tick].top();\n"
628 pad " current_cpu->SETMEM" mode " (w.pc" idx-args ", w.val);\n"
629 pad " " nm "_writes[tick].pop();\n"
633 (define (/gen-reset-fn)
634 (let* ((sa string-append)
635 (objs (append (map (lambda (h) (gen-c-symbol (obj:name h)))
636 (find hw-need-write-stack? (current-hw-list)))
637 (map (lambda (m) (sa (symbol->string m) "_memory"))
638 write-stack-memory-mode-names)))
639 (clr (lambda (elt) (sa " clear_stacks (" elt "_writes);\n"))))
641 " template <typename ST> \n"
642 " static void clear_stacks (ST &st)\n"
644 " for (int i = 0; i < @prefix@::pipe_sz; i++)\n"
647 " void @prefix@::write_stacks::reset ()\n {\n"
648 (string-map clr objs)
651 (define (/gen-unified-write-fn)
652 (let* ((hw (find hw-need-write-stack? (current-hw-list)))
653 (modes write-stack-memory-mode-names)
654 (hw-triples (map (lambda (h) (list (gen-c-symbol (obj:name h))
655 (obj:name (hw-mode h))
656 (length (/hw-vector-dims h))))
658 (mem-triples (map (lambda (m) (list (string-append (symbol->string m)
662 (logit 2 "Generating writer function ...\n")
665 void @prefix@::write_stacks::writeback (int tick, @cpu@::@cpu@_cpu* current_cpu)
668 "\n // register writeback loops\n"
669 (string-map (lambda (t) (apply /gen-register-writer t)) hw-triples)
670 "\n // memory writeback loops\n"
671 (string-map (lambda (t) (apply /gen-memory-writer t)) mem-triples)
676 (define (cgen-write.cxx)
677 (logit 1 "Generating " (gen-cpu-name) "-write.cxx ...\n")
682 ; Turn parallel execution support off.
683 (set-with-parallel?! #f)
685 ; Tell the rtx->c translator we are the simulator.
686 (rtl-c-config! #:rtl-cover-fns? #t)
689 (gen-c-copyright (string-append "Simulator instruction operand writer for "
690 (symbol->string (current-arch-name))
692 copyright-red-hat package-red-hat-simulators)
699 /gen-unified-write-fn
706 ; Return C code to perform the semantics of INSN.
708 (define (gen-semantic-code insn)
709 (cond ((insn-compiled-semantics insn)
711 (rtl-c++-parsed VOID sem
715 ((insn-canonical-semantics insn)
717 (rtl-c++-parsed VOID sem
722 (context-error (make-obj-context insn #f)
723 "While generating semantic code"
724 "semantics of insn are not canonicalized")))
727 ; Return definition of C function to perform INSN.
728 ; This version handles the with-scache case.
730 (define (/gen-scache-semantic-fn insn)
731 (logit 2 "Processing semantics for " (obj:name insn) ": \"" (insn-syntax insn) "\" ...\n")
732 (set! /with-profile? /with-profile-fn?)
733 (let ((cti? (insn-cti? insn))
734 (insn-len (insn-length-bytes insn)))
736 "// ********** " (obj:name insn) ": " (insn-syntax insn) "\n\n"
740 "@prefix@_sem_" (gen-sym insn)
742 (string-append " (@cpu@_cpu* current_cpu, @prefix@_scache* sem, const int tick, \n\t"
743 "@prefix@::write_stacks &buf)\n")
744 " (@cpu@_cpu* current_cpu, @prefix@_scache* sem)\n")
746 (gen-define-field-macro (insn-sfmt insn))
747 " sem_status status = SEM_STATUS_NORMAL;\n"
748 " @prefix@_scache* abuf = sem;\n"
749 ; Unconditionally written operands are not recorded here.
750 (if (or (with-profile?) (with-parallel-write?))
751 " unsigned long long written = 0;\n"
753 ; The address of this insn, needed by extraction and semantic code.
754 ; Note that the address recorded in the cpu state struct is not used.
755 ; For faster engines that copy will be out of date.
756 " PCADDR pc = abuf->addr;\n"
757 " PCADDR npc = pc + " (number->string insn-len) ";\n"
759 (gen-semantic-code insn)
761 ; Only update what's been written if some are conditionally written.
762 ; Otherwise we know they're all written so there's no point in
764 (if (or (with-profile?) (with-parallel-write?))
765 (if (/any-cond-written? (insn-sfmt insn))
766 " abuf->written = written;\n"
770 " current_cpu->done_cti_insn (npc, status);\n"
771 " current_cpu->done_insn (npc, status);\n")
775 (gen-undef-field-macro (insn-sfmt insn))
780 (define (/gen-all-semantic-fns)
781 (logit 2 "Processing semantics ...\n")
782 (let ((insns (scache-engine-insns)))
784 (string-write-map /gen-scache-semantic-fn insns)
785 (error "must specify `with-scache'")))
788 ; Generate <cpu>-sem.cxx.
789 ; Each instruction is implemented in its own function.
791 (define (cgen-semantics.cxx)
792 (logit 1 "Generating " (gen-cpu-name) "-semantics.cxx ...\n")
797 ; Turn parallel execution support on if cpu needs it.
798 (set-with-parallel?! (state-parallel-exec?))
800 ; Tell the rtx->c translator we are the simulator.
801 (rtl-c-config! #:rtl-cover-fns? #t)
803 ; Indicate we're currently not generating a pbb engine.
804 (set-current-pbb-engine?! #f)
807 (gen-c-copyright "Simulator instruction semantics for @prefix@."
808 copyright-red-hat package-red-hat-simulators)
812 #include \"config.h\"
816 using namespace @cpu@; // FIXME: namespace organization still wip\n")
819 using namespace @prefix@; // FIXME: namespace organization still wip\n"))
821 #define GET_ATTR(name) GET_ATTR_##name ()
825 /gen-all-semantic-fns
829 ; *******************
830 ; cgen-sem-switch.cxx
832 ; The semantic switch engine has two flavors: one case per insn, and one
833 ; case per "frag" (where each insn is split into one or more fragments).
835 ; Utility of /gen-sem-case to return the mask of operands always written
836 ; to in <sformat> SFMT.
837 ; ??? Not currently used.
839 (define (/uncond-written-mask sfmt)
840 (apply + (map (lambda (op)
843 (logsll 1 (op:num op))))
844 (sfmt-out-ops sfmt)))
847 ; Utility of /gen-sem-case to return #t if any operand in <sformat> SFMT is
848 ; conditionally written to.
850 (define (/any-cond-written? sfmt)
851 (any-true? (map op:cond? (sfmt-out-ops sfmt)))
854 ; One case per insn version.
856 ; Generate a switch case to perform INSN.
858 (define (/gen-sem-case insn parallel?)
859 (logit 2 "Processing "
860 (if parallel? "parallel " "")
861 "semantic switch case for " (obj:name insn) ": \""
862 (insn-syntax insn) "\" ...\n")
863 (set! /with-profile? /with-profile-sw?)
864 (let ((cti? (insn-cti? insn))
865 (insn-len (insn-length-bytes insn)))
867 ; INSN_ is prepended here and not elsewhere to avoid name collisions
868 ; with symbols like AND, etc.
870 // ********** " (insn-syntax insn) "
872 CASE (INSN_" (if parallel? "PAR_" "") (string-upcase (gen-sym insn)) "):
874 @prefix@_scache* abuf = vpc;\n"
876 (gen-define-field-macro (insn-sfmt insn))
878 ; Unconditionally written operands are not recorded here.
879 (if (or (with-profile?) (with-parallel-write?))
880 " unsigned long long written = 0;\n"
882 ; The address of this insn, needed by extraction and semantic code.
883 ; Note that the address recorded in the cpu state struct is not used.
884 " PCADDR pc = abuf->addr;\n"
885 (if (and cti? (not parallel?))
886 (string-append " PCADDR npc;\n"
887 " branch_status br_status = BRANCH_UNTAKEN;\n")
889 (string-list " vpc = vpc + 1;\n")
890 ; Emit setup-semantics code for real insns.
891 (if (and (insn-real? insn)
892 (isa-setup-semantics (current-isa)))
895 (rtl-c++ VOID (obj-isa-list insn) nil
896 (isa-setup-semantics (current-isa))
902 (gen-semantic-code insn)
904 ; Only update what's been written if some are conditionally written.
905 ; Otherwise we know they're all written so there's no point in
907 (if (or (with-profile?) (with-parallel-write?))
908 (if (/any-cond-written? (insn-sfmt insn))
909 " abuf->written = written;\n"
912 (if (and cti? (not parallel?))
913 (string-append " pbb_br_npc = npc;\n"
914 " pbb_br_status = br_status;\n")
917 (gen-undef-field-macro (insn-sfmt insn))
924 (define (/gen-sem-switch)
925 (logit 2 "Processing semantic switch ...\n")
926 ; Turn parallel execution support off.
927 (set-with-parallel?! #f)
928 (string-write-map (lambda (insn) (/gen-sem-case insn #f))
929 (non-multi-insns (non-alias-insns (current-insn-list))))
932 ; Generate the guts of a C switch statement to execute parallel instructions.
933 ; This switch is included after the non-parallel instructions in the semantic
936 ; ??? We duplicate the writeback case for each insn, even though we only need
937 ; one case per insn format. The former keeps the code for each insn
938 ; together and might improve cache usage. On the other hand the latter
939 ; reduces the amount of code, though it is believed that in this particular
940 ; instance the win isn't big enough.
942 (define (/gen-parallel-sem-switch)
943 (logit 2 "Processing parallel insn semantic switch ...\n")
944 ; Turn parallel execution support on.
945 (set-with-parallel?! #t)
946 (string-write-map (lambda (insn)
947 (string-list (/gen-sem-case insn #t)
948 (/gen-write-case (insn-sfmt insn) insn)))
949 (parallel-insns (current-insn-list)))
952 ; Return computed-goto engine.
954 (define (/gen-sem-switch-engine)
958 @cpu@_cpu::@prefix@_pbb_run ()
960 @cpu@_cpu* current_cpu = this;
961 @prefix@_scache* vpc;
962 // These two are used to pass data from cti insns to the cti-chain insn.
964 branch_status pbb_br_status;
968 static const struct sem_labels
970 enum @prefix@_insn_type insn;
977 (string-write-map (lambda (insn)
980 (string-upcase (gen-sym insn))
982 (string-upcase (gen-sym insn))
984 (non-multi-insns (non-alias-insns (current-insn-list)))))
986 (if (state-parallel-exec?)
988 (string-write-map (lambda (insn)
991 (string-upcase (gen-sym insn))
992 ", && case_INSN_PAR_"
993 (string-upcase (gen-sym insn))
996 "@PREFIX@_INSN_WRITE_"
997 (string-upcase (gen-sym insn))
998 ", && case_INSN_WRITE_"
999 (string-upcase (gen-sym insn))
1001 (parallel-insns (current-insn-list))))
1004 " { (@prefix@_insn_type) 0, 0 }
1007 if (! @prefix@_idesc::idesc_table_initialized_p)
1009 for (int i=0; labels[i].label != 0; i++)
1010 @prefix@_idesc::idesc_table[labels[i].insn].cgoto.label = labels[i].label;
1012 // confirm that table is all filled up
1013 for (int i = 0; i <= @PREFIX@_INSN_" (/last-insn) "; i++)
1014 assert (@prefix@_idesc::idesc_table[i].cgoto.label != 0);
1016 // Initialize the compiler virtual insn.
1017 current_cpu->@prefix@_engine.compile_begin_insn (current_cpu);
1019 @prefix@_idesc::idesc_table_initialized_p = true;
1025 #define CASE(X) case_##X
1026 // Branch to next handler without going around main loop.
1027 #define NEXT(vpc) goto * vpc->execute.cgoto.label;
1028 // Break out of threaded interpreter and return to \"main loop\".
1029 #define BREAK(vpc) goto end_switch
1031 #define CASE(X) case @PREFIX@_##X
1032 #define NEXT(vpc) goto restart
1033 #define BREAK(vpc) break
1036 // Get next insn to execute.
1037 vpc = current_cpu->@prefix@_engine.get_next_vpc (current_cpu->h_pc_get ());
1041 goto * vpc->execute.cgoto.label;
1043 switch (vpc->idesc->sem_index)
1051 (if (state-parallel-exec?)
1052 /gen-parallel-sem-switch
1063 // Save vpc for next time.
1064 current_cpu->@prefix@_engine.set_next_vpc (vpc);
1070 ; Semantic frag version.
1072 ; Return declaration of frag enum.
1074 (define (/gen-sfrag-enum-decl frag-list)
1075 (gen-enum-decl "@prefix@_frag_type"
1076 "semantic fragments in cpu family @prefix@"
1078 (append '((list-end))
1082 (atlist-attrs (obj-atlist i)))))
1087 ; Return header file decls for semantic frag threaded engine.
1089 (define (/gen-sfrag-engine-decls)
1091 "namespace @cpu@ {\n\n"
1093 ; FIXME: vector->list
1094 (/gen-sfrag-enum-decl (vector->list (sim-sfrag-frag-table)))
1097 struct @prefix@_insn_frag {
1098 @PREFIX@_INSN_TYPE itype;
1099 // 4: header+middle+trailer+delimiter
1100 @PREFIX@_FRAG_TYPE ftype[4];
1103 struct @prefix@_pbb_label {
1104 @PREFIX@_FRAG_TYPE frag;
1108 } // end @cpu@ namespace
1112 ; Return C code to perform the semantics of FRAG.
1113 ; LOCALS is a list of sequence locals made global to all frags.
1114 ; Each element is (symbol <mode> "c-var-name").
1116 (define (/gen-sfrag-code frag locals)
1117 (let ((sem (sfrag-semantics frag))
1118 ; If the frag has one owner, use it. Otherwise indicate the owner is
1119 ; unknown. In cases where the owner is needed by the semantics, the
1120 ; frag should have only one owner. In practice this means that frags
1121 ; with the ref,current-insn rtx cannot be used by multiple insns.
1122 (owner (if (= (length (sfrag-users frag)) 1)
1123 (car (sfrag-users frag))
1125 ;; NOTE: (sfrag-users frag) is nil for the x-header and x-trailer frags.
1126 ;; They are just nops.
1127 (rtl-c++ VOID (and owner (obj-isa-list owner)) locals sem
1133 ; Generate a switch case to perform FRAG.
1134 ; LOCALS is a list of sequence locals made global to all frags.
1135 ; Each element is (symbol <mode> "c-var-name").
1137 (define (/gen-sfrag-case frag locals)
1138 (set! /with-profile? /with-profile-sw?)
1139 (let ((cti? (sfmt-cti? (sfrag-sfmt frag)))
1140 (parallel? (sfrag-parallel? frag)))
1141 (logit 2 "Processing "
1142 (if parallel? "parallel " "")
1143 "semantic switch case for " (obj:name frag) " ...\n")
1145 ; FRAG_ is prepended here and not elsewhere to avoid name collisions
1146 ; with symbols like AND, etc.
1149 (if (= (length (sfrag-users frag)) 1)
1153 (string-map (lambda (user)
1154 (string-append ", " (obj:str-name user)))
1155 (sfrag-users frag)))
1158 CASE (FRAG_" (string-upcase (gen-sym frag)) "):
1160 (if (sfrag-header? frag)
1161 (string-append " abuf = vpc;\n"
1162 " vpc = vpc + 1;\n")
1164 (gen-define-field-macro (sfrag-sfmt frag))
1165 ; Unconditionally written operands are not recorded here.
1166 (if (or (with-profile?) (with-parallel-write?))
1167 " unsigned long long written = 0;\n"
1169 ; The address of this insn, needed by extraction and semantic code.
1170 ; Note that the address recorded in the cpu state struct is not used.
1171 " PCADDR pc = abuf->addr;\n"
1174 (sfrag-header? frag))
1175 (string-append ; " npc = 0;\n" ??? needed?
1176 " br_status = BRANCH_UNTAKEN;\n")
1178 ; Emit setup-semantics code for headers of real insns.
1179 (if (and (sfrag-header? frag)
1180 (not (obj-has-attr? frag 'VIRTUAL))
1181 (isa-setup-semantics (current-isa)))
1184 (rtl-c++ VOID (list (obj:name (current-isa))) nil
1185 (isa-setup-semantics (current-isa))
1190 (/gen-sfrag-code frag locals)
1192 ; Only update what's been written if some are conditionally written.
1193 ; Otherwise we know they're all written so there's no point in
1195 (if (or (with-profile?) (with-parallel-write?))
1196 (if (/any-cond-written? (sfrag-sfmt frag))
1197 " abuf->written = written;\n"
1202 (sfrag-trailer? frag))
1203 (string-append " pbb_br_npc = npc;\n"
1204 " pbb_br_status = br_status;\n")
1206 (gen-undef-field-macro (sfrag-sfmt frag))
1208 (if (sfrag-trailer? frag)
1209 " NEXT_INSN (vpc, fragpc);\n"
1210 " NEXT_FRAG (fragpc);\n")
1215 ; Convert locals from form computed by sem-find-common-frags to that needed by
1216 ; /gen-sfrag-engine-code (and ultimately rtl-c++).
1218 (define (/frag-convert-c-locals locals)
1219 (map (lambda (local)
1220 (list (car local) (mode:lookup (cadr local))
1221 (gen-c-symbol (car local))))
1225 ; Return definition of insn frag usage table.
1227 (define (/gen-sfrag-engine-frag-table insn-list frag-table frag-usage)
1230 // Table of frags used by each insn.
1232 const @prefix@_insn_frag @prefix@_frag_usage[] = {\n"
1235 (for-each (lambda (insn frag-nums)
1238 (string-upcase (gen-sym insn))
1239 (string-map (lambda (frag-num)
1240 (string-append ", @PREFIX@_FRAG_"
1241 (string-upcase (gen-sym (vector-ref frag-table frag-num)))))
1243 ", @PREFIX@_FRAG_LIST_END },\n"))
1244 insn-list frag-usage)
1249 ; Return sfrag computed-goto engine.
1250 ; LOCALS is a list of sequence locals made global to all frags.
1251 ; Each element is (symbol <mode> "c-var-name").
1253 (define (/gen-sfrag-engine-fn frag-table locals)
1257 @cpu@_cpu::@prefix@_pbb_run ()
1259 @cpu@_cpu* current_cpu = this;
1260 @prefix@_scache* vpc;
1261 @prefix@_scache* abuf;
1265 ARM_FRAG_TYPE* fragpc;
1270 static const @prefix@_pbb_label labels[] =
1272 { @PREFIX@_FRAG_LIST_END, 0 },
1276 (string-write-map (lambda (frag)
1277 (string-append " { "
1279 (string-upcase (gen-sym frag))
1281 (string-upcase (gen-sym frag))
1283 ; FIXME: vector->list
1284 (vector->list frag-table)))
1287 { @PREFIX@_FRAG_MAX, 0 }
1290 if (! @prefix@_idesc::idesc_table_initialized_p)
1292 // Several tables are in play here:
1293 // idesc table: const table of misc things for each insn
1294 // frag usage table: const set of frags used by each insn
1295 // frag label table: same as frag usage table, but contains labels
1296 // selected insn frag table: table of pointers to either the frag usage
1297 // table (if !gnuc) or frag label table (if gnuc) for the currently
1298 // selected ISA. Insns not in the ISA are redirected to the `invalid'
1299 // insn handler. FIXME: This one isn't implemented yet.
1301 // Allocate frag label table and point idesc table entries at it.
1302 // FIXME: Temporary hack, to be redone.
1303 static void** frag_label_table;
1304 int max_insns = @PREFIX@_INSN_" (/last-insn) " + 1;
1305 int tabsize = max_insns * 4;
1306 frag_label_table = new void* [tabsize];
1307 memset (frag_label_table, 0, sizeof (void*) * tabsize);
1310 for (i = 0, v = frag_label_table; i < max_insns; ++i)
1312 @prefix@_idesc::idesc_table[@prefix@_frag_usage[i].itype].cgoto.frags = v;
1313 for (int j = 0; @prefix@_frag_usage[i].ftype[j] != @PREFIX@_FRAG_LIST_END; ++j)
1314 *v++ = labels[@prefix@_frag_usage[i].ftype[j]].label;
1317 // Initialize the compiler virtual insn.
1318 // FIXME: Also needed if !gnuc.
1319 current_cpu->@prefix@_engine.compile_begin_insn (current_cpu);
1321 @prefix@_idesc::idesc_table_initialized_p = true;
1327 #define CASE(X) case_##X
1328 // Branch to next handler without going around main loop.
1329 #define NEXT_INSN(vpc, fragpc) fragpc = vpc->execute.cgoto.frags; goto * *fragpc
1330 #define NEXT_FRAG(fragpc) ++fragpc; goto * *fragpc
1331 // Break out of threaded interpreter and return to \"main loop\".
1332 #define BREAK(vpc) goto end_switch
1334 #define CASE(X) case @PREFIX@_##X
1335 #define NEXT_INSN(vpc, fragpc) fragpc = vpc->idesc->frags; goto restart
1336 #define NEXT_FRAG(fragpc) ++fragpc; goto restart
1337 #define BREAK(vpc) break
1340 // Get next insn to execute.
1341 vpc = current_cpu->@prefix@_engine.get_next_vpc (current_cpu->h_pc_get ());
1344 // These two are used to pass data from cti insns to the cti-chain insn.
1346 branch_status pbb_br_status;
1347 // These two are used to build up values of the previous two.
1349 branch_status br_status;
1350 // Top level locals moved here so they're usable by multiple fragments.
1354 (string-write-map (lambda (local)
1356 (mode:c-type (cadr local))
1366 fragpc = vpc->execute.cgoto.frags;
1369 fragpc = vpc->idesc->frags;
1378 ; Turn parallel execution support off.
1380 (set-with-parallel?! #f)
1381 (string-write-map (lambda (frag)
1382 (/gen-sfrag-case frag locals))
1383 ; FIXME: vector->list
1384 (vector->list frag-table)))
1395 // Save vpc for next time.
1396 current_cpu->@prefix@_engine.set_next_vpc (vpc);
1401 (define (/gen-sfrag-engine)
1404 (/gen-sfrag-engine-frag-table (sim-sfrag-insn-list)
1405 (sim-sfrag-frag-table)
1406 (sim-sfrag-usage-table)))
1408 (/gen-sfrag-engine-fn (sim-sfrag-frag-table)
1409 (/frag-convert-c-locals (sim-sfrag-locals-list))))
1413 ; Generate sem-switch.cxx.
1415 (define (cgen-sem-switch.cxx)
1416 (logit 1 "Generating " (gen-cpu-name) "-sem-switch.cxx ...\n")
1418 (sim-analyze-insns!)
1419 (if (with-sem-frags?)
1420 (sim-sfrag-analyze-insns!))
1422 ; Turn parallel execution support off.
1423 ; It is later turned on/off when generating the actual semantic code.
1424 (set-with-parallel?! #f)
1426 ; Tell the rtx->c translator we are the simulator.
1427 (rtl-c-config! #:rtl-cover-fns? #t)
1429 ; Indicate we're currently generating a pbb engine.
1430 (set-current-pbb-engine?! #t)
1433 (gen-c-copyright "Simulator instruction semantics for @prefix@."
1434 copyright-red-hat package-red-hat-simulators)
1437 #include \"@cpu@.h\"
1439 using namespace @cpu@; // FIXME: namespace organization still wip
1441 #define GET_ATTR(name) GET_ATTR_##name ()
1445 (if (with-sem-frags?)
1446 /gen-sfrag-engine-decls
1449 (if (with-sem-frags?)
1451 /gen-sem-switch-engine)