; Ubicom IP2K CPU description. -*- Scheme -*-
; Copyright (C) 2002, 2009, 2011 Free Software Foundation, Inc.
;
; Contributed by Red Hat Inc;
;
; This file is part of the GNU Binutils.
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
; MA 02110-1301, USA.
(define-rtl-version 0 8)
(include "simplify.inc")
; define-arch must appear first
(define-arch
(name ip2k) ; name of cpu family
(comment "Ubicom IP2000 family")
(default-alignment aligned)
(insn-lsb0? #t)
(machs ip2022 ip2022ext)
(isas ip2k)
)
; Attributes.
(define-attr
(for insn)
(type boolean)
(name EXT-SKIP-INSN)
(comment "instruction is a PAGE, LOADL, LOADH or BREAKX instruction")
)
(define-attr
(for insn)
(type boolean)
(name SKIPA)
(comment "instruction is a SKIP instruction")
)
(define-cpu
; cpu names must be distinct from the architecture name and machine names.
(name ip2kbf)
(comment "Ubicom IP2000 Family")
(endian big)
(word-bitsize 16)
)
; FIXME: It might simplify things to separate the execute process from the
; one that updates the PC.
; Instruction fields.
;
; Attributes:
; XXX: what VPE attrs
; PCREL-ADDR: pc relative value (for reloc and disassembly purposes)
; ABS-ADDR: absolute address (for reloc and disassembly purposes?)
; RESERVED: bits are not used to decode insn, must be all 0
; RELOC: there is a relocation associated with this field (experiment)
; insn-dir: bit 9
(define-normal-insn-enum insn-dir "dir enums" () DIR_ f-dir
; This bit specifies the polarity of many two-operand instructions:
; TO_W writes result to W regiser (eg. ADDC W,$fr)
; NOTTO_W writes result in general register (eg. ADDC $fr,W)
(TO_W NOTTO_W)
)
; Pseudo-RTL for DC flag calculations
; "DC" = "digit carry", ie carry between nibbles
(define-pmacro (add-dcflag a b c)
(add-cflag (sll QI a 4) (sll QI b 4) c)
)
(define-pmacro (sub-dcflag a b c)
(sub-cflag (sll QI a 4) (sll QI b 4) c)
)
; Check to see if an fr is one of IPL, SPL, DPL, ADDRL, PCL.
(define-pmacro (LregCheck isLreg fr9bit)
(sequence()
(set isLreg #x0) ;; Assume it's not an Lreg
(if (or (or (eq fr9bit #x5) (eq fr9bit #x7))
(or (eq fr9bit #x9)
(or (eq fr9bit #xd) (eq fr9bit #x11))))
(set isLreg #x1)
)
)
)
; Instructions, in order of the "Instruction Set Map" table on
; pp 19-20 of IP2022 spec V1.09
; note that in call, we push pc instead of pc + 1 because the ip2k increments
; the pc prior to execution of the instruction
(dni call "Call"
()
"call $addr16cjp"
(+ OP3_CALL addr16cjp)
(sequence ()
(c-call "push_pc_stack" pc)
(set pc (or (sll pabits 13) addr16cjp)))
()
)
(dni sb "Skip if bit set"
()
"sb $fr,$bitno"
(+ OP4_SB bitno fr)
(if (and fr (sll 1 bitno))
(skip 1))
()
)
(dni snb "Skip if bit clear"
()
"snb $fr,$bitno"
(+ OP4_SNB bitno fr)
(if (not (and fr (sll 1 bitno)))
(skip 1))
()
)
;; THIS NO LONGER EXISTS -> Now LOADL
;;(dni bank_l "Bank literal"
;; ()
;; "bank #$lit8"
;; (+ OP4_LITERAL OP4MID_BANK_L lit8)
;; (set bank lit8)
;; ()
;;)
(dni addcfr_w "Add w/carry fr,W"
()
"addc $fr,W"
(+ OP6_ADDC DIR_NOTTO_W fr)
(sequence ((QI result) (BI newcbit) (QI isLreg) (HI 16bval))
(set newcbit (add-cflag w fr cbit))
(set dcbit (add-dcflag w fr cbit))
;; If fr is an Lreg, then we have to do 16-bit arithmetic.
;; We can take advantage of the fact that by a lucky
;; coincidence, the address of register xxxH is always
;; one lower than the address of register xxxL.
(LregCheck isLreg (ifield f-reg))
(if (eq isLreg #x1)
(sequence()
(set 16bval (reg h-spr (sub (ifield f-reg) 1)))
(set 16bval (sll 16bval 8))
(set 16bval (or 16bval (and (reg h-spr (ifield f-reg)) #xFF)))
(set 16bval (addc HI 16bval w cbit))
(set (reg h-spr (ifield f-reg)) (and 16bval #xFF))
(set (reg h-spr (sub (ifield f-reg) 1))
(and (srl 16bval 8) #xFF))
(set result (reg h-spr (ifield f-reg)))
)
(set result (addc w fr cbit)) ;; else part
)
(dni addcw_fr "Add w/carry W,fr"
()
"addc W,$fr"
(+ OP6_ADDC DIR_TO_W fr)
(sequence ((QI result) (BI newcbit))
(set newcbit (add-cflag w fr cbit))
(set dcbit (add-dcflag w fr cbit))
(set result (addc w fr cbit))
(set zbit (zflag result))
(set cbit newcbit)
(set w result))
()
)
(dni incsnz_fr "Skip if fr++ not zero"
()
"incsnz $fr"
(+ OP6_INCSNZ DIR_NOTTO_W fr)
(sequence ((QI isLreg) (HI 16bval))
(LregCheck isLreg (ifield f-reg))
;; If fr is an Lreg, then we have to do 16-bit arithmetic.
;; We can take advantage of the fact that by a lucky
;; coincidence, the address of register xxxH is always
;; one lower than the address of register xxxL.
(if (eq isLreg #x1)
(sequence()
; Create the 16 bit value
(set 16bval (reg h-spr (sub (ifield f-reg) 1)))
(set 16bval (sll 16bval 8))
(set 16bval (or 16bval (and (reg h-spr (ifield f-reg)) #xFF)))
; Do 16 bit arithmetic.
(set 16bval (add HI 16bval 1))
; Separate the 16 bit values into the H and L regs
(set (reg h-spr (ifield f-reg)) (and 16bval #xFF))
(set (reg h-spr (sub (ifield f-reg) 1))
(and (srl 16bval 8) #xFF))
(set fr (reg h-spr (ifield f-reg)))
)
(set fr (add fr 1)) ; Do 8 bit arithmetic.
)
(if (not (zflag fr))
(skip 1)))
()
)
(dni incsnzw_fr "Skip if W=fr+1 not zero"
()
"incsnz W,$fr"
(+ OP6_INCSNZ DIR_TO_W fr)
(sequence ()
(set w (add fr 1))
(if (not (zflag w))
(skip 1)))
()
)
(dni decsnz_fr "Skip if fr-- not zero"
()
"decsnz $fr"
(+ OP6_DECSNZ DIR_NOTTO_W fr)
(sequence ((QI isLreg) (HI 16bval))
(LregCheck isLreg (ifield f-reg))
;; If fr is an Lreg, then we have to do 16-bit arithmetic.
;; We can take advantage of the fact that by a lucky
;; coincidence, the address of register xxxH is always
;; one lower than the address of register xxxL.
(if (eq isLreg #x1)
(sequence()
; Create the 16 bit value
(set 16bval (reg h-spr (sub (ifield f-reg) 1)))
(set 16bval (sll 16bval 8))
(set 16bval (or 16bval (and (reg h-spr (ifield f-reg)) #xFF)))
; New 16 bit instruction
(set 16bval (sub HI 16bval 1))
; Separate the 16 bit values into the H and L regs
(set (reg h-spr (ifield f-reg)) (and 16bval #xFF))
(set (reg h-spr (sub (ifield f-reg) 1))
(and (srl 16bval 8) #xFF))
(set fr (reg h-spr (ifield f-reg)))
)
; Original instruction
(set fr (sub fr 1))
)
(if (not (zflag fr))
(skip 1)))
()
)
(dni decsnzw_fr "Skip if W=fr-1 not zero"
()
"decsnz W,$fr"
(+ OP6_DECSNZ DIR_TO_W fr)
(sequence ()
(set w (sub fr 1))
(if (not (zflag w))
(skip 1)))
()
)
(dni subcw_fr "Subract w/carry W,fr"
()
"subc W,$fr"
(+ OP6_SUBC DIR_TO_W fr)
(sequence ((QI result) (BI newcbit))
(set newcbit (not (sub-cflag fr w (not cbit))))
(set dcbit (not (sub-dcflag fr w (not cbit))))
(set result (subc fr w (not cbit)))
(set zbit (zflag result))
(set cbit newcbit)
(set w result))
()
)
(dni subcfr_w "Subtract w/carry fr,W"
()
"subc $fr,W"
(+ OP6_SUBC DIR_NOTTO_W fr)
(sequence ((QI result) (BI newcbit) (QI isLreg) (HI 16bval))
(set newcbit (not (sub-cflag fr w (not cbit))))
(set dcbit (not (sub-dcflag fr w (not cbit))))
(LregCheck isLreg (ifield f-reg))
;; If fr is an Lreg, then we have to do 16-bit arithmetic.
;; We can take advantage of the fact that by a lucky
;; coincidence, the address of register xxxH is always
;; one lower than the address of register xxxL.
(if (eq isLreg #x1)
(sequence()
; Create the 16 bit value
(set 16bval (reg h-spr (sub (ifield f-reg) 1)))
(set 16bval (sll 16bval 8))
(set 16bval (or 16bval (and (reg h-spr (ifield f-reg)) #xFF)))
; New 16 bit instruction
(set 16bval (subc HI 16bval w (not cbit)))
; Separate the 16 bit values into the H and L regs
(set (reg h-spr (ifield f-reg)) (and 16bval #xFF))
(set (reg h-spr (sub (ifield f-reg) 1))
(and (srl 16bval 8) #xFF))
(set result (reg h-spr (ifield f-reg)))
)
; Original instruction
(set result (subc fr w (not cbit)))
)
;;(dni csaw_fr "Skip if W above fr"
;; ((MACH ip2022ext))
;; "csa W,$fr"
;; (+ OP6_CSAB (f-dir 1) fr)
;; (if (gt w fr)
;; (skip 1))
;; ()
;;)
;;(dni csbw_fr "Skip if W below fr"
;; ((MACH ip2022ext))
;; "csb W,$fr"
;; (+ OP6_CSAB (f-dir 0) fr)
;; (if (lt w fr)
;; (skip 1))
;; ()
;;)
(dni incsz_fr "Skip if fr++ zero"
()
"incsz $fr"
(+ OP6_INCSZ DIR_NOTTO_W fr)
(sequence ((QI isLreg) (HI 16bval))
(LregCheck isLreg (ifield f-reg))
;; If fr is an Lreg, then we have to do 16-bit arithmetic.
;; We can take advantage of the fact that by a lucky
;; coincidence, the address of register xxxH is always
;; one lower than the address of register xxxL.
(if (eq isLreg #x1)
(sequence()
; Create the 16 bit value
(set 16bval (reg h-spr (sub (ifield f-reg) 1)))
(set 16bval (sll 16bval 8))
(set 16bval (or 16bval (and (reg h-spr (ifield f-reg)) #xFF)))
; New 16 bit instruction
(set 16bval (add HI 16bval 1))
; Separate the 16 bit values into the H and L regs
(set (reg h-spr (ifield f-reg)) (and 16bval #xFF))
(set (reg h-spr (sub (ifield f-reg) 1))
(and (srl 16bval 8) #xFF))
(set fr (reg h-spr (ifield f-reg)))
)
; Original instruction
(set fr (add fr 1))
)
(if (zflag fr)
(skip 1)))
()
)
(dni rrw_fr "Rotate fr right with carry into W"
()
"rr W,$fr"
(+ OP6_RR DIR_TO_W fr)
(sequence ((QI newfr) (BI newc))
(set newc (and fr #x01))
(set newfr (or (srl fr 1) (if QI cbit #x80 #x00)))
(set cbit (if QI newc 1 0))
(set w newfr))
()
)
(dni decsz_fr "Skip if fr-- zero"
()
"decsz $fr"
(+ OP6_DECSZ DIR_NOTTO_W fr)
(sequence ((QI isLreg) (HI 16bval))
(LregCheck isLreg (ifield f-reg))
;; If fr is an Lreg, then we have to do 16-bit arithmetic.
;; We can take advantage of the fact that by a lucky
;; coincidence, the address of register xxxH is always
;; one lower than the address of register xxxL.
(if (eq isLreg #x1)
(sequence()
; Create the 16 bit value
(set 16bval (reg h-spr (sub (ifield f-reg) 1)))
(set 16bval (sll 16bval 8))
(set 16bval (or 16bval (and (reg h-spr (ifield f-reg)) #xFF)))
; New 16 bit instruction
(set 16bval (sub HI 16bval 1))
; Separate the 16 bit values into the H and L regs
(set (reg h-spr (ifield f-reg)) (and 16bval #xFF))
(set (reg h-spr (sub (ifield f-reg) 1))
(and (srl 16bval 8) #xFF))
(set fr (reg h-spr (ifield f-reg)))
)
; Original instruction
(set fr (sub fr 1))
)
(if (zflag fr)
(skip 1)))
()
)
(dni inc_fr "Increment fr"
()
"inc $fr"
(+ OP6_INC DIR_NOTTO_W fr)
(sequence ((QI isLreg) (HI 16bval))
(LregCheck isLreg (ifield f-reg))
;; If fr is an Lreg, then we have to do 16-bit arithmetic.
;; We can take advantage of the fact that by a lucky
;; coincidence, the address of register xxxH is always
;; one lower than the address of register xxxL.
(if (eq isLreg #x1)
(sequence()
; Create the 16 bit value
(set 16bval (reg h-spr (sub (ifield f-reg) 1)))
(set 16bval (sll 16bval 8))
(set 16bval (or 16bval (and (reg h-spr (ifield f-reg)) #xFF)))
; New 16 bit instruction
(set 16bval (add HI 16bval 1))
; Separate the 16 bit values into the H and L regs
(set (reg h-spr (ifield f-reg)) (and 16bval #xFF))
(set (reg h-spr (sub (ifield f-reg) 1))
(and (srl 16bval 8) #xFF))
(set fr (reg h-spr (ifield f-reg)))
)
; Original instruction
(set fr (add fr 1))
)
(set zbit (zflag fr)))
()
)
;; If fr is an Lreg, then we have to do 16-bit arithmetic.
;; We can take advantage of the fact that by a lucky
;; coincidence, the address of register xxxH is always
;; one lower than the address of register xxxL.
(if (eq isLreg #x1)
(sequence()
(set 16bval (reg h-spr (sub (ifield f-reg) 1)))
(set 16bval (sll 16bval 8))
(set 16bval (or 16bval (and (reg h-spr (ifield f-reg)) #xFF)))
(set 16bval (add HI (and w #xFF) 16bval))
(set (reg h-spr (ifield f-reg)) (and 16bval #xFF))
(set (reg h-spr (sub (ifield f-reg) 1))
(and (srl 16bval 8) #xFF))
(set result (reg h-spr (ifield f-reg)))
)
(set result (addc w fr 0)) ;; else part
)
(set zbit (zflag result))
(set fr result))
()
)
(dni addw_fr "Add W,fr"
()
"add W,$fr"
(+ OP6_ADD DIR_TO_W fr)
(sequence ((QI result))
(set cbit (add-cflag w fr 0))
(set dcbit (add-dcflag w fr 0))
(set result (addc w fr 0))
(set zbit (zflag result))
(set w result))
()
)
(dni dec_fr "Decrement fr"
()
"dec $fr"
(+ OP6_DEC DIR_NOTTO_W fr)
(sequence ((QI isLreg) (HI 16bval))
(LregCheck isLreg (ifield f-reg))
;; If fr is an Lreg, then we have to do 16-bit arithmetic.
;; We can take advantage of the fact that by a lucky
;; coincidence, the address of register xxxH is always
;; one lower than the address of register xxxL.
(if (eq isLreg #x1)
(sequence()
; Create the 16 bit value
(set 16bval (reg h-spr (sub (ifield f-reg) 1)))
(set 16bval (sll 16bval 8))
(set 16bval (or 16bval (and (reg h-spr (ifield f-reg)) #xFF)))
; New 16 bit instruction
(set 16bval (sub HI 16bval 1))
; Separate the 16 bit values into the H and L regs
(set (reg h-spr (ifield f-reg)) (and 16bval #xFF))
(set (reg h-spr (sub (ifield f-reg) 1))
(and (srl 16bval 8) #xFF))
(set fr (reg h-spr (ifield f-reg)))
)
; Original instruction
(set fr (sub fr 1))
)
(set zbit (zflag fr)))
()
)
(dni subfr_w "Sub fr,W"
()
"sub $fr,W"
(+ OP6_SUB DIR_NOTTO_W fr)
(sequence ((QI result) (QI isLreg) (HI 16bval))
(set cbit (not (sub-cflag fr w 0)))
(set dcbit (not (sub-dcflag fr w 0)))
(LregCheck isLreg (ifield f-reg))
;; If fr is an Lreg, then we have to do 16-bit arithmetic.
;; We can take advantage of the fact that by a lucky
;; coincidence, the address of register xxxH is always
;; one lower than the address of register xxxL.
(if (eq isLreg #x1)
(sequence()
; Create the 16 bit value
(set 16bval (reg h-spr (sub (ifield f-reg) 1)))
(set 16bval (sll 16bval 8))
(set 16bval (or 16bval (and (reg h-spr (ifield f-reg)) #xFF)))
; New 16 bit instruction
(set 16bval (sub HI 16bval (and w #xFF)))
; Separate the 16 bit values into the H and L regs
(set (reg h-spr (ifield f-reg)) (and 16bval #xFF))
(set (reg h-spr (sub (ifield f-reg) 1))
(and (srl 16bval 8) #xFF))
(set result (reg h-spr (ifield f-reg)))
)
; Original instruction
(set result (subc fr w 0))
)
(set zbit (zflag result))
(set fr result))
()
)
(dni subw_fr "Sub W,fr"
()
"sub W,$fr"
(+ OP6_SUB DIR_TO_W fr)
(sequence ((QI result))
(set cbit (not (sub-cflag fr w 0)))
(set dcbit (not (sub-dcflag fr w 0)))
(set result (subc fr w 0))
(set zbit (zflag result))
(set w result))
()
)