OSDN Git Service

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