From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by monty-python.gnu.org with tmda-scanned (Exim 4.24) id 1AM1V8-0005V4-7M for qemu-devel@nongnu.org; Tue, 18 Nov 2003 03:46:22 -0500 Received: from mail by monty-python.gnu.org with spam-scanned (Exim 4.24) id 1AM1UZ-0004aq-AB for qemu-devel@nongnu.org; Tue, 18 Nov 2003 03:46:18 -0500 Received: from [62.210.158.41] (helo=moscou.magic.fr) by monty-python.gnu.org with esmtp (Exim 4.24) id 1AM1UR-0004ME-3Z for qemu-devel@nongnu.org; Tue, 18 Nov 2003 03:45:39 -0500 Received: from 10.0.0.2 (ppp-181.net-555.magic.fr [62.210.255.181]) by moscou.magic.fr (8.11.6/8.10.1) with ESMTP id hAI7iBO03321 for ; Tue, 18 Nov 2003 08:44:11 +0100 (CET) Subject: Re: [Qemu-devel] [ADD] PPC processor emulation From: "J. Mayer" In-Reply-To: <1069140512.14646.2174.camel@rapid> References: <20031117105133.7e856e56.Jens.Arm@gmx.de> <1069140512.14646.2174.camel@rapid> Content-Type: text/plain Message-Id: <1069141734.14646.2222.camel@rapid> Mime-Version: 1.0 Date: 18 Nov 2003 08:48:55 +0100 Content-Transfer-Encoding: 7bit Reply-To: qemu-devel@nongnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org gen_multi.c.diff New utility to generate repetitive micro-ops diff -urNbB -x CVS qemu-current/gen_multi.c qemu/gen_multi.c --- qemu-current/gen_multi.c Thu Jan 1 01:00:00 1970 +++ qemu/gen_multi.c Sun Aug 17 13:36:23 2003 @@ -0,0 +1,519 @@ +/* + * Minimalist preprocessor. + * Recognized token: + * $DEF regname number + * $OP name rega0 rega1 regb0 + * ... + * $ENDOP + * + * example: + * $DEF gpr 32 + * $DEF T 3 + * $OP load_gpr gpr0 T0 + * { + * .... + * } + * $ENDOP + * $OP add T0 T1 + * { + * .... + * } + * $ENDOP + * $OP op3 T0 T1 T2 + * { + * .... + * } + * $ENDOP + * + * The '$' MUST be at start of the line. + * + * The preprocessor will generate: + * - n micro-routines + * - 1 routine to select the right micro helper at run-time. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const unsigned char *prologue_str = +"/* This file has been auto-generated - PLEASE DON'T EDIT BY HAND */\n\n"; + +typedef struct reg_t { + char *name; + int nr; +} reg_t; + +static int regtypes_nr; +static reg_t regtypes[16], *host_reg; /* Should be sufficient... */ +static FILE *fuops = NULL, *fc = NULL; +static int verbose, limit, host_max; + +static int outbuf (FILE *file, + const unsigned char *start, + const unsigned char *end) +{ + int out; + + for (out = 0; out == 0;) { + out = fwrite(start, end - start, 1, file); + if (out == 0) { + if (errno != EINTR && errno != ERESTART) { + fprintf(stderr, "Unable to copy function out\n"); + return -1; + } + } + } + + return 0; +} + +static int recurs_out_uop (const unsigned char *name, + const unsigned char *start, + const unsigned char *end, + int nr, int *regnums, const int *regmax, + unsigned char *const *regs) +{ + int hostregs[16] = { 0, }; + int i, j, tmphost = 0, tmpemu = 0, tmpparm = 0; + + /* Generate function prototype */ + if (fuops != NULL) { + /* Define registers */ + for (i = 0; i < nr; i++) { + if (strcmp(regs[i], host_reg->name) == 0) { + fprintf(fuops, "#define %s%c %s%d\n", + regs[i], 'a' + tmphost, regs[i], regnums[i]); + hostregs[regnums[i]] = 1; + tmphost++; + } else if (strcmp(regs[i], "PARAM") == 0) { + tmpparm++; + } else { + fprintf(fuops, "#define %s%c %s[%d]\n", + regs[i], 'a' + tmpemu, regs[i], regnums[i]); + tmpemu++; + } + } + j = 0; + fprintf(fuops, "volatile void op_%s", name); + } + if (fc != NULL && nr > tmpparm) + fprintf(fc, " &gen_op_%s", name); + for (i = 0; i < nr; i++) { + if (strcmp(regs[i], "PARAM") == 0) + continue; + if (fuops != NULL) + fprintf(fuops, "_%s%d", regs[i], regnums[i]); + if (fc != NULL) + fprintf(fc, "_%s%d", regs[i], regnums[i]); + } + if (fuops != NULL) + fprintf(fuops, " (void)\n"); + if (fc != NULL && nr > tmpparm) + fprintf(fc, ",\n"); + if (fuops != NULL) { + /* Copy function core */ + if (outbuf(fuops, start, end) < 0) + return -1; + /* Undef registers */ + tmphost = tmpemu = 0; + for (i = 0; i < nr; i++) { + if (strcmp(regs[i], host_reg->name) == 0) { + fprintf(fuops, "#undef %s%c\n", regs[i], 'a' + tmphost++); + } else if (strcmp(regs[i], "PARAM") == 0) { + continue; + } else { + fprintf(fuops, "#undef %s%c\n", regs[i], 'a' + tmpemu++); + } + } + /* Separate functions */ + fprintf(fuops, "\n"); + } + + return 0; +} + +static int _recurs_out_uop (const unsigned char *name, + const unsigned char *start, + const unsigned char *end, + int nr, int *regnums, const int *regmax, + unsigned char *const *regs, int level) +{ + int i; + + if (level >= 0) { + if (strcmp(regs[level], "PARAM") == 0) { + if (_recurs_out_uop(name, start, end, nr, regnums, regmax, + regs, level - 1) < 0) + return -1; + } else if (strcmp(regs[level], host_reg->name) == 0) { + for (i = 0; i < regmax[level]; i++) { + regnums[level] = i; + if (_recurs_out_uop(name, start, end, nr, regnums, regmax, + regs, level - 1) < 0) + return -1; + } +#if 0 + for (; i < regmax[level]; i++) { + if (fc != NULL && nr > 0) + fprintf(fc, " NULL,\n"); + } +#endif + } else { + for (i = 0; i < regmax[level]; i++) { + regnums[level] = i; + if (_recurs_out_uop(name, start, end, nr, regnums, regmax, + regs, level - 1) < 0) + return -1; + } + } + } else { + if (recurs_out_uop(name, start, end, nr, + regnums, regmax, regs) < 0) + return -1; + } + + return 0; +} + +static void usage (const unsigned char *progname, + const unsigned char *message) +{ + fprintf(stderr, "Usage: %s -o uops_file -s -h h_file in_file\n", + progname); + fprintf(stderr, "Generate C-code...\n"); + fprintf(stderr, "\tuops_file: C-code: micro-operations routines\n"); + fprintf(stderr, "\th_file : C-code; run-time selector for uops\n"); + if (message != NULL) + fprintf(stderr, message); +} + +int main (int argc, char **argv) +{ + unsigned char *function, *regs[32]; + int regnums[16], regmax[16]; + struct stat st; + const unsigned char *message; + unsigned char *map, *start, *end; + unsigned char *name_start, *name_end, *tmp_end; + int fd_in = -1; + int nr_regs, nr_tmp; + int tmp, mul; + int i, j; + int c; + + while ((c = getopt(argc, argv, "o:s:lvh?")) != -1) { + switch (c) { + case 'o': + if (fuops != NULL) { + message = "Can output only one uops file at once\n"; + goto out_error; + } + fuops = fopen(argv[optind - 1], "w"); + if (fuops == NULL) { + message = "Can't open fuops file\n"; + goto out_error; + } + break; + case 's': + if (fc != NULL) { + message = "Can output only one C file at once\n"; + goto out_error; + } + fc = fopen(argv[optind - 1], "w"); + if (fc == NULL) { + message = "Can't open C file\n"; + goto out_error; + } + break; + case 'v': + verbose++; + break; + case 'l': + limit++; + break; + case 'h': + case '?': + usage(argv[0], NULL); + exit(0); + break; + default: + message = "Unknown option\n"; + goto out_error; + } + } + if (fuops == NULL && fc == NULL) { + message = "Must have at least one output file\n"; + goto out_error; + } + if (optind != (argc - 1)) { + message = "Bad number of arguments\n"; + goto out_error; + } + fd_in = open(argv[optind], O_RDONLY); + if (fd_in < 0) { + message = "Error oppening in file\n"; + goto out_error; + } + if (fstat(fd_in, &st) < 0) { + message = "Error getting in file infos\n"; + goto out_error; + } + map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, + fd_in, 0); + if (map == NULL) { + message = "Can't map in_file\n"; + goto out_error; + } + + /* Get variables definitions */ + end = map; + for (regtypes_nr = 0; regtypes_nr < 16;) { + start = strstr(end, "$DEF"); + if (start == NULL) + break; + if (start == map || *(start - 1) == '\n') { + end = strchr(start, '\n'); + if (end == NULL) + end = start + st.st_size; + start += 4; + if (*start == 'H') { + if (host_reg != NULL) { + message = "host regs cannot be defined more than once"; + goto out_error; + } + host_reg = ®types[regtypes_nr]; + start++; + } + if (!isspace(*start++)) { + message = "invalid $DEF token\n"; + goto out_error; + } + for (name_start = start; isspace(*name_start); name_start++) + continue; + if (name_start == end) { + message = "no $DEF name\n"; + goto out_error; + } + for (name_end = name_start; + !isspace(*name_end) && name_end < end; name_end++) + continue; + tmp = strtol(name_end + 1, NULL, 0); + if (tmp == 0) { + message = "invalid number of registers\n"; + goto out_error; + } + regtypes[regtypes_nr].nr = tmp; + tmp = name_end - name_start; + regtypes[regtypes_nr].name = malloc(tmp + 1); + if (regtypes[regtypes_nr].name == NULL) { + message = "memory error\n"; + goto out_error; + } + memcpy(regtypes[regtypes_nr].name, name_start, tmp); + regtypes[regtypes_nr].name[tmp] = '\0'; + if (verbose > 0) { + printf("Registered %d vars of type: %s\n", + regtypes[regtypes_nr].nr, regtypes[regtypes_nr].name); + } + regtypes_nr++; + } else { + end = start + 4; + } + } + + if (host_reg == NULL) { + message = "No host registers defined !\n"; + goto out_error; + } + + tmp = strlen(prologue_str); + if (fuops != NULL) { + fwrite(prologue_str, tmp, 1, fuops); + } + + if (fc != NULL) + fwrite(prologue_str, tmp, 1, fc); + /* Proceed micro-operations */ + while (1) { + host_max = 0; + start = strstr(end, "$OP"); + if (start == NULL) + break; + if (outbuf(fuops, end, start) < 0) + return -1; + if (start == map || *(start - 1) == '\n') { + tmp_end = strchr(start, '\n'); + if (tmp_end == NULL) + tmp_end = start + st.st_size; + start += 3; + if (!isspace(*start++)) { + message = "invalid $OP token\n"; + goto out_error; + } + for (name_start = start; isspace(*name_start); name_start++) + continue; + if (name_start == tmp_end) { + message = "no $OP name\n"; + goto out_error; + } + for (name_end = name_start; + !isspace(*name_end) && name_end < tmp_end; name_end++) + continue; + tmp = name_end - name_start; + function = malloc(tmp + 1); + if (function == NULL) { + message = "memory error\n"; + goto out_error; + } + memcpy(function, name_start, tmp); + function[tmp] = '\0'; + for (nr_regs = 0; + name_end != tmp_end && nr_regs < 32;) { + for (name_start = name_end + 1; + isspace(*name_start); name_start++) + continue; + if (name_start == tmp_end) + break; + for (name_end = name_start; + !isspace(*name_end) && name_end < tmp_end; name_end++) + continue; + tmp = name_end - name_start; + regs[nr_regs] = malloc(tmp + 1); + if (regs[nr_regs] == NULL) { + message = "memory error\n"; + goto out_error; + } + memcpy(regs[nr_regs], name_start, tmp); + (regs[nr_regs++])[tmp] = '\0'; + } + end = strstr(tmp_end, "$ENDOP"); + if (end == NULL) { + message = "operation with no end\n"; + goto out_error; + } + if (verbose > 0) + printf("Generate function: %s\n", function); + + nr_tmp = 0; + for (i = 0; i < nr_regs; i++) { + for (j = 0; j < regtypes_nr; j++) { + if (strcmp(regs[i], regtypes[j].name) == 0) { + if (verbose > 0) { + printf("\tregister of type: %s (%s - %d)\n", + regs[i], regtypes[j].name, regtypes[j].nr); + } + regmax[i] = regtypes[j].nr; + goto got_it; + } + if (strcmp(regs[i], "PARAM") == 0) { + nr_tmp++; + goto got_it; + } + } + printf("register %s not found\n", regs[i]); + message = "register not found\n"; + goto out_error; + got_it: + continue; + } + + if (nr_regs > nr_tmp) { + if (fc != NULL) + fprintf(fc, "static void *table_%s[] = {\n", function); + memset(regnums, 0, sizeof(regnums)); + } + if (_recurs_out_uop(function, tmp_end + 1, end, nr_regs, + regnums, regmax, regs, nr_regs - 1) < 0) { + message = "code generation error\n"; + goto out_error; + } + if (nr_regs > nr_tmp) { + if (fc != NULL) { + fprintf(fc, "};\n\n"); + fprintf(fc, "static inline void gen_op_%s (", function); + } + } + if (nr_regs == nr_tmp) + goto do_free; + + if (fc != NULL) { + int tmp = 0; + for (i = 0; i < nr_tmp; i++) { + if (i > 0) + fprintf(fc, ", "); + fprintf(fc, "unsigned long parm%d", i); + } + for (i = 0; i < nr_regs; i++) { + if (strcmp(regs[i], "PARAM") == 0) + continue; + if (tmp++ > 0 || nr_tmp > 0) + fprintf(fc, ", "); + if (fc != NULL) + fprintf(fc, "int regn%d", i); + } + fprintf(fc, ")\n"); + fprintf(fc, "{\n"); + fprintf(fc, " void (*gen_op)("); + for (i = 0; i < nr_tmp; i++) { + if (i > 0) + fprintf(fc, ", "); + fprintf(fc, "unsigned long p%d", i); + } + fprintf(fc, ");\n\n"); + fprintf(fc, " gen_op = table_%s[", function); + fprintf(fc, "regn0"); + mul = 1; + for (i = 1; i < nr_regs; i++) { + if (strcmp(regs[i], "PARAM") == 0) + continue; + mul *= regmax[i - 1]; + fprintf(fc, " + (regn%d * %d)", i, mul); + } + fprintf(fc, "];\n"); + fprintf(fc, " (*gen_op)("); + for (i = 0; i < nr_tmp; i++) { + if (i > 0) + fprintf(fc, ", "); + fprintf(fc, "parm%d", i); + } + fprintf(fc, ");\n"); + fprintf(fc, "}\n\n"); + } + do_free: + free(function); + for (; nr_regs > 0; nr_regs--) + free(regs[nr_regs - 1]); + end = strchr(end, '\n'); + if (end == NULL) + break; + } else { + end = start + 3; + } + } + + if (fuops != NULL) + fclose(fuops); + if (fc != NULL) + fclose(fc); + close(fd_in); + + exit(0); + +out_error: + if (fuops != NULL) + fclose(fuops); + if (fc != NULL) + fclose(fc); + if (fd_in >= 0) + close(fd_in); + usage(argv[0], message); + + exit(1); +}