OSDN Git Service

* sim.scm (/operand-number-elaboration-written?): New variable.
[pf3gnuchains/pf3gnuchains4x.git] / cgen / ifield.scm
1 ; Instruction fields.
2 ; Copyright (C) 2000, 2002, 2009 Red Hat, Inc.
3 ; This file is part of CGEN.
4 ; See file COPYING.CGEN for details.
5
6 ; The `<ifield>' class.
7 ; (pronounced "I-field")
8 ;
9 ; These describe raw data, little semantic content is attributed to them.
10 ; The goal being to avoid interfering with future applications.
11 ;
12 ; FIXME: Move start, word-offset, word-length into the instruction format?
13 ; - would require proper ordering of fields in insns, but that's ok.
14 ;   (??? though the sparc64 description shows a case where its useful to
15 ;   not have to worry about instruction ordering - different versions of an
16 ;   insn take different fields and these fields are passed via a macro)
17 ;
18 ; ??? One could treat all ifields as being unsigned.  They could be thought of
19 ; as indices into a table of values, be they signed, unsigned, floating point,
20 ; whatever.  Just an idea.
21 ;
22 ; ??? Split into two?  One for definition, and one for value.
23
24 (define <ifield>
25   (class-make '<ifield>
26               '(<source-ident>)
27               '(
28                 ; The mode the raw value is to be interpreted in.
29                 ; This is a <mode> object.
30                 mode
31
32                 ; A <bitrange> object.
33                 ; This contains the field's offset, start, length, word-length,
34                 ; and orientation (msb==0, lsb==0).  The orientation is
35                 ; recorded to keep the <bitrange> object self-contained.
36                 ; Endianness is not recorded.
37                 bitrange
38
39                 ; Argument to :follows, as an object.
40                 ; FIXME: wip
41                 (follows . #f)
42
43                 ; ENCODE/DECODE operate on the raw value, absent of any context
44                 ; save `pc' and mode of field.
45                 ; If #f, no special processing is required.
46                 ; ??? It's not clear where the best place to process fields is.
47                 ; An earlier version had insert/extract fields in operands to
48                 ; handle more complicated cases.  Following the goal of
49                 ; incremental complication, the special handling for m32r's
50                 ; f-disp8 field is handled entirely here, rather than partially
51                 ; here and partially in the operand.
52                 encode decode
53
54                 ; Value of field, if there is one, or #f.
55                 ; Possible types are: integer, <operand>, ???
56                 (value . #f)
57                 )
58               nil)
59 )
60
61 ; {ordinal} is missing on purpose, it's handled at a higher level.
62 ; {value},{follows} are missing on purpose.
63 ; {value} is handled specially.
64 ; {follows} is rarely used.
65 (method-make-make! <ifield>
66                    '(location name comment attrs mode bitrange encode decode))
67
68 ; Accessor fns
69 ; ??? `value' is treated specially, needed anymore?
70
71 (define-getters <ifield> ifld (mode encode decode follows))
72
73 (define-setters <ifield> ifld (follows))
74
75 ; internal fn
76 (define /ifld-bitrange (elm-make-getter <ifield> 'bitrange))
77
78 (define (ifld-word-offset f) (bitrange-word-offset (/ifld-bitrange f)))
79 (define (ifld-word-length f) (bitrange-word-length (/ifld-bitrange f)))
80
81 ; Return the mode of the decoded value of <ifield> F.
82 ; ??? This is made easy because we require the decode expression to have
83 ; an explicit mode.
84
85 (define (ifld-decode-mode f)
86   (assert (elm-bound? f 'decode))
87   (let ((d (ifld-decode f)))
88     (if d
89         ;; FIXME: Does this work with canonicalized rtl?
90         (mode:lookup (cadr (cadr d)))
91         (ifld-mode f)))
92 )
93
94 ; Return start of ifield.
95
96 (method-make!
97  <ifield> 'field-start
98  (lambda (self)
99    (bitrange-start (/ifld-bitrange self)))
100 )
101
102 (define (ifld-start ifld)
103   (send ifld 'field-start)
104 )
105
106 (method-make!
107  <ifield> 'field-length
108  (lambda (self)
109    (bitrange-length (elm-get self 'bitrange)))
110 )
111
112 (define (ifld-length f) (send f 'field-length))
113
114 ; FIXME: It might make things more "readable" if enum values were preserved in
115 ; their symbolic form and the get-field-value method did the lookup.
116
117 (method-make!
118  <ifield> 'get-field-value
119  (lambda (self)
120    (elm-get self 'value))
121 )
122 (define (ifld-get-value self)
123   (send self 'get-field-value)
124 )
125 (method-make!
126  <ifield> 'set-field-value!
127  (lambda (self new-val)
128    (elm-set! self 'value new-val))
129 )
130 (define (ifld-set-value! self new-val)
131   (send self 'set-field-value! new-val)
132 )
133
134 ; Return a boolean indicating if X is an <ifield>.
135
136 (define (ifield? x) (class-instance? <ifield> x))
137
138 ; Return ilk of field as a string.
139 ; ("ilk" sounds klunky but "type" is too ambiguous.  Here "ilk" means
140 ; the kind of the hardware element, enum, etc.)
141 ; The result is a character string naming the field type.
142
143 (define (ifld-ilk fld)
144   (let ((value (elm-xget fld 'value)))
145     ; ??? One could require that the `value' field always be an object.
146     ; I can't get too worked up over it yet.
147     (if (object? value)
148         (symbol->string (obj:name value)) ; send 'get-name to fetch the name
149         "#")) ; # -> "it's a number"
150 )
151
152 ; Generate the name of the enum for instruction field ifld.
153 ; If PREFIX? is present and #f, the @ARCH@_ prefix is omitted.
154
155 (define (ifld-enum ifld . prefix?)
156   (string-upcase (string-append (if (or (null? prefix?) (car prefix?))
157                                     "@ARCH@_"
158                                     "")
159                                 (gen-sym ifld)))
160 )
161
162 ; Return a boolean indicating if ifield F is an opcode field
163 ; (has a constant value).
164
165 (define (ifld-constant? f)
166   (number? (ifld-get-value f))
167 ;  (and (number? (ifld-get-value f))
168 ;       (if option:reserved-as-opcode?
169 ;          #t
170 ;          (not (has-attr? f 'RESERVED))))
171 )
172
173 ; Return a boolean indicating if ifield F is an operand.
174 ; FIXME: Should check for operand? or some such.
175
176 (define (ifld-operand? f) (not (number? (ifld-get-value f))))
177
178 ; Return known value table for rtx-simplify of <ifield> list ifld-list.
179
180 (define (ifld-known-values ifld-list)
181   (let ((constant-iflds (find ifld-constant? (ifields-base-ifields ifld-list))))
182     (map (lambda (f)
183            (cons (obj:name f)
184                  (rtx-make-const 'INT (ifld-get-value f))))
185          constant-iflds))
186 )
187
188 ; Return mask to use for a field in <bitrange> CONTAINER.
189 ; If the bitrange is outside the range of the field, return 0.
190 ; If CONTAINER is #f, use the recorded bitrange.
191 ; BASE-LEN, if non-#f, overrides the base insn length of the insn.
192 ; BASE-LEN is present for architectures like the m32r where there are insns
193 ; smaller than the base insn size (LIW).
194 ;
195 ; Simplifying restrictions [to be relaxed as necessary]:
196 ; - the field must either be totally contained within CONTAINER or totally
197 ;   outside it, partial overlaps aren't handled
198 ; - CONTAINER must be an integral number of bytes, beginning on a
199 ;   byte boundary [simplifies things]
200 ; - both SELF's bitrange and CONTAINER must have the same word length
201 ; - LSB0? of SELF's bitrange and CONTAINER must be the same
202
203 (method-make!
204  <ifield> 'field-mask
205  (lambda (self base-len container)
206    (let* ((container (or container (/ifld-bitrange self)))
207           (bitrange (/ifld-bitrange self))
208           (recorded-word-length (bitrange-word-length bitrange))
209           (word-offset (bitrange-word-offset bitrange)))
210      (let ((lsb0? (bitrange-lsb0? bitrange))
211            (start (bitrange-start bitrange))
212            (length (bitrange-length bitrange))
213            (word-length (or (and (= word-offset 0) base-len)
214                             recorded-word-length))
215            (container-word-offset (bitrange-word-offset container))
216            (container-word-length (bitrange-word-length container)))
217        (cond
218         ; must be same lsb0
219         ((not (eq? lsb0? (bitrange-lsb0? container)))
220          (error "field-mask: different lsb0? values"))
221         ((not (= word-length container-word-length))
222          0)
223         ; container occurs after?
224         ((<= (+ word-offset word-length) container-word-offset)
225          0)
226         ; container occurs before?
227         ((>= word-offset (+ container-word-offset container-word-length))
228          0)
229         (else
230          (word-mask start length word-length lsb0? #f))))))
231 )
232
233 (define (ifld-mask ifld base-len container)
234   (send ifld 'field-mask base-len container)
235 )
236
237 ; Return VALUE inserted into the field's position.
238 ; BASE-LEN, if non-#f, overrides the base insn length of the insn.
239 ; BASE-LEN is present for architectures like the m32r where there are insns
240 ; smaller than the base insn size (LIW).
241
242 (method-make!
243  <ifield> 'field-value
244  (lambda (self base-len value)
245    (let* ((bitrange (/ifld-bitrange self))
246           (recorded-word-length (bitrange-word-length bitrange))
247           (word-offset (bitrange-word-offset bitrange))
248           (word-length (or (and (= word-offset 0) base-len)
249                            recorded-word-length)))
250      (word-value (ifld-start self)
251                  (bitrange-length bitrange)
252                  word-length
253                  (bitrange-lsb0? bitrange) #f
254                  value)))
255 )
256
257 ; FIXME: confusion with ifld-get-value.
258 (define (ifld-value f base-len value)
259   (send f 'field-value base-len value)
260 )
261
262 ; Return a list of ifields required to compute <ifield> F's value.
263 ; Normally this is just F itself.  For multi-ifields it will be more.
264 ; ??? It can also be more if F's value is derived from other fields but
265 ; that isn't supported yet.
266
267 (method-make!
268  <ifield> 'needed-iflds
269  (lambda (self)
270    (list self))
271 )
272
273 (define (ifld-needed-iflds f)
274   (send f 'needed-iflds)
275 )
276
277 ; Extract <ifield> IFLD's value out of VALUE in <insn> INSN.
278 ; VALUE is the entire insn's value if it fits in a word, or is a list
279 ; of values, one per word (not implemented, sigh).
280 ; ??? The instruction's format should specify where the word boundaries are.
281
282 (method-make!
283  <ifield> 'field-extract
284  (lambda (self insn value)
285    (let ((base-len (insn-base-mask-length insn)))
286      (word-extract (ifld-start self)
287                    (ifld-length self)
288                    base-len
289                    (ifld-lsb0? self)
290                    #f ; start is msb
291                    value)))
292 )
293
294 (define (ifld-extract ifld value insn)
295   (send ifld 'field-extract value insn)
296 )
297
298 ; Return a boolean indicating if bit 0 is the least significant bit.
299
300 (method-make!
301  <ifield> 'field-lsb0?
302  (lambda (self)
303    (bitrange-lsb0? (/ifld-bitrange self)))
304 )
305
306 (define (ifld-lsb0? f) (send f 'field-lsb0?))
307
308 ; Return the minimum value of a field.
309
310 (method-make!
311  <ifield> 'min-value
312  (lambda (self)
313   (case (mode:class (ifld-mode self))
314     ((INT) (- (integer-expt 2 (- (ifld-length self) 1))))
315     ((UINT) 0)
316     (else (error "unsupported mode class" (mode:class (ifld-mode self))))))
317 )
318
319 ; Return the maximum value of a field.
320
321 (method-make!
322  <ifield> 'max-value
323  (lambda (self)
324   (case (mode:class (ifld-mode self))
325     ((INT) (- (integer-expt 2 (- (ifld-length self) 1)) 1))
326     ((UINT) (- (integer-expt 2 (ifld-length self)) 1))
327     (else (error "unsupported mode class" (mode:class (ifld-mode self))))))
328 )
329
330 ; Create a copy of field F with value VALUE.
331 ; VALUE is either ... ???
332
333 (define (ifld-new-value f value)
334   (let ((new-f (object-copy-top f)))
335     (ifld-set-value! new-f value)
336     new-f)
337 )
338
339 ; Change the offset of the word containing an ifield to {word-offset}.
340
341 (method-make!
342  <ifield> 'set-word-offset!
343  (lambda (self word-offset)
344    (let ((bitrange (object-copy-top (/ifld-bitrange self))))
345      (bitrange-set-word-offset! bitrange word-offset)
346      (elm-set! self 'bitrange bitrange)
347      *UNSPECIFIED*))
348 )
349 (define (ifld-set-word-offset! f word-offset)
350   (send f 'set-word-offset! word-offset)
351 )
352
353 ; Return a copy of F with new {word-offset}.
354
355 (define (ifld-new-word-offset f word-offset)
356   (let ((new-f (object-copy-top f)))
357     (ifld-set-word-offset! new-f word-offset)
358     new-f)
359 )
360
361 ; Return the bit offset of the word after the word <ifield> F is in.
362 ; What a `word' here is defined by F in its bitrange.
363
364 (method-make!
365  <ifield> 'next-word
366  (lambda (self)
367   (let ((br (/ifld-bitrange f)))
368     (bitrange-next-word br)))
369 )
370
371 (define (ifld-next-word f) (send f 'next-word))
372
373 ; Return a boolean indicating if <ifield> F1 precedes <ifield> F2.
374 ; FIXME: Move into a method as different subclasses will need
375 ; different handling.
376
377 (define (ifld-precedes? f1 f2)
378   (let ((br1 (/ifld-bitrange f1))
379         (br2 (/ifld-bitrange f2)))
380     (cond ((< (bitrange-word-offset br1) (bitrange-word-offset br2))
381            #t)
382           ((= (bitrange-word-offset br1) (bitrange-word-offset br2))
383            (begin
384              (assert (eq? (bitrange-lsb0? br1) (bitrange-lsb0? br2)))
385              (assert (= (bitrange-word-length br1) (bitrange-word-length br1)))
386              ; ??? revisit
387              (if (bitrange-lsb0? br1)
388                  (> (bitrange-start br1) (bitrange-start br2))
389                  (< (bitrange-start br1) (bitrange-start br2)))))
390           (else
391            #f)))
392 )
393
394 ;; Pretty print an ifield, typically for error messages.
395
396 (method-make!
397  <ifield> 'pretty-print
398  (lambda (self)
399    (string-append "(" (obj:str-name self)
400                   " " (number->string (ifld-start self))
401                   " " (number->string (ifld-length self))
402                   ")"))
403 )
404
405 (define (ifld-pretty-print f)
406   (send f 'pretty-print)
407 )
408 \f
409 ; Parse an ifield definition.
410 ; This is the main routine for building an ifield object from a
411 ; description in the .cpu file.
412 ; All arguments are in raw (non-evaluated) form.
413 ; The result is the parsed object or #f if object isn't for selected mach(s).
414 ;
415 ; Two forms of specification are supported, loosely defined as the RISC way
416 ; and the CISC way.  The reason for the distinction is to simplify ifield
417 ; specification of RISC-like cpus.
418 ; Note that VLIW's are another way.  These are handled like the RISC way, with
419 ; the possible addition of instruction framing (which is, surprise surprise,
420 ; wip).
421 ;
422 ; RISC:
423 ; WORD-OFFSET and WORD-LENGTH are #f.  Insns are assumed to be N copies of
424 ; (isa-default-insn-word-bitsize).  WORD-OFFSET is computed from START.
425 ; START is the offset in bits from the start of the insn.
426 ; FLENGTH is the length of the field in bits.
427 ;
428 ; CISC:
429 ; WORD-OFFSET is the offset in bits from the start to the first byte of the
430 ; word containing the ifield.
431 ; WORD-LENGTH is the length in bits of the word containing the ifield.
432 ; START is the starting bit number in the word.  Bit numbering is taken from
433 ; (current-arch-insn-lsb0?).
434 ; FLENGTH is the length in bits of the ifield.  It is named that way to avoid
435 ; collision with the proc named `length'.
436 ;
437 ; FIXME: More error checking.
438
439 (define (/ifield-parse context name comment attrs
440                        word-offset word-length start flength follows
441                        mode encode decode)
442   (logit 2 "Processing ifield " name " ...\n")
443
444   ;; Pick out name first to augment the error context.
445   (let* ((name (parse-name context name))
446          (context (context-append-name context name))
447          (atlist (atlist-parse context attrs "cgen_ifld"))
448          (isas (atlist-attr-value atlist 'ISA #f)))
449
450     ; No longer ensure only one isa specified.
451     ;(if (!= (length isas) 1)
452     ;   (parse-error context "can only specify 1 isa" attrs))
453
454     (if (not (eq? (->bool word-offset)
455                   (->bool word-length)))
456         (parse-error context "either both or neither of word-offset,word-length can be specified"))
457
458     (if (keep-isa-atlist? atlist #f)
459
460         (let ((isa (current-isa-lookup (car isas)))
461               (word-offset (and word-offset
462                                 (parse-number context word-offset '(0 . 256))))
463               (word-length (and word-length
464                                 (parse-number context word-length '(0 . 128))))
465               ; ??? 0.127 for now
466               (start (parse-number context start '(0 . 127)))
467               ; ??? 0.127 for now
468               (flength (parse-number context flength '(0 . 127)))
469               (lsb0? (current-arch-insn-lsb0?))
470               (mode-obj (parse-mode-name context mode))
471               (follows-obj (/ifld-parse-follows context follows isas))
472               )
473
474           ; Calculate the <bitrange> object.
475           ; ??? Move positional info to format?
476           (let ((bitrange
477                  (if word-offset
478
479                      ; CISC-like. Easy. Everything must be specified.
480                      (make <bitrange>
481                        word-offset start flength word-length lsb0?)
482
483                      ; RISC-like. Hard. Have to make best choice of start,
484                      ; flength. This doesn't have to be perfect, just easily
485                      ; explainable.  Cases this doesn't handle can explicitly
486                      ; specify word-offset,word-length.
487                      ; One can certainly argue the choice of the term
488                      ; "RISC-like" is inaccurate.  Perhaps.
489                      (let* ((diwb (isa-default-insn-word-bitsize isa))
490                             (word-offset (/get-ifld-word-offset start flength diwb lsb0?))
491                             (word-length (/get-ifld-word-length start flength diwb lsb0?))
492                             (start (- start word-offset))
493                             )
494                        (make <bitrange>
495                          word-offset
496                          start
497                          flength
498                          word-length
499                          lsb0?))))
500                  )
501
502             (let ((result
503                    (make <ifield>
504                          (context-location context)
505                          name
506                          (parse-comment context comment)
507                          atlist
508                          mode-obj
509                          bitrange
510                          (/ifld-parse-encode context encode)
511                          (/ifld-parse-decode context decode))))
512               (if follows-obj
513                   (ifld-set-follows! result follows-obj))
514               result)))
515
516         ; Else ignore entry.
517         (begin
518           (logit 2 "Ignoring " name ".\n")
519           #f)))
520 )
521
522 ; Subroutine of /ifield-parse to simplify it.
523 ; Given START,FLENGTH, return the "best" choice for the offset to the word
524 ; containing the ifield.
525 ; This is easy to visualize, hard to put into words.
526 ; Imagine several words of size DIWB laid out from the start of the insn.
527 ; On top of that lay the ifield.
528 ; Now pick the minimal set of words that are required to contain the ifield.
529 ; That's what we want.
530 ; No claim is made that this is always the correct choice for any
531 ; particular architecture.  For those where this isn't correct, the ifield
532 ; must be fully specified (i.e. word-offset,word-length explicitly specified).
533
534 (define (/get-ifld-word-offset start flength diwb lsb0?)
535   (if lsb0?
536       ; Convert to non-lsb0 case, then it's easy.
537       ; NOTE: The conversion is seemingly wrong because `start' is misnamed.
538       ; It's now `end'.
539       (set! start (+ (- start flength) 1)))
540   (- start (remainder start diwb))
541 )
542
543 ; Subroutine of /ifield-parse to simplify it.
544 ; Given START,FLENGTH, return the "best" choice for the length of the word
545 ; containing the ifield.
546 ; DIWB = default insn word bitsize
547 ; See -get-ifld-word-offset for more info.
548
549 (define (/get-ifld-word-length start flength diwb lsb0?)
550   (if lsb0?
551       ; Convert to non-lsb0 case, then it's easy.
552       ; NOTE: The conversion is seemingly wrong because `start' is misnamed.
553       ; It's now `end'.
554       (set! start (+ (- start flength) 1)))
555   (* (quotient (+ (remainder start diwb) flength (- diwb 1))
556                diwb)
557      diwb)
558 )
559
560 ; Read an instruction field description.
561 ; This is the main routine for analyzing instruction fields in the .cpu file.
562 ; CONTEXT is a <context> object for error messages.
563 ; ARG-LIST is an associative list of field name and field value.
564 ; /ifield-parse is invoked to create the <ifield> object.
565
566 (define (/ifield-read context . arg-list)
567   (let (
568         (name #f)
569         (comment "")
570         (attrs nil)
571         (word-offset #f)
572         (word-length #f)
573         (start 0)
574         ; FIXME: Hobbit computes the wrong symbol for `length'
575         ; in the `case' expression below because there is a local var
576         ; of the same name ("__1" gets appended to the symbol name).
577         ; As a workaround we name it "length-".
578         (length- 0)
579         (follows #f)
580         (mode 'UINT)
581         (encode #f)
582         (decode #f)
583         )
584
585     ; Loop over each element in ARG-LIST, recording what's found.
586     (let loop ((arg-list arg-list))
587       (if (null? arg-list)
588           nil
589           (let ((arg (car arg-list))
590                 (elm-name (caar arg-list)))
591             (case elm-name
592               ((name) (set! name (cadr arg)))
593               ((comment) (set! comment (cadr arg)))
594               ((attrs) (set! attrs (cdr arg)))
595               ((mode) (set! mode (cadr arg)))
596               ((word-offset) (set! word-offset (cadr arg)))
597               ((word-length) (set! word-length (cadr arg)))
598               ((start) (set! start (cadr arg)))
599               ((length) (set! length- (cadr arg)))
600               ((follows) (set! follows (cadr arg)))
601               ((encode) (set! encode (cdr arg)))
602               ((decode) (set! decode (cdr arg)))
603               (else (parse-error context "invalid ifield arg" arg)))
604             (loop (cdr arg-list)))))
605
606     ; See if encode/decode were specified as "unspecified".
607     ; This happens with shorthand macros.
608     (if (and (pair? encode)
609              (eq? (car encode) #f))
610         (set! encode #f))
611     (if (and (pair? decode)
612              (eq? (car decode) #f))
613         (set! decode #f))
614
615     ; Now that we've identified the elements, build the object.
616     (/ifield-parse context name comment attrs
617                    word-offset word-length start length- follows
618                    mode encode decode))
619 )
620
621 ; Parse a `follows' spec.
622
623 (define (/ifld-parse-follows context follows isas)
624   (if follows
625       (let ((follows-obj (current-op-lookup follows isas)))
626         (if (not follows-obj)
627             (parse-error context "unknown operand to follow" follows))
628         follows-obj)
629       #f)
630 )
631
632 ; Do common parts of <ifield> encode/decode processing.
633
634 (define (/ifld-parse-encode-decode context which value)
635   (if value
636       (begin
637         (if (or (not (list? value))
638                 (not (= (length value) 2))
639                 (not (list? (car value)))
640                 (not (= (length (car value)) 2))
641                 (not (list? (cadr value))))
642             (parse-error context
643                          (string-append "bad ifield " which " spec")
644                          value))
645         (if (or (not (> (length (cadr value)) 2))
646                 (not (mode:lookup (cadr (cadr value)))))
647             (parse-error context
648                          (string-append which " expression must have a mode")
649                          value))))
650   value
651 )
652
653 ; Parse an <ifield> encode spec.
654
655 (define (/ifld-parse-encode context encode)
656   (/ifld-parse-encode-decode context "encode" encode)
657 )
658
659 ; Parse an <ifield> decode spec.
660
661 (define (/ifld-parse-decode context decode)
662   (/ifld-parse-encode-decode context "decode" decode)
663 )
664
665 ; Define an instruction field object, name/value pair list version.
666
667 (define define-ifield
668   (lambda arg-list
669     (let ((f (apply /ifield-read (cons (make-current-context "define-ifield")
670                                        arg-list))))
671       (if f
672           (current-ifld-add! f))
673       f))
674 )
675
676 ; Define an instruction field object, all arguments specified.
677 ; ??? Leave out word-offset,word-length,follows for now (RISC version).
678 ; FIXME: Eventually this should be fixed to take *all* arguments.
679
680 (define (define-full-ifield name comment attrs start length mode encode decode)
681   (let ((f (/ifield-parse (make-current-context "define-full-ifield")
682                           name comment attrs
683                           #f #f start length #f mode encode decode)))
684     (if f
685         (current-ifld-add! f))
686     f)
687 )
688
689 (define (/ifield-add-commands!)
690   (reader-add-command! 'define-ifield
691                        "\
692 Define an instruction field, name/value pair list version.
693 "
694                        nil 'arg-list define-ifield)
695   (reader-add-command! 'define-full-ifield
696                        "\
697 Define an instruction field, all arguments specified.
698 "
699                        nil '(name comment attrs start length mode encode decode)
700                        define-full-ifield)
701   (reader-add-command! 'define-multi-ifield
702                        "\
703 Define an instruction multi-field, name/value pair list version.
704 "
705                        nil 'arg-list define-multi-ifield)
706   (reader-add-command! 'define-full-multi-ifield
707                        "\
708 Define an instruction multi-field, all arguments specified.
709 "
710                        nil '(name comment attrs mode subflds insert extract)
711                        define-full-multi-ifield)
712
713   *UNSPECIFIED*
714 )
715 \f
716 ; Instruction fields consisting of multiple parts.
717
718 (define <multi-ifield>
719   (class-make '<multi-ifield>
720               '(<ifield>)
721               '(
722                 ; List of <ifield> objects.
723                 subfields
724                 ; rtl to set SUBFIELDS from self
725                 insert
726                 ; rtl to set self from SUBFIELDS
727                 extract
728                 )
729               nil)
730 )
731
732 (method-make-make! <multi-ifield> '(name comment attrs
733                                     mode bitrange encode decode
734                                     subfields insert extract))
735
736 ; Accessors
737
738 (define-getters <multi-ifield> multi-ifld
739   (subfields insert extract)
740 )
741
742 ; Return a boolean indicating if X is an <ifield>.
743
744 (define (multi-ifield? x) (class-instance? <multi-ifield> x))
745
746 (define (non-multi-ifields ifld-list)
747   (find (lambda (ifld) (not (multi-ifield? ifld))) ifld-list)
748 )
749
750 (define (non-derived-ifields ifld-list)
751   (find (lambda (ifld) (not (derived-ifield? ifld))) ifld-list)
752 )
753
754 ; Return the starting bit number of the first field.
755
756 (method-make!
757  <multi-ifield> 'field-start
758  (lambda (self)
759    (apply min (map (lambda (f) (ifld-start f)) (elm-get self 'subfields))))
760 )
761
762 ; Return the total length.
763
764 (method-make!
765  <multi-ifield> 'field-length
766  (lambda (self)
767    (apply + (map ifld-length (elm-get self 'subfields))))
768 )
769
770 ; Return the bit offset of the word after the last word SELF is in.
771 ; What a `word' here is defined by subfields in their bitranges.
772
773 (method-make!
774  <multi-ifield> 'next-word
775  (lambda (self)
776    (apply max (map (lambda (f)
777                      (bitrange-next-word (/ifld-bitrange f)))
778                    (multi-ifld-subfields self))))
779 )
780
781 ; Return mask of field in bitrange CONTAINER.
782
783 (method-make!
784  <multi-ifield> 'field-mask
785  (lambda (self base-len container)
786    (apply + (map (lambda (f) (ifld-mask f base-len container)) (elm-get self 'subfields))))
787 )
788
789 ; Return VALUE inserted into the field's position.
790 ; The value is spread out over the various subfields in sorted order.
791 ; We assume the subfields have been sorted by starting bit position.
792
793 (method-make!
794  <multi-ifield> 'field-value
795  (lambda (self base-len value)
796    (apply + (map (lambda (f) (ifld-value f base-len value)) (elm-get self 'subfields))))
797 )
798
799 ; Return a list of ifields required to compute the field's value.
800
801 (method-make!
802  <multi-ifield> 'needed-iflds
803  (lambda (self)
804    (cons self (elm-get self 'subfields)))
805 )
806
807 ; Extract <ifield> IFLD's value out of VALUE in <insn> INSN.
808 ; VALUE is the entire insn's value if it fits in a word, or is a list
809 ; of values, one per word (not implemented, sigh).
810 ; ??? The instruction's format should specify where the word boundaries are.
811
812 (method-make!
813  <multi-ifield> 'field-extract
814  (lambda (self insn value)
815    (let* ((subflds (sort-ifield-list (elm-get self 'subfields)
816                                      (not (ifld-lsb0? self))))
817           (subvals (map (lambda (subfld)
818                           (ifld-extract subfld insn value))
819                         subflds))
820          )
821      ; We have each subfield's value, now concatenate them.
822      (letrec ((plus-scan (lambda (lengths current)
823                            ; do the -1 drop here as it's easier
824                            (if (null? (cdr lengths))
825                                nil
826                                (cons current
827                                      (plus-scan (cdr lengths)
828                                                 (+ current (car lengths))))))))
829        (apply + (map logsll
830                      subvals
831                      (plus-scan (map ifld-length subflds) 0))))))
832 )
833
834 ; Return a boolean indicating if bit 0 is the least significant bit.
835
836 (method-make!
837  <multi-ifield> 'field-lsb0?
838  (lambda (self)
839    (ifld-lsb0? (car (elm-get self 'subfields))))
840 )
841
842 ;; Pretty print a multi-ifield, typically for error messages.
843
844 (method-make!
845  <multi-ifield> 'pretty-print
846  (lambda (self)
847    (string-append "(" (obj:str-name self)
848                   (string-map (lambda (f)
849                                 (string-append " " (ifld-pretty-print f)))
850                               (elm-get self 'subfields))
851                   ")"))
852 )
853 \f
854 ; Multi-ifield parsing.
855
856 ; Subroutine of /multi-ifield-parse to build the default insert expression.
857
858 (define (/multi-ifield-make-default-insert container-name subfields)
859   (let* ((lengths (map ifld-length subfields))
860          (shifts (list-tail-drop 1 (plus-scan (cons 0 lengths)))))
861     ; Build RTL expression to shift and mask each ifield into right spot.
862     (let ((exprs (map (lambda (f length shift)
863                         (rtx-make 'and (rtx-make 'srl container-name shift)
864                                   (mask length)))
865                       subfields lengths shifts)))
866       ; Now set each ifield with their respective values.
867       (apply rtx-make (cons 'sequence
868                             (cons nil
869                                   (map (lambda (f expr)
870                                          (rtx-make-set f expr))
871                                        subfields exprs))))))
872 )
873
874 ; Subroutine of /multi-ifield-parse to build the default extract expression.
875
876 (define (/multi-ifield-make-default-extract container-name subfields)
877   (let* ((lengths (map ifld-length subfields))
878          (shifts (list-tail-drop 1 (plus-scan (cons 0 lengths)))))
879     ; Build RTL expression to shift and mask each ifield into right spot.
880     (let ((exprs (map (lambda (f length shift)
881                         (rtx-make 'sll (rtx-make 'and (obj:name f)
882                                                  (mask length))
883                                   shift))
884                       subfields lengths shifts)))
885       ; Now set {container-name} with all the values or'd together.
886       (rtx-make-set container-name
887                     (rtx-combine 'or exprs))))
888 )
889
890 ; Parse a multi-ifield spec.
891 ; This is the main routine for building the object from the .cpu file.
892 ; All arguments are in raw (non-evaluated) form.
893 ; The result is the parsed object or #f if object isn't for selected mach(s).
894
895 (define (/multi-ifield-parse context name comment attrs mode
896                              subfields insert extract encode decode)
897   (logit 2 "Processing multi-ifield element " name " ...\n")
898
899   (if (null? subfields)
900       (parse-error context "empty subfield list" subfields))
901
902   ;; Pick out name first to augment the error context.
903   (let* ((name (parse-name context name))
904          (context (context-append-name context name))
905          (atlist (atlist-parse context attrs "cgen_ifld"))
906          (isas (atlist-attr-value atlist 'ISA #f)))
907
908     ; No longer ensure only one isa specified.
909     ; (if (!= (length isas) 1)
910     ;     (parse-error context "can only specify 1 isa" attrs))
911
912     (if (keep-isa-atlist? atlist #f)
913
914         (begin
915           (let ((result (new <multi-ifield>))
916                 (subfields (map (lambda (subfld)
917                                   (let ((f (current-ifld-lookup subfld)))
918                                     (if (not f)
919                                         (parse-error context "unknown ifield"
920                                                      subfld))
921                                     f))
922                                 subfields)))
923
924             (elm-xset! result 'name name)
925             (elm-xset! result 'comment (parse-comment context comment))
926             (elm-xset! result 'attrs
927                        ;; multi-ifields are always VIRTUAL
928                        (atlist-parse context (cons 'VIRTUAL attrs)
929                                      "multi-ifield"))
930             (elm-xset! result 'mode (parse-mode-name context mode))
931             (elm-xset! result 'encode (/ifld-parse-encode context encode))
932             (elm-xset! result 'decode (/ifld-parse-encode context decode))
933             (elm-xset! result 'bitrange "multi-ifields don't have bitranges") ;; FIXME
934             (if insert
935                 (elm-xset! result 'insert insert)
936                 (elm-xset! result 'insert
937                            (/multi-ifield-make-default-insert name subfields)))
938             (if extract
939                 (elm-xset! result 'extract extract)
940                 (elm-xset! result 'extract
941                            (/multi-ifield-make-default-extract name subfields)))
942             (elm-xset! result 'subfields subfields)
943             result))
944
945         ; else don't keep isa
946         #f))
947 )
948
949 ; Read an instruction multi-ifield.
950 ; This is the main routine for analyzing multi-ifields in the .cpu file.
951 ; CONTEXT is a <context> object for error messages.
952 ; ARG-LIST is an associative list of field name and field value.
953 ; /multi-ifield-parse is invoked to create the `multi-ifield' object.
954
955 (define (/multi-ifield-read context . arg-list)
956   (let (
957         (name nil)
958         (comment "")
959         (attrs nil)
960         (mode 'UINT)
961         (subflds nil)
962         (insert #f)
963         (extract #f)
964         (encode #f)
965         (decode #f)
966         )
967
968     ; Loop over each element in ARG-LIST, recording what's found.
969     (let loop ((arg-list arg-list))
970       (if (null? arg-list)
971           nil
972           (let ((arg (car arg-list))
973                 (elm-name (caar arg-list)))
974             (case elm-name
975               ((name) (set! name (cadr arg)))
976               ((comment) (set! comment (cadr arg)))
977               ((attrs) (set! attrs (cdr arg)))
978               ((mode) (set! mode (cadr arg)))
979               ((subfields) (set! subflds (cdr arg)))
980               ((insert) (set! insert (cadr arg)))
981               ((extract) (set! extract (cadr arg)))
982               ((encode) (set! encode (cdr arg)))
983               ((decode) (set! decode (cdr arg)))
984               (else (parse-error context "invalid ifield arg" arg)))
985             (loop (cdr arg-list)))))
986
987     ; Now that we've identified the elements, build the object.
988     (/multi-ifield-parse context name comment attrs mode subflds
989                          insert extract encode decode))
990 )
991
992 ; Define an instruction multi-field object, name/value pair list version.
993
994 (define define-multi-ifield
995   (lambda arg-list
996     (let ((f (apply /multi-ifield-read (cons (make-current-context "define-multi-ifield")
997                                              arg-list))))
998       (if f
999           (current-ifld-add! f))
1000       f))
1001 )
1002
1003 ; Define an instruction multi-field object, all arguments specified.
1004 ; FIXME: encode/decode arguments are missing.
1005
1006 (define (define-full-multi-ifield name comment attrs mode subflds insert extract)
1007   (let ((f (/multi-ifield-parse (make-current-context "define-full-multi-ifield")
1008                                 name comment attrs
1009                                 mode subflds insert extract #f #f)))
1010     (current-ifld-add! f)
1011     f)
1012 )
1013 \f
1014 ; Derived ifields (ifields based on one or more other ifields).
1015 ; These support the complicated requirements of CISC instructions
1016 ; where one "ifield" is actually a placeholder for an addressing mode
1017 ; which can consist of several ifields.
1018 ; These are also intended to support other complex ifield usage.
1019 ;
1020 ; Derived ifields are (currently) always machine generated from other
1021 ; elements of the description file so there is no reader support.
1022 ;
1023 ; ??? experimental and wip!
1024 ; ??? These are kind of like multi-ifields but I don't want to disturb them
1025 ; while this is still experimental.
1026
1027 (define <derived-ifield>
1028   (class-make '<derived-ifield>
1029               '(<ifield>)
1030               '(
1031                 ; Operand that uses this ifield.
1032                 ; Unlike other ifields, derived ifields have a one-to-one
1033                 ; correspondence with the operand that uses them.
1034                 ; ??? Not true in -anyof-merge-subchoices.
1035                 owner
1036
1037                 ; List of ifields that make up this ifield.
1038                 subfields
1039                 )
1040               nil)
1041 )
1042
1043 (method-make!
1044  <derived-ifield> 'needed-iflds
1045  (lambda (self)
1046    (find (lambda (ifld) (not (ifld-constant? ifld)))
1047          (elm-get self 'subfields)))
1048 )
1049
1050 (method-make!
1051  <derived-ifield> 'make!
1052  (lambda (self name comment attrs owner subfields)
1053    (elm-set! self 'name name)
1054    (elm-set! self 'comment comment)
1055    (elm-set! self 'attrs attrs)
1056    (elm-set! self 'mode UINT)
1057    (elm-set! self 'bitrange (make <bitrange> 0 0 0 0 #f))
1058    (elm-set! self 'encode #f)
1059    (elm-set! self 'decode #f)
1060    (elm-set! self 'owner owner)
1061    (elm-set! self 'subfields subfields)
1062    self)
1063 )
1064
1065 ; Accessors.
1066
1067 (define-getters <derived-ifield> derived-ifield (owner subfields))
1068
1069 (define-setters <derived-ifield> derived-ifield (owner subfields))
1070
1071 (define (derived-ifield? x) (class-instance? <derived-ifield> x))
1072
1073 ; Return a boolean indicating if F is a derived ifield with a derived operand
1074 ; for a value.
1075 ; ??? The former might imply the latter so some simplification may be possible.
1076
1077 (define (ifld-derived-operand? f)
1078   (and (derived-ifield? f)
1079        (derived-operand? (ifld-get-value f)))
1080 )
1081
1082 ; Return the bit offset of the word after the last word SELF is in.
1083 ; What a `word' here is defined by subfields in their bitranges.
1084
1085 (method-make!
1086  <derived-ifield> 'next-word
1087  (lambda (self)
1088    (apply max (map (lambda (f)
1089                      (bitrange-next-word (/ifld-bitrange f)))
1090                    (derived-ifield-subfields self))))
1091 )
1092
1093 ; Return a list of all base (non-derived) ifields in IFLD.
1094 ; NOTE: multi-ifields are *not* reduced to their sub-ifields.
1095
1096 (define (ifld-base-ifields ifld)
1097   (cond ((derived-ifield? ifld) (ifields-base-ifields (derived-ifield-subfields ifld)))
1098         ;;((multi-ifield? ifld) (ifields-base-ifields (multi-ifld-subfields ifld)))
1099         (else (list ifld)))
1100 )
1101
1102 ; Collect all base (non-derived) ifields in IFLD-LIST.
1103 ; NOTE: multi-ifields are *not* reduced to their sub-ifields.
1104
1105 (define (ifields-base-ifields ifld-list)
1106   (collect ifld-base-ifields ifld-list)
1107 )
1108
1109 ; Return a list of all simple ifields in IFLD.
1110 ; NOTE: multi-ifields *are* reduced to their sub-ifields.
1111
1112 (define (ifld-simple-ifields ifld)
1113   (cond ((derived-ifield? ifld) (ifields-simple-ifields (derived-ifield-subfields ifld)))
1114         ((multi-ifield? ifld) (ifields-simple-ifields (multi-ifld-subfields ifld)))
1115         (else (list ifld)))
1116 )
1117
1118 ; Collect all simple ifields in IFLD-LIST.
1119 ; NOTE: multi-ifields *are* reduced to their sub-ifields.
1120
1121 (define (ifields-simple-ifields ifld-list)
1122   (collect ifld-simple-ifields ifld-list)
1123 )
1124 \f
1125 ; Misc. utilities.
1126
1127 ; Sort a list of fields (sorted by the starting bit number).
1128 ; This must be carefully defined to pass through Hobbit.
1129 ; (define foo (if x bar baz)) is ok.
1130 ; (if x (define foo bar) (define foo baz)) is not ok.
1131 ;
1132 ; ??? Usually there aren't that many fields and the range of values is fixed,
1133 ; so I think this needn't use a general purpose sort routine (should it become
1134 ; an issue).
1135
1136 (define sort-ifield-list
1137   (if (and (defined? 'cgh-qsort) (defined? 'cgh-qsort-int-cmp))
1138       (lambda (fld-list up?)
1139         (cgh-qsort fld-list
1140                    (if up?
1141                        (lambda (a b)
1142                          (cgh-qsort-int-cmp (ifld-start a)
1143                                             (ifld-start b)))
1144                        (lambda (a b)
1145                          (- (cgh-qsort-int-cmp (ifld-start a)
1146                                                (ifld-start b)))))))
1147       (lambda (fld-list up?)
1148         (sort fld-list
1149               (if up?
1150                   (lambda (a b) (< (ifld-start a)
1151                                    (ifld-start b)))
1152                   (lambda (a b) (> (ifld-start a)
1153                                    (ifld-start b)))))))
1154 )
1155
1156 ; Return a boolean indicating if field F extends beyond the base insn.
1157
1158 (define (ifld-beyond-base? f)
1159   (> (ifld-word-offset f) 0)
1160 )
1161
1162 ; Return <hardware> object to use to hold value of <ifield> F.
1163 ; i.e. one of h-uint, h-sint.
1164 ; NB: Should be defined in terms of `hardware-for-mode'.
1165 (define (ifld-hw-type f)
1166   (case (mode:class (ifld-mode f))
1167     ((INT) h-sint)
1168     ((UINT) h-uint)
1169     (else (error "unsupported mode class" (mode:class (ifld-mode f)))))
1170 )
1171 \f
1172 ; Builtin fields, attributes, init/fini support.
1173
1174 ; The f-nil field is a placeholder when building operands out of hardware
1175 ; elements that aren't indexed by an instruction field (scalars).
1176 (define f-nil #f)
1177
1178 (define (ifld-nil? f)
1179   (eq? (obj:name f) 'f-nil)
1180 )
1181
1182 ; The f-anyof field is a placeholder when building "anyof" operands.
1183 (define f-anyof #f)
1184
1185 (define (ifld-anyof? f)
1186   (eq? (obj:name f) 'f-anyof)
1187 )
1188
1189 ; Return a boolean indicating if F is an anyof ifield with an anyof operand
1190 ; for a value.
1191 ; ??? The former implies the latter so some simplification is possible.
1192
1193 (define (ifld-anyof-operand? f)
1194   (and (ifld-anyof? f)
1195        (anyof-operand? (ifld-get-value f)))
1196 )
1197
1198 ; Called before loading the .cpu file to initialize.
1199
1200 (define (ifield-init!)
1201   (/ifield-add-commands!)
1202
1203   *UNSPECIFIED*
1204 )
1205
1206 ; Called before loading the .cpu file to create any builtins.
1207
1208 (define (ifield-builtin!)
1209   ; Standard ifield attributes.
1210   ; ??? Some of these can be combined into one, booleans are easier to
1211   ; work with.
1212   (define-attr '(for ifield operand) '(type boolean) '(name PCREL-ADDR)
1213     '(comment "pc relative address"))
1214   (define-attr '(for ifield operand) '(type boolean) '(name ABS-ADDR)
1215     '(comment "absolute address"))
1216   (define-attr '(for ifield) '(type boolean) '(name RESERVED)
1217     '(comment "field is reserved"))
1218   (define-attr '(for ifield operand) '(type boolean) '(name SIGN-OPT)
1219     '(comment "value is signed or unsigned"))
1220   ; ??? This is an internal attribute for implementation purposes only.
1221   ; To be revisited.
1222   (define-attr '(for ifield operand) '(type boolean) '(name SIGNED)
1223     '(comment "value is unsigned"))
1224   ; Also (defined elsewhere): VIRTUAL
1225
1226   (set! f-nil (make <ifield> (builtin-location)
1227                     'f-nil "empty ifield"
1228                     (atlist-cons (all-isas-attr) nil)
1229                     UINT
1230                     (make <bitrange> 0 0 0 0 #f)
1231                     #f #f)) ; encode/decode
1232   (current-ifld-add! f-nil)
1233
1234   (set! f-anyof (make <ifield> (builtin-location)
1235                       'f-anyof "placeholder for anyof operands"
1236                       (atlist-cons (all-isas-attr) nil)
1237                       UINT
1238                       (make <bitrange> 0 0 0 0 #f)
1239                       #f #f)) ; encode/decode
1240   (current-ifld-add! f-anyof)
1241
1242   *UNSPECIFIED*
1243 )
1244
1245 ; Called after the .cpu file has been read in.
1246
1247 (define (ifield-finish!)
1248   *UNSPECIFIED*
1249 )