[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [ADD] PPC processor emulation
From: |
J. Mayer |
Subject: |
Re: [Qemu-devel] [ADD] PPC processor emulation |
Date: |
18 Nov 2003 08:48:55 +0100 |
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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+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);
+}
- Re: [Qemu-devel] [ADD] floppy disk emulation, (continued)
- [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation,
J. Mayer <=
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18
- Re: [Qemu-devel] [ADD] PPC processor emulation, J. Mayer, 2003/11/18