1 ; CPU documentation generator, html output
2 ; Copyright (C) 2003, 2009 Doug Evans
3 ; This file is part of CGEN. See file COPYING.CGEN for details.
6 ; - assumes names, comments, etc. don't interfere with html.
7 ; Just like in generation of C there are routines to C-ize symbols,
8 ; we need to pass output through an html-izer.
9 ; - make generated html more readable, e.g. more indentation
10 ; - should really print the semantics in pseudo-C, a much better form for
11 ; the intended audience
12 ; - registers that have multiple independent fields (like x86 eflags)
13 ; need to be printed like instruction formats are
14 ; - uses some deprecated html, use css at very least
16 ; - mapping from operands to h/w isn't as clear as it needs to be
17 ; - for insn formats, if field is large consider printing "n ... m",
18 ; would want "n" left justified and "m" right justified though
19 ; - for insn formats, consider printing them better,
20 ; e.g. maybe generate image and include that instead
21 ; - need ability to specify more prose for each architecture
23 ; - need to add docs to website that can be linked to here, rather than
24 ; including generic cgen documentation here
25 ; - function units, timing, etc.
26 ; - instruction framing
28 ; Global state variables.
30 ; Specify which application.
31 (set! APPLICATION 'DOC)
33 ; String containing copyright text.
34 (define CURRENT-COPYRIGHT #f)
36 ; String containing text defining the package we're generating code for.
37 (define CURRENT-PACKAGE #f)
41 THIS FILE IS MACHINE GENERATED WITH CGEN.
43 See the input .cpu file(s) for copyright information.
48 ; Initialize the options.
50 (define (option-init!)
51 (set! CURRENT-COPYRIGHT copyright-doc)
52 (set! CURRENT-PACKAGE package-cgen)
56 ; Handle an option passed in from the command line.
58 (define (option-set! name value)
60 ((copyright) (cond ((equal? value '("doc"))
61 (set! CURRENT-COPYRIGHT copyright-doc))
62 (else (error "invalid copyright value" value))))
63 ((package) (cond ((equal? value '("cgen"))
64 (set! CURRENT-PACKAGE package-cgen))
65 (else (error "invalid package value" value))))
66 (else (error "unknown option" name))
73 ; Return COPYRIGHT, with FILE-DESC as the first line
74 ; and PACKAGE as the name of the package which the file belongs in.
75 ; COPYRIGHT is a pair of (header . trailer).
77 (define (gen-html-copyright file-desc copyright package)
78 (string-append "<! " file-desc "\n\n"
85 ; KIND is one of "Architecture" or "Instruction".
86 ; TODO: Add author arg so all replies for this arch go to right person.
88 (define (gen-html-header kind)
89 (let* ((arch (symbol->string (current-arch-name)))
90 (ARCH (string-upcase arch)))
92 "<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">\n"
95 " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">\n"
96 " <meta name=\"description\" content=\"" ARCH " " kind " Documentation\">\n"
97 " <meta name=\"language\" content=\"en-us\">\n"
98 " <meta name=\"owner\" content=\"dje@sebabeach.org (Doug Evans)\">\n"
99 " <meta name=\"reply-to\" content=\"dje@sebabeach.org (Doug Evans)\">\n"
100 " <title>" ARCH " " kind " Documentation</title>\n"
102 "<body bgcolor=\"#F0F0F0\" TEXT=\"#003333\" LINK=\"#FF0000\" VLINK=\"#444444\" alink=\"#000000\">\n"
107 (define (gen-html-trailer)
111 "This documentation was machine generated from the cgen cpu description\n"
112 "files for this architecture.\n"
114 "<a href=\"http://sources.redhat.com/cgen/\">http://sources.redhat.com/cgen/</a>\n"
120 ; INSN-FILE is the name of the .html file containing instruction definitions.
122 (define (gen-table-of-contents insn-file)
123 (let ((ARCH (string-upcase (symbol->string (current-arch-name)))))
126 (string-append ARCH " Architecture Documentation")
130 "DISCLAIMER: This documentation is derived from the cgen cpu description\n"
131 "of this architecture, and does not represent official documentation\n"
132 "of the chip maker.\n"
136 "<li><a href=\"#arch\">Architecture</a></li>\n"
137 "<li><a href=\"#machines\">Machine variants</a></li>\n"
138 "<li><a href=\"#models\">Model variants</a></li>\n"
139 "<li><a href=\"#registers\">Registers</a></li>\n"
140 "<li><a href=\"" insn-file "#insns\">Instructions</a></li>\n"
141 "<li><a href=\"" insn-file "#macro-insns\">Macro instructions</a></li>\n"
142 "<li><a href=\"#assembler\">Assembler supplemental</a></li>\n"
145 ; TODO: Move this to the cgen website, and include a link here.
146 "In cgen-parlance, an architecture consists of machines and models.\n"
147 "A `machine' is the specification of a variant of the architecture,\n"
148 "and a `model' is the implementation of that specification.\n"
149 "Typically there is a one-to-one correspondance between machine and model.\n"
150 "The distinction allows for separation of what application programs see\n"
151 "(the machine), and how to tune for the chip (what the compiler sees).\n"
153 "A \"cpu family\" is a cgen concoction to help organize the generated code.\n"
154 "Chip variants that are quite dissimilar can be treated separately by the\n"
155 "generated code even though they're both members of the same architecture.\n"
159 ; Utility to print a list entry for NAME/COMMENT, kind KIND
160 ; which is a link to the entry's description.
161 ; KIND is one of "mach", "model", etc.
163 (define (gen-list-entry name comment kind)
164 (string-append "<li>"
165 "<a href=\"#" kind "-" (->string name) "\">"
173 ; Cover-fn to gen-list-entry for use with objects.
175 (define (gen-obj-list-entry o kind)
176 (gen-list-entry (obj:name o) (obj:comment o) kind)
179 ; Utility to print the header for the description of TEXT.
181 (define (gen-doc-header text anchor-name)
183 "<a name=\"" anchor-name "\"></a>\n"
184 "<h3>" text "</h3>\n"
188 ; Cover-fn to gen-doc-header for use with objects.
189 ; KIND is one of "mach", "model", etc.
191 (define (gen-obj-doc-header o kind)
192 (gen-doc-header (string-append (obj:str-name o) " - " (obj:comment o))
193 (string-append kind "-" (obj:str-name o)))
198 (define (gen-cpu-intro cpu)
201 (obj:str-name cpu) " - " (obj:comment cpu) "\n"
206 (string-list-map gen-mach-intro
207 (alpha-sort-obj-list (machs-for-cpu cpu)))
214 (define (gen-mach-intro mach)
217 (obj:str-name mach) " - " (obj:comment mach) "\n"
222 (string-list-map gen-model-intro
223 (alpha-sort-obj-list (models-for-mach mach)))
230 (define (gen-model-intro model)
233 (obj:str-name model) " - " (obj:comment model) "\n"
239 (define (gen-isa-intro isa)
242 (obj:str-name isa) " - " (obj:comment isa) "\n"
245 ; I'd like to include the .cpu file tag here, but using English text
246 ; feels more appropriate. Having both is excessive.
247 ; Pick one, and have a link to its description/tag.
248 ; I'm leaning toward using the cgen tag here as we'll probably want
249 ; access (via an html tag) to more than one-liner descriptions.
251 "<li>default-insn-word-bitsize: "
252 (number->string (isa-default-insn-word-bitsize isa))
255 "<li>default-insn-bitsize: "
256 (number->string (isa-default-insn-bitsize isa))
259 "<li>base-insn-bitsize: "
260 (number->string (isa-base-insn-bitsize isa))
263 "<li>decode-assist: "
264 (string-map (lambda (n) (string-append " " (number->string n)))
265 (isa-decode-assist isa))
268 "<li>decode-splits: "
269 (string-map (lambda (n) (string-append " " (number->string n)))
270 (isa-decode-splits isa))
273 (if (> (isa-liw-insns isa) 1)
274 (string-append "<li>liw-insns: "
275 (number->string (isa-liw-insns isa))
279 (if (> (isa-parallel-insns isa) 1)
280 (string-append "<li>parallel-insns: "
281 (number->string (isa-parallel-insns isa))
285 (if (isa-condition isa)
286 (string-append "<li>condition-field: "
287 (symbol->string (car (isa-condition isa)))
292 "<pre>" ; no trailing newline here on purpose
293 (with-output-to-string
295 (pretty-print (cadr (isa-condition isa)))))
300 (if (isa-setup-semantics isa)
301 (string-append "<li>setup-semantics:\n"
303 "<pre>" ; no trailing newline here on purpose
304 (with-output-to-string
306 (pretty-print (cdr (isa-setup-semantics isa)))))
316 (define (gen-arch-intro)
317 ; NOTE: This includes cpu families.
318 (let ((ARCH (string-upcase (symbol->string (current-arch-name))))
319 (isas (current-isa-list))
320 (cpus (current-cpu-list))
325 "<a name=\"arch\"></a>\n"
326 "<h2>" ARCH " Architecture</h2>\n"
328 "This section describes various things about the cgen description of\n"
329 "the " ARCH " architecture. Familiarity with cgen cpu descriptions\n"
332 "Bit number orientation (arch.lsb0?): "
333 (if (current-arch-insn-lsb0?) "lsb = 0" "msb = 0")
336 "<h3>ISA description</h3>\n"
337 ; NOTE: For the normal case there's only one isa, thus specifying it in
338 ; a list is excessive. Later.
341 (string-list-map gen-isa-intro
342 (alpha-sort-obj-list isas))
345 "<h3>CPU Families</h3>\n"
347 (string-list-map gen-cpu-intro
348 (alpha-sort-obj-list cpus))
355 (define (gen-machine-doc-1 mach)
357 (gen-obj-doc-header mach "mach")
366 (string-map (lambda (isa)
367 (string-append " " (obj:str-name isa)))
375 (define (gen-machine-docs)
376 (let ((machs (alpha-sort-obj-list (current-mach-list))))
380 "<a name=\"machines\"></a>\n"
381 "<h2>Machine variants</h2>\n"
383 (string-map (lambda (o)
384 (gen-obj-list-entry o "mach"))
387 (string-list-map gen-machine-doc-1 machs)
393 (define (gen-model-doc-1 model)
395 (gen-obj-doc-header model "model")
401 (define (gen-model-docs)
402 (let ((models (alpha-sort-obj-list (current-model-list))))
406 "<a name=\"models\"></a>\n"
407 "<h2>Model variants</h2>\n"
409 (string-map (lambda (o)
410 (gen-obj-list-entry o "model"))
413 (string-list-map gen-model-doc-1 models)
419 ; TODO: Provide tables of regs for each mach.
421 ; Subroutine of gen-reg-doc-1 to simplify it.
422 ; Generate a list of names of registers in register array REG.
423 ; The catch is that we want to shrink r0,r1,r2,...,r15 to r0...r15.
425 (define (gen-pretty-reg-array-names reg)
426 ; We currently only support arrays of rank 1 (vectors).
427 (if (!= (hw-rank reg) 1)
428 (error "gen-pretty-reg-array-names: unsupported rank" (hw-rank reg)))
429 (let ((indices (hw-indices reg)))
430 (if (class-instance? <keyword> indices)
431 (let ((values (kw-values indices)))
436 "<table frame=border border=2>\n"
438 (string-list-map (lambda (v)
439 (string-list "<tr>\n"
444 (number->string (cadr v))
451 (define (gen-reg-doc-1 reg)
453 (gen-obj-doc-header reg "reg")
457 (string-map (lambda (mach)
458 (string-append " " (symbol->string mach)))
459 (obj-attr-value reg 'MACH))
464 (number->string (hw-bits reg))
467 (if (not (hw-scalar? reg))
468 (string-list "<li>\n"
470 (string-map (lambda (dim)
471 (string-append "[" (number->string dim) "]"))
474 (gen-pretty-reg-array-names reg)
481 (define (gen-register-docs)
482 (let ((regs (alpha-sort-obj-list (find register? (current-hw-list)))))
486 "<a name=\"registers\"></a>\n"
487 "<h2>Registers</h2>\n"
489 (string-map (lambda (o)
490 (gen-obj-list-entry o "reg"))
493 (string-list-map gen-reg-doc-1 regs)
499 ; Generate a diagram typically used to display instruction fields.
500 ; OPERANDS is a list of numbers (for constant valued ifields)
503 (define (gen-iformat-table-1 bitnums names operands)
505 "<table frame=border border=2>\n"
507 (string-list-map (lambda (b)
508 (string-list "<td>\n"
509 (string-map (lambda (n)
518 (string-list-map (lambda (n)
519 (string-list "<td>\n"
526 (string-list-map (lambda (o)
527 (string-list "<td>\n"
530 (number->string o 16))
539 ; Compute the list of field bit-numbers for each field.
541 (define (get-ifield-bitnums widths lsb0?)
542 (let* ((total-width (apply + widths))
543 (bitnums (iota total-width
544 (if lsb0? (1- total-width) 0)
546 (let loop ((result '()) (widths widths) (bitnums bitnums))
549 (loop (cons (list-take (car widths) bitnums)
552 (list-drop (car widths) bitnums)))))
555 ; Generate a diagram typically used to display instruction fields.
557 (define (gen-iformat-table insn)
558 (let* ((lsb0? (current-arch-insn-lsb0?))
559 (sorted-iflds (sort-ifield-list (insn-iflds insn) (not lsb0?))))
560 (let ((widths (map ifld-length sorted-iflds))
561 (names (map obj:name sorted-iflds))
562 (operands (map (lambda (f)
563 (if (ifld-constant? f)
565 (obj:name (ifld-get-value f))))
567 (gen-iformat-table-1 (get-ifield-bitnums widths lsb0?) names operands)))
570 (define (gen-insn-doc-1 insn)
572 (gen-obj-doc-header insn "insn")
576 (string-map (lambda (mach)
577 (string-append " " (symbol->string mach)))
578 (obj-attr-value insn 'MACH))
591 (gen-iformat-table insn)
594 (if (insn-ifield-assertion insn)
595 (string-append "<li>\n"
596 "instruction field constraint:\n"
598 "<pre>" ; no trailing newline here on purpose
599 (with-output-to-string
601 (pretty-print (insn-ifield-assertion insn))))
609 "<pre>" ; no trailing newline here on purpose
610 (with-output-to-string
612 ; Print the const-folded semantics, computed in `tmp'.
613 (pretty-print (rtx-trim-for-doc (insn-tmp insn)))))
616 ; "<br>\n" ; not present on purpose
617 (if (not (null? (insn-timing insn)))
618 (string-list "<li>\n"
619 "execution unit(s):\n"
625 (string-append "<li>\n"
628 (string-map (lambda (u)
630 (obj:str-name (iunit:unit u))))
631 (timing:units (cdr t)))
634 ; ignore timings for discarded
635 (find (lambda (t) (not (null? (cdr t))))
645 (define (gen-insn-doc-list mach name comment insns)
648 (gen-doc-header (string-append (obj:str-name mach)
651 (if (string=? comment "")
653 (string-append " - " comment)))
654 (string-append "mach-insns-"
659 (string-list-map (lambda (o)
660 (gen-obj-list-entry o "insn"))
666 ; Return boolean indicating if INSN sets the pc.
668 (define (insn-sets-pc? insn)
669 (or (obj-has-attr? insn 'COND-CTI)
670 (obj-has-attr? insn 'UNCOND-CTI)
671 (obj-has-attr? insn 'SKIP-CTI))
674 ; Traverse the semantics of INSN and return a list of symbols
675 ; indicating various interesting properties we find.
676 ; This is taken from `semantic-attrs' which does the same thing to find the
678 ; The result is list of properties computed from the semantics.
679 ; The possibilities are: MEM, FPU.
681 (define (get-insn-properties insn)
682 (logit 2 "Collecting properties of insn " (obj:name insn) " ...\n")
685 ((context #f) ; ??? do we need a better context?
687 ; List of attributes computed from SEM-CODE-LIST.
688 ; The first element is just a dummy so that append! always works.
689 (sem-attrs (list #f))
691 ; Called for expressions encountered in SEM-CODE-LIST.
693 (lambda (rtx-obj expr parent-expr op-pos tstate appstuff)
696 ((operand) (if (memory? (op:type (current-op-lookup (rtx-arg1 expr)
697 (obj-isa-list insn))))
698 ; Don't change to '(MEM), since we use append!.
699 (append! sem-attrs (list 'MEM)))
700 (if (mode-float? (mode:lookup (rtx-mode expr)))
701 ; Don't change to '(FPU), since we use append!.
702 (append! sem-attrs (list 'FPU)))
705 ((mem) (append! sem-attrs (list 'MEM)))
707 ; If this is a syntax expression, the operands won't have been
708 ; processed, so tell our caller we want it to by returning #f.
709 ; We do the same for non-syntax expressions to keep things
710 ; simple. This requires collaboration with the traversal
711 ; handlers which are defined to do what we want if we return #f.
715 ; Traverse the expression recording the attributes.
716 ; We just want the side-effects of computing various properties
717 ; so we discard the result.
719 (rtx-traverse context
721 ; Simplified semantics recorded in the `tmp' field.
726 ; Drop dummy first arg and remove duplicates.
727 (nub (cdr sem-attrs) identity))
730 ; Return boolean indicating if PROPS indicates INSN references memory.
732 (define (insn-refs-mem? insn props)
733 (->bool (memq 'MEM props))
736 ; Return boolean indicating if PROPS indicates INSN uses the fpu.
738 (define (insn-uses-fpu? insn props)
739 (->bool (memq 'FPU props))
742 ; Ensure INSN has attribute IDOC.
743 ; If not specified, guess(?).
745 (define (guess-insn-idoc-attr! insn)
746 (if (not (obj-attr-present? insn 'IDOC))
748 (props (get-insn-properties insn)))
749 ; Try various heuristics.
751 (insn-sets-pc? insn))
754 (insn-refs-mem? insn props))
757 (insn-uses-fpu? insn props))
759 ; If nothing else works, assume ALU.
762 (obj-cons-attr! insn (enum-attr-make 'IDOC attr))))
766 ; Return subset of insns in IDOC category CAT-NAME.
768 (define (get-insns-for-category insns cat-name)
770 (obj-has-attr-value-no-default? insn 'IDOC cat-name))
774 ; CATEGORIES is a list of "enum value" elements for each category.
775 ; See <enum-attribute> for the definition.
776 ; INSNS is already alphabetically sorted and selected for just MACH.
778 (define (gen-categories-insn-lists mach categories insns)
780 ; generate a table of insns for each category
781 (string-list-map (lambda (c)
782 (let ((cat-insns (get-insns-for-category insns (enum-val-name c)))
783 (comment (enum-val-comment c)))
784 (if (null? cat-insns)
786 (gen-insn-doc-list mach (enum-val-name c) comment cat-insns))))
788 ; lastly, the alphabetical list
789 (gen-insn-doc-list mach (obj:name mach) (obj:comment mach) insns)
793 ; CATEGORIES is a list of "enum value" elements for each category.
794 ; See <enum-attribute> for the definition.
795 ; INSNS is already alphabetically sorted and selected for just MACH.
797 (define (gen-insn-categories mach categories insns)
800 (string-list-map (lambda (c)
801 (let ((cat-insns (get-insns-for-category insns (enum-val-name c)))
802 (comment (enum-val-comment c)))
803 (if (null? cat-insns)
806 "<li><a href=\"#mach-insns-"
809 (->string (enum-val-name c))
811 (->string (enum-val-name c))
812 (if (string=? comment "")
814 (string-append " - " comment))
818 "<li><a href=\"#mach-insns-"
822 "\">alphabetically</a></li>\n"
827 ; ??? There's an inefficiency here, we compute insns for each mach for each
828 ; category twice. Left for later if warranted.
830 (define (gen-insn-docs)
831 ; First simplify the semantics, e.g. do constant folding.
832 ; For insns built up from macros, often this will remove a lot of clutter.
833 (for-each (lambda (insn)
834 (logit 2 "Simplifying the rtl for insn " (obj:name insn) " ...\n")
835 (insn-set-tmp! insn (rtx-simplify-insn #f insn)))
838 (let ((machs (current-mach-list))
839 (insns (alpha-sort-obj-list (current-insn-list)))
840 (categories (attr-values (current-attr-lookup 'IDOC))))
841 ; First, install IDOC attributes for insns that don't specify one.
842 (for-each guess-insn-idoc-attr! insns)
846 "<a name=\"insns\"></a>\n"
847 "<h2>Instructions</h2>\n"
848 "Instructions for each machine:\n"
850 ; (string-map (lambda (o)
851 ; (gen-obj-list-entry o "mach-insns"))
853 (string-list-map (lambda (m)
854 (let ((mach-insns (find (lambda (insn)
855 (mach-supports? m insn))
862 (gen-insn-categories m categories mach-insns)
866 ; (string-list-map (lambda (m)
867 ; (gen-insn-doc-list m insns))
869 (string-list-map (lambda (m)
870 (let ((mach-insns (find (lambda (insn)
871 (mach-supports? m insn))
873 (gen-categories-insn-lists m categories mach-insns)))
876 "<h2>Individual instructions descriptions</h2>\n"
878 (string-list-map gen-insn-doc-1 insns)
882 ; Macro-instruction page.
884 (define (gen-macro-insn-doc-1 minsn)
886 (gen-obj-doc-header minsn "macro-insn")
898 "<pre>" ; no trailing newline here on purpose
899 (with-output-to-string
901 (pretty-print (minsn-expansions minsn))))
908 (define (gen-macro-insn-doc-list mach)
909 (let ((minsns (find (lambda (minsn)
910 (mach-supports? mach minsn))
911 (current-minsn-list))))
913 (gen-obj-doc-header mach "mach-macro-insns")
915 (string-map (lambda (o)
916 (gen-obj-list-entry o "macro-insn"))
922 (define (gen-macro-insn-docs)
923 (let ((machs (current-mach-list))
924 (minsns (alpha-sort-obj-list (current-minsn-list))))
928 "<a name=\"macro-insns\"></a>\n"
929 "<h2>Macro Instructions</h2>\n"
930 "Macro instructions for each machine:\n"
932 (string-map (lambda (o)
933 (gen-obj-list-entry o "mach-macro-insns"))
936 (string-list-map gen-macro-insn-doc-list machs)
938 "<h2>Individual macro-instructions descriptions</h2>\n"
940 (string-list-map gen-macro-insn-doc-1 minsns)
946 (define (gen-asm-docs)
950 "<a name=\"assembler\"></a>\n"
951 "<h2>Assembler supplemental</h2>\n"
955 ; Documentation init,finish,analyzer support.
957 ; Initialize any doc specific things before loading the .cpu file.
961 (mode-set-biggest-word-bitsizes!)
965 ; Finish any doc specific things after loading the .cpu file.
966 ; This is separate from analyze-data! as cpu-load performs some
967 ; consistency checks in between.
969 (define (doc-finish!)
974 ; Compute various needed globals and assign any computed fields of
975 ; the various objects. This is the standard routine that is called after
976 ; a .cpu file is loaded.
978 (define (doc-analyze!)
981 ; If the IDOC attribute isn't defined, provide a default one.
982 (if (not (current-attr-lookup 'IDOC))
987 '(comment "insn kind for documentation")
994 (MISC - () "Miscellaneous"))))
996 ; Initialize the rtl->c translator.
999 ; Only include semantic operands when computing the format tables if we're
1000 ; generating operand instance tables.
1001 ; ??? Actually, may always be able to exclude the semantic operands.
1002 ; Still need to traverse the semantics to derive machine computed attributes.
1003 (arch-analyze-insns! CURRENT-ARCH
1004 #t ; include aliases?
1005 #f) ; analyze semantics?
1010 ; Top level C code generators
1012 ; Set by the -N argument.
1013 (define *insn-html-file-name* "unspecified.html")
1016 (logit 1 "Generating " (current-arch-name) ".html ...\n")
1018 (gen-html-copyright (string-append "Architecture documentation for "
1019 (symbol->string (current-arch-name))
1021 CURRENT-COPYRIGHT CURRENT-PACKAGE)
1022 (gen-html-header "Architecture")
1023 (gen-table-of-contents *insn-html-file-name*)
1033 (define (cgen-insn.html)
1034 (logit 1 "Generating " (current-arch-name) "-insn.html ...\n")
1036 (gen-html-copyright (string-append "Instruction documentation for "
1037 (symbol->string (current-arch-name))
1039 CURRENT-COPYRIGHT CURRENT-PACKAGE)
1040 (gen-html-header "Instruction")