OSDN Git Service

*** empty log message ***
[pf3gnuchains/sourceware.git] / cgen / sid-cpu.scm
index 4ddc44d..1e5367d 100644 (file)
@@ -1,17 +1,17 @@
 ; 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))
@@ -22,7 +22,7 @@
 
 ; 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"
@@ -59,7 +59,7 @@
 
 
 ; 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 "
@@ -71,7 +71,7 @@
 ; 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
@@ -104,12 +111,11 @@ namespace @arch@ {
 
 ; 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))
@@ -117,10 +123,12 @@ namespace @arch@ {
                              (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
@@ -133,11 +141,12 @@ namespace @arch@ {
                              (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."
@@ -169,10 +178,14 @@ namespace @arch@ {
        (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.
       ""
@@ -181,7 +194,7 @@ namespace @arch@ {
           (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 "_")
@@ -193,16 +206,95 @@ namespace @arch@ {
 ; 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.
@@ -220,12 +312,14 @@ namespace @arch@ {
 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"
    )
@@ -238,7 +332,7 @@ public:
 ; 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.
@@ -258,7 +352,7 @@ public:
 
 ; 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
@@ -295,72 +389,154 @@ typedef struct {
    )
 )
 
-; 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.  */
@@ -376,7 +552,7 @@ typedef struct @prefix@_trace_record {
 ; 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.
@@ -392,15 +568,27 @@ typedef struct @prefix@_trace_record {
 #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"
    )
@@ -417,50 +605,81 @@ namespace @cpu@ {
 ; 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!)
@@ -479,10 +698,10 @@ namespace @cpu@ {
    "\
 
 #include \"@cpu@.h\"
-using namespace @cpu@;
 
 "
-   -gen-write-fns
+   /gen-reset-fn
+   /gen-unified-write-fn
    )
 )
 \f
@@ -492,27 +711,30 @@ using namespace @cpu@;
 ; 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
@@ -522,13 +744,11 @@ using namespace @cpu@;
         "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.
@@ -547,7 +767,7 @@ using namespace @cpu@;
      ; 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"
             "")
         "")
@@ -557,19 +777,16 @@ using namespace @cpu@;
      (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'")))
 )
 
@@ -577,7 +794,7 @@ using namespace @cpu@;
 ; 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!)
@@ -601,13 +818,16 @@ using namespace @cpu@;
 #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
@@ -617,11 +837,11 @@ using namespace @cpu@; // FIXME: namespace organization still wip
 ; 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
@@ -629,10 +849,10 @@ using namespace @cpu@; // FIXME: namespace organization still wip
                (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
@@ -640,11 +860,12 @@ using namespace @cpu@; // FIXME: namespace organization still wip
 
 ; 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
@@ -659,9 +880,6 @@ using namespace @cpu@; // FIXME: namespace organization still wip
      (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"
@@ -679,7 +897,9 @@ using namespace @cpu@; // FIXME: namespace organization still wip
              (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))
         "")
@@ -690,7 +910,7 @@ using namespace @cpu@; // FIXME: namespace organization still wip
      ; 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"
             "")
         "")
@@ -698,9 +918,6 @@ using namespace @cpu@; // FIXME: namespace organization still wip
         (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))
         "")
@@ -709,11 +926,11 @@ using namespace @cpu@; // FIXME: namespace organization still wip
      ))
 )
 
-(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))))
 )
 
@@ -727,19 +944,19 @@ using namespace @cpu@; // FIXME: namespace organization still wip
 ; 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
@@ -798,7 +1015,7 @@ 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.
@@ -834,10 +1051,10 @@ restart:
   {
 "
 
-  -gen-sem-switch
+  /gen-sem-switch
 
    (if (state-parallel-exec?)
-       -gen-parallel-sem-switch
+       /gen-parallel-sem-switch
        "")
 
 "
@@ -859,7 +1076,7 @@ restart:
 
 ; 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_"
@@ -874,12 +1091,12 @@ restart:
 
 ; 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 {
@@ -901,38 +1118,34 @@ struct @prefix@_pbb_label {
 ; 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.
@@ -954,9 +1167,6 @@ struct @prefix@_pbb_label {
                        "      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"
@@ -976,18 +1186,19 @@ struct @prefix@_pbb_label {
              (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"
             "")
         "")
@@ -997,9 +1208,6 @@ struct @prefix@_pbb_label {
         (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)
@@ -1010,9 +1218,9 @@ struct @prefix@_pbb_label {
 )
 
 ; 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))))
@@ -1021,7 +1229,7 @@ struct @prefix@_pbb_label {
 
 ; 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.
@@ -1047,7 +1255,7 @@ const @prefix@_insn_frag @prefix@_frag_usage[] = {\n"
 ; 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
@@ -1098,7 +1306,7 @@ 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);
@@ -1176,7 +1384,7 @@ restart:
      ; ??? 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)))
 
@@ -1195,22 +1403,22 @@ restart:
 \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?)
@@ -1240,11 +1448,11 @@ using namespace @cpu@; // FIXME: namespace organization still wip
 \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)
    )
 )