OSDN Git Service

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