1 ; Hardware descriptions.
2 ; Copyright (C) 2000 Red Hat, Inc.
3 ; This file is part of CGEN.
4 ; See file COPYING.CGEN for details.
6 ; This is the base class for all hardware descriptions.
7 ; The actual hardware objects inherit from this (e.g. register, immediate).
8 ; This is used to describe registers, memory, and immediates.
9 ; ??? Maybe other things as well, but this is all that's needed at present.
10 ; ??? Eventually rename to <hardware> but not yet.
12 (define <hardware-base>
13 (class-make '<hardware-base>
16 ; Name used in semantics.
17 ; This is for cases where a particular hardware element is
18 ; sufficiently different on different mach's of an architecture
19 ; that it is defined separately for each case. The semantics
20 ; refer to this name (which means that one must use a different
21 ; mechanism if one wants both machs in the same semantic code).
24 ; The type, an object of class <array>.
25 ; (mode + scalar or vector length)
29 ; An object of class <hw-asm>, or a subclass of it, or
30 ; #f if there is no special indexing support.
31 ; For register banks, a table of register names.
32 ; ??? Same class as VALUES.
33 ; ??? There are currently no descriptions that require both an
34 ; INDICES and a VALUES specification. It might make sense to
35 ; combine them (which is how things used to be), but it is odd
36 ; to have them combined.
40 ; An object of class <hw-asm>, or a subclass of it, or
41 ; #f if there is no special values support.
42 ; For immediates with special names, a table of names.
43 ; ??? Same class as INDICES.
46 ; Associative list of (symbol . "handler") entries.
47 ; Each entry maps an operation to its handler (which is up to
48 ; the application but is generally a function name).
51 ; Get/set handlers or #f to use the default.
55 ; Associative list of get/set handlers for each supported mode,
56 ; or #f to use the default.
57 ; ??? An interesting idea, but not sure it's the best way
58 ; to go. Another way is to explicitly handle it in the insn
59 ; [complicates the RTL]. Another way is to handle this in
60 ; operand get/set handlers. Another way is to have virtual
61 ; regs for each non-default mode. Not sure which is better.
65 ; List of <isa> objects that use this hardware element
66 ; or #f if not computed yet.
67 ; This is a derived from the ISA attribute and is for speed.
75 (define-getters <hardware-base> hw
76 (sem-name type indices values handlers
77 ; ??? These might be more properly named hw-get/hw-set, but those names
79 (get . getter) (set . setter)
83 ; Mode,rank,shape support.
85 (method-make-forward! <hardware-base> 'type '(get-mode get-rank get-shape get-num-elms))
86 (define (hw-mode hw) (send hw 'get-mode))
87 (define (hw-rank hw) (send hw 'get-rank))
88 (define (hw-shape hw) (send hw 'get-shape))
89 (define (hw-num-elms hw) (send hw 'get-num-elms))
91 ; Return default mode to reference HW in.
93 (define (hw-default-mode hw)
97 ; Return a boolean indicating if X is a hardware object.
98 ; ??? <hardware-base> to be renamed <hardware> in time.
100 (define (hardware? x) (class-instance? <hardware-base> x))
102 ; Return #t if HW is a scalar.
104 (define (hw-scalar? hw) (= (hw-rank hw) 0))
106 ; Return number of bits in an element of HW.
109 (type-bits (hw-type hw))
112 ; Generate the name of the enum for hardware object HW.
113 ; This uses the semantic name, not obj:name.
114 ; If HW is a symbol, it is already the semantic name.
118 (string-upcase (string-append "HW_" (gen-c-symbol hw)))
119 (string-upcase (string-append "HW_" (gen-c-symbol (hw-sem-name hw)))))
122 ; Return a boolean indicating if it's ok to reference SELF in mode
123 ; NEW-MODE-NAME, index INDEX.
124 ; Hardware types are required to override this method.
125 ; VOID and DFLT are never valid for NEW-MODE-NAME.
128 <hardware-base> 'mode-ok?
129 (lambda (self new-mode-name index)
130 (error "mode-ok? method not overridden:" (obj:name self)))
133 (define (hw-mode-ok? hw new-mode-name index)
134 (send hw 'mode-ok? new-mode-name index)
137 ; Return mode to use for the index or #f if scalar.
140 <hardware-base> 'get-index-mode
142 (error "get-index-mode method not overridden:" (obj:name self)))
145 (define (hw-index-mode hw) (send hw 'get-index-mode))
147 ; Compute the isas used by HW and cache the results.
150 <hardware-base> 'get-isas
152 (or (elm-get self 'isas-cache)
153 (let* ((isas (obj-attr-value self 'ISA))
154 (isa-objs (if (eq? isas 'all) (current-isa-list)
155 (map current-isa-lookup
156 (bitset-attr->list isas)))))
157 (elm-set! self 'isas-cache isa-objs)
161 (define (hw-isas hw) (send hw 'get-isas))
163 ; FIXME: replace pc?,memory?,register?,iaddress? with just one method.
165 ; Return boolean indicating if hardware element is the PC.
167 (method-make! <hardware-base> 'pc? (lambda (self) #f))
169 ; Return boolean indicating if hardware element is some kind of memory.
170 ; ??? Need to allow multiple kinds of memory and therefore need to allow
171 ; .cpu files to specify this (i.e. an attribute). We could use has-attr?
172 ; here, or we could have the code that creates the object override this
173 ; method if the MEMORY attribute is present.
174 ; ??? Could also use a member instead of a method.
176 (method-make! <hardware-base> 'memory? (lambda (self) #f))
177 (define (memory? hw) (send hw 'memory?))
179 ; Return boolean indicating if hardware element is some kind of register.
181 (method-make! <hardware-base> 'register? (lambda (self) #f))
182 (define (register? hw) (send hw 'register?))
184 ; Return boolean indicating if hardware element is an address.
186 (method-make! <hardware-base> 'address? (lambda (self) #f))
187 (method-make! <hardware-base> 'iaddress? (lambda (self) #f))
188 (define (address? hw) (send hw 'address?))
189 (define (iaddress? hw) (send hw 'iaddress?))
196 (class-make '<hw-asm> '(<ident>)
199 ; A copy of the object's mode if we're in the "values"
200 ; member. If we're in the "indices" member this is typically
208 ; Keyword lists associate a name with a number and are used for things
209 ; like register name tables (the `indices' field of a hw spec) and
210 ; immediate value tables (the `values' field of a hw spec).
212 ; TODO: For things like the sparc fp regs, have a quasi-keyword that is
213 ; prefix plus number. This will save having to create a table of each
217 (class-make '<keyword> '(<hw-asm>)
219 ; Name to use in generated code, as a string.
222 ; Prefix of each name in VALUES, as a string.
225 ; Associative list of values.
226 ; Each element is (name value [attrs]).
227 ; ??? May wish to allow calling a function to compute the
236 (define kw-mode (elm-make-getter <keyword> 'mode))
237 (define kw-print-name (elm-make-getter <keyword> 'print-name))
238 (define kw-prefix (elm-make-getter <keyword> 'prefix))
239 (define kw-values (elm-make-getter <keyword> 'values))
241 ; Parse a keyword spec.
243 ; The syntax of VALUES is: (prefix ((name1 [value1 [(attr-list1)]]) ...))
244 ; PREFIX is a string prefix for each name.
245 ; Each value is a number of mode MODE.
246 ; ??? We have no problem handling any kind of number, we're Scheme.
247 ; However, it's not clear yet how applications will want to handle it, but
248 ; that is left to the application. Still, it might be preferable to impose
249 ; some restrictions which can later be relaxed as necessary.
251 (define (keyword-parse context name comment attrs mode print-name prefix values)
252 ; FIXME: parse values.
253 (let ((result (make <keyword>
254 (parse-name name context)
255 (parse-comment comment context)
256 (atlist-parse attrs "" context)
257 (parse-mode-name mode (string-append context ": mode"))
258 (parse-string (string-append context ": print-name") print-name)
259 (parse-string (string-append context ": prefix") prefix)
264 ; Read a keyword description
265 ; This is the main routine for analyzing a keyword description in the .cpu
267 ; ARG-LIST is an associative list of field name and field value.
268 ; keyword-parse is invoked to create the <keyword> object.
270 (define (-keyword-read context . arg-list)
279 ; Loop over each element in ARG-LIST, recording what's found.
280 (let loop ((arg-list arg-list))
283 (let ((arg (car arg-list))
284 (elm-name (caar arg-list)))
286 ((name) (set! name (cadr arg)))
287 ((comment) (set! comment (cadr arg)))
288 ((attrs) (set! attrs (cdr arg)))
289 ((mode) (set! mode (cadr arg)))
290 ((print-name) (set! print-name (cadr arg)))
291 ((prefix) (set! prefix (cadr arg)))
292 ((values) (set! values (cdr arg)))
293 (else (parse-error context "invalid hardware arg" arg)))
294 (loop (cdr arg-list)))))
295 ; Now that we've identified the elements, build the object.
296 (keyword-parse context name comment attrs mode
302 ; Define a keyword object, name/value pair list version.
304 (define define-keyword
306 (let ((kw (apply -keyword-read (cons "define-keyword" arg-list))))
310 ; Define an enum so the values are usable everywhere.
311 ; One use is giving names to register numbers and special constants
312 ; to make periphery C/C++ code more legible.
313 (define-full-enum (obj:name kw) (obj:comment kw)
314 (atlist-source-form (obj-atlist kw))
315 (string-upcase (string-append (kw-print-name kw) "-"))
322 ; List of hardware types.
323 ; This maps names in the `type' entry of define-hardware to the class name.
325 (define -hardware-types
326 '((register . <hw-register>)
328 (memory . <hw-memory>)
329 (immediate . <hw-immediate>)
330 (address . <hw-address>)
331 (iaddress . <hw-iaddress>))
334 ; Parse an inline keyword spec.
335 ; These are keywords defined inside something else.
336 ; CONTAINER is the <ident> object of the container.
338 (define (-hw-parse-keyword context args container mode)
339 (if (!= (length args) 2)
340 (parse-error context "invalid keyword spec" args))
342 ; These are copied from our container object.
343 ; They're needed to output the table.
344 ; ??? This isn't quite right as the container may contain multiple keyword
345 ; instances. To be fixed in time.
346 (keyword-parse context (obj:name container) (obj:comment container)
347 ; PRIVATE: keyword table is implicitly defined and made
348 ; "static" (in the C sense).
349 (cons 'PRIVATE (atlist-source-form (obj-atlist container)))
351 (obj:name container) ; print-name
356 ; Parse an indices spec.
357 ; CONTAINER is the <ident> object of the container.
358 ; Currently there is only special support for keywords.
359 ; Otherwise MODE is used.
360 ; The syntax is: (keyword keyword-spec) - see <keyword> for details.
362 (define (-hw-parse-indices errtxt indices container mode)
365 (obj:name container) (obj:comment container) (obj-atlist container)
368 (if (not (list? indices))
369 (parse-error errtxt "invalid indices spec" indices))
371 ((keyword) (-hw-parse-keyword errtxt (cdr indices) container mode))
372 ((extern-keyword) (begin
373 (if (null? (cdr indices))
374 (parse-error errtxt "missing keyword name"
376 (let ((kw (current-kw-lookup (cadr indices))))
378 (parse-error errtxt "unknown keyword"
381 (else (parse-error errtxt "unknown indices type" (car indices))))))
384 ; Parse a values spec.
385 ; CONTAINER is the <ident> object of the container.
386 ; Currently there is only special support for keywords.
387 ; Otherwise MODE is used.
388 ; The syntax is: (keyword keyword-spec) - see <keyword> for details.
390 (define (-hw-parse-values errtxt values container mode)
393 (obj:name container) (obj:comment container) (obj-atlist container)
396 (if (not (list? values))
397 (parse-error errtxt "invalid values spec" values))
399 ((keyword) (-hw-parse-keyword errtxt (cdr values) container mode))
400 ((extern-keyword) (begin
401 (if (null? (cdr values))
402 (parse-error errtxt "missing keyword name"
404 (let ((kw (current-kw-lookup (cadr values))))
406 (parse-error errtxt "unknown keyword"
409 (else (parse-error errtxt "unknown values type" (car values))))))
412 ; Parse a handlers spec.
413 ; Each element is (name "string").
415 (define (-hw-parse-handlers errtxt handlers)
416 (parse-handlers errtxt '(parse print) handlers)
419 ; Parse a getter spec.
420 ; The syntax is (([index]) (expression)).
421 ; Omit `index' for scalar objects.
422 ; Externally they're specified as `get'. Internally we use `getter'.
424 (define (-hw-parse-getter errtxt getter scalar?)
427 (let ((valid "((index) (expression))")
428 (scalar-valid "(() (expression))"))
429 (if (or (not (list? getter))
430 (!= (length getter) 2)
431 (not (and (list? (car getter))
432 (= (length (car getter)) (if scalar? 0 1)))))
434 (string-append "invalid getter, should be "
435 (if scalar? scalar-valid valid))
437 (if (not (rtx? (cadr getter)))
438 (parse-error errtxt "invalid rtx expression" getter))
442 ; Parse a setter spec.
443 ; The syntax is (([index] newval) (expression)).
444 ; Omit `index' for scalar objects.
445 ; Externally they're specified as `set'. Internally we use `setter'.
447 (define (-hw-parse-setter errtxt setter scalar?)
450 (let ((valid "((index newval) (expression))")
451 (scalar-valid "((newval) (expression))"))
452 (if (or (not (list? setter))
453 (!= (length setter) 2)
454 (not (and (list? (car setter))
455 (= (length (car setter)) (if scalar? 1 2)))))
457 (string-append "invalid setter, should be "
458 (if scalar? scalar-valid valid))
460 (if (not (rtx? (cadr setter)))
461 (parse-error errtxt "invalid rtx expression" setter))
465 ; Parse hardware description
466 ; This is the main routine for building a hardware object from a hardware
467 ; description in the .cpu file.
468 ; All arguments are in raw (non-evaluated) form.
469 ; The result is the parsed object or #f if object isn't for selected mach(s).
471 ; ??? Might want to redo to handle hardware type specific specs more cleanly.
472 ; E.g. <hw-immediate> shouldn't have to see get/set specs.
474 (define (-hw-parse errtxt name comment attrs semantic-name type
475 indices values handlers get set layout)
476 (logit 2 "Processing hardware element " name " ...\n")
479 (parse-error errtxt "missing hardware type" name))
481 ; Pick out name first 'cus we need it as a string(/symbol).
482 (let ((name (parse-name name "hardware"))
483 (class-name (assq-ref -hardware-types (car type)))
484 (atlist-obj (atlist-parse attrs "cgen_hw" errtxt)))
487 (parse-error errtxt "unknown hardware type" type))
489 (if (keep-atlist? atlist-obj #f)
491 (let ((result (new (class-lookup class-name))))
492 (send result 'set-name! name)
493 (send result 'set-comment! (parse-comment comment errtxt))
494 (send result 'set-atlist! atlist-obj)
495 (elm-xset! result 'sem-name semantic-name)
496 (send result 'parse! errtxt
497 (cdr type) indices values handlers get set layout)
498 ; If this is a virtual reg, get/set specs must be provided.
499 (if (and (obj-has-attr? result 'VIRTUAL)
500 (not (and (hw-getter result) (hw-setter result))))
501 (parse-error errtxt "virtual reg requires get/set specs" name))
502 ; If get or set specs are specified, can't have CACHE-ADDR.
503 (if (and (obj-has-attr? result 'CACHE-ADDR)
504 (or (hw-getter result) (hw-setter result)))
505 (parse-error errtxt "can't have CACHE-ADDR with get/set specs" name))
509 (logit 2 "Ignoring " name ".\n")
513 ; Read a hardware description
514 ; This is the main routine for analyzing a hardware description in the .cpu
516 ; ARG-LIST is an associative list of field name and field value.
517 ; -hw-parse is invoked to create the <hardware> object.
519 (define (-hw-read errtxt . arg-list)
520 (let ((name nil) ; name of hardware
523 (semantic-name nil) ; name used in semantics, default is `name'
524 (type nil) ; hardware type (register, immediate, etc.)
532 ; Loop over each element in ARG-LIST, recording what's found.
533 (let loop ((arg-list arg-list))
536 (let ((arg (car arg-list))
537 (elm-name (caar arg-list)))
539 ((name) (set! name (cadr arg)))
540 ((comment) (set! comment (cadr arg)))
541 ((attrs) (set! attrs (cdr arg)))
542 ((semantic-name) (set! semantic-name (cadr arg)))
543 ((type) (set! type (cdr arg)))
544 ((indices) (set! indices (cdr arg)))
545 ((values) (set! values (cdr arg)))
546 ((handlers) (set! handlers (cdr arg)))
547 ((get) (set! get (cdr arg)))
548 ((set) (set! set (cdr arg)))
549 ((layout) (set! layout (cdr arg)))
550 (else (parse-error errtxt "invalid hardware arg" arg)))
551 (loop (cdr arg-list)))))
552 ; Now that we've identified the elements, build the object.
553 (-hw-parse errtxt name comment attrs
554 (if (null? semantic-name) name semantic-name)
555 type indices values handlers get set layout)
559 ; Define a hardware object, name/value pair list version.
561 (define define-hardware
563 (let ((hw (apply -hw-read (cons "define-hardware" arg-list))))
565 (current-hw-add! hw))
569 ; Define a hardware object, all arguments specified.
571 (define (define-full-hardware name comment attrs semantic-name type
572 indices values handlers get set layout)
573 (let ((hw (-hw-parse "define-full-hardware"
574 name comment attrs semantic-name type
575 indices values handlers get set layout)))
577 (current-hw-add! hw))
581 ; Main routine for modifying existing definitions.
583 (define modify-hardware
585 (let ((errtxt "modify-hardware"))
587 ; FIXME: Experiment. This implements the :name/value style by
588 ; converting it to (name value). In the end there shouldn't be two
589 ; styles. People might prefer :name/value, but it's not as amenable
590 ; to macro processing (insert potshots regarding macro usage).
591 (if (keyword-list? (car arg-list))
592 (set! arg-list (keyword-list->arg-list arg-list)))
594 ; First find out which element.
595 ; There's no requirement that the name be specified first.
596 (let ((hw-spec (assq 'name arg-list)))
598 (parse-error errtxt "hardware name not specified"))
600 (let ((hw (current-hw-lookup (arg-list-symbol-arg errtxt hw-spec))))
602 (parse-error errtxt "undefined hardware element" hw-spec))
604 ; Process the rest of the args now that we have the affected object.
605 (let loop ((args arg-list))
608 (let ((arg-spec (car args)))
610 ((name) #f) ; ignore, already processed
612 (let ((atlist-obj (atlist-parse (cdr arg-spec)
614 ; prepend attrs so new ones override existing ones
615 (obj-prepend-atlist! hw atlist-obj)))
617 (parse-error errtxt "invalid/unsupported option" (car arg-spec))))
618 (loop (cdr args))))))))
623 ; Lookup a hardware object using its semantic name.
624 ; The result is a list of elements with SEM-NAME.
625 ; Callers must deal with cases where there is more than one.
627 (define (current-hw-sem-lookup sem-name)
628 (find (lambda (hw) (eq? (hw-sem-name hw) sem-name))
632 ; Same as current-hw-sem-lookup, but result is 1 hw element or #f if not
633 ; found. An error is signalled if multiple hw elements are found.
635 (define (current-hw-sem-lookup-1 sem-name)
636 (let ((hw-objs (current-hw-sem-lookup sem-name)))
637 (case (length hw-objs)
640 (else (error "ambiguous hardware reference" sem-name))))
643 ; Basic hardware types.
644 ; These inherit from `hardware-base'.
645 ; ??? Might wish to allow each target to add more, but we provide enough
646 ; examples to cover most cpus.
648 ; A register (or an array of them).
650 (define <hw-register> (class-make '<hw-register> '(<hardware-base>) nil nil))
652 ; Subroutine of -hw-create-[gs]etter-from-layout to validate a layout.
658 (define (-hw-validate-layout errtxt layout width)
659 (if (not (list? layout))
660 (parse-error errtxt "layout is not a list" layout))
662 (let loop ((layout layout) (shift 0))
665 ; Done. Now see if number of bits in layout matches total width.
666 (if (not (= shift width))
667 (parse-error errtxt (string-append
668 "insufficient number of bits (need "
669 (number->string width)
672 ; Validate next entry.
673 (let ((val (car layout)))
675 (if (not (memq val '(0 1)))
677 "non 0/1 layout entry requires length"
679 (loop (cdr layout) (1+ shift)))
681 (if (or (not (number? (car val)))
682 (not (pair? (cdr val)))
683 (not (number? (cadr val)))
684 (not (null? (cddr val))))
686 "syntax error in layout, expecting `(value length)'"
688 (loop (cdr layout) (+ shift (cadr val))))
690 (let ((hw (current-hw-lookup val)))
692 (parse-error errtxt "unknown hardware element" val))
693 (if (not (hw-scalar? hw))
694 (parse-error errtxt "non-scalar hardware element" val))
696 (+ shift (hw-bits hw)))))
698 (parse-error errtxt "bad layout element" val))))))
702 ; Return the getter spec to use for LAYOUT.
703 ; WIDTH is the width of the combined value in bits.
706 ; Assuming h-hw[123] are 1 bit registers, and width is 32
707 ; given ((0 29) h-hw1 h-hw2 h-hw3), return
709 ; (or SI (sll SI (zext SI (reg h-hw1)) 2)
710 ; (or SI (sll SI (zext SI (reg h-hw2)) 1)
711 ; (zext SI (reg h-hw3)))))
713 (define (-hw-create-getter-from-layout errtxt layout width)
714 (let ((add-to-res (lambda (result mode-name val shift)
716 (rtx-make 'sll mode-name val shift)
717 (rtx-make 'or mode-name
718 (rtx-make 'sll mode-name
719 (rtx-make 'zext mode-name val)
722 (mode-name (obj:name (mode-find width 'UINT))))
723 (let loop ((result nil) (layout (reverse layout)) (shift 0))
725 (list nil result) ; getter spec: (get () (expression))
726 (let ((val (car layout)))
730 (loop result (cdr layout) (1+ shift))
731 (loop (add-to-res result mode-name val shift)
737 (loop result (cdr layout) (+ shift (cadr val)))
738 (loop (add-to-res result mode-name (car val) shift)
740 (+ shift (cadr val)))))
742 (let ((hw (current-hw-lookup val)))
743 (loop (add-to-res result mode-name
747 (+ shift (hw-bits hw)))))
749 (assert (begin "bad layout element" #f))))))))
752 ; Return the setter spec to use for LAYOUT.
753 ; WIDTH is the width of the combined value in bits.
756 ; Assuming h-hw[123] are 1 bit registers,
757 ; given (h-hw1 h-hw2 h-hw3), return
760 ; (set (reg h-hw1) (and (srl val 2) 1))
761 ; (set (reg h-hw2) (and (srl val 1) 1))
762 ; (set (reg h-hw3) (and (srl val 0) 1))
765 (define (-hw-create-setter-from-layout errtxt layout width)
766 (let ((mode-name (obj:name (mode-find width 'UINT))))
767 (let loop ((sets nil) (layout (reverse layout)) (shift 0))
769 (list '(val) ; setter spec: (set (val) (expression))
770 (apply rtx-make (cons 'sequence (cons nil sets))))
771 (let ((val (car layout)))
773 (loop sets (cdr layout) (1+ shift)))
775 (loop sets (cdr layout) (+ shift (cadr val))))
777 (let ((hw (current-hw-lookup val)))
778 (loop (cons (rtx-make 'set
781 (rtx-make 'srl 'val shift)
782 (1- (logsll 1 (hw-bits hw)))))
785 (+ shift (hw-bits hw)))))
787 (assert (begin "bad layout element" #f))))))))
790 ; Parse a register spec.
791 ; .cpu syntax: (register mode [(dimension)])
792 ; or: (register (mode bits) [(dimension)])
795 <hw-register> 'parse!
796 (lambda (self errtxt type indices values handlers getter setter layout)
799 (parse-error errtxt "invalid register spec" type))
800 (if (and (= (length type) 2)
801 (or (not (list? (cadr type)))
802 (> (length (cadr type)) 1)))
803 (parse-error errtxt "bad register dimension spec" type))
805 ; Must parse and set type before analyzing LAYOUT.
806 (elm-set! self 'type (parse-type errtxt type))
808 ; LAYOUT is a shorthand way of specifying getter/setter specs.
809 ; For registers that are just a collection of other registers
810 ; (e.g. the status register in mips), it's easier to specify the
811 ; registers that make up the bigger register, rather than to specify
813 ; We don't override any provided get/set specs though.
814 (if (not (null? layout))
815 (let ((width (hw-bits self)))
816 (-hw-validate-layout errtxt layout width)
819 (-hw-create-getter-from-layout errtxt layout width)))
822 (-hw-create-setter-from-layout errtxt layout width)))
825 (elm-set! self 'indices (-hw-parse-indices errtxt indices self UINT))
826 (elm-set! self 'values (-hw-parse-values errtxt values self
827 (send (elm-get self 'type)
829 (elm-set! self 'handlers (-hw-parse-handlers errtxt handlers))
830 (elm-set! self 'get (-hw-parse-getter errtxt getter (hw-scalar? self)))
831 (elm-set! self 'set (-hw-parse-setter errtxt setter (hw-scalar? self)))
835 ; Return boolean indicating if hardware element is some kind of register.
837 (method-make! <hw-register> 'register? (lambda (self) #t))
839 ; Return a boolean indicating if it's ok to reference SELF in mode
840 ; NEW-MODE-NAME, index INDEX.
842 ; ??? INDEX isn't currently used. The intent is to use it if it's a known
843 ; value, and otherwise assume for our purposes it's valid and leave any
844 ; further error checking to elsewhere.
846 ; ??? This method makes more sense if we support multiple modes via
847 ; getters/setters. Maybe we will some day, so this is left as is for now.
850 <hw-register> 'mode-ok?
851 (lambda (self new-mode-name index)
852 (let ((cur-mode (send self 'get-mode))
853 (new-mode (mode:lookup new-mode-name)))
854 (if (mode:eq? new-mode-name cur-mode)
856 ; ??? Subject to revisiting.
857 ; Only allow floats if same mode (which is handled above).
858 ; Only allow non-widening if ints.
859 ; On architectures where shortening/widening can refer to a
860 ; quasi-different register, it is up to the target to handle this.
861 ; See the comments for the getter/setter/getters/setters class
863 (let ((cur-mode-class (mode:class cur-mode))
864 (cur-bits (mode:bits cur-mode))
865 (new-mode-class (mode:class new-mode))
866 (new-bits (mode:bits new-mode)))
867 ; Compensate for registers defined with an unsigned mode.
868 (if (eq? cur-mode-class 'UINT)
869 (set! cur-mode-class 'INT))
870 (if (eq? new-mode-class 'UINT)
871 (set! new-mode-class 'INT))
872 (if (eq? cur-mode-class 'INT)
873 (and (eq? new-mode-class cur-mode-class)
874 (<= new-bits cur-bits))
878 ; Return mode to use for the index or #f if scalar.
881 <hw-register> 'get-index-mode
883 (if (scalar? (hw-type self))
888 ; The program counter (PC) hardware register.
889 ; This is a separate class as the simulator needs a place to put special
892 (define <hw-pc> (class-make '<hw-pc> '(<hw-register>) nil nil))
898 (lambda (self errtxt type indices values handlers getter setter layout)
899 (if (not (null? type))
900 (elm-set! self 'type (parse-type errtxt type))
901 (elm-set! self 'type (make <scalar> (mode:lookup 'IAI))))
902 (if (not (null? indices))
903 (parse-error errtxt "indices specified for pc" indices))
904 (if (not (null? values))
905 (parse-error errtxt "values specified for pc" values))
906 (if (not (null? layout))
907 (parse-error errtxt "layout specified for pc" values))
908 ; The initial value of INDICES, VALUES is #f which is what we want.
909 (elm-set! self 'handlers (-hw-parse-handlers errtxt handlers))
910 (elm-set! self 'get (-hw-parse-getter errtxt getter (hw-scalar? self)))
911 (elm-set! self 'set (-hw-parse-setter errtxt setter (hw-scalar? self)))
915 ; Indicate we're the pc.
917 (method-make! <hw-pc> 'pc? (lambda (self) #t))
921 (define <hw-memory> (class-make '<hw-memory> '(<hardware-base>) nil nil))
923 ; Parse a memory spec.
924 ; .cpu syntax: (memory mode [(dimension)])
925 ; or: (memory (mode bits) [(dimension)])
929 (lambda (self errtxt type indices values handlers getter setter layout)
932 (parse-error errtxt "invalid memory spec" type))
933 (if (and (= (length type) 2)
934 (or (not (list? (cadr type)))
935 (> (length (cadr type)) 1)))
936 (parse-error errtxt "bad memory dimension spec" type))
937 (if (not (null? layout))
938 (parse-error errtxt "layout specified for memory" values))
939 (elm-set! self 'type (parse-type errtxt type))
940 ; Setting INDICES,VALUES here is mostly for experimentation at present.
941 (elm-set! self 'indices (-hw-parse-indices errtxt indices self AI))
942 (elm-set! self 'values (-hw-parse-values errtxt values self
943 (send (elm-get self 'type)
945 (elm-set! self 'handlers (-hw-parse-handlers errtxt handlers))
946 (elm-set! self 'get (-hw-parse-getter errtxt getter (hw-scalar? self)))
947 (elm-set! self 'set (-hw-parse-setter errtxt setter (hw-scalar? self)))
951 ; Return boolean indicating if hardware element is some kind of memory.
953 (method-make! <hw-memory> 'memory? (lambda (self) #t))
955 ; Return a boolean indicating if it's ok to reference SELF in mode
956 ; NEW-MODE-NAME, index INDEX.
959 <hw-memory> 'mode-ok?
960 (lambda (self new-mode-name index)
961 ; Allow any mode for now.
965 ; Return mode to use for the index or #f if scalar.
968 <hw-memory> 'get-index-mode
973 ; Immediate values (numbers recorded in the insn).
975 (define <hw-immediate> (class-make '<hw-immediate> '(<hardware-base>) nil nil))
977 ; Parse an immediate spec.
978 ; .cpu syntax: (immediate mode)
979 ; or: (immediate (mode bits))
982 <hw-immediate> 'parse!
983 (lambda (self errtxt type indices values handlers getter setter layout)
984 (if (not (= (length type) 1))
985 (parse-error errtxt "invalid immediate spec" type))
986 (elm-set! self 'type (parse-type errtxt type))
987 ; An array of immediates may be useful some day, but not yet.
988 (if (not (null? indices))
989 (parse-error errtxt "indices specified for immediate" indices))
990 (if (not (null? layout))
991 (parse-error errtxt "layout specified for immediate" values))
992 (elm-set! self 'values (-hw-parse-values errtxt values self
993 (send (elm-get self 'type)
995 (elm-set! self 'handlers (-hw-parse-handlers errtxt handlers))
996 (if (not (null? getter))
997 (parse-error errtxt "getter specified for immediate" getter))
998 (if (not (null? setter))
999 (parse-error errtxt "setter specified for immediate" setter))
1003 ; Return a boolean indicating if it's ok to reference SELF in mode
1004 ; NEW-MODE-NAME, index INDEX.
1007 <hw-immediate> 'mode-ok?
1008 (lambda (self new-mode-name index)
1009 (let ((cur-mode (send self 'get-mode))
1010 (new-mode (mode:lookup new-mode-name)))
1011 (if (mode:eq? new-mode-name cur-mode)
1013 ; ??? Subject to revisiting.
1014 ; Only allow floats if same mode (which is handled above).
1015 ; For ints allow anything.
1016 (let ((cur-mode-class (mode:class cur-mode))
1017 (new-mode-class (mode:class new-mode)))
1018 (->bool (and (memq cur-mode-class '(INT UINT))
1019 (memq new-mode-class '(INT UINT))))))))
1022 ; These are scalars.
1025 <hw-immediate> 'get-index-mode
1030 ; These are usually symbols.
1032 (define <hw-address> (class-make '<hw-address> '(<hardware-base>) nil nil))
1034 (method-make! <hw-address> 'address? (lambda (self) #t))
1036 ; Parse an address spec.
1039 <hw-address> 'parse!
1040 (lambda (self errtxt type indices values handlers getter setter layout)
1041 (if (not (null? type))
1042 (parse-error errtxt "invalid address spec" type))
1043 (elm-set! self 'type (make <scalar> AI))
1044 (if (not (null? indices))
1045 (parse-error errtxt "indices specified for address" indices))
1046 (if (not (null? values))
1047 (parse-error errtxt "values specified for address" values))
1048 (if (not (null? layout))
1049 (parse-error errtxt "layout specified for address" values))
1050 (elm-set! self 'values (-hw-parse-values errtxt values self
1051 (send (elm-get self 'type)
1053 (elm-set! self 'handlers (-hw-parse-handlers errtxt handlers))
1054 (if (not (null? getter))
1055 (parse-error errtxt "getter specified for address" getter))
1056 (if (not (null? setter))
1057 (parse-error errtxt "setter specified for address" setter))
1061 ; Return a boolean indicating if it's ok to reference SELF in mode
1062 ; NEW-MODE-NAME, index INDEX.
1065 <hw-address> 'mode-ok?
1066 (lambda (self new-mode-name index)
1067 ; We currently don't allow referencing an address in any mode other than
1068 ; the original mode.
1069 (mode-compatible? 'samesize new-mode-name (send self 'get-mode)))
1072 ; Instruction addresses.
1073 ; These are treated separately from normal addresses as the simulator
1074 ; may wish to treat them specially.
1075 ; FIXME: Doesn't use mode IAI.
1077 (define <hw-iaddress> (class-make '<hw-iaddress> '(<hw-address>) nil nil))
1079 (method-make! <hw-iaddress> 'iaddress? (lambda (self) #t))
1081 ; Misc. random hardware support.
1083 ; Map a mode to a hardware object that can contain immediate values of that
1086 (define (hardware-for-mode mode)
1087 (cond ((mode:eq? mode 'AI) h-addr)
1088 ((mode:eq? mode 'IAI) h-iaddr)
1089 ((mode-signed? mode) h-sint)
1090 ((mode-unsigned? mode) h-uint)
1091 (else (error "Don't know h-object for mode " mode)))
1094 ; Called when a cpu-family is read in to set the word sizes.
1095 ; Must be called after mode-set-word-modes! has been called.
1097 (define (hw-update-word-modes!)
1098 (elm-xset! h-addr 'type (make <scalar> (mode:lookup 'AI)))
1099 (elm-xset! h-iaddr 'type (make <scalar> (mode:lookup 'IAI)))
1102 ; Builtins, attributes, init/fini support.
1104 (define h-memory #f)
1110 ; Called before reading a .cpu file in.
1112 (define (hardware-init!)
1113 (reader-add-command! 'define-keyword
1115 Define a keyword, name/value pair list version.
1117 nil 'arg-list define-keyword)
1118 (reader-add-command! 'define-hardware
1120 Define a hardware element, name/value pair list version.
1122 nil 'arg-list define-hardware)
1123 (reader-add-command! 'define-full-hardware
1125 Define a hardware element, all arguments specified.
1127 nil '(name comment attrs semantic-name type
1128 indices values handlers get set layout)
1129 define-full-hardware)
1130 (reader-add-command! 'modify-hardware
1132 Modify a hardware element, name/value pair list version.
1134 nil 'arg-list modify-hardware)
1139 ; Install builtin hardware objects.
1141 (define (hardware-builtin!)
1142 ; Standard h/w attributes.
1143 (define-attr '(for hardware) '(type boolean) '(name CACHE-ADDR)
1144 '(comment "cache register address during insn extraction"))
1145 ; FIXME: This should be deletable.
1146 (define-attr '(for hardware) '(type boolean) '(name PC)
1147 '(comment "the program counter"))
1148 (define-attr '(for hardware) '(type boolean) '(name PROFILE)
1149 '(comment "collect profiling data"))
1151 (let ((all (stringize (current-arch-isa-name-list) ",")))
1152 ; ??? The program counter, h-pc, used to be defined here.
1153 ; However, some targets need to modify it (e.g. provide special get/set
1154 ; specs). There's still an outstanding issue of how to add things to
1155 ; objects after the fact (e.g. model parameters to instructions), but
1156 ; that's further down the road.
1157 (set! h-memory (define-full-hardware 'h-memory "memory"
1159 ; Ensure memory not flagged as a scalar.
1160 'h-memory '(memory UQI (1)) nil nil nil
1162 (set! h-sint (define-full-hardware 'h-sint "signed integer"
1164 'h-sint '(immediate (INT 32)) nil nil nil
1166 (set! h-uint (define-full-hardware 'h-uint "unsigned integer"
1168 'h-uint '(immediate (UINT 32)) nil nil nil
1170 (set! h-addr (define-full-hardware 'h-addr "address"
1172 'h-addr '(address) nil nil '((print "print_address"))
1174 ; Instruction addresses.
1175 ; These are different because the simulator may want to do something
1176 ; special with them, and some architectures treat them differently.
1177 (set! h-iaddr (define-full-hardware 'h-iaddr "instruction address"
1179 'h-iaddr '(iaddress) nil nil '((print "print_address"))
1185 ; Called after a .cpu file has been read in.
1187 (define (hardware-finish!)