qemu-devel
[Top][All Lists]
Advanced

[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 = &regtypes[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);
+}






reply via email to

[Prev in Thread] Current Thread [Next in Thread]