home *** CD-ROM | disk | FTP | other *** search
- /* $VER: pasm instructions.c V0.8 (14.02.98)
- *
- * This file is part of pasm, a portable PowerPC assembler.
- * Copyright (c) 1997-98 Frank Wille
- *
- * pasm is freeware and part of the portable and retargetable ANSI C
- * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
- * pasm may be freely redistributed as long as no modifications are
- * made and nothing is charged for it. Non-commercial usage is allowed
- * without any restrictions.
- * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
- * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
- *
- *
- * v0.8 (14.02.98) phx
- * Alignment list for each section. This fixes the problems
- * with optimizations.
- * V0.7 (02.01.98) phx
- * Implemented optimization OPT_FAR_BRANCH.
- * v0.6 (30.10.97) phx
- * No more warnings for val@l(rA), where val is > 0x7fff.
- * Warnings for optional, 64-bit and supervisor instructions
- * can be suppressed.
- * v0.5 (03.10.97) phx
- * Auto-converting (rA) into 0(rA) had lead to conflicts with terms.
- * For example: (x+y)(rA)
- * v0.4 (05.07.97) phx
- * AA bit in BC instructions is set to allow correct EHF reloction
- * (by using AmigaDOS HUNK_RELRELOC16. This should be no problem,
- * because absolute branches are not supported by EHF anyway.
- * Branch prediction with BCA didn't work correctly.
- * Relative branches into other sections are allowed, but the
- * user will be warned, because not all object formats / linkers
- * support it.
- * Omitting zero in load/store instructions is allowed, e.g.
- * "rD,(rA)" will be converted into "rD,0(rA)".
- * R_PPC_TOC16 support for T_DD- and T_DS-type instructions.
- * v0.3 (05.04.97) phx
- * An external symbol@l/h/ha, used in d(Rn) addressing mode, got
- * R_PPC_ADDR16 relocation instead R_PPC_ADDR16_LO/HI/HA.
- * Little-endian support.
- * v0.2 (25.03.97) phx
- * Writes ELF object for 32-bit PowerPC big-endian. Either absolute
- * or ELF output format may be selected. ELF is default for all
- * currently supported platforms. PPCasm supports nine different
- * relocation types (there are much more...).
- * Compiles and works also under NetBSD/amiga (68k).
- * Changed function declaration to 'new style' in all sources
- * (to avoid problems with '...' for example).
- * @l/h/ha is allowed for all displacements.
- * v0.1 (11.03.97) phx
- * First test version with all PowerPC instructions and most
- * important directives. Only raw, absolute output.
- * Although all 32- and 64-bit PowerPC instructions are imple-
- * mented, too few are really tested till now. I'm expecting many
- * bugs in this long list.
- * 'la' is the only extended mnemonic, which was implemented as a
- * real instruction and not by a macro. It is possible to imple-
- * ment all extended mnemonics here, but it would be much work.
- * Maybe later, to improve speed. ;)
- * v0.0 (21.02.97) phx
- * File created.
- */
-
-
- #define INSTRUCTIONS_C
- #include "ppcasm.h"
-
-
- void instr(struct GlobalVars *,struct ParsedLine *);
- char *check_comma(char *);
- void pcadd(struct GlobalVars *,unsigned long);
- void store_byte(struct GlobalVars *,uint8);
- void store_half(struct GlobalVars *,uint16);
- void store_word(struct GlobalVars *,uint32);
- void store_float(struct GlobalVars *,double);
- void store_double(struct GlobalVars *,double);
- void store_space(struct GlobalVars *,unsigned long);
-
- static void opt_far_branch(struct GlobalVars *,struct ParsedLine *,
- uint32 *,uint32 *,int32 *,char *);
- static void swapops(uint32 *,uint32 *);
- static int count_operands(struct GlobalVars *,char *);
- static bool chk_regindir(char *);
- static void move_symbols(struct GlobalVars *,uint32,int32);
- static void move_aligned_symbols_offset(struct GlobalVars *,
- struct AlignPoint *,uint32,int32);
- static void move_aligned_symbols_all(struct GlobalVars *gv,
- struct AlignPoint *ap,int32);
-
-
-
- struct CPUInstr instructions[] = {
- /* standard PowerPC instruction set */
- { 0,"add",0,T_X,31,0,0,(0<<10)+(266<<1)+0 },
- { 0,"add.",0,T_X,31,0,0,(0<<10)+(266<<1)+1 },
- { 0,"addo",0,T_X,31,0,0,(1<<10)+(266<<1)+0 },
- { 0,"addo.",0,T_X,31,0,0,(1<<10)+(266<<1)+1 },
- { 0,"addc",0,T_X,31,0,0,(0<<10)+(10<<1)+0 },
- { 0,"addc.",0,T_X,31,0,0,(0<<10)+(10<<1)+1 },
- { 0,"addco",0,T_X,31,0,0,(1<<10)+(10<<1)+0 },
- { 0,"addco.",0,T_X,31,0,0,(1<<10)+(10<<1)+1 },
- { 0,"adde",0,T_X,31,0,0,(0<<10)+(138<<1)+0 },
- { 0,"adde.",0,T_X,31,0,0,(0<<10)+(138<<1)+1 },
- { 0,"addeo",0,T_X,31,0,0,(1<<10)+(138<<1)+0 },
- { 0,"addeo.",0,T_X,31,0,0,(1<<10)+(138<<1)+1 },
- { 0,"addi",F_SIGNED,T_DI,14,0,0,0 },
- { 0,"addic",F_SIGNED,T_DI,12,0,0,0 },
- { 0,"addic.",F_SIGNED,T_DI,13,0,0,0 },
- { 0,"addis",F_SIGNED,T_DI,15,0,0,0 },
- { 0,"addme",F_SUPP_B,T_X,31,0,0,(0<<10)+(234<<1)+0 },
- { 0,"addme.",F_SUPP_B,T_X,31,0,0,(0<<10)+(234<<1)+1 },
- { 0,"addmeo",F_SUPP_B,T_X,31,0,0,(1<<10)+(234<<1)+0 },
- { 0,"addmeo.",F_SUPP_B,T_X,31,0,0,(1<<10)+(234<<1)+1 },
- { 0,"addze",F_SUPP_B,T_X,31,0,0,(0<<10)+(202<<1)+0 },
- { 0,"addze.",F_SUPP_B,T_X,31,0,0,(0<<10)+(202<<1)+1 },
- { 0,"addzeo",F_SUPP_B,T_X,31,0,0,(1<<10)+(202<<1)+0 },
- { 0,"addzeo.",F_SUPP_B,T_X,31,0,0,(1<<10)+(202<<1)+1 },
- { 0,"and",F_SWAP,T_X,31,0,0,(28<<1)+0 },
- { 0,"and.",F_SWAP,T_X,31,0,0,(28<<1)+1 },
- { 0,"andc",F_SWAP,T_X,31,0,0,(60<<1)+0 },
- { 0,"andc.",F_SWAP,T_X,31,0,0,(60<<1)+1 },
- { 0,"andi.",F_SWAP,T_DI,28,0,0,0 },
- { 0,"andis.",F_SWAP,T_DI,29,0,0,0 },
- { 0,"b",F_SIGNED,T_I,18,0,0,0 },
- { 0,"bl",F_SIGNED,T_I,18,0,0,1 },
- { 0,"ba",0,T_I,18,0,0,2 },
- { 0,"bla",0,T_I,18,0,0,3 },
- { 0,"bc",F_SIGNED,T_B,16,0,0,0 },
- { 0,"bcl",F_SIGNED,T_B,16,0,0,1 },
- { 0,"bca",0,T_B,16,0,0,2 },
- { 0,"bcla",0,T_B,16,0,0,3 },
- { 0,"bcctr",0,T_XLB,19,0,0,(528<<1)+0 },
- { 0,"bcctrl",0,T_XLB,19,0,0,(528<<1)+1 },
- { 0,"bclr",0,T_XLB,19,0,0,(16<<1)+0 },
- { 0,"bclrl",0,T_XLB,19,0,0,(16<<1)+1 },
- { 0,"cmp",0,T_CMP,31,0,0,(0<<1) },
- { 0,"cmpl",0,T_CMP,31,0,0,(32<<1) },
- { 0,"cmpi",F_SIGNED|F_SUPP_B,T_CMP,11,0,0,0 },
- { 0,"cmpli",F_SUPP_B,T_CMP,10,0,0,0 },
- { 0,"cntlzd",F_SWAP|F_SUPP_B|F_64BIT,T_X,31,0,0,(58<<1)+0 },
- { 0,"cntlzd.",F_SWAP|F_SUPP_B|F_64BIT,T_X,31,0,0,(58<<1)+1 },
- { 0,"cntlzw",F_SWAP|F_SUPP_B,T_X,31,0,0,(26<<1)+0 },
- { 0,"cntlzw.",F_SWAP|F_SUPP_B,T_X,31,0,0,(26<<1)+1 },
- { 0,"crand",0,T_X,19,0,0,(257<<1) },
- { 0,"crandc",0,T_X,19,0,0,(129<<1) },
- { 0,"creqv",0,T_X,19,0,0,(289<<1) },
- { 0,"crnand",0,T_X,19,0,0,(225<<1) },
- { 0,"crnor",0,T_X,19,0,0,(33<<1) },
- { 0,"cror",0,T_X,19,0,0,(449<<1) },
- { 0,"crorc",0,T_X,19,0,0,(417<<1) },
- { 0,"crxor",0,T_X,19,0,0,(193<<1) },
- { 0,"dcbf",F_SUPP_D,T_X,31,0,0,(86<<1) },
- { 0,"dcbi",F_SUPP_D|F_SUPER,T_X,31,0,0,(470<<1) },
- { 0,"dcbst",F_SUPP_D,T_X,31,0,0,(54<<1) },
- { 0,"dcbt",F_SUPP_D,T_X,31,0,0,(278<<1) },
- { 0,"dcbtst",F_SUPP_D,T_X,31,0,0,(246<<1) },
- { 0,"dcbz",F_SUPP_D,T_X,31,0,0,(1014<<1) },
- { 0,"divd",F_64BIT,T_X,31,0,0,(0<<10)+(489<<1)+0 },
- { 0,"divd.",F_64BIT,T_X,31,0,0,(0<<10)+(489<<1)+1 },
- { 0,"divdo",F_64BIT,T_X,31,0,0,(1<<10)+(489<<1)+0 },
- { 0,"divdo.",F_64BIT,T_X,31,0,0,(1<<10)+(489<<1)+1 },
- { 0,"divdu",F_64BIT,T_X,31,0,0,(0<<10)+(457<<1)+0 },
- { 0,"divdu.",F_64BIT,T_X,31,0,0,(0<<10)+(457<<1)+1 },
- { 0,"divduo",F_64BIT,T_X,31,0,0,(1<<10)+(457<<1)+0 },
- { 0,"divduo.",F_64BIT,T_X,31,0,0,(1<<10)+(457<<1)+1 },
- { 0,"divw",0,T_X,31,0,0,(0<<10)+(491<<1)+0 },
- { 0,"divw.",0,T_X,31,0,0,(0<<10)+(491<<1)+1 },
- { 0,"divwo",0,T_X,31,0,0,(1<<10)+(491<<1)+0 },
- { 0,"divwo.",0,T_X,31,0,0,(1<<10)+(491<<1)+1 },
- { 0,"divwu",0,T_X,31,0,0,(0<<10)+(459<<1)+0 },
- { 0,"divwu.",0,T_X,31,0,0,(0<<10)+(459<<1)+1 },
- { 0,"divwuo",0,T_X,31,0,0,(1<<10)+(459<<1)+0 },
- { 0,"divwuo.",0,T_X,31,0,0,(1<<10)+(459<<1)+1 },
- { 0,"eciwx",0,T_X,31,0,0,(310<<1) },
- { 0,"ecowx",0,T_X,31,0,0,(438<<1) },
- { 0,"eieio",F_SUPP_D|F_SUPP_A|F_SUPP_B,T_X,31,0,0,(854<<1) },
- { 0,"eqv",F_SWAP,T_X,31,0,0,(284<<1)+0 },
- { 0,"eqv.",F_SWAP,T_X,31,0,0,(284<<1)+0 },
- { 0,"extsb",F_SWAP|F_SUPP_B,T_X,31,0,0,(954<<1)+0 },
- { 0,"extsb.",F_SWAP|F_SUPP_B,T_X,31,0,0,(954<<1)+1 },
- { 0,"extsh",F_SWAP|F_SUPP_B,T_X,31,0,0,(922<<1)+0 },
- { 0,"extsh.",F_SWAP|F_SUPP_B,T_X,31,0,0,(922<<1)+1 },
- { 0,"extsw",F_SWAP|F_SUPP_B|F_64BIT,T_X,31,0,0,(986<<1)+0 },
- { 0,"extsw.",F_SWAP|F_SUPP_B|F_64BIT,T_X,31,0,0,(986<<1)+1 },
- { 0,"fabs",F_SUPP_A,T_X,63,0,0,(264<<1)+0 },
- { 0,"fabs.",F_SUPP_A,T_X,63,0,0,(264<<1)+1 },
- { 0,"fadd",F_SUPP_C,T_A,63,0,0,(21<<1)+0 },
- { 0,"fadd.",F_SUPP_C,T_A,63,0,0,(21<<1)+1 },
- { 0,"fadds",F_SUPP_C,T_A,59,0,0,(21<<1)+0 },
- { 0,"fadds.",F_SUPP_C,T_A,59,0,0,(21<<1)+1 },
- { 0,"fcfid",F_SUPP_A|F_64BIT,T_X,63,0,0,(846<<1)+0 },
- { 0,"fcfid.",F_SUPP_A|F_64BIT,T_X,63,0,0,(846<<1)+1 },
- { 0,"fcmpo",F_CRF_D,T_X,63,0,0,(32<<1) },
- { 0,"fcmpu",F_CRF_D,T_X,63,0,0,(0<<1) },
- { 0,"fctid",F_SUPP_A|F_64BIT,T_X,63,0,0,(814<<1)+0 },
- { 0,"fctid.",F_SUPP_A|F_64BIT,T_X,63,0,0,(814<<1)+1 },
- { 0,"fctidz",F_SUPP_A|F_64BIT,T_X,63,0,0,(815<<1)+0 },
- { 0,"fctidz.",F_SUPP_A|F_64BIT,T_X,63,0,0,(815<<1)+1 },
- { 0,"fctiw",F_SUPP_A,T_X,63,0,0,(14<<1)+0 },
- { 0,"fctiw.",F_SUPP_A,T_X,63,0,0,(14<<1)+1 },
- { 0,"fctiwz",F_SUPP_A,T_X,63,0,0,(15<<1)+0 },
- { 0,"fctiwz.",F_SUPP_A,T_X,63,0,0,(15<<1)+1 },
- { 0,"fdiv",F_SUPP_C,T_A,63,0,0,(18<<1)+0 },
- { 0,"fdiv.",F_SUPP_C,T_A,63,0,0,(18<<1)+1 },
- { 0,"fdivs",F_SUPP_C,T_A,59,0,0,(18<<1)+0 },
- { 0,"fdivs.",F_SUPP_C,T_A,59,0,0,(18<<1)+1 },
- { 0,"fmadd",0,T_A,63,0,0,(29<<1)+0 },
- { 0,"fmadd.",0,T_A,63,0,0,(29<<1)+1 },
- { 0,"fmadds",0,T_A,59,0,0,(29<<1)+0 },
- { 0,"fmadds.",0,T_A,59,0,0,(29<<1)+1 },
- { 0,"fmr",F_SUPP_A,T_X,63,0,0,(72<<1)+0 },
- { 0,"fmr.",F_SUPP_A,T_X,63,0,0,(72<<1)+1 },
- { 0,"fmsub",0,T_A,63,0,0,(28<<1)+0 },
- { 0,"fmsub.",0,T_A,63,0,0,(28<<1)+1 },
- { 0,"fmsubs",0,T_A,59,0,0,(28<<1)+0 },
- { 0,"fmsubs.",0,T_A,59,0,0,(28<<1)+1 },
- { 0,"fmul",F_SUPP_B,T_A,63,0,0,(25<<1)+0 },
- { 0,"fmul.",F_SUPP_B,T_A,63,0,0,(25<<1)+1 },
- { 0,"fmuls",F_SUPP_B,T_A,59,0,0,(25<<1)+0 },
- { 0,"fmuls.",F_SUPP_B,T_A,59,0,0,(25<<1)+1 },
- { 0,"fnabs",F_SUPP_A,T_X,63,0,0,(136<<1)+0 },
- { 0,"fnabs.",F_SUPP_A,T_X,63,0,0,(136<<1)+1 },
- { 0,"fneg",F_SUPP_A,T_X,63,0,0,(40<<1)+0 },
- { 0,"fneg.",F_SUPP_A,T_X,63,0,0,(40<<1)+1 },
- { 0,"fnmadd",0,T_A,63,0,0,(31<<1)+0 },
- { 0,"fnmadd.",0,T_A,63,0,0,(31<<1)+1 },
- { 0,"fnmadds",0,T_A,59,0,0,(31<<1)+0 },
- { 0,"fnmadds.",0,T_A,59,0,0,(31<<1)+1 },
- { 0,"fnmsub",0,T_A,63,0,0,(30<<1)+0 },
- { 0,"fnmsub.",0,T_A,63,0,0,(30<<1)+1 },
- { 0,"fnmsubs",0,T_A,59,0,0,(30<<1)+0 },
- { 0,"fnmsubs.",0,T_A,59,0,0,(30<<1)+1 },
- { 0,"fres",F_SUPP_A|F_SUPP_C|F_OPTIONAL,T_A,59,0,0,(24<<1)+0 },
- { 0,"fres.",F_SUPP_A|F_SUPP_C|F_OPTIONAL,T_A,59,0,0,(24<<1)+1 },
- { 0,"frsp",F_SUPP_A,T_X,63,0,0,(12<<1)+0 },
- { 0,"frsp.",F_SUPP_A,T_X,63,0,0,(12<<1)+1 },
- { 0,"frsqrte",F_SUPP_A|F_SUPP_C|F_OPTIONAL,T_A,63,0,0,(26<<1)+0 },
- { 0,"frsqrte.",F_SUPP_A|F_SUPP_C|F_OPTIONAL,T_A,63,0,0,(26<<1)+1 },
- { 0,"fsel",F_OPTIONAL,T_A,63,0,0,(23<<1)+0 },
- { 0,"fsel.",F_OPTIONAL,T_A,63,0,0,(23<<1)+1 },
- { 0,"fsqrt",F_SUPP_A|F_SUPP_C|F_OPTIONAL,T_A,63,0,0,(22<<1)+0 },
- { 0,"fsqrt.",F_SUPP_A|F_SUPP_C|F_OPTIONAL,T_A,63,0,0,(22<<1)+1 },
- { 0,"fsqrts",F_SUPP_A|F_SUPP_C|F_OPTIONAL,T_A,59,0,0,(22<<1)+0 },
- { 0,"fsqrts.",F_SUPP_A|F_SUPP_C|F_OPTIONAL,T_A,59,0,0,(22<<1)+1 },
- { 0,"fsub",F_SUPP_C,T_A,63,0,0,(20<<1)+0 },
- { 0,"fsub.",F_SUPP_C,T_A,63,0,0,(20<<1)+1 },
- { 0,"fsubs",F_SUPP_C,T_A,59,0,0,(20<<1)+0 },
- { 0,"fsubs.",F_SUPP_C,T_A,59,0,0,(20<<1)+1 },
- { 0,"icbi",F_SUPP_D,T_X,31,0,0,(982<<1) },
- { 0,"isync",F_SUPP_D|F_SUPP_A|F_SUPP_B,T_X,19,0,0,(150<<1) },
- { 0,"lbz",0,T_DD,34,0,0,0 },
- { 0,"lbzu",0,T_DD,35,0,0,0 },
- { 0,"lbzux",0,T_X,31,0,0,(119<<1) },
- { 0,"lbzx",0,T_X,31,0,0,(87<<1) },
- { 0,"ld",F_64BIT,T_DS,58,0,0,0 },
- { 0,"ldarx",F_64BIT,T_X,31,0,0,(84<<1) },
- { 0,"ldu",F_64BIT,T_DS,58,0,0,1 },
- { 0,"ldux",F_64BIT,T_X,31,0,0,(53<<1) },
- { 0,"ldx",F_64BIT,T_X,31,0,0,(21<<1) },
- { 0,"lfd",0,T_DD,50,0,0,0 },
- { 0,"lfdu",0,T_DD,51,0,0,0 },
- { 0,"lfdux",0,T_X,31,0,0,(631<<1) },
- { 0,"lfdx",0,T_X,31,0,0,(599<<1) },
- { 0,"lfs",0,T_DD,48,0,0,0 },
- { 0,"lfsu",0,T_DD,49,0,0,0 },
- { 0,"lfsux",0,T_X,31,0,0,(567<<1) },
- { 0,"lfsx",0,T_X,31,0,0,(535<<1) },
- { 0,"lha",0,T_DD,42,0,0,0 },
- { 0,"lhau",0,T_DD,43,0,0,0 },
- { 0,"lhaux",0,T_X,31,0,0,(375<<1) },
- { 0,"lhax",0,T_X,31,0,0,(343<<1) },
- { 0,"lhbrx",0,T_X,31,0,0,(790<<1) },
- { 0,"lhz",0,T_DD,40,0,0,0 },
- { 0,"lhzu",0,T_DD,41,0,0,0 },
- { 0,"lhzux",0,T_X,31,0,0,(311<<1) },
- { 0,"lhzx",0,T_X,31,0,0,(279<<1) },
- { 0,"lmw",0,T_DD,46,0,0,0 },
- { 0,"lswi",0,T_X,31,0,0,(597<<1) },
- { 0,"lswx",0,T_X,31,0,0,(533<<1) },
- { 0,"lwa",F_64BIT,T_DS,58,0,0,2 },
- { 0,"lwarx",0,T_X,31,0,0,(20<<1) },
- { 0,"lwaux",F_64BIT,T_X,31,0,0,(373<<1) },
- { 0,"lwax",F_64BIT,T_X,31,0,0,(341<<1) },
- { 0,"lwbrx",0,T_X,31,0,0,(534<<1) },
- { 0,"lwz",0,T_DD,32,0,0,0 },
- { 0,"lwzu",0,T_DD,33,0,0,0 },
- { 0,"lwzux",0,T_X,31,0,0,(55<<1) },
- { 0,"lwzx",0,T_X,31,0,0,(23<<1) },
- { 0,"mcrf",F_CRF_D|F_CRF_S|F_SUPP_B,T_X,19,0,0,(0<<1) },
- { 0,"mcrfs",F_CRF_D|F_CRF_S|F_SUPP_B,T_X,63,0,0,(64<<1) },
- { 0,"mcrxr",F_CRF_D|F_SUPP_A|F_SUPP_B,T_X,31,0,0,(512<<1) },
- { 0,"mfcr",F_SUPP_A|F_SUPP_B,T_X,31,0,0,(19<<1) },
- { 0,"mffs",F_SUPP_A|F_SUPP_B,T_X,63,0,0,(583<<1)+0 },
- { 0,"mffs.",F_SUPP_A|F_SUPP_B,T_X,63,0,0,(583<<1)+1 },
- { 0,"mfmsr",F_SUPP_A|F_SUPP_B|F_SUPER,T_X,31,0,0,(83<<1) },
- { 0,"mfspr",0,T_XSPR,31,0,0,(339<<1) },
- { 0,"mfsr",F_SUPP_B|F_SUPER,T_X,31,0,0,(595<<1) },
- { 0,"mfsrin",F_SUPP_A|F_SUPER,T_X,31,0,0,(659<<1) },
- { 0,"mftb",0,T_XSPR,31,0,0,(371<<1) },
- { 0,"mtcrf",0,T_XCRM,31,0,0,(144<<1) },
- { 0,"mtfsb0",F_SUPP_A|F_SUPP_B,T_X,63,0,0,(70<<1)+0 },
- { 0,"mtfsb0.",F_SUPP_A|F_SUPP_B,T_X,63,0,0,(70<<1)+1 },
- { 0,"mtfsb1",F_SUPP_A|F_SUPP_B,T_X,63,0,0,(38<<1)+0 },
- { 0,"mtfsb1.",F_SUPP_A|F_SUPP_B,T_X,63,0,0,(38<<1)+1 },
- { 0,"mtfsf",0,T_XFL,63,0,0,(711<<1)+0 },
- { 0,"mtfsf.",0,T_XFL,63,0,0,(711<<1)+1 },
- { 0,"mtfsfi",0,T_IMM,63,0,0,(134<<1)+0 },
- { 0,"mtfsfi.",0,T_IMM,63,0,0,(134<<1)+1 },
- { 0,"mtmsr",F_SUPP_A|F_SUPP_B|F_SUPER,T_X,31,0,0,(146<<1) },
- { 0,"mtspr",F_SWAP,T_XSPR,31,0,0,(467<<1) },
- { 0,"mtsr",F_SWAP|F_SUPP_B|F_SUPER,T_X,31,0,0,(210<<1) },
- { 0,"mtsrin",F_SUPP_A,T_X,31,0,0,(242<<1) },
- { 0,"mulhd",F_64BIT,T_X,31,0,0,(73<<1)+0 },
- { 0,"mulhd.",F_64BIT,T_X,31,0,0,(73<<1)+1 },
- { 0,"mulhdu",F_64BIT,T_X,31,0,0,(9<<1)+0 },
- { 0,"mulhdu.",F_64BIT,T_X,31,0,0,(9<<1)+1 },
- { 0,"mulhw",0,T_X,31,0,0,(75<<1)+0 },
- { 0,"mulhw.",0,T_X,31,0,0,(75<<1)+1 },
- { 0,"mulhwu",0,T_X,31,0,0,(11<<1)+0 },
- { 0,"mulhwu.",0,T_X,31,0,0,(11<<1)+1 },
- { 0,"mulld",F_64BIT,T_X,31,0,0,(0<<10)+(233<<1)+0 },
- { 0,"mulld.",F_64BIT,T_X,31,0,0,(0<<10)+(233<<1)+1 },
- { 0,"mulldo",F_64BIT,T_X,31,0,0,(1<<10)+(233<<1)+0 },
- { 0,"mulldo.",F_64BIT,T_X,31,0,0,(1<<10)+(233<<1)+1 },
- { 0,"mulli",F_SIGNED,T_DI,7,0,0,0 },
- { 0,"mullw",0,T_X,31,0,0,(0<<10)+(235<<1)+0 },
- { 0,"mullw.",0,T_X,31,0,0,(0<<10)+(235<<1)+1 },
- { 0,"mullwo",0,T_X,31,0,0,(1<<10)+(235<<1)+0 },
- { 0,"mullwo.",0,T_X,31,0,0,(1<<10)+(235<<1)+1 },
- { 0,"nand",F_SWAP,T_X,31,0,0,(476<<1)+0 },
- { 0,"nand.",F_SWAP,T_X,31,0,0,(476<<1)+1 },
- { 0,"neg",F_SUPP_B,T_X,31,0,0,(0<<10)+(104<<1)+0 },
- { 0,"neg.",F_SUPP_B,T_X,31,0,0,(0<<10)+(104<<1)+1 },
- { 0,"nego",F_SUPP_B,T_X,31,0,0,(1<<10)+(104<<1)+0 },
- { 0,"nego.",F_SUPP_B,T_X,31,0,0,(1<<10)+(104<<1)+1 },
- { 0,"nor",F_SWAP,T_X,31,0,0,(124<<1)+0 },
- { 0,"nor.",F_SWAP,T_X,31,0,0,(124<<1)+1 },
- { 0,"or",F_SWAP,T_X,31,0,0,(444<<1)+0 },
- { 0,"or.",F_SWAP,T_X,31,0,0,(444<<1)+1 },
- { 0,"orc",F_SWAP,T_X,31,0,0,(412<<1)+0 },
- { 0,"orc.",F_SWAP,T_X,31,0,0,(412<<1)+1 },
- { 0,"ori",F_SWAP,T_DI,24,0,0,0 },
- { 0,"oris",F_SWAP,T_DI,25,0,0,0 },
- { 0,"rfi",F_SUPP_D|F_SUPP_A|F_SUPP_B|F_SUPER,T_X,19,0,0,(50<<1) },
- { 0,"rldcl",F_SWAP|F_64BIT,T_A,30,0,0,(8<<1)+0 },
- { 0,"rldcl.",F_SWAP|F_64BIT,T_A,30,0,0,(8<<1)+1 },
- { 0,"rldcr",F_SWAP|F_64BIT,T_A,30,0,0,(9<<1)+0 },
- { 0,"rldcr.",F_SWAP|F_64BIT,T_A,30,0,0,(9<<1)+1 },
- { 0,"rldic",F_64BIT,T_MD,30,0,0,(2<<2)+0 },
- { 0,"rldic.",F_64BIT,T_MD,30,0,0,(2<<2)+1 },
- { 0,"rldicl",F_64BIT,T_MD,30,0,0,(0<<2)+0 },
- { 0,"rldicl.",F_64BIT,T_MD,30,0,0,(0<<2)+1 },
- { 0,"rldicr",F_64BIT,T_MD,30,0,0,(1<<2)+0 },
- { 0,"rldicr.",F_64BIT,T_MD,30,0,0,(1<<2)+1 },
- { 0,"rldimi",F_64BIT,T_MD,30,0,0,(3<<2)+0 },
- { 0,"rldimi.",F_64BIT,T_MD,30,0,0,(3<<2)+1 },
- { 0,"rlwimi",0,T_M,20,0,0,0 },
- { 0,"rlwimi.",0,T_M,20,0,0,1 },
- { 0,"rlwinm",0,T_M,21,0,0,0 },
- { 0,"rlwinm.",0,T_M,21,0,0,1 },
- { 0,"rlwnm",0,T_M,23,0,0,0 },
- { 0,"rlwnm.",0,T_M,23,0,0,1 },
- { 0,"sc",F_SUPP_D|F_SUPP_A|F_SUPP_B,T_X,17,0,0,2 },
- { 0,"slbia",F_SUPP_D|F_SUPP_A|F_SUPP_B|F_SUPER|F_64BIT|F_OPTIONAL,
- T_X,31,0,0,(498<<1) },
- { 0,"slbie",F_SUPP_D|F_SUPP_A|F_SUPER|F_64BIT|F_OPTIONAL,
- T_X,31,0,0,(434<<1) },
- { 0,"sld",F_SWAP|F_64BIT,T_X,31,0,0,(27<<1)+0 },
- { 0,"sld.",F_SWAP|F_64BIT,T_X,31,0,0,(27<<1)+1 },
- { 0,"slw",F_SWAP,T_X,31,0,0,(24<<1)+0 },
- { 0,"slw.",F_SWAP,T_X,31,0,0,(24<<1)+1 },
- { 0,"srad",F_SWAP|F_64BIT,T_X,31,0,0,(794<<1)+0 },
- { 0,"srad.",F_SWAP|F_64BIT,T_X,31,0,0,(794<<1)+1 },
- { 0,"sradi",F_64BIT,T_XS,31,0,0,(413<<2)+0 },
- { 0,"sradi.",F_64BIT,T_XS,31,0,0,(413<<2)+1 },
- { 0,"sraw",F_SWAP,T_X,31,0,0,(792<<1)+0 },
- { 0,"sraw.",F_SWAP,T_X,31,0,0,(792<<1)+1 },
- { 0,"srawi",F_SWAP,T_X,31,0,0,(824<<1)+0 },
- { 0,"srawi.",F_SWAP,T_X,31,0,0,(824<<1)+1 },
- { 0,"srd",F_SWAP|F_64BIT,T_X,31,0,0,(539<<1)+0 },
- { 0,"srd.",F_SWAP|F_64BIT,T_X,31,0,0,(539<<1)+1 },
- { 0,"srw",F_SWAP,T_X,31,0,0,(536<<1)+0 },
- { 0,"srw.",F_SWAP,T_X,31,0,0,(536<<1)+1 },
- { 0,"stb",0,T_DD,38,0,0,0 },
- { 0,"stbu",0,T_DD,39,0,0,0 },
- { 0,"stbux",0,T_X,31,0,0,(247<<1) },
- { 0,"stbx",0,T_X,31,0,0,(215<<1) },
- { 0,"std",F_64BIT,T_DS,62,0,0,0 },
- { 0,"stdcx.",F_64BIT,T_X,31,0,0,(214<<1)+1 },
- { 0,"stdu",F_64BIT,T_DS,62,0,0,1 },
- { 0,"stdux",F_64BIT,T_X,31,0,0,(181<<1) },
- { 0,"stdx",F_64BIT,T_X,31,0,0,(149<<1) },
- { 0,"stfd",0,T_DD,54,0,0,0 },
- { 0,"stfdu",0,T_DD,55,0,0,0 },
- { 0,"stfdux",0,T_X,31,0,0,(759<<1) },
- { 0,"stfdx",0,T_X,31,0,0,(727<<1) },
- { 0,"stfiwx",F_OPTIONAL,T_X,31,0,0,(983<<1) },
- { 0,"stfs",0,T_DD,52,0,0,0 },
- { 0,"stfsu",0,T_DD,53,0,0,0 },
- { 0,"stfsux",0,T_X,31,0,0,(695<<1) },
- { 0,"stfsx",0,T_X,31,0,0,(663<<1) },
- { 0,"sth",0,T_DD,44,0,0,0 },
- { 0,"sthbrx",0,T_X,31,0,0,(918<<1) },
- { 0,"sthu",0,T_DD,45,0,0,0 },
- { 0,"sthux",0,T_X,31,0,0,(439<<1) },
- { 0,"sthx",0,T_X,31,0,0,(407<<1) },
- { 0,"stmw",0,T_DD,47,0,0,0 },
- { 0,"stswi",0,T_X,31,0,0,(725<<1) },
- { 0,"stswx",0,T_X,31,0,0,(661<<1) },
- { 0,"stw",0,T_DD,36,0,0,0 },
- { 0,"stwbrx",0,T_X,31,0,0,(662<<1) },
- { 0,"stwcx.",0,T_X,31,0,0,(150<<1)+1 },
- { 0,"stwu",0,T_DD,37,0,0,0 },
- { 0,"stwux",0,T_X,31,0,0,(183<<1) },
- { 0,"stwx",0,T_X,31,0,0,(151<<1) },
- { 0,"subf",0,T_X,31,0,0,(0<<10)+(40<<1)+0 },
- { 0,"subf.",0,T_X,31,0,0,(0<<10)+(40<<1)+1 },
- { 0,"subfo",0,T_X,31,0,0,(1<<10)+(40<<1)+0 },
- { 0,"subfo.",0,T_X,31,0,0,(1<<10)+(40<<1)+1 },
- { 0,"subfc",0,T_X,31,0,0,(0<<10)+(8<<1)+0 },
- { 0,"subfc.",0,T_X,31,0,0,(0<<10)+(8<<1)+1 },
- { 0,"subfco",0,T_X,31,0,0,(1<<10)+(8<<1)+0 },
- { 0,"subfco.",0,T_X,31,0,0,(1<<10)+(8<<1)+1 },
- { 0,"subfe",0,T_X,31,0,0,(0<<10)+(136<<1)+0 },
- { 0,"subfe.",0,T_X,31,0,0,(0<<10)+(136<<1)+1 },
- { 0,"subfeo",0,T_X,31,0,0,(1<<10)+(136<<1)+0 },
- { 0,"subfeo.",0,T_X,31,0,0,(1<<10)+(136<<1)+1 },
- { 0,"subfic",F_SIGNED,T_DI,8,0,0,0 },
- { 0,"subfme",F_SUPP_B,T_X,31,0,0,(0<<10)+(232<<1)+0 },
- { 0,"subfme.",F_SUPP_B,T_X,31,0,0,(0<<10)+(232<<1)+1 },
- { 0,"subfmeo",F_SUPP_B,T_X,31,0,0,(1<<10)+(232<<1)+0 },
- { 0,"subfmeo.",F_SUPP_B,T_X,31,0,0,(1<<10)+(232<<1)+1 },
- { 0,"subfze",F_SUPP_B,T_X,31,0,0,(0<<10)+(200<<1)+0 },
- { 0,"subfze.",F_SUPP_B,T_X,31,0,0,(0<<10)+(200<<1)+1 },
- { 0,"subfzeo",F_SUPP_B,T_X,31,0,0,(1<<10)+(200<<1)+0 },
- { 0,"subfzeo.",F_SUPP_B,T_X,31,0,0,(1<<10)+(200<<1)+1 },
- { 0,"sync",F_SUPP_D|F_SUPP_A|F_SUPP_B,T_X,31,0,0,(598<<1) },
- { 0,"td",F_64BIT,T_X,31,0,0,(68<<1) },
- { 0,"tdi",F_SIGNED|F_64BIT,T_DI,2,0,0,0 },
- { 0,"tlbia",F_SUPP_D|F_SUPP_A|F_SUPP_B|F_SUPER|F_OPTIONAL,
- T_X,31,0,0,(370<<1) },
- { 0,"tlbie",F_SUPP_D|F_SUPP_A|F_SUPER|F_OPTIONAL,T_X,31,0,0,(306<<1) },
- { 0,"tlsync",F_SUPP_D|F_SUPP_A|F_SUPP_B|F_SUPER|F_OPTIONAL,
- T_X,31,0,0,(566<<1) },
- { 0,"tw",0,T_X,31,0,0,(4<<1) },
- { 0,"twi",F_SIGNED,T_DI,3,0,0,0 },
- { 0,"xor",F_SWAP,T_X,31,0,0,(316<<1)+0 },
- { 0,"xor.",F_SWAP,T_X,31,0,0,(316<<1)+1 },
- { 0,"xori",F_SWAP,T_DI,26,0,0,0 },
- { 0,"xoris",F_SWAP,T_DI,27,0,0,0 },
-
- /* extended mnemonics, rest is implemented as predefined macros */
- { 0,"la",F_EXTENDED,T_DD,14,0,0,0 },
- { 0,0 } /* end mark */
- };
-
-
-
- void instr(struct GlobalVars *gv,struct ParsedLine *pl)
- {
- struct CPUInstr *ins=(struct CPUInstr *)pl->opcode;
- char *op=pl->operand;
- uint32 d=ins->fieldD,a=ins->fieldA;
- uint32 b=0,c=0,x=0;
- uint32 oc=ins->opcd<<26;
- uint32 xo=ins->xo;
- uint16 flags=ins->flags;
- char *oldop=op;
- struct Expression exp;
- bool signchk=TRUE;
-
- if (flags & F_64BIT)
- if (!gv->sixtyfourmode)
- error(37,ins->name); /* warning: 64-bit instruction */
- if (flags & F_OPTIONAL)
- if (!gv->optinstrmode)
- error(38,ins->name); /* warning: optional instruction */
- if (flags & F_SUPER)
- if (!gv->supermode)
- error(39,ins->name); /* warning: supervisor-level instruction */
- gv->signedexp = flags&F_SIGNED ? TRUE:FALSE;
-
- switch (ins->type) {
-
- case T_I: /* Bx */
- op = eval_expression(gv,&exp,op);
- if (exp.type < SYM_RELOC)
- switch (exp.type) {
- case SYM_UNDEF:
- error(19); /* undefined symbol */
- break;
- case SYM_ABS:
- error(32); /* Reloc symbol required */
- break;
- }
- if (flags & F_SIGNED) { /* relative branch */
- exp.reloctype = R_PPC_REL24;
- switch (exp.type) {
- case SYM_RELOC:
- if (exp.symbol->relsect == gv->csect)
- x = exp.value - gv->csect->pc; /* branch distance */
- else {
- error(33); /* branch destination is not in current section */
- x = makereloc(gv,&exp);
- }
- break;
- case SYM_EXTERN:
- x = makexref(gv,&exp,3);
- break;
- }
- checkrange(x,3,TRUE);
- }
- else { /* absolute branch */
- exp.reloctype = R_PPC_ADDR24;
- switch (exp.type) {
- case SYM_RELOC:
- x = makereloc(gv,&exp);
- break;
- case SYM_EXTERN:
- x = makexref(gv,&exp,3);
- break;
- }
- checkrange(x,3,FALSE);
- }
- oc |= (x&0x3fffffc)|xo;
- break;
-
- case T_B: /* BCx */
- op = getintexp(gv,op,&d); /* BO, branch operand */
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&a); /* BI, branch condition index */
- if (!(op = check_comma(op)))
- break;
- oldop = op;
- op = eval_expression(gv,&exp,op);
- if (exp.type < SYM_RELOC)
- switch (exp.type) {
- case SYM_UNDEF:
- error(19); /* undefined symbol */
- break;
- case SYM_ABS:
- error(32); /* Reloc symbol required */
- break;
- }
- if (flags & F_SIGNED) { /* relative branch */
- exp.reloctype = R_PPC_REL14;
- switch (exp.type) {
- case SYM_RELOC:
- if (exp.symbol->relsect == gv->csect) {
- x = exp.value - gv->csect->pc; /* branch distance */
- if (gv->opt & OPT_FAR_BRANCH)
- opt_far_branch(gv,pl,&d,&a,(int32 *)&x,oldop);
- }
- else {
- error(33); /* branch destination is not in current section */
- x = makereloc(gv,&exp);
- }
- break;
- case SYM_EXTERN:
- x = makexref(gv,&exp,2);
- break;
- }
- checkrange(x,2,TRUE);
- }
- else { /* absolute branch */
- exp.reloctype = R_PPC_ADDR14;
- switch (exp.type) {
- case SYM_RELOC:
- x = makereloc(gv,&exp);
- break;
- case SYM_EXTERN:
- x = makexref(gv,&exp,2);
- break;
- }
- checkrange(x,2,FALSE);
- }
- if (flags & F_SIGNED) {
- if ((int32)x >= 0)
- d &= ~1;
- else
- d |= 1;
- }
- else {
- if (x < gv->csect->pc && exp.symbol->relsect == gv->csect)
- d |= 1;
- else
- d &= ~1;
- }
- if (pl->branch_hint > 0) /* + */
- d ^= 1;
- x &= 0xfffc;
- if (gv->output == OFMT_EHF) /* hack to allow correct EHF relocation */
- x += 2;
- if (d>31 || a>31)
- error(34); /* Branch operand out of range */
- else
- oc |= (d<<21)|(a<<16)|x|xo;
- break;
-
- case T_XLB: /* BCLRx,BCCTRx */
- op = getintexp(gv,op,&d); /* BO, branch operand */
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&a); /* BI, branch condition index */
- if (pl->branch_hint > 0)
- d |= 1;
- else if (pl->branch_hint < 0)
- d &= ~1;
- if (d>31 || a>31)
- error(34); /* Branch operand out of range */
- else
- oc |= (d<<21)|(a<<16)|xo;
- break;
-
- case T_CMP: /* CMP, CMPI, CMPL, CMPLI */
- if (count_operands(gv,op) > 3) { /* CR-field specified? */
- op = getintexp(gv,op,&d);
- if (!(op = check_comma(op)))
- break;
- }
- op = getintexp(gv,op,&c); /* L = word or double word */
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&a);
- if (!(op = check_comma(op)))
- break;
- if (flags & F_SUPP_B) { /* immediate comparison */
- op = getexp(gv,op,&x,2);
- checkrange(x,2,flags&F_SIGNED);
- }
- else /* register comparison */
- op = getintexp(gv,op,&b);
- if (d>7)
- error(35); /* CR-specifier out of range */
- else if (c>1)
- error(36,"L"); /* Operand field out of range */
- else if (a>31 || b>31)
- error(31); /* register operand out of range */
- else if (flags & F_SUPP_B)
- oc |= (d<<23)|(c<<21)|(a<<16)|(x&0xffff);
- else
- oc |= (d<<23)|(c<<21)|(a<<16)|(b<<11)|xo;
- break;
-
- case T_DI: /* ADDI,ANDI,ORI */
- op = getintexp(gv,op,&d);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&a);
- if (!(op = check_comma(op)))
- break;
- op = getexp(gv,op,&x,2);
- if (flags & F_SWAP)
- swapops(&d,&a);
- checkrange(x,2,flags&F_SIGNED);
- if (d>31 || a>31)
- error(31); /* register operand out of range */
- else
- oc |= (d<<21)|(a<<16)|(x&0xffff);
- break;
-
- case T_X: /* ADDx, ANDx, DIVx, FMRx, .. */
- if (!(flags & F_SUPP_D))
- op = getintexp(gv,op,&d);
- if (!(flags & F_SUPP_A)) {
- if (op != oldop)
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&a);
- }
- if (!(flags & F_SUPP_B)) {
- if (op != oldop)
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&b);
- }
- if (flags & F_CRF_D)
- d <<= 2;
- if (flags & F_CRF_S)
- a <<= 2;
- if (flags & F_SWAP)
- swapops(&d,&a);
- if (d>31 || a>31 || b>31)
- error(31);
- else
- oc |= (d<<21)|(a<<16)|(b<<11)|xo;
- break;
-
- case T_A: /* FADDx, FSUBx, FMULx, FDIVx, .. */
- if (!(flags & F_SUPP_D))
- op = getintexp(gv,op,&d);
- if (!(flags & F_SUPP_A)) {
- if (op != oldop)
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&a);
- }
- if (!(flags & F_SUPP_C)) {
- if (op != oldop)
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&c);
- }
- if (!(flags & F_SUPP_B)) {
- if (op != oldop)
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&b);
- }
- if (flags & F_SWAP) { /* rldcl/rldcr rA,rS,rB,mb */
- swapops(&d,&a);
- swapops(&c,&b);
- }
- if (d>31 || a>31 || b>31 || c>31)
- error(31);
- else
- oc |= (d<<21)|(a<<16)|(b<<11)|(c<<6)|xo;
- break;
-
- case T_DD: /* LBZ, LHA, LZWU, STBU, STW, .. */
- op = getintexp(gv,op,&d);
- if (!(op = check_comma(op)))
- break;
- if (chk_regindir(op)) { /* rD,(rA) -> rD,0(rA) */
- exp.value = 0;
- exp.type = SYM_ABS;
- }
- else
- op = eval_expression(gv,&exp,op);
- if (*op++ == '(') {
- op = getintexp(gv,op,&a);
- if (*op++ != ')') {
- error(40); /* (rA) expected, after index expression */
- op = NULL;
- break;
- }
- if (exp.type != SYM_UNDEF) {
- switch (exp.type) {
- case SYM_RELOC:
- if (exp.reloctype == R_PPC_ADDR16_LO) { /* sym@l */
- x = makereloc(gv,&exp);
- signchk = FALSE;
- break;
- }
- else if (exp.symbol->relsect == gv->tocsect) {
- if ((int)a == gv->rtoc) { /* valid ref. to rtoc symbol */
- exp.reloctype = R_PPC_TOC16;
- x = makereloc(gv,&exp);
- break;
- }
- }
- error(46); /* symbol is not part of a base-relative section */
- break;
- case SYM_EXTERN: /* reference to external symbol */
- if (exp.reloctype != R_PPC_ADDR16_LO)
- exp.reloctype = R_PPC_ADDR16;
- else if ((int)a == gv->rtoc) /* ext. symbol via rtoc - */
- exp.reloctype = R_PPC_TOC16; /* might be a TOC16 ref. */
- x = makexref(gv,&exp,2);
- break;
- default: /* SYM_ABS */
- x = exp.value;
- break;
- }
- }
- else
- error(19); /* undefined symbol */
- }
- else { /* rD,v -> rD,v_off(rtoc) */
- if (exp.type != SYM_UNDEF) {
- switch (exp.type) {
- case SYM_RELOC:
- if (exp.symbol->relsect == gv->tocsect) {
- a = gv->rtoc;
- exp.reloctype = R_PPC_TOC16;
- x = makereloc(gv,&exp);
- break;
- }
- error(46);
- break;
- case SYM_EXTERN: /* we assume that this is a TOC16 reference */
- a = gv->rtoc;
- exp.reloctype = R_PPC_TOC16;
- x = makexref(gv,&exp,2);
- break;
- default:
- error(46);
- break;
- }
- }
- else
- error(19);
- }
- checkrange(x,2,signchk);
- if (d>31 || a>31)
- error(31); /* register operand out of range */
- else
- oc |= (d<<21)|(a<<16)|(x&0xffff);
- break;
-
- case T_DS: /* LD, LDU, LWA, STD , .. */
- op = getintexp(gv,op,&d);
- if (!(op = check_comma(op)))
- break;
- if (chk_regindir(op)) { /* rD,(rA) -> rD,0(rA) */
- exp.value = 0;
- exp.type = SYM_ABS;
- }
- else
- op = eval_expression(gv,&exp,op);
- if (*op++ == '(') {
- op = getintexp(gv,op,&a);
- if (*op++ != ')') {
- error(40); /* (rA) expected, after index expression */
- op = NULL;
- break;
- }
- if (exp.type != SYM_UNDEF) {
- switch (exp.type) {
- case SYM_RELOC:
- if (exp.reloctype == R_PPC_ADDR16_LO) { /* sym@l */
- x = makereloc(gv,&exp);
- signchk = FALSE;
- break;
- }
- else if (exp.symbol->relsect == gv->tocsect) {
- if ((int)a == gv->rtoc) { /* valid ref. to rtoc symbol */
- exp.reloctype = R_PPC_TOC16;
- x = makereloc(gv,&exp);
- break;
- }
- }
- error(46); /* symbol is not part of a base-relative section */
- break;
- case SYM_EXTERN: /* reference to external symbol */
- if (exp.reloctype != R_PPC_ADDR16_LO)
- exp.reloctype = R_PPC_ADDR16;
- else if ((int)a == gv->rtoc) /* ext. symbol via rtoc - */
- exp.reloctype = R_PPC_TOC16; /* might be a TOC16 ref. */
- x = makexref(gv,&exp,2);
- break;
- default: /* SYM_ABS */
- x = exp.value;
- break;
- }
- }
- else
- error(19); /* undefined symbol */
- }
- else { /* rD,v -> rD,v_off(rtoc) */
- if (exp.type != SYM_UNDEF) {
- switch (exp.type) {
- case SYM_RELOC:
- if (exp.symbol->relsect == gv->tocsect) {
- a = gv->rtoc;
- exp.reloctype = R_PPC_TOC16;
- x = makereloc(gv,&exp);
- break;
- }
- error(46);
- break;
- case SYM_EXTERN: /* we assume that this is a TOC16 reference */
- a = gv->rtoc;
- exp.reloctype = R_PPC_TOC16;
- x = makexref(gv,&exp,2);
- break;
- default:
- error(46);
- break;
- }
- }
- else
- error(19);
- }
- checkrange(x,2,signchk);
- if (x & 3)
- error(41); /* expression must be dividable by four */
- else if (d>31 || a>31)
- error(31); /* register operand out of range */
- else
- oc |= (d<<21)|(a<<16)|(x&0xfffc)|xo;
- break;
-
- case T_XSPR: /* MFSPR, MTSPR */
- op = getintexp(gv,op,&d);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&a);
- if (flags & F_SWAP)
- swapops(&d,&a);
- if (d>31 || a>0x3ff)
- error(31);
- else
- oc |= (d<<21)|((a&0x1f)<<16)|((a&0x3e0)<<6)|xo;
- break;
-
- case T_XCRM: /* MFCRF */
- op = getintexp(gv,op,&x);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&d);
- if (x > 0xff)
- error(42); /* invalid register field mask */
- else if (a>31)
- error(31);
- else
- oc |= (d<<21)|(x<<12)|xo;
- break;
-
- case T_XFL: /* MTFSF */
- op = getintexp(gv,op,&x);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&b);
- if (x > 0xff)
- error(42); /* invalid register field mask */
- else if (b>31)
- error(31);
- else
- oc |= (x<<17)|(b<<11)|xo;
- break;
-
- case T_IMM: /* MTFSFI */
- op = getintexp(gv,op,&d);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&b);
- if (b>15)
- error(36,"IMM"); /* operand field out of range */
- else if (d>7)
- error(31);
- else
- oc |= (d<<23)|(b<<12)|xo;
- break;
-
- case T_MD: /* RLDIC, .. */
- op = getintexp(gv,op,&a);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&d);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&b);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&c);
- if (b>63)
- error(36,"SH"); /* operand field out of range */
- else if (c>31)
- error(36,"MB/ME");
- else if (d>31 || a>31)
- error(31);
- else
- oc |= (d<<21)|(a<<16)|((b&0x1f)<<11)|(c<<6)|xo|((b&0x20)>>4);
- break;
-
- case T_M: /* RLWINM, RLWNM, RLWIMI, .. */
- op = getintexp(gv,op,&a);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&d);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&b);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&c);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&x);
- if (b>31)
- error(36,"SH/rB"); /* operand field out of range */
- else if (c>31)
- error(36,"MB");
- else if (c>31)
- error(36,"ME");
- else if (d>31 || a>31)
- error(31);
- else
- oc |= (d<<21)|(a<<16)|(b<<11)|(c<<6)|(x<<1)|xo;
- break;
-
- case T_XS: /* SRADIx */
- op = getintexp(gv,op,&a);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&d);
- if (!(op = check_comma(op)))
- break;
- op = getintexp(gv,op,&b);
- if (b>63)
- error(36,"SH"); /* operand field out of range */
- else if (d>31 || a>31)
- error(31);
- else
- oc |= (d<<21)|(a<<16)|((b&0x1f)<<11)|xo|((b&0x20)>>4);
- break;
- }
-
- store_word(gv,oc);
- if (op)
- checkEOL(op);
- }
-
-
- static void opt_far_branch(struct GlobalVars *gv,struct ParsedLine *pl,
- uint32 *bo,uint32 *bi,int32 *bd,char *lab)
- /* If branch destination is out of range, convert into a */
- /* B!cc $+8 / B combination. */
- {
- if (*bd>0x7fff || *bd<-0x8000) {
- struct ParsedLine *newpl = alloczero(sizeof(struct ParsedLine));
- char buf[STRBUFSIZE];
-
- move_symbols(gv,(uint32)gv->csect->pc,4); /* space for new instruction */
- *bo ^= 8; /* negate condition */
- *bd = 8; /* branch displacement = "$+8" */
- newpl->type = OT_INSTRUCTION;
- newpl->flags = pl->flags;
- newpl->narg = pl->narg;
- newpl->lineptr = pl->lineptr;
- newpl->opcode = (void *)search_instr(gv,"b");
- newpl->operand = lab;
- newpl->next = pl->next;
- /* free(pl->operand); @@@@ ? */
- sprintf(buf,"%d,%d,$+8",(int)*bo,(int)*bi);
- pl->branch_hint = -(pl->branch_hint);
- pl->operand = allocstring(buf);
- pl->next = newpl;
- }
- }
-
-
- static void swapops(uint32 *a,uint32 *b)
- {
- uint32 c = *a;
-
- *a = *b;
- *b = c;
- }
-
-
- static int count_operands(struct GlobalVars *gv,char *s)
- {
- int n=0;
-
- if (*s!=0 && *s!='#')
- do {
- n++;
- s = skipexpression(gv,s);
- }
- while (*s++ == ',');
- return (n);
- }
-
-
- static bool chk_regindir(char *s)
- /* "(...)\0" has a high probability to be a register-indirect */
- /* addressing mode. */
- {
- char c;
-
- if (*s++ == '(') {
- while (c = *s++) {
- if (c == '(')
- break; /* "((..." will never be register-indirect */
- if (c == ')') {
- s = skipspaces(s);
- if (*s == '\0') /* line ends directly after "(...)" ? */
- return (TRUE);
- else
- break;
- }
- }
- }
- return (FALSE);
- }
-
-
- static void move_symbols(struct GlobalVars *gv,uint32 so,int32 d)
- /* All relocatable symbols of current section with a greater */
- /* section-offset than 'so' are moved by delta 'd'. */
- {
- struct AlignPoint *ap = gv->csect->current_align;
- long g,a;
- unsigned long off;
-
- move_aligned_symbols_offset(gv,ap,so,d);
- while (ap = ap->next) {
- g = ap->gap - d;
- a = ap->val;
- off = ap->offset + ap->gap; /* current offset after alignment */
- ap->offset += d; /* new align-point offset */
- if (g<0 || g>=a) { /* need to move the alignment point? */
- g = a - (ap->offset & (a-1));
- d = ap->offset + g - off;
- ap->gap = g;
- move_aligned_symbols_all(gv,ap,d);
- }
- else { /* delta is neutralized by alignment gap */
- ap->gap = g;
- break;
- }
- }
- gv->csect->data = NULL; /* no further data is written to section */
- gv->anotherpass = TRUE; /* this requires another pass :( */
- }
-
-
- static void move_aligned_symbols_offset(struct GlobalVars *gv,
- struct AlignPoint *ap,
- uint32 so,int32 d)
- {
- struct Symbol *sym;
- struct Symbol **symtab = gv->symbols;
- int i;
-
- for (i=0; i<SYMHTABSIZE; i++) {
- sym = *symtab++;
- while (sym) {
- if (sym->type == SYM_RELOC)
- if (sym->alignpoint == ap)
- if (sym->value > so)
- sym->value += d;
- sym = sym->hash_chain;
- }
- }
- }
-
-
- static void move_aligned_symbols_all(struct GlobalVars *gv,
- struct AlignPoint *ap,int32 d)
- {
- struct Symbol *sym;
- struct Symbol **symtab = gv->symbols;
- int i;
-
- for (i=0; i<SYMHTABSIZE; i++) {
- sym = *symtab++;
- while (sym) {
- if (sym->type==SYM_RELOC && sym->alignpoint==ap)
- sym->value += d;
- sym = sym->hash_chain;
- }
- }
- }
-
-
- char *check_comma(char *s)
- {
- s = skipspaces(s);
- if (*s++ != ',') {
- error(27); /* instruction has too few operands */
- return (NULL);
- }
- s = skipspaces(s);
- return (s);
- }
-
-
- void pcadd(struct GlobalVars *gv,unsigned long offset)
- {
- gv->csect->pc += offset;
- }
-
-
- void store_byte(struct GlobalVars *gv,uint8 x)
- {
- struct Section *sec = gv->csect;
- uint8 *d;
-
- if (d = (uint8 *)sec->data) {
- *d++ = x;
- sec->data = d;
- }
- sec->pc += 1;
- gv->lcsym->value += 1;
- }
-
-
- void store_half(struct GlobalVars *gv,uint16 x)
- {
- struct Section *sec = gv->csect;
- uint16 *d;
-
- if (d = (uint16 *)sec->data) {
- *d++ = ECVH(x);
- sec->data = d;
- }
- sec->pc += 2;
- gv->lcsym->value += 2;
- }
-
-
- void store_word(struct GlobalVars *gv,uint32 x)
- {
- struct Section *sec = gv->csect;
- uint32 *d;
-
- if (d = (uint32 *)sec->data) {
- *d++ = ECVW(x);
- sec->data = d;
- }
- sec->pc += 4;
- gv->lcsym->value += 4;
- }
-
-
- void store_float(struct GlobalVars *gv,double x)
- {
- struct Section *sec = gv->csect;
- float *d;
-
- if (d = (float *)sec->data) {
- *d++ = (float)x;
- sec->data = d;
- }
- sec->pc += 4;
- gv->lcsym->value += 4;
- }
-
-
- void store_double(struct GlobalVars *gv,double x)
- {
- struct Section *sec = gv->csect;
- double *d;
-
- if (d = (double *)sec->data) {
- *d++ = x;
- sec->data = d;
- }
- sec->pc += 8;
- gv->lcsym->value += 8;
- }
-
-
- void store_space(struct GlobalVars *gv,unsigned long n)
- {
- struct Section *sec = gv->csect;
- uint8 *d;
-
- sec->pc += n;
- gv->lcsym->value += n;
- if (d = (uint8 *)sec->data) {
- while (n--)
- *d++ = 0;
- sec->data = d;
- }
- }
-