URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [branches/] [stable_0_2_x/] [or1ksim/] [cpu/] [or32/] [generate.c] - Rev 709
Go to most recent revision | Compare with Previous | Blame | View Log
/* generate.c -- generates file execgen.c from instruction set 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 <stdlib.h> #include <stdio.h> #include <string.h> #include <stdarg.h> #include <ctype.h> #include "config.h" #include "opcode/or32.h" #include "abstract.h" #include "labels.h" #include "parse.h" #include "execute.h" #define LEAF_FLAG (0x80000000) #define SHIFT {int i; for (i = 0; i < level; i++) fprintf (fo, " ");} extern unsigned long *automata; extern struct temp_insn_struct { unsigned long insn; unsigned long insn_mask; int in_pass; } *ti; static char *in_file; inline void debug(int level, const char *format, ...) { char *p; va_list ap; #if DEBUG if ((p = malloc(1000)) == NULL) return; va_start(ap, format); (void) vsnprintf(p, 1000, format, ap); va_end(ap); printf("%s\n", p); fflush(stdout); free(p); #endif } int output_function (FILE *fo, const char *func_name, int level) { FILE *fi; if ((fi = fopen (in_file, "rt")) == NULL) return 1; while (!feof (fi)) { char line[10000], *str = line; fgets (str, sizeof (line), fi); line[sizeof(line) - 1] = 0; if (strncmp (str, "INSTRUCTION (", 13) == 0) { char *s; str += 13; while (isspace (*str)) str++; s = str; while (*s && *s != ')') s++; *s = 0; while (isspace(*(s - 1))) s--; *s = 0; if (strcmp (str, func_name) == 0) { char c; int olevel = 1; str += strlen (str) + 1; while (isspace (*str)) str++; s = str; while (*s && *s != '\n' && *s != '\r') s++; *s = 0; while (isspace(*(s - 1))) s--; *s = 0; fprintf (fo, "%s", str); fprintf (fo, " /* \"%s\" */\n", func_name); SHIFT; do { c = fgetc (fi); if (c == '}') {olevel--;} else if (c == '{') {olevel++;} fputc (c, fo); if (c == '\n') SHIFT; } while (olevel); return 0; } } } fprintf (fo, "{\n"); level++; SHIFT; fprintf (fo, "%s ();\n", func_name); level--; SHIFT; fprintf (fo, "}"); return 0; } /* Parses and puts operands into op[] structure. Replacement for eval_operands routine. */ static void gen_eval_operands (FILE *fo, int insn_index, int level) { struct insn_op_struct *opd = op_start[insn_index]; int dis = 0; int no = 0; int firstd = 1; while (1) { int nbits = 0, first = 1; while (1) { SHIFT; fprintf (fo, "tmp %s= ((insn >> %i) & 0x%08x) << %i;\n", first ? "" : "|", opd->type & OPTYPE_SHR, (1 << opd->data) - 1, nbits); nbits += opd->data; if (opd->type & OPTYPE_OP) break; opd++; first = 0; } /* Do we have to sign extend? */ if (opd->type & OPTYPE_SIG) { int sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR; SHIFT; fprintf (fo, "if (tmp & (1 << %i)) tmp |= 0xFFFFFFFF << %i; /* Sign extend */\n", sbit, sbit); } if (opd->type & OPTYPE_DIS) { /* We have to read register later. */ SHIFT; fprintf (fo, "data %s= tmp;\n", firstd ? "" : "+"); firstd = 0; dis = 1; } else { if (dis && (opd->type & OPTYPE_REG)) { SHIFT; fprintf (fo, "op[%i] = data + eval_reg32 (tmp);\n", no); } else { SHIFT; fprintf (fo, "op[%i] = tmp;\n", no); } SHIFT; fprintf (fo, "op[%i + MAX_OPERANDS] = 0x%08x;\n", no, opd->type | (dis ? OPTYPE_DIS : 0)); no++; firstd = 1; dis = 0; } if(opd->type & OPTYPE_LAST) { SHIFT; fprintf (fo, "num_op = %i;\n", no); return; } opd++; } SHIFT; fprintf (fo, "num_op = %i;\n", no); } int output_call (FILE *fo, int index, int level) { fprintf (fo, "{\n"); level++; if (index >= 0) { SHIFT; fprintf (fo, "unsigned long data = 0, tmp = 0, nbits = 0;\n"); } SHIFT; fprintf (fo, "insn_index = %i; /* \"%s\" */\n", index, insn_name (index)); if (index >= 0) { SHIFT; fprintf (fo, "op = &cur->op[0];\n"); //SHIFT; fprintf (fo, "eval_operands (insn, insn_index, &breakpoint);\n"); gen_eval_operands (fo, index, level); } SHIFT; if (index < 0) output_function (fo, "l_invalid", level); else output_function (fo, or32_opcodes[index].function_name, level); fprintf (fo, "\n"); level--; SHIFT; fprintf (fo, "}"); return 0; } static int generate_header (FILE *fo) { fprintf (fo, "/* This file was automatically generated by generate (see cpu/or32/generate.c) */\n\n"); fprintf (fo, "static inline void decode_execute (struct iqueue_entry *current, int *breapoint)\n{\n"); fprintf (fo, " unsigned long insn = current->insn;\n"); fprintf (fo, " int insn_index = -1;\n"); return 0; } int generate_footer (FILE *fo) { fprintf (fo, " current->insn_index = insn_index;\n"); fprintf (fo, "}\n"); return 0; } /* Decodes all instructions and generates code for that. This function is similar to insn_decode, except it decodes all instructions. */ static int generate_body (FILE *fo, unsigned long *a, unsigned long cur_mask, int level) { int i; if (!(*a & LEAF_FLAG)) { unsigned int shift = *a++; unsigned int mask = *a++; int prev_invalid = 0; fprintf (fo, "\n"); SHIFT; fprintf (fo, "/* (insn >> %i) & 0x%x */\n", shift, mask); SHIFT; fprintf (fo, "switch ((insn >> %i) & 0x%x) {\n", shift, mask); level++; /* Print each case recursively */ for (i = 0; i <= mask; i++, a++) { /* Group invalid instruction decodes together */ if (!*a) { if (prev_invalid) fprintf (fo, "\n"); prev_invalid = 1; SHIFT; fprintf (fo, "case 0x%02x: ", i); } else { if (prev_invalid) { if (output_call (fo, -1, level)) return 1; fprintf (fo, " break;\n"); } SHIFT; fprintf (fo, "case 0x%02x: ", i); if (generate_body (fo, automata + *a, cur_mask | (mask << shift), level + 1)) return 1; prev_invalid = 0; } } if (prev_invalid) { if (output_call (fo, -1, level)) return 1; fprintf (fo, " break;\n"); } level--; SHIFT; if (level > 1) fprintf (fo, "} break;\n"); else fprintf (fo, "}\n"); } else { i = *a & ~LEAF_FLAG; /* Final check - do we have direct match? (based on or32_opcodes this should be the only possibility, but in case of invalid/missing instruction we must perform a check) */ if (ti[i].insn_mask != cur_mask) { fprintf (fo, "\n"); SHIFT; fprintf (fo, "/* Not unique: real mask %08x and current mask %08x differ - do final check */\n", ti[i].insn_mask, cur_mask); SHIFT; fprintf (fo, "if ((insn & 0x%08x) == 0x%08x) ", ti[i].insn_mask, ti[i].insn); output_call (fo, i, level); fprintf (fo, " else "); if (output_call (fo, -1, level)) return 1; } else { output_call (fo, i, level - 1); } fprintf (fo, " break;\n"); } return 0; } /* Main function; it takes two parameters: input_file(possibly insnset.c) output_file(possibly execgen.c)*/ int main (int argc, char *argv[]) { FILE *fo; if (argc != 3) { fprintf (stderr, "USAGE: generate input_file(possibly insnset.c) output_file(possibly execgen.c)\n"); exit (-1); } in_file = argv[1]; if (!(fo = fopen (argv[2], "wt+"))) { fprintf (stderr, "Cannot create '%s'.\n", argv[2]); exit (1); } build_automata (); if (generate_header (fo)) {fprintf (stderr, "generate_header\n"); return 1;} if (generate_body (fo, automata, 0, 1)) {fprintf (stderr, "generate_body\n"); return 1;} if (generate_footer (fo)) {fprintf (stderr, "generate_footer\n"); return 1;} fclose (fo); destruct_automata (); return 0; }
Go to most recent revision | Compare with Previous | Blame | View Log