; SPARC64 CPU description.  -*- Scheme -*-
; This file contains elements specific to sparc64.
; Copyright (C) 2000 Red Hat, Inc.
; This file is part of CGEN.
; See file COPYING.CGEN for details.

; Notes:
; - sparc64 support wip
; - fp support todo
; - source file layout wip
; - cpu family layout wip

; ??? For the nonce there is one cpu family to cover all 64 bit sparcs.
; It's not clear this will work, but following the goal of incremental
; complication ....

(define-cpu
  (name sparc64)
  (comment "SPARC 64 bit architecture")
  (endian big) ; ??? big insn, either data
  (word-bitsize 64)
  ; Generated files have a "64" suffix.
  (file-transform "64")
)

(define-mach
  (name sparc-v9)
  (comment "sparc v9")
  ;(attrs S64-P)
  (cpu sparc64)
  (bfd-name "sparc_v9")
)

(define-mach
  (name sparc-v9a)
  (comment "sparc v9a (sparc-v9 + vis)")
  ;(attrs S64-P)
  (cpu sparc64)
  (bfd-name "sparc_v9a")
)

; sparc64 models

(define-model
  (name sparc64-def)
  (comment "sparc64 default")
  (attrs)
  (mach sparc-v9)
  ; wip (Meaning, yes I know this is inaccurate, duh ...
  ; When I have time I'll finish this up right.
  ; Support for some of this isn't even implemented yet and support for the
  ; rest will be rewritten.)
  (pipeline p-foo "" () ((fetch) (decode) (execute) (memory) (writeback)))
  (unit u-exec "Execution Unit" ()
	1 1 ; issue done
	() () () ())
)

; sparc64 instruction fields

(dnf f-fmt2-cc1     "cc"           ((MACH64)) 21 1)
(dnf f-fmt2-cc0     "cc"           ((MACH64)) 20 1)
(dnf f-p            "p"            ((MACH64)) 19 1)
(dnf f-fmt2-rcond   "fmt2 rcond"   ((MACH64)) 27 3)
(df  f-disp19       "disp19"       (PCREL-ADDR (MACH64)) 13 19 INT #f #f)
(dnf f-fmt3-rcond   "fmt3 rcond"   ((MACH64)) 19 3)
(dnf f-shcnt64      "shcnt64"      ((MACH64)) 5 6)
(dnf f-fmt4-cond    "cond"         ((MACH64)) 14 4)
(dnf f-fmt4-ccx-hi  "ccx hi"       ((MACH64)) 13 1)
(dnf f-fmt4-ccx-lo  "ccx lo"       ((MACH64)) 19 2)
(dnf f-fmt4-rcond   "fmt4 rcond"   ((MACH64)) 19 3)
(dnf f-fmt4-cc2     "fmt4 cc2"     ((MACH64)) 18 1)
(dnf f-fmt4-cc1-0   "fmt4 cc1,cc0" ((MACH64)) 12 2)
(dnf f-fmt4-res10-6 "reserved bits in movcc insns" (RESERVED (MACH64)) 10 6)

; The disp16 field requires a bit of special handling as it is split in two.
(df  f-disp16-hi    "disp16 hi"    ((MACH64)) 10 2 INT #f #f)
(dnf f-disp16-lo    "disp16 lo"    ((MACH64)) 18 14)
(dnmf f-disp16      "disp16"       (PCREL-ADDR (MACH64)) INT
      (f-disp16-hi f-disp16-lo)
      (sequence () ; insert
		(set (ifield f-disp16-hi) (srl (ifield f-disp16) (const 14)))
		(set (ifield f-disp16-lo) (and (ifield f-disp16) (const #x3fff)))
		)
      (sequence () ; extract
		; ??? where will pc be added?
		(set (ifield f-disp16) (or (sll (ifield f-disp16-hi) (const 14))
					   (ifield f-disp16-low)))
		)
)

(dnf f-res-18-19    "reserved bits in done/retry" (RESERVED (MACH64)) 18 19)

; sparc64 enums of opcodes, special insn values, etc.

(define-normal-insn-enum insn-rcond "rcond op values" () RCOND_ f-fmt2-rcond
  (
   (BRZ 1)
   (BRLEZ 2)
   (BRLZ 3)
   (BRNZ 5)
   (BRGZ 6)
   (BRGEZ 7)
   )
)

; sparc64 hardware pieces.

(dsh h-ver "version" ((MACH64)) (register UDI))

(dsh h-pstate "processor state" ((MACH64)) (register UDI))

(dsh h-tba "trap base address" ((MACH64)) (register UDI))

; FIXME: These are a stack of values.
(dsh h-tt "trap type" ((MACH64)) (register UDI))
(dsh h-tpc "trap pc" ((MACH64)) (register UDI))
(dsh h-tnpc "trap npc" ((MACH64)) (register UDI))
(dsh h-tstate "trap state" ((MACH64)) (register UDI))

(dsh h-tl "trap level" ((MACH64)) (register UQI))

(dsh h-asi "address space identifier" ((MACH64)) (register UQI))

(dsh h-tick "tick counter" ((MACH64)) (register UDI))

(dsh h-cansave "savable window registers" ((MACH64)) (register UDI))
(dsh h-canrestore "restorable window registers" ((MACH64)) (register UDI))
(dsh h-otherwin "other window registers" ((MACH64)) (register UDI))
(dsh h-cleanwin "clean window registers" ((MACH64)) (register UDI))

(dsh h-wstate "window state" ((MACH64)) (register UDI))

(define-hardware
  (name h-ixcc)
  (comment "condition code selector")
  (attrs (MACH64))
  (type immediate (UINT 1))
  (values keyword "%" (("icc" 0) ("xcc" 1)))
)

(define-hardware
  (name h-p)
  (comment "prediction bit")
  (attrs (MACH64))
  (type immediate (UINT 1))
  (values keyword "" (("" 0) (",pf" 0) (",pt" 1)))
)

; sparc64 operands

(dnop ixcc "%icc,%xcc arg to bpcc insns" ((MACH64)) h-ixcc f-fmt2-cc1)

(dnop p "prediction bit" ((MACH64)) h-p f-p)

(dnop disp16 "16 bit displacement" ((MACH64)) h-iaddr f-disp16)
(dnop disp19 "19 bit displacement" ((MACH64)) h-iaddr f-disp19)

; sparc64 branches

(dnf f-bpr-res28-1 "reserved bit 28 in bpr insn" (RESERVED (MACH64)) 28 1)

(define-pmacro (bpr-cbranch name comment rcond-op comp-op)
  (dni name (.str comment ", v9 page 136")
       ((MACH64))
       (.str name "$a$p $rs1,$disp16")
       (+ OP_0 a (f-bpr-res28-1 0) (.sym RCOND_ rcond-op)
	  OP2_BPR p rs1 disp16)
       (delay (const 1)
	      (if (comp-op rs1 (const 0))
		  (set pc disp16)
		  (annul a)))
       ())
)
(bpr-cbranch beqz "beqz" BRZ eq)
(bpr-cbranch bgez "bgez" BRGEZ ge)
(bpr-cbranch bgtz "bgtz" BRGZ gt)
(bpr-cbranch blez "blez" BRLEZ le)
(bpr-cbranch bltz "bltz" BRLZ lt)
(bpr-cbranch bnez "bnez" BRNZ ne)

(define-pmacro (bpcc-branch bname comment cond test br-sem)
  (dni (.sym bpcc- bname)
       (.str "branch with prediction %icc " comment ", v9 page 146")
       ((MACH64))
       (.str bname "$a$p %icc,$disp19")
       (+ OP_0 a cond OP2_BPCC (f-fmt2-cc1 0) (f-fmt2-cc0 0) p disp19)
       (br-sem test icc)
       ())
  (dni (.sym bpcc- bname)
       (.str "branch with prediction %xcc " comment ", v9 page 146")
       ((MACH64))
       (.str bname "$a$p %xcc,$disp19")
       (+ OP_0 a cond OP2_BPCC (f-fmt2-cc1 1) (f-fmt2-cc0 0) p disp19)
       (br-sem test xcc)
       ())
)
; test-*,uncond-br-sem,cond-br-sem are defined in sparc.cpu.
(bpcc-branch ba   "always" CC_A   test-always uncond-br-sem)
(bpcc-branch bn   "never"  CC_N   test-never uncond-br-sem)
(bpcc-branch bne  "ne"     CC_NE  test-ne cond-br-sem)
(bpcc-branch be   "eq"     CC_E   test-eq cond-br-sem)
(bpcc-branch bg   "gt"     CC_G   test-gt cond-br-sem)
(bpcc-branch ble  "le"     CC_LE  test-le cond-br-sem)
(bpcc-branch bge  "ge"     CC_GE  test-ge cond-br-sem)
(bpcc-branch bl   "lt"     CC_L   test-lt cond-br-sem)
(bpcc-branch bgu  "gtu"    CC_GU  test-gtu cond-br-sem)
(bpcc-branch bleu "leu"    CC_LEU test-leu cond-br-sem)
(bpcc-branch bcc  "geu"    CC_CC  test-geu cond-br-sem)
(bpcc-branch bcs  "ltu"    CC_CS  test-ltu cond-br-sem)
(bpcc-branch bpos "pos"    CC_POS test-pos cond-br-sem)
(bpcc-branch bneg "neg"    CC_NEG test-neg cond-br-sem)
(bpcc-branch bvc  "vc"     CC_VC  test-vc cond-br-sem)
(bpcc-branch bvs  "vs"     CC_VS  test-vs cond-br-sem)

; Misc.

(dni done "done, v9 page 155" ((MACH64))
     "done"
     (+ OP_2 (f-fcn 0) OP3_DONE_RETRY (f-res-18-19 0))
     (c-call "@cpu@_done" pc)
     ()
)
(dni retry "retry, v9 page 155" ((MACH64))
     "done"
     (+ OP_2 (f-fcn 1) OP3_DONE_RETRY (f-res-18-19 0))
     (c-call "@cpu@_retry" pc)
     ()
)

(dni flush "flush instruction memory rs1+rs2, v9 page 165" ((MACH64))
     "flush"
     (+ OP_2 (f-rd 0) OP3_FLUSH rs1 (f-i 0) (f-res-asi 0) rs2)
     (c-call "@cpu@_flush" pc (add rs1 rs2))
     ()
)
(dni flush-imm "flush instruction memory rs1+simm13, v9 page 165" ((MACH64))
     "flush"
     (+ OP_2 (f-rd 0) OP3_FLUSH rs1 (f-i 1) simm13)
     (c-call "@cpu@_flush" pc (add rs1 simm13))
     ()
)

(dni flushw "flush register windows, v9 page 167" ((MACH64))
     "flushw"
     (+ OP_2 (f-rd 0) OP3_FLUSHW (f-rs1 0) (f-i 0) (f-simm13 0))
     (c-call "@cpu@_flushw" pc)
     ()
)

; On sparc64 unimp is called illtrap.

(dnmi illtrap "illegal instruction trap, v9 page 168" ((MACH64))
      "illtrap $imm22"
      (emit unimp imm22)
)

; Impdep insns

(dnf f-impdep5  "5 bit field in impdep insns"  ((MACH64)) 29 5)
(dnf f-impdep19 "19 bit field in impdep insns" ((MACH64)) 18 19)

(dnop impdep5   "5 bit arg in impdep insns"    ((MACH64)) h-uint f-impdep5)
(dnop impdep19  "19 bit arg in impdep insns"   ((MACH64)) h-uint f-impdep19)

(dni impdep1 "implementation dependent instruction 1, v9 page 169"
     ((MACH64))
     "impdep1 $impdep5,$impdep19"
     (+ OP_2 impdep5 OP3_IMPDEP1 impdep19)
     (c-call "@cpu@_impdep1" pc impdep5 impdep19)
     ()
)
(dni impdep2 "implementation dependent instruction 1, v9 page 169"
     ((MACH64))
     "impdep2 $impdep5,$impdep19"
     (+ OP_2 impdep5 OP3_IMPDEP2 impdep19)
     (c-call "@cpu@_impdep2" pc impdep5 impdep19)
     ()
)

; Memory barrier insn

(dnf f-membar-res12-6 "reserved bits 12-7 in membar insn"
     (RESERVED (MACH64)) 12 6)
(dnf f-cmask          "cmask field in membar insn"       ((MACH64)) 6 3)
(dnf f-mmask          "mmask field in membar insn"       ((MACH64)) 3 4)
(dnf f-membarmask     "cmask+mmask field in membar insn" ((MACH64)) 6 7)

(define-hardware
  (name h-membarmask)
  (comment "membar mask")
  (attrs (MACH64))
  (type immediate (UINT 7))
  (values keyword "" (
		      ("#StoreStore" #x8)
		      ("#LoadStore" #x4)
		      ("#StoreLoad" #x2)
		      ("#LoadLoad" #x1)
		      ("#Sync" #x40)
		      ("#MemIssue" #x20)
		      ("#Lookaside" #x10)
		      ))
)

(define-operand
  (name membarmask)
  (comment "cmask+mmask arg in membar insn")
  (attrs (MACH64))
  (type h-membarmask)
  (index f-membarmask)
  (handlers (parse "membar_mask")
	    (print "membar_mask"))
)

(dni membar "memory barrier, v9 page 183"
     ((MACH64))
     "member $membarmask" ; ${membar-mask}
     (+ OP_2 (f-rd 0) OP3_MEMBAR (f-rs1 15) (f-i 1) (f-membar-res12-6 0)
	membarmask)
     (c-call "@cpu@_membar" pc membarmask)
     ()
)

; Conditional move insns

(df f-simm11 "11 bit signed immediate field" ((MACH64)) 10 11 INT #f #f)

(dnop simm11 "11 bit signed immediate arg to condition move insns"
      ((MACH64)) h-sint f-simm11)

(define-pmacro (cond-move-1 name comment mnemonic cc-prefix cc-name cc-opcode
			    src-name src-opcode cond test)
  (dni name
       (.str "move %" cc-name " " comment ", v9 page 191")
       ((MACH64))
       (.str mnemonic " " cc-prefix cc-name ",$" src-name ",$rd")
       (.splice + OP_2 rd OP3_MOVCC cond
		(.unsplice cc-opcode) (.unsplice src-opcode))
       (if (test cc-name)
	   (set rd src-name))
       ())
)

(define-pmacro (cond-move name comment cond test)
  (begin
    (cond-move-1 (.sym name -icc) comment
		 name "%" icc ((f-fmt4-cc2 1) (f-fmt4-cc1-0 0))
		 rs2 ((f-i 0) (f-fmt4-res10-6 0) rs2)
		 cond test)
    (cond-move-1 (.sym name -imm-icc) comment
		 name "%" icc ((f-fmt4-cc2 1) (f-fmt4-cc1-0 0))
		 simm11 ((f-i 1) simm11)
		 cond test)
    (cond-move-1 (.sym name -xcc) comment
		 name "%" xcc ((f-fmt4-cc2 1) (f-fmt4-cc1-0 2))
		 rs2 ((f-i 0) (f-fmt4-res10-6 0) rs2)
		 cond test)
    (cond-move-1 (.sym name -imm-xcc) comment
		 name "%" xcc ((f-fmt4-cc2 1) (f-fmt4-cc1-0 2))
		 simm11 ((f-i 1) simm11)
		 cond test)
    )
)
; test-* are defined in sparc.cpu.
(cond-move mova   "always" CC_A   test-always)
(cond-move movn   "never"  CC_N   test-never)
(cond-move movne  "ne"     CC_NE  test-ne)
(cond-move move   "eq"     CC_E   test-eq)
(cond-move movg   "gt"     CC_G   test-gt)
(cond-move movle  "le"     CC_LE  test-le)
(cond-move movge  "ge"     CC_GE  test-ge)
(cond-move movl   "lt"     CC_L   test-lt)
(cond-move movgu  "gtu"    CC_GU  test-gtu)
(cond-move movleu "leu"    CC_LEU test-leu)
(cond-move movcc  "geu"    CC_CC  test-geu)
(cond-move movcs  "ltu"    CC_CS  test-ltu)
(cond-move movpos "pos"    CC_POS test-pos)
(cond-move movneg "neg"    CC_NEG test-neg)
(cond-move movvc  "vc"     CC_VC  test-vc)
(cond-move movvs  "vs"     CC_VS  test-vs)

; Arithmetic binary ops

(define-pmacro (v8-addx-rename old new)
  (begin
    (dnmi new
	  (.str old " in v8 is " new " in v9, v9 page 135") ()
	  (.str new " $rs1,$rs2,$rd")
	  (emit old rs1 rs2 rd))
    (dnmi (.sym new -imm)
	  (.str old " in v8 is " new " in v9, v9 page 135") ()
	  (.str new " $rs1,$simm13,$rd")
	  (emit old rs1 simm13 rd))
    )
)
(v8-addx-rename addx addc)
(v8-addx-rename addxcc addccc)

; Binary boolean ops

(define-pmacro (s64-set-bool-flags x)
  (sequence ()
	    (set icc-z (zflag (trunc SI x)))
	    (set icc-n (nflag (trunc SI x)))
	    (set icc-c (const 0))
	    (set icc-v (const 0))
	    (set xcc-z (zflag x))
	    (set xcc-n (nflag x))
	    (set xcc-c (const 0))
	    (set xcc-v (const 0))
	    )
)

; Multiply/Divide

; FIXME: flags handling incomplete
; FIXME: div-binop is in sparccom.cpu which is included later.
;(div-binop s64-sdiv "sdiv" MACH64 SDIV div ext: (s64-set-bool-flags rd))
;(div-binop s64-udiv "udiv" MACH64 UDIV div zext: (s64-set-bool-flags rd))

; TODO
; - casa, casxa
