// asm8051.c #include #include #include #include #include #define versionName "8051 assembler" #define INSTR_MAX 3 // length of longest valid instruction #define CPU_LITTLE_ENDIAN // CPU is little-endian #include "asmguts.h" enum instrType { o_None, // NOP RET RETI - no operands o_AJMP, // ACALL AJMP - 11-bit jump with A11-A15 unchanged o_LJMP, // LCALL LJMP - 16-bit jump o_Rel, // JC JNC JNZ JZ SJMP - relative jump o_BitRel, // JB JBC JNB - relative jump with bit o_DJNZ, // DJNZ - decrement and relative jump if not zero o_Arith, // ADD ADDC SUBB - imm, @R0, @R1, R0-R7, dir o_Logical, // ANL ORL XRL - imm, @R0, @R1, R0-R7, dir, C-bit, dir-imm, dir-A o_AccA, // DA RL RLC RR RRC SWAP - only accepts A as parameter (should also have o_None aliases) o_AccAB, // DIV MUL - only accepts AB as parameter o_MOV, // MOV - mucho complicated o_INC_DEC, // INC DEC - @R0, @R1, A, R0-R7, dir, and DPTR for INC only o_XCHD, // XCHD A,@R0/@R1 o_PushPop, // POP PUSH - parameter is direct address o_A_bit_C, // SETB CLR CPL - accepts A, bit, C, except SETB does not accept A o_JMP, // JMP @A+DPTR o_MOVC, // MOVC A,@A+DPTR/PC o_MOVX, // MOVX A to or from @DPTR, @R0, @R1 o_CJNE, // CJNE @R0, @R1, A, R0-R7, dir with immediate and relative operands o_XCH // XCH A with @R0, @R1, R0-R7, dir // o_Foo = o_LabelOp, }; struct OpcdRec opcdTab[] = { {"NOP", o_None, 0x00}, {"RET", o_None, 0x22}, {"RETI", o_None, 0x32}, {"ACALL",o_AJMP, 0x11}, {"AJMP", o_AJMP, 0x01}, {"LCALL",o_LJMP, 0x12}, {"LJMP", o_LJMP, 0x02}, {"JC", o_Rel, 0x40}, {"JNC", o_Rel, 0x50}, {"JNZ", o_Rel, 0x70}, {"JZ", o_Rel, 0x60}, {"SJMP", o_Rel, 0x80}, {"JB", o_BitRel, 0x20}, {"JBC", o_BitRel, 0x10}, {"JNB", o_BitRel, 0x30}, {"DJNZ", o_DJNZ, 0x00}, {"ADD", o_Arith, 0x20}, {"ADDC", o_Arith, 0x30}, {"SUBB", o_Arith, 0x90}, {"ANL", o_Logical, 0x8050}, {"ORL", o_Logical, 0x7040}, {"XRL", o_Logical, 0x0060}, {"DA", o_AccA, 0xD4}, {"RL", o_AccA, 0x23}, {"RLC", o_AccA, 0x33}, {"RR", o_AccA, 0x03}, {"RRC", o_AccA, 0x13}, {"SWAP", o_AccA, 0xC4}, // aliases for o_AccA instructions // {"DAA", o_None, 0xD4}, // {"RLA", o_None, 0x23}, // {"RLCA", o_None, 0x33}, // {"RRA", o_None, 0x03}, // {"RRCA", o_None, 0x13}, // {"SWAPA",o_None, 0xC4}, {"DIV", o_AccAB, 0x84}, {"MUL", o_AccAB, 0xA4}, {"MOV", o_MOV, 0x00}, {"INC", o_INC_DEC, 0xA300}, {"DEC", o_INC_DEC, 0x0010}, {"XCHD", o_XCHD, 0x00}, {"POP", o_PushPop, 0xD0}, {"PUSH", o_PushPop, 0xC0}, {"CLR", o_A_bit_C, 0xE4C2}, {"CPL", o_A_bit_C, 0xF4B2}, {"SETB", o_A_bit_C, 0x00D2}, {"JMP", o_JMP, 0x00}, {"MOVC", o_MOVC, 0x00}, {"MOVX", o_MOVX, 0x00}, {"CJNE", o_CJNE, 0x00}, {"XCH", o_XCH, 0x00}, {"", o_Illegal, 0} }; // -------------------------------------------------------------- int FindReg(const char *regName, const char *regList) { const char *p; int i; i = 0; while (*regList) { p = regName; // compare words while (*p && *p == *regList++) p++; // if not match, skip rest of word if (*p) { // skip to next whitespace while (*regList && *regList != ' ') regList++; // skip to next word while (*regList == ' ') regList++; i++; } else return i; } return -1; } int GetReg(const char *regList) { Str255 word; int token; if (!(token = GetWord(word))) { MissingOperand(); return -2; } if (token == '@') GetWord(word+1); return FindReg(word,regList); } int EvalBitReg() { int val1,val2; Str255 word; char *oldLine; val1 = Eval(); oldLine = linePtr; if (GetWord(word) == '.') { val2 = Eval(); if (0x20 <= val1 && val1 <= 0x2F) return (val1 & 0x1F) * 8 + val2; if ((val1 & 0x87) == 0x80) return (val1 & 0xF8) + val2; IllegalOperand(); return -1; } linePtr = oldLine; if (val1 & 0xFFFFFF00) { IllegalOperand(); return -1; } return val1; } int DoCPUOpcode(int typ, int parm) { int val; int reg1; int reg2; Str255 word; char *oldLine; int token; switch(typ) { case o_None: Instr1(parm); break; case o_AJMP: val = Eval(); if ((val & 0xF800) != ((locPtr + 2) & 0xF800)) { if (parm == 0x01) Warning("AJMP out of range"); else Warning("ACALL out of range"); } Instr2(parm + ((val & 0x0700) >> 3),val & 0xFF); break; case o_LJMP: val = Eval(); Instr3W(parm,val); break; case o_Rel: val = EvalBranch(2); Instr2(parm,val); break; case o_BitRel: reg1 = EvalBitReg(); if (reg1 < 0) break; Comma(); val = EvalBranch(3); Instr3(parm,reg1,val); break; case o_DJNZ: oldLine = linePtr; switch((reg1 = GetReg("R0 R1 R2 R3 R4 R5 R6 R7"))) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: Comma(); val = EvalBranch(2); Instr2(0xD8+reg1,val); break; case -1: linePtr = oldLine; reg1 = EvalByte(); Comma(); val = EvalBranch(3); Instr3(0xD5,reg1,val); break; default: IllegalOperand(); break; } break; case o_Arith: switch(GetReg("A")) { default: case -1: IllegalOperand(); case -2: break; case 0: Comma(); oldLine = linePtr; switch((reg1 = GetReg("@R0 @R1 R0 R1 R2 R3 R4 R5 R6 R7 #"))) { default: IllegalOperand(); case -2: // EOL break; case -1: // dir linePtr = oldLine; val = EvalByte(); Instr2(parm + 0x05, val); break; case 0: // @Rn case 1: case 2: // Rn case 3: case 4: case 5: case 6: case 7: case 8: case 9: Instr1(parm + 0x06 + reg1); break; case 10: // #imm val = EvalByte(); Instr2(parm + 0x04, val); break; } break; } break; case o_Logical: oldLine = linePtr; switch ((GetReg("A C"))) { default: IllegalOperand(); case -2: break; case -1: // dir linePtr = oldLine; val = EvalByte(); Comma(); switch (GetReg("A #")) { default: case -1: IllegalOperand(); case -2: break; case 0: // A Instr1((parm & 0xFF) + 0x02); break; case 1: // #imm val = EvalByte(); Instr2((parm & 0xFF) + 0x03, val); break; } break; case 0: // A Comma(); oldLine = linePtr; switch((reg1 = GetReg("@R0 @R1 R0 R1 R2 R3 R4 R5 R6 R7 #"))) { default: IllegalOperand(); case -2: break; case -1: // dir linePtr = oldLine; val = EvalByte(); Instr2((parm & 0xFF) + 0x05, val); break; case 0: // @Rn case 1: case 2: // Rn case 3: case 4: case 5: case 6: case 7: case 8: case 9: Instr1((parm & 0xFF) + 0x06 + reg1); break; case 10: // #imm val = EvalByte(); Instr2((parm & 0xFF) + 0x04, val); break; } break; case 1: // C if ((parm & 0xFF00) == 0) { // XRL C,bit IllegalOperand(); break; } Comma(); // "bit" or "/bit" val = 0x02; oldLine = linePtr; token = GetWord(word); if (token == '/') val = 0x30; else linePtr = oldLine; reg1 = EvalBitReg(); if (reg1 < 0) break; Instr2((parm >> 8) + val, reg1); break; } break; case o_AccA: switch(GetReg("A")) { default: case -1: IllegalOperand(); case -2: break; case 0: Instr1(parm); } break; case o_AccAB: switch(GetReg("AB")) { default: case -1: IllegalOperand(); case -2: break; case 0: Instr1(parm); } break; case o_MOV: oldLine = linePtr; switch((reg1 = GetReg("@R0 @R1 R0 R1 R2 R3 R4 R5 R6 R7 A C DPTR"))) { case -2: // EOL break; case -1: // dir or bit linePtr = oldLine; reg1 = EvalByte(); oldLine = linePtr; token = GetWord(word); if (token == '.') // bit.b,C { if (0x20 <= reg1 && reg1 <= 0x2F) reg1 = (reg1 & 0x1F) * 8; else if ((reg1 & 0x87) != 0x80) { IllegalOperand(); break; } reg2 = EvalByte(); if (reg2 < 0 || reg2 > 7) { IllegalOperand(); break; } Comma(); switch (GetReg("C")) { default: case -1: IllegalOperand(); case -2: break; case 0: Instr2(0x92,reg1 + reg2); } break; } else if (token != ',') { oldLine = linePtr; Expect(","); break; } oldLine = linePtr; // dir,Rn or bit,C switch((reg2 = GetReg("@R0 @R1 R0 R1 R2 R3 R4 R5 R6 R7 A # C"))) { default: IllegalOperand(); case -2: break; case -1: // dir linePtr = oldLine; val = EvalByte(); Instr3(0x85, val, reg1); break; case 0: // @Rn case 1: case 2: // Rn case 3: case 4: case 5: case 6: case 7: case 8: case 9: Instr2(0x86 + reg2, reg1); break; case 10: // A Instr2(0xF5, reg1); break; case 11: // #imm val = EvalByte(); Instr3(0x75, reg1, val); break; case 12: // bit,C Instr2(0x92,reg1); break; } break; case 0: // @R0 @R1 case 1: case 2: // Rn case 3: case 4: case 5: case 6: case 7: case 8: case 9: Comma(); oldLine = linePtr; switch (GetReg("A #")) { default: IllegalOperand(); case -2: break; case -1: // dir linePtr = oldLine; val = EvalByte(); Instr2(0xA6 + reg1, val); break; case 0: // A Instr1(0xF6 + reg1); break; case 1: // #imm val = EvalByte(); Instr2(0x76 + reg1, val); break; } break; case 10: // A Comma(); oldLine = linePtr; switch((reg1 = GetReg("@R0 @R1 R0 R1 R2 R3 R4 R5 R6 R7 #"))) { default: IllegalOperand(); case -2: break; case -1: // dir linePtr = oldLine; val = EvalByte(); Instr2(0xE5, val); break; case 0: // @Rn case 1: case 2: // Rn case 3: case 4: case 5: case 6: case 7: case 8: case 9: Instr1(0xE6 + reg1); break; case 10: // #imm val = EvalByte(); Instr2(0x74, val); break; } break; case 11: // C Comma(); reg1 = EvalBitReg(); if (reg1 < 0) break; Instr2(0xA2,reg1); break; case 12: // DPTR Comma(); Expect("#"); val = Eval(); Instr3W(0x90,val); break; default: IllegalOperand(); } break; case o_INC_DEC: oldLine = linePtr; switch((reg1 = GetReg("A DPTR @R0 @R1 R0 R1 R2 R3 R4 R5 R6 R7"))) { case -2: // EOL break; case -1: // dir linePtr = oldLine; val = EvalByte(); Instr2(parm + 0x05, val); break; case 0: // A case 2: // @Rn case 3: case 4: // Rn case 5: case 6: case 7: case 8: case 9: case 10: case 11: Instr1((parm & 0xFF) + 0x04 + reg1); break; case 1: // DPTR if (parm & 0xFF00) Instr1(parm >> 8); else IllegalOperand(); break; default: IllegalOperand(); } break; case o_XCHD: switch(GetReg("A")) { default: case -1: IllegalOperand(); case -2: break; case 0: Comma(); switch((reg1 = GetReg("@R0 @R1"))) { default: case -1: IllegalOperand(); case -2: break; case 0: case 1: Instr1(0xD6 + reg1); break; } break; } break; case o_PushPop: val = Eval(); Instr2(parm,val); break; case o_A_bit_C: oldLine = linePtr; switch((reg1 = GetReg("A C"))) { case 0: // A if ((parm & 0xFF00) == 0) IllegalOperand(); else Instr1(parm >> 8); break; case 1: // C Instr1((parm & 0xFF) + 1); break; case -1: // bit linePtr = oldLine; reg1 = EvalBitReg(); if (reg1 < 0) break; Instr2(parm & 0xFF, reg1); break; default: break; } break; case o_JMP: switch (GetReg("@A")) { default: case -1: IllegalOperand(); case -2: break; case 0: Expect("+"); switch (GetReg("DPTR")) { default: case -1: IllegalOperand(); case -2: break; case 0: Instr1(0x73); break; } break; } break; case o_MOVC: switch (GetReg("A")) { default: case -1: IllegalOperand(); case -2: break; case 0: Comma(); switch (GetReg("@A")) { default: case -1: IllegalOperand(); case -2: break; case 0: Expect("+"); switch (GetReg("PC DPTR")) { default: case -1: IllegalOperand(); case -2: break; case 0: Instr1(0x83); break; case 1: Instr1(0x93); break; } break; } break; } break; case o_MOVX: switch ((reg1 = GetReg("@DPTR A @R0 @R1"))) { default: case -1: IllegalOperand(); case -2: break; case 1: // A Comma(); switch ((reg1 = GetReg("@DPTR A @R0 @R1"))) { case 1: // A,A default: case -1: IllegalOperand(); case -2: break; case 0: // A,@DPTR case 2: // A,@R0 case 3: // A,@R1 Instr1(0xE0 + reg1); break; } break; case 0: // @DPTR case 2: // @R0 case 3: // @R1 Comma(); switch (GetReg("A")) { default: case -1: IllegalOperand(); case -2: break; case 0: break; } Instr1(0xF0 + reg1); break; } break; case o_CJNE: oldLine = linePtr; switch((reg1 = GetReg("A A @R0 @R1 R0 R1 R2 R3 R4 R5 R6 R7"))) { case -1: linePtr = oldLine; reg1 = EvalByte(); Comma(); val = EvalBranch(3); Instr3(0xB5,reg1,val); break; case 0: // A case 2: // @Rn case 3: case 4: // Rn case 5: case 6: case 7: case 8: case 9: case 10: case 11: Comma(); Expect("#"); reg2 = EvalByte(); Comma(); val = EvalBranch(3); Instr3(0xB4+reg1,reg2,val); break; default: break; } break; case o_XCH: switch (GetReg("A")) { default: case -1: IllegalOperand(); case -2: break; case 0: Comma(); oldLine = linePtr; switch ((reg1 = GetReg("@R0 @R1 R0 R1 R2 R3 R4 R5 R6 R7"))) { default: IllegalOperand(); case -2: break; case -1: // dir linePtr = oldLine; val = EvalByte(); Instr2(0xC5, val); break; case 0: // @R0 case 1: case 2: // Rn case 3: case 4: case 5: case 6: case 7: case 8: case 9: Instr1(0xC6 + reg1); break; } break; } break; default: return 0; break; } return 1; } int DoCPULabelOp(int typ, int parm, char *labl) { // int i,val; // Str255 word; switch(typ) { default: return 0; break; } return 1; } void usage(void) { stdversion(); stdusage(); exit(1); } void PassInit(void) { } void AsmInit(void) { }