diff options
Diffstat (limited to 'bcc/codefrag.c')
-rw-r--r-- | bcc/codefrag.c | 1843 |
1 files changed, 1843 insertions, 0 deletions
diff --git a/bcc/codefrag.c b/bcc/codefrag.c new file mode 100644 index 0000000..e42b05b --- /dev/null +++ b/bcc/codefrag.c @@ -0,0 +1,1843 @@ +/* codefrag.c - code fragments for bcc */ + +/* Copyright (C) 1992 Bruce Evans */ + +#include "const.h" +#include "types.h" +#include "byteord.h" +#include "condcode.h" +#include "gencode.h" +#include "label.h" +#include "output.h" +#include "reg.h" +#include "scan.h" +#include "sizes.h" + +#define DEFSTR_BYTEMAX 10 +#define DEFSTR_DELIMITER '"' +#define DEFSTR_STRINGMAX 40 +#define EOS_TEXT '0' +#define MAXPRINTCHAR '~' +#define MINPRINTCHAR ' ' + +/* segment numbers */ + +#ifdef I8088 +# define CSEG 0 +# define outcseg() outop0str(".text\n") +# define DSEG 1 +# define outdseg() outop0str(".data\n") +# define BSSSEG 2 +# define outbssseg() outop0str(".bss\n") +#endif + +#ifdef MC6809 +# define CSEG 0 +# define outcseg() outop0str("LOC\t0\n") +# define DPSEG 2 +# define outdpseg() outop0str("LOC\t2\n") +# define DSEG 3 +# define outdseg() outop0str("LOC\t3\n") +# define STRSEG 1 +# define outstrseg() outop0str("LOC\t1\n") +#endif + +#ifdef I8088 +FORWARD void adjcarry P((void)); +#endif +FORWARD void clr P((store_pt reg)); +FORWARD bool_pt lowregisDreg P((void)); +#ifdef I8088 +FORWARD void outand P((void)); +FORWARD void outequate P((void)); +# ifdef XENIX_AS +FORWARD void outexport P((void)); +# endif +FORWARD void outmovsx P((void)); +FORWARD void outmovzx P((void)); +FORWARD void tfrhilo P((void)); +FORWARD void tfrlohi P((void)); +#endif +#ifdef MC6809 +FORWARD void negBsbcA P((void)); +#endif +FORWARD void outaccum P((void)); +FORWARD void outstackreg P((void)); +FORWARD void opregadr P((void)); + +/* operator and miscellaneous strings */ + +#ifdef I8088 + +# define ACCHISTR "ah" +# define ANDSTRING "and\t" +# define DEFSTR_QUOTER '\\' +# define EORSTRING "xor\t" +# define MAX_INLINE_SHIFT 2 /* better 3 for 88, 1 for 186 and above */ +# define ORSTRING "or\t" +# define TARGET_FIRST +# define addfactor(reg) (outadd(), outregname(reg), outncregname(DXREG)) +# define defstorage() outop0str(".blkb\t") +# define extBnegD() (ctoi(), negDreg()) +# define finishfactor() /* save/add/subfactor() ended already */ +# define outadc() outop3str("adc\t") +# define outandac() (outand(), outaccum(), bumplc()) +# define outandlo() (outand(), outstr(acclostr)) +# define outbimmed() outbyte('*') +# define outcommon() outop0str(".comm\t") +# define outcwd() outnop1str("cwd") +# define outdefstr() outop0str(".ascii\t\"") +# define outexchange() outop1str("xchg\t") +# define outglobl() outop0str(".globl\t") +# ifdef XENIX_AS +# define outimport() outexport() +# else +# define outexport() outop0str("export\t") +# define outimport() outop0str("import\t") +# endif +# ifdef XENIX_AS +# define outj1switch() outop3str("seg\tcs\nbr\t@"); +# else +# define outj1switch() outop3str("seg\tcs\nbr\t"); +# endif +# define outj2switch() \ + (outindleft(), outstr(ireg0str), outindright(), bumplc2(), outnl()) +# define outlcommon() outop0str("\tlcomm\t") +# define outlswitch() (outload(), outstr(ireg0str), outncregname(DREG)) +# define outnc1() outnstr(",*1") +# define outsbc() outop3str("sbb\t") +# define outset() outstr ("\tset\t") +# define outsl() outop2str("shl\t") +# define outsr() outop2str("sar\t") +# define outtransfer() outload() +# define outusr() outop2str("shr\t") +# define outxor() outop2str(EORSTRING) +# define reclaimfactor() /* factor in DXREG, DXREG now junk */ +# define savefactor(reg) regtransfer((reg), DXREG) +# define smiDreg() (outcwd(), regexchange(DREG, DXREG)) +# define sr1() (outsr(), outaccum(), outnc1()) +# define subfactor(reg) (outsub(), outregname(reg), outncregname(DXREG)) +# define usr1() (outusr(), outaccum(), outnc1()) +PRIVATE void adjcarry() +{ + outop3str("rcl\t"); + outregname(DXREG); + outncimmadr((offset_t) 9); + outand(); + bumplc2(); + bumplc2(); + outregname(DXREG); + outncimmadr((offset_t) 0x100); +} +PUBLIC void clrBreg() +{ + outxor(); + outstr(acclostr); + outncregname(BREG); +} +PUBLIC void comment() +{ + outstr("! "); +} +PUBLIC void ctoi() +{ + if (i386_32) + { + outmovzx(); + outaccum(); + outncregname(BREG); + } + else + { + outxor(); + outhiaccum(); + outcomma(); + outhiaccum(); + outnl(); + } +} +PUBLIC void defbyte() +{ + outop0str(".byte\t"); +} +#ifdef XENIX_AS +PUBLIC void defword() +{ +} /* don't have to print ".word\t" */ +#else +PUBLIC void defword() +{ + outop0str(".word\t"); +} +#endif +PUBLIC void defdword() +{ + outop0str("dd\t"); +} +PUBLIC void even() +{ + outop0str(".even\n"); +} +PUBLIC void negDreg() +{ + outop2str("neg\t"); + outnregname(DREG); +} +PUBLIC void comDreg() +{ + outop2str("not\t"); + outnregname(DREG); +} +PUBLIC void outadd() +{ + outop2str("add\t"); +} +PUBLIC void outaddsp() +{ + outadd(); + outstackreg(); + outcomma(); + outimmed(); + bumplc2(); +} +PRIVATE void outand() +{ + outop2str(ANDSTRING); +} +#ifdef XENIX_AS +PUBLIC void outcalladr() +{ + outop2str("call\t@"); +} +#else +PUBLIC void outcalladr() +{ + outop2str("call\t"); +} +#endif +PUBLIC void outcmp() +{ + outop2str("cmp\t"); +} +PUBLIC void outdec() +{ + outop1str("dec\t"); +} +PUBLIC void outdword() +{ + outstr("dword "); +} +PRIVATE void outequate() +{ + outop0str("\t=\t"); +} +#ifdef XENIX_AS +PRIVATE void outexport() +{ + outop0str(".globl\t"); +} +#endif +PUBLIC void outfail() +{ + outop0str(".fail\t"); +} +PUBLIC void outinc() +{ + outop1str("inc\t"); +} +#ifdef XENIX_AS +PUBLIC void outindleft() +{ + outbyte('('); +} +PUBLIC void outindright() +{ + outbyte(')'); +} +#else +PUBLIC void outindleft() +{ + outbyte('['); +} +PUBLIC void outindright() +{ + outbyte(']'); +} +#endif +#ifndef FRAMEPOINTER +PUBLIC void outindstackreg() +{ + outindleft(); + outregname(STACKREG); + outindright(); +} +#endif +PUBLIC void outldaccum() +{ + outload(); + outaccum(); + outcomma(); +} +PUBLIC void outldmulreg() +{ + outload(); + outregname(MULREG); + outcomma(); +} +PUBLIC void outlea() +{ + outop2str("lea\t"); +} +PUBLIC void outleasp() +{ + outlea(); + outstackreg(); + outcomma(); +} +PUBLIC void outload() +{ + outop2str("mov\t"); +} +PRIVATE void outmovsx() +{ + outop3str("movsx\t"); +} +PRIVATE void outmovzx() +{ + outop3str("movzx\t"); +} +PUBLIC void outmulmulreg() +{ + outop2str("mul\t"); + outnregname(MULREG); +} +PUBLIC void outopsep() +{ + outcomma(); +} +PUBLIC void outpshs() +{ + outop1str("push"); +} +PUBLIC void outpuls() +{ + outop1str("pop"); +} +PUBLIC void outreturn() +{ + outnop1str("ret"); +} +PUBLIC void outstore() +{ + outload(); +} +PUBLIC void outsub() +{ + outop2str("sub\t"); +} +PUBLIC void outtest() +{ + outop2str("test\t"); +} +PUBLIC void outword() +{ + outstr("word "); +} +PUBLIC void sctoi() +{ + if (i386_32) + { + outmovsx(); + outncregname(BREG); + } + else + outnop1str("cbw"); +} +PUBLIC void stoi() +{ + outnop1str("cwde"); +} +PRIVATE void tfrhilo() +{ + outload(); + outstr(acclostr); + outcomma(); + outhiaccum(); + outnl(); +} +PRIVATE void tfrlohi() +{ + outload(); + outhiaccum(); + outncregname(BREG); +} +PUBLIC void ustoi() +{ + outmovzx(); + outaccum(); + outcomma(); + outshortregname(DREG); + outnl(); +} +#endif /* I8088 */ + +#ifdef MC6809 + +# define ACCHISTR "A" +# define ANDSTRING "AND" +# define DEFSTR_QUOTER '"' +# define EORSTRING "EOR" +# define MAX_INLINE_SHIFT 16 +# define ORSTRING "OR" +# define addfactor(reg) outop2str("ADDD\t,S") +# define defstorage() outop0str("RMB\t") +# define extBnegD() (ctoi(), negBsbcA()) +# define finishfactor() outnl() +# define outadc() outop2str("ADC") +# define outandhi() outop2str("ANDA") +# define outandlo() outop2str("ANDB") +# define outcommon() outop0str("\tCOMM\t") +# define outdefstr() outop0str("FCC\t\"") +# define outequate() outop0str("\tEQU\t") +# define outexchange() outop2str("EXG\t") +# define outexport() outop0str("EXPORT\t") +# define outglobl() outop0str("GLOBL\t") +# define outimport() outop0str("IMPORT\t") +# define outjswitch() outnop2str("JMP\t[D,X]") +# define outlcommon() outop0str("\tLCOMM\t") +# define outlswitch() outop3str("LDX\t#") +# define outpijswitch() outnop2str("JMP\tD,X") +# define outpil1switch() outop3str("LEAX\t<") +# define outpil2switch() outnop2str("LDD\tD,X") +# define outrolhi() outnop1str("ROLA"); +# define outsbc() outop2str("SBC") +# define outset() outstr ("\tSET\t") +# define outsl() outop1str("LSL") +# define outtransfer() outop2str("TFR\t") +# define reclaimfactor() outnstr ("++") /* discard factor from stack */ +# define savefactor(reg) outop2str("PSHS\tD") +# define smiDreg() (clrBreg(), outnop1str("ROLA"), \ + outnop2str("SBCB\t#0"), sctoi()) + /* this tricky sequence is twice as fast as TFR A,B; SEX; TFR A,B */ + /* it gets the sign bit of A in the carry */ + /* then subtracts it from 0 in D (effectively) */ +# define sr1() (outnop1str("ASRA"), outnop1str("RORB")) +# define stackregstr "S" +# define subfactor(reg) outop2str("SUBD\t,S") +# define testhi() outnop1str("TSTA") +# define tfrhilo() outnop2str("TFR\tA,B") +# define tfrlohi() outnop2str("TFR\tB,A") +# define usr1() (outnop1str("LSRA"), outnop1str("RORB")) +PUBLIC void clrBreg() +{ + outnop1str("CLRB"); +} +PUBLIC void comment() +{ + outstr("| "); +} +PUBLIC void defbyte() +{ + outop0str("FCB\t"); +} +PUBLIC void defword() +{ + outop0str("FDB\t"); +} +PUBLIC void negDreg() +{ + outnop1str("NEGA"); + negBsbcA(); +} +PRIVATE void negBsbcA() +{ + outnop1str("NEGB"); + sbc0(); +} +PUBLIC void comDreg() +{ + outnop1str("COMA"); + outnop1str("COMB"); +} +PUBLIC void outABX() +{ + outnop1str("ABX"); +} +PUBLIC void outadd() +{ + outop2str("ADD"); +} +PUBLIC void outaddsp() +{ + outleasp(); + bumplc2(); +} +PUBLIC void outcalladr() +{ + outop2str("JSR"); +} +PUBLIC void outcmp() +{ + outop2str("CMP"); +} +PUBLIC void outdec() +{ + outop1str("DEC"); +} +PUBLIC void outdirectpage() +{ + outbyte('<'); +} +PUBLIC void outextended() +{ + outbyte('>'); +} +PUBLIC void outfail() +{ + outop0str("FAIL\t"); +} +PUBLIC void outinc() +{ + outop1str("INC"); +} +PUBLIC void outindleft() +{ + outbyte('['); +} +PUBLIC void outindright() +{ + outbyte(']'); +} +PUBLIC void outldaccum() +{ + outload(); + outaccum(); +} +PUBLIC void outldmulreg() +{ + outop2str("LDA"); +} +PUBLIC void outlea() +{ + outop2str("LEA"); +} +PUBLIC void outleasp() +{ + outop2str("LEAS\t"); +} +PUBLIC void outload() +{ + outop2str("LD"); +} +PUBLIC void outmulmulreg() +{ + outnop1str("MUL"); +} +PUBLIC void outncspregname() +{ + outcomma(); + outstackreg(); + outnl(); +} +PUBLIC void outopsep() +{ +} /* is tab, but already done by outadr() */ +PUBLIC void outpshs() +{ + outop2str("PSHS"); +} +PUBLIC void outpuls() +{ + outop2str("PULS"); +} +PUBLIC void outreturn() +{ + outnop1str("RTS"); +} +PUBLIC void outstore() +{ + outop2str("ST"); +} +PUBLIC void outsub() +{ + outop2str("SUB"); +} +PUBLIC void outtest() +{ + outop1str("TST"); +} +PUBLIC void sctoi() +{ + outnop1str("SEX"); +} +PUBLIC void ctoi() +{ + outnop1str("CLRA"); +} +#endif /* MC6809 */ +#ifdef FRAMEREG +PUBLIC void outindframereg() +{ + outindleft(); + outregname(FRAMEREG); + outindright(); +} +#endif + +typedef fastin_t seg_t; /* range 0..3 */ + +PRIVATE seg_t segment; /* current seg, depends on init to CSEG = 0 */ + +/* add carry resulting from char addition */ + +PUBLIC void adc0() +{ +#ifdef I8088 + if (i386_32) + { + adjcarry(); + outadd(); + outaccum(); + outncregname(DXREG); + } + else +#endif + { + outadc(); + outhiaccum(); + outncimmadr((offset_t) 0); + } +} + +/* add constant to register */ + +PUBLIC void addconst(offset, reg) +offset_t offset; +store_pt reg; +{ +#ifdef I8088 + if ((i386_32 && (uoffset_t) offset + 1 <= 2) /* do -1 to 1 by dec/inc */ + || (!i386_32 && (uoffset_t) offset + 2 <= 4)) /* do -2 to 2 */ + { + if (reg == ALREG) + reg = AXREG; /* shorter and faster */ + do + { + if (offset < 0) + { + outdec(); + ++offset; + } + else /* if offset == 0, do inc + dec */ + { + outinc(); + --offset; /* shouldn't happen and harmless */ + } + outnregname(reg); + } + while (offset); + } + else +#endif +#ifdef MC6809 + if (!(reg & ALLDATREGS)) + lea(offset, reg, reg); + else if (reg == BREG && (offset == 1 || offset == -1)) + { + if (offset < 0) + outdec(); + else + outinc(); + outnregname(reg); + } + else +#endif + { + outadd(); + outimadj(offset, reg); + } +} + +/* adjust lc for signed offset */ + +PUBLIC void adjlc(offset, reg) +offset_t offset; +store_pt reg; +{ + if (!(reg & CHARREGS)) + { + bumplc(); + if (!isbyteoffset(offset)) + { +#ifdef I8088 + if ((store_t) reg != AXREG) +#endif + bumplc(); +#ifdef I8088 + if (i386_32) + bumplc2(); +#endif + } + } +} + +/* adjust stack ptr by adding a labelled constant less current sp */ + +PUBLIC void adjsp(label) +label_t label; +{ + outaddsp(); + outbyte(LOCALSTARTCHAR); + outlabel(label); + if (switchnow != NULL) + { + outminus(); + outswstacklab(); + } + else + { + outplus(); + outhex((uoffset_t) - sp); + } +#ifdef MC6809 + outcregname(LOCAL); +#endif +#ifdef I8088 + if (i386_32) + bumplc2(); +#endif + outnl(); +} + +/* and accumulator with constant */ + +PUBLIC void andconst(offset) +offset_t offset; +{ + char_t botbits; + uoffset_t topbits; + + if ((topbits = offset & ~(uoffset_t) CHMASKTO & intmaskto) != 0 && + topbits != (~(uoffset_t) CHMASKTO & intmaskto)) + /* if topbits == 0, callers reduce the type */ + { +#ifdef OP1 + outandhi(); + outncimmadr((offset_t) (topbits >> (INT16BITSTO - CHBITSTO))); +#else + outandac(); + if (i386_32) + bumplc2(); + outncimmadr(offset); + return; +#endif + } + if ((botbits = (char_t) offset & CHMASKTO) == 0) + clrBreg(); + else if (botbits != CHMASKTO) + { + outandlo(); + outncimmadr((offset_t) botbits); + } +} + +#ifdef I8088 + +/* set bss segment */ + +PUBLIC void bssseg() +{ + if (segment != BSSSEG) + { + segment = BSSSEG; + outbssseg(); + } +} + +#endif + +/* jump to case of switch */ + +PUBLIC label_t casejump() +{ + label_t jtablelab; + +#ifdef I8088 + outlswitch(); + outj1switch(); + outlabel(jtablelab = getlabel()); + outj2switch(); + if (i386_32) + bumplc2(); +#endif +#ifdef MC6809 + if (posindependent) + { + outpil1switch(); + outlabel(jtablelab = getlabel()); + outncregname(GLOBAL); + outpil2switch(); + outpijswitch(); + } + else + { + outlswitch(); + outnlabel(jtablelab = getlabel()); + outjswitch(); + } +#endif + return jtablelab; +} + +/* clear register to 0 */ + +PRIVATE void clr(reg) +store_pt reg; +{ + loadconst((offset_t) 0, reg); +} + +/* define common storage */ + +PUBLIC void common(name) +char *name; +{ +#ifdef I8088 + outcommon(); + outccname(name); + outcomma(); +#endif +#ifdef MC6809 + outccname(name); + outcommon(); +#endif +} + +/* set code segment */ + +PUBLIC void cseg() +{ + if (segment != CSEG) + { + segment = CSEG; + outcseg(); + } +} + +/* define long */ + +PUBLIC void deflong(value) +uoffset_t value; +{ + uoffset_t longhigh; + uoffset_t longlow; + + longlow = value & (uoffset_t) intmaskto; +#ifdef I8088 + if (i386_32) + defdword(); + else +#endif + { + longhigh = (value >> INT16BITSTO) & (uoffset_t) intmaskto; + defword(); +#if DYNAMIC_LONG_ORDER + if (long_big_endian) +#endif +#if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN + outnhex(longhigh); +#endif +#if DYNAMIC_LONG_ORDER + else +#endif +#if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN == 0 + { + outnhex(longlow); + longlow = longhigh; + } +#endif + defword(); + } + outnhex(longlow); +} + +/* define null storage */ + +PUBLIC void defnulls(nullcount) +uoffset_t nullcount; +{ + if (nullcount != 0) + { + defstorage(); + outnhex(nullcount); + } +} + +/* define string */ + +PUBLIC label_t defstr(sptr, stop, dataflag) +char *sptr; +char *stop; +bool_pt dataflag; +{ + int byte; /* promoted char for output */ + label_t strlab; + seg_t oldsegment; + fastin_t count; /* range 0..max(DEFSTR_BYTEMAX,DEFSTR_STRMAX) */ + +#ifdef HOLDSTRINGS + if (!(bool_t) dataflag) + return holdstr(sptr, stop); +#endif + oldsegment = segment; +#ifdef I8088 + dseg(); +#endif +#ifdef MC6809 + if (dataflag) + dseg(); + else + { + segment = STRSEG; /* could use dseg() */ + outstrseg(); /* this brings strings together */ + } +#endif + outnlabel(strlab = getlabel()); + byte = (unsigned char) *sptr++; + while (sptr <= stop) + { + if ((unsigned char) byte >= MINPRINTCHAR + && (unsigned char) byte <= MAXPRINTCHAR) + { + outdefstr(); + count = DEFSTR_STRINGMAX; + while (count-- > 0 && (unsigned char) byte >= MINPRINTCHAR + && (unsigned char) byte <= MAXPRINTCHAR && sptr <= stop) + { +#if DEFSTR_DELIMITER - DEFSTR_QUOTER + if ((unsigned char) byte == DEFSTR_DELIMITER + || (unsigned char) byte == DEFSTR_QUOTER) +#else + if ((unsigned char) byte == DEFSTR_DELIMITER) +#endif + outbyte(DEFSTR_QUOTER); + outbyte(byte); + byte = (unsigned char) *sptr++; + } + outnbyte(DEFSTR_DELIMITER); + } + else + { + defbyte(); + count = DEFSTR_BYTEMAX; + while (count-- > 0 && ((unsigned char) byte < MINPRINTCHAR + || (unsigned char) byte > MAXPRINTCHAR) && sptr <= stop) + { + if (count < DEFSTR_BYTEMAX - 1) + outcomma(); /* byte separator */ + outhex((uoffset_t) byte); + byte = (unsigned char) *sptr++; + } + outnl(); + } + } + defbyte(); + outnbyte(EOS_TEXT); + switch (oldsegment) + { + case CSEG: + cseg(); + break; + case DSEG: + dseg(); + break; +#ifdef I8088 + case BSSSEG: + bssseg(); + break; +#endif +#ifdef MC6809 + case DPSEG: + dpseg(); + break; +#endif + } + return strlab; +} + +/* divide D register by a constant if it is easy to do with shifts */ + +PUBLIC bool_pt diveasy(divisor, uflag) +value_t divisor; +bool_pt uflag; +{ + bool_t sign; + + sign = FALSE; + if (divisor < 0 && !(bool_t) uflag) + { + sign = TRUE; + divisor = -divisor; + } + if (bitcount((uvalue_t) divisor) > 1) + return FALSE; + if (divisor == 0) + clr(DREG); + else + { + if (sign) + negDreg(); + srconst((value_t) highbit((uvalue_t) divisor), uflag); + } + return TRUE; +} + +#ifdef MC6809 + +/* set direct page segment */ + +PUBLIC void dpseg() +{ + if (segment != DPSEG) + { + segment = DPSEG; + outdpseg(); + } +} + +#endif + +/* set data segment */ + +PUBLIC void dseg() +{ + if (segment != DSEG) + { + segment = DSEG; + outdseg(); + } +} + +/* equate a name to an EOL-terminated string */ + +PUBLIC void equ(name, string) +char *name; +char *string; +{ + outstr(name); + outequate(); + outline(string); +} + +/* equate a local label to a value */ + +PUBLIC void equlab(label, offset) +label_t label; +offset_t offset; +{ + outbyte(LOCALSTARTCHAR); + outlabel(label); + outequate(); + outshex(offset); + outnl(); +} + +/* import or export a variable */ + +PUBLIC void globl(name) +char *name; +{ + outglobl(); + outnccname(name); +} + +/* import a variable */ + +PUBLIC void import(name) +char *name; +{ + outimport(); + outnccname(name); +} + +/* extend an int to a long */ + +PUBLIC void itol(reg) +store_pt reg; +{ +#define TEMP_LABEL_FOR_REGRESSION_TESTS +#ifdef TEMP_LABEL_FOR_REGRESSION_TESTS + getlabel(); +#endif + + if (lowregisDreg()) + { +#ifdef I8088 + outcwd(); + regtransfer(DXREG, reg); +#else + label_t exitlab; + + clr(reg); + testhi(); + sbranch(GE, exitlab = getlabel()); + loadconst((offset_t) - 1, reg); + outnlabel(exitlab); +#endif + } + else + { + regtransfer(DREG, reg); + smiDreg(); + } +} + +/* define local common storage */ + +PUBLIC void lcommlab(label) +label_t label; +{ + outlabel(label); + outlcommon(); +} + +PUBLIC void lcommon(name) +char *name; +{ + outccname(name); + outlcommon(); +} + +#ifdef MC6809 + +/* load effective address */ + +PUBLIC void lea(offset, sourcereg, targreg) +offset_t offset; +store_pt sourcereg; +store_pt targreg; +{ + outlea(); + outregname(targreg); + outtab(); + outshex(offset); + outncregname(sourcereg); +} + +#endif + +/* load constant into given register */ + +PUBLIC void loadconst(offset, reg) +offset_t offset; +store_pt reg; +{ +#ifdef I8088 + if (offset == 0) + { + outxor(); + outregname(reg); + outncregname(reg); + } + else +#endif +#ifdef MC6809 + if (offset == 0 && reg == BREG) + clrBreg(); + else +#endif + { + outload(); + outregname(reg); +#ifdef MC6809 + if (reg == YREG) + bumplc2(); + else +#endif + if (reg != BREG) + { + bumplc(); +#ifdef I8088 + if (i386_32) + bumplc2(); +#endif + } + outncimmadr(offset); + } +} + +/* convert index half of long reg pair into low half of pair */ + +PRIVATE bool_pt lowregisDreg() +{ +#if DYNAMIC_LONG_ORDER + if (long_big_endian) +#endif +# if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN + return FALSE; +#endif +#if DYNAMIC_LONG_ORDER + else +#endif +#if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN == 0 + return TRUE; +#endif +} + +/* partially long shift left register by a constant (negative = infinity) */ + +PUBLIC int lslconst(shift, reg) +value_t shift; +store_pt reg; +{ + if ((uvalue_t) shift >= INT16BITSTO) + { + slconst(shift - INT16BITSTO, lowregisDreg() ? DREG : reg); + regexchange(reg, DREG); + clr(lowregisDreg() ? DREG : reg); + return 0; + } +#ifdef I8088 + if (shift >= CHBITSTO) + { + if (long_big_endian) + { + tfrlohi(); + outnop2str("mov\tal,bh"); + outnop2str("mov\tbh,bl"); + outnop2str("sub\tbl,bl"); + } + else + { + outnop2str("mov\tbh,bl"); + outnop2str("mov\tbl,ah"); + tfrlohi(); + clrBreg(); + } + return (int) shift - CHBITSTO; + } +#endif + return (int) shift; +} + +/* partially long shift right register by a constant (negative = infinity) */ + +PUBLIC int lsrconst(shift, reg, uflag) +value_t shift; +store_pt reg; +bool_pt uflag; +{ + if ((uvalue_t) shift >= INT16BITSTO) + { + if (lowregisDreg()) + regexchange(reg, DREG); + srconst(shift - INT16BITSTO, uflag); + if ((bool_t) uflag) + uitol(reg); + else + itol(reg); + return 0; + } +#ifdef I8088 + if (shift >= CHBITSTO) + { + if (long_big_endian) + { + outnop2str("mov\tbl,bh"); + outnop2str("mov\tbh,al"); + tfrhilo(); + if ((bool_t) uflag) + ctoi(); + else + sctoi(); + } + else + { + tfrhilo(); + outnop2str("mov\tah,bl"); + outnop2str("mov\tbl,bh"); + if ((bool_t) uflag) + outnop2str("sub\tbh,bh"); + else + { + regexchange(reg, DREG); + sctoi(); + regexchange(reg, DREG); + } + } + return (int) shift - CHBITSTO; + } +#endif + return (int) shift; +} + +/* take D register modulo a constant if it is easy to do with a mask */ + +PUBLIC bool_pt modeasy(divisor, uflag) +value_t divisor; +bool_pt uflag; +{ + bool_t sign; + + sign = FALSE; + if (divisor < 0 && !(bool_t) uflag) + { + sign = TRUE; + divisor = -divisor; + } + if (bitcount((uvalue_t) divisor) > 1) + return FALSE; + if (--divisor == 0) + clrBreg(); /* original divisor 1 or -1 yields 0 */ + else + { + if (sign) + negDreg(); + andconst((offset_t) divisor); /* if original divisor 0, this is + null */ + if (sign) + negDreg(); + } + return TRUE; +} + +/* multiply register by a constant if it is easy to do with shifts */ + +PUBLIC bool_pt muleasy(factor, reg) +uvalue_t factor; +store_pt reg; +{ + int mulstack[MAXINTBITSTO / 2 + 1]; /* must be signed, not a fastin_t */ + fastin_pt count; + fastin_t single1skip; + fastin_t lastcount; + fastin_t mulsp; + int stackentry; /* signed */ + + if (factor == 0) + { + clr(reg); + return TRUE; + } + single1skip = 0; + mulsp = -1; /* may be unsigned, but bumps to 0 */ + while (factor != 0) + { + for (lastcount = single1skip; (factor & 1) == 0; factor >>= 1) + ++lastcount; + mulstack[(int)++mulsp] = lastcount; + /* first time bumps mulsp to 0 even if an unsigned char */ + for (count = 0; (factor & 1) != 0; factor >>= 1) + ++count; + single1skip = 1; + if (count == 2 && factor == 0) + /* 3 = 2 + 1 better than 3 = 4 - 1 */ + /* but rest of algorithm messed up unless factor now 0 */ + mulstack[(int)++mulsp] = 1; + else if (count > 1) + { + single1skip = 0; + if (lastcount == 1 && mulsp != 0) + mulstack[(int)mulsp] = -1 - count; + else + mulstack[(int)++mulsp] = -count; + } + } + if (mulsp > 3) + return FALSE; + if (mulsp != 0) + { + savefactor(reg); /* on stack or in reg as nec */ + do + { + finishfactor(); /* finish save/add/subfactor() if nec */ + stackentry = mulstack[(int)mulsp--]; + if (stackentry < 0) + { +#ifdef I8088 + if (stackentry == -INT32BITSTO) + clr(reg); /* shifting would do nothing */ + else +#endif + slconst((value_t) - stackentry, reg); + subfactor(reg); /* from wherever put by savefactor() */ + } + else + { + slconst((value_t) stackentry, reg); + addfactor(reg); /* from wherever put by savefactor() */ + } + } + while (mulsp != 0); + reclaimfactor(); /* reclaim storage if nec */ + } + slconst((value_t) mulstack[0], reg); + return TRUE; +} + +/* negate a register */ + +PUBLIC void negreg(reg) +store_pt reg; +{ + if ((store_t) reg == BREG) + extBnegD(); + else + negDreg(); +} + +/* return string of operator */ + +PUBLIC char *opstring(op) +op_pt op; +{ + switch (op) + { + case ANDOP: + return ANDSTRING; + case EOROP: + return EORSTRING; + case OROP: + return ORSTRING; + } + return "badop"; +} + +/* print DREG (accumulator) */ + +PRIVATE void outaccum() +{ + outstr(accumstr); +} + +/* print a c compiler name with leading CCNAMEPREXFIX */ + +PUBLIC void outccname(name) +char *name; +{ + outbyte(CCNAMEPREFIX); + outstr(name); +} + +/* print high byte of word accumulator */ + +PUBLIC void outhiaccum() +{ + outstr(ACCHISTR); +} + +/* print immediate address */ + +PUBLIC void outimmadr(offset) +offset_t offset; +{ +#ifdef I8088 + if (!isbyteoffset(offset)) + outimmed(); + else + outbimmed(); +#else + outimmed(); +#endif + outshex(offset); +} + +/* print register, comma, immediate address and adjust lc */ + +PUBLIC void outimadj(offset, targreg) +offset_t offset; +store_pt targreg; +{ + outregname(targreg); + adjlc(offset, targreg); + outncimmadr(offset); +} + +/* print immediate address designator */ + +PUBLIC void outimmed() +{ + outbyte('#'); +} + +PUBLIC void outjumpstring() +{ + outop3str(jumpstring); +#ifdef I8088 + if (i386_32) + bumplc2(); +#endif +} + +/* print cc name, then newline */ + +PUBLIC void outnccname(name) +char *name; +{ + outccname(name); + outnl(); +} + +/* print separator, immediate address, newline */ + +PUBLIC void outncimmadr(offset) +offset_t offset; +{ +#ifdef I8088 + outcomma(); +#endif +#ifdef MC6809 + outtab(); +#endif + outimmadr(offset); + outnl(); +} + +/* print signed offset and adjust lc */ + +PUBLIC void outoffset(offset) +offset_t offset; +{ +#ifdef MC6809 + if (!is5bitoffset(offset)) +#endif + adjlc(offset, INDREG0); + outshex(offset); +} + +/* print stack register */ + +PRIVATE void outstackreg() +{ + outstr(stackregstr); +} + +PUBLIC void public(name) +char *name; +{ +#ifndef AS09 + outexport(); + outnccname(name); +#endif + outccname(name); + outnbyte(PUBLICENDCHAR); +} + +/* print cc name as a private label */ + +PUBLIC void private(name) +char *name; +{ +#ifdef LABELENDCHAR + outccname(name); + outnbyte(LABELENDCHAR); +#else + outnccname(name); +#endif +} + +/* exchange registers */ + +PUBLIC void regexchange(sourcereg, targreg) +store_pt sourcereg; +store_pt targreg; +{ + outexchange(); + outregname(sourcereg); + outncregname(targreg); +#ifdef I8088 + if (!((sourcereg | targreg) & AXREG)) + bumplc(); +#endif +} + +/* transfer a register */ + +PUBLIC void regtransfer(sourcereg, targreg) +store_pt sourcereg; +store_pt targreg; +{ + outtransfer(); +#ifdef TARGET_FIRST + outregname(targreg); + outncregname(sourcereg); +#else + outregname(sourcereg); + outncregname(targreg); +#endif +} + +/* subtract carry resulting from char addition */ + +PUBLIC void sbc0() +{ +#ifdef I8088 + if (i386_32) + { + adjcarry(); + outsub(); + outaccum(); + outncregname(DXREG); + } + else +#endif + { + outsbc(); + outhiaccum(); + outncimmadr((offset_t) 0); + } +} + +/* set a name to a value */ + +PUBLIC void set(name, value) +char *name; +offset_t value; +{ + outccname(funcname); + outbyte(LOCALSTARTCHAR); + outstr(name); + outset(); + outshex(value); + outnl(); +} + +/* shift left register by 1 */ + +PUBLIC void sl1(reg) +store_pt reg; +{ + outsl(); +#ifdef I8088 + outregname(reg); + outnc1(); +#endif +#ifdef MC6809 + outnregname(BREG); + outrolhi(); +#endif +} + +/* shift left register by a constant (negative = infinity) */ + +PUBLIC void slconst(shift, reg) +value_t shift; +store_pt reg; +{ +#ifdef I8088 + if (i386_32) + { + if ((shift = (uvalue_t) shift % INT32BITSTO) != 0) + { + outsl(); + if (shift != 1) + bumplc(); + outregname(reg); + outncimmadr((offset_t) shift); + } + return; + } +#endif + if ((uvalue_t) shift >= INT16BITSTO) + clr(reg); + else + { + if (shift >= CHBITSTO && reg == DREG) + { + tfrlohi(); + clrBreg(); + shift -= CHBITSTO; + } +#ifdef I8088 +# if MAX_INLINE_SHIFT < INT16BITSTO + if (shift > MAX_INLINE_SHIFT) + { + outload(); + outregname(SHIFTREG); + outcomma(); + outimmadr((offset_t) shift); + outnl(); + outsl(); + outregname(reg); + outncregname(SHIFTREG); + } + else +# endif +#endif + while (shift--) + sl1(reg); + } +} + +/* shift right D register by a constant (negative = infinity) */ + +PUBLIC void srconst(shift, uflag) +value_t shift; +bool_pt uflag; +{ +#ifdef I8088 + if (i386_32) + { + if ((shift = (uvalue_t) shift % INT32BITSTO) != 0) + { + if (uflag) + outusr(); + else + outsr(); + if (shift != 1) + bumplc(); + outaccum(); + outncimmadr((offset_t) shift); + } + return; + } +#endif + if ((uvalue_t) shift >= INT16BITSTO) /* covers negatives too */ + { + if ((bool_t) uflag) + clr(DREG); + else /* make D == 0 if D >= 0, else D == -1 */ + smiDreg(); /* special case of 68020 Scc instruction */ + } + else + { + if (shift >= CHBITSTO) + { + tfrhilo(); + if ((bool_t) uflag) + ctoi(); + else + sctoi(); + shift -= CHBITSTO; + } +#ifdef I8088 +# if MAX_INLINE_SHIFT < INT16BITSTO + if (shift > MAX_INLINE_SHIFT) + { + outload(); + outregname(SHIFTREG); + outcomma(); + outimmadr((offset_t) shift); + outnl(); + if ((bool_t) uflag) + outusr(); + else + outsr(); + outaccum(); + outncregname(SHIFTREG); + } + else +# endif +#endif + while (shift--) + { + if ((bool_t) uflag) + usr1(); + else + sr1(); + } + } +} + +/* extend an unsigned in DREG to a long */ + +PUBLIC void uitol(reg) +store_pt reg; +{ + if (lowregisDreg()) + clr(reg); + else + { + regexchange(DREG, reg); + clr(DREG); + } +} + +PRIVATE char opregstr[] = "_opreg"; + +/*----------------------------------------------------------------------------- + opregadr() + outputs address of variable opreg where OPREG is saved +-----------------------------------------------------------------------------*/ + +PRIVATE void opregadr() +{ +#ifdef I8088 + outindleft(); + outccname(opregstr); + outindright(); + bumplc2(); + if (i386_32) + bumplc2(); +#endif +#ifdef MC6809 + outregname(OPREG); + outtab(); + if (posindependent) + { + outccname(opregstr); + outncregname(GLOBAL); + bumplc(); + } + else + { + outextended(); + outnccname(opregstr); + } + bumplc(); +#endif +} + +/*----------------------------------------------------------------------------- + restoreopreg() + restores register OPREG from static location >opreg if it is was use +-----------------------------------------------------------------------------*/ + +PUBLIC void restoreopreg() +{ + if (reguse & OPREG) + { +#ifdef I8088 + outload(); + outregname(OPREG); + outopsep(); + opregadr(); + outnl(); +#endif +#ifdef MC6809 + outload(); + opregadr(); +#endif + } +} + +/*----------------------------------------------------------------------------- + saveopreg() + saves register OPREG to static location >opreg if it is in use + this makes the flop routines non-reentrant. It is too messy to + push it because the flop routines leave results on the stack +-----------------------------------------------------------------------------*/ + +PUBLIC void saveopreg() +{ + if (reguse & OPREG) + { +#ifdef I8088 + bssseg(); + common(opregstr); + outnhex(opregsize); + cseg(); + outstore(); + opregadr(); + outncregname(OPREG); +#endif +#ifdef MC6809 + dseg(); + common(opregstr); + outnhex(opregsize); + cseg(); + outstore(); + opregadr(); +#endif + } +} |