; CPU family related simulator generator, excluding decoding and model support.
-; Copyright (C) 2000, 2002 Red Hat, Inc.
+; Copyright (C) 2000, 2002, 2003, 2005, 2006, 2009, 2010 Red Hat, Inc.
; This file is part of CGEN.
; ***********
; cgen-desc.h
-(define (-last-insn)
+(define (/last-insn)
(string-upcase (gen-c-symbol (caar (list-take -1
(gen-obj-list-enums (non-multi-insns (current-insn-list))))))))
; Declare the attributes.
-(define (-gen-attr-decls)
+(define (/gen-attr-decls)
(string-list
"// Insn attribute indices.\n\n"
(gen-attr-enum-decl "cgen_insn" (current-insn-attr-list))
; Generate class to hold an instruction's attributes.
-(define (-gen-insn-attr-decls)
+(define (/gen-insn-attr-decls)
(let ((attrs (current-insn-attr-list)))
(string-append
"// Insn attributes.\n\n"
; Emit a macro that specifies the word-bitsize for each machine.
-(define (-gen-mach-params)
+(define (/gen-mach-params)
(string-map (lambda (mach)
(string-append
"#define MACH_" (string-upcase (gen-sym mach)) "_INSN_CHUNK_BITSIZE "
; Generate <cpu>-desc.h.
(define (cgen-desc.h)
- (logit 1 "Generating " (gen-cpu-name) " desc.h ...\n")
+ (logit 1 "Generating " (gen-cpu-name) "-desc.h ...\n")
(string-write
(gen-c-copyright "Misc. entries in the @arch@ description file."
#ifndef DESC_@ARCH@_H
#define DESC_@ARCH@_H
+#include \"cgen/bitset.h\"
+
namespace @arch@ {
\n"
- "// Enums.\n\n"
- (lambda () (string-map gen-decl (current-enum-list)))
+ (let ((enums (find (lambda (obj) (not (obj-has-attr? obj 'VIRTUAL)))
+ (current-enum-list))))
+ (if (null? enums)
+ ""
+ (string-list
+ "// Enums.\n\n"
+ (string-map gen-decl enums))))
- -gen-attr-decls
- -gen-insn-attr-decls
- -gen-mach-params
+ /gen-attr-decls
+ /gen-insn-attr-decls
+ /gen-mach-params
"
} // end @arch@ namespace
; Get/set fns for hardware element HW.
-(define (-gen-reg-access-defns hw)
+(define (/gen-reg-access-defns hw)
(let ((scalar? (hw-scalar? hw))
(name (obj:name hw))
(getter (hw-getter hw))
(setter (hw-setter hw))
- (isas (bitset-attr->list (obj-attr-value hw 'ISA)))
(type (gen-type hw)))
(let ((get-code (if getter
(let ((mode (hw-mode hw))
(expr (cadr getter)))
(string-append
"return "
- (rtl-c++ mode expr
+ (rtl-c++ mode
+ #f ;; h/w is not ISA-specific
(if scalar?
nil
(list (list (car args) 'UINT "regno")))
+ expr
#:rtl-cover-fns? #t)
";"))
(string-append
(expr (cadr setter)))
(rtl-c++
VOID ; not `mode', sets have mode VOID
- expr
+ #f ;; h/w is not ISA-specific
(if scalar?
(list (list (car args) (hw-mode hw) "newval"))
(list (list (car args) 'UINT "regno")
(list (cadr args) (hw-mode hw) "newval")))
+ expr
#:rtl-cover-fns? #t))
(string-append
"this->hardware."
(not (obj-has-attr? hw 'VIRTUAL)))
)
-; Subroutine of -gen-hardware-types to generate the struct containing
+(define (hw-need-write-stack? hw)
+ (and (register? hw) (hw-used-in-delay-rtl? hw))
+)
+
+; Subroutine of /gen-hardware-types to generate the struct containing
; hardware elements of one isa.
-(define (-gen-hardware-struct prefix hw-list)
+(define (/gen-hardware-struct prefix hw-list)
(if (null? hw-list)
; If struct is empty, leave it out to simplify generated code.
""
(string-append " // Hardware elements for " prefix ".\n")
" // Hardware elements.\n")
" struct {\n"
- (string-list-map gen-decl hw-list)
+ (string-list-map gen-defn hw-list)
" } "
(if prefix
(string-append prefix "_")
; Return C type declarations of all of the hardware elements.
; The name of the type is prepended with the cpu family name.
-(define (-gen-hardware-types)
+(define (/gen-hardware-types)
(string-list
"// CPU state information.\n\n"
- (-gen-hardware-struct #f (find hw-need-storage? (current-hw-list))))
+ (/gen-hardware-struct #f (find hw-need-storage? (current-hw-list))))
)
+(define (/gen-hw-stream-and-destream-fns)
+ (let* ((sa string-append)
+ (regs (find hw-need-storage? (current-hw-list)))
+ (stack-regs (find hw-need-write-stack? (current-hw-list)))
+ (reg-dim (lambda (r)
+ (let ((dims (/hw-vector-dims r)))
+ (if (equal? 0 (length dims))
+ "0"
+ (number->string (car dims))))))
+ (write-stacks
+ (map (lambda (n) (sa n "_writes"))
+ (append (map (lambda (r) (gen-c-symbol (obj:name r))) stack-regs)
+ (map (lambda (m) (sa (symbol->string m) "_memory")) write-stack-memory-mode-names))))
+ (stream-reg (lambda (r)
+ (let ((rname (sa "hardware." (gen-c-symbol (obj:name r)))))
+ (if (hw-scalar? r)
+ (sa " ost << " rname " << ' ';\n")
+ (sa " for (int i = 0; i < " (reg-dim r)
+ "; i++)\n ost << " rname "[i] << ' ';\n")))))
+ (destream-reg (lambda (r)
+ (let ((rname (sa "hardware." (gen-c-symbol (obj:name r)))))
+ (if (hw-scalar? r)
+ (sa " ist >> " rname ";\n")
+ (sa " for (int i = 0; i < " (reg-dim r)
+ "; i++)\n ist >> " rname "[i];\n")))))
+ (stream-stacks (lambda (s) (sa " stream_stacks ( stacks." s ", ost);\n")))
+ (destream-stacks (lambda (s) (sa " destream_stacks ( stacks." s ", ist);\n")))
+ (stack-boilerplate
+ (sa
+ " template <typename ST> \n"
+ " void stream_stacks (const ST &st, std::ostream &ost) const\n"
+ " {\n"
+ " for (int i = 0; i < @prefix@::pipe_sz; i++)\n"
+ " {\n"
+ " ost << st[i].t << ' ';\n"
+ " for (int j = 0; j <= st[i].t; j++)\n"
+ " {\n"
+ " ost << st[i].buf[j].pc << ' ';\n"
+ " ost << st[i].buf[j].val << ' ';\n"
+ " ost << st[i].buf[j].idx0 << ' ';\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " \n"
+ " template <typename ST> \n"
+ " void destream_stacks (ST &st, std::istream &ist)\n"
+ " {\n"
+ " for (int i = 0; i < @prefix@::pipe_sz; i++)\n"
+ " {\n"
+ " ist >> st[i].t;\n"
+ " for (int j = 0; j <= st[i].t; j++)\n"
+ " {\n"
+ " ist >> st[i].buf[j].pc;\n"
+ " ist >> st[i].buf[j].val;\n"
+ " ist >> st[i].buf[j].idx0;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " \n")))
+ (sa
+ " void stream_cgen_hardware (std::ostream &ost) const \n {\n"
+ (string-map stream-reg regs)
+ " }\n"
+ " void destream_cgen_hardware (std::istream &ist) \n {\n"
+ (string-map destream-reg regs)
+ " }\n"
+ (if (with-parallel?)
+ (sa stack-boilerplate
+ " void stream_cgen_write_stacks (std::ostream &ost, "
+ "const @prefix@::write_stacks &stacks) const \n {\n"
+ (string-map stream-stacks write-stacks)
+ " }\n"
+ " void destream_cgen_write_stacks (std::istream &ist, "
+ "@prefix@::write_stacks &stacks) \n {\n"
+ (string-map destream-stacks write-stacks)
+ " }\n")
+ ""))))
+
+
; Generate <cpu>-cpu.h
(define (cgen-cpu.h)
- (logit 1 "Generating " (gen-cpu-name) " cpu.h ...\n")
+ (logit 1 "Generating " (gen-cpu-name) "-cpu.h ...\n")
(assert-keep-one)
; Turn parallel execution support on if cpu needs it.
public:
\n"
- -gen-hardware-types
+ /gen-hardware-types
+
+ /gen-hw-stream-and-destream-fns
" // C++ register access function templates\n"
"#define current_cpu this\n\n"
(lambda ()
- (string-list-map -gen-reg-access-defns
+ (string-list-map /gen-reg-access-defns
(find register? (current-hw-list))))
"#undef current_cpu\n\n"
)
; A "cpu family" here is a collection of variants of a particular architecture
; that share sufficient commonality that they can be handled together.
-(define (-gen-cpu-defines)
+(define (/gen-cpu-defines)
(string-append
"\
/* Maximum number of instructions that are fetched at a time.
; Generate type of struct holding model state while executing.
-(define (-gen-model-decls)
+(define (/gen-model-decls)
(logit 2 "Generating model decls ...\n")
(string-list
(string-list-map
)
)
-; Utility of gen-parallel-exec-type to generate the definition of one
-; structure in PAREXEC.
-; SFMT is an <sformat> object.
-
-(define (gen-parallel-exec-elm sfmt)
- (string-append
- " struct { /* " (obj:comment sfmt) " */\n"
- (let ((sem-ops
- ((if (with-parallel-write?) sfmt-out-ops sfmt-in-ops) sfmt)))
- (if (null? sem-ops)
- " int empty;\n"
- (string-map
- (lambda (op)
- (logit 2 "Processing operand " (obj:name op) " of format "
- (obj:name sfmt) " ...\n")
- (if (with-parallel-write?)
- (let ((index-type (and (op-save-index? op)
- (gen-index-type op sfmt))))
- (string-append " " (gen-type op)
- " " (gen-sym op) ";\n"
- (if index-type
- (string-append " " index-type
- " " (gen-sym op) "_idx;\n")
- "")))
- (string-append " "
- (gen-type op)
- " "
- (gen-sym op)
- ";\n")))
- sem-ops)))
- " } " (gen-sym sfmt) ";\n"
- )
-)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; begin stack-based write schedule
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define write-stack-memory-mode-names '())
+
+(define (/calculated-memory-write-buffer-size)
+ (let* ((is-mem? (lambda (op) (eq? (hw-sem-name (op:type op)) 'h-memory)))
+ (count-mem-writes
+ (lambda (sfmt) (length (find is-mem? (sfmt-out-ops sfmt))))))
+ (apply max (append '(0) (map count-mem-writes (current-sfmt-list))))))
+
+
+;; note: this doesn't really correctly approximate the worst case. user-supplied functions
+;; might rewrite the pipeline extensively while it's running.
+;(define (/worst-case-number-of-writes-to hw-name)
+; (let* ((sfmts (current-sfmt-list))
+; (out-ops (map sfmt-out-ops sfmts))
+; (pred (lambda (op) (equal? hw-name (gen-c-symbol (obj:name (op:type op))))))
+; (filtered-ops (map (lambda (ops) (find pred ops)) out-ops)))
+; (apply max (cons 0 (map (lambda (ops) (length ops)) filtered-ops)))))
+
+(define (/hw-gen-write-stack-decl nm mode)
+ (let* (
+; for the time being, we're disabling this size-estimation stuff and just
+; requiring the user to supply a parameter WRITE_BUF_SZ before they include -defs.h
+; (pipe-sz (+ 1 (max-delay (cpu-max-delay (current-cpu)))))
+; (sz (* pipe-sz (/worst-case-number-of-writes-to nm))))
+
+ (mode-pad (spaces (- 4 (string-length (symbol->string mode)))))
+ (stack-name (string-append nm "_writes")))
+ (string-append
+ " write_stack< write<" (symbol->string mode) "> >" mode-pad "\t" stack-name "\t[pipe_sz];\n")))
+
+
+(define (/hw-gen-write-struct-decl)
+ (let* ((dims (/worst-case-index-dims))
+ (sa string-append)
+ (ns number->string)
+ (idxs (iota dims))
+ (ctor (sa "write (PCADDR _pc, MODE _val"
+ (string-map (lambda (x) (sa ", USI _idx" (ns x) "=0")) idxs)
+ ") : pc(_pc), val(_val)"
+ (string-map (lambda (x) (sa ", idx" (ns x) "(_idx" (ns x) ")")) idxs)
+ " {} \n"))
+ (idx-fields (string-map (lambda (x) (sa " USI idx" (ns x) ";\n")) idxs)))
+ (sa
+ "\n\n"
+ " template <typename MODE>\n"
+ " struct write\n"
+ " {\n"
+ " USI pc;\n"
+ " MODE val;\n"
+ idx-fields
+ " " ctor
+ " write() {}\n"
+ " };\n" )))
+
+(define (/hw-vector-dims hw) (elm-get (hw-type hw) 'dimensions))
+(define (/worst-case-index-dims)
+ (apply max
+ (append '(1) ; for memory accesses
+ (map (lambda (hw) (length (/hw-vector-dims hw)))
+ (find (lambda (hw) (not (scalar? hw))) (current-hw-list))))))
+
+
+(define (/gen-writestacks)
+ (let* ((hw (find hw-need-write-stack? (current-hw-list)))
+ (modes write-stack-memory-mode-names)
+ (hw-pairs (map (lambda (h) (list (gen-c-symbol (obj:name h))
+ (obj:name (hw-mode h))))
+ hw))
+ (mem-pairs (map (lambda (m) (list (string-append (symbol->string m)
+ "_memory") m))
+ modes))
+ (all-pairs (append mem-pairs hw-pairs))
+
+ (h1 "\n\n// write stacks used in parallel execution\n\n struct write_stacks\n {\n // types of stacks\n\n")
+ (wb (string-append
+ "\n\n // unified writeback function (defined in @prefix@-write.cc)"
+ "\n void writeback (int tick, @cpu@::@cpu@_cpu* current_cpu);"
+ "\n // unified write-stack clearing function (defined in @prefix@-write.cc)"
+ "\n void reset ();"))
+ (zz "\n\n }; // end struct @prefix@::write_stacks \n\n"))
+ (string-append
+ (/hw-gen-write-struct-decl)
+ (foldl (lambda (s pair) (string-append s (apply /hw-gen-write-stack-decl pair))) h1 all-pairs)
+ wb
+ zz)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; end stack-based write schedule
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
; Generate the definition of the structure that holds register values, etc.
-; for use during parallel execution. When instructions are executed parallelly
-; either
-; - their inputs are read before their outputs are written. Thus we have to
-; fetch the input values of several instructions before executing any of them.
-; - or their outputs are queued here first and then written out after all insns
-; have executed.
-; The fetched/queued values are stored in an array of PAREXEC structs, one
-; element per instruction.
-
-(define (gen-parallel-exec-type)
- (logit 2 "Generating PAREXEC type ...\n")
- (string-append
- (if (with-parallel-write?)
- "/* Queued output values of an instruction. */\n"
- "/* Fetched input values of an instruction. */\n")
- "\
+; for use during parallel execution.
+
+(define (gen-write-stack-structure)
+ (let ((membuf-sz (/calculated-memory-write-buffer-size))
+ (max-delay (cpu-max-delay (current-cpu))))
+ (logit 2 "Generating write stack structure ...\n")
+ (string-append
+ " static const int max_delay = "
+ (number->string max-delay) ";\n"
+ " static const int pipe_sz = "
+ (number->string (+ 1 max-delay)) "; // max_delay + 1\n"
-struct @prefix@_parexec {
- union {\n"
- (string-map gen-parallel-exec-elm (current-sfmt-list))
- "\
- } operands;
- /* For conditionally written operands, bitmask of which ones were. */
- unsigned long long written;
-};\n\n"
- )
-)
+"
+ template <typename ELT>
+ struct write_stack
+ {
+ int t;
+ const int sz;
+ ELT buf[WRITE_BUF_SZ];
+
+ write_stack () : t(-1), sz(WRITE_BUF_SZ) {}
+ inline bool empty () { return (t == -1); }
+ inline void clear () { t = -1; }
+ inline void pop () { if (t > -1) t--;}
+ inline void push (const ELT &e) { if (t+1 < sz) buf [++t] = e;}
+ inline ELT &top () { return buf [t>0 ? ( t<sz ? t : sz-1) : 0];}
+ };
+
+ // look ahead for latest write with index = idx, where time of write is
+ // <= dist steps from base (present) in write_stack array st.
+ // returning def if no scheduled write is found.
+
+ template <typename STKS, typename VAL>
+ inline VAL lookahead (int dist, int base, STKS &st, VAL def, int idx=0)
+ {
+ for (; dist > 0; --dist)
+ {
+ write_stack <VAL> &v = st [(base + dist) % pipe_sz];
+ for (int i = v.t; i > 0; --i)
+ if (v.buf [i].idx0 == idx) return v.buf [i];
+ }
+ return def;
+ }
+
+"
+
+ (/gen-writestacks)
+ )))
; Generate the TRACE_RECORD struct definition.
-(define (-gen-trace-record-type)
+(define (/gen-trace-record-type)
(string-list
"\
/* Collection of various things for the trace handler to use. */
; Generate <cpu>-defs.h
(define (cgen-defs.h)
- (logit 1 "Generating " (gen-cpu-name) " defs.h ...\n")
+ (logit 1 "Generating " (gen-cpu-name) "-defs.h ...\n")
(assert-keep-one)
; Turn parallel execution support on if cpu needs it.
#ifndef DEFS_@PREFIX@_H
#define DEFS_@PREFIX@_H
+")
+ (if (with-parallel?)
+ (string-write "\
+#include <stack>
+#include \"cgen-types.h\"
+
+// forward declaration\n\n
namespace @cpu@ {
-\n"
+struct @cpu@_cpu;
+}
- (if (with-parallel?)
- gen-parallel-exec-type
- "")
+namespace @prefix@ {
- "\
-} // end @cpu@ namespace
+using namespace cgen;
+
+"
+ gen-write-stack-structure
+ "\
+} // end @prefix@ namespace
+"))
+ (string-write "\
#endif /* DEFS_@PREFIX@_H */\n"
)
; Return C code to fetch and save all output operands to instructions with
; <sformat> SFMT.
-(define (-gen-write-args sfmt)
- (string-map (lambda (op) (op:write op sfmt))
- (sfmt-out-ops sfmt))
-)
-
-; Utility of gen-write-fns to generate a writer function for <sformat> SFMT.
-
-(define (-gen-write-fn sfmt)
- (logit 2 "Processing write function for \"" (obj:name sfmt) "\" ...\n")
- (string-list
- "\nsem_status\n"
- (-gen-write-fn-name sfmt) " (@cpu@_cpu* current_cpu, @prefix@_scache* sem, @prefix@_parexec* par_exec)\n"
- "{\n"
- (if (with-scache?)
- (gen-define-field-macro sfmt)
- "")
- (gen-define-parallel-operand-macro sfmt)
- " @prefix@_scache* abuf = sem;\n"
- " unsigned long long written = abuf->written;\n"
- " PCADDR pc = abuf->addr;\n"
- " PCADDR npc = 0; // dummy value for branches\n"
- " sem_status status = SEM_STATUS_NORMAL; // ditto\n"
- "\n"
- (-gen-write-args sfmt)
- "\n"
- " return status;\n"
- (gen-undef-parallel-operand-macro sfmt)
- (if (with-scache?)
- (gen-undef-field-macro sfmt)
- "")
- "}\n\n")
-)
-
-(define (-gen-write-fns)
- (logit 2 "Processing writer functions ...\n")
- (string-write-map (lambda (sfmt) (-gen-write-fn sfmt))
- (current-sfmt-list))
-)
-
; Generate <cpu>-write.cxx.
+(define (/gen-register-writer nm mode dims)
+ (let* ((pad " ")
+ (sa string-append)
+ (mode (symbol->string mode))
+ (idx-args (string-map (lambda (x) (sa "w.idx" (number->string x) ", "))
+ (iota dims))))
+ (sa pad "while (! " nm "_writes[tick].empty())\n"
+ pad "{\n"
+ pad " write<" mode "> &w = " nm "_writes[tick].top();\n"
+ pad " current_cpu->" nm "_set(" idx-args "w.val);\n"
+ pad " " nm "_writes[tick].pop();\n"
+ pad "}\n\n")))
+
+(define (/gen-memory-writer nm mode dims)
+ (let* ((pad " ")
+ (sa string-append)
+ (mode (symbol->string mode))
+ (idx-args (string-map (lambda (x) (sa ", w.idx" (number->string x) ""))
+ (iota dims))))
+ (sa pad "while (! " nm "_writes[tick].empty())\n"
+ pad "{\n"
+ pad " write<" mode "> &w = " nm "_writes[tick].top();\n"
+ pad " current_cpu->SETMEM" mode " (w.pc" idx-args ", w.val);\n"
+ pad " " nm "_writes[tick].pop();\n"
+ pad "}\n\n")))
+
+
+(define (/gen-reset-fn)
+ (let* ((sa string-append)
+ (objs (append (map (lambda (h) (gen-c-symbol (obj:name h)))
+ (find hw-need-write-stack? (current-hw-list)))
+ (map (lambda (m) (sa (symbol->string m) "_memory"))
+ write-stack-memory-mode-names)))
+ (clr (lambda (elt) (sa " clear_stacks (" elt "_writes);\n"))))
+ (sa
+ " template <typename ST> \n"
+ " static void clear_stacks (ST &st)\n"
+ " {\n"
+ " for (int i = 0; i < @prefix@::pipe_sz; i++)\n"
+ " st[i].clear();\n"
+ " }\n\n"
+ " void @prefix@::write_stacks::reset ()\n {\n"
+ (string-map clr objs)
+ " }")))
+
+(define (/gen-unified-write-fn)
+ (let* ((hw (find hw-need-write-stack? (current-hw-list)))
+ (modes write-stack-memory-mode-names)
+ (hw-triples (map (lambda (h) (list (gen-c-symbol (obj:name h))
+ (obj:name (hw-mode h))
+ (length (/hw-vector-dims h))))
+ hw))
+ (mem-triples (map (lambda (m) (list (string-append (symbol->string m)
+ "_memory")
+ m 1))
+ modes)))
+ (logit 2 "Generating writer function ...\n")
+ (string-append
+ "
+ void @prefix@::write_stacks::writeback (int tick, @cpu@::@cpu@_cpu* current_cpu)
+ {
+"
+ "\n // register writeback loops\n"
+ (string-map (lambda (t) (apply /gen-register-writer t)) hw-triples)
+ "\n // memory writeback loops\n"
+ (string-map (lambda (t) (apply /gen-memory-writer t)) mem-triples)
+"
+ }
+")))
+
(define (cgen-write.cxx)
- (logit 1 "Generating " (gen-cpu-name) " write.cxx ...\n")
+ (logit 1 "Generating " (gen-cpu-name) "-write.cxx ...\n")
(assert-keep-one)
(sim-analyze-insns!)
"\
#include \"@cpu@.h\"
-using namespace @cpu@;
"
- -gen-write-fns
+ /gen-reset-fn
+ /gen-unified-write-fn
)
)
\f
; Return C code to perform the semantics of INSN.
(define (gen-semantic-code insn)
- ; Indicate generating code for INSN.
- ; Use the compiled form if available.
- ; The case when they're not available is for virtual insns.
- (let ((sem-c-code
- (if (insn-compiled-semantics insn)
- (rtl-c++-parsed VOID (insn-compiled-semantics insn) nil
- #:rtl-cover-fns? #t
- #:owner insn)
- (rtl-c++ VOID (insn-semantics insn) nil
- #:rtl-cover-fns? #t
- #:owner insn)))
- )
- sem-c-code)
+ (cond ((insn-compiled-semantics insn)
+ => (lambda (sem)
+ (rtl-c++-parsed VOID sem
+ #:for-insn? #t
+ #:rtl-cover-fns? #t
+ #:owner insn)))
+ ((insn-canonical-semantics insn)
+ => (lambda (sem)
+ (rtl-c++-parsed VOID sem
+ #:for-insn? #t
+ #:rtl-cover-fns? #t
+ #:owner insn)))
+ (else
+ (context-error (make-obj-context insn #f)
+ "While generating semantic code"
+ "semantics of insn are not canonicalized")))
)
; Return definition of C function to perform INSN.
; This version handles the with-scache case.
-(define (-gen-scache-semantic-fn insn)
+(define (/gen-scache-semantic-fn insn)
(logit 2 "Processing semantics for " (obj:name insn) ": \"" (insn-syntax insn) "\" ...\n")
- (set! -with-profile? -with-profile-fn?)
+ (set! /with-profile? /with-profile-fn?)
(let ((cti? (insn-cti? insn))
(insn-len (insn-length-bytes insn)))
(string-list
"sem_status\n")
"@prefix@_sem_" (gen-sym insn)
(if (with-parallel?)
- " (@cpu@_cpu* current_cpu, @prefix@_scache* sem, @prefix@_parexec* par_exec)\n"
+ (string-append " (@cpu@_cpu* current_cpu, @prefix@_scache* sem, const int tick, \n\t"
+ "@prefix@::write_stacks &buf)\n")
" (@cpu@_cpu* current_cpu, @prefix@_scache* sem)\n")
"{\n"
(gen-define-field-macro (insn-sfmt insn))
- (if (with-parallel?)
- (gen-define-parallel-operand-macro (insn-sfmt insn))
- "")
" sem_status status = SEM_STATUS_NORMAL;\n"
" @prefix@_scache* abuf = sem;\n"
; Unconditionally written operands are not recorded here.
; Otherwise we know they're all written so there's no point in
; keeping track.
(if (or (with-profile?) (with-parallel-write?))
- (if (-any-cond-written? (insn-sfmt insn))
+ (if (/any-cond-written? (insn-sfmt insn))
" abuf->written = written;\n"
"")
"")
(if (with-parallel?)
""
" return status;\n")
- (if (with-parallel?)
- (gen-undef-parallel-operand-macro (insn-sfmt insn))
- "")
(gen-undef-field-macro (insn-sfmt insn))
- "}\n\n"
+ "}\n\n"
))
)
-(define (-gen-all-semantic-fns)
+(define (/gen-all-semantic-fns)
(logit 2 "Processing semantics ...\n")
(let ((insns (scache-engine-insns)))
(if (with-scache?)
- (string-write-map -gen-scache-semantic-fn insns)
+ (string-write-map /gen-scache-semantic-fn insns)
(error "must specify `with-scache'")))
)
; Each instruction is implemented in its own function.
(define (cgen-semantics.cxx)
- (logit 1 "Generating " (gen-cpu-name) " semantics.cxx ...\n")
+ (logit 1 "Generating " (gen-cpu-name) "-semantics.cxx ...\n")
(assert-keep-one)
(sim-analyze-insns!)
#endif
#include \"@cpu@.h\"
-using namespace @cpu@; // FIXME: namespace organization still wip
-
+using namespace @cpu@; // FIXME: namespace organization still wip\n")
+ (if (with-parallel?)
+ (string-write "\
+using namespace @prefix@; // FIXME: namespace organization still wip\n"))
+ (string-write "\
#define GET_ATTR(name) GET_ATTR_##name ()
\n"
- -gen-all-semantic-fns
+ /gen-all-semantic-fns
)
)
\f
; The semantic switch engine has two flavors: one case per insn, and one
; case per "frag" (where each insn is split into one or more fragments).
-; Utility of -gen-sem-case to return the mask of operands always written
+; Utility of /gen-sem-case to return the mask of operands always written
; to in <sformat> SFMT.
; ??? Not currently used.
-(define (-uncond-written-mask sfmt)
+(define (/uncond-written-mask sfmt)
(apply + (map (lambda (op)
(if (op:cond? op)
0
(sfmt-out-ops sfmt)))
)
-; Utility of -gen-sem-case to return #t if any operand in <sformat> SFMT is
+; Utility of /gen-sem-case to return #t if any operand in <sformat> SFMT is
; conditionally written to.
-(define (-any-cond-written? sfmt)
+(define (/any-cond-written? sfmt)
(any-true? (map op:cond? (sfmt-out-ops sfmt)))
)
\f
; Generate a switch case to perform INSN.
-(define (-gen-sem-case insn parallel?)
+(define (/gen-sem-case insn parallel?)
(logit 2 "Processing "
(if parallel? "parallel " "")
- "semantic switch case for \"" (insn-syntax insn) "\" ...\n")
- (set! -with-profile? -with-profile-sw?)
+ "semantic switch case for " (obj:name insn) ": \""
+ (insn-syntax insn) "\" ...\n")
+ (set! /with-profile? /with-profile-sw?)
(let ((cti? (insn-cti? insn))
(insn-len (insn-length-bytes insn)))
(string-list
(if (with-scache?)
(gen-define-field-macro (insn-sfmt insn))
"")
- (if parallel?
- (gen-define-parallel-operand-macro (insn-sfmt insn))
- "")
; Unconditionally written operands are not recorded here.
(if (or (with-profile?) (with-parallel-write?))
" unsigned long long written = 0;\n"
(isa-setup-semantics (current-isa)))
(string-append
" "
- (rtl-c++ VOID (isa-setup-semantics (current-isa)) nil
+ (rtl-c++ VOID (obj-isa-list insn) nil
+ (isa-setup-semantics (current-isa))
+ #:for-insn? #t
#:rtl-cover-fns? #t
#:owner insn))
"")
; Otherwise we know they're all written so there's no point in
; keeping track.
(if (or (with-profile?) (with-parallel-write?))
- (if (-any-cond-written? (insn-sfmt insn))
+ (if (/any-cond-written? (insn-sfmt insn))
" abuf->written = written;\n"
"")
"")
(string-append " pbb_br_npc = npc;\n"
" pbb_br_status = br_status;\n")
"")
- (if parallel?
- (gen-undef-parallel-operand-macro (insn-sfmt insn))
- "")
(if (with-scache?)
(gen-undef-field-macro (insn-sfmt insn))
"")
))
)
-(define (-gen-sem-switch)
+(define (/gen-sem-switch)
(logit 2 "Processing semantic switch ...\n")
; Turn parallel execution support off.
(set-with-parallel?! #f)
- (string-write-map (lambda (insn) (-gen-sem-case insn #f))
+ (string-write-map (lambda (insn) (/gen-sem-case insn #f))
(non-multi-insns (non-alias-insns (current-insn-list))))
)
; reduces the amount of code, though it is believed that in this particular
; instance the win isn't big enough.
-(define (-gen-parallel-sem-switch)
+(define (/gen-parallel-sem-switch)
(logit 2 "Processing parallel insn semantic switch ...\n")
; Turn parallel execution support on.
(set-with-parallel?! #t)
(string-write-map (lambda (insn)
- (string-list (-gen-sem-case insn #t)
- (-gen-write-case (insn-sfmt insn) insn)))
+ (string-list (/gen-sem-case insn #t)
+ (/gen-write-case (insn-sfmt insn) insn)))
(parallel-insns (current-insn-list)))
)
; Return computed-goto engine.
-(define (-gen-sem-switch-engine)
+(define (/gen-sem-switch-engine)
(string-write
"\
void
@prefix@_idesc::idesc_table[labels[i].insn].cgoto.label = labels[i].label;
// confirm that table is all filled up
- for (int i = 0; i <= @PREFIX@_INSN_" (-last-insn) "; i++)
+ for (int i = 0; i <= @PREFIX@_INSN_" (/last-insn) "; i++)
assert (@prefix@_idesc::idesc_table[i].cgoto.label != 0);
// Initialize the compiler virtual insn.
{
"
- -gen-sem-switch
+ /gen-sem-switch
(if (state-parallel-exec?)
- -gen-parallel-sem-switch
+ /gen-parallel-sem-switch
"")
"
; Return declaration of frag enum.
-(define (-gen-sfrag-enum-decl frag-list)
+(define (/gen-sfrag-enum-decl frag-list)
(gen-enum-decl "@prefix@_frag_type"
"semantic fragments in cpu family @prefix@"
"@PREFIX@_FRAG_"
; Return header file decls for semantic frag threaded engine.
-(define (-gen-sfrag-engine-decls)
+(define (/gen-sfrag-engine-decls)
(string-write
"namespace @cpu@ {\n\n"
; FIXME: vector->list
- (-gen-sfrag-enum-decl (vector->list (sim-sfrag-frag-table)))
+ (/gen-sfrag-enum-decl (vector->list (sim-sfrag-frag-table)))
"\
struct @prefix@_insn_frag {
; LOCALS is a list of sequence locals made global to all frags.
; Each element is (symbol <mode> "c-var-name").
-(define (-gen-sfrag-code frag locals)
- ; Indicate generating code for FRAG.
- ; Use the compiled form if available.
- ; The case when they're not available is for virtual insns.
- (let ((sem (sfrag-compiled-semantics frag))
+(define (/gen-sfrag-code frag locals)
+ (let ((sem (sfrag-semantics frag))
; If the frag has one owner, use it. Otherwise indicate the owner is
; unknown. In cases where the owner is needed by the semantics, the
- ; frag should have only one owner.
+ ; frag should have only one owner. In practice this means that frags
+ ; with the ref,current-insn rtx cannot be used by multiple insns.
(owner (if (= (length (sfrag-users frag)) 1)
(car (sfrag-users frag))
- #f))
- )
- (if sem
- (rtl-c++-parsed VOID sem locals
- #:rtl-cover-fns? #t
- #:owner owner)
- (rtl-c++ VOID (sfrag-semantics frag) locals
- #:rtl-cover-fns? #t
- #:owner owner)))
+ #f)))
+ ;; NOTE: (sfrag-users frag) is nil for the x-header and x-trailer frags.
+ ;; They are just nops.
+ (rtl-c++ VOID (and owner (obj-isa-list owner)) locals sem
+ #:for-insn? #t
+ #:rtl-cover-fns? #t
+ #:owner owner))
)
; Generate a switch case to perform FRAG.
; LOCALS is a list of sequence locals made global to all frags.
; Each element is (symbol <mode> "c-var-name").
-(define (-gen-sfrag-case frag locals)
- (set! -with-profile? -with-profile-sw?)
+(define (/gen-sfrag-case frag locals)
+ (set! /with-profile? /with-profile-sw?)
(let ((cti? (sfmt-cti? (sfrag-sfmt frag)))
(parallel? (sfrag-parallel? frag)))
(logit 2 "Processing "
(if parallel? "parallel " "")
- "semantic switch case for \"" (obj:name frag) "\" ...\n")
+ "semantic switch case for " (obj:name frag) " ...\n")
(string-list
; FRAG_ is prepended here and not elsewhere to avoid name collisions
; with symbols like AND, etc.
" vpc = vpc + 1;\n")
"")
(gen-define-field-macro (sfrag-sfmt frag))
- (if parallel?
- (gen-define-parallel-operand-macro (sfrag-sfmt frag))
- "")
; Unconditionally written operands are not recorded here.
(if (or (with-profile?) (with-parallel-write?))
" unsigned long long written = 0;\n"
(isa-setup-semantics (current-isa)))
(string-append
" "
- (rtl-c++ VOID (isa-setup-semantics (current-isa)) nil
+ (rtl-c++ VOID (list (obj:name (current-isa))) nil
+ (isa-setup-semantics (current-isa))
#:rtl-cover-fns? #t
#:owner #f))
"")
"\n"
- (-gen-sfrag-code frag locals)
+ (/gen-sfrag-code frag locals)
"\n"
; Only update what's been written if some are conditionally written.
; Otherwise we know they're all written so there's no point in
; keeping track.
(if (or (with-profile?) (with-parallel-write?))
- (if (-any-cond-written? (sfrag-sfmt frag))
+ (if (/any-cond-written? (sfrag-sfmt frag))
" abuf->written = written;\n"
"")
"")
(string-append " pbb_br_npc = npc;\n"
" pbb_br_status = br_status;\n")
"")
- (if parallel?
- (gen-undef-parallel-operand-macro (sfrag-sfmt frag))
- "")
(gen-undef-field-macro (sfrag-sfmt frag))
" }\n"
(if (sfrag-trailer? frag)
)
; Convert locals from form computed by sem-find-common-frags to that needed by
-; -gen-sfrag-engine-code (and ultimately rtl-c++).
+; /gen-sfrag-engine-code (and ultimately rtl-c++).
-(define (-frag-convert-c-locals locals)
+(define (/frag-convert-c-locals locals)
(map (lambda (local)
(list (car local) (mode:lookup (cadr local))
(gen-c-symbol (car local))))
; Return definition of insn frag usage table.
-(define (-gen-sfrag-engine-frag-table insn-list frag-table frag-usage)
+(define (/gen-sfrag-engine-frag-table insn-list frag-table frag-usage)
(string-write
"\
// Table of frags used by each insn.
; LOCALS is a list of sequence locals made global to all frags.
; Each element is (symbol <mode> "c-var-name").
-(define (-gen-sfrag-engine-fn frag-table locals)
+(define (/gen-sfrag-engine-fn frag-table locals)
(string-write
"\
void
// Allocate frag label table and point idesc table entries at it.
// FIXME: Temporary hack, to be redone.
static void** frag_label_table;
- int max_insns = @PREFIX@_INSN_" (-last-insn) " + 1;
+ int max_insns = @PREFIX@_INSN_" (/last-insn) " + 1;
int tabsize = max_insns * 4;
frag_label_table = new void* [tabsize];
memset (frag_label_table, 0, sizeof (void*) * tabsize);
; ??? Still needed?
(set-with-parallel?! #f)
(string-write-map (lambda (frag)
- (-gen-sfrag-case frag locals))
+ (/gen-sfrag-case frag locals))
; FIXME: vector->list
(vector->list frag-table)))
\n")
)
-(define (-gen-sfrag-engine)
+(define (/gen-sfrag-engine)
(string-write
(lambda ()
- (-gen-sfrag-engine-frag-table (sim-sfrag-insn-list)
+ (/gen-sfrag-engine-frag-table (sim-sfrag-insn-list)
(sim-sfrag-frag-table)
(sim-sfrag-usage-table)))
(lambda ()
- (-gen-sfrag-engine-fn (sim-sfrag-frag-table)
- (-frag-convert-c-locals (sim-sfrag-locals-list))))
+ (/gen-sfrag-engine-fn (sim-sfrag-frag-table)
+ (/frag-convert-c-locals (sim-sfrag-locals-list))))
)
)
\f
; Generate sem-switch.cxx.
(define (cgen-sem-switch.cxx)
- (logit 1 "Generating " (gen-cpu-name) " sem-switch.cxx ...\n")
+ (logit 1 "Generating " (gen-cpu-name) "-sem-switch.cxx ...\n")
(sim-analyze-insns!)
(if (with-sem-frags?)
\n"
(if (with-sem-frags?)
- -gen-sfrag-engine-decls
+ /gen-sfrag-engine-decls
"")
(if (with-sem-frags?)
- -gen-sfrag-engine
- -gen-sem-switch-engine)
+ /gen-sfrag-engine
+ /gen-sem-switch-engine)
)
)