/* M16MCH:C */ /* * (C) Copyright 1991 * All Rights Reserved * * Alan R. Baldwin * 721 Berkeley St. * Kent, Ohio 44240 */ #include #include #include "asm.h" #include "m6816.h" #define NB 256 int *bp; int bm; int bb[NB]; /* * Process a machine op. */ VOID machine(mp) struct mne *mp; { register op, rf, cpg; struct expr e1, e2, e3; char id[NCPS]; struct area *espa; int c, pc, t1, t2, vn; pc = dot.s_addr; cpg = 0; op = mp->m_valu; switch (rf = mp->m_type) { case S_SDP: e1.e_mode = 0; e1.e_flag = 0; e1.e_addr = 0; e1.e_base.e_ap = NULL; espa = NULL; if (more()) { expr(&e1, 0); if (e1.e_flag == 0 && e1.e_base.e_ap == NULL) { if (e1.e_addr) { err('b'); } } if ((c = getnb()) == ',') { getid(id, -1); espa = alookup(id); if (espa == NULL) { err('u'); } } else { unget(c); } } if (espa) { outdp(espa, &e1); } else { outdp(dot.s_area, &e1); } lmode = SLIST; break; case S_IMMA: if (addr(&e1) == T_IMM) { if (mchimm(&e1)) { outab(PAGE3); outab(op); outrw(&e1, R_NORM); } else { outab(op); outrb(&e1, R_NORM); } } else { dot.s_addr += 4; aerr(); } break; case S_IM16: if (addr(&e1) == T_IMM) { outab(PAGE3); outab(op); outrw(&e1, R_NORM); } else { dot.s_addr += 4; aerr(); } break; case S_BIT: t1 = addr(&e1); comma(); t2 = addr(&e2); if ((t2 != T_IMM) && (t2 != T_EXT)) { aerr(); } if (t1 == T_EXT) { outab(op|0x30); mchubyt(&e2); outrb(&e2, R_USGN); outrw(&e1, R_NORM); } else if (t1 & T_INDX) { if (mchindx(t1, &e1)) { outab(op|(t1 & 0x30)); mchubyt(&e2); outrb(&e2, R_USGN); outrw(&e1, R_NORM); } else { outab(PAGE1); outab(op|(t1 & 0x30)); mchubyt(&e2); outrb(&e2, R_USGN); mchubyt(&e1); outrb(&e1, R_USGN); } } else { dot.s_addr += 4; aerr(); } break; case S_BITW: t1 = addr(&e1); comma(); t2 = addr(&e2); if ((t2 != T_IMM) && (t2 != T_EXT)) { aerr(); } if (t1 == T_EXT) { t1 |= 0x30; } else if (t1 & T_INDX) { if (t1 & T_IND8) { aerr(); } } else { aerr(); } outab(PAGE2); outab(op|(t1 & 0x30)); outrw(&e2, R_NORM); outrw(&e1, R_NORM); break; case S_BRBT: t1 = addr(&e1); comma(); t2 = addr(&e2); comma(); addr(&e3); if ((t2 != T_IMM) && (t2 != T_EXT)) { aerr(); } if (t1 == T_EXT) { outab(op|0x30); mchubyt(&e2); outrb(&e2, R_USGN); outrw(&e1, R_NORM); if (mchabs(&e3)) { vn = e3.e_addr - dot.s_addr - 2; outaw(vn); } else { outrw(&e3, R_PCR); } } else if (t1 & T_INDX) { if ((t1 & T_IND8) || (t1 & T_IND16)) { ; } else if (mchindx(t1, &e1)) { t1 |= T_IND16; } else { if (mchabs(&e3)) { vn = e3.e_addr - dot.s_addr - 4; if ((vn < -128) || (vn > 127)) { t1 |= T_IND16; } else { t1 |= T_IND8; } } else { t1 |= T_IND16; } } if (t1 & T_IND8) { if (op == 0x0A) op = 0xCB; if (op == 0x0B) op = 0x8B; outab(op|(t1 & 0x30)); mchubyt(&e2); outrb(&e2, R_USGN); mchubyt(&e1); outrb(&e1, R_USGN); if (mchabs(&e3)) { vn = e3.e_addr - dot.s_addr - 1; if ((vn < -128) || (vn > 127)) aerr(); outab(vn); } else { outrb(&e3, R_PCR); } } else if (t1 & T_IND16) { outab(op|(t1 & 0x30)); mchubyt(&e2); outrb(&e2, R_USGN); outrw(&e1, R_NORM); if (mchabs(&e3)) { vn = e3.e_addr - dot.s_addr - 2; outaw(vn); } else { outrw(&e3, R_PCR); } } } else { dot.s_addr += 6; aerr(); } break; case S_LDED: t1 = addr(&e1); if (t1 == T_EXT) { outab(PAGE2); outab(op); outrw(&e1, R_NORM); } else { dot.s_addr += 4; aerr(); } break; case S_MAC: t1 = addr(&e1); if (more()) { comma(); t2 = addr(&e2); if ((t1 != T_IMM) || !mchabs(&e1) || (t2 != T_IMM) || !mchabs(&e2)) aerr(); outab(op); outab(((e1.e_addr << 4) & 0xF0) | (e2.e_addr & 0x0F)); } else { if (t1 != T_IMM) aerr(); outab(op); outrb(&e1, R_NORM); } break; case S_PSHM: vn = 0; do { if ((t1 = admode(pshm)) == 0 || vn & t1) aerr(); vn |= t1; } while (more() && comma()); outab(op); outab(vn); break; case S_PULM: vn = 0; do { if ((t1 = admode(pulm)) == 0 || vn & t1) aerr(); vn |= t1; } while (more() && comma()); outab(op); outab(vn); break; case S_JXX: t1 = addr(&e1); comma(); t2 = addr(&e2); if ((t1 != T_IMM) && (t1 != T_EXT)) { aerr(); } if (t2 == T_EXT) { if (op == 0x4B) outab(0x70); if (op == 0x89) outab(0xFA); mchubyt(&e1); outrb(&e1, R_USGN); outrw(&e2, R_NORM); } else if ((t2 & T_INDX) && (t2 != (T_INDX|T_IND8))) { outab(op|(t2 & 0x30)); mchubyt(&e1); outrb(&e1, R_USGN); outrw(&e2, R_NORM); } else { dot.s_addr += 4; aerr(); } break; case S_MOVB: case S_MOVW: t1 = addr(&e1); comma(); t2 = addr(&e2); if((t1 == T_EXT) && (t2 == T_EXT)) { outab(PAGE3); outab(op|0xFE); outrw(&e1, R_NORM); outrw(&e2, R_NORM); } else if((t1 & T_INDX) && (t2 == T_EXT)) { outab(op|(t1 & 0x30)); mchubyt(&e1); outrb(&e1, R_USGN); outrw(&e2, R_NORM); } else if((t1 == T_EXT) && (t2 & T_INDX)) { outab(op|0x02|(t2 & 0x30)); mchubyt(&e2); outrb(&e2, R_USGN); outrw(&e1, R_NORM); } else { dot.s_addr += 6; aerr(); } break; case S_CMP: case S_LOAD: case S_STOR: t1 = addr(&e1); if (t1 == T_EXT) { outab(PAGE1); outab(op|0x30); outrw(&e1, R_NORM); } else if ((t1 == T_IMM) && (rf != S_STOR)) { outab(PAGE3); if (rf == S_CMP) outab(op|0x30); if (rf == S_LOAD) outab((op|0x30) & 0xBF); outrw(&e1, R_NORM); } else if (t1 & T_INDX) { if (mchindx(t1, &e1)) { outab(PAGE1); outab(op|(t1 & 0x30)); outrw(&e1, R_NORM); } else { outab(op|(t1 & 0x30)); mchubyt(&e1); outrb(&e1, R_USGN); } } else { dot.s_addr += 4; aerr(); } break; case S_SOPW: t1 = addr(&e1); if (t1 == T_EXT) { t1 |= 0x30; } else if (t1 & T_INDX) { if (t1 & T_IND8) { aerr(); } } else { aerr(); } outab(PAGE2); outab(op|(t1 & 0x30)); outrw(&e1, R_NORM); break; case S_SOP: t1 = addr(&e1); if (t1 == T_EXT) { outab(PAGE1); outab(op|0x30); outrw(&e1, R_NORM); } else if (t1 & T_INDX) { if (mchindx(t1, &e1)) { outab(PAGE1); outab(op|(t1 & 0x30)); outrw(&e1, R_NORM); } else { outab(op|(t1 & 0x30)); mchubyt(&e1); outrb(&e1, R_USGN); } } else { dot.s_addr += 4; aerr(); } break; case S_DOPE: t1 = addr(&e1); if (t1 == T_EXT) { outab(PAGE3); outab(op|0x30); outrw(&e1, R_NORM); } else if (t1 == T_IMM) { if (op == 0x41) { if (mchimm(&e1)) { outab(PAGE3); outab((op|0x30)&0x3F); outrw(&e1, R_NORM); } else { outab(0x7C); outrb(&e1, R_NORM); } } else { outab(PAGE3); outab((op|0x30)&0x3F); outrw(&e1, R_NORM); } } else if ((t1 & T_INDX) && (t1 != (T_INDX|T_IND8))) { outab(PAGE3); outab(op|(t1 & 0x30)); outrw(&e1, R_NORM); } else { dot.s_addr += 4; aerr(); } break; case S_DOPD: t1 = addr(&e1); if (t1 == T_EXT) { outab(PAGE3); outab(op|0x70); outrw(&e1, R_NORM); } else if ((t1 == T_IMM) && (op != 0x8A)) { if (op == 0x81) { if (mchimm(&e1)) { outab(PAGE3); outab(op|0x30); outrw(&e1, R_NORM); } else { outab(0xFC); outrb(&e1, R_NORM); } } else { outab(PAGE3); outab(op|0x30); outrw(&e1, R_NORM); } } else if (t1 & T_INDX) { if (mchindx(t1, &e1)) { outab(PAGE3); outab(op|0x40|(t1 & 0x30)); outrw(&e1, R_NORM); } else { outab(op|(t1 & 0x30)); mchubyt(&e1); outrb(&e1, R_USGN); } } else if (t1 & T_E_I) { outab(PAGE2); outab(op|(t1 & 0x30)); } else { dot.s_addr += 4; aerr(); } break; case S_DOP: t1 = addr(&e1); if (t1 == T_EXT) { outab(PAGE1); outab(op|0x30); outrw(&e1, R_NORM); } else if ((t1 == T_IMM) && (op != 0x4A) && (op != 0xCA)) { outab(op|0x30); outrb(&e1, R_NORM); } else if (t1 & T_INDX) { if (mchindx(t1, &e1)) { outab(PAGE1); outab(op|(t1 & 0x30)); outrw(&e1, R_NORM); } else { outab(op|(t1 & 0x30)); mchubyt(&e1); outrb(&e1, R_USGN); } } else if (t1 & T_E_I) { outab(PAGE2); outab(op|(t1 & 0x30)); } else { dot.s_addr += 4; aerr(); } break; case S_INH37: cpg += PAGE3-PAGE2; case S_INH27: cpg += PAGE2; outab(cpg); outab(op); break; case S_LBRA: cpg += PAGE3-PAGE2; case S_LBSR: cpg += PAGE2; expr(&e1, 0); outab(cpg); outab(op); if (mchabs(&e1)) { vn = e1.e_addr - dot.s_addr - 2; outaw(vn); } else { outrw(&e1, R_PCR); } if (e1.e_mode != S_USER) aerr(); break; case S_BRA: case S_BSR: expr(&e1, 0); outab(op); if (mchabs(&e1)) { vn = e1.e_addr - dot.s_addr - 1; if ((vn < -128) || (vn > 127)) rerr(); outab(vn); } else { outrb(&e1, R_PCR); } if (e1.e_mode != S_USER) rerr(); break; default: err('o'); } if (pc & 0x0001) { err('b'); dot.s_addr += 1; } } /* * Check if argument is absolute */ int mchabs(e1) struct expr *e1; { if (e1->e_base.e_ap == NULL || e1->e_base.e_ap == dot.s_area) { return(-1); } return(0); } /* * Addressing error if argument is absolute * and unsigned byte is greater than 0x00FF */ VOID mchubyt(e1) struct expr *e1; { if (mchabs(e1) && (e1->e_addr & 0xFF00)) { aerr(); } } /* * Check index mode */ int mchindx(t1,e1) int t1; struct expr *e1; { int flag; if (t1 & T_IND8) { flag = 0; } else if (t1 & T_IND16) { flag = 1; } else if (pass == 0) { flag = 1; } else if (pass == 1) { if (e1->e_addr >= dot.s_addr) e1->e_addr -= fuzz; flag = 0; if (e1->e_addr>255 || e1->e_flag || e1->e_base.e_ap) flag = 1; if (setbit(flag)) flag = 1; } else { if (getbit()) { flag = 1; } else { flag = 0; } } return(flag); } /* * Check immediate mode */ int mchimm(e1) struct expr *e1; { int flag, vn; if (pass == 0) { flag = 1; } else if (pass == 1) { if (e1->e_addr >= dot.s_addr) e1->e_addr -= fuzz; vn = e1->e_addr; flag = 0; if ((vn<-128) || (vn>127) || e1->e_flag || e1->e_base.e_ap) flag = 1; if (setbit(flag)) { flag = 1; } } else { if (getbit()) { flag = 1; } else { flag = 0; } } return(flag); } /* * Machine specific initialization. * Set up the bit table. */ VOID minit() { bp = bb; bm = 1; } /* * Store `b' in the next slot of the bit table. * If no room, force the longer form of the offset. */ int setbit(b) { if (bp >= &bb[NB]) return(1); if (b) *bp |= bm; bm <<= 1; if (bm == 0) { bm = 1; ++bp; } return(b); } /* * Get the next bit from the bit table. * If none left, return a `1'. * This will force the longer form of the offset. */ int getbit() { register f; if (bp >= &bb[NB]) return (1); f = *bp & bm; bm <<= 1; if (bm == 0) { bm = 1; ++bp; } return (f); } /* * The next character must be a * comma. */ int comma() { if (getnb() != ',') qerr(); return(1); }