URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [tags/] [nog_patch_42/] [or1ksim/] [cpu/] [common/] [parse.c] - Rev 42
Go to most recent revision | Compare with Previous | Blame | View Log
/* parce.c -- Architecture independent load and parsing of assembly Copyright (C) 1999 Damjan Lampret, lampret@opencores.org This file is part of OpenRISC 1000 Architectural Simulator. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <ctype.h> #include <string.h> #include <stdlib.h> #include "parse.h" #include "abstract.h" #include "arch.h" #include "coff.h" #define MAXLINE_LEN 18000 extern char *disassembled; /* Unused mem memory marker. It is used when allocating program and data memory during parsing */ unsigned int freemem; int nonempty(char *line) { int i; for(i = 0; i < strlen(line); i++) if (!isspace(line[i])) return(1); return(0); } int nondigit(char *line) { int i; for(i = 0; i < strlen(line); i++) if (!isdigit(line[i])) return(1); return(0); } char *strtoken(char *in, char *out, int which) { char *super; char *sub; char *newline; super = strdup(in); sub = strtok(super, " \t"); while (sub && --which) sub = strtok(NULL, " \t"); if (sub && !which) { if ((newline = strchr(sub, '\n'))) newline[0] = '\0'; strcpy(out, sub); } else out[0] = '\0'; free(super); if ((newline = strchr(out, '\r'))) /* get rid of CR */ newline[0] = '\0'; return(out); } void adddatastr(char *str) { if (str) str++; else return; for(; *str && *str != '\"'; str++, freemem++) if (*str == '\\') switch (*++str) { case 'n': mem[freemem].data = '\n'; break; case 't': mem[freemem].data = '\t'; break; case 'r': mem[freemem].data = '\r'; break; case '0': mem[freemem].data = '\0'; break; default: break; } else mem[freemem].data = *str; } void adddataword(char *item) { unsigned long num; if (isdigit(*item)) num = strtoul(item, NULL, 0); else num = eval_label(item); debug("adddataword: [0x%x] <= %x\n", freemem, num); mem[freemem].data = (char) (num >> 24); mem[freemem + 1].data = (char) (num >> 16); mem[freemem + 2].data = (char) (num >> 8); mem[freemem + 3].data = (char) (num); freemem += 4; } void adddatahalf(char *item) { unsigned long num; if (isdigit(*item)) num = strtoul(item, NULL, 0); else num = eval_label(item); mem[freemem].data = (char) (num >> 8); mem[freemem + 1].data = (char) (num); freemem += 2; } void adddatabyte(char *item) { unsigned long num; if (isdigit(*item)) num = strtoul(item, NULL, 0); else num = eval_label(item); mem[freemem].data = (char) (num); freemem++; } void adddataspace(char *num) { freemem += atol(num); } void addlabel(char *label, unsigned long freemem) { struct label_entry **tmp; debug("Adding label %s at 0x%x\n", label, freemem); tmp = &mem[freemem].label; for (; *tmp; tmp = &((*tmp)->next)); *tmp = malloc(sizeof(**tmp)); (*tmp)->name = malloc(strlen(label)+1); strcpy((*tmp)->name, label); (*tmp)->next = NULL; return; } char null_str[1] = "\0"; void addprogram(char *insn, char *operands) { int h_insn_is_word_flag=0; char insn_first2_char[3]; debug("addprogram 1\n"); if (!mem[freemem].insn) { mem[freemem].insn = malloc(sizeof(*mem[freemem].insn)); mem[freemem].insn->insn = null_str; mem[freemem].insn->op1 = null_str; mem[freemem].insn->op2 = null_str; mem[freemem].insn->op3 = null_str; mem[freemem].insn->op4 = null_str; } else { printf("internal error: reloading the same location\n"); exit(1); } debug("addprogram 2\n"); mem[freemem].insn->insn = malloc(strlen(insn)+1); #ifdef OR16 strcpy(mem[freemem].insn->insn, insn); printf("half:%s:\n", insn); insn_first2_char[0]=insn[0]; insn_first2_char[1]=insn[1]; insn_first2_char[2]='\0'; debug("addprogram 3\n"); if(strcmp("h.", insn_first2_char) == 0) { if(strcmp("h.load32u", insn) == 0 || strcmp("h.load16u", insn) == 0 || strcmp("h.load8u", insn) == 0 || strcmp("h.stor32", insn) == 0 || strcmp("h.stor16", insn) == 0 || strcmp("h.stor8", insn) == 0 || strcmp("h.jal", insn) == 0 || /* strcmp("h.mtsr", insn) == 0 || strcmp("h.mfsr", insn) == 0 || */ strcmp("h.movi16ze", insn) == 0 || strcmp("h.immhi16u", insn) == 0 || strcmp("h.addi16s", insn) == 0 || strcmp("h.subi16s", insn) == 0 || strcmp("h.xori16", insn) == 0 || strcmp("h.ori16", insn) == 0 || strcmp("h.andi16", insn) == 0 ) h_insn_is_word_flag = 2; /* h.xxx insn AND occupy 4 bytes */ else h_insn_is_word_flag = 1; /* h.xxx insn AND occupy 2 bytes */ } else { h_insn_is_word_flag = 0; /* not h.xxx insn */ } #else debug("addprogram 4\n"); strcpy(mem[freemem].insn->insn, insn); debug("addprogram 5\n"); #endif /* op1 */ if (*operands) { mem[freemem].insn->op1 = malloc(strlen(operands)+1); strcpy(mem[freemem].insn->op1, operands); } debug("addprogram 6\n"); debug("operands:%s\n", operands); if (strstr(operands, OPERAND_DELIM)) { debug("addprogram 6a\n"); operands = strstr(mem[freemem].insn->op1, OPERAND_DELIM); *operands = '\0'; operands++; } else { debug("addprogram 6b\n"); #ifdef OR16 freemem += (h_insn_is_word_flag == 1) ? 2 : 4; #else freemem += 4; #endif return; } debug("addprogram 7\n"); /* op2 */ if (*operands) { mem[freemem].insn->op2 = malloc(strlen(operands)+1); strcpy(mem[freemem].insn->op2, operands); } if (strstr(operands, OPERAND_DELIM)) { operands = strstr(mem[freemem].insn->op2, OPERAND_DELIM); *operands = '\0'; operands++; } else { #ifdef OR16 freemem += (h_insn_is_word_flag == 1) ? 2 : 4; #else freemem += 4; #endif return; } debug("addprogram 8\n"); /* op3 */ if (*operands) { mem[freemem].insn->op3 = malloc(strlen(operands)+1); strcpy(mem[freemem].insn->op3, operands); } if (strstr(operands, OPERAND_DELIM)) { operands = strstr(mem[freemem].insn->op3, OPERAND_DELIM); *operands = '\0'; operands++; } else { #ifdef OR16 freemem += (h_insn_is_word_flag == 1) ? 2 : 4; #else freemem += 4; #endif return; } /* op4 */ if (*operands) { mem[freemem].insn->op4 = malloc(strlen(operands)+1); strcpy(mem[freemem].insn->op4, operands); } if (strstr(operands, OPERAND_DELIM)) { operands = strstr(mem[freemem].insn->op4, OPERAND_DELIM); *operands = '\0'; operands++; } #ifdef OR16 freemem += (h_insn_is_word_flag == 1) ? 2 : 4; #else freemem += 4; #endif return; } /* Non-architecture dependent parsing: stripping comments, filling abstract memory */ void parseline(char *inputline) { char item[MAXLINE_LEN]; char item2[MAXLINE_LEN]; int i = 0; /* Strip comments: simply terminate line where the first comment character appears. */ debug("PARSING: %s", inputline); while (inputline[i] != '\0') if (inputline[i] == COMMENT_CHAR) { inputline[i] = '\0'; break; } else i++; /* Get the first item from this line */ strtoken(inputline, item, 1); /* opcode */ strtoken(inputline, item2, 2); /* all the remaining one/two/three operands */ /* Is this item empty? Nothing to process, so return. */ if (strlen(item) == 0) return; /* Is this item a label? If yes, add it to the label table and return immediately. */ if (strstr(item, LABELEND_CHAR)) { *strstr(item, LABELEND_CHAR) = '\0'; addlabel(item, freemem); return; } /* Is this item a .directive? If yes, check for some supported and then return (even if unsupported found). */ if (item[0] == DIRECTIVE_CHAR) { if (strcmp(item, ".align") == 0) { int align = strtoul(item2, NULL, 0); if (!(freemem % align)) return; freemem &= -align; freemem += align; return; } else if (strcmp(item, ".org") == 0) { int addr = strtoul(item2, NULL, 0); freemem = addr; return; } else if (strcmp(item, ".ascii") == 0) { adddatastr(strstr(inputline, "\"")); return; } else if (strcmp(item, ".word") == 0) { adddataword(item2); return; } else if (strcmp(item, ".half") == 0) { adddatahalf(item2); return; } else if (strcmp(item, ".byte") == 0) { adddatabyte(item2); return; } else if (strcmp(item, ".space") == 0) { adddataspace(item2); return; } else /* .directive but not one of the supported */ return; } /* This item can only be an instruction. Get all operands and add everything to mem array but as a program. */ debug("%x: ", freemem); addprogram(item, item2); /* Also do static, single stats. */ addsstats(item, 0, 1); return; } /* Load big-endian COFF file. At the moment it doesn't load symbols yet. */ void readfile_coff(char *filename, short sections) { FILE *inputfs; char inputbuf[4]; unsigned long insn; signed long sectsize; COFF_AOUTHDR coffaouthdr; struct COFF_scnhdr coffscnhdr; int len; char item[MAXLINE_LEN]; char item2[MAXLINE_LEN]; int firstthree = 0; if (!(inputfs = fopen(filename, "r"))) { perror("readfile_coff"); exit(1); } if (fseek(inputfs, sizeof(struct COFF_filehdr), SEEK_SET) == -1) { fclose(inputfs); perror("readfile_coff"); exit(1); } if (fread(&coffaouthdr, sizeof(coffaouthdr), 1, inputfs) != 1) { fclose(inputfs); perror("readfile_coff"); exit(1); } while(sections--) { long scnhdr_pos = sizeof(struct COFF_filehdr) + sizeof(coffaouthdr) + sizeof(struct COFF_scnhdr) * firstthree; if (fseek(inputfs, scnhdr_pos, SEEK_SET) == -1) { fclose(inputfs); perror("readfile_coff"); exit(1); } if (fread(&coffscnhdr, sizeof(struct COFF_scnhdr), 1, inputfs) != 1) { fclose(inputfs); perror("readfile_coff"); exit(1); } printf("Section: %s,", coffscnhdr.s_name); printf(" vaddr: 0x%.8x,", COFF_LONG_H(coffscnhdr.s_vaddr)); printf(" size: 0x%.8x,", COFF_LONG_H(coffscnhdr.s_size)); printf(" scnptr: 0x%.8x\n", COFF_LONG_H(coffscnhdr.s_scnptr)); sectsize = COFF_LONG_H(coffscnhdr.s_size); /* A couple of sanity checks. */ if (COFF_LONG_H(coffscnhdr.s_vaddr) < MEMORY_START) { printf("Section %s starts out of ", coffscnhdr.s_name); printf("memory (at %x)\n", COFF_LONG_H(coffscnhdr.s_vaddr)); exit(1); } if (COFF_LONG_H(coffscnhdr.s_vaddr) + sectsize > MEMORY_START + MEMORY_LEN) { printf("Section %s ends out of ", coffscnhdr.s_name); printf("memory.\n"); exit(1); } if (++firstthree == 1 && strcmp(coffscnhdr.s_name, ".text") != 0) { printf("First section should be .text (%s instead)\n", coffscnhdr.s_name); exit(1); } if (firstthree == 2 && strcmp(coffscnhdr.s_name, ".data") != 0) { printf("Second section should be .data (%s instead)\n", coffscnhdr.s_name); exit(1); } if (firstthree == 3 && strcmp(coffscnhdr.s_name, ".bss") != 0) { printf("Third section should be .bss (%s instead)\n", coffscnhdr.s_name); exit(1); } /* loading section */ freemem = COFF_LONG_H(coffscnhdr.s_vaddr); if (fseek(inputfs, COFF_LONG_H(coffscnhdr.s_scnptr), SEEK_SET) == -1) { fclose(inputfs); perror("readfile_coff"); exit(1); } while (sectsize > 0 && (len = fread(&inputbuf, sizeof(inputbuf), 1, inputfs))) { insn = COFF_LONG_H(inputbuf); len = disassemble_insn(insn); sprintf(item, "%u", insn); adddataword(item); freemem -= len; if (len == 2) { fseek(inputfs, -2, SEEK_CUR); debug("readfile_coff: %x 0x%x ", sectsize, insn >> 16); } else debug("readfile_coff: %x 0x%x ", sectsize, insn); debug("%s\n", disassembled); strtoken(disassembled, item, 1); /* opcode */ strtoken(disassembled, item2, 2); /* all the remaining one/two/three operands */ addprogram(item, item2); sectsize -= len; } } if (firstthree < 3) { printf("One or more missing sections. At least"); printf(" three sections expected (.text, .data, .bss).\n"); exit(1); } if (firstthree > 3) { printf("Warning: one or more extra sections. These"); printf(" sections were handled as .data sections.\n"); } fclose(inputfs); printf("Finished loading COFF.\n"); return; } /* Load symbols from big-endian COFF file. */ void readsyms_coff(char *filename, unsigned long symptr, long syms) { FILE *inputfs; struct COFF_syment coffsymhdr; if (!(inputfs = fopen(filename, "r"))) { perror("readsyms_coff"); exit(1); } if (fseek(inputfs, symptr, SEEK_SET) == -1) { fclose(inputfs); perror("readsyms_coff"); exit(1); } while(syms--) { if (fread(&coffsymhdr, COFF_SYMESZ, 1, inputfs) != 1) { fclose(inputfs); perror("readsyms_coff"); exit(1); } debug("Symbol: %s,", coffsymhdr.e.e_name); debug(" val: 0x%.8x,", COFF_LONG_H(coffsymhdr.e_value)); debug(" auxs: %c\n", coffsymhdr.e_numaux); if (strlen(coffsymhdr.e.e_name) && strlen(coffsymhdr.e.e_name) < 9) addlabel(coffsymhdr.e.e_name, COFF_LONG_H(coffsymhdr.e_value)); } fclose(inputfs); printf("Finished loading symbols.\n"); return; } /* Load file and hand over every line to parse routine. */ void readfile_assembly(char *filename) { FILE *inputfs; char inputbuf[MAXLINE_LEN]; char *status; if (!(inputfs = fopen(filename, "r"))) { perror("readfile_assembly"); exit(1); } while ((status = fgets(inputbuf, sizeof(inputbuf), inputfs))) { if (nonempty(inputbuf)) parseline(inputbuf); } fclose(inputfs); return; } /* Identify file type and call appropriate readfile_X routine. It only handles orX-coff-big executables at the moment. */ void identifyfile(char *filename) { FILE *inputfs; struct COFF_filehdr coffhdr; size_t len; if (!(inputfs = fopen(filename, "r"))) { perror("identifyfile"); exit(1); } if (fread(&coffhdr, sizeof(coffhdr), 1, inputfs) == 1) { if (COFF_SHORT_H(coffhdr.f_magic) == 0x17a) { unsigned long opthdr_size; printf("COFF magic: 0x%.4x\n", COFF_SHORT_H(coffhdr.f_magic)); printf("COFF flags: 0x%.4x\n", COFF_SHORT_H(coffhdr.f_flags)); printf("COFF symptr: 0x%.8x\n", COFF_LONG_H(coffhdr.f_symptr)); if ((COFF_SHORT_H(coffhdr.f_flags) & COFF_F_EXEC) != COFF_F_EXEC) { printf("This COFF is not an executable.\n"); exit(1); } opthdr_size = COFF_SHORT_H(coffhdr.f_opthdr); if (opthdr_size != sizeof(COFF_AOUTHDR)) { printf("COFF optional header is missing or not recognized.\n"); printf("COFF f_opthdr: 0x%.2x\n", opthdr_size); exit(1); } fclose(inputfs); readfile_coff(filename, COFF_SHORT_H(coffhdr.f_nscns)); readsyms_coff(filename, COFF_LONG_H(coffhdr.f_symptr), COFF_LONG_H(coffhdr.f_nsyms)); return; } else { printf("Not COFF, trying to load as assembly.\n"); fclose(inputfs); readfile_assembly(filename); return; } } else perror("identifyfile"); fclose(inputfs); return; } void loadcode(char *filename) { freemem = MEMORY_START; memset(mem, 0, sizeof(mem)); identifyfile(filename); return; }
Go to most recent revision | Compare with Previous | Blame | View Log