+static char _defaultRules[] =
+{
+#include "peeph.rul"
+};
+
+/* list of key words used by msc51 */
+static char *_mcs51_keywords[] =
+{
+ "at",
+ "banked",
+ "bit",
+ "code",
+ "critical",
+ "data",
+ "far",
+ "idata",
+ "interrupt",
+ "near",
+ "pdata",
+ "reentrant",
+ "sfr",
+ "sfr16",
+ "sfr32",
+ "sbit",
+ "using",
+ "xdata",
+ "_data",
+ "_code",
+ "_generic",
+ "_near",
+ "_xdata",
+ "_pdata",
+ "_idata",
+ "_naked",
+ "_overlay",
+ NULL
+};
+
+
+
+void mcs51_assignRegisters (ebbIndex *);
+
+static int regParmFlg = 0; /* determine if we can register a parameter */
+static int regBitParmFlg = 0; /* determine if we can register a bit parameter */
+
+static void
+_mcs51_init (void)
+{
+ asm_addTree (&asm_asxxxx_mapping);
+}
+
+static void
+_mcs51_reset_regparm (void)
+{
+ regParmFlg = 0;
+ regBitParmFlg = 0;
+}
+
+static int
+_mcs51_regparm (sym_link * l, bool reentrant)
+{
+ if (IS_SPEC(l) && (SPEC_NOUN(l) == V_BIT)) {
+ /* bit parameters go to b0 thru b7 */
+ if (reentrant && (regBitParmFlg < 8)) {
+ regBitParmFlg++;
+ return 12 + regBitParmFlg;
+ }
+ return 0;
+ }
+ if (options.parms_in_bank1 == 0) {
+ /* simple can pass only the first parameter in a register */
+ if (regParmFlg)
+ return 0;
+
+ regParmFlg = 1;
+ return 1;
+ } else {
+ int size = getSize(l);
+ int remain ;
+
+ /* first one goes the usual way to DPTR */
+ if (regParmFlg == 0) {
+ regParmFlg += 4 ;
+ return 1;
+ }
+ /* second one onwards goes to RB1_0 thru RB1_7 */
+ remain = regParmFlg - 4;
+ if (size > (8 - remain)) {
+ regParmFlg = 12 ;
+ return 0;
+ }
+ regParmFlg += size ;
+ return regParmFlg - size + 1;
+ }
+}
+
+static bool
+_mcs51_parseOptions (int *pargc, char **argv, int *i)
+{
+ /* TODO: allow port-specific command line options to specify
+ * segment names here.
+ */
+ return FALSE;
+}
+
+static void
+_mcs51_finaliseOptions (void)
+{
+ if (options.noXinitOpt) {
+ port->genXINIT=0;
+ }
+
+ switch (options.model)
+ {
+ case MODEL_SMALL:
+ port->mem.default_local_map = data;
+ port->mem.default_globl_map = data;
+ port->s.gptr_size = 3;
+ break;
+ case MODEL_MEDIUM:
+ port->mem.default_local_map = pdata;
+ port->mem.default_globl_map = pdata;
+ port->s.gptr_size = 3;
+ break;
+ case MODEL_LARGE:
+ port->mem.default_local_map = xdata;
+ port->mem.default_globl_map = xdata;
+ port->s.gptr_size = 3;
+ break;
+ default:
+ port->mem.default_local_map = data;
+ port->mem.default_globl_map = data;
+ break;
+ }
+
+ if (options.parms_in_bank1) {
+ addSet(&preArgvSet, Safe_strdup("-DSDCC_PARMS_IN_BANK1"));
+ }
+}
+
+static void
+_mcs51_setDefaultOptions (void)
+{
+}
+
+static const char *
+_mcs51_getRegName (struct regs *reg)
+{
+ if (reg)
+ return reg->name;
+ return "err";
+}
+
+static void
+_mcs51_genAssemblerPreamble (FILE * of)
+{
+ if (options.parms_in_bank1) {
+ int i ;
+ for (i=0; i < 8 ; i++ )
+ fprintf (of,"b1_%d = 0x%x \n",i,8+i);
+ }
+}
+
+/* Generate interrupt vector table. */
+static int
+_mcs51_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
+{
+ int i;
+
+ fprintf (of, "\tljmp\t__sdcc_gsinit_startup\n");
+
+ /* now for the other interrupts */
+ for (i = 0; i < maxInterrupts; i++)
+ {
+ if (interrupts[i])
+ {
+ fprintf (of, "\tljmp\t%s\n", interrupts[i]->rname);
+ if ( i != maxInterrupts - 1 )
+ fprintf (of, "\t.ds\t5\n");
+ }
+ else
+ {
+ fprintf (of, "\treti\n");
+ if ( i != maxInterrupts - 1 )
+ fprintf (of, "\t.ds\t7\n");
+ }
+ }
+ return TRUE;
+}
+
+static void
+_mcs51_genExtraAreas(FILE *of, bool hasMain)
+{
+ tfprintf (of, "\t!area\n", HOME_NAME);
+ tfprintf (of, "\t!area\n", "GSINIT0 (CODE)");
+ tfprintf (of, "\t!area\n", "GSINIT1 (CODE)");
+ tfprintf (of, "\t!area\n", "GSINIT2 (CODE)");
+ tfprintf (of, "\t!area\n", "GSINIT3 (CODE)");
+ tfprintf (of, "\t!area\n", "GSINIT4 (CODE)");
+ tfprintf (of, "\t!area\n", "GSINIT5 (CODE)");
+ tfprintf (of, "\t!area\n", STATIC_NAME);
+ tfprintf (of, "\t!area\n", port->mem.post_static_name);
+ tfprintf (of, "\t!area\n", CODE_NAME);
+}
+
+static void
+_mcs51_genInitStartup (FILE *of)
+{
+ tfprintf (of, "\t!global\n", "__sdcc_gsinit_startup");
+ tfprintf (of, "\t!global\n", "__sdcc_program_startup");
+ tfprintf (of, "\t!global\n", "__start__stack");
+
+ if (options.useXstack)
+ {
+ tfprintf (of, "\t!global\n", "__sdcc_init_xstack");
+ tfprintf (of, "\t!global\n", "__start__xstack");
+ }
+
+ // if the port can copy the XINIT segment to XISEG
+ if (port->genXINIT)
+ {
+ port->genXINIT(of);
+ }
+
+ if (!getenv("SDCC_NOGENRAMCLEAR"))
+ tfprintf (of, "\t!global\n", "__mcs51_genRAMCLEAR");
+}
+
+
+/* Generate code to copy XINIT to XISEG */
+static void _mcs51_genXINIT (FILE * of) {
+ tfprintf (of, "\t!global\n", "__mcs51_genXINIT");
+
+ if (!getenv("SDCC_NOGENRAMCLEAR"))
+ tfprintf (of, "\t!global\n", "__mcs51_genXRAMCLEAR");
+}
+
+
+/* Do CSE estimation */
+static bool cseCostEstimation (iCode *ic, iCode *pdic)
+{
+ operand *result = IC_RESULT(ic);
+ sym_link *result_type = operandType(result);
+
+ /* if it is a pointer then return ok for now */
+ if (IC_RESULT(ic) && IS_PTR(result_type)) return 1;
+
+ /* if bitwise | add & subtract then no since mcs51 is pretty good at it
+ so we will cse only if they are local (i.e. both ic & pdic belong to
+ the same basic block */
+ if (IS_BITWISE_OP(ic) || ic->op == '+' || ic->op == '-') {
+ /* then if they are the same Basic block then ok */
+ if (ic->eBBlockNum == pdic->eBBlockNum) return 1;
+ else return 0;
+ }
+
+ /* for others it is cheaper to do the cse */
+ return 1;
+}
+
+/* Indicate which extended bit operations this port supports */
+static bool
+hasExtBitOp (int op, int size)
+{
+ if (op == RRC
+ || op == RLC
+ || op == GETHBIT
+ || op == GETABIT
+ || op == GETBYTE
+ || op == GETWORD
+ || (op == SWAP && size <= 2)
+ )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/* Indicate the expense of an access to an output storage class */
+static int
+oclsExpense (struct memmap *oclass)
+{
+ if (IN_FARSPACE(oclass))
+ return 1;
+
+ return 0;
+}
+
+
+
+static int
+instructionSize(char *inst, char *op1, char *op2)
+{
+ #define ISINST(s) (strncmp(inst, (s), sizeof(s)-1) == 0)
+ #define IS_A(s) (*(s) == 'a' && *(s+1) == '\0')
+ #define IS_C(s) (*(s) == 'c' && *(s+1) == '\0')
+ #define IS_Rn(s) (*(s) == 'r' && *(s+1) >= '0' && *(s+1) <= '7')
+ #define IS_atRi(s) (*(s) == '@' && *(s+1) == 'r')
+
+ /* Based on the current (2003-08-22) code generation for the
+ small library, the top instruction probability is:
+
+ 57% mov/movx/movc
+ 6% push
+ 6% pop
+ 4% inc
+ 4% lcall
+ 4% add
+ 3% clr
+ 2% subb
+ */
+ /* mov, push, & pop are the 69% of the cases. Check them first! */
+ if (ISINST ("mov"))
+ {
+ if (*(inst+3)=='x') return 1; /* movx */
+ if (*(inst+3)=='c') return 1; /* movc */
+ if (IS_C (op1) || IS_C (op2)) return 2;
+ if (IS_A (op1))
+ {
+ if (IS_Rn (op2) || IS_atRi (op2)) return 1;
+ return 2;
+ }
+ if (IS_Rn(op1) || IS_atRi(op1))
+ {
+ if (IS_A(op2)) return 1;
+ return 2;
+ }
+ if (strcmp (op1, "dptr") == 0) return 3;
+ if (IS_A (op2) || IS_Rn (op2) || IS_atRi (op2)) return 2;
+ return 3;
+ }
+
+ if (ISINST ("push")) return 2;
+ if (ISINST ("pop")) return 2;
+
+ if (ISINST ("lcall")) return 3;
+ if (ISINST ("ret")) return 1;
+ if (ISINST ("ljmp")) return 3;
+ if (ISINST ("sjmp")) return 2;
+ if (ISINST ("rlc")) return 1;
+ if (ISINST ("rrc")) return 1;
+ if (ISINST ("rl")) return 1;
+ if (ISINST ("rr")) return 1;
+ if (ISINST ("swap")) return 1;
+ if (ISINST ("jc")) return 2;
+ if (ISINST ("jnc")) return 2;
+ if (ISINST ("jb")) return 3;
+ if (ISINST ("jnb")) return 3;
+ if (ISINST ("jbc")) return 3;
+ if (ISINST ("jmp")) return 1; // always jmp @a+dptr
+ if (ISINST ("jz")) return 2;
+ if (ISINST ("jnz")) return 2;
+ if (ISINST ("cjne")) return 3;
+ if (ISINST ("mul")) return 1;
+ if (ISINST ("div")) return 1;
+ if (ISINST ("da")) return 1;
+ if (ISINST ("xchd")) return 1;
+ if (ISINST ("reti")) return 1;
+ if (ISINST ("nop")) return 1;
+ if (ISINST ("acall")) return 2;
+ if (ISINST ("ajmp")) return 2;
+
+
+ if (ISINST ("add") || ISINST ("addc") || ISINST ("subb") || ISINST ("xch"))
+ {
+ if (IS_Rn(op2) || IS_atRi(op2)) return 1;
+ return 2;
+ }
+ if (ISINST ("inc") || ISINST ("dec"))
+ {
+ if (IS_A(op1) || IS_Rn(op1) || IS_atRi(op1)) return 1;
+ if (strcmp(op1, "dptr") == 0) return 1;
+ return 2;
+ }
+ if (ISINST ("anl") || ISINST ("orl") || ISINST ("xrl"))
+ {
+ if (IS_C(op1)) return 2;
+ if (IS_A(op1))
+ {
+ if (IS_Rn(op2) || IS_atRi(op2)) return 1;
+ return 2;
+ }
+ else
+ {
+ if (IS_A(op2)) return 2;
+ return 3;
+ }
+ }
+ if (ISINST ("clr") || ISINST ("setb") || ISINST ("cpl"))
+ {
+ if (IS_A(op1) || IS_C(op1)) return 1;
+ return 2;
+ }
+ if (ISINST ("djnz"))
+ {
+ if (IS_Rn(op1)) return 2;
+ return 3;
+ }
+
+ /* If the instruction is unrecognized, we shouldn't try to optimize. */
+ /* Return a large value to discourage optimization. */
+ return 999;
+}
+
+static asmLineNode *
+newAsmLineNode (void)
+{
+ asmLineNode *aln;
+
+ aln = Safe_alloc ( sizeof (asmLineNode));
+ aln->size = 0;
+ aln->regsRead = NULL;
+ aln->regsWritten = NULL;
+
+ return aln;
+}
+
+
+typedef struct mcs51operanddata
+ {
+ char name[6];
+ int regIdx1;
+ int regIdx2;
+ }
+mcs51operanddata;
+
+static mcs51operanddata mcs51operandDataTable[] =
+ {
+ {"a", A_IDX, -1},
+ {"ab", A_IDX, B_IDX},
+ {"ac", CND_IDX, -1},
+ {"acc", A_IDX, -1},
+ {"ar0", R0_IDX, -1},
+ {"ar1", R1_IDX, -1},
+ {"ar2", R2_IDX, -1},
+ {"ar3", R3_IDX, -1},
+ {"ar4", R4_IDX, -1},
+ {"ar5", R5_IDX, -1},
+ {"ar6", R6_IDX, -1},
+ {"ar7", R7_IDX, -1},
+ {"b", B_IDX, -1},
+ {"c", CND_IDX, -1},
+ {"cy", CND_IDX, -1},
+ {"dph", DPH_IDX, -1},
+ {"dpl", DPL_IDX, -1},
+ {"dptr", DPL_IDX, DPH_IDX},
+ {"f0", CND_IDX, -1},
+ {"f1", CND_IDX, -1},
+ {"ov", CND_IDX, -1},
+ {"p", CND_IDX, -1},
+ {"psw", CND_IDX, -1},
+ {"r0", R0_IDX, -1},
+ {"r1", R1_IDX, -1},
+ {"r2", R2_IDX, -1},
+ {"r3", R3_IDX, -1},
+ {"r4", R4_IDX, -1},
+ {"r5", R5_IDX, -1},
+ {"r6", R6_IDX, -1},
+ {"r7", R7_IDX, -1},
+ };
+
+static int
+mcs51operandCompare (const void *key, const void *member)
+{
+ return strcmp((const char *)key, ((mcs51operanddata *)member)->name);
+}
+
+static void
+updateOpRW (asmLineNode *aln, char *op, char *optype)
+{
+ mcs51operanddata *opdat;
+ char *dot;
+
+ dot = strchr(op, '.');
+ if (dot)
+ *dot = '\0';
+
+ opdat = bsearch (op, mcs51operandDataTable,
+ sizeof(mcs51operandDataTable)/sizeof(mcs51operanddata),
+ sizeof(mcs51operanddata), mcs51operandCompare);
+
+ if (opdat && strchr(optype,'r'))
+ {
+ if (opdat->regIdx1 >= 0)
+ aln->regsRead = bitVectSetBit (aln->regsRead, opdat->regIdx1);
+ if (opdat->regIdx2 >= 0)
+ aln->regsRead = bitVectSetBit (aln->regsRead, opdat->regIdx2);
+ }
+ if (opdat && strchr(optype,'w'))
+ {
+ if (opdat->regIdx1 >= 0)
+ aln->regsWritten = bitVectSetBit (aln->regsWritten, opdat->regIdx1);
+ if (opdat->regIdx2 >= 0)
+ aln->regsWritten = bitVectSetBit (aln->regsWritten, opdat->regIdx2);
+ }
+ if (op[0] == '@')