OSDN Git Service

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