/* * Process a machine op. */ VOID machine(struct mne * mp) { int op, t1, t2; struct expr e1, e2; int rf, v1, v2; clrexpr(&e1); clrexpr(&e2); op = (int) mp->m_valu; rf = mp->m_type; #if 0 if (!hd64 && rf>X_HD64) rf = 0; #endif if (!r4k_mode && rf > X_R4K_MODE) rf = 0; switch (rf) { case S_INH1: outab(op); break; case S_INH2: outab(0xED); outab(op); break; case S_RET: if (more()) { if ((v1 = admode(CND)) != 0) { outab(op | (v1<<3)); } else { qerr(); } } else { outab(0xC9); } break; case S_PUSH: if (admode(R16X)) { outab(op+0x30); break; } else if ((v1 = admode(R8IP)) != 0) { outab(0xED); if (op == 0xC5) outab(0x76); /* push */ else outab(0x7E); /* pop */ break; } else if ((v1 = admode(R16)) != 0 && (v1 &= 0xFF) != SP) { if (v1 != gixiy(v1)) { outab(op+0x20); break; } outab(op | (v1<<4)); break; } else if (r4k_mode) { if ( (v1 = admode(R32_JKHL)) != 0 ) { outab(JKHL_PG); outab(op+0x30); break; } else if ( (v1 = admode(R32_BCDE)) != 0 ) { outab(BCDE_PG); outab(op+0x30); break; } } aerr(); break; case S_RST: v1 = (int) absexpr(); /* ljm comment - * block RST 00, 08, and 30 b/c those opcodes * are assigned to different instructions in the * rabbit processor */ if ((v1 == 0x00) || (v1 == 0x08) || (v1 == 0x30)) { aerr( ); v1 = 0; } if (v1 & ~0x38) { aerr(); v1 = 0; } outab(op|v1); break; #if 0 /* IM x set interrupt mode on Z-80 */ /* Rabbit processor use the opcode to set interrupt level */ case S_IM: expr(&e1, 0); abscheck(&e1); if (e1.e_addr > 2) { aerr(); e1.e_addr = 0; } outab(op); outab(imtab[(int) e1.e_addr]); break; #endif case S_BIT: expr(&e1, 0); t1 = 0; v1 = (int) e1.e_addr; if (v1 > 7) { ++t1; v1 &= 0x07; } op |= (v1<<3); comma(1); addr(&e2); abscheck(&e1); if (genop(0xCB, op, &e2, 0) || t1) aerr(); break; case S_RL: t1 = 0; t2 = addr(&e2); if ((t2 == S_IMMED) && r4k_mode) { v1 = (int) e2.e_addr; /* v1 should be shift count of 1,2,4, or 8 */ comma(1); clrexpr(&e2); t2 = addr(&e2); if ((t2 != S_R32_BCDE) && (t2 != S_R32_JKHL)) aerr( ); if (v1 == 1) v1 = 0x48; else if (v1 == 2) v1 = 0x49; else if (v1 == 4) v1 = 0x4B; else if ((v1 == 8) && (op < 0x20 /* op is rlc|rrc|rl|rr */)) v1 = 0x4F; else { err('o'); break; } /* 00 rlc, 08 rrc, 10 rl , 18 rr * * 20 sla, 28 sra, 38 srl, [30 sll == sla] */ outab( ((t2 == S_R32_JKHL)?JKHL_PG:BCDE_PG) ); outab(v1 + (op << 1)); break; } else if (more()) { if ((t2 != S_R8) || (e2.e_addr != A)) ++t1; comma(1); clrexpr(&e2); t2 = addr(&e2); } else if (t2 == S_R16) { v2 = (int) e2.e_addr; if ((v2 == DE) && ((op == 0x10 /* rl */) || (op == 0x18 /* rr */))) { outab( 0xF3 - 0x10 + op ); break; } if ((v2 == HL) && (op == 0x18 /* rr */)) { outab( 0xFC ); break; } if (r4k_mode) { if ((v2 == HL) && (op == 0x10 /* rl */)) { outab( 0x42 ); break; } if (((v2 == BC)||(v2 == DE)) && (op < 0x20 /* 00 rlc, 08 rrc, 10 rl, 18 rr */)) { outab( 0x50 + (op >> 3) + ((v2==BC)?0x10:0x00) ); break; } } aerr( ); }
/* Classify argument as to address mode */ int addr(struct expr *esp) { int c; unsigned rd; if ((c = getnb()) == '#') { /* Immediate mode */ expr(esp, 0); esp->e_mode = S_IMMED; } else if (c == '@') { /* choices are @R0, @R1, @DPTR, @A+PC, @A+DPTR */ switch (reg()) { case R0: esp->e_mode = S_AT_R; esp->e_addr = R0; break; case R1: esp->e_mode = S_AT_R; esp->e_addr = R1; break; case DPTR: esp->e_mode = S_AT_DP; esp->e_addr = DPTR; break; case A: if (getnb() == '+') { rd = reg(); if (rd == PC) { esp->e_mode = S_AT_APC; esp->e_addr = 0; } else if (rd == DPTR) { esp->e_mode = S_AT_ADP; esp->e_addr = 0; } else { aerr(); } } else aerr(); break; } esp->e_flag = 0; esp->e_base.e_ap = NULL; } else if (c == '*') { if ((c = getnb()) == '/') { /* Force inverted bit */ expr(esp, 0); esp->e_mode = S_NOT_BIT; } else { unget(c); /* Force direct page */ expr(esp, 0); esp->e_mode = S_DIR; } if (esp->e_addr & ~0xFF) err('d'); } else if (c == '/') { /* Force inverted bit */ expr(esp, 0); esp->e_mode = S_NOT_BIT; } else { unget(c); /* try for register: A, AB, R0-R7, DPTR, PC, Cy */ if ((esp->e_addr = admode(reg51)) != -1) { switch (esp->e_addr) { case A: esp->e_mode = S_A; break; case AB: esp->e_mode = S_RAB; break; case DPTR: esp->e_mode = S_DPTR; break; case PC: esp->e_mode = S_PC; break; case C: esp->e_mode = S_C; break; default: /* R0-R7 */ esp->e_mode = S_REG; } } else { /* Must be an expression */ esp->e_addr = 0; expr(esp, 0); if ((!esp->e_flag) && (esp->e_base.e_ap==NULL) && !(esp->e_addr & ~0xFF)) { esp->e_mode = S_DIR; } else { esp->e_mode = S_EXT; } } } return (esp->e_mode); }