From 381cd1b3697dfaf4fccf8c3e0636918e70e96be1 Mon Sep 17 00:00:00 2001 From: Ben Elliston Date: Wed, 17 Jul 2002 14:56:53 +0000 Subject: [PATCH] * cpu/ip2k.cpu: New file. * cpu/ip2k.opc: Likewise. --- ChangeLog | 10 + NEWS | 2 + cpu/ip2k.cpu | 1463 ++++++++++++++++++++++++++++++++++++++++++++++++++ cpu/ip2k.opc | 682 +++++++++++++++++++++++ 4 files changed, 2157 insertions(+) create mode 100644 cpu/ip2k.cpu create mode 100644 cpu/ip2k.opc diff --git a/ChangeLog b/ChangeLog index 9b415f5..c819d81 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2002-07-17 Frank Ch. Eigler + Ben Elliston + John Healy + Jeff Johnston + Alan Lehotsky + Ubicom Inc. + + * cpu/ip2k.cpu: New file. + * cpu/ip2k.opc: Likewise. + 2002-07-01 Hans-Peter Nilsson * utils-gen.scm (-gen-extract-word): Handle lsb0?. diff --git a/NEWS b/NEWS index 9a42ea8..a72497c 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,5 @@ +Support for the Ubicom IP2K processor contributed by Red Hat and Ubicom, Inc. + Support for the Fujitsu FRV architecture added by Red Hat. Models for FR400 and FR500 included. diff --git a/cpu/ip2k.cpu b/cpu/ip2k.cpu new file mode 100644 index 0000000..769d1b0 --- /dev/null +++ b/cpu/ip2k.cpu @@ -0,0 +1,1463 @@ +; Ubicom IP2K CPU description. -*- Scheme -*- +; Copyright (C) 2000, 2001 Red Hat, Inc. +; Copyright (C) 2002 Free Software Foundation, Inc. +; This file is part of CGEN. +; See file COPYING.CGEN for details. + +(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") +) + +; Instruction set parameters. + +(define-isa + (name ip2k) + (comment "Ubicom IP2000 ISA") + + (default-insn-word-bitsize 16) + (default-insn-bitsize 16) + (base-insn-bitsize 16) +) + +; Cpu family definitions. + + +(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) +) + +(define-mach + (name ip2022) + (comment "Ubicom IP2022") + (cpu ip2kbf) +) + +(define-mach + (name ip2022ext) + (comment "Ubicom IP2022 extended") + (cpu ip2kbf) +) + + +; Model descriptions. + +(define-model + (name ip2k) (comment "VPE 2xxx") (attrs) + (mach ip2022ext) + + (unit u-exec "Execution Unit" () + 1 1 ; issue done + () ; state + () ; inputs + () ; outputs + () ; profile action (default) + ) +) + + +; 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) + + +(dnf f-imm8 "imm8" () 7 8) +(dnf f-reg "reg" (ABS-ADDR) 8 9) +(dnf f-addr16cjp "addr16cjp" (ABS-ADDR) 12 13) +(dnf f-dir "dir" () 9 1) +(dnf f-bitno "bit number" () 11 3) +(dnf f-op3 "op3" () 15 3) +(dnf f-op4 "op4" () 15 4) +(dnf f-op4mid "op4mid" () 11 4) +(dnf f-op6 "op6" () 15 6) +(dnf f-op8 "op8" () 15 8) +(dnf f-op6-10low "op6-10low" () 9 10) +(dnf f-op6-7low "op6-7low" () 9 7) +(dnf f-reti3 "reti3" () 2 3) +(dnf f-skipb "sb/snb" (ABS-ADDR) 12 1) +(dnf f-page3 "page3" () 2 3) +;(define-ifield (name f-page3) (comment "page3") (attrs) (start 2) (length 3) +; (encode (value pc) (srl WI value 13)) +; (decode (value pc) (sll WI value 13)) +;) +; To fix the page/call asymmetry +;(define-ifield (name f-page3) (comment "page3") (attrs) (start 2) (length 3) +; (encode (value pc) (srl WI value 13)) +; (decode (value pc) (sll WI value 13)) +;) + + + +; Enums. + +; insn-op6: bits 15-10 +(define-normal-insn-enum insn-op6 "op6 enums" () OP6_ f-op6 + (OTHER1 OTHER2 SUB DEC OR AND XOR ADD + TEST NOT INC DECSZ RR RL SWAP INCSZ + CSE POP SUBC DECSNZ MULU MULS INCSNZ ADDC + - - - - - - - - + - - - - - - - - + - - - - - - - - + - - - - - - - - + - - - - - - - - + ) +) + +; 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) +) + + +; insn-op4: bits 15-12 +(define-normal-insn-enum insn-op4 "op4 enums" () OP4_ f-op4 + (- - - - - - - LITERAL + CLRB SETB SNB SB - - - - + ) +) + +; insn-op4mid: bits 11-8 +; used for f-op4=LITERAL +(define-normal-insn-enum insn-op4mid "op4mid enums" () OP4MID_ f-op4mid + (LOADH_L LOADL_L MULU_L MULS_L PUSH_L - CSNE_L CSE_L + RETW_L CMP_L SUB_L ADD_L MOV_L OR_L AND_L XOR_L) +) + +; insn-op3: bits 15-13 +(define-normal-insn-enum insn-op3 "op3 enums" () OP3_ f-op3 + (- - - - - - CALL JMP) +) + + + +; Hardware pieces. + +; Bank-relative general purpose registers + +; (define-pmacro (build-reg-name n) (.splice (.str "$" n) n)) + +(define-keyword + (name register-names) + (print-name h-registers) + (prefix "") + (values + ; These are the "Special Purpose Registers" that are not reserved + ("ADDRSEL" #x2) ("ADDRX" #x3) + ("IPH" #x4) ("IPL" #x5) ("SPH" #x6) ("SPL" #x7) + ("PCH" #x8) ("PCL" #x9) ("WREG" #xA) ("STATUS" #xB) + ("DPH" #xC) ("DPL" #xD) ("SPDREG" #xE) ("MULH" #xF) + ("ADDRH" #x10) ("ADDRL" #x11) ("DATAH" #x12) ("DATAL" #x13) + ("INTVECH" #x14) ("INTVECL" #x15) ("INTSPD" #x16) ("INTF" #x17) + ("INTE" #x18) ("INTED" #x19) ("FCFG" #x1A) ("TCTRL" #x1B) + ("XCFG" #x1C) ("EMCFG" #x1D) ("IPCH" #x1E) ("IPCL" #x1F) + ("RAIN" #x20) ("RAOUT" #x21) ("RADIR" #x22) ("LFSRH" #x23) + ("RBIN" #x24) ("RBOUT" #x25) ("RBDIR" #x26) ("LFSRL" #x27) + ("RCIN" #x28) ("RCOUT" #x29) ("RCDIR" #x2A) ("LFSRA" #x2B) + ("RDIN" #x2C) ("RDOUT" #x2D) ("RDDIR" #x2E) + ("REIN" #x30) ("REOUT" #x31) ("REDIR" #x32) + ("RFIN" #x34) ("RFOUT" #x35) ("RFDIR" #x36) + ("RGOUT" #x39) ("RGDIR" #x3A) + ("RTTMR" #x40) ("RTCFG" #x41) ("T0TMR" #x42) ("T0CFG" #x43) + ("T1CNTH" #x44) ("T1CNTL" #x45) ("T1CAP1H" #x46) ("T1CAP1L" #x47) + ("T1CAP2H" #x48) ("T1CMP2H" #x48) ("T1CAP2L" #x49) ("T1CMP2L" #x49) ; note aliases + ("T1CMP1H" #x4A) ("T1CMP1L" #x4B) + ("T1CFG1H" #x4C) ("T1CFG1L" #x4D) ("T1CFG2H" #x4E) ("T1CFG2L" #x4F) + ("ADCH" #x50) ("ADCL" #x51) ("ADCCFG" #x52) ("ADCTMR" #x53) + ("T2CNTH" #x54) ("T2CNTL" #x55) ("T2CAP1H" #x56) ("T2CAP1L" #x57) + ("T2CAP2H" #x58) ("T2CMP2H" #x58) ("T2CAP2L" #x59) ("T2CMP2L" #x59) ; note aliases + ("T2CMP1H" #x5A) ("T2CMP1L" #x5B) + ("T2CFG1H" #x5C) ("T2CFG1L" #x5D) ("T2CFG2H" #x5E) ("T2CFG2L" #x5F) + ("S1TMRH" #x60) ("S1TMRL" #x61) ("S1TBUFH" #x62) ("S1TBUFL" #x63) + ("S1TCFG" #x64) ("S1RCNT" #x65) ("S1RBUFH" #x66) ("S1RBUFL" #x67) + ("S1RCFG" #x68) ("S1RSYNC" #x69) ("S1INTF" #x6A) ("S1INTE" #x6B) + ("S1MODE" #x6C) ("S1SMASK" #x6D) ("PSPCFG" #x6E) ("CMPCFG" #x6F) + ("S2TMRH" #x70) ("S2TMRL" #x71) ("S2TBUFH" #x72) ("S2TBUFL" #x73) + ("S2TCFG" #x74) ("S2RCNT" #x75) ("S2RBUFH" #x76) ("S2RBUFL" #x77) + ("S2RCFG" #x78) ("S2RSYNC" #x79) ("S2INTF" #x7A) ("S2INTE" #x7B) + ("S2MODE" #x7C) ("S2SMASK" #x7D) ("CALLH" #x7E) ("CALLL" #x7F)) + ) + +(define-hardware + (name h-spr) + (comment "special-purpose registers") + (type register QI (128)) + (get (index) (c-call QI "get_spr" index )) + (set (index newval) (c-call VOID "set_spr" index newval )) +) + + +;;(define-hardware +;; (name h-gpr-global) +;; (comment "gpr registers - global") +;; (type register QI (128)) +;;) + +; The general register + +(define-hardware + (name h-registers) + (comment "all addressable registers") + (attrs VIRTUAL) + (type register QI (512)) + (get (index) (c-call QI "get_h_registers" index )) + (set (index newval) (c-call VOID "set_h_registers" index newval )) +) + +; The hardware stack. +; Use {push,pop}_pc_stack c-calls to operate on this hardware element. + +(define-hardware + (name h-stack) + (comment "hardware stack") + (type register UHI (16)) +) + +(dsh h-pabits "page bits" () (register QI)) +(dsh h-zbit "zero bit" () (register BI)) +(dsh h-cbit "carry bit" () (register BI)) +(dsh h-dcbit "digit-carry bit" () (register BI)) +(dnh h-pc "program counter" (PC PROFILE) (pc) () () ()) + + +; Operands + +(define-operand (name addr16cjp) (comment "13-bit address") (attrs) + (type h-uint) (index f-addr16cjp) (handlers (parse "addr16_cjp") (print "dollarhex_cj"))) ; overload lit8 printer +(define-operand (name fr) (comment "register") (attrs) + (type h-registers) (index f-reg) (handlers (parse "fr") (print "fr"))) +(define-operand (name lit8) (comment "8-bit signed literal") (attrs) + (type h-sint) (index f-imm8) (handlers (parse "lit8") (print "dollarhex8"))) +(define-operand (name bitno) (comment "bit number") (attrs) + (type h-uint) (index f-bitno) (handlers (parse "bit3")(print "decimal"))) +(define-operand (name addr16p) (comment "page number") (attrs) + (type h-uint) (index f-page3) (handlers (parse "addr16_cjp") (print "dollarhex_p"))) +(define-operand (name addr16h) (comment "high 8 bits of address") (attrs) + (type h-uint) (index f-imm8) (handlers (parse "addr16") (print "dollarhex_addr16h"))) +(define-operand (name addr16l) (comment "low 8 bits of address") (attrs) + (type h-uint) (index f-imm8) (handlers (parse "addr16") (print "dollarhex_addr16l"))) +(define-operand (name reti3) (comment "reti flags") (attrs) + (type h-uint) (index f-reti3) (handlers (print "dollarhex"))) +(dnop pabits "page bits" () h-pabits f-nil) +(dnop zbit "zero bit" () h-zbit f-nil) +(dnop cbit "carry bit" () h-cbit f-nil) +(dnop dcbit "digit carry bit" () h-dcbit f-nil) +;;(dnop bank "bank register" () h-bank-no f-nil) + +(define-pmacro w (reg h-spr #x0A)) +(define-pmacro mulh (reg h-spr #x0F)) +(define-pmacro dph (reg h-spr #x0C)) +(define-pmacro dpl (reg h-spr #x0D)) +(define-pmacro sph (reg h-spr #x06)) +(define-pmacro spl (reg h-spr #x07)) +(define-pmacro iph (reg h-spr #x04)) +(define-pmacro ipl (reg h-spr #x05)) +(define-pmacro addrh (reg h-spr #x10)) +(define-pmacro addrl (reg h-spr #x11)) + + + +; 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 + +(dni jmp "Jump" + () + "jmp $addr16cjp" + (+ OP3_JMP addr16cjp) + (set pc (or (sll pabits 13) addr16cjp)) + () +) + +; 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)) + () +) + +(dni setb "Set bit" + () + "setb $fr,$bitno" + (+ OP4_SETB bitno fr) + (set fr (or fr (sll 1 bitno))) + () +) + +(dni clrb "Clear bit" + () + "clrb $fr,$bitno" + (+ OP4_CLRB bitno fr) + (set fr (and fr (inv (sll 1 bitno)))) + () +) + +(dni xorw_l "XOR W,literal" + () + "xor W,#$lit8" + (+ OP4_LITERAL OP4MID_XOR_L lit8) + (sequence () + (set w (xor w lit8)) + (set zbit (zflag w))) + () +) + +(dni andw_l "AND W,literal" + () + "and W,#$lit8" + (+ OP4_LITERAL OP4MID_AND_L lit8) + (sequence () + (set w (and w lit8)) + (set zbit (zflag w))) + () +) + +(dni orw_l "OR W,literal" + () + "or W,#$lit8" + (+ OP4_LITERAL OP4MID_OR_L lit8) + (sequence () + (set w (or w lit8)) + (set zbit (zflag w))) + () +) + +(dni addw_l "ADD W,literal" + () + "add W,#$lit8" + (+ OP4_LITERAL OP4MID_ADD_L lit8) + (sequence () + (set cbit (add-cflag w lit8 0)) + (set dcbit (add-dcflag w lit8 0)) + (set w (add w lit8)) + (set zbit (zflag w))) + () +) + +(dni subw_l "SUB W,literal" + () + "sub W,#$lit8" + (+ OP4_LITERAL OP4MID_SUB_L lit8) + (sequence () + (set cbit (not (sub-cflag lit8 w 0))) + (set dcbit (not (sub-dcflag lit8 w 0))) + (set zbit (zflag (sub w lit8))) + (set w (sub lit8 w))) + () +) + +(dni cmpw_l "CMP W,literal" + () + "cmp W,#$lit8" + (+ OP4_LITERAL OP4MID_CMP_L lit8) + (sequence () + (set cbit (not (sub-cflag lit8 w 0))) + (set dcbit (not (sub-dcflag lit8 w 0))) + (set zbit (zflag (sub w lit8)))) + () +) + +(dni retw_l "RETW literal" + () + "retw #$lit8" + (+ OP4_LITERAL OP4MID_RETW_L lit8) + (sequence ((USI new_pc)) + (set w lit8) + (set new_pc (c-call UHI "pop_pc_stack")) + (set pabits (srl new_pc 13)) + (set pc new_pc)) + () +) + +(dni csew_l "CSE W,literal" + () + "cse W,#$lit8" + (+ OP4_LITERAL OP4MID_CSE_L lit8) + (if (eq w lit8) + (skip 1)) + () +) + +(dni csnew_l "CSNE W,literal" + () + "csne W,#$lit8" + (+ OP4_LITERAL OP4MID_CSNE_L lit8) + (if (not (eq w lit8)) + (skip 1)) + () +) + +(dni push_l "Push #lit8" + () + "push #$lit8" + (+ OP4_LITERAL OP4MID_PUSH_L lit8) + (sequence () + (c-call "push" lit8) + (c-call VOID "adjuststackptr" (const -1)) + + ) + () +) + +(dni mulsw_l "Multiply W,literal (signed)" + () + "muls W,#$lit8" + (+ OP4_LITERAL OP4MID_MULS_L lit8) + (sequence ((SI tmp)) + (set tmp (mul (ext SI w) (ext SI (and UQI #xff lit8)))) + (set w (and tmp #xFF)) + (set mulh (srl tmp 8))) + () +) + +(dni muluw_l "Multiply W,literal (unsigned)" + () + "mulu W,#$lit8" + (+ OP4_LITERAL OP4MID_MULU_L lit8) + (sequence ((USI tmp)) + (set tmp (and #xFFFF (mul (zext USI w) (zext USI lit8)))) + (set w (and tmp #xFF)) + (set mulh (srl tmp 8))) + () +) + +(dni loadl_l "LoadL literal" + (EXT-SKIP-INSN) + "loadl #$lit8" + (+ OP4_LITERAL OP4MID_LOADL_L lit8) + (set dpl (and lit8 #x00FF)) + () +) + +(dni loadh_l "LoadH literal" + (EXT-SKIP-INSN) + "loadh #$lit8" + (+ OP4_LITERAL OP4MID_LOADH_L lit8) + (set dph (and lit8 #x00FF)) + () +) + +(dni loadl_a "LoadL addr16l" + (EXT-SKIP-INSN) + "loadl $addr16l" + (+ OP4_LITERAL OP4MID_LOADL_L addr16l) + (set dpl (and addr16l #x00FF)) + () +) + +(dni loadh_a "LoadH addr16h" + (EXT-SKIP-INSN) + "loadh $addr16h" + (+ OP4_LITERAL OP4MID_LOADH_L addr16h) + (set dph (and addr16l #x0FF00)) + () +) + +;; 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 + ) + + (set zbit (zflag result)) + (set cbit newcbit) + (set fr result)) + () +) + +(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 mulsw_fr "Multiply W,fr (signed)" + () + "muls W,$fr" + (+ OP6_MULS DIR_TO_W fr) + (sequence ((SI tmp)) + (set tmp (mul (ext SI w) (ext SI fr))) + (set w (and tmp #xFF)) + (set mulh (srl tmp 8))) + () +) + +(dni muluw_fr "Multiply W,fr (unsigned)" + () + "mulu W,$fr" + (+ OP6_MULU DIR_TO_W fr) + (sequence ((USI tmp)) + (set tmp (and #xFFFF (mul (zext USI w) (zext USI fr)))) + (set w (and tmp #xFF)) + (set mulh (srl tmp 8))) + () +) + +(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))) + ) + + + (set zbit (zflag result)) + (set cbit newcbit) + (set fr result)) + () +) + + +(dni pop_fr "Pop fr" + () + "pop $fr" + (+ OP6_POP (f-dir 1) fr) + (sequence() + (set fr (c-call QI "pop")) + (c-call VOID "adjuststackptr" (const 1)) + ) + () +) + +(dni push_fr "Push fr" + () + "push $fr" + (+ OP6_POP (f-dir 0) fr) + (sequence() + (c-call "push" fr) + (c-call VOID "adjuststackptr" (const -1)) + ) + () +) + +(dni csew_fr "Skip if equal W,fr" + () + "cse W,$fr" + (+ OP6_CSE (f-dir 1) fr) + (if (eq w fr) + (skip 1)) + () +) + +(dni csnew_fr "Skip if not-equal W,fr" + () + "csne W,$fr" + (+ OP6_CSE (f-dir 0) fr) + (if (not (eq w fr)) + (skip 1)) + () +) + +;;(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 incszw_fr "Skip if W=fr+1 zero" + () + "incsz W,$fr" + (+ OP6_INCSZ DIR_TO_W fr) + (sequence () + (set w (add fr 1)) + (if (zflag w) + (skip 1))) + () +) + +(dni swap_fr "Swap fr nibbles" + () + "swap $fr" + (+ OP6_SWAP DIR_NOTTO_W fr) + (set fr (or (and (sll fr 4) #xf0) + (and (srl fr 4) #x0f))) + () +) + +(dni swapw_fr "Swap fr nibbles into W" + () + "swap W,$fr" + (+ OP6_SWAP DIR_TO_W fr) + (set w (or (and (sll fr 4) #xf0) + (and (srl fr 4) #x0f))) + () +) + +(dni rl_fr "Rotate fr left with carry" + () + "rl $fr" + (+ OP6_RL DIR_NOTTO_W fr) + (sequence ((QI newfr) (BI newc)) + (set newc (and fr #x80)) + (set newfr (or (sll fr 1) (if QI cbit 1 0))) + (set cbit (if QI newc 1 0)) + (set fr newfr)) + () +) + +(dni rlw_fr "Rotate fr left with carry into W" + () + "rl W,$fr" + (+ OP6_RL DIR_TO_W fr) + (sequence ((QI newfr) (BI newc)) + (set newc (and fr #x80)) + (set newfr (or (sll fr 1) (if QI cbit 1 0))) + (set cbit (if QI newc 1 0)) + (set w newfr)) + () +) + +(dni rr_fr "Rotate fr right with carry" + () + "rr $fr" + (+ OP6_RR DIR_NOTTO_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 fr newfr)) + () +) + +(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 decszw_fr "Skip if W=fr-1 zero" + () + "decsz W,$fr" + (+ OP6_DECSZ DIR_TO_W fr) + (sequence () + (set w (sub fr 1)) + (if (zflag w) + (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))) + () +) + +(dni incw_fr "Increment fr into w" + () + "inc W,$fr" + (+ OP6_INC DIR_TO_W fr) + (sequence () + (set w (add fr 1)) + (set zbit (zflag w))) + () +) + +(dni not_fr "Invert fr" + () + "not $fr" + (+ OP6_NOT DIR_NOTTO_W fr) + (sequence () + (set fr (inv fr)) + (set zbit (zflag fr))) + () +) + +(dni notw_fr "Invert fr into w" + () + "not W,$fr" + (+ OP6_NOT DIR_TO_W fr) + (sequence () + (set w (inv fr)) + (set zbit (zflag w))) + () +) + +(dni test_fr "Test fr" + () + "test $fr" + (+ OP6_TEST DIR_NOTTO_W fr) + (sequence () + (set zbit (zflag fr))) + () +) + +(dni movw_l "MOV W,literal" + () + "mov W,#$lit8" + (+ OP4_LITERAL OP4MID_MOV_L lit8) + (set w lit8) + () +) + +(dni movfr_w "Move/test w into fr" + () + "mov $fr,W" + (+ OP6_OTHER1 DIR_NOTTO_W fr) + (set fr w) + () +) + +(dni movw_fr "Move/test fr into w" + () + "mov W,$fr" + (+ OP6_TEST DIR_TO_W fr) + (sequence () + (set w fr) + (set zbit (zflag w))) + () +) + + +(dni addfr_w "Add fr,W" + () + "add $fr,W" + (+ OP6_ADD DIR_NOTTO_W fr) + (sequence ((QI result) (QI isLreg) (HI 16bval)) + (set cbit (add-cflag w fr 0)) + (set dcbit (add-dcflag w fr 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() + (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 xorfr_w "XOR fr,W" + () + "xor $fr,W" + (+ OP6_XOR DIR_NOTTO_W fr) + (sequence () + (set fr (xor w fr)) + (set zbit (zflag fr))) + () +) + +(dni xorw_fr "XOR W,fr" + () + "xor W,$fr" + (+ OP6_XOR DIR_TO_W fr) + (sequence () + (set w (xor fr w)) + (set zbit (zflag w))) + () +) + +(dni andfr_w "AND fr,W" + () + "and $fr,W" + (+ OP6_AND DIR_NOTTO_W fr) + (sequence () + (set fr (and w fr)) + (set zbit (zflag fr))) + () +) + +(dni andw_fr "AND W,fr" + () + "and W,$fr" + (+ OP6_AND DIR_TO_W fr) + (sequence () + (set w (and fr w)) + (set zbit (zflag w))) + () +) + +(dni orfr_w "OR fr,W" + () + "or $fr,W" + (+ OP6_OR DIR_NOTTO_W fr) + (sequence () + (set fr (or w fr)) + (set zbit (zflag fr))) + () +) + +(dni orw_fr "OR W,fr" + () + "or W,$fr" + (+ OP6_OR DIR_TO_W fr) + (sequence () + (set w (or fr w)) + (set zbit (zflag w))) + () +) + +(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 decw_fr "Decrement fr into w" + () + "dec W,$fr" + (+ OP6_DEC DIR_TO_W fr) + (sequence () + (set w (sub fr 1)) + (set zbit (zflag w))) + () +) + +(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)) + () +) + +(dni clr_fr "Clear fr" + () + "clr $fr" + (+ OP6_OTHER2 (f-dir 1) fr) + (sequence () + (set fr 0) + (set zbit (zflag fr))) + () +) + +(dni cmpw_fr "CMP W,fr" + () + "cmp W,$fr" + (+ OP6_OTHER2 (f-dir 0) fr) + (sequence () + (set cbit (not (sub-cflag fr w 0))) + (set dcbit (not (sub-dcflag fr w 0))) + (set zbit (zflag (sub w fr)))) + () +) + +(dni speed "Set speed" + () + "speed #$lit8" + (+ (f-op8 1) lit8) + (set (reg h-registers #x0E) lit8) + () +) + +(dni ireadi "Insn memory read with increment" + () + "ireadi" + (+ OP6_OTHER1 (f-op6-10low #x1D)) + (c-call "do_insn_read") + () +) + +(dni iwritei "Insn memory write with increment" + () + "iwritei" + (+ OP6_OTHER1 (f-op6-10low #x1C)) + (c-call "do_insn_write") + () +) + +(dni fread "Flash read" + () + "fread" + (+ OP6_OTHER1 (f-op6-10low #x1B)) + (c-call "do_flash_read") + () +) + +(dni fwrite "Flash write" + () + "fwrite" + (+ OP6_OTHER1 (f-op6-10low #x1A)) + (c-call "do_flash_write") + () +) + +(dni iread "Insn memory read" + () + "iread" + (+ OP6_OTHER1 (f-op6-10low #x19)) + (c-call "do_insn_read") + () +) + +(dni iwrite "Insn memory write" + () + "iwrite" + (+ OP6_OTHER1 (f-op6-10low #x18)) + (c-call "do_insn_write") + () +) + +(dni page "Set insn page" + (EXT-SKIP-INSN) + ;"page $page3" + "page $addr16p" + ;(+ OP6_OTHER1 (f-op6-7low #x2) page3) + ;(set pabits (srl page3 13)) + (+ OP6_OTHER1 (f-op6-7low #x2) addr16p) + (set pabits addr16p) + () +) + +(dni system "System call" + () + "system" + (+ OP6_OTHER1 (f-op6-10low #xff)) + (c-call "do_system") + () +) + +(dni reti "Return from interrupt" + () + "reti #$reti3" + (+ OP6_OTHER1 (f-op6-7low #x1) reti3) + (c-call "do_reti" reti3) + () +) + +(dni ret "Return" + () + "ret" + (+ OP6_OTHER1 (f-op6-10low #x07)) + (sequence ((USI new_pc)) + (set new_pc (c-call UHI "pop_pc_stack")) + (set pabits (srl new_pc 13)) + (set pc new_pc)) + () +) + +(dni int "Software interrupt" + () + "int" + (+ OP6_OTHER1 (f-op6-10low #x6)) + (nop) + () +) + +(dni breakx "Breakpoint with extended skip" + (EXT-SKIP-INSN) + "breakx" + (+ OP6_OTHER1 (f-op6-10low #x5)) + (c-call "do_break" pc) + () +) + +(dni cwdt "Clear watchdog timer" + () + "cwdt" + (+ OP6_OTHER1 (f-op6-10low #x4)) + (c-call "do_clear_wdt") + () +) + +(dni ferase "Flash erase" + () + "ferase" + (+ OP6_OTHER1 (f-op6-10low #x3)) + (c-call "do_flash_erase") + () +) + +(dni retnp "Return, no page" + () + "retnp" + (+ OP6_OTHER1 (f-op6-10low #x2)) + (sequence ((USI new_pc)) + (set new_pc (c-call UHI "pop_pc_stack")) + (set pc new_pc)) + () +) + +(dni break "Breakpoint" + () + "break" + (+ OP6_OTHER1 (f-op6-10low #x1)) + (c-call "do_break" pc) + () +) + +(dni nop "No operation" + () + "nop" + (+ OP6_OTHER1 (f-op6-10low #x0)) + (nop) + () +) + + +; Macro instructions +(dnmi sc "Skip on carry" + () + "sc" + (emit sb (bitno 0) (fr #xB)) ; sb status.0 +) + +(dnmi snc "Skip on no carry" + () + "snc" + (emit snb (bitno 0) (fr #xB)) ; snb status.0 +) + +(dnmi sz "Skip on zero" + () + "sz" + (emit sb (bitno 2) (fr #xB)) ; sb status.2 +) + +(dnmi snz "Skip on no zero" + () + "snz" + (emit snb (bitno 2) (fr #xB)) ; snb status.2 +) + +(dnmi skip "Skip always" + (SKIPA) + "skip" + (emit snb (bitno 0) (fr 9)) ; snb pcl.0 | (pcl&1)<<12 +) + +(dnmi skipb "Skip always" + (SKIPA) + "skip" + (emit sb (bitno 0) (fr 9)) ; sb pcl.0 | (pcl&1)<<12 +) + diff --git a/cpu/ip2k.opc b/cpu/ip2k.opc new file mode 100644 index 0000000..5d64c17 --- /dev/null +++ b/cpu/ip2k.opc @@ -0,0 +1,682 @@ +/* IP2K opcode support. -*- C -*- + Copyright (C) 2000 Red Hat, Inc. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of CGEN. */ + +/* + Each section is delimited with start and end markers. + + -opc.h additions use: "-- opc.h" + -opc.c additions use: "-- opc.c" + -asm.c additions use: "-- asm.c" + -dis.c additions use: "-- dis.c" + -ibd.h additions use: "-- ibd.h" +*/ + +/* -- opc.h */ + +/* Check applicability of instructions against machines. */ +#define CGEN_VALIDATE_INSN_SUPPORTED + +/* Allows reason codes to be output when assembler errors occur. */ +#define CGEN_VERBOSE_ASSEMBLER_ERRORS + +/* Override disassembly hashing - there are variable bits in the top + byte of these instructions. */ +#define CGEN_DIS_HASH_SIZE 8 +#define CGEN_DIS_HASH(buf,value) (((* (unsigned char*) (buf)) >> 5) % CGEN_DIS_HASH_SIZE) + +#define CGEN_ASM_HASH_SIZE 127 +#define CGEN_ASM_HASH(insn) ip2k_asm_hash(insn) + +extern unsigned int ip2k_asm_hash (const char *insn); + + +/* Special check to ensure that instruction exists for given machine. */ +static int +ip2k_cgen_insn_supported (cd, insn) + CGEN_CPU_DESC cd; + CGEN_INSN *insn; +{ + int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH); + + /* No mach attribute? Assume it's supported for all machs. */ + if (machs == 0) + return 1; + + return ((machs & cd->machs) != 0); +} + + +/* -- opc.c */ + +/* A better hash function for instruction mnemonics. */ +unsigned int +ip2k_asm_hash (insn) + const char* insn; +{ + unsigned int hash; + const char* m = insn; + + for (hash = 0; *m && !isspace(*m); m++) + hash = (hash * 23) ^ (0x1F & tolower(*m)); + + /* printf ("%s %d\n", insn, (hash % CGEN_ASM_HASH_SIZE)); */ + + return hash % CGEN_ASM_HASH_SIZE; +} + + + + +/* -- asm.c */ + +static const char * +parse_fr (cd, strp, opindex, valuep) + CGEN_CPU_DESC cd; + const char **strp; + int opindex; + long *valuep; +{ + const char *errmsg; + char *old_strp; + char *afteroffset; + enum cgen_parse_operand_result result_type; + bfd_vma value; + extern CGEN_KEYWORD ip2k_cgen_opval_register_names; + long tempvalue; + + old_strp = *strp; + afteroffset = NULL; + + + /* Check here to see if you're about to try parsing a w as the first arg */ + /* and return an error if you are. */ + if ( (strncmp(*strp,"w",1)==0) || (strncmp(*strp,"W",1)==0) ) + { + (*strp)++; + + if ( (strncmp(*strp,",",1)==0) || isspace(**strp) ) + { + /* We've been passed a w. Return with an error message so that */ + /* cgen will try the next parsing option. */ + errmsg = _("W keyword invalid in FR operand slot."); + return errmsg; + } + *strp = old_strp; + } + + + /* Attempt parse as register keyword. */ + /* old_strp = *strp; */ + + errmsg = cgen_parse_keyword (cd, strp, & ip2k_cgen_opval_register_names, valuep); + if ( *strp != NULL ) + if (errmsg == NULL) + return errmsg; + + /* Attempt to parse for "(IP)" */ + afteroffset = strstr(*strp,"(IP)"); + + if ( afteroffset == NULL) + { + /* Make sure it's not in lower case */ + afteroffset = strstr(*strp,"(ip)"); + } + + if ( afteroffset != NULL ) + { + if ( afteroffset != *strp ) + { + /* Invalid offset present.*/ + errmsg = _("offset(IP) is not a valid form"); + return errmsg; + } + else + { + *strp += 4; + *valuep = 0; + errmsg = NULL; + return errmsg; + } + } + + /* Attempt to parse for DP. ex: mov w, offset(DP) */ + /* mov offset(DP),w */ + + /* Try parsing it as an address and see what comes back */ + + afteroffset = strstr(*strp,"(DP)"); + + if ( afteroffset == NULL) + { + /* Maybe it's in lower case */ + afteroffset = strstr(*strp,"(dp)"); + } + + if ( afteroffset != NULL ) + { + if ( afteroffset == *strp ) + { + /* No offset present. Use 0 by default. */ + tempvalue = 0; + errmsg = NULL; + } + else + { + errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IP2K_FR_OFFSET, + & result_type, & tempvalue); + } + + if (errmsg == NULL) + { + if ( (tempvalue >= 0) && (tempvalue <= 127) ) + { + /* Value is ok. Fix up the first 2 bits and return */ + *valuep = 0x0100 | tempvalue; + *strp += 4; /* skip over the (DP) in *strp */ + return errmsg; + } else + { + /* Found something there in front of (DP) but it's out of range. */ + errmsg = _("(DP) offset out of range."); + return errmsg; + } + + } + } + + + /* Attempt to parse for SP. ex: mov w, offset(SP) */ + /* mov offset(SP), w */ + + + afteroffset = strstr(*strp,"(SP)"); + + if (afteroffset == NULL) + { + /* Maybe it's in lower case. */ + afteroffset = strstr(*strp, "(sp)"); + } + + if ( afteroffset != NULL ) + { + if ( afteroffset == *strp ) + { + /* No offset present. Use 0 by default. */ + tempvalue = 0; + errmsg = NULL; + } + else + { + errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IP2K_FR_OFFSET, + & result_type, & tempvalue); + } + if (errmsg == NULL) + { + if ( (tempvalue >= 0) && (tempvalue <= 127) ) + { + /* Value is ok. Fix up the first 2 bits and return */ + *valuep = 0x0180 | tempvalue; + *strp += 4; /* skip over the (SP) in *strp */ + return errmsg; + } else + { + /* Found something there in front of (SP) but it's out of range. */ + errmsg = _("(SP) offset out of range."); + return errmsg; + } + + } + } + + + /* Attempt to parse as an address. */ + *strp = old_strp; + errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IP2K_FR9, + & result_type, & value); + if (errmsg == NULL) + { + *valuep = value; + + /* if a parenthesis is found, warn about invalid form */ + + if (**strp == '(') + { + errmsg = _("illegal use of parentheses"); + } + /* if a numeric value is specified, ensure that it is between 1 and 255 */ + else if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) + { + if (value < 0x1 || value > 0xff) + errmsg = _("operand out of range (not between 1 and 255)"); + } + } + return errmsg; +} + +static const char * +parse_addr16 (cd, strp, opindex, valuep) + CGEN_CPU_DESC cd; + const char **strp; + int opindex; + long *valuep; +{ + const char *errmsg; + enum cgen_parse_operand_result result_type; + bfd_reloc_code_real_type code = BFD_RELOC_NONE; + long value; + + if ( opindex == (CGEN_OPERAND_TYPE)IP2K_OPERAND_ADDR16H ) + code = BFD_RELOC_IP2K_HI8DATA; + else if ( opindex == (CGEN_OPERAND_TYPE)IP2K_OPERAND_ADDR16L ) + code = BFD_RELOC_IP2K_LO8DATA; + else + { + /* Something is very wrong. opindex has to be one of the above. */ + errmsg = _("parse_addr16: invalid opindex."); + return errmsg; + } + + errmsg = cgen_parse_address (cd, strp, opindex, code, + & result_type, & value); + if (errmsg == NULL) + { + /* We either have a relocation or a number now. */ + if ( result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER ) + { + /* We got a number back. */ + if ( code == BFD_RELOC_IP2K_HI8DATA ) + value >>= 8; + else /* code = BFD_RELOC_IP2K_LOW8DATA */ + value &= 0x00FF; + } + *valuep = value; + } + + return errmsg; +} + + + static const char * + parse_addr16_p (cd, strp, opindex, valuep) + CGEN_CPU_DESC cd; + const char **strp; + int opindex; + long *valuep; + { + const char *errmsg; + enum cgen_parse_operand_result result_type; + bfd_reloc_code_real_type code = BFD_RELOC_IP2K_PAGE3; + long value; + + errmsg = cgen_parse_address (cd, strp, opindex, code, + & result_type, & value); + if (errmsg == NULL) + { + if ( result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER ) + *valuep = (value >> 13) & 0x7; + else if ( result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED ) + *valuep = value; + } + return errmsg; + } + + + static const char * + parse_addr16_cjp (cd, strp, opindex, valuep) + CGEN_CPU_DESC cd; + const char **strp; + int opindex; + long *valuep; + { + const char *errmsg; + enum cgen_parse_operand_result result_type; + bfd_reloc_code_real_type code = BFD_RELOC_NONE; + long value; + + if ( opindex == (CGEN_OPERAND_TYPE)IP2K_OPERAND_ADDR16CJP ) + code = BFD_RELOC_IP2K_ADDR16CJP; + else if ( opindex == (CGEN_OPERAND_TYPE)IP2K_OPERAND_ADDR16P ) + code = BFD_RELOC_IP2K_PAGE3; + + errmsg = cgen_parse_address (cd, strp, opindex, code, + & result_type, & value); + if (errmsg == NULL) + { + if ( result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER ) + { + if ( (value & 0x1) == 0) /* If the address is even .... */ + { + if ( opindex == (CGEN_OPERAND_TYPE)IP2K_OPERAND_ADDR16CJP ) + *valuep = (value >> 1) & 0x1FFF; /* Should mask be 1FFF? */ + else if ( opindex == (CGEN_OPERAND_TYPE)IP2K_OPERAND_ADDR16P ) + *valuep = (value >> 14) & 0x7; + } + else + errmsg = _("Byte address required. - must be even."); + }else if ( result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED ) + { + /* This will happen for things like (s2-s1) where s2 and s1 */ + /* are labels. */ + *valuep = value; + } + else + errmsg = _("cgen_parse_address returned a symbol. Literal required."); + } + return errmsg; + } + + +static const char * +parse_lit8 (cd, strp, opindex, valuep) + CGEN_CPU_DESC cd; + const char **strp; + int opindex; + long *valuep; +{ + const char *errmsg; + enum cgen_parse_operand_result result_type; + bfd_reloc_code_real_type code = BFD_RELOC_NONE; + long value; + + /* Parse %OP relocating operators. */ + if (strncmp (*strp, "%bank", 5) == 0) + { + *strp += 5; + code = BFD_RELOC_IP2K_BANK; + } + else if (strncmp (*strp, "%lo8data", 8) == 0) + { + *strp += 8; + code = BFD_RELOC_IP2K_LO8DATA; + } + else if (strncmp (*strp, "%hi8data", 8) == 0) + { + *strp += 8; + code = BFD_RELOC_IP2K_HI8DATA; + } + else if (strncmp (*strp, "%ex8data", 8) == 0) + { + *strp += 8; + code = BFD_RELOC_IP2K_EX8DATA; + } + else if (strncmp (*strp, "%lo8insn", 8) == 0) + { + *strp += 8; + code = BFD_RELOC_IP2K_LO8INSN; + } + else if (strncmp (*strp, "%hi8insn", 8) == 0) + { + *strp += 8; + code = BFD_RELOC_IP2K_HI8INSN; + } + + + /* Parse %op operand. */ + if (code != BFD_RELOC_NONE) + { + errmsg = cgen_parse_address (cd, strp, opindex, code, + & result_type, & value); + if ((errmsg == NULL) && + (result_type != CGEN_PARSE_OPERAND_RESULT_QUEUED)) + errmsg = _("%operator operand is not a symbol"); + + *valuep = value; + } + /* Parse as a number. */ + else + { + errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep); + + /* Truncate to eight bits to accept both signed and unsigned input. */ + if (errmsg == NULL) + *valuep &= 0xFF; + } + + return errmsg; +} + +static const char * +parse_bit3 (cd, strp, opindex, valuep) + CGEN_CPU_DESC cd; + const char **strp; + int opindex; + long *valuep; +{ + const char *errmsg; + char mode = 0; + long count = 0; + unsigned long value; + + if (strncmp (*strp, "%bit", 4) == 0) + { + *strp += 4; + mode = 1; + } + else if (strncmp (*strp, "%msbbit", 7) == 0) + { + *strp += 7; + mode = 1; + } + else if (strncmp (*strp, "%lsbbit", 7) == 0) + { + *strp += 7; + mode = 2; + } + + errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep); + if (errmsg) { + return errmsg; + } + + if (mode) { + value = (unsigned long) *valuep; + if (value == 0) { + errmsg = _("Attempt to find bit index of 0"); + return errmsg; + } + + if (mode == 1) { + count = 31; + while ((value & 0x80000000) == 0) { + count--; + value <<= 1; + } + } else if (mode == 2) { + count = 0; + while ((value & 0x00000001) == 0) { + count++; + value >>= 1; + } + } + + *valuep = count; + } + + return errmsg; +} + + +/* -- dis.c */ + +static void +print_fr (cd, dis_info, value, attrs, pc, length) + CGEN_CPU_DESC cd; + PTR dis_info; + long value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + disassemble_info *info = (disassemble_info *) dis_info; + const CGEN_KEYWORD_ENTRY *ke; + extern CGEN_KEYWORD ip2k_cgen_opval_register_names; + long offsettest; + long offsetvalue; + + if ( value == 0 ) /* This is (IP) */ + { + (*info->fprintf_func) (info->stream, "%s", "(IP)"); + return; + } + + offsettest = value >> 7; + offsetvalue = value & 0x7F; + + /* Check to see if first two bits are 10 -> (DP) */ + if ( offsettest == 2 ) + { + if ( offsetvalue == 0 ) + (*info->fprintf_func) (info->stream, "%s","(DP)"); + else + (*info->fprintf_func) (info->stream, "$%x%s",offsetvalue, "(DP)"); + return; + } + + /* Check to see if first two bits are 11 -> (SP) */ + if ( offsettest == 3 ) + { + if ( offsetvalue == 0 ) + (*info->fprintf_func) (info->stream, "%s", "(SP)"); + else + (*info->fprintf_func) (info->stream, "$%x%s", offsetvalue,"(SP)"); + return; + } + + /* Attempt to print as a register keyword. */ + ke = cgen_keyword_lookup_value (& ip2k_cgen_opval_register_names, value); + if (ke != NULL) + { + (*info->fprintf_func) (info->stream, "%s", ke->name); + return; + } + + /* Print as an address literal. */ + (*info->fprintf_func) (info->stream, "$%02x", value); +} + +static void +print_dollarhex (cd, dis_info, value, attrs, pc, length) + CGEN_CPU_DESC cd; + PTR dis_info; + long value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + disassemble_info *info = (disassemble_info *) dis_info; + + (*info->fprintf_func) (info->stream, "$%x", value); +} + +static void +print_dollarhex8 (cd, dis_info, value, attrs, pc, length) + CGEN_CPU_DESC cd; + PTR dis_info; + long value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + disassemble_info *info = (disassemble_info *) dis_info; + + (*info->fprintf_func) (info->stream, "$%02x", value); +} + +static void +print_dollarhex16 (cd, dis_info, value, attrs, pc, length) + CGEN_CPU_DESC cd; + PTR dis_info; + long value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + disassemble_info *info = (disassemble_info *) dis_info; + + (*info->fprintf_func) (info->stream, "$%04x", value); +} + +static void +print_dollarhex_addr16h (cd, dis_info, value, attrs, pc, length) + CGEN_CPU_DESC cd; + PTR dis_info; + long value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + disassemble_info *info = (disassemble_info *) dis_info; + + /* This is a loadh instruction. Shift the value to the left */ + /* by 8 bits so that disassembled code will reassemble properly. */ + value = ((value << 8) & 0xFF00); + + (*info->fprintf_func) (info->stream, "$%04x", value); +} + +static void +print_dollarhex_addr16l (cd, dis_info, value, attrs, pc, length) + CGEN_CPU_DESC cd; + PTR dis_info; + long value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + disassemble_info *info = (disassemble_info *) dis_info; + + (*info->fprintf_func) (info->stream, "$%04x", value); +} + +static void +print_dollarhex_p (cd, dis_info, value, attrs, pc, length) + CGEN_CPU_DESC cd; + PTR dis_info; + long value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + disassemble_info *info = (disassemble_info *) dis_info; + + value = ((value << 14) & 0x1C000); + ;value = (value & 0x1FFFF); + (*info->fprintf_func) (info->stream, "$%05x", value); +} + +static void +print_dollarhex_cj (cd, dis_info, value, attrs, pc, length) + CGEN_CPU_DESC cd; + PTR dis_info; + long value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + disassemble_info *info = (disassemble_info *) dis_info; + + value = ((value << 1) & 0x1FFFF); + (*info->fprintf_func) (info->stream, "$%05x", value); +} + + +static void +print_decimal (cd, dis_info, value, attrs, pc, length) + CGEN_CPU_DESC cd; + PTR dis_info; + long value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + disassemble_info *info = (disassemble_info *) dis_info; + + (*info->fprintf_func) (info->stream, "%d", value); +} + + + +/* -- */ + -- 2.43.5