From 8edbff9795ef559eaefefefdf1760f57b3a926c8 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 15 Jan 2017 00:15:01 +0100 Subject: [PATCH 1/8] Add assembler support for fixing up arbitrary oris/addi pairs of instructions; this should allow oris/lwz constant value loads, which will save an opcode. --- mach/powerpc/as/mach2.c | 3 ++ mach/powerpc/as/mach3.c | 5 ++- mach/powerpc/as/mach4.c | 88 +++++++++++++++++++++++++++++------------ mach/powerpc/as/mach5.c | 1 - mach/powerpc/ncg/table | 24 ++++++++--- util/led/relocate.c | 19 +++++---- 6 files changed, 97 insertions(+), 43 deletions(-) diff --git a/mach/powerpc/as/mach2.c b/mach/powerpc/as/mach2.c index 480c5faa3..a07f21b99 100644 --- a/mach/powerpc/as/mach2.c +++ b/mach/powerpc/as/mach2.c @@ -84,6 +84,9 @@ %token OP_LA %token OP_LI32 +%token OP_POWERPC_FIXUP +%token OP_HI OP_LO + /* Other token types */ %type c diff --git a/mach/powerpc/as/mach3.c b/mach/powerpc/as/mach3.c index 0f0bfdae7..62ed20471 100644 --- a/mach/powerpc/as/mach3.c +++ b/mach/powerpc/as/mach3.c @@ -102,6 +102,9 @@ 0, OP_LA, 0, "la", 0, OP_LA, 0, "li", 0, OP_RS_RA_RA_C, 31<<26 | 444<<1, "mr", +0, OP_POWERPC_FIXUP, 0, ".powerpcfixup", +0, OP_HI, 0, "hi", +0, OP_LO, 0, "lo", /* Branch processor instructions (page 20) */ @@ -270,7 +273,7 @@ 0, OP_RS_RA_SH_ME6_SH_C, 30<<26 | 1<<2, "rldicr", 0, OP_RS_RA_SH_MB6_SH_C, 30<<26 | 2<<2, "rldic", 0, OP_RS_RA_SH_MB5_ME5_C, 21<<26, "rlwinm", -0, OP_RS_RA_RB_MB6_C, 30<<26 | 8<<1, "rldcl", +0, OP_RS_RA_RB_MB6_C, 30<<26 | 8<<1, "rldcl", 0, OP_RS_RA_RB_ME6_C, 30<<26 | 9<<1, "rldcr", 0, OP_RS_RA_RB_MB5_ME5_C, 23<<26, "rlwnm", 0, OP_RS_RA_SH_MB6_SH_C, 30<<26 | 3<<2, "rldimi", diff --git a/mach/powerpc/as/mach4.c b/mach/powerpc/as/mach4.c index e1fb3fdf0..d9e4b0371 100644 --- a/mach/powerpc/as/mach4.c +++ b/mach/powerpc/as/mach4.c @@ -19,9 +19,9 @@ operation | OP_FRS_RA_D FPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); } | OP_FRS_RA_RB FPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } | OP_FRT_FRA_FRB_C c FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); } - | OP_FRT_FRA_FRC_FRB_C c FPR ',' FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($9<<11) | ($7<<6)); } + | OP_FRT_FRA_FRC_FRB_C c FPR ',' FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($9<<11) | ($7<<6)); } | OP_FRT_FRA_FRC_C c FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<6)); } - | OP_FRT_FRB_C c FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<11)); } + | OP_FRT_FRB_C c FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<11)); } | OP_FRT_RA_D FPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); } | OP_FRT_RA_RB FPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } | OP_FRT_C c FPR { emit4($1 | $2 | ($3<<21)); } @@ -40,15 +40,15 @@ operation | OP_RS_RA_D GPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); } | OP_RS_RA_DS GPR ',' ds '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); } | OP_RS_RA_NB GPR ',' GPR ',' nb { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } - | OP_RS_RA_UI GPR ',' GPR ',' e16 { emit4($1 | ($4<<21) | ($2<<16) | $6); } - | OP_RS_RA_UI_CC C GPR ',' GPR ',' e16 { emit4($1 | ($5<<21) | ($3<<16) | $7); } + | OP_RS_RA_UI GPR ',' GPR ',' e16 { emit4($1 | ($4<<21) | ($2<<16) | $6); } + | OP_RS_RA_UI_CC C GPR ',' GPR ',' e16 { emit4($1 | ($5<<21) | ($3<<16) | $7); } | OP_RS_RA_RB GPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } | OP_RS_RA_RB_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); } | OP_RS_RA_RA_C c GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($5<<11)); } - | OP_RS_RA_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); } + | OP_RS_RA_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); } | OP_RS_RA_RB_MB6_C c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); } | OP_RS_RA_RB_ME6_C c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); } - | OP_RS_RA_SH_MB5_ME5_C c GPR ',' GPR ',' u5 ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); } + | OP_RS_RA_SH_MB5_ME5_C c GPR ',' GPR ',' u5 ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); } | OP_RS_RA_SH_MB6_SH_C c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); } | OP_RS_RA_SH_ME6_SH_C c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); } | OP_RS_RA_SH5_C c GPR ',' GPR ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); } @@ -60,13 +60,14 @@ operation | OP_LIA lia { emit4($1 | $2); } | OP_LIL lil { emit4($1 | $2); } | OP_LI32 li32 /* emitted in subrule */ + | OP_POWERPC_FIXUP powerpcfixup /* emitted in subrule */ ; c : /* nothing */ { $$ = 0; } | C { $$ = 1; } ; - + e16 : absexp { @@ -75,8 +76,34 @@ e16 serror("16-bit value out of range"); $$ = (uint16_t) $1; } + | OP_HI expr + { + /* If this is a symbol reference, discard the symbol and keep only the + * offset part. */ + quad type = $2.typ & S_TYP; + quad val = $2.val; + + /* If the assembler stored a symbol for relocation later, we need to + * abandon it (because we're not going to generate a relocation). */ + if (type != S_ABS) + relonami = 0; + + $$ = ((quad)val) >> 16; + } + | OP_LO expr + { + quad type = $2.typ & S_TYP; + quad val = $2.val; + + /* If the assembler stored a symbol for relocation later, we need to + * abandon it (because we're not going to generate a relocation). */ + if (type != S_ABS) + relonami = 0; + + $$ = val & 0xffff; + } ; - + u8 : absexp { @@ -85,7 +112,7 @@ u8 $$ = $1; } ; - + u7 : absexp { @@ -94,7 +121,7 @@ u7 $$ = $1; } ; - + u6 : absexp { @@ -103,7 +130,7 @@ u6 $$ = $1; } ; - + u5 : absexp { @@ -112,7 +139,7 @@ u5 $$ = $1; } ; - + u4 : absexp { @@ -121,7 +148,7 @@ u4 $$ = $1; } ; - + u1 : absexp { @@ -130,7 +157,7 @@ u1 $$ = $1; } ; - + u2 : absexp { @@ -139,7 +166,7 @@ u2 $$ = $1; } ; - + ds : e16 { @@ -148,26 +175,26 @@ ds $$ = $1; } ; - + nb : absexp { if (($1 < 1) || ($1 > 32)) serror("register count must be in the range 1..32"); - + if ($1 == 32) $$ = 0; else - $$ = $1; + $$ = $1; } ; - + bdl : expr { int dist = $1.val - DOTVAL; fit(fitx(dist, 25)); - + if (dist & 0x3) serror("jump targets must be 4-aligned"); @@ -183,7 +210,7 @@ bda { int target = $1.val; fit(fitx(target, 16)); - + if (target & 0x3) serror("jump targets must be 4-aligned"); @@ -193,7 +220,7 @@ bda $$ = target & 0xFFFD; } ; - + li32 : GPR ',' expr { @@ -215,7 +242,7 @@ lil { int dist = $1.val - DOTVAL; fit(fitx(dist, 26)); - + if (dist & 0x3) serror("jump targets must be 4-aligned"); @@ -223,13 +250,13 @@ lil $$ = dist & 0x03FFFFFD; } ; - + lia : expr { int target = $1.val; fit(fitx(target, 26)); - + if (target & 0x3) serror("jump targets must be 4-aligned"); @@ -248,3 +275,14 @@ spr_num $$ = ($1 >> 5) | (($1 & 0x1f) << 5); } ; + +powerpcfixup + : expr + { + quad type = $1.typ & S_TYP; + quad val = $1.val; + if (type == S_ABS) + serror(".powerpcfixup is useless on absolute values"); + newrelo($1.typ, RELOPPC | FIXUPFLAGS); + } + ; diff --git a/mach/powerpc/as/mach5.c b/mach/powerpc/as/mach5.c index 998cd8d9c..5b8eb9167 100644 --- a/mach/powerpc/as/mach5.c +++ b/mach/powerpc/as/mach5.c @@ -2,4 +2,3 @@ * $Source$ * $State$ */ - diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index 52f335c3d..29353a259 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -169,11 +169,14 @@ TOKENS /* Used only in instruction descriptions (to generate the correct syntax). */ GPRINDIRECT = { GPR reg; INT off; } 4 off "(" reg ")". + GPRINDIRECT_OFFSET_LO = { GPR reg; ADDR adr; } 4 "lo [" adr "](" reg ")". CONST = { INT val; } 4 val. /* Primitives */ LABEL = { ADDR adr; } 4 adr. + LABEL_OFFSET_HI = { ADDR adr; } 4 "hi " adr. + LABEL_OFFSET_LO = { ADDR adr; } 4 "lo " adr. LOCAL = { INT off; } 4. /* Allows us to use regvar() to refer to registers */ @@ -282,7 +285,7 @@ INSTRUCTIONS add GPR:wo, GPR:ro, GPR:ro. addX "add." GPR:wo, GPR:ro, GPR:ro. addi GPR:wo, GPR:ro, CONST:ro. - addis GPR:wo, GPR:ro, CONST:ro. + addis GPR:wo, GPR:ro, CONST+LABEL_OFFSET_HI:ro. and GPR:wo, GPR:ro, GPR:ro. andc GPR:wo, GPR:ro, GPR:ro. andiX "andi." GPR:wo:cc, GPR:ro, CONST:ro. @@ -329,10 +332,9 @@ INSTRUCTIONS lhz GPR:wo, GPRINDIRECT:ro cost(4, 3). lhzx GPR:wo, GPR:ro, GPR:ro cost(4, 3). li32 GPR:wo, CONST:ro cost(8, 2). - li32 GPR:wo, LABEL:ro cost(8, 2). lwzu GPR:wo, GPRINDIRECT:ro cost(4, 3). lwzx GPR:wo, GPR:ro, GPR:ro cost(4, 3). - lwz GPR:wo, GPRINDIRECT:ro cost(4, 3). + lwz GPR:wo, GPRINDIRECT+GPRINDIRECT_OFFSET_LO:ro cost(4, 3). nand GPR:wo, GPR:ro, GPR:ro. neg GPR:wo, GPR:ro. nor GPR:wo, GPR:ro, GPR:ro. @@ -342,7 +344,7 @@ INSTRUCTIONS mtspr SPR:wo, GPR:ro cost(4, 2). or GPR:wo, GPR:ro, GPR:ro. orc GPR:wo, GPR:ro, GPR:ro. - ori GPR:wo, GPR:ro, CONST:ro. + ori GPR:wo, GPR:ro, CONST+LABEL_OFFSET_LO:ro. oris GPR:wo, GPR:ro, CONST:ro. orX "or." GPR:wo:cc, GPR:ro, GPR:ro. rlwinm GPR:wo, GPR:ro, CONST:ro, CONST:ro, CONST:ro. @@ -368,7 +370,8 @@ INSTRUCTIONS xori GPR:wo, GPR:ro, CONST:ro. xoris GPR:wo, GPR:ro, CONST:ro. - comment "!" LABEL:ro cost(0, 0). + fixup ".powerpcfixup" LABEL:ro. + comment "!" LABEL:ro cost(0, 0). @@ -405,7 +408,9 @@ MOVES from LABEL to GPR gen COMMENT("move LABEL->GPR") - li32 %2, {LABEL, %1.adr} + fixup {LABEL, %1.adr} + addis %2, R0, {LABEL_OFFSET_HI, %1.adr} + ori %2, %2, {LABEL_OFFSET_LO, %1.adr} /* Sign extension */ @@ -1142,6 +1147,13 @@ PATTERNS yields {IND_RC_H, %1.reg, %1.off} pat loi $1==INT32 /* Load word indirect */ + with LABEL + uses REG + gen + fixup {LABEL, %1.adr} + addis %a, R0, {LABEL_OFFSET_HI, %1.adr} + lwz %a, {GPRINDIRECT_OFFSET_LO, %a, %1.adr} + yields %a with GPR yields {IND_RC_W, %1, 0} with SUM_RC diff --git a/util/led/relocate.c b/util/led/relocate.c index c72965e75..02b0be381 100644 --- a/util/led/relocate.c +++ b/util/led/relocate.c @@ -119,14 +119,13 @@ static uint32_t get_powerpc_valu(char* addr, uint16_t type) /* branch instruction */ return opcode1 & 0x03fffffd; } - else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && - ((opcode2 & 0xfc000000) == 0x60000000)) + else { - /* addis / ori instruction pair */ + /* If it's not a branch, we're just going to assume that the user + * knows what they're doing and this is a addis/ori pair (or + * compatible). */ return ((opcode1 & 0xffff) << 16) | (opcode2 & 0xffff); } - - assert(0 && "unrecognised PowerPC instruction"); } /* @@ -260,17 +259,17 @@ static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type) i |= value & 0x03fffffd; write4(i, addr, type); } - else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && - ((opcode2 & 0xfc000000) == 0x60000000)) + else { + /* If it's not a branch, we're just going to assume that the user + * knows what they're doing and this is a addis/ori pair (or + * compatible). */ uint16_t hi = value >> 16; uint16_t lo = value & 0xffff; write4((opcode1 & 0xffff0000) | hi, addr+0, type); write4((opcode2 & 0xffff0000) | lo, addr+4, type); } - else - assert(0 && "unrecognised PowerPC instruction"); } /* @@ -339,7 +338,7 @@ addrelo(relo, names, valu_out) extern int hash(); extern struct outname *searchname(); extern unsigned indexof(); - extern struct outhead outhead; + extern struct outhead outhead; name = searchname(local->on_mptr, hash(local->on_mptr)); if (name == (struct outname *)0) From 3c0bc205fcf8e38cf4fc6658412ee254ac2cf248 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 15 Jan 2017 10:21:02 +0100 Subject: [PATCH 2/8] Update the hi/lo syntax to be a bit more standard. --- mach/powerpc/as/mach3.c | 4 ++-- mach/powerpc/as/mach4.c | 12 ++++++------ mach/powerpc/ncg/table | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mach/powerpc/as/mach3.c b/mach/powerpc/as/mach3.c index 62ed20471..a40e2495d 100644 --- a/mach/powerpc/as/mach3.c +++ b/mach/powerpc/as/mach3.c @@ -103,8 +103,8 @@ 0, OP_LA, 0, "li", 0, OP_RS_RA_RA_C, 31<<26 | 444<<1, "mr", 0, OP_POWERPC_FIXUP, 0, ".powerpcfixup", -0, OP_HI, 0, "hi", -0, OP_LO, 0, "lo", +0, OP_HI, 0, "ha16", +0, OP_LO, 0, "lo16", /* Branch processor instructions (page 20) */ diff --git a/mach/powerpc/as/mach4.c b/mach/powerpc/as/mach4.c index d9e4b0371..016877576 100644 --- a/mach/powerpc/as/mach4.c +++ b/mach/powerpc/as/mach4.c @@ -76,12 +76,12 @@ e16 serror("16-bit value out of range"); $$ = (uint16_t) $1; } - | OP_HI expr + | OP_HI ASC_LPAR expr ASC_RPAR { /* If this is a symbol reference, discard the symbol and keep only the * offset part. */ - quad type = $2.typ & S_TYP; - quad val = $2.val; + quad type = $3.typ & S_TYP; + quad val = $3.val; /* If the assembler stored a symbol for relocation later, we need to * abandon it (because we're not going to generate a relocation). */ @@ -90,10 +90,10 @@ e16 $$ = ((quad)val) >> 16; } - | OP_LO expr + | OP_LO ASC_LPAR expr ASC_RPAR { - quad type = $2.typ & S_TYP; - quad val = $2.val; + quad type = $3.typ & S_TYP; + quad val = $3.val; /* If the assembler stored a symbol for relocation later, we need to * abandon it (because we're not going to generate a relocation). */ diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index 29353a259..a907e4294 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -169,14 +169,14 @@ TOKENS /* Used only in instruction descriptions (to generate the correct syntax). */ GPRINDIRECT = { GPR reg; INT off; } 4 off "(" reg ")". - GPRINDIRECT_OFFSET_LO = { GPR reg; ADDR adr; } 4 "lo [" adr "](" reg ")". + GPRINDIRECT_OFFSET_LO = { GPR reg; ADDR adr; } 4 "lo16[" adr "](" reg ")". CONST = { INT val; } 4 val. /* Primitives */ LABEL = { ADDR adr; } 4 adr. - LABEL_OFFSET_HI = { ADDR adr; } 4 "hi " adr. - LABEL_OFFSET_LO = { ADDR adr; } 4 "lo " adr. + LABEL_OFFSET_HI = { ADDR adr; } 4 "ha16[" adr "]". + LABEL_OFFSET_LO = { ADDR adr; } 4 "lo16[" adr "]". LOCAL = { INT off; } 4. /* Allows us to use regvar() to refer to registers */ From 14aab2120463064cbd196cf9fc39e77ed419a163 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 15 Jan 2017 10:31:20 +0100 Subject: [PATCH 3/8] Revert change; addis/ori requires different handling to addis/lwz due to ori's payload being unsigned while lwz's payload is signed. --- util/led/relocate.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/util/led/relocate.c b/util/led/relocate.c index 02b0be381..9e5c92b7c 100644 --- a/util/led/relocate.c +++ b/util/led/relocate.c @@ -119,13 +119,14 @@ static uint32_t get_powerpc_valu(char* addr, uint16_t type) /* branch instruction */ return opcode1 & 0x03fffffd; } - else + else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && + ((opcode2 & 0xfc000000) == 0x60000000)) { - /* If it's not a branch, we're just going to assume that the user - * knows what they're doing and this is a addis/ori pair (or - * compatible). */ + /* addis / ori instruction pair */ return ((opcode1 & 0xffff) << 16) | (opcode2 & 0xffff); } + + assert(0 && "unrecognised PowerPC instruction"); } /* @@ -259,17 +260,17 @@ static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type) i |= value & 0x03fffffd; write4(i, addr, type); } - else + else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && + ((opcode2 & 0xfc000000) == 0x60000000)) { - /* If it's not a branch, we're just going to assume that the user - * knows what they're doing and this is a addis/ori pair (or - * compatible). */ uint16_t hi = value >> 16; uint16_t lo = value & 0xffff; write4((opcode1 & 0xffff0000) | hi, addr+0, type); write4((opcode2 & 0xffff0000) | lo, addr+4, type); } + else + assert(0 && "unrecognised PowerPC instruction"); } /* From f80acfe9f5cdbdea954df4d553fd347129b34038 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 15 Jan 2017 11:51:37 +0100 Subject: [PATCH 4/8] Signed vs unsigned lower halves of powerpc fixups are now handled by having two assembler directives, ha16() and has16(), for the upper half; has16() applies the sign adjustment. .powerpcfixup is now gone, as we generate the relocation in ha*() instead. Add special logic to the linker for undoing and redoing the sign adjustment when reading/writing fixups. Tests still pass. --- mach/powerpc/as/mach1.c | 4 +++ mach/powerpc/as/mach2.c | 2 +- mach/powerpc/as/mach3.c | 4 +-- mach/powerpc/as/mach4.c | 30 +++------------------- mach/powerpc/as/mach5.c | 42 ++++++++++++++++++++++++++++--- mach/powerpc/ncg/table | 12 ++++----- util/led/const.h | 2 -- util/led/debug.h | 2 ++ util/led/relocate.c | 55 +++++++++++++++++++++++++++++++++++++++-- 9 files changed, 108 insertions(+), 45 deletions(-) diff --git a/mach/powerpc/as/mach1.c b/mach/powerpc/as/mach1.c index 998cd8d9c..8cf9ca282 100644 --- a/mach/powerpc/as/mach1.c +++ b/mach/powerpc/as/mach1.c @@ -3,3 +3,7 @@ * $State$ */ +#include + +extern quad emit_ha(struct expr_t* expr, bool is_signed); +extern quad emit_lo(struct expr_t* expr); diff --git a/mach/powerpc/as/mach2.c b/mach/powerpc/as/mach2.c index a07f21b99..f64d148cd 100644 --- a/mach/powerpc/as/mach2.c +++ b/mach/powerpc/as/mach2.c @@ -85,7 +85,7 @@ %token OP_LI32 %token OP_POWERPC_FIXUP -%token OP_HI OP_LO +%token OP_HA OP_HAS OP_LO /* Other token types */ diff --git a/mach/powerpc/as/mach3.c b/mach/powerpc/as/mach3.c index a40e2495d..74415aa9f 100644 --- a/mach/powerpc/as/mach3.c +++ b/mach/powerpc/as/mach3.c @@ -102,8 +102,8 @@ 0, OP_LA, 0, "la", 0, OP_LA, 0, "li", 0, OP_RS_RA_RA_C, 31<<26 | 444<<1, "mr", -0, OP_POWERPC_FIXUP, 0, ".powerpcfixup", -0, OP_HI, 0, "ha16", +0, OP_HA, 0, "ha16", +0, OP_HAS, 0, "has16", 0, OP_LO, 0, "lo16", /* Branch processor instructions (page 20) */ diff --git a/mach/powerpc/as/mach4.c b/mach/powerpc/as/mach4.c index 016877576..bb6f5163b 100644 --- a/mach/powerpc/as/mach4.c +++ b/mach/powerpc/as/mach4.c @@ -60,7 +60,6 @@ operation | OP_LIA lia { emit4($1 | $2); } | OP_LIL lil { emit4($1 | $2); } | OP_LI32 li32 /* emitted in subrule */ - | OP_POWERPC_FIXUP powerpcfixup /* emitted in subrule */ ; c @@ -76,32 +75,9 @@ e16 serror("16-bit value out of range"); $$ = (uint16_t) $1; } - | OP_HI ASC_LPAR expr ASC_RPAR - { - /* If this is a symbol reference, discard the symbol and keep only the - * offset part. */ - quad type = $3.typ & S_TYP; - quad val = $3.val; - - /* If the assembler stored a symbol for relocation later, we need to - * abandon it (because we're not going to generate a relocation). */ - if (type != S_ABS) - relonami = 0; - - $$ = ((quad)val) >> 16; - } - | OP_LO ASC_LPAR expr ASC_RPAR - { - quad type = $3.typ & S_TYP; - quad val = $3.val; - - /* If the assembler stored a symbol for relocation later, we need to - * abandon it (because we're not going to generate a relocation). */ - if (type != S_ABS) - relonami = 0; - - $$ = val & 0xffff; - } + | OP_HA ASC_LPAR expr ASC_RPAR { $$ = emit_ha(&$3, false); } + | OP_HAS ASC_LPAR expr ASC_RPAR { $$ = emit_ha(&$3, true); } + | OP_LO ASC_LPAR expr ASC_RPAR { $$ = emit_lo(&$3); } ; u8 diff --git a/mach/powerpc/as/mach5.c b/mach/powerpc/as/mach5.c index 5b8eb9167..a8e4cd043 100644 --- a/mach/powerpc/as/mach5.c +++ b/mach/powerpc/as/mach5.c @@ -1,4 +1,38 @@ -/* - * $Source$ - * $State$ - */ + +quad emit_ha(struct expr_t* expr, bool is_signed) +{ + /* If this is a symbol reference, discard the symbol and keep only the + * offset part. */ + quad type = expr->typ & S_TYP; + quad val = expr->val; + uint16_t hi = val >> 16; + uint16_t lo = val & 0xffff; + + if (type != S_ABS) + newrelo(expr->typ, RELOPPC | FIXUPFLAGS); + + /* If the low half of this relocation is going to be a memory operation, + * then it'll be treated as a signed value. That means that values greater + * than 0x7fff will cause the high word to have 1 subtracted from it; so + * we apply an adjustment here. + */ + + if (is_signed && (lo > 0x7fff)) + hi++; + + return hi; +} + +quad emit_lo(struct expr_t* expr) +{ + quad type = expr->typ & S_TYP; + quad val = expr->val; + + /* If the assembler stored a symbol for relocation later, we need to + * abandon it (because the relocation was generated by emit_ha). */ + + if (type != S_ABS) + relonami = 0; + + return val & 0xffff; +} diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index a907e4294..d37bed8f0 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -175,7 +175,8 @@ TOKENS /* Primitives */ LABEL = { ADDR adr; } 4 adr. - LABEL_OFFSET_HI = { ADDR adr; } 4 "ha16[" adr "]". + LABEL_OFFSET_HA = { ADDR adr; } 4 "ha16[" adr "]". + LABEL_OFFSET_HAS = { ADDR adr; } 4 "has16[" adr "]". LABEL_OFFSET_LO = { ADDR adr; } 4 "lo16[" adr "]". LOCAL = { INT off; } 4. @@ -285,7 +286,7 @@ INSTRUCTIONS add GPR:wo, GPR:ro, GPR:ro. addX "add." GPR:wo, GPR:ro, GPR:ro. addi GPR:wo, GPR:ro, CONST:ro. - addis GPR:wo, GPR:ro, CONST+LABEL_OFFSET_HI:ro. + addis GPR:wo, GPR:ro, CONST+LABEL_OFFSET_HA+LABEL_OFFSET_HAS:ro. and GPR:wo, GPR:ro, GPR:ro. andc GPR:wo, GPR:ro, GPR:ro. andiX "andi." GPR:wo:cc, GPR:ro, CONST:ro. @@ -370,7 +371,6 @@ INSTRUCTIONS xori GPR:wo, GPR:ro, CONST:ro. xoris GPR:wo, GPR:ro, CONST:ro. - fixup ".powerpcfixup" LABEL:ro. comment "!" LABEL:ro cost(0, 0). @@ -408,8 +408,7 @@ MOVES from LABEL to GPR gen COMMENT("move LABEL->GPR") - fixup {LABEL, %1.adr} - addis %2, R0, {LABEL_OFFSET_HI, %1.adr} + addis %2, R0, {LABEL_OFFSET_HA, %1.adr} ori %2, %2, {LABEL_OFFSET_LO, %1.adr} /* Sign extension */ @@ -1150,8 +1149,7 @@ PATTERNS with LABEL uses REG gen - fixup {LABEL, %1.adr} - addis %a, R0, {LABEL_OFFSET_HI, %1.adr} + addis %a, R0, {LABEL_OFFSET_HAS, %1.adr} lwz %a, {GPRINDIRECT_OFFSET_LO, %a, %1.adr} yields %a with GPR diff --git a/util/led/const.h b/util/led/const.h index 40ad395b5..d2d27f51a 100644 --- a/util/led/const.h +++ b/util/led/const.h @@ -4,8 +4,6 @@ */ /* $Id$ */ -typedef int bool; - #define FALSE 0 #define TRUE 1 diff --git a/util/led/debug.h b/util/led/debug.h index 0e493185d..715409d25 100644 --- a/util/led/debug.h +++ b/util/led/debug.h @@ -17,3 +17,5 @@ extern int DEB; extern int Verbose; #define verbose(s, a1, a2, a3, a4) (Verbose && do_verbose(s, a1, a2, a3, a4)) + +extern void fatal(char* format, ...); diff --git a/util/led/relocate.c b/util/led/relocate.c index 9e5c92b7c..613a0afa7 100644 --- a/util/led/relocate.c +++ b/util/led/relocate.c @@ -9,6 +9,7 @@ static char rcsid[] = "$Id$"; #include #include #include +#include #include #include "out.h" #include "const.h" @@ -104,6 +105,24 @@ static uint32_t get_vc4_valu(char* addr) assert(0 && "unrecognised VC4 instruction"); } +static bool is_powerpc_memory_op(uint32_t opcode) +{ + /* Tests for any PowerPC memory indirection instruction where the payload + * is a *signed* 16-bit value. */ + switch ((opcode & 0xfc000000) >> 26) + { + case 34: /* lbz */ + case 40: /* lhz */ + case 32: /* lwz */ + case 38: /* stb */ + case 44: /* sth */ + case 36: /* stw */ + return true; + } + + return false; +} + /* PowerPC fixups are complex as we need to patch up to the next two * instructions in one of several different ways, depending on what the * instructions area. @@ -125,8 +144,23 @@ static uint32_t get_powerpc_valu(char* addr, uint16_t type) /* addis / ori instruction pair */ return ((opcode1 & 0xffff) << 16) | (opcode2 & 0xffff); } + else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && + is_powerpc_memory_op(opcode2)) + { + /* addis / memoryop instruction pair */ + uint16_t hi = opcode1 & 0xffff; + uint16_t lo = opcode2 & 0xffff; - assert(0 && "unrecognised PowerPC instruction"); + /* Undo the sign adjustment (see mach/powerpc/as/mach5.c). */ + + if (lo > 0x7fff) + hi--; + + return ((hi << 16) | lo); + } + + fatal("Don't know how to read from PowerPC fixup on instructions 0x%08x+0x%08x", + opcode1, opcode2); } /* @@ -269,8 +303,25 @@ static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type) write4((opcode1 & 0xffff0000) | hi, addr+0, type); write4((opcode2 & 0xffff0000) | lo, addr+4, type); } + else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && + is_powerpc_memory_op(opcode2)) + { + /* addis / memoryop instruction pair */ + uint16_t hi = value >> 16; + uint16_t lo = value & 0xffff; + + /* Apply the sign adjustment (see mach/powerpc/as/mach5.c). */ + + if (lo > 0x7fff) + hi++; + + write4((opcode1 & 0xffff0000) | hi, addr+0, type); + write4((opcode2 & 0xffff0000) | lo, addr+4, type); + } + else - assert(0 && "unrecognised PowerPC instruction"); + fatal("Don't know how to write a PowerPC fixup to instructions 0x%08x+0x%08x", + opcode1, opcode2); } /* From 9a346c382d74e07471b7025d6aa8364dc00bbe6d Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 15 Jan 2017 11:59:33 +0100 Subject: [PATCH 5/8] Turns out Apple's hi16/ha16 exactly match my ha16/has16, so renamed accordingly. (Memo to self: read the docs *before* doing the work.) --- mach/powerpc/as/mach1.c | 2 +- mach/powerpc/as/mach2.c | 2 +- mach/powerpc/as/mach3.c | 4 ++-- mach/powerpc/as/mach4.c | 4 ++-- mach/powerpc/as/mach5.c | 2 +- mach/powerpc/ncg/table | 8 ++++---- util/led/relocate.c | 1 + 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/mach/powerpc/as/mach1.c b/mach/powerpc/as/mach1.c index 8cf9ca282..c1651fcfe 100644 --- a/mach/powerpc/as/mach1.c +++ b/mach/powerpc/as/mach1.c @@ -5,5 +5,5 @@ #include -extern quad emit_ha(struct expr_t* expr, bool is_signed); +extern quad emit_hi(struct expr_t* expr, bool is_signed); extern quad emit_lo(struct expr_t* expr); diff --git a/mach/powerpc/as/mach2.c b/mach/powerpc/as/mach2.c index f64d148cd..3ecaf10cf 100644 --- a/mach/powerpc/as/mach2.c +++ b/mach/powerpc/as/mach2.c @@ -85,7 +85,7 @@ %token OP_LI32 %token OP_POWERPC_FIXUP -%token OP_HA OP_HAS OP_LO +%token OP_HI OP_HA OP_LO /* Other token types */ diff --git a/mach/powerpc/as/mach3.c b/mach/powerpc/as/mach3.c index 74415aa9f..724ba7312 100644 --- a/mach/powerpc/as/mach3.c +++ b/mach/powerpc/as/mach3.c @@ -102,8 +102,8 @@ 0, OP_LA, 0, "la", 0, OP_LA, 0, "li", 0, OP_RS_RA_RA_C, 31<<26 | 444<<1, "mr", -0, OP_HA, 0, "ha16", -0, OP_HAS, 0, "has16", +0, OP_HI, 0, "hi16", +0, OP_HA, 0, "ha16", 0, OP_LO, 0, "lo16", /* Branch processor instructions (page 20) */ diff --git a/mach/powerpc/as/mach4.c b/mach/powerpc/as/mach4.c index bb6f5163b..1ad180de4 100644 --- a/mach/powerpc/as/mach4.c +++ b/mach/powerpc/as/mach4.c @@ -75,8 +75,8 @@ e16 serror("16-bit value out of range"); $$ = (uint16_t) $1; } - | OP_HA ASC_LPAR expr ASC_RPAR { $$ = emit_ha(&$3, false); } - | OP_HAS ASC_LPAR expr ASC_RPAR { $$ = emit_ha(&$3, true); } + | OP_HI ASC_LPAR expr ASC_RPAR { $$ = emit_hi(&$3, false); } + | OP_HA ASC_LPAR expr ASC_RPAR { $$ = emit_hi(&$3, true); } | OP_LO ASC_LPAR expr ASC_RPAR { $$ = emit_lo(&$3); } ; diff --git a/mach/powerpc/as/mach5.c b/mach/powerpc/as/mach5.c index a8e4cd043..e3e23f272 100644 --- a/mach/powerpc/as/mach5.c +++ b/mach/powerpc/as/mach5.c @@ -1,5 +1,5 @@ -quad emit_ha(struct expr_t* expr, bool is_signed) +quad emit_hi(struct expr_t* expr, bool is_signed) { /* If this is a symbol reference, discard the symbol and keep only the * offset part. */ diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index d37bed8f0..d3d2fcbf4 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -175,8 +175,8 @@ TOKENS /* Primitives */ LABEL = { ADDR adr; } 4 adr. + LABEL_OFFSET_HI = { ADDR adr; } 4 "hi16[" adr "]". LABEL_OFFSET_HA = { ADDR adr; } 4 "ha16[" adr "]". - LABEL_OFFSET_HAS = { ADDR adr; } 4 "has16[" adr "]". LABEL_OFFSET_LO = { ADDR adr; } 4 "lo16[" adr "]". LOCAL = { INT off; } 4. @@ -286,7 +286,7 @@ INSTRUCTIONS add GPR:wo, GPR:ro, GPR:ro. addX "add." GPR:wo, GPR:ro, GPR:ro. addi GPR:wo, GPR:ro, CONST:ro. - addis GPR:wo, GPR:ro, CONST+LABEL_OFFSET_HA+LABEL_OFFSET_HAS:ro. + addis GPR:wo, GPR:ro, CONST+LABEL_OFFSET_HI+LABEL_OFFSET_HA:ro. and GPR:wo, GPR:ro, GPR:ro. andc GPR:wo, GPR:ro, GPR:ro. andiX "andi." GPR:wo:cc, GPR:ro, CONST:ro. @@ -408,7 +408,7 @@ MOVES from LABEL to GPR gen COMMENT("move LABEL->GPR") - addis %2, R0, {LABEL_OFFSET_HA, %1.adr} + addis %2, R0, {LABEL_OFFSET_HI, %1.adr} ori %2, %2, {LABEL_OFFSET_LO, %1.adr} /* Sign extension */ @@ -1149,7 +1149,7 @@ PATTERNS with LABEL uses REG gen - addis %a, R0, {LABEL_OFFSET_HAS, %1.adr} + addis %a, R0, {LABEL_OFFSET_HA, %1.adr} lwz %a, {GPRINDIRECT_OFFSET_LO, %a, %1.adr} yields %a with GPR diff --git a/util/led/relocate.c b/util/led/relocate.c index 613a0afa7..7e2f9db10 100644 --- a/util/led/relocate.c +++ b/util/led/relocate.c @@ -297,6 +297,7 @@ static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type) else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && ((opcode2 & 0xfc000000) == 0x60000000)) { + /* addis / ori instruction pair */ uint16_t hi = value >> 16; uint16_t lo = value & 0xffff; From b63a4513d5ecb19a2781fe01ea15d8ead37f5230 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 15 Jan 2017 12:04:47 +0100 Subject: [PATCH 6/8] Add missing header. --- util/led/archive.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/led/archive.c b/util/led/archive.c index e36958d17..7cb3397b8 100644 --- a/util/led/archive.c +++ b/util/led/archive.c @@ -8,6 +8,8 @@ static char rcsid[] = "$Id$"; #include #include +#include +#include #include "arch.h" #include "out.h" #include "ranlib.h" From d5a83fd73e2eb14dd9e20cda3719710369fb2022 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 18 Jan 2017 19:55:56 +0100 Subject: [PATCH 7/8] Clean up the led includes. --- util/led/archive.c | 2 +- util/led/error.c | 8 +++++--- util/led/extract.c | 4 +++- util/led/finish.c | 4 ++++ util/led/main.c | 4 +++- util/led/memory.c | 15 +++++++++------ util/led/output.c | 6 +++++- util/led/read.c | 5 +++++ util/led/save.c | 4 +++- util/led/scan.c | 4 +++- util/led/sym.c | 8 +++++--- util/led/write.c | 6 ++++-- 12 files changed, 50 insertions(+), 20 deletions(-) diff --git a/util/led/archive.c b/util/led/archive.c index 7cb3397b8..7e39e9fb7 100644 --- a/util/led/archive.c +++ b/util/led/archive.c @@ -6,8 +6,8 @@ static char rcsid[] = "$Id$"; #endif -#include #include +#include #include #include #include "arch.h" diff --git a/util/led/error.c b/util/led/error.c index e7f4fc6ec..61dc7983e 100644 --- a/util/led/error.c +++ b/util/led/error.c @@ -6,9 +6,11 @@ static char rcsid[] = "$Id$"; #endif -#include -#include #include +#include +#include +#include +#include #include #include "const.h" @@ -73,7 +75,7 @@ do_verbose(char *format, ...) static void diag(char *tail, char *format, va_list ap) { - extern char *progname, *archname, *modulname; + extern char *progname, *archname, *modulname; fprintf(stderr, "%s: ", progname); if (archname && modulname) diff --git a/util/led/extract.c b/util/led/extract.c index 5878d527d..48a2f16c6 100644 --- a/util/led/extract.c +++ b/util/led/extract.c @@ -6,8 +6,10 @@ static char rcsid[] = "$Id$"; #endif -#include #include +#include +#include +#include #include "out.h" #include "const.h" #include "debug.h" diff --git a/util/led/finish.c b/util/led/finish.c index 2eace760b..439d4b364 100644 --- a/util/led/finish.c +++ b/util/led/finish.c @@ -6,6 +6,10 @@ static char rcsid[] = "$Id$"; #endif +#include +#include +#include +#include #include #include "const.h" #include "defs.h" diff --git a/util/led/main.c b/util/led/main.c index 028bc3b3f..125f0c9a5 100644 --- a/util/led/main.c +++ b/util/led/main.c @@ -11,7 +11,9 @@ static char rcsid[] = "$Id$"; */ #include +#include #include +#include #include #include "const.h" #include "debug.h" @@ -168,7 +170,7 @@ first_pass(argv) case 'c': /* * Leave relocation information in the output, so that - * a next pass can see where relocation was done. The + * a next pass can see where relocation was done. The * resulting output however is no longer relocatable. */ flagword &= ~RFLAG; diff --git a/util/led/memory.c b/util/led/memory.c index 6349c826a..df4ee99d9 100644 --- a/util/led/memory.c +++ b/util/led/memory.c @@ -22,6 +22,9 @@ static char rcsid[] = "$Id$"; */ #include +#include +#include +#include #include #include "const.h" #include "assert.h" @@ -112,7 +115,7 @@ init_core() incore = FALSE; /* In core strategy failed. */ if (sbreak(AT_LEAST) == -1) fatal("no core at all"); - + base = BASE; for (mem = mems; mem < &mems[NMEMS]; mem++) { mem->mem_base = base; @@ -198,15 +201,15 @@ compact(piece, incr, flag) gain = (mem->mem_full + incr) >> SHIFT_COUNT; if (incr < gain) incr = gain; } - + /* * First, check that moving will result in enough space */ if (flag != FREEZE) { gain = mem->mem_left; for (mem = &mems[piece-1]; mem >= &mems[0]; mem--) { - /* - * Don't give it all away! + /* + * Don't give it all away! * If this does not give us enough, bad luck */ if (flag == FORCED) @@ -224,8 +227,8 @@ compact(piece, incr, flag) } if (min == piece) for (mem = &mems[piece+1]; mem <= &mems[NMEMS - 1]; mem++) { - /* - * Don't give it all away! + /* + * Don't give it all away! * If this does not give us enough, bad luck */ if (flag == FORCED) diff --git a/util/led/output.c b/util/led/output.c index 0ee622e3a..835627631 100644 --- a/util/led/output.c +++ b/util/led/output.c @@ -6,6 +6,10 @@ static char rcsid[] = "$Id$"; #endif +#include +#include +#include +#include #include #include "const.h" #include "memory.h" @@ -60,7 +64,7 @@ generate_section_names() extern struct outsect outsect[]; extern char *core_alloc(); - size = (long)outhead.oh_nsect * sizeof(struct outname); + size = (long)outhead.oh_nsect * sizeof(struct outname); name = (struct outname *)core_alloc(ALLOGLOB, size); if (name == (struct outname *)0) return; diff --git a/util/led/read.c b/util/led/read.c index 95ec7dd6b..3ea15925c 100644 --- a/util/led/read.c +++ b/util/led/read.c @@ -6,6 +6,11 @@ static char rcsid[] = "$Id$"; #endif +#include +#include +#include +#include + int infile; /* The current input file. */ rd_fatal() diff --git a/util/led/save.c b/util/led/save.c index 3804413d9..952649633 100644 --- a/util/led/save.c +++ b/util/led/save.c @@ -10,8 +10,10 @@ static char rcsid[] = "$Id$"; * If everything is kept in core, we must save some things for the second pass. */ -#include #include +#include +#include +#include #include #include "arch.h" #include "out.h" diff --git a/util/led/scan.c b/util/led/scan.c index a870f8e05..1740a14de 100644 --- a/util/led/scan.c +++ b/util/led/scan.c @@ -6,8 +6,10 @@ static char rcsid[] = "$Id$"; #endif -#include #include +#include +#include +#include #ifdef SYMDBUG #include #include diff --git a/util/led/sym.c b/util/led/sym.c index 2ec47b6b7..53f0f3440 100644 --- a/util/led/sym.c +++ b/util/led/sym.c @@ -10,8 +10,10 @@ static char rcsid[] = "$Id$"; * Symbol table management. */ -#include #include +#include +#include +#include #include "out.h" #include "const.h" #include "memory.h" @@ -49,7 +51,7 @@ init_symboltable() * in the hash table is followed. If the names match, a pointer to the outname * in this element of the list is returned. When a match cannot be found, * NIL is returned. - */ + */ struct outname * searchname(string, hashval) char *string; @@ -74,7 +76,7 @@ searchname(string, hashval) debug("found %x, %x, %lx\n", name->on_type, name->on_desc, name->on_valu, 0); return name; - } + } symindex = sym->sy_next; } /* Not found. */ diff --git a/util/led/write.c b/util/led/write.c index d77ea98ef..b916949ae 100644 --- a/util/led/write.c +++ b/util/led/write.c @@ -6,8 +6,10 @@ static char rcsid[] = "$Id$"; #endif -#include #include +#include +#include +#include #include #include "out.h" #include "const.h" @@ -75,7 +77,7 @@ end_write() for (sectindex = 0; sectindex < outhead.oh_nsect; sectindex++) wrt_name(sectname(sectindex), 1); } - + wrt_emit(emit, sectindex, cnt) char *emit; int sectindex; From 9cc264cfee18f8a1491794fafb0959122a83fbf4 Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 18 Jan 2017 20:10:16 +0100 Subject: [PATCH 8/8] Add a man page for the PowerPC assembler (not used anywhere yet). --- man/powerpc_as.6 | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 man/powerpc_as.6 diff --git a/man/powerpc_as.6 b/man/powerpc_as.6 new file mode 100644 index 000000000..8198d6bce --- /dev/null +++ b/man/powerpc_as.6 @@ -0,0 +1,33 @@ +.TH POWERPC_AS 1 +.ad +.SH NAME +powerpc_as \- assembler for PowerPC + +.SH SYNOPSIS +as [options] argument ... + +.SH DESCRIPTION +This assembler is made with the general framework +described in \fIuni_ass\fP(6). + +.SH SYNTAX +Most 32-bit integer and floating point instructions are supported, but not many +short form instructions. Instructions which take 16-bit operands can additionally +use the following special functions: + +.IP hi16[value], ha16[value] +Returns the high half of the value of the expression; if the value is not absolute, +also generates the appropriate fixup. Use of either of these \fImust\fR be followed, +in the next instruction, by the corresponding use of \fBlo16[]\fR. Use \fBhi16[]\fR +if the low half is going to interpret its payload as an unsigned value, and +\fBha16[]\fR if it will be interpreted as a signed value (so that the high half can +be adjusted to match). + +.IP lo16[] +Returns the low half of the value of the expression. No fixup is generated. Use of +\fBlo16[]\fR must come in the instruction immediately after a use of \fBhi16[]\fR or +\fBha16[]\fR. + +.SH "SEE ALSO" +uni_ass(6), +ack(1)