OSDN Git Service

daily update
[pf3gnuchains/pf3gnuchains3x.git] / cgen / hardware.scm
1 ; Hardware descriptions.
2 ; Copyright (C) 2000 Red Hat, Inc.
3 ; This file is part of CGEN.
4 ; See file COPYING.CGEN for details.
5
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.
11
12 (define <hardware-base>
13   (class-make '<hardware-base>
14               '(<ident>)
15               '(
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).
22                 sem-name
23
24                 ; The type, an object of class <array>.
25                 ; (mode + scalar or vector length)
26                 type
27
28                 ; Indexing support.
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.
37                 (indices . #f)
38
39                 ; Table of values.
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.
44                 (values . #f)
45
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).
49                 (handlers . ())
50
51                 ; Get/set handlers or #f to use the default.
52                 (get . #f)
53                 (set . #f)
54
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.
62                 ;(getters . #f)
63                 ;(setters . #f)
64
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.
68                 (isas-cache . #f)
69                 )
70               nil)
71 )
72
73 ; Accessors
74
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
78    ; seem ambiguous.
79    (get . getter) (set . setter)
80    isas-cache)
81 )
82
83 ; Mode,rank,shape support.
84
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))
90
91 ; Return default mode to reference HW in.
92
93 (define (hw-default-mode hw)
94   (hw-mode hw)
95 )
96
97 ; Return a boolean indicating if X is a hardware object.
98 ; ??? <hardware-base> to be renamed <hardware> in time.
99
100 (define (hardware? x) (class-instance? <hardware-base> x))
101
102 ; Return #t if HW is a scalar.
103
104 (define (hw-scalar? hw) (= (hw-rank hw) 0))
105
106 ; Return number of bits in an element of HW.
107
108 (define (hw-bits hw)
109   (type-bits (hw-type hw))
110 )
111
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.
115
116 (define (hw-enum hw)
117   (if (symbol? hw)
118       (string-upcase (string-append "HW_" (gen-c-symbol hw)))
119       (string-upcase (string-append "HW_" (gen-c-symbol (hw-sem-name hw)))))
120 )
121
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.
126
127 (method-make!
128  <hardware-base> 'mode-ok?
129  (lambda (self new-mode-name index)
130    (error "mode-ok? method not overridden:" (obj:name self)))
131 )
132
133 (define (hw-mode-ok? hw new-mode-name index)
134   (send hw 'mode-ok? new-mode-name index)
135 )
136
137 ; Return mode to use for the index or #f if scalar.
138
139 (method-make!
140  <hardware-base> 'get-index-mode
141  (lambda (self)
142    (error "get-index-mode method not overridden:" (obj:name self)))
143 )
144
145 (define (hw-index-mode hw) (send hw 'get-index-mode))
146
147 ; Compute the isas used by HW and cache the results.
148
149 (method-make!
150  <hardware-base> 'get-isas
151  (lambda (self)
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)
158          isa-objs)))
159 )
160
161 (define (hw-isas hw) (send hw 'get-isas))
162
163 ; FIXME: replace pc?,memory?,register?,iaddress? with just one method.
164
165 ; Return boolean indicating if hardware element is the PC.
166
167 (method-make! <hardware-base> 'pc? (lambda (self) #f))
168
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.
175
176 (method-make! <hardware-base> 'memory? (lambda (self) #f))
177 (define (memory? hw) (send hw 'memory?))
178
179 ; Return boolean indicating if hardware element is some kind of register.
180
181 (method-make! <hardware-base> 'register? (lambda (self) #f))
182 (define (register? hw) (send hw 'register?))
183
184 ; Return boolean indicating if hardware element is an address.
185
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?))
190 \f
191 ; Assembler support.
192
193 ; Baseclass.
194
195 (define <hw-asm>
196   (class-make '<hw-asm> '(<ident>)
197               '(
198                 ; The mode to use.
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
201                 ; UINT.
202                 mode
203                 )
204               nil)
205 )
206
207 ; Keywords.
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).
211 ;
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
214 ; register name.
215
216 (define <keyword>
217   (class-make '<keyword> '(<hw-asm>)
218               '(
219                 ; Name to use in generated code, as a string.
220                 print-name
221
222                 ; Prefix of each name in VALUES, as a string.
223                 prefix
224
225                 ; Associative list of values.
226                 ; Each element is (name value [attrs]).
227                 ; ??? May wish to allow calling a function to compute the
228                 ; value at runtime.
229                 values
230                 )
231               nil)
232 )
233
234 ; Accessors
235
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))
240
241 ; Parse a keyword spec.
242 ;
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.
250
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)
260                   values)))
261     result)
262 )
263
264 ; Read a keyword description
265 ; This is the main routine for analyzing a keyword description in the .cpu
266 ; file.
267 ; ARG-LIST is an associative list of field name and field value.
268 ; keyword-parse is invoked to create the <keyword> object.
269
270 (define (-keyword-read context . arg-list)
271   (let ((name #f)
272         (comment "")
273         (attrs nil)
274         (mode INT)
275         (print-name #f)
276         (prefix "")
277         (values nil)
278         )
279     ; Loop over each element in ARG-LIST, recording what's found.
280     (let loop ((arg-list arg-list))
281       (if (null? arg-list)
282           nil
283           (let ((arg (car arg-list))
284                 (elm-name (caar arg-list)))
285             (case elm-name
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
297                    (or print-name name)
298                    prefix values)
299     )
300 )
301
302 ; Define a keyword object, name/value pair list version.
303
304 (define define-keyword
305   (lambda arg-list
306     (let ((kw (apply -keyword-read (cons "define-keyword" arg-list))))
307       (if kw
308           (begin
309             (current-kw-add! kw)
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) "-"))
316               (kw-values kw))))
317       kw))
318 )
319 \f
320 ; Parsing support.
321
322 ; List of hardware types.
323 ; This maps names in the `type' entry of define-hardware to the class name.
324
325 (define -hardware-types
326   '((register . <hw-register>)
327     (pc . <hw-pc>)
328     (memory . <hw-memory>)
329     (immediate . <hw-immediate>)
330     (address . <hw-address>)
331     (iaddress . <hw-iaddress>))
332 )
333
334 ; Parse an inline keyword spec.
335 ; These are keywords defined inside something else.
336 ; CONTAINER is the <ident> object of the container.
337
338 (define (-hw-parse-keyword context args container mode)
339   (if (!= (length args) 2)
340       (parse-error context "invalid keyword spec" args))
341
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)))
350                  mode
351                  (obj:name container) ; print-name
352                  (car args) ; prefix
353                  (cadr args)) ; value
354 )
355
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.
361
362 (define (-hw-parse-indices errtxt indices container mode)
363   (if (null? indices)
364       (make <hw-asm>
365         (obj:name container) (obj:comment container) (obj-atlist container)
366         mode)
367       (begin
368         (if (not (list? indices))
369             (parse-error errtxt "invalid indices spec" indices))
370         (case (car 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"
375                                                indices))
376                               (let ((kw (current-kw-lookup (cadr indices))))
377                                 (if (not kw)
378                                     (parse-error errtxt "unknown keyword"
379                                                  indices))
380                                 kw)))
381           (else (parse-error errtxt "unknown indices type" (car indices))))))
382 )
383
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.
389
390 (define (-hw-parse-values errtxt values container mode)
391   (if (null? values)
392       (make <hw-asm>
393         (obj:name container) (obj:comment container) (obj-atlist container)
394         mode)
395       (begin
396         (if (not (list? values))
397             (parse-error errtxt "invalid values spec" values))
398         (case (car 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"
403                                                values))
404                               (let ((kw (current-kw-lookup (cadr values))))
405                                 (if (not kw)
406                                     (parse-error errtxt "unknown keyword"
407                                                  values))
408                                 kw)))
409           (else (parse-error errtxt "unknown values type" (car values))))))
410 )
411
412 ; Parse a handlers spec.
413 ; Each element is (name "string").
414
415 (define (-hw-parse-handlers errtxt handlers)
416   (parse-handlers errtxt '(parse print) handlers)
417 )
418
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'.
423
424 (define (-hw-parse-getter errtxt getter scalar?)
425   (if (null? getter)
426       #f ; use default
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)))))
433             (parse-error errtxt
434                          (string-append "invalid getter, should be "
435                                         (if scalar? scalar-valid valid))
436                          getter))
437         (if (not (rtx? (cadr getter)))
438             (parse-error errtxt "invalid rtx expression" getter))
439         getter))
440 )
441
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'.
446
447 (define (-hw-parse-setter errtxt setter scalar?)
448   (if (null? setter)
449       #f ; use default
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)))))
456             (parse-error errtxt
457                          (string-append "invalid setter, should be "
458                                         (if scalar? scalar-valid valid))
459                          setter))
460         (if (not (rtx? (cadr setter)))
461             (parse-error errtxt "invalid rtx expression" setter))
462         setter))
463 )
464
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).
470 ;
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.
473
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")
477
478   (if (null? type)
479       (parse-error errtxt "missing hardware type" name))
480
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)))
485
486     (if (not class-name)
487         (parse-error errtxt "unknown hardware type" type))
488
489     (if (keep-atlist? atlist-obj #f)
490
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))
506           result)
507
508         (begin
509           (logit 2 "Ignoring " name ".\n")
510           #f)))
511 )
512
513 ; Read a hardware description
514 ; This is the main routine for analyzing a hardware description in the .cpu
515 ; file.
516 ; ARG-LIST is an associative list of field name and field value.
517 ; -hw-parse is invoked to create the <hardware> object.
518
519 (define (-hw-read errtxt . arg-list)
520   (let ((name nil)          ; name of hardware
521         (comment "")
522         (attrs nil)
523         (semantic-name nil) ; name used in semantics, default is `name'
524         (type nil)          ; hardware type (register, immediate, etc.)
525         (indices nil)
526         (values nil)
527         (handlers nil)
528         (get nil)
529         (set nil)
530         (layout nil)
531         )
532     ; Loop over each element in ARG-LIST, recording what's found.
533     (let loop ((arg-list arg-list))
534       (if (null? arg-list)
535           nil
536           (let ((arg (car arg-list))
537                 (elm-name (caar arg-list)))
538             (case elm-name
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)
556     )
557 )
558
559 ; Define a hardware object, name/value pair list version.
560
561 (define define-hardware
562   (lambda arg-list
563     (let ((hw (apply -hw-read (cons "define-hardware" arg-list))))
564       (if hw
565           (current-hw-add! hw))
566       hw))
567 )
568
569 ; Define a hardware object, all arguments specified.
570
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)))
576     (if hw
577         (current-hw-add! hw))
578     hw)
579 )
580
581 ; Main routine for modifying existing definitions.
582
583 (define modify-hardware
584   (lambda arg-list
585     (let ((errtxt "modify-hardware"))
586
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)))
593
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)))
597         (if (not hw-spec)
598             (parse-error errtxt "hardware name not specified"))
599
600         (let ((hw (current-hw-lookup (arg-list-symbol-arg errtxt hw-spec))))
601           (if (not hw)
602               (parse-error errtxt "undefined hardware element" hw-spec))
603
604           ; Process the rest of the args now that we have the affected object.
605           (let loop ((args arg-list))
606             (if (null? args)
607                 #f ; done
608                 (let ((arg-spec (car args)))
609                   (case (car arg-spec)
610                     ((name) #f) ; ignore, already processed
611                     ((add-attrs)
612                      (let ((atlist-obj (atlist-parse (cdr arg-spec)
613                                                      "cgen_hw" errtxt)))
614                        ; prepend attrs so new ones override existing ones
615                        (obj-prepend-atlist! hw atlist-obj)))
616                     (else
617                      (parse-error errtxt "invalid/unsupported option" (car arg-spec))))
618                   (loop (cdr args))))))))
619
620     *UNSPECIFIED*)
621 )
622
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.
626
627 (define (current-hw-sem-lookup sem-name)
628   (find (lambda (hw) (eq? (hw-sem-name hw) sem-name))
629         (current-hw-list))
630 )
631
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.
634
635 (define (current-hw-sem-lookup-1 sem-name)
636   (let ((hw-objs (current-hw-sem-lookup sem-name)))
637     (case (length hw-objs)
638       ((0) #f)
639       ((1) (car hw-objs))
640       (else (error "ambiguous hardware reference" sem-name))))
641 )
642 \f
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.
647
648 ; A register (or an array of them).
649
650 (define <hw-register> (class-make '<hw-register> '(<hardware-base>) nil nil))
651
652 ; Subroutine of -hw-create-[gs]etter-from-layout to validate a layout.
653 ; Valid values:
654 ; - 0 or 1
655 ; - (value length)
656 ; - hardware-name
657
658 (define (-hw-validate-layout errtxt layout width)
659   (if (not (list? layout))
660       (parse-error errtxt "layout is not a list" layout))
661
662   (let loop ((layout layout) (shift 0))
663     (if (null? layout)
664         (begin
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)
670                                    ")")
671                            shift)))
672         ; Validate next entry.
673         (let ((val (car layout)))
674           (cond ((number? val)
675                  (if (not (memq val '(0 1)))
676                      (parse-error errtxt
677                                   "non 0/1 layout entry requires length"
678                                   val))
679                  (loop (cdr layout) (1+ shift)))
680                 ((pair? val)
681                  (if (or (not (number? (car val)))
682                          (not (pair? (cdr val)))
683                          (not (number? (cadr val)))
684                          (not (null? (cddr val))))
685                      (parse-error errtxt
686                                   "syntax error in layout, expecting `(value length)'"
687                                   val))
688                  (loop (cdr layout) (+ shift (cadr val))))
689                 ((symbol? val)
690                  (let ((hw (current-hw-lookup val)))
691                    (if (not hw)
692                        (parse-error errtxt "unknown hardware element" val))
693                    (if (not (hw-scalar? hw))
694                        (parse-error errtxt "non-scalar hardware element" val))
695                    (loop (cdr layout)
696                          (+ shift (hw-bits hw)))))
697                 (else
698                  (parse-error errtxt "bad layout element" val))))))
699   *UNSPECIFIED*
700 )
701
702 ; Return the getter spec to use for LAYOUT.
703 ; WIDTH is the width of the combined value in bits.
704 ;
705 ; Example:
706 ; Assuming h-hw[123] are 1 bit registers, and width is 32
707 ; given ((0 29) h-hw1 h-hw2 h-hw3), return
708 ; (()
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)))))
712
713 (define (-hw-create-getter-from-layout errtxt layout width)
714   (let ((add-to-res (lambda (result mode-name val shift)
715                       (if (null? result)
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)
720                                               shift)
721                                     result))))
722         (mode-name (obj:name (mode-find width 'UINT))))
723     (let loop ((result nil) (layout (reverse layout)) (shift 0))
724       (if (null? layout)
725           (list nil result) ; getter spec: (get () (expression))
726           (let ((val (car layout)))
727             (cond ((number? val)
728                    ; ignore if zero
729                    (if (= val 0)
730                        (loop result (cdr layout) (1+ shift))
731                        (loop (add-to-res result mode-name val shift)
732                              (cdr layout)
733                              (1+ shift))))
734                   ((pair? val)
735                    ; ignore if zero
736                    (if (= (car val) 0)
737                        (loop result (cdr layout) (+ shift (cadr val)))
738                        (loop (add-to-res result mode-name (car val) shift)
739                              (cdr layout)
740                              (+ shift (cadr val)))))
741                   ((symbol? val)
742                    (let ((hw (current-hw-lookup val)))
743                      (loop (add-to-res result mode-name
744                                        (rtx-make 'reg val)
745                                        shift)
746                            (cdr layout)
747                            (+ shift (hw-bits hw)))))
748                   (else
749                    (assert (begin "bad layout element" #f))))))))
750 )
751
752 ; Return the setter spec to use for LAYOUT.
753 ; WIDTH is the width of the combined value in bits.
754 ;
755 ; Example:
756 ; Assuming h-hw[123] are 1 bit registers,
757 ; given (h-hw1 h-hw2 h-hw3), return
758 ; ((val)
759 ;  (sequence ()
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))
763 ;            ))
764
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))
768       (if (null? layout)
769           (list '(val) ; setter spec: (set (val) (expression))
770                 (apply rtx-make (cons 'sequence (cons nil sets))))
771           (let ((val (car layout)))
772             (cond ((number? val)
773                    (loop sets (cdr layout) (1+ shift)))
774                   ((pair? val)
775                    (loop sets (cdr layout) (+ shift (cadr val))))
776                   ((symbol? val)
777                    (let ((hw (current-hw-lookup val)))
778                      (loop (cons (rtx-make 'set
779                                            (rtx-make 'reg val)
780                                            (rtx-make 'and
781                                                      (rtx-make 'srl 'val shift)
782                                                      (1- (logsll 1 (hw-bits hw)))))
783                                  sets)
784                            (cdr layout)
785                            (+ shift (hw-bits hw)))))
786                   (else
787                    (assert (begin "bad layout element" #f))))))))
788 )
789
790 ; Parse a register spec.
791 ; .cpu syntax: (register mode [(dimension)])
792 ;          or: (register (mode bits) [(dimension)])
793
794 (method-make!
795  <hw-register> 'parse!
796  (lambda (self errtxt type indices values handlers getter setter layout)
797    (if (or (null? type)
798            (> (length type) 2))
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))
804
805    ; Must parse and set type before analyzing LAYOUT.
806    (elm-set! self 'type (parse-type errtxt type))
807
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
812    ; get/set specs.
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)
817          (if (null? getter)
818              (set! getter
819                    (-hw-create-getter-from-layout errtxt layout width)))
820          (if (null? setter)
821              (set! setter
822                    (-hw-create-setter-from-layout errtxt layout width)))
823          ))
824
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)
828                                                   'get-mode)))
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)))
832    *UNSPECIFIED*)
833 )
834
835 ; Return boolean indicating if hardware element is some kind of register.
836
837 (method-make! <hw-register> 'register? (lambda (self) #t))
838
839 ; Return a boolean indicating if it's ok to reference SELF in mode
840 ; NEW-MODE-NAME, index INDEX.
841 ;
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.
845 ;
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.
848
849 (method-make!
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)
855          #t
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
862          ; members.
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))
875                #f)))))
876 )
877
878 ; Return mode to use for the index or #f if scalar.
879
880 (method-make!
881  <hw-register> 'get-index-mode
882  (lambda (self)
883    (if (scalar? (hw-type self))
884        #f
885        UINT))
886 )
887
888 ; The program counter (PC) hardware register.
889 ; This is a separate class as the simulator needs a place to put special
890 ; get/set methods.
891
892 (define <hw-pc> (class-make '<hw-pc> '(<hw-register>) nil nil))
893
894 ; Parse a pc spec.
895
896 (method-make!
897  <hw-pc> 'parse!
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)))
912    *UNSPECIFIED*)
913 )
914
915 ; Indicate we're the pc.
916
917 (method-make! <hw-pc> 'pc? (lambda (self) #t))
918
919 ; Memory.
920
921 (define <hw-memory> (class-make '<hw-memory> '(<hardware-base>) nil nil))
922
923 ; Parse a memory spec.
924 ; .cpu syntax: (memory mode [(dimension)])
925 ;          or: (memory (mode bits) [(dimension)])
926
927 (method-make!
928  <hw-memory> 'parse!
929  (lambda (self errtxt type indices values handlers getter setter layout)
930    (if (or (null? type)
931            (> (length type) 2))
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)
944                                                   'get-mode)))
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)))
948    *UNSPECIFIED*)
949 )
950
951 ; Return boolean indicating if hardware element is some kind of memory.
952
953 (method-make! <hw-memory> 'memory? (lambda (self) #t))
954
955 ; Return a boolean indicating if it's ok to reference SELF in mode
956 ; NEW-MODE-NAME, index INDEX.
957
958 (method-make!
959  <hw-memory> 'mode-ok?
960  (lambda (self new-mode-name index)
961    ; Allow any mode for now.
962    #t)
963 )
964
965 ; Return mode to use for the index or #f if scalar.
966
967 (method-make!
968  <hw-memory> 'get-index-mode
969  (lambda (self)
970    AI)
971 )
972
973 ; Immediate values (numbers recorded in the insn).
974
975 (define <hw-immediate> (class-make '<hw-immediate> '(<hardware-base>) nil nil))
976
977 ; Parse an immediate spec.
978 ; .cpu syntax: (immediate mode)
979 ;          or: (immediate (mode bits))
980
981 (method-make!
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)
994                                                   'get-mode)))
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))
1000    *UNSPECIFIED*)
1001 )
1002
1003 ; Return a boolean indicating if it's ok to reference SELF in mode
1004 ; NEW-MODE-NAME, index INDEX.
1005
1006 (method-make!
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)
1012          #t
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))))))))
1020 )
1021
1022 ; These are scalars.
1023
1024 (method-make!
1025  <hw-immediate> 'get-index-mode
1026  (lambda (self) #f)
1027 )
1028
1029 ; Addresses.
1030 ; These are usually symbols.
1031
1032 (define <hw-address> (class-make '<hw-address> '(<hardware-base>) nil nil))
1033
1034 (method-make! <hw-address> 'address? (lambda (self) #t))
1035
1036 ; Parse an address spec.
1037
1038 (method-make!
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)
1052                                                   'get-mode)))
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))
1058    *UNSPECIFIED*)
1059 )
1060
1061 ; Return a boolean indicating if it's ok to reference SELF in mode
1062 ; NEW-MODE-NAME, index INDEX.
1063
1064 (method-make!
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)))
1070 )
1071
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.
1076
1077 (define <hw-iaddress> (class-make '<hw-iaddress> '(<hw-address>) nil nil))
1078
1079 (method-make! <hw-iaddress> 'iaddress? (lambda (self) #t))
1080 \f
1081 ; Misc. random hardware support.
1082
1083 ; Map a mode to a hardware object that can contain immediate values of that
1084 ; mode.
1085
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)))
1092 )
1093
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.
1096
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)))
1100 )
1101 \f
1102 ; Builtins, attributes, init/fini support.
1103
1104 (define h-memory #f)
1105 (define h-sint #f)
1106 (define h-uint #f)
1107 (define h-addr #f)
1108 (define h-iaddr #f)
1109
1110 ; Called before reading a .cpu file in.
1111
1112 (define (hardware-init!)
1113   (reader-add-command! 'define-keyword
1114                        "\
1115 Define a keyword, name/value pair list version.
1116 "
1117                        nil 'arg-list define-keyword)
1118   (reader-add-command! 'define-hardware
1119                        "\
1120 Define a hardware element, name/value pair list version.
1121 "
1122                        nil 'arg-list define-hardware)
1123   (reader-add-command! 'define-full-hardware
1124                        "\
1125 Define a hardware element, all arguments specified.
1126 "
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
1131                        "\
1132 Modify a hardware element, name/value pair list version.
1133 "
1134                        nil 'arg-list modify-hardware)
1135
1136   *UNSPECIFIED*
1137 )
1138
1139 ; Install builtin hardware objects.
1140
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"))
1150
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"
1158                      `((ISA ,all))
1159                      ; Ensure memory not flagged as a scalar.
1160                      'h-memory '(memory UQI (1)) nil nil nil
1161                      nil nil nil))
1162     (set! h-sint (define-full-hardware 'h-sint "signed integer"
1163                    `((ISA ,all))
1164                    'h-sint '(immediate (INT 32)) nil nil nil
1165                    nil nil nil))
1166     (set! h-uint (define-full-hardware 'h-uint "unsigned integer"
1167                    `((ISA ,all))
1168                    'h-uint '(immediate (UINT 32)) nil nil nil
1169                    nil nil nil))
1170     (set! h-addr (define-full-hardware 'h-addr "address"
1171                    `((ISA ,all))
1172                    'h-addr '(address) nil nil '((print "print_address"))
1173                    nil nil nil))
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"
1178                     `((ISA ,all))
1179                     'h-iaddr '(iaddress) nil nil '((print "print_address"))
1180                     nil nil nil)))
1181
1182   *UNSPECIFIED*
1183 )
1184
1185 ; Called after a .cpu file has been read in.
1186
1187 (define (hardware-finish!)
1188   *UNSPECIFIED*
1189 )