Search
lxdream.org :: lxdream/src/tools/genmach.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/tools/genmach.c
changeset 1298:d0eb2307b847
prev1296:30ecee61f811
author nkeynes
date Wed Feb 04 08:38:23 2015 +1000 (9 years ago)
permissions -rw-r--r--
last change Fix assorted compile warnings reported by Clang
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * mmio register code generator
     5  *
     6  * Copyright (c) 2010 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    19 #include <stdio.h>
    20 #include <stdlib.h>
    21 #include <string.h>
    22 #include <unistd.h>
    23 #include <getopt.h>
    24 #include <ctype.h>
    25 #include <errno.h>
    26 #include <glib.h>
    27 #include "gettext.h"
    28 #include "genmach.h"
    30 #define LXDREAM_PAGE_SIZE 4096
    32 const char *short_options = "cd:ho:v";
    33 struct option long_options[] = {
    34         { "output", required_argument, NULL, 'o' },
    35         { "header", required_argument, NULL, 'd' },
    36         { "check-only", no_argument, NULL, 'c' },
    37         { "help", no_argument, NULL, 'h' },
    38         { "verbose", no_argument, NULL, 'v' },
    39         { NULL, 0, 0, 0 } };
    41 static void print_version()
    42 {
    43     printf( "genmmio 0.1\n" );
    44 }
    46 static void print_usage()
    47 {
    48     print_version();
    49     printf( "Usage: genmmio [options] <input-register-files>\n" );
    50     printf( "Options:\n" );
    51     printf( "   -c, --check-only       %s\n", _("Check specification files but don't write any output") );
    52     printf( "   -d, --header=FILE      %s\n", _("Specify header output file [corresponding .h for .c file]") );
    53     printf( "   -h, --help             %s\n", _("Display this usage information") );
    54     printf( "   -o, --output=FILE      %s\n", _("Specify main output file [corresponding .c for input file]") );
    55     printf( "   -v, --verbose          %s\n", _("Print verbose output") );
    56 }
    58 /**
    59  * Given an input baseName of the form "path/file.blah", return
    60  * a newly allocated string "file<ext>" where <ext> is the second
    61  * parameter.
    62  *
    63  * @param baseName a non-null filename
    64  * @param ext a file extension including leading '.'
    65  */
    66 char *makeFilename( const char *baseName, const char *ext )
    67 {
    68     const char *p = strrchr(baseName, '/');
    69     if( p == NULL )
    70         p = baseName;
    71     const char *q = strchr(p, '.');
    72     if( q == NULL ) {
    73         return g_strdup_printf("%s%s", p, ext);
    74     } else {
    75         return g_strdup_printf("%.*s%s", (int)(q-p), p, ext );
    76     }
    77 }
    79 /**
    80  * Process all registers after parsing is complete. This does a few things:
    81  *   1. Ensures that there are no overlapping registers, so that every operation
    82  *      is well-defined.
    83  *   2. Replaces transitive mirror groups with a set of equivalent direct
    84  *      mirrors so that later processing doesn't need to check for this case.
    85  *      This also checks for cycles in the graph.
    86  *   3. Organises the memory map(s) into page-size quantities (combining and
    87  *      splitting groups where necessary).
    88  */
    89 GList *postprocess_registers( GList *blocks )
    90 {
    91     for( GList *ptr = blocks; ptr != NULL; ptr = ptr->next ) {
    92         regblock_t block = (regblock_t)ptr->data;
    93         for( unsigned i=0; i<block->numRegs; i++ ) {
    94             regdef_t reg = block->regs[i];
    95             if( reg->mode == REG_MIRROR ) {
    96             }
    97         }
    98     }
    99     return blocks;
   100 }
   102 /**
   103  * Check register definition semantics. Primarily this verifies that there
   104  * are no overlapping definitions.
   105  * @return number of errors found.
   106  */
   107 int check_registers( GList *registers )
   108 {
   109     return 0;
   110 }
   112 /**
   113  * Dump the high-level register map to the given file.
   114  */
   115 void dump_register_blocks( FILE *f, GList *blocks, gboolean detail )
   116 {
   117     const char *mode_names[] = { "--", "RW", "RO", "RW" };
   118     for( GList *ptr = blocks; ptr != NULL; ptr=ptr->next ) {
   119         regblock_t block = (regblock_t)ptr->data;
   120         fprintf( f, "%08X: %s - %s\n", block->address,
   121                  block->name,
   122                  (block->description == NULL ? "<no description>" : block->description) );
   123         if( detail ) {
   124             for( unsigned i=0; i<block->numRegs; i++ ) {
   125                 regdef_t reg = block->regs[i];
   126                 fprintf( f, "    %04X: %s %s", reg->offset,
   127                         mode_names[reg->mode],
   128                         reg->name == NULL ? "<anon>" : reg->name );
   129                 if( reg->numElements > 1 ) {
   130                     fprintf( f, "[%d]", reg->numElements );
   131                 }
   132                 fprintf( f, " - %s\n",
   133                          (reg->description == NULL ? "<no description>" : reg->description) );
   134             }
   135         }
   136     }
   137 }
   139 unsigned char *build_page_initializer( regblock_t block )
   140 {
   141     unsigned char *page = g_malloc(LXDREAM_PAGE_SIZE);
   143     /* First, background fill if any */
   144     if( block->flags.fillSizeBytes == 0 ) {
   145         memset(page, 0, LXDREAM_PAGE_SIZE);
   146     } else {
   147         for( unsigned i=0; i<LXDREAM_PAGE_SIZE; i++ ) {
   148             page[i] = block->flags.fillValue.a[i%block->flags.fillSizeBytes];
   149         }
   150     }
   152     /* Next, set register initializer (except for wo + mirror regs) */
   153     for( unsigned i=0; i<block->numRegs; i++ ) {
   154         regdef_t reg = block->regs[i];
   155         if( reg->mode != REG_WO && reg->mode != REG_MIRROR ) {
   156             unsigned offset = reg->offset;
   157             for( unsigned j=0; j<reg->numElements; j++ ) {
   158                 if( reg->type == REG_STRING ) {
   159                     memcpy( &page[offset], reg->initValue.s, reg->numBytes );
   160                 } else {
   161                     memcpy( &page[offset], reg->initValue.a, reg->numBytes );
   162                 }
   163                 offset += reg->numBytes;
   164             }
   165         }
   166     }
   168     /* Finally clone mirror groups */
   169     for( unsigned i=0; i<block->numRegs; i++ ) {
   170         regdef_t reg = block->regs[i];
   171         if( reg->mode == REG_MIRROR ) {
   172             unsigned offset = reg->offset;
   173             unsigned target = reg->initValue.i;
   174             for( unsigned i=0; i<reg->numElements; i++ ) {
   175                 memcpy( &page[offset], &page[target], reg->numBytes );
   176                 offset += reg->stride;
   177             }
   178         }
   179     }
   181     return page;
   182 }
   185 void fwrite_dump( unsigned char *data, unsigned int length, FILE *f )
   186 {
   187     unsigned int i, j;
   188     int skipped = 0;
   189     for( i =0; i<length; i+=16 ) {
   190         if( i >= 16 && i < length-16 && memcmp( &data[i], &data[i-16], 16) == 0 ) {
   191             skipped++;
   192             continue;
   193         }
   194         if( skipped ) {
   195             fprintf( f, "   **    \n" );
   196             skipped = 0;
   197         }
   198         fprintf( f, "%08X:", i);
   199         for( j=i; j<i+16; j++ ) {
   200             if( j != i && (j % 4) == 0 )
   201                 fprintf( f, " " );
   202             if( j < length )
   203                 fprintf( f, " %02X", (unsigned int)(data[j]) );
   204             else
   205                 fprintf( f, "   " );
   206         }
   207         fprintf( f, "  " );
   208         for( j=i; j<i+16 && j<length; j++ ) {
   209             fprintf( f, "%c", isprint(data[j]) ? data[j] : '.' );
   210         }
   211         fprintf( f, "\n" );
   212     }
   213 }
   215 static const char *file_top = "/**\n"
   216         " * This file was automatically generated by genmmio, do not edit\n"
   217         " */\n";
   219 void write_source( FILE *f, GList *blocks, const char *header_filename )
   220 {
   221     fputs( file_top, f );
   222     fprintf( f, "\n#include \"%s\"\n\n", header_filename );
   224     for( GList *ptr = blocks; ptr != NULL; ptr = ptr->next ) {
   225         regblock_t block = (regblock_t)ptr->data;
   226         /* Generate the mmio region struct */
   227         fprintf( f, "void FASTCALL mmio_region_%s_write(uint32_t, uint32_t);\n", block->name );
   228         fprintf( f, "void FASTCALL mmio_region_%s_write_word(uint32_t, uint32_t);\n", block->name );
   229         fprintf( f, "void FASTCALL mmio_region_%s_write_byte(uint32_t, uint32_t);\n", block->name );
   230         fprintf( f, "void FASTCALL mmio_region_%s_write_burst(uint32_t, unsigned char *);\n", block->name );
   231         fprintf( f, "int32_t FASTCALL mmio_region_%s_read(uint32_t);\n", block->name );
   232         fprintf( f, "int32_t FASTCALL mmio_region_%s_read_word(uint32_t);\n", block->name );
   233         fprintf( f, "int32_t FASTCALL mmio_region_%s_read_byte(uint32_t);\n", block->name );
   234         fprintf( f, "void FASTCALL mmio_region_%s_read_burst(unsigned char *, uint32_t);\n", block->name );
   235         fprintf( f, "struct mmio_region mmio_region_%s = {\n", block->name );
   236         fprintf( f, "    \"%s\", \"%s\", %08x, {\n", block->name,
   237                 block->description == NULL ? block->name : block->description,
   238                 block->address );
   239         fprintf( f, "        mmio_region_%s_read, mmio_region_%s_write,\n", block->name, block->name );
   240         fprintf( f, "        mmio_region_%s_read_word, mmio_region_%s_write_word,\n", block->name, block->name );
   241         fprintf( f, "        mmio_region_%s_read_byte, mmio_region_%s_write_byte,\n", block->name, block->name );
   242         fprintf( f, "        mmio_region_%s_read_burst, mmio_region_%s_write_burst,\n", block->name, block->name );
   243         fprintf( f, "        unmapped_prefetch, mmio_region_%s_read_byte },\n", block->name );
   244         fprintf( f, "    NULL, NULL, {\n" );
   245         for( unsigned i=0; i<block->numRegs; i++ ) {
   246             regdef_t reg = block->regs[i];
   247             if( reg->mode != REG_CONST ) {
   248                 char tmp[32];
   249                 const char *regname = reg->name;
   250                 if( regname == NULL ) {
   251                     regname = tmp;
   252                     snprintf( tmp, sizeof(tmp), "%s_%03X", block->name, reg->offset );
   253                 }
   255                 fprintf( f, "        { \"%s\", \"%s\", %d, 0x%03x, 0x%08x, %s },\n", regname,
   256                          reg->description == NULL ? regname : reg->description,
   257                                  reg->numBytes*8, reg->offset, (unsigned)reg->initValue.i,
   258                                  (reg->mode == REG_RW ? "PORT_MRW" : (reg->mode == REG_WO ? "PORT_W" : "PORT_R")) );
   259             }
   260         }
   261         fprintf( f, "    }, NULL };\n" );
   262     }
   264 }
   266 void write_header( FILE *f, GList *blocks )
   267 {
   268     fputs( file_top, f );
   270     fputs( "\n#include \"mmio.h\"\n\n", f );
   272     for( GList *ptr = blocks; ptr != NULL; ptr = ptr->next ) {
   273         regblock_t block = (regblock_t)ptr->data;
   274         fprintf( f, "extern struct mmio_region mmio_region_%s;\n", block->name );
   275         fprintf( f, "enum mmio_region_%s_port_t {\n", block->name );
   276         for( unsigned i=0; i<block->numRegs; i++ ) {
   277             regdef_t reg = block->regs[i];
   278             if( reg->name != NULL ) {
   279                 fprintf( f, "    %s = 0x%03x,\n", reg->name, reg->offset );
   280             }
   281         }
   282         fprintf( f, "};\n" );
   283     }
   284 }
   286 void write_test( FILE *f, GList *blocks )
   287 {
   290 }
   292 int main(int argc, char *argv[])
   293 {
   294     const char *header = NULL;
   295     const char *output = NULL;
   296     gboolean check_only = FALSE;
   297     int verbose = 0, opt;
   298     GList *block_list = NULL;
   300     while( (opt = getopt_long( argc, argv, short_options, long_options, NULL )) != -1 ) {
   301         switch(opt) {
   302         case 'c':
   303             check_only = TRUE;
   304             break;
   305         case 'd':
   306             header = optarg;
   307             break;
   308         case 'h':
   309             print_usage();
   310             exit(0);
   311         case 'o':
   312             output = optarg;
   313             break;
   314         case 'v':
   315             verbose++;
   316             break;
   317         }
   318     }
   320     if( optind == argc ) {
   321         print_usage();
   322         exit(1);
   323     }
   325     if( output == NULL ) {
   326         output = makeFilename(argv[optind],".c");
   327     }
   328     if( header == NULL ) {
   329         header = makeFilename(argv[optind],".h");
   330     }
   332     for( ; optind < argc; optind++ ) {
   333         block_list = ioparse(argv[optind], block_list);
   334     }
   336     if( verbose ) {
   337         dump_register_blocks(stdout, block_list, verbose>1);
   338     }
   340     int errors = check_registers(block_list);
   341     if( errors != 0 ) {
   342         fprintf( stderr, "Aborting due to validation errors\n" );
   343         return 2;
   344     }
   346     if( !check_only ) {
   347         FILE *f = fopen( output, "wo" );
   348         if( f == NULL ) {
   349             fprintf( stderr, "Unable to open output file '%s': %s\n", output, strerror(errno) );
   350             return 3;
   351         }
   352         write_source( f, block_list, header );
   353         fclose(f);
   355         f = fopen( header, "wo" );
   356         if( f == NULL ) {
   357             fprintf( stderr, "Unable to open header file '%s': %s\n", header, strerror(errno) );
   358             return 4;
   359         }
   360         write_header( f, block_list );
   361         fclose(f);
   362     }
   364     for( GList *ptr = block_list; ptr != NULL; ptr = ptr->next ) {
   365         unsigned char *data = build_page_initializer((regblock_t)ptr->data);
   366         fwrite_dump( data, LXDREAM_PAGE_SIZE, stdout );
   367         g_free(data);
   368     }
   369     return 0;
   370 }
.