/* * generates branch opcodes * * opcode : opcode of the branch (for instance 0x8f for BR7) * str : operand string */ static void generate_branch(unsigned char opcode, char *str) { unsigned long target_adr; long disp; programlabel(); /* get target address */ if (parse_value(str, &target_adr)) { /* unresolved target address, reserve space */ emit_opcode2(0, 0); return; } /* calculate displacement */ if (isPCKnown()) { disp = target_adr - getPC() - 1; if (disp > 127 || disp < -128) { char buf[64]; sprintf(buf, "%d", (int)disp); asmerr(ERROR_BRANCH_OUT_OF_RANGE, false, buf); } } else { /* unknown pc, will be (hopefully) resolved in future passes */ disp = 0; } emit_opcode2(opcode, disp & 255); }
/* * handles opcodes with a scratchpad register operand: * as, asd, ds, ns, xs */ static void v_sreg_op(char *str, MNEMONIC *mne) { unsigned char reg; programlabel(); parse_scratchpad_register(str, ®); emit_opcode1(mne->opcode[0] | reg); }
/* * handles instructions that take a byte operand: * ai, ci, in, li, ni, oi, out, xi */ static void v_byteop(char *str, MNEMONIC *mne) { unsigned long value; programlabel(); parse_value(str, &value); if (value > 0xff) { f8err(ERROR_ADDRESS_MUST_BE_LT_100, mne->name, str, false); } emit_opcode2(mne->opcode[0], value & 0xff); }
/* * handles instructions that take a word operand: * dci, jmp, pi */ static void v_wordop(char *str, MNEMONIC *mne) { unsigned long value; programlabel(); parse_value(str, &value); if (value > 0xffff) { f8err(ERROR_VALUE_MUST_BE_LT_10000, mne->name, str, false); } emit_opcode3(mne->opcode[0], (value >> 8) & 0xff, value & 0xff); }
static void v_lisu_lisl(char *str, MNEMONIC *mne) { unsigned long operand; programlabel(); parse_value(str, &operand); if (operand > 7) { f8err(ERROR_VALUE_MUST_BE_LT_8, mne->name, str, false); } emit_opcode1(mne->opcode[0] | (operand & 7)); }
static void v_lis(char *str, MNEMONIC *mne) { unsigned long operand; programlabel(); parse_value(str, &operand); if (operand > 15) { f8err(ERROR_VALUE_MUST_BE_LT_10, mne->name, str, false); } emit_opcode1(0x70 | (operand & 15)); }
static void v_sl_sr(char *str, MNEMONIC *mne) { unsigned long operand; programlabel(); if (parse_value(str, &operand)) { /* unresolved expression, reserve space */ emit_opcode1(0); } else { switch (operand) { case 1: emit_opcode1(mne->opcode[0]); break; case 4: emit_opcode1(mne->opcode[0] + 2); break; default: f8err(ERROR_VALUE_MUST_BE_1_OR_4, mne->name, str, false); emit_opcode1(0); break; } } }
void v_mnemonic(char *str, MNEMONIC *mne) { int addrmode; SYMBOL *sym; unsigned int opcode; short opidx; SYMBOL *symbase; int opsize; Csegment->flags |= SF_REF; programlabel(); symbase = eval(str, 1); if ( bTrace ) printf("PC: %04lx MNEMONIC: %s addrmode: %d ", Csegment->org, mne->name, symbase->addrmode); for (sym = symbase; sym; sym = sym->next) { if (sym->flags & SYM_UNKNOWN) { ++Redo; Redo_why |= REASON_MNEMONIC_NOT_RESOLVED; } } sym = symbase; if (mne->flags & MF_IMOD) { if (sym->next) { sym->addrmode = AM_BITMOD; if ((mne->flags & MF_REL) && sym->next) sym->addrmode = AM_BITBRAMOD; } } addrmode = sym->addrmode; if ((sym->flags & SYM_UNKNOWN) || sym->value >= 0x100) opsize = 2; else opsize = (sym->value) ? 1 : 0; while (badcode(mne,addrmode) && Cvt[addrmode]) addrmode = Cvt[addrmode]; if ( bTrace ) printf("mnemask: %08lx adrmode: %d Cvt[am]: %d\n", mne->okmask, addrmode, Cvt[addrmode]); if (badcode(mne,addrmode)) { char sBuffer[128]; sprintf( sBuffer, "%s %s", mne->name, str ); asmerr( ERROR_ILLEGAL_ADDRESSING_MODE, false, sBuffer ); FreeSymbolList(symbase); return; } if (Mnext >= 0 && Mnext < NUMOC) /* Force */ { addrmode = Mnext; if (badcode(mne,addrmode)) { asmerr( ERROR_ILLEGAL_FORCED_ADDRESSING_MODE, false, mne->name ); FreeSymbolList(symbase); return; } } if ( bTrace ) printf("final addrmode = %d\n", addrmode); while (opsize > Opsize[addrmode]) { if (Cvt[addrmode] == 0 || badcode(mne,Cvt[addrmode])) { char sBuffer[128]; if (sym->flags & SYM_UNKNOWN) break; sprintf( sBuffer, "%s %s", mne->name, str ); asmerr( ERROR_ADDRESS_MUST_BE_LT_100, false, sBuffer ); break; } addrmode = Cvt[addrmode]; } opcode = mne->opcode[addrmode]; opidx = 1 + (opcode > 0xFF); if (opidx == 2) { Gen[0] = opcode >> 8; Gen[1] = opcode; }
static void v_lr(char *str, MNEMONIC *mne) { int i; int ncommas; int cindex; char *op1; char *op2; unsigned char reg_dst; unsigned char reg_src; int opcode; programlabel(); /* a valid operand string must contain exactly one comma. find it. */ ncommas = 0; cindex = 0; for (i=0; str[i]; i++) { if (',' == str[i]) { ncommas++; cindex = i; } } if (1 != ncommas) { f8err(ERROR_SYNTAX_ERROR, mne->name, str, false); return; } /* extract operand strings */ str[cindex] = 0; op1 = str; op2 = &str[cindex+1]; if ( (0 != cindex) && (isspace(str[cindex-1])) ) { str[cindex-1] = 0; } if (isspace(*op2)) { op2++; } /* parse operand strings for register names */ reg_dst = parse_special_register(op1); if (REG_NONE == reg_dst) { if (parse_scratchpad_register(op1, ®_dst)) { /* unresolved expression, reserve space */ emit_opcode1(0); return; } } reg_src = parse_special_register(op2); if (REG_NONE == reg_src) { if (parse_scratchpad_register(op2, ®_src)) { /* unresolved expression, reserve space */ emit_opcode1(0); return; } } /* restore operand string */ str[cindex] = ','; if ( (0 != cindex) && (0 == str[cindex-1])) { str[cindex-1] = ' '; } /* generate opcode */ opcode = -1; switch (reg_dst) { case REG_A: /* lr a,xxx */ switch (reg_src) { case REG_IS: opcode = 0x0a; break; case REG_KL: opcode = 0x01; break; case REG_KU: opcode = 0x00; break; case REG_QL: opcode = 0x03; break; case REG_QU: opcode = 0x02; break; default: if (reg_src < 15) { opcode = 0x40 | reg_src; } break; } break; case REG_DC0: switch (reg_src) { case REG_H: opcode = 0x10; break; case REG_Q: opcode = 0x0f; break; } break; case REG_H: if (REG_DC0 == reg_src) opcode = 0x11; break; case REG_IS: if (REG_A == reg_src) opcode = 0x0b; break; case REG_K: if (REG_PC1 == reg_src) opcode = 0x08; break; case REG_KL: if (REG_A == reg_src) opcode = 0x05; break; case REG_KU: if (REG_A == reg_src) opcode = 0x04; break; case REG_PC0: if (REG_Q == reg_src) opcode = 0x0d; break; case REG_PC1: if (REG_K == reg_src) opcode = 0x09; break; case REG_Q: if (REG_DC0 == reg_src) opcode = 0x0e; break; case REG_QL: if (REG_A == reg_src) opcode = 0x07; break; case REG_QU: if (REG_A == reg_src) opcode = 0x06; break; case REG_W: if (0x09 == reg_src) opcode = 0x1d; break; default: /* lr sreg,xxx*/ if ( (15 > reg_dst) && (REG_A == reg_src) ) { /* lr sreg,a */ opcode = 0x50 | reg_dst; } else if ( (9 == reg_dst) && (REG_W == reg_src) ) { /* special case : lr j,w */ opcode = 0x1e; } break; } if (opcode < 0) { f8err(ERROR_ILLEGAL_OPERAND_COMBINATION, mne->name, str, true); } else { emit_opcode1(opcode); } }
static int MainShadow(int ac, char **av, bool *pbTableSort ) { int nError = ERROR_NONE; bool bDoAllPasses = false; int nMaxPasses = 10; char buf[MAXLINE]; int i; MNEMONIC *mne; int oldredo = -1; unsigned long oldwhy = 0; int oldeval = 0; addhashtable(Ops); pass = 1; if (ac < 2) { fail: puts(dasm_id); puts("Copyright (c) 1988-2008 by various authors (see file AUTHORS)."); puts("License GPLv2+: GNU GPL version 2 or later (see file COPYING)."); puts("DASM is free software: you are free to change and redistribute it."); puts("There is ABSOLUTELY NO WARRANTY, to the extent permitted by law."); puts(""); puts("Usage: dasm sourcefile [options]"); puts(""); puts("-f# output format 1-3 (default 1)"); puts("-oname output file name (else a.out)"); puts("-lname list file name (else none generated)"); puts("-Lname list file, containing all passes"); puts("-sname symbol dump file name (else none generated)"); puts("-v# verboseness 0-4 (default 0)"); puts("-d debug mode (for developers)"); puts("-Dsymbol define symbol, set to 0"); puts("-Dsymbol=expression define symbol, set to expression"); puts("-Msymbol=expression define symbol using EQM (same as -D)"); puts("-Idir search directory for INCLUDE and INCBIN"); puts("-p# maximum number of passes"); puts("-P# maximum number of passes, with fewer checks"); puts("-T# symbol table sorting (default 0 = alphabetical, 1 = address/value)"); puts("-E# error format (default 0 = MS, 1 = Dillon, 2 = GNU)"); puts(""); puts("Report bugs to [email protected] please!"); return ERROR_COMMAND_LINE; } for (i = 2; i < ac; ++i) { if ( ( av[i][0] == '-' ) || ( av[i][0] == '/' ) ) { char *str = av[i]+2; switch(av[i][1]) { /* TODO: need to improve option parsing and errors for it */ case 'E': F_errorformat = atoi(str); if (F_errorformat < ERRORFORMAT_DEFAULT || F_errorformat >= ERRORFORMAT_MAX ) { panic("Invalid error format for -E, must be 0, 1, 2"); } break; case 'T': F_sortmode = atoi(str); if (F_sortmode < SORTMODE_DEFAULT || F_sortmode >= SORTMODE_MAX ) { panic("Invalid sorting mode for -T option, must be 0 or 1"); } /* TODO: refactor into regular configuration [phf] */ *pbTableSort = (F_sortmode != SORTMODE_DEFAULT); break; case 'd': Xdebug = atoi(str) != 0; printf( "Debug trace %s\n", Xdebug ? "ON" : "OFF" ); break; case 'M': case 'D': while (*str && *str != '=') ++str; if (*str == '=') { *str = 0; ++str; } else { str = "0"; } Av[0] = av[i]+2; if (av[i][1] == 'M') v_eqm(str, NULL); else v_set(str, NULL); break; case 'f': /* F_format */ F_format = atoi(str); if (F_format < FORMAT_DEFAULT || F_format >= FORMAT_MAX ) panic("Illegal format specification"); break; case 'o': /* F_outfile */ F_outfile = str; nofile: if (*str == 0) panic("-o Switch requires file name."); break; case 'L': F_ListAllPasses = 1; /* fall through to 'l' */ case 'l': /* F_listfile */ F_listfile = str; goto nofile; case 'P': /* F_Passes */ bDoAllPasses = true; /* fall through to 'p' */ case 'p': /* F_passes */ nMaxPasses = atoi(str); break; case 's': /* F_symfile */ F_symfile = str; goto nofile; case 'v': /* F_verbose */ F_verbose = atoi(str); break; case 'I': v_incdir(str, NULL); break; default: goto fail; } continue; } goto fail; } /* INITIAL SEGMENT */ { SEGMENT *seg = (SEGMENT *)permalloc(sizeof(SEGMENT)); seg->name = strcpy(permalloc(sizeof(ISEGNAME)), ISEGNAME); seg->flags= seg->rflags = seg->initflags = seg->initrflags = SF_UNKNOWN; Csegment = Seglist = seg; } /* TOP LEVEL IF */ { IFSTACK *ifs = (IFSTACK *)zmalloc(sizeof(IFSTACK)); ifs->file = NULL; ifs->flags = IFF_BASE; ifs->acctrue = 1; ifs->xtrue = 1; Ifstack = ifs; } nextpass: if ( F_verbose ) { puts(""); printf("START OF PASS: %d\n", pass); } Localindex = Lastlocalindex = 0; Localdollarindex = Lastlocaldollarindex = 0; /*_fmode = 0x8000;*/ FI_temp = fopen(F_outfile, "wb"); /*_fmode = 0;*/ Fisclear = 1; CheckSum = 0; if (FI_temp == NULL) { printf("Warning: Unable to [re]open '%s'\n", F_outfile); return ERROR_FILE_ERROR; } if (F_listfile) { FI_listfile = fopen(F_listfile, F_ListAllPasses && (pass > 1)? "a" : "w"); if (FI_listfile == NULL) { printf("Warning: Unable to [re]open '%s'\n", F_listfile); return ERROR_FILE_ERROR; } } pushinclude(av[1]); while ( pIncfile ) { for (;;) { const char *comment; if ( pIncfile->flags & INF_MACRO) { if ( pIncfile->strlist == NULL) { Av[0] = ""; v_mexit(NULL, NULL); continue; } strcpy(buf, pIncfile->strlist->buf); pIncfile->strlist = pIncfile->strlist->next; } else { if (fgets(buf, MAXLINE, pIncfile->fi) == NULL) break; } if (Xdebug) printf("%08lx %s\n", (unsigned long) pIncfile, buf); comment = cleanup(buf, false); ++pIncfile->lineno; mne = parse(buf); if (Av[1][0]) { if (mne) { if ((mne->flags & MF_IF) || (Ifstack->xtrue && Ifstack->acctrue)) (*mne->vect)(Av[2], mne); } else { if (Ifstack->xtrue && Ifstack->acctrue) asmerr( ERROR_UNKNOWN_MNEMONIC, false, Av[1] ); } } else { if (Ifstack->xtrue && Ifstack->acctrue) programlabel(); } if (F_listfile && ListMode) outlistfile(comment); } while (Reploop && Reploop->file == pIncfile) rmnode((void **)&Reploop, sizeof(REPLOOP)); while (Ifstack->file == pIncfile) rmnode((void **)&Ifstack, sizeof(IFSTACK)); fclose( pIncfile->fi ); free( pIncfile->name ); --Inclevel; rmnode((void **)&pIncfile, sizeof(INCFILE)); if ( pIncfile ) { /* if (F_verbose > 1) printf("back to: %s\n", Incfile->name); */ if (F_listfile) fprintf(FI_listfile, "------- FILE %s\n", pIncfile->name); } } if ( F_verbose >= 1 ) ShowSegments(); if ( F_verbose >= 3 ) { if ( !Redo || ( F_verbose == 4 ) ) ShowSymbols( stdout, *pbTableSort ); ShowUnresolvedSymbols(); } closegenerate(); fclose(FI_temp); if (FI_listfile) fclose(FI_listfile); if (Redo) { if ( !bDoAllPasses ) if (Redo == oldredo && Redo_why == oldwhy && Redo_eval == oldeval) { ShowUnresolvedSymbols(); return ERROR_NOT_RESOLVABLE; } oldredo = Redo; oldwhy = Redo_why; oldeval = Redo_eval; Redo = 0; Redo_why = 0; Redo_eval = 0; Redo_if <<= 1; ++pass; if ( bStopAtEnd ) { printf("Unrecoverable error(s) in pass, aborting assembly!\n"); } else if ( pass > nMaxPasses ) { char sBuffer[64]; sprintf( sBuffer, "%d", pass ); return asmerr( ERROR_TOO_MANY_PASSES, false, sBuffer ); } else { clearrefs(); clearsegs(); goto nextpass; } } return nError; }
void v_mnemonic(char *str, MNE *mne) { register int addrmode; register SYMBOL *sym; register uword opcode; short opidx; SYMBOL *symbase; int opsize; Csegment->flags |= SF_REF; programlabel(); symbase = eval(str, 1); if (Xtrace) printf("PC: %04lx MNE: %s addrmode: %d ", Csegment->org, mne->name, symbase->addrmode); for (sym = symbase; sym; sym = sym->next) { if (sym->flags & SYM_UNKNOWN) { ++Redo; Redo_why |= 1 << 0; } } sym = symbase; if (mne->flags & MF_IMOD) { if (sym->next) { sym->addrmode = AM_BITMOD; if ((mne->flags & MF_REL) && sym->next) sym->addrmode = AM_BITBRAMOD; } } addrmode = sym->addrmode; if ((sym->flags & SYM_UNKNOWN) || sym->value >= 0x100) opsize = 2; else opsize = (sym->value) ? 1 : 0; while (badcode(mne,addrmode) && Cvt[addrmode]) addrmode = Cvt[addrmode]; if (Xtrace) printf("mnemask: %08lx adrmode: %d Cvt[am]: %d\n", mne->okmask, addrmode, Cvt[addrmode]); if (badcode(mne,addrmode)) { asmerr(5,0); freesymbollist(symbase); return; } if (Mnext >= 0 && Mnext < NUMOC) { /* Force */ addrmode = Mnext; if (badcode(mne,addrmode)) { asmerr(19,0); freesymbollist(symbase); return; } } if (Xtrace) printf("final addrmode = %d\n", addrmode); while (opsize > Opsize[addrmode]) { if (Cvt[addrmode] == 0 || badcode(mne,Cvt[addrmode])) { if (sym->flags & SYM_UNKNOWN) break; asmerr(14,0); break; } addrmode = Cvt[addrmode]; } opcode = mne->opcode[addrmode]; opidx = 1 + (opcode > 0xFF); if (opidx == 2) { Gen[0] = opcode >> 8; Gen[1] = opcode; } else {