; cpu description for debugging and experimental purposes. -*- Scheme -*-
; This file is part of CGEN.
; See file COPYING.CGEN for details.
; Copyright (C) 2000 Red Hat, Inc.
;
; This file is for experimental purposes.  Don't expect it to be correct
; or up to date.

(define-rtl-version 0 7)

(include "simplify.inc")

(define-arch
  (name play) ; name of cpu
  (comment "experimental .cpu file")
  (insn-lsb0? #t)
  (machs playb)
  (isas play)
)

(define-isa
  (name play)
  (base-insn-bitsize 16)
  (decode-assist (0 1 2 3))
)
  
(define-cpu
  (name cpuf)
  (comment "experimental cpu family")
  (endian little)
  (word-bitsize 32)
)

(define-mach
  (name playb)
  (comment "experimental mach")
  (cpu cpuf)
)

(define-model
  (name test) (comment "test") (attrs)
  (mach playb)
  ;(pipeline all "" () ((fetch) (decode) (execute) (writeback)))
  (unit u-exec "Execution Unit" () 1 1
	() () () ())
)

; Instruction fields.
; Copies of all the variations.

; little endian, lsb0? = #f
;(dnf f-op1       "op1"                 () 0 4)
;(dnf f-op2       "op2"                 () 4 4)
;(dnf f-op3       "op3"                 () 8 4)
;(dnf f-op4       "op4"                 () 12 4)
;(dnf f-r1        "r1"                  () 8 4)
;(dnf f-r2        "r2"                  () 12 4)
;(df  f-simm16     "simm16"             () 16 16 INT #f #f)
;(df  f-simm16b    "16 bit signed immediate after simm32" () 48 16 INT #f #f)
;(df  f-simm32     "simm32"             () 16 32 INT #f #f)
;(df  f-simm32b    "32 bit signed immediate after simm16" () 32 32 INT #f #f)

; little endian, lsb0? = #t
(dnf f-op1       "op1"                 () 15 4)
(dnf f-op2       "op2"                 () 11 4)
(dnf f-op3       "op3"                 () 7 4)
(dnf f-op4       "op4"                 () 3 4)
(dnf f-r1        "r1"                  () 7 4)
(dnf f-r2        "r2"                  () 3 4)
(df  f-simm16     "simm16"             () 31 16 INT #f #f)
(df  f-simm16b    "16 bit signed immediate after simm32" () 63 16 INT #f #f)
(df  f-simm32     "simm32"             () 47 32 INT #f #f)
(df  f-simm32b    "32 bit signed immediate after simm16" () 63 32 INT #f #f)

; big endian, lsb0? = #f
;(dnf f-op1       "op1"                 () 0 4)
;(dnf f-op2       "op2"                 () 4 4)
;(dnf f-op3       "op3"                 () 8 4)
;(dnf f-op4       "op4"                 () 12 4)
;(dnf f-r1        "r1"                  () 8 4)
;(dnf f-r2        "r2"                  () 12 4)
;(df  f-simm16     "simm16"             () 16 16 INT #f #f)
;(df  f-simm16b    "16 bit signed immediate after simm32" () 48 16 INT #f #f)
;(df  f-simm32     "simm32"             () 16 32 INT #f #f)
;(df  f-simm32b    "32 bit signed immediate after simm16" () 32 32 INT #f #f)

; big endian, lsb0? = #t
;(dnf f-op1       "op1"                 () 15 4)
;(dnf f-op2       "op2"                 () 11 4)
;(dnf f-op3       "op3"                 () 7 4)
;(dnf f-op4       "op4"                 () 3 4)
;(dnf f-r1        "r1"                  () 7 4)
;(dnf f-r2        "r2"                  () 3 4)
;(df  f-simm16     "simm16"             () 31 16 INT #f #f)
;(df  f-simm16b    "16 bit signed immediate after simm32" () 63 16 INT #f #f)
;(df  f-simm32     "simm32"             () 47 32 INT #f #f)
;(df  f-simm32b    "32 bit signed immediate after simm16" () 63 32 INT #f #f)

(define-normal-insn-enum insn-op1 "insn format enums" () OP1_ f-op1
  (.map .str (.iota 16))
)

(define-normal-insn-enum insn-op2 "insn format enums (2)" () OP2_ f-op2
  (.map .str (.iota 16))
)

(define-normal-insn-enum insn-op3 "insn format enums (3)" () OP3_ f-op3
  (.map .str (.iota 16))
)

(define-normal-insn-enum insn-op4 "insn format enums (4)" () OP4_ f-op4
  (.map .str (.iota 16))
)

; Hardware.

(dnh h-pc "program counter" (PC PROFILE) (pc) () () ())

; get the real index of a gpr on the circular register queue.

(define-pmacro (real-gpr-index index)
  (if WI (lt index 20)
    ; global reg
    index
    ; local reg
    (sequence WI ((WI pr))
      (set pr (add index (reg h-gr 0)))
      (if WI (ge pr 256)
    (sub pr 236)
    pr
      )
    )
  )
)

; All accesses to gprs in instructions use {get|set}-{gpr|vgpr}
; functions.  These functions handle register 0 being 0.  This cannot
; be handled without understanding the context of the get or set since
; regs 1-3 are 0 for vector instructions but not for scalar
; instructions.
;
; general purpose registers.

;(define-hardware
;  (name h-gpr)
;  (comment "General Purpose Registers")
;  (type register DI (256))
;  (indices keyword "" (gen-register-names "r" 256 0 1))
;  (get (index)
;    (raw-reg DI h-gpr (real-gpr-index index))
;  )
;  (set (index newval)
;    (set (raw-reg DI h-gpr (real-gpr-index index)) newval)
;  )
;)


(define-hardware
  (name h-gr)
  (comment "general registers")
  (attrs PROFILE );CACHE-ADDR)
  (type register WI (16))
  (indices keyword ""
	   ( (fp 13) (lr 14) (sp 15)
	     (r0 0) (r1 1) (r2 2) (r3 3) (r4 4) (r5 5) (r6 6) (r7 7)
	     (r8 8) (r9 9) (r10 10) (r11 11) (r12 12) (r13 13) (r14 14) (r15 15)
	     ))
  (get (index)
    (raw-reg WI h-gr (real-gpr-index index))
  )
  (set (index newval)
    (set (raw-reg WI h-gr (real-gpr-index index)) newval)
  )
)

(define-hardware
  (name h-status)
  (comment "status reg")
  (type register SI)
  (get () (const 0))
  (set (newval) (nop))
)

; These bits are actually part of the PS register
(dsh h-nbit "negative bit" () (register BI))
(dsh h-zbit "zero     bit" () (register BI))
(dsh h-vbit "overflow bit" () (register BI))
(dsh h-cbit "carry    bit" () (register BI))

(define-hardware
  (name ps)
  (type register QI)
  (layout h-nbit h-zbit h-vbit h-cbit (0 4))
)

(dsh h-df "df test" () (register DF))
(dsh h-tf "tf test" () (register TF))

(define-hardware
  (name accum)
  (type register (INT 64))
)

; Operand attributes.

(define-attr
  (for operand)
  (type boolean)
  (name HASH-PREFIX)
  (comment "immediates have a '#' prefix")
)

; Operands.

(dnop nbit "negative bit" (SEM-ONLY) h-nbit f-nil)
(dnop vbit "overflow bit" (SEM-ONLY) h-vbit f-nil)
(dnop zbit "zero     bit" (SEM-ONLY) h-zbit f-nil)
(dnop cbit "carry    bit" (SEM-ONLY) h-cbit f-nil)

(dnop dr     "destination register"    () h-gr   f-r1)
(dnop sr     "source register"         () h-gr   f-r2)
(dnop simm16 "16 bit signed immediate" (HASH-PREFIX) h-sint f-simm16)
(dnop simm16b "16 bit signed immediate after simm32" (HASH-PREFIX) h-sint f-simm16b)
(dnop simm32 "32 bit signed immediate" (HASH-PREFIX) h-sint f-simm32)
(dnop simm32b "32 bit signed immediate after simm16" (HASH-PREFIX) h-sint f-simm32b)

; Note that `df' doesn't work as that is a pmacro.
(dnop df-reg "df reg" () h-df f-nil)
(dnop tf-reg "tf reg" () h-tf f-nil)

; Instructions.

(dni add "add"
     ()
     "add $dr,$sr"
     ; Use (f-op1 OP1_4) to exercise it.
     (+ (f-op1 OP1_4) OP2_0 dr sr)
     (sequence ()
	       (set vbit (add-oflag dr sr (const 0)))
	       (set cbit (add-cflag dr sr (const 0)))
	       (set dr (add dr sr))
	       (set zbit (zflag dr))
	       (set nbit (nflag dr)))
     ()
)

(dni addv2 "add version 2"
     ()
     "add $dr,$sr"
     (+ OP1_4 OP2_1 dr sr)
     (sequence ((WI tmp1))
	       (parallel ()
			 (set (local DFLT tmp1) (add dr sr))
			 (set vbit (add-oflag dr sr (const 0)))
			 (set cbit (add-cflag dr sr (const 0))))
	       (set zbit (zflag tmp1))
	       (set nbit (nflag tmp1))
	       (set dr tmp1)
	       )
     ()
)

(dni addi16 "addi16"
     ()
     "addi16 $dr,$sr,$simm16"
     (+ OP1_4 OP2_2 dr sr simm16)
     (set dr (add sr simm16))
     ()
)

(dni addi32 "addi32"
     ()
     "addi32 $dr,$sr,$simm32"
     (+ OP1_4 OP2_3 dr sr simm32)
     (set dr (add sr simm32))
     ()
)

(define-pmacro (reg+ oprnd n)
  (reg h-gr (add (index-of oprnd) (const n)))
)

(dni ldm "ldm"
     ()
     "ldm $dr,$sr"
     (+ OP1_5 OP2_2 dr sr)
     (sequence ()
	       (set dr sr)
	       (set (reg+ dr 1) (reg+ sr 1))
	       )
     ()
)

(dni use-ifield "use-ifield"
     ()
     "foo $dr,$sr"
     (+ OP1_5 OP2_3 dr sr)
     (sequence ()
	       (set dr (ifield f-r2))
	       )
     ()
)

(dni use-index-of "index-of"
     ()
     "index-of $dr,$sr"
     (+ OP1_5 OP2_4 dr sr)
     (set dr (reg h-gr (add (index-of sr) (const 1))))
     ()
)

(dni load-df "use df"
     ()
     "load-df df,[$sr]"
     (+ OP1_6 OP2_0 OP3_0 sr)
     (set df-reg (mem DF sr))
     ()
)

(dni make-df "use df"
     ()
     "make-df df,[$sr]"
     (+ OP1_6 OP2_1 OP3_0 sr)
     (set df-reg (join DF SI (mem SI sr) (mem SI (add sr (const 4)))))
     ()
)

(dni split-df "use df"
     ()
     "split-df df,[$sr]"
     (+ OP1_6 OP2_2 OP3_0 sr)
     (sequence ((DF temp))
	       (set temp df-reg)
	       (set (concat (SI SI)
			     sr
			     (reg h-gr (add (regno sr) (const 1))))
		    (split DF SI temp))
	       )
     ()
)

(dni load-tf "use tf"
     ()
     "load-tf tf,[$sr]"
     (+ OP1_6 OP2_3 OP3_0 sr)
     (set tf-reg (mem TF sr))
     ()
)

(dni make-tf "use tf"
     ()
     "make-tf tf,[$sr]"
     (+ OP1_6 OP2_4 OP3_0 sr)
     (set tf-reg (join TF SI
		    sr
		    (reg h-gr (add (regno sr) (const 1)))
		    (reg h-gr (add (regno sr) (const 2)))
		    (reg h-gr (add (regno sr) (const 3)))))
     ()
)

(dni split-tf "use tf"
     ()
     "split-tf tf,[$sr]"
     (+ OP1_6 OP2_5 OP3_0 sr)
     (sequence ((TF temp))
	       (set temp tf-reg)
	       (set (concat (SI SI SI SI)
			     sr
			     (reg h-gr (add (regno sr) (const 1)))
			     (reg h-gr (add (regno sr) (const 2)))
			     (reg h-gr (add (regno sr) (const 3))))
		    (split TF SI temp))
	       )
     ()
)

;;(define-pmacro (no-ext-expr mode expr) expr)
;;(define-pmacro (ext-expr mode expr) (ext mode expr))
;;(define-pmacro (zext-expr mode expr) (zext mode expr))

(define-pmacro (load-op suffix op2-op mode ext-op)
 (.let (
	(no-ext-expr (.pmacro (mode expr) expr))
	(ext-expr (.pmacro (mode expr) (ext mode expr)))
	(zext-expr (.pmacro (mode expr) (zext mode expr)))
	 )
  (begin
    (dni (.sym ld suffix) (.str "ld" suffix)
	 ()
	 (.str "ld" suffix " $dr,@@$sr")
	 (+ OP1_2 op2-op dr sr)
	 (set dr (ext-op WI (mem mode sr)))
	 ())
  )
 )
)

(load-op "" OP2_12 WI no-ext-expr)
(load-op b OP2_8 QI ext-expr)
(load-op h OP2_10 HI ext-expr)
(load-op ub OP2_9 QI zext-expr)
(load-op uh OP2_11 HI zext-expr)

(dni do-count-test "do-count-test"
     ()
     "do-count-test $dr,$sr"
     (+ OP1_7 OP2_0 dr sr)
     (sequence ()
	       (do-count VOID iter 4 (set dr (add sr iter)))
	       (do-count iter (and sr 7) (set dr (add sr iter)))
	       )
     ()
)
