#include #include #include #include #include #include "asm.h" #include "defines.h" #include "main.ext" #include "structs.h" #include "externs.h" #include "asm.pro" ///////////////////////////////////////////////////////////////////////////// UWORD assemble() { clrscr(); printf("\n\n Assembler"); gotoxy(30,8); printf("\nEnter Source filename -> "); gets(SrcFile); printf("\nEnter Relocation Value -> "); gets(String); OrgLoc = atoi(String); //strcpy(SrcFile, "source.asm"); if(access(SrcFile, EXIST) == 0 ) { if(passone(SrcFile) != ERROR ) { // assembler pass one if( passtwo() != ERROR ); { // assembler pass two write_object_file(); // save object file to disk gotoxy(18,20); printf("Assembly Complete. Object file written to disk."); pause(); } } else return(ERROR); } else { printf("\nError. File %s does not exist.", SrcFile); pause(); return(ERROR); } return(OK); } ///////////////////////////////////////////////////////////////////////////// UWORD passone(UBYTE * input_filename) { UBYTE output_filename[MAX_FILENAME]; UBYTE more_input; UBYTE line[MAX_LINE]; UBYTE * line_ptr; UBYTE instruction_number; UBYTE * nl_loc; UBYTE error; UBYTE pseudo_status; UBYTE symbol; strcpy(output_filename, "passone.out"); if( openfiles(input_filename, output_filename) != ERROR) { // variable Initializations memset(output_filename, NULL, sizeof(output_filename) ); memset(Instruction, 0xFF, sizeof(INSTRUCTION) * MAX_INSTRUCTIONS ); memset(SymTab, 0, sizeof(SYMTAB) * MAX_INSTRUCTIONS ); memset(line, NULL, sizeof(line) ); instruction_number = 0; InstructionPtr[instruction_number].lctr = LOC_CTR_START; error = FALSE; more_input = TRUE; // main input loop while( !feof(In_Ptr) && (more_input) && (!error) ) { memset(line, NULL, sizeof(line) ); fgets(line, sizeof(line),In_Ptr); // read in line from input file line_ptr = line; swapchars(line_ptr, TAB, SPACE); // replace tabs with spaces if(*line_ptr != NEWLINE) { nl_loc = strchr(line_ptr, NEWLINE); if(nl_loc) { *nl_loc = NULL; // replace newline with NULL } // save input for assembler pass two if(save_for_pass_two(line_ptr) == LINE_IS_NOT_COMMENT) { if( check_for_symbol(&line_ptr,SymTabPtr->symbol) == SYMBOL_FOUND ) symbol = TRUE; else symbol = FALSE; // get opcode and determine instruction length for Symbol Table if(extract_opcode(&line_ptr, &InstructionPtr->opcode ) == OK) { calc_instruction_length(&line_ptr,InstructionPtr); } else if( (pseudo_status = check_for_pseudo_op(&line_ptr, InstructionPtr, SymTabPtr)) == HALT ) more_input = FALSE; else if( pseudo_status != OK ) error = TRUE; if( (instruction_number) && (! error) ) { if( InstructionPtr->pseudo != ENDOFCODE ) InstructionPtr->lctr = ( (InstructionPtr - 1)->lctr + ( (InstructionPtr - 1)->instr_len) ); } else SymTabPtr->lctr = 0; if(!error) { SymTabPtr->lctr = InstructionPtr->lctr; SymTabPtr++; } } InstructionPtr++; instruction_number++; } } // end while } else return(ERROR); flushall(); fclose(Out_Ptr); fclose(In_Ptr); return(OK); } ///////////////////////////////////////////////////////////////////////////// UBYTE openfiles(UBYTE * in_file, UBYTE * out_file) { // open two files, one for input, one for output if ((In_Ptr = fopen(in_file, "rt")) == NULL) { printf("\nError Opening Input file %s", in_file); pause(); return(ERROR); } else { if ((Out_Ptr = fopen(out_file, "wt")) == NULL) { printf("\nError Opening Output file %s", out_file); pause(); return(ERROR); } } return(OK); } ///////////////////////////////////////////////////////////////////////////// UBYTE save_for_pass_two(UBYTE * current_line) { UBYTE * symbol_loc; // save "filtered" output for pass two. No comments are written out get_next_symbol(¤t_line); if( (symbol_loc = strchr(current_line, SYMBOL_TERM)) !=NULL ) { // strip off symbol, it's in the Symbol Table current_line = symbol_loc; get_next_symbol(¤t_line); } if( !check_for_comment(current_line) ) { // is this line a comment ? fprintf(Out_Ptr,"%s\n", current_line); // no, then write to output file for passtwo() fflush(Out_Ptr); return(LINE_IS_NOT_COMMENT); } else return(LINE_IS_COMMENT); } ///////////////////////////////////////////////////////////////////////////// UBYTE check_for_comment(UBYTE * line) { UBYTE offset = 0; // checks to see if current line is a comment while( *(line+offset) == SPACE) // find the first character that is NOT a space offset++; if( *(line+offset) == COMMENT_CHAR) // check to see if it is a comment line or not return(LINE_IS_COMMENT); else { line = (line+offset); // move ptr to first NON space character return(LINE_IS_NOT_COMMENT); } } ///////////////////////////////////////////////////////////////////////////// UBYTE check_for_symbol(UBYTE * * line, UBYTE * symbol_ptr) { UBYTE x; UBYTE * symbol; // looks to see if symbol (label) is present strcpy(Temp, *line); if(*line != NULL ) { strupr(*line); if( (symbol = strchr(Temp, SYMBOL_TERM)) != NULL) { *symbol = NULL; // now we can treat it as a string strcpy(symbol_ptr, Temp); // put symbol into symbol table *line = strchr(*line, SYMBOL_TERM); get_next_symbol(line); return(SYMBOL_FOUND); } } return(FALSE); } ///////////////////////////////////////////////////////////////////////////// // Find the first text word in a line so we can identify it as a symbol or opcode later void get_next_symbol(UBYTE * * line) { // moves pointer to first NON space character *line = strchr(*line, SPACE); if(*line != NULL) { while( ( **line == SPACE) && (*line != NULL) && ( **line != NEWLINE) ) (*line)++; } } ///////////////////////////////////////////////////////////////////////////// void swapchars(UBYTE * line, UBYTE before, UBYTE after) { UBYTE x = 0; // replaces tabs with spaces. Makes processing easier while( (*line != NULL) && (*line != NEWLINE) && (x++ < MAX_LINE) ) { if(*line == before) // if tab *line = after; /// replace with space line++; } } ///////////////////////////////////////////////////////////////////////////// UBYTE extract_opcode(UBYTE * * line, UWORD * opcode) { // looks to see if opcode is valid *opcode = 0; if( check_for_opcode(line, opcode) == OK ) { return(OK); } else return(ILLEGAL_OPCODE); } ///////////////////////////////////////////////////////////////////////////// UBYTE check_for_opcode(UBYTE * *line, UWORD * opcode_ptr) { UBYTE x; // returns actual opcode to caller for(x=0; x < MAX_OPCODES; x++) { if( strstr(*line, Opcodes[x].name) ) { *opcode_ptr = Opcodes[x].val; // opcode occupies upper 4 bits get_next_symbol( line); return(OK); } } return(ERROR); } ///////////////////////////////////////////////////////////////////////////// void calc_instruction_length(UBYTE * * line, INSTRUCTION * inst) { // determines instruction length based on opcode // All instructions are MODE 0 inst->opcode |= (MODE0 << 2); // mode occupies bits 2&3 switch(inst->opcode & OPCODE_MASK) { case HLT : inst->instr_len = ONE_BYTE; break; case LOD : case ADD : if( strchr(*line, IMMEDIATE_MODE) != NULL) { inst->instr_len = MODE1_LENGTH; } else { inst->instr_len = MODE0_LENGTH; } break; case STO : inst->instr_len = MODE0_LENGTH; break; case OUT : inst->instr_len = NO_MODE_LENGTH; break; case CALL : inst->instr_len = MODE0_LENGTH; break; case JZE : inst->instr_len = MODE0_LENGTH; break; case JMP : inst->instr_len = MODE0_LENGTH; break; case RET : inst->instr_len = ONE_BYTE; break; default : inst->instr_len = ILLEGAL_INSTRUCTION; break; } } ///////////////////////////////////////////////////////////////////////////// UBYTE check_for_pseudo_op(UBYTE * * line, INSTRUCTION * inst, SYMTAB * table) { INSTRUCTION * prev; static UBYTE first_time= FALSE; // lookss to see if opcode is a pseudo op prev = inst; prev --; // point to last instruction's location so we can use it to determine the // value for this Pseudo Op if( strstr( *line, "DC") ) { get_next_symbol(line); // move ptr to first NON space character inst->instr_len = 2; inst->eff_add = atoi(*line); if(!first_time) { inst->lctr = 1; first_time = TRUE; inst->lctr += (prev->lctr); // add one to previous value inst->pseudo = DC; } else { inst->lctr = 0; inst->lctr += ( (prev->lctr) + 2 ); // each value is a 16 bit word inst->pseudo = DC; } } else if( strstr( *line, "DS") ) { get_next_symbol(line); // move ptr to first NON space character inst->eff_add = atoi(*line); inst->instr_len = inst->eff_add; // this pseudo actually reserves an N byte array inst->lctr = 0; inst->lctr += ( (prev->lctr) + inst->eff_add ); inst->pseudo = DS; } else if( strstr( *line, "END") ) { get_next_symbol(line); get_next_symbol(line); // get program starting location ModuleStart = search_symtab(*line); // get starting address of module inst->instr_len = 2; inst->lctr = 0; inst->lctr += ( (prev->lctr) + 2 ); // each value is a 16 bit word inst->pseudo = END; ModuleEnd = inst->lctr ; // this actually represents the module size return(HALT); } else return(ERROR); return(OK); } ///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////