123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788 |
- /*
- * Andrea Di Biagio
- * Politecnico di Milano, 2007
- *
- * asm_engine.c
- * Formal Languages & Compilers Machine, 2007/2008
- *
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include "asm_engine.h"
- #include "asm_debug.h"
- /* Function used when a compare is needed between two labels */
- static int compareLabels (void *labelA, void *labelB);
- /* Function used to produce the header of an object file.
- * This function returns ASM_OK if everything went good*/
- static int print_header_infos(FILE *fp);
- /* Function that translates every code and data segment.
- * This function returns ASM_OK if everything went good */
- static int translateCode(t_translation_infos *infos, FILE *fp);
- /* This function translates a single instruction found into the
- * code segment. Returns ASM_OK if everything went good */
- static int translateInstruction(t_translation_infos *infos
- , t_asm_instruction *inst, FILE *fp);
- /* This function translates a single block of data found into a
- * data segment. Returns ASM_OK if everything went good */
- static int translateData(t_translation_infos *infos
- , t_asm_data *inst, FILE *fp);
- /* The function `getBinaryOpcode' returns the coded opcode that will
- * be stored into the object file */
- static int getBinaryOpcode(int opcode);
- /* This function returns the index of the given instruction/data
- * that is stored inside the macro block of code plus data */
- static int getInstructionOrDataIndex(t_translation_infos *infos, void *target);
- /* this function is directly called from `finalizeStructures'. The main
- * goal of this function is: free all the memory associated with the
- * labels */
- static void finalizeLabels(t_list *labels);
- /* This function returns the index of the given instruction/data
- * that is stored inside the macro block of code plus data */
- int getInstructionOrDataIndex(t_translation_infos *infos
- , void *target)
- {
- t_list *target_element;
- int position;
- /* the list is empty */
- if (infos->code == NULL)
- return ASM_INVALID_MEMORY_OFFSET;
-
- /* preconditions: infos and inst MUST NOT be NULL references! */
- target_element = findElement(infos->code, target);
- if (target_element == NULL)
- return ASM_INVALID_MEMORY_OFFSET;
- /* retrieve the position of the statement */
- position = getPosition(infos->code, target_element);
- /* the code list doesn't hold target_element */
- if (position == -1)
- return ASM_INVALID_MEMORY_OFFSET;
- /* return the displacement in bytes from the beginning
- * of the instruction segment */
- if (position < infos->codesize)
- return ( ((position * ASM_INSTRUCTION_SIZE) / ASM_ALIGMENT_SIZE)
- + ((((position *ASM_INSTRUCTION_SIZE)
- % ASM_ALIGMENT_SIZE) > 0)? 1:0) );
- else
- {
- t_list *current_elem;
- t_asm_data *current_data;
-
- int counter = 0;
- current_elem = getElementAt(infos->code, infos->codesize);
- assert(current_elem != NULL);
- counter = ( ((infos->codesize * ASM_INSTRUCTION_SIZE) / ASM_ALIGMENT_SIZE)
- + ((((infos->codesize * ASM_INSTRUCTION_SIZE)
- % ASM_ALIGMENT_SIZE) > 0)? 1:0) );
- while (current_elem != NULL && LDATA(current_elem) != target)
- {
- current_data = LDATA(current_elem);
- if (current_data->dataType == ASM_WORD)
- {
- counter += (ASM_WORD_SIZE / ASM_ALIGMENT_SIZE)
- + (((ASM_WORD_SIZE % ASM_ALIGMENT_SIZE) > 0)? 1 : 0);
- }
- else if (current_data->dataType == ASM_SPACE)
- {
- /* precondition always verified */
- assert(current_data->value > 0);
- counter += (current_data->value / ASM_ALIGMENT_SIZE)
- + (((current_data->value % ASM_ALIGMENT_SIZE) > 0)? 1: 0);
- }
- current_elem = LNEXT(current_elem);
- }
- return counter;
- }
- return -1;
- }
- /* this function translates a single block of data found into a
- * data segment. Returns ASM_OK if everything went good */
- int translateData(t_translation_infos *infos
- , t_asm_data *data, FILE *fp)
- {
- if (data == NULL)
- return ASM_UNDEFINED_DATA;
-
- if (data->dataType == ASM_WORD)
- {
- /* postcondition: print on file the coded data */
- if (fwrite(&(data->value), ASM_WORD_SIZE, 1, fp) != 1)
- return ASM_FWRITE_ERROR;
- return ASM_OK;
- }
- else if (data->dataType == ASM_SPACE)
- {
- char *zero_val;
- /* preconditions: data->value must be >= 0 */
- if (data->value < 0)
- return ASM_INVALID_DATA_FORMAT;
- /* force alignment to 4 bytes */
- if (data->value % ASM_WORD_SIZE != 0)
- data->value = data->value + (data->value % ASM_WORD_SIZE);
- /* initialize the value `zero_val' */
- zero_val = _ASM_ALLOC_FUNCTION(sizeof(char) * data->value);
- if (zero_val == NULL)
- return ASM_OUT_OF_MEMORY;
- /* set the block of memory to zero */
- memset(zero_val, 0, data->value);
-
- /* postcondition: print on file the coded data */
- if (fwrite(zero_val, data->value, 1, fp) != 1)
- {
- _ASM_FREE_FUNCTION(zero_val);
- return ASM_FWRITE_ERROR;
- }
- _ASM_FREE_FUNCTION(zero_val);
- return ASM_OK;
- }
-
- /* default: the data format in unknown */
- return ASM_INVALID_DATA_FORMAT;
- }
- /* This function translates a single instruction found into the
- * code segment. Returns ASM_OK if everything went good */
- int translateInstruction(t_translation_infos *infos
- , t_asm_instruction *inst, FILE *fp)
- {
- int instruction;
- int pattern;
- int func;
-
- /* preconditions */
- if (inst == NULL)
- return ASM_UNDEFINED_INSTRUCTION;
-
- if (fp == NULL)
- return ASM_INVALID_INPUT_FILE;
-
- #ifndef NDEBUG
- fprintf(stderr, "Coding instruction: [opcode == %s, format == %s] --> "
- , opcode_toString(inst->opcode)
- , dataFormat_toString(inst->format) );
- #endif
-
- /* initialize the instruction */
- instruction = 0;
- /* set the format of instruction */
- if (inst->format == ASM_FORMAT_TER)
- {
- pattern = 0;
- }
- else if (inst->format == ASM_FORMAT_BIN)
- {
- pattern = (1 << 30);
- }
- else if ( (inst->format == ASM_FORMAT_UNR)
- || (inst->format == ASM_FORMAT_NULL) )
- {
- pattern = (1 << 31);
- }
- else
- {
- assert(inst->format == ASM_FORMAT_JMP);
- pattern = (3 << 30);
- }
-
- /* update the instruction format value */
- instruction = pattern;
-
- /* initialize the opcode information */
- pattern = getBinaryOpcode(inst->opcode);
- /* test if the opcode is valid */
- if (pattern == INVALID_OPCODE)
- return ASM_INVALID_OPCODE;
-
- /* update the instruction format value */
- instruction = instruction + (pattern << 26);
-
- /* initialize the value of `func' */
- func = 0;
-
- if (inst->format == ASM_FORMAT_TER)
- {
- if ((inst->reg_1)->indirect)
- func = 4;
- if ((inst->reg_3)->indirect)
- func = func + 8;
-
- instruction = instruction + ( ((inst->reg_1)->ID) << 21);
- instruction = instruction + ( ((inst->reg_2)->ID) << 16);
- instruction = instruction + ( ((inst->reg_3)->ID) << 11);
- instruction = instruction + func;
- }
- else if (inst->format == ASM_FORMAT_BIN)
- {
- instruction = instruction + ( ((inst->reg_1)->ID) << 21);
- instruction = instruction + ( ((inst->reg_2)->ID) << 16);
- instruction = instruction + ( inst->immediate & 0x0000FFFF);
- }
- else if (inst->format == ASM_FORMAT_UNR)
- {
- instruction = instruction + ( ((inst->reg_1)->ID) << 21);
- if ((inst->address)->label != NULL)
- {
- int destinationIndex;
-
- /* we have to retrieve the position of the requested data */
- destinationIndex = getInstructionOrDataIndex
- (infos, ((inst->address)->label)->data);
- /* test if the destinationIndex is a valid destination */
- if (destinationIndex == ASM_INVALID_MEMORY_OFFSET)
- return ASM_INVALID_LABEL_FOUND;
-
- /* update the displacement information */
- instruction = instruction
- + ( destinationIndex & 0x000FFFFF);
- }
- else
- {
- instruction = instruction + ( (inst->address)->addr & 0x000FFFFF);
- }
- }
- else if (inst->format == ASM_FORMAT_NULL)
- {
- /* DOES NOTHING */
- }
- else
- {
- /* test a precondition */
- assert(inst->format == ASM_FORMAT_JMP);
-
- if ((inst->address)->label != NULL)
- {
- int currentIndex;
- int destinationIndex;
-
- /* we have to retrieve the displacement between this
- * instruction and the instruction referred by the
- * label */
- currentIndex = getInstructionOrDataIndex(infos, inst);
- destinationIndex = getInstructionOrDataIndex
- (infos, ((inst->address)->label)->data);
-
- /* test if the destinationIndex is a valid destination */
- if (destinationIndex == ASM_INVALID_MEMORY_OFFSET)
- return ASM_INVALID_LABEL_FOUND;
-
- /* postcondition that MUST be always verified */
- assert(destinationIndex < infos->codesize);
-
- /* update the displacement information */
- instruction = instruction
- + ( (destinationIndex - currentIndex) & 0x000FFFFF);
- }
- else
- {
- instruction = instruction + ( (inst->address)->addr & 0x000FFFFF);
- }
- }
-
- /* postcondition: print on file the coded instruction */
- if (fwrite(&instruction, 4, 1, fp) != 1)
- return ASM_FWRITE_ERROR;
- #ifndef NDEBUG
- fprintf(stderr, "Coded Instruction:\t[0x%08x] \n", instruction);
- #endif
- return ASM_OK;
- }
- /* function used when a compare is needed between two labels */
- int compareLabels (void *labelA, void *labelB)
- {
- t_asm_label *asm_labelA;
- t_asm_label *asm_labelB;
-
- /* preconditions */
- if (labelA == NULL)
- {
- if (labelB == NULL)
- return 1;
- return 0;
- }
-
- if (labelB == NULL)
- return 0;
-
- /* initialize labels */
- asm_labelA = (t_asm_label *) labelA;
- asm_labelB = (t_asm_label *) labelB;
-
- /* verify the consistency of this operation */
- assert(asm_labelA->ID != NULL);
- assert(asm_labelB->ID != NULL);
- /* postcondition */
- return (!strcmp(asm_labelA->ID, asm_labelB->ID));
- }
- /* create an instance of `t_translation_info' initializing the internal data
- * of every field of the structure */
- t_translation_infos * initStructures(int *errorcode)
- {
- t_translation_infos *result;
-
- /* allocate memory for an instance of `t_translation_infos' */
- result = _ASM_ALLOC_FUNCTION(sizeof(t_translation_infos));
-
- /* test the out of memory condition */
- if (result == NULL)
- {
- /* update the value of `errorcode' */
- (*errorcode) = ASM_OUT_OF_MEMORY;
- return NULL;
- }
- /* no errors encountered so far */
- (*errorcode) = ASM_OK;
-
- /* initialize the content of `result' */
- result->code = NULL;
- result->labels = NULL;
- result->codesize = 0;
-
- /* return a new instance of `t_translation_infos' */
- return result;
- }
- /* Insert an instruction inside the `code' list of `infos' */
- int addInstruction(t_translation_infos *infos
- , t_asm_instruction *instruction)
- {
- /* preconditions */
- if (infos == NULL)
- return ASM_NOT_INITIALIZED_INFO;
-
- if (instruction == NULL)
- return ASM_UNDEFINED_INSTRUCTION;
- /* update the list of instructions */
- infos->code = addElement(infos->code, instruction, infos->codesize);
-
- /* update the codesize */
- infos->codesize++;
- /* notify that everything went correctly */
- return ASM_OK;
- }
- /* Insert a new label. The label must be initialized externally */
- int insertLabel(t_translation_infos *infos, t_asm_label *label)
- {
- /* preconditions */
- if (infos == NULL)
- return ASM_NOT_INITIALIZED_INFO;
-
- if (label == NULL)
- return ASM_INVALID_LABEL_FOUND;
-
- /* update the list of labels */
- infos->labels = addFirst(infos->labels, label);
-
- /* notify that everything went correctly */
- return ASM_OK;
- }
- /* find a label with a given `ID' */
- t_asm_label * findLabel(t_translation_infos *infos, char *ID, int *asm_errorcode)
- {
- t_asm_label pattern;
- t_list *label_element;
-
- /* preconditions */
- if (infos == NULL && asm_errorcode != NULL)
- (*asm_errorcode) = ASM_NOT_INITIALIZED_INFO;
-
- if (ID == NULL && asm_errorcode != NULL)
- (*asm_errorcode) = ASM_INVALID_LABEL_FOUND;
-
- /* initialize the value of `asm_errorcode' */
- (*asm_errorcode) = ASM_OK;
-
- /* initialize `pattern' */
- pattern.ID = ID;
- pattern.data = NULL;
- /* search the label */
- label_element = CustomfindElement(infos->labels, &pattern, compareLabels);
- /* if not found return a NULL pointer */
- if (label_element == NULL)
- return NULL;
- /* return the label found */
- return (t_asm_label *) LDATA(label_element);
- }
- /* remove a label */
- int removeLabel(t_translation_infos *infos, char *ID)
- {
- t_asm_label *result;
- int asm_errorcode;
-
- /* initialize the value of `asm_errorcode' */
- asm_errorcode = ASM_OK;
-
- /* initialize the value of `result' */
- result = findLabel(infos, ID, &asm_errorcode);
-
- /* postconditions */
- if (result == NULL)
- return asm_errorcode;
-
- /* remove the label from the list */
- infos->labels = removeElement(infos->labels, result);
-
- return asm_errorcode;
- }
- /* add a block of data into the data segment */
- int addData(t_translation_infos *infos, t_asm_data *data)
- {
- /* preconditions */
- if (infos == NULL)
- return ASM_NOT_INITIALIZED_INFO;
-
- if (data == NULL)
- return ASM_UNDEFINED_DATA;
-
- /* update the list of instructions */
- infos->code = addElement(infos->code, data, -1);
- return ASM_OK;
- }
- /* finalization of the `infos' structure */
- int finalizeStructures(t_translation_infos *infos)
- {
- if (infos == NULL)
- return ASM_NOT_INITIALIZED_INFO;
-
- if (infos->code != NULL)
- {
- t_list *current_element;
- t_asm_instruction *current_instr;
- /* initialize `data' */
- current_element = infos->code;
-
- while ((current_element != NULL) && (infos->codesize > 0) )
- {
- current_instr = (t_asm_instruction *) LDATA(current_element);
-
- /* free memory associated with the current instruction */
- freeInstruction(current_instr);
- /* update the value of `current_element' */
- current_element = LNEXT(current_element);
- infos->codesize --;
- }
- while (current_element != NULL)
- {
- /* free memory associated with the current data info. */
- freeData((t_asm_data *) LDATA(current_element));
-
- /* update the value of `current_element' */
- current_element = LNEXT(current_element);
- }
- /* free the code and data segment infos */
- freeList(infos->code);
- }
-
- /* remove labels */
- finalizeLabels(infos->labels);
-
- /* free the memory block associated with `infos' */
- _ASM_FREE_FUNCTION(infos);
-
- return ASM_OK;
- }
- /* begin the translation process */
- int asm_writeObjectFile(t_translation_infos *infos, char *output_file)
- {
- FILE *fp;
- int errorcode;
- if (output_file == NULL)
- {
- /* set "output.o" as output file name */
- output_file = "output.o";
- }
- #ifndef NDEBUG
- fprintf(stdout, "\n\n*******************************************\n");
- fprintf(stdout, "INITIALIZE OUTPUT FILE: %s. \n", output_file);
- fprintf(stdout, "CODE SEGMENT has a size of %d instructions \n", infos->codesize);
- fprintf(stdout, "DATA SEGMENT has a size of %d elements \n"
- , (getLength(infos->code) - infos->codesize) );
- fprintf(stdout, "NUMBER OF LABELS : %d. \n", getLength(infos->labels));
- fprintf(stdout, "*******************************************\n\n");
- #endif
-
- /* open a new file */
- fp = fopen(output_file, "w");
- if (fp == NULL)
- return ASM_FOPEN_ERROR;
-
- /* print the header of the object file */
- errorcode = print_header_infos(fp);
-
- if (errorcode != ASM_OK)
- {
- if (fclose(fp) == EOF)
- return ASM_FCLOSE_ERROR;
- return errorcode;
- }
-
- /* print the code and data segment */
- errorcode = translateCode(infos, fp);
- if (errorcode != ASM_OK)
- {
- if (fclose(fp) == EOF)
- return ASM_FCLOSE_ERROR;
- return errorcode;
- }
- /* print the trailer informations */
- //DOES NOTHING
- /* close the file and return */
- errorcode = fclose(fp);
- if (errorcode == EOF)
- return ASM_FCLOSE_ERROR;
-
- return ASM_OK;
- }
- /* Function that translates every code and data segment.
- * This function returns ASM_OK if everything went good */
- int translateCode(t_translation_infos *infos, FILE *fp)
- {
- int instruction_counter;
- t_list *current_instruction;
- void *instruction_or_data;
- int errorcode;
-
- /* unchecked preconditions: pf and infos are different from NULL */
-
- if (infos->code == NULL)
- return ASM_CODE_NOT_PRESENT;
-
- /* initialize the instruction_counter */
- instruction_counter = 0;
- current_instruction = infos->code;
- errorcode = ASM_OK;
-
- /* translate the instruction segment */
- while (instruction_counter < infos->codesize)
- {
- instruction_or_data = LDATA(current_instruction);
- assert(instruction_or_data != NULL);
-
- /* translate every single instruction */
- errorcode = translateInstruction
- (infos, (t_asm_instruction *) instruction_or_data, fp);
- /* verify the errorcode */
- if (errorcode != ASM_OK)
- return errorcode;
-
- /* update the instruction counter and the current instruction data */
- instruction_counter++;
- current_instruction = LNEXT(current_instruction);
- }
- #ifndef NDEBUG
- fprintf(stderr, "\n");
- #endif
-
- /* translate the data segment */
- while (current_instruction != NULL)
- {
- instruction_or_data = LDATA(current_instruction);
- assert(instruction_or_data != NULL);
-
- /* translate every single element of data */
- #ifndef NDEBUG
- fprintf(stderr, "Adding data into the data segment [datatype == %s \t; "
- , dataType_toString(((t_asm_data *)instruction_or_data)->dataType) );
- fprintf(stderr, "value == 0x%08x] \n"
- , ((t_asm_data *)instruction_or_data)->value);
- #endif
-
- errorcode = translateData(infos, (t_asm_data *) instruction_or_data, fp);
-
- /* verify the errorcode */
- if (errorcode != ASM_OK)
- return errorcode;
-
- current_instruction = LNEXT(current_instruction);
- }
-
- #ifndef NDEBUG
- fprintf(stderr, "\n");
- #endif
- return ASM_OK;
- }
- /* Function used to produce the header of an object file.
- * This function returns ASM_OK if everything went good*/
- int print_header_infos(FILE *fp)
- {
- char begin_header[4] = {'L', 'F', 'C', 'M'};
- char other_data[16];
- /* preconditions */
- if (fp == NULL)
- return ASM_INVALID_INPUT_FILE;
-
- /* write the starting string `LFCM' without the end of string '\0' */
- fputc(begin_header[0], fp);
- fputc(begin_header[1], fp);
- fputc(begin_header[2], fp);
- fputc(begin_header[3], fp);
-
- /* set `other_data' */
- memset(other_data, 0, 16);
-
- /* write the other_data infos */
- if (fwrite(other_data, 1, 16, fp) != 16)
- return ASM_FWRITE_ERROR;
-
- return ASM_OK;
- }
- /* The function `getBinaryOpcode' returns the coded opcode that will
- * be stored into the object file */
- int getBinaryOpcode(int opcode)
- {
- switch(opcode)
- {
- case ADD_OP: return 0;
- case SUB_OP: return 1;
- case ANDL_OP: return 2;
- case ORL_OP: return 3;
- case XORL_OP: return 4;
- case ANDB_OP: return 5;
- case ORB_OP: return 6;
- case XORB_OP: return 7;
- case MUL_OP: return 8;
- case DIV_OP: return 9;
- case SHL_OP: return 10;
- case SHR_OP: return 11;
- case ROTL_OP: return 12;
- case ROTR_OP: return 13;
- case NEG_OP: return 14;
- case SPCL_OP: return 15;
- case ADDI_OP: return 0;
- case SUBI_OP: return 1;
- case ANDLI_OP: return 2;
- case ORLI_OP: return 3;
- case XORLI_OP: return 4;
- case ANDBI_OP: return 5;
- case ORBI_OP: return 6;
- case XORBI_OP: return 7;
- case MULI_OP: return 8;
- case DIVI_OP: return 9;
- case SHLI_OP: return 10;
- case SHRI_OP: return 11;
- case ROTLI_OP: return 12;
- case ROTRI_OP: return 13;
- case NOTL_OP: return 14;
- case NOTB_OP: return 15;
- case NOP_OP: return 0;
- case MOVA_OP: return 1;
- case LOAD_OP: return 4;
- case STORE_OP: return 5;
- case JSR_OP: return 2;
- case RET_OP: return 3;
- case HALT_OP: return 6;
- case SEQ_OP: return 7;
- case SGE_OP: return 8;
- case SGT_OP: return 9;
- case SLE_OP: return 10;
- case SLT_OP: return 11;
- case SNE_OP: return 12;
- case READ_OP: return 13;
- case WRITE_OP: return 14;
- case BT_OP: return 0;
- case BF_OP: return 1;
- case BHI_OP: return 2;
- case BLS_OP: return 3;
- case BCC_OP: return 4;
- case BCS_OP: return 5;
- case BNE_OP: return 6;
- case BEQ_OP: return 7;
- case BVC_OP: return 8;
- case BVS_OP: return 9;
- case BPL_OP: return 10;
- case BMI_OP: return 11;
- case BGE_OP: return 12;
- case BLT_OP: return 13;
- case BGT_OP: return 14;
- case BLE_OP: return 15;
- default: return INVALID_OPCODE;
- }
- }
- void finalizeLabels(t_list *labels)
- {
- t_list *current_element;
- t_asm_label *current_label;
-
- if (labels == NULL)
- return;
- current_element = labels;
- while(current_element != NULL)
- {
- current_label = (t_asm_label *) LDATA(current_element);
- if (current_label != NULL)
- {
- if (current_label->ID != NULL)
- free(current_label->ID);
- _ASM_FREE_FUNCTION(current_label);
- }
-
- current_element = LNEXT(current_element);
- }
- freeList(labels);
- }
|