Logo Search packages:      
Sourcecode: linux86 version File versions  Download package

codefrag.c

/* codefrag.c - code fragments for bcc */

/* Copyright (C) 1992 Bruce Evans */

#include "bcc.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()
{
#ifdef I80386
    if (i386_32)
    {
      outmovzx();
      outaccum();
      outncregname(BREG);
    }
    else
#endif
    {
      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()
{
#ifdef I80386
    if (i386_32)
    {
      outmovsx();
      outaccum();
      outncregname(BREG);
    }
    else
#endif
      outnop1str("cbw");
}
PUBLIC void stoi()
{
    outnop1str("cwde");
}
PRIVATE void tfrhilo()
{
    outload();
    outstr(acclostr);
    outcomma();
    outhiaccum();
    outnl();
}
PRIVATE void tfrlohi()
{
    outload();
    outhiaccum();
    outncregname(BREG);
}
#ifdef I80386
PUBLIC void ustoi()
{
    outmovzx();
    outaccum();
    outcomma();
    outshortregname(DREG);
    outnl();
}
#endif /* I80386 */
#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 I80386
    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
#ifdef I80386
    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  */
#else
    if ((uoffset_T) offset + 2 <= 4)      /* do -2 to 2  */
#endif
    {
      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 I80386
          if (i386_32)
            bumplc2();
#endif
      }
    }
}

/* adjust stack ptr by adding a labelled constant less current sp */

PUBLIC void adjsp(label)
label_no label;
{
    outaddsp();
    outbyte(LOCALSTARTCHAR);
    outlabel(label);
    if (switchnow != NULL)
    {
      outminus();
      outswstacklab();
    }
    else
    {
      outplus();
      outhex((uoffset_T) - sp);
    }
#ifdef MC6809
    outcregname(LOCAL);
#endif
#ifdef I80386
    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();
#ifdef I80386
      if (i386_32)
          bumplc2();
#endif
      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_no casejump()
{
    label_no jtablelab;

#ifdef I8088
    outlswitch();
    outj1switch();
    outlabel(jtablelab = getlabel());
    outj2switch();
#ifdef I80386
    if (i386_32)
      bumplc2();
#endif
#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 I80386
    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_no defstr(sptr, stop, dataflag)
char *sptr;
char *stop;
bool_pt dataflag;
{
    int byte;                 /* promoted char for output */
    label_no 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_no 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_no 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_no 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 I80386
          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 */

#ifdef I8088
    /* Now using imul directly so don't be so keen to shift */
    if( factor > 16 && factor != 32 && factor != 64 && factor != 0xFFFFFFFFL )
       return FALSE;
#endif

    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 I80386
    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 I80386
    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();
#ifdef FRAMEPOINTER
    if (framep) 
    {
       outbyte(LOCALSTARTCHAR);
       outstr(funcname);
       outbyte(LOCALSTARTCHAR);
       outstr(name);
       outset();
       outshex(value+sp-framep);
       outnl();
    }
#endif
}

/* 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 I80386
    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 I80386
    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();
#ifdef I80386
    if (i386_32)
      bumplc2();
#endif
#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
    }
}

Generated by  Doxygen 1.6.0   Back to index