revision 1104:700e16c321e5
summary |
tree |
shortlog |
changelog |
graph |
changeset |
raw | bz2 | zip | gz changeset | 1104:700e16c321e5 |
parent | 1103:de9ad2c0cf56 |
child | 1105:73da8fd129fb |
author | nkeynes |
date | Mon Mar 15 22:10:24 2010 +1000 (14 years ago) |
Commit genmach work-in-progress
1.1 --- a/src/Makefile.am Sun Feb 21 11:19:59 2010 +10001.2 +++ b/src/Makefile.am Mon Mar 15 22:10:24 2010 +10001.3 @@ -12,7 +12,7 @@1.4 PLUGINCFLAGS = @PLUGINCFLAGS@1.5 PLUGINLDFLAGS = @PLUGINLDFLAGS@1.6 bin_PROGRAMS = lxdream1.7 -noinst_PROGRAMS = gendec genglsl1.8 +noinst_PROGRAMS = gendec genglsl genmach1.9 check_PROGRAMS = test/testxlt test/testisoread1.11 pkglib_PROGRAMS=1.12 @@ -36,6 +36,7 @@1.13 #all-am: checkversion1.15 gendec_SOURCES = tools/gendec.c tools/gendec.h tools/insparse.c tools/actparse.c1.16 +genmach_SOURCES = tools/genmach.c tools/genmach.h tools/mdparse.c1.17 genglsl_SOURCES = tools/genglsl.c1.18 lxdream_LINK = $(LINK) @LXDREAMLDFLAGS@1.19 lxdream_LDADD = @LXDREAM_LIBS@ @GLIB_LIBS@ @GTK_LIBS@ @LIBPNG_LIBS@ $(INTLLIBS)1.20 @@ -236,6 +237,7 @@1.22 gendec_LDADD = @GLIB_LIBS@ @GTK_LIBS@ $(INTLLIBS)1.23 genglsl_LDADD = @GLIB_LIBS@ @GTK_LIBS@ $(INTLLIBS)1.24 +genmach_LDADD = @GLIB_LIBS@ @GTK_LIBS@ $(INTLLIBS)1.27 test_testxlt_SOURCES = test/testxlt.c xlat/xltcache.c xlat/xltcache.h
2.1 --- a/src/Makefile.in Sun Feb 21 11:19:59 2010 +10002.2 +++ b/src/Makefile.in Mon Mar 15 22:10:24 2010 +10002.3 @@ -37,7 +37,7 @@2.4 build_triplet = @build@2.5 host_triplet = @host@2.6 bin_PROGRAMS = lxdream$(EXEEXT)2.7 -noinst_PROGRAMS = gendec$(EXEEXT) genglsl$(EXEEXT)2.8 +noinst_PROGRAMS = gendec$(EXEEXT) genglsl$(EXEEXT) genmach$(EXEEXT)2.9 check_PROGRAMS = test/testxlt$(EXEEXT) test/testisoread$(EXEEXT) \2.10 $(am__EXEEXT_1)2.11 pkglib_PROGRAMS = $(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4) \2.12 @@ -135,6 +135,9 @@2.13 am_genglsl_OBJECTS = genglsl.$(OBJEXT)2.14 genglsl_OBJECTS = $(am_genglsl_OBJECTS)2.15 genglsl_DEPENDENCIES = $(am__DEPENDENCIES_1)2.16 +am_genmach_OBJECTS = genmach.$(OBJEXT) mdparse.$(OBJEXT)2.17 +genmach_OBJECTS = $(am_genmach_OBJECTS)2.18 +genmach_DEPENDENCIES = $(am__DEPENDENCIES_1)2.19 am_input_lirc_@SOEXT@_OBJECTS =2.20 input_lirc_@SOEXT@_OBJECTS = $(am_input_lirc_@SOEXT@_OBJECTS)2.21 @BUILD_SHARED_TRUE@@INPUT_LIRC_TRUE@input_lirc_@SOEXT@_DEPENDENCIES = \2.22 @@ -336,16 +339,16 @@2.23 $(LDFLAGS) -o $@2.24 SOURCES = $(audio_alsa_@SOEXT@_SOURCES) $(audio_esd_@SOEXT@_SOURCES) \2.25 $(audio_pulse_@SOEXT@_SOURCES) $(audio_sdl_@SOEXT@_SOURCES) \2.26 - $(gendec_SOURCES) $(genglsl_SOURCES) \2.27 + $(gendec_SOURCES) $(genglsl_SOURCES) $(genmach_SOURCES) \2.28 $(input_lirc_@SOEXT@_SOURCES) $(lxdream_SOURCES) \2.29 $(lxdream_dummy_@SOEXT@_SOURCES) $(test_testisoread_SOURCES) \2.30 $(test_testsh4x86_SOURCES) $(test_testxlt_SOURCES)2.31 DIST_SOURCES = $(audio_alsa_@SOEXT@_SOURCES) \2.32 $(audio_esd_@SOEXT@_SOURCES) $(audio_pulse_@SOEXT@_SOURCES) \2.33 $(audio_sdl_@SOEXT@_SOURCES) $(gendec_SOURCES) \2.34 - $(genglsl_SOURCES) $(input_lirc_@SOEXT@_SOURCES) \2.35 - $(am__lxdream_SOURCES_DIST) $(lxdream_dummy_@SOEXT@_SOURCES) \2.36 - $(test_testisoread_SOURCES) \2.37 + $(genglsl_SOURCES) $(genmach_SOURCES) \2.38 + $(input_lirc_@SOEXT@_SOURCES) $(am__lxdream_SOURCES_DIST) \2.39 + $(lxdream_dummy_@SOEXT@_SOURCES) $(test_testisoread_SOURCES) \2.40 $(am__test_testsh4x86_SOURCES_DIST) $(test_testxlt_SOURCES)2.41 ETAGS = etags2.42 CTAGS = ctags2.43 @@ -555,6 +558,7 @@2.45 #all-am: checkversion2.46 gendec_SOURCES = tools/gendec.c tools/gendec.h tools/insparse.c tools/actparse.c2.47 +genmach_SOURCES = tools/genmach.c tools/genmach.h tools/mdparse.c2.48 genglsl_SOURCES = tools/genglsl.c2.49 lxdream_LINK = $(LINK) @LXDREAMLDFLAGS@2.50 lxdream_LDADD = @LXDREAM_LIBS@ @GLIB_LIBS@ @GTK_LIBS@ @LIBPNG_LIBS@ \2.51 @@ -631,6 +635,7 @@2.52 @BUILD_SHARED_TRUE@@INPUT_LIRC_TRUE@input_lirc_@SOEXT@_LDFLAGS = $(PLUGINLDFLAGS)2.53 gendec_LDADD = @GLIB_LIBS@ @GTK_LIBS@ $(INTLLIBS)2.54 genglsl_LDADD = @GLIB_LIBS@ @GTK_LIBS@ $(INTLLIBS)2.55 +genmach_LDADD = @GLIB_LIBS@ @GTK_LIBS@ $(INTLLIBS)2.56 test_testxlt_SOURCES = test/testxlt.c xlat/xltcache.c xlat/xltcache.h2.57 test_testisoread_SOURCES = test/testisoread.c drivers/cdrom/isoread.c \2.58 drivers/cdrom/isoread.h drivers/cdrom/isofs_impl.h drivers/cdrom/ecc.h \2.59 @@ -746,6 +751,9 @@2.60 genglsl$(EXEEXT): $(genglsl_OBJECTS) $(genglsl_DEPENDENCIES)2.61 @rm -f genglsl$(EXEEXT)2.62 $(LINK) $(genglsl_LDFLAGS) $(genglsl_OBJECTS) $(genglsl_LDADD) $(LIBS)2.63 +genmach$(EXEEXT): $(genmach_OBJECTS) $(genmach_DEPENDENCIES)2.64 + @rm -f genmach$(EXEEXT)2.65 + $(LINK) $(genmach_LDFLAGS) $(genmach_OBJECTS) $(genmach_LDADD) $(LIBS)2.66 input_lirc.@SOEXT@$(EXEEXT): $(input_lirc_@SOEXT@_OBJECTS) $(input_lirc_@SOEXT@_DEPENDENCIES)2.67 @rm -f input_lirc.@SOEXT@$(EXEEXT)2.68 $(LINK) $(input_lirc_@SOEXT@_LDFLAGS) $(input_lirc_@SOEXT@_OBJECTS) $(input_lirc_@SOEXT@_LDADD) $(LIBS)2.69 @@ -783,6 +791,7 @@2.70 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edc_ecc.Po@am__quote@2.71 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gendec.Po@am__quote@2.72 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genglsl.Po@am__quote@2.73 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genmach.Po@am__quote@2.74 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/insparse.Po@am__quote@2.75 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isoread.Po@am__quote@2.76 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-aica.Po@am__quote@2.77 @@ -905,6 +914,7 @@2.78 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-x86dasm.Po@am__quote@2.79 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-xltcache.Po@am__quote@2.80 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-yuv.Po@am__quote@2.81 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mdparse.Po@am__quote@2.82 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sector.Po@am__quote@2.83 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testsh4x86-cpu.Po@am__quote@2.84 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testsh4x86-dis-buf.Po@am__quote@2.85 @@ -992,6 +1002,34 @@2.86 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@2.87 @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o genglsl.obj `if test -f 'tools/genglsl.c'; then $(CYGPATH_W) 'tools/genglsl.c'; else $(CYGPATH_W) '$(srcdir)/tools/genglsl.c'; fi`2.89 +genmach.o: tools/genmach.c2.90 +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT genmach.o -MD -MP -MF "$(DEPDIR)/genmach.Tpo" -c -o genmach.o `test -f 'tools/genmach.c' || echo '$(srcdir)/'`tools/genmach.c; \2.91 +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/genmach.Tpo" "$(DEPDIR)/genmach.Po"; else rm -f "$(DEPDIR)/genmach.Tpo"; exit 1; fi2.92 +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tools/genmach.c' object='genmach.o' libtool=no @AMDEPBACKSLASH@2.93 +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@2.94 +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o genmach.o `test -f 'tools/genmach.c' || echo '$(srcdir)/'`tools/genmach.c2.95 +2.96 +genmach.obj: tools/genmach.c2.97 +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT genmach.obj -MD -MP -MF "$(DEPDIR)/genmach.Tpo" -c -o genmach.obj `if test -f 'tools/genmach.c'; then $(CYGPATH_W) 'tools/genmach.c'; else $(CYGPATH_W) '$(srcdir)/tools/genmach.c'; fi`; \2.98 +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/genmach.Tpo" "$(DEPDIR)/genmach.Po"; else rm -f "$(DEPDIR)/genmach.Tpo"; exit 1; fi2.99 +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tools/genmach.c' object='genmach.obj' libtool=no @AMDEPBACKSLASH@2.100 +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@2.101 +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o genmach.obj `if test -f 'tools/genmach.c'; then $(CYGPATH_W) 'tools/genmach.c'; else $(CYGPATH_W) '$(srcdir)/tools/genmach.c'; fi`2.102 +2.103 +mdparse.o: tools/mdparse.c2.104 +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mdparse.o -MD -MP -MF "$(DEPDIR)/mdparse.Tpo" -c -o mdparse.o `test -f 'tools/mdparse.c' || echo '$(srcdir)/'`tools/mdparse.c; \2.105 +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/mdparse.Tpo" "$(DEPDIR)/mdparse.Po"; else rm -f "$(DEPDIR)/mdparse.Tpo"; exit 1; fi2.106 +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tools/mdparse.c' object='mdparse.o' libtool=no @AMDEPBACKSLASH@2.107 +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@2.108 +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mdparse.o `test -f 'tools/mdparse.c' || echo '$(srcdir)/'`tools/mdparse.c2.109 +2.110 +mdparse.obj: tools/mdparse.c2.111 +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mdparse.obj -MD -MP -MF "$(DEPDIR)/mdparse.Tpo" -c -o mdparse.obj `if test -f 'tools/mdparse.c'; then $(CYGPATH_W) 'tools/mdparse.c'; else $(CYGPATH_W) '$(srcdir)/tools/mdparse.c'; fi`; \2.112 +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/mdparse.Tpo" "$(DEPDIR)/mdparse.Po"; else rm -f "$(DEPDIR)/mdparse.Tpo"; exit 1; fi2.113 +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tools/mdparse.c' object='mdparse.obj' libtool=no @AMDEPBACKSLASH@2.114 +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@2.115 +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mdparse.obj `if test -f 'tools/mdparse.c'; then $(CYGPATH_W) 'tools/mdparse.c'; else $(CYGPATH_W) '$(srcdir)/tools/mdparse.c'; fi`2.116 +2.117 lxdream-main.o: main.c2.118 @am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lxdream-main.o -MD -MP -MF "$(DEPDIR)/lxdream-main.Tpo" -c -o lxdream-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c; \2.119 @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/lxdream-main.Tpo" "$(DEPDIR)/lxdream-main.Po"; else rm -f "$(DEPDIR)/lxdream-main.Tpo"; exit 1; fi
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00003.2 +++ b/src/tools/genmach.c Mon Mar 15 22:10:24 2010 +10003.3 @@ -0,0 +1,372 @@3.4 +/**3.5 + * $Id$3.6 + *3.7 + * mmio register code generator3.8 + *3.9 + * Copyright (c) 2010 Nathan Keynes.3.10 + *3.11 + * This program is free software; you can redistribute it and/or modify3.12 + * it under the terms of the GNU General Public License as published by3.13 + * the Free Software Foundation; either version 2 of the License, or3.14 + * (at your option) any later version.3.15 + *3.16 + * This program is distributed in the hope that it will be useful,3.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of3.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the3.19 + * GNU General Public License for more details.3.20 + */3.21 +3.22 +#include <stdio.h>3.23 +#include <stdlib.h>3.24 +#include <string.h>3.25 +#include <unistd.h>3.26 +#include <getopt.h>3.27 +#include <ctype.h>3.28 +#include <errno.h>3.29 +#include <glib/gstrfuncs.h>3.30 +#include <glib/glist.h>3.31 +#include "gettext.h"3.32 +#include "genmach.h"3.33 +3.34 +#define LXDREAM_PAGE_SIZE 40963.35 +3.36 +const char *short_options = "cd:ho:v";3.37 +struct option long_options[] = {3.38 + { "output", required_argument, NULL, 'o' },3.39 + { "header", required_argument, NULL, 'd' },3.40 + { "check-only", no_argument, NULL, 'c' },3.41 + { "help", no_argument, NULL, 'h' },3.42 + { "verbose", no_argument, NULL, 'v' },3.43 + { NULL, 0, 0, 0 } };3.44 +3.45 +static void print_version()3.46 +{3.47 + printf( "genmmio 0.1\n" );3.48 +}3.49 +3.50 +static void print_usage()3.51 +{3.52 + print_version();3.53 + printf( "Usage: genmmio [options] <input-register-files>\n" );3.54 + printf( "Options:\n" );3.55 + printf( " -c, --check-only %s\n", _("Check specification files but don't write any output") );3.56 + printf( " -d, --header=FILE %s\n", _("Specify header output file [corresponding .h for .c file]") );3.57 + printf( " -h, --help %s\n", _("Display this usage information") );3.58 + printf( " -o, --output=FILE %s\n", _("Specify main output file [corresponding .c for input file]") );3.59 + printf( " -v, --verbose %s\n", _("Print verbose output") );3.60 +}3.61 +3.62 +/**3.63 + * Given an input baseName of the form "path/file.blah", return3.64 + * a newly allocated string "file<ext>" where <ext> is the second3.65 + * parameter.3.66 + *3.67 + * @param baseName a non-null filename3.68 + * @param ext a file extension including leading '.'3.69 + */3.70 +char *makeFilename( const char *baseName, const char *ext )3.71 +{3.72 + const char *p = strrchr(baseName, '/');3.73 + if( p == NULL )3.74 + p = baseName;3.75 + const char *q = strchr(p, '.');3.76 + if( q == NULL ) {3.77 + return g_strdup_printf("%s%s", p, ext);3.78 + } else {3.79 + return g_strdup_printf("%.*s%s", q-p, p, ext );3.80 + }3.81 +}3.82 +3.83 +/**3.84 + * Process all registers after parsing is complete. This does a few things:3.85 + * 1. Ensures that there are no overlapping registers, so that every operation3.86 + * is well-defined.3.87 + * 2. Replaces transitive mirror groups with a set of equivalent direct3.88 + * mirrors so that later processing doesn't need to check for this case.3.89 + * This also checks for cycles in the graph.3.90 + * 3. Organises the memory map(s) into page-size quantities (combining and3.91 + * splitting groups where necessary).3.92 + */3.93 +GList *postprocess_registers( GList *blocks )3.94 +{3.95 + for( GList *ptr = blocks; ptr != NULL; ptr = ptr->next ) {3.96 + regblock_t block = (regblock_t)ptr->data;3.97 + for( unsigned i=0; i<block->numRegs; i++ ) {3.98 + regdef_t reg = block->regs[i];3.99 + if( reg->mode == REG_MIRROR ) {3.100 + }3.101 + }3.102 + }3.103 + return blocks;3.104 +}3.105 +3.106 +/**3.107 + * Check register definition semantics. Primarily this verifies that there3.108 + * are no overlapping definitions.3.109 + * @return number of errors found.3.110 + */3.111 +int check_registers( GList *registers )3.112 +{3.113 + return 0;3.114 +}3.115 +3.116 +/**3.117 + * Dump the high-level register map to the given file.3.118 + */3.119 +void dump_register_blocks( FILE *f, GList *blocks, gboolean detail )3.120 +{3.121 + const char *mode_names[] = { "--", "RW", "RO", "RW" };3.122 + for( GList *ptr = blocks; ptr != NULL; ptr=ptr->next ) {3.123 + regblock_t block = (regblock_t)ptr->data;3.124 + fprintf( f, "%08X: %s - %s\n", block->address,3.125 + block->name,3.126 + (block->description == NULL ? "<no description>" : block->description) );3.127 + if( detail ) {3.128 + for( unsigned i=0; i<block->numRegs; i++ ) {3.129 + regdef_t reg = block->regs[i];3.130 + fprintf( f, " %04X: %s %s", reg->offset,3.131 + mode_names[reg->mode],3.132 + reg->name == NULL ? "<anon>" : reg->name );3.133 + if( reg->numElements > 1 ) {3.134 + fprintf( f, "[%d]", reg->numElements );3.135 + }3.136 + fprintf( f, " - %s\n",3.137 + (reg->description == NULL ? "<no description>" : reg->description) );3.138 + }3.139 + }3.140 + }3.141 +}3.142 +3.143 +char *build_page_initializer( regblock_t block )3.144 +{3.145 + char *page = g_malloc(LXDREAM_PAGE_SIZE);3.146 +3.147 + /* First, background fill if any */3.148 + if( block->flags.fillSizeBytes == 0 ) {3.149 + memset(page, 0, LXDREAM_PAGE_SIZE);3.150 + } else {3.151 + for( unsigned i=0; i<LXDREAM_PAGE_SIZE; i++ ) {3.152 + page[i] = block->flags.fillValue.a[i%block->flags.fillSizeBytes];3.153 + }3.154 + }3.155 +3.156 + /* Next, set register initializer (except for wo + mirror regs) */3.157 + for( unsigned i=0; i<block->numRegs; i++ ) {3.158 + regdef_t reg = block->regs[i];3.159 + if( reg->mode != REG_WO && reg->mode != REG_MIRROR ) {3.160 + unsigned offset = reg->offset;3.161 + for( unsigned j=0; j<reg->numElements; j++ ) {3.162 + if( reg->type == REG_STRING ) {3.163 + memcpy( &page[offset], reg->initValue.s, reg->numBytes );3.164 + } else {3.165 + memcpy( &page[offset], reg->initValue.a, reg->numBytes );3.166 + }3.167 + offset += reg->numBytes;3.168 + }3.169 + }3.170 + }3.171 +3.172 + /* Finally clone mirror groups */3.173 + for( unsigned i=0; i<block->numRegs; i++ ) {3.174 + regdef_t reg = block->regs[i];3.175 + if( reg->mode == REG_MIRROR ) {3.176 + unsigned offset = reg->offset;3.177 + unsigned target = reg->initValue.i;3.178 + for( unsigned i=0; i<reg->numElements; i++ ) {3.179 + memcpy( &page[offset], &page[target], reg->numBytes );3.180 + offset += reg->stride;3.181 + }3.182 + }3.183 + }3.184 +3.185 + return page;3.186 +}3.187 +3.188 +3.189 +void fwrite_dump( unsigned char *data, unsigned int length, FILE *f )3.190 +{3.191 + unsigned int i, j;3.192 + int skipped = 0;3.193 + for( i =0; i<length; i+=16 ) {3.194 + if( i >= 16 && i < length-16 && memcmp( &data[i], &data[i-16], 16) == 0 ) {3.195 + skipped++;3.196 + continue;3.197 + }3.198 + if( skipped ) {3.199 + fprintf( f, " ** \n" );3.200 + skipped = 0;3.201 + }3.202 + fprintf( f, "%08X:", i);3.203 + for( j=i; j<i+16; j++ ) {3.204 + if( j != i && (j % 4) == 0 )3.205 + fprintf( f, " " );3.206 + if( j < length )3.207 + fprintf( f, " %02X", (unsigned int)(data[j]) );3.208 + else3.209 + fprintf( f, " " );3.210 + }3.211 + fprintf( f, " " );3.212 + for( j=i; j<i+16 && j<length; j++ ) {3.213 + fprintf( f, "%c", isprint(data[j]) ? data[j] : '.' );3.214 + }3.215 + fprintf( f, "\n" );3.216 + }3.217 +}3.218 +3.219 +static const char *file_top = "/**\n"3.220 + " * This file was automatically generated by genmmio, do not edit\n"3.221 + " */\n";3.222 +3.223 +void write_source( FILE *f, GList *blocks, const char *header_filename )3.224 +{3.225 + fputs( file_top, f );3.226 + fprintf( f, "\n#include \"%s\"\n\n", header_filename );3.227 +3.228 + for( GList *ptr = blocks; ptr != NULL; ptr = ptr->next ) {3.229 + regblock_t block = (regblock_t)ptr->data;3.230 + /* Generate the mmio region struct */3.231 + fprintf( f, "void FASTCALL mmio_region_%s_write(uint32_t, uint32_t);\n", block->name );3.232 + fprintf( f, "void FASTCALL mmio_region_%s_write_word(uint32_t, uint32_t);\n", block->name );3.233 + fprintf( f, "void FASTCALL mmio_region_%s_write_byte(uint32_t, uint32_t);\n", block->name );3.234 + fprintf( f, "void FASTCALL mmio_region_%s_write_burst(uint32_t, unsigned char *);\n", block->name );3.235 + fprintf( f, "int32_t FASTCALL mmio_region_%s_read(uint32_t);\n", block->name );3.236 + fprintf( f, "int32_t FASTCALL mmio_region_%s_read_word(uint32_t);\n", block->name );3.237 + fprintf( f, "int32_t FASTCALL mmio_region_%s_read_byte(uint32_t);\n", block->name );3.238 + fprintf( f, "void FASTCALL mmio_region_%s_read_burst(unsigned char *, uint32_t);\n", block->name );3.239 + fprintf( f, "struct mmio_region mmio_region_%s = {\n", block->name );3.240 + fprintf( f, " \"%s\", \"%s\", %08x, {\n", block->name,3.241 + block->description == NULL ? block->name : block->description,3.242 + block->address );3.243 + fprintf( f, " mmio_region_%s_read, mmio_region_%s_write,\n", block->name, block->name );3.244 + fprintf( f, " mmio_region_%s_read_word, mmio_region_%s_write_word,\n", block->name, block->name );3.245 + fprintf( f, " mmio_region_%s_read_byte, mmio_region_%s_write_byte,\n", block->name, block->name );3.246 + fprintf( f, " mmio_region_%s_read_burst, mmio_region_%s_write_burst,\n", block->name, block->name );3.247 + fprintf( f, " unmapped_prefetch, mmio_region_%s_read_byte },\n", block->name, block->name );3.248 + fprintf( f, " NULL, NULL, {\n" );3.249 + for( unsigned i=0; i<block->numRegs; i++ ) {3.250 + regdef_t reg = block->regs[i];3.251 + if( reg->mode != REG_CONST ) {3.252 + char tmp[32];3.253 + const char *regname = reg->name;3.254 + if( regname == NULL ) {3.255 + regname = tmp;3.256 + snprintf( tmp, sizeof(tmp), "%s_%03X", block->name, reg->offset );3.257 + }3.258 +3.259 + fprintf( f, " { \"%s\", \"%s\", %d, 0x%03x, 0x%08x, %s },\n", regname,3.260 + reg->description == NULL ? regname : reg->description,3.261 + reg->numBytes*8, reg->offset, (unsigned)reg->initValue.i,3.262 + (reg->mode == REG_RW ? "PORT_MRW" : (reg->mode == REG_WO ? "PORT_W" : "PORT_R")) );3.263 + }3.264 + }3.265 + fprintf( f, " }, NULL };\n" );3.266 + }3.267 +3.268 +}3.269 +3.270 +void write_header( FILE *f, GList *blocks )3.271 +{3.272 + fputs( file_top, f );3.273 +3.274 + fputs( "\n#include \"mmio.h\"\n\n", f );3.275 +3.276 + for( GList *ptr = blocks; ptr != NULL; ptr = ptr->next ) {3.277 + regblock_t block = (regblock_t)ptr->data;3.278 + fprintf( f, "extern struct mmio_region mmio_region_%s;\n", block->name );3.279 + fprintf( f, "enum mmio_region_%s_port_t {\n", block->name );3.280 + for( unsigned i=0; i<block->numRegs; i++ ) {3.281 + regdef_t reg = block->regs[i];3.282 + if( reg->name != NULL ) {3.283 + fprintf( f, " %s = 0x%03x,\n", reg->name, reg->offset );3.284 + }3.285 + }3.286 + fprintf( f, "};\n" );3.287 + }3.288 +}3.289 +3.290 +void write_test( FILE *f, GList *blocks )3.291 +{3.292 +3.293 +3.294 +}3.295 +3.296 +int main(int argc, char *argv[])3.297 +{3.298 + const char *header = NULL;3.299 + const char *output = NULL;3.300 + gboolean check_only = FALSE;3.301 + int verbose = 0, opt;3.302 + GList *block_list = NULL;3.303 +3.304 + while( (opt = getopt_long( argc, argv, short_options, long_options, NULL )) != -1 ) {3.305 + switch(opt) {3.306 + case 'c':3.307 + check_only = TRUE;3.308 + break;3.309 + case 'd':3.310 + header = optarg;3.311 + break;3.312 + case 'h':3.313 + print_usage();3.314 + exit(0);3.315 + case 'o':3.316 + output = optarg;3.317 + break;3.318 + case 'v':3.319 + verbose++;3.320 + break;3.321 + }3.322 + }3.323 +3.324 + if( optind == argc ) {3.325 + print_usage();3.326 + exit(1);3.327 + }3.328 +3.329 + if( output == NULL ) {3.330 + output = makeFilename(argv[optind],".c");3.331 + }3.332 + if( header == NULL ) {3.333 + header = makeFilename(argv[optind],".h");3.334 + }3.335 +3.336 + for( ; optind < argc; optind++ ) {3.337 + block_list = ioparse(argv[optind], block_list);3.338 + }3.339 +3.340 + if( verbose ) {3.341 + dump_register_blocks(stdout, block_list, verbose>1);3.342 + }3.343 +3.344 + int errors = check_registers(block_list);3.345 + if( errors != 0 ) {3.346 + fprintf( stderr, "Aborting due to validation errors\n" );3.347 + return 2;3.348 + }3.349 +3.350 + if( !check_only ) {3.351 + FILE *f = fopen( output, "wo" );3.352 + if( f == NULL ) {3.353 + fprintf( stderr, "Unable to open output file '%s': %s\n", output, strerror(errno) );3.354 + return 3;3.355 + }3.356 + write_source( f, block_list, header );3.357 + fclose(f);3.358 +3.359 + f = fopen( header, "wo" );3.360 + if( f == NULL ) {3.361 + fprintf( stderr, "Unable to open header file '%s': %s\n", header, strerror(errno) );3.362 + return 4;3.363 + }3.364 + write_header( f, block_list );3.365 + fclose(f);3.366 + }3.367 +3.368 + for( GList *ptr = block_list; ptr != NULL; ptr = ptr->next ) {3.369 + char *data = build_page_initializer((regblock_t)ptr->data);3.370 + fwrite_dump( data, LXDREAM_PAGE_SIZE, stdout );3.371 + g_free(data);3.372 + }3.373 + return 0;3.374 +}3.375 +
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00004.2 +++ b/src/tools/genmach.h Mon Mar 15 22:10:24 2010 +10004.3 @@ -0,0 +1,127 @@4.4 +/**4.5 + * $Id$4.6 + *4.7 + * mmio register code generator4.8 + *4.9 + * Copyright (c) 2010 Nathan Keynes.4.10 + *4.11 + * This program is free software; you can redistribute it and/or modify4.12 + * it under the terms of the GNU General Public License as published by4.13 + * the Free Software Foundation; either version 2 of the License, or4.14 + * (at your option) any later version.4.15 + *4.16 + * This program is distributed in the hope that it will be useful,4.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of4.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the4.19 + * GNU General Public License for more details.4.20 + */4.21 +4.22 +#ifndef lxdream_genmmio_H4.23 +#define lxdream_genmmio_H 14.24 +4.25 +#include <stdint.h>4.26 +#include <glib/glist.h>4.27 +4.28 +#ifdef __cplusplus4.29 +extern "C" {4.30 +#endif4.31 +4.32 +typedef enum {4.33 + REG_CONST,4.34 + REG_RW,4.35 + REG_RO,4.36 + REG_WO,4.37 + REG_MIRROR, /* Additional address for an existing register - value is the offset of the target reg */4.38 +} register_mode_t;4.39 +4.40 +typedef enum {4.41 + REG_I8,4.42 + REG_I16,4.43 + REG_I32,4.44 + REG_I64,4.45 + REG_F32,4.46 + REG_F64,4.47 + REG_STRING,4.48 +} register_type_t;4.49 +4.50 +typedef enum {4.51 + ENDIAN_DEFAULT,4.52 + ENDIAN_LITTLE,4.53 + ENDIAN_BIG4.54 +} register_endian_t;4.55 +4.56 +typedef enum {4.57 + ACCESS_DEFAULT,4.58 + ACCESS_ANY,4.59 + ACCESS_NOOFFSET,4.60 + ACCESS_EXACT4.61 +} register_access_t;4.62 +4.63 +typedef enum {4.64 + TRACE_DEFAULT,4.65 + TRACE_NEVER,4.66 + TRACE_ALWAYS4.67 +} register_trace_t;4.68 +4.69 +typedef enum {4.70 + TEST_DEFAULT,4.71 + TEST_OFF,4.72 + TEST_ON4.73 +} register_test_t;4.74 +4.75 +union apval {4.76 + uint64_t i;4.77 + char a[8];4.78 + const char *s;4.79 +};4.80 +4.81 +struct action {4.82 + const char *filename;4.83 + int lineno;4.84 + const char *text;4.85 +};4.86 +4.87 +typedef struct regflags {4.88 + register_endian_t endian;4.89 + register_access_t access;4.90 + register_trace_t traceFlag;4.91 + register_test_t testFlag;4.92 + union apval maskValue;4.93 + unsigned int fillSizeBytes;4.94 + union apval fillValue;4.95 +} *regflags_t;4.96 +4.97 +typedef struct regdef {4.98 + const char *name;4.99 + const char *description;4.100 + uint32_t offset;4.101 + unsigned numBytes;4.102 + unsigned numElements;4.103 + unsigned stride;4.104 + register_mode_t mode;4.105 + register_type_t type;4.106 + gboolean initUndefined;4.107 + union apval initValue;4.108 + struct regflags flags;4.109 + struct action *action;4.110 +} *regdef_t;4.111 +4.112 +typedef struct regblock {4.113 + const char *name;4.114 + const char *description;4.115 + uint32_t address;4.116 + struct regflags flags;4.117 + unsigned numRegs;4.118 + unsigned blockSize;4.119 + regdef_t regs[];4.120 +} *regblock_t;4.121 +4.122 +4.123 +4.124 +GList *ioparse( const char *filename, GList *list );4.125 +4.126 +#ifdef __cplusplus4.127 +}4.128 +#endif4.129 +4.130 +#endif /* !lxdream_genmmio_H */
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00005.2 +++ b/src/tools/mdparse.c Mon Mar 15 22:10:24 2010 +10005.3 @@ -0,0 +1,721 @@5.4 +/**5.5 + * $Id$5.6 + *5.7 + * genmmio I/O register definition parser.5.8 + *5.9 + * Copyright (c) 2010 Nathan Keynes.5.10 + *5.11 + * This program is free software; you can redistribute it and/or modify5.12 + * it under the terms of the GNU General Public License as published by5.13 + * the Free Software Foundation; either version 2 of the License, or5.14 + * (at your option) any later version.5.15 + *5.16 + * This program is distributed in the hope that it will be useful,5.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of5.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the5.19 + * GNU General Public License for more details.5.20 + */5.21 +5.22 +#include <assert.h>5.23 +#include <stdlib.h>5.24 +#include <stdio.h>5.25 +#include <string.h>5.26 +#include <unistd.h>5.27 +#include <fcntl.h>5.28 +#include <ctype.h>5.29 +#include <errno.h>5.30 +#include <sys/stat.h>5.31 +#include <glib/gmem.h>5.32 +5.33 +#include "genmach.h"5.34 +/*5.35 + * Grammar:5.36 + *5.37 + * start: start register_block | ;5.38 + * register_block: 'registers' IDENTIFIER 'at' INTEGER opt_paramlist '{' register_list '}';5.39 + * opt_paramlist: '(' param_list ')' | '(' ')' | ;5.40 + * param_list: param_list ',' param | param ;5.41 + * param: access_param | fill_param | endian_param | mask_param ;5.42 + * access_param: 'access' '=' 'any' // Behaves as if it were memory5.43 + * | 'access' '=' 'nooffset' // Recognize any size access (zero-ext or trunc) as long as the address is exactly the same5.44 + * | 'access' '=' 'exact' // Recognize only the exact access type at the exact address5.45 + * ;5.46 + * fill_param: 'fill' '=' literal;5.47 + * endian_param: 'endian' '=' 'little'5.48 + * | 'endian' '=' 'big'5.49 + * ;5.50 + * mask_param: 'mask' '=' literal;5.51 + *5.52 + * register_list: register_list register_desc | ;5.53 + * register_desc: INTEGER ':' mode_spec type_spec IDENTIFIER opt_paramlist [ '=' literal ] [ ACTION ]5.54 + * mode_spec: 'const' | 'rw' | 'ro' | 'wo';5.55 + * type_spec: 'i8' | 'i16' | 'i32' | 'i64' | 'f32' | 'f64' | 'string' | 'cstring';5.56 + * literal: INTEGER | STRING | 'undefined' ;5.57 + *5.58 + * C-style comments are recognized as such.5.59 + */5.60 +5.61 +#define TOK_IDENTIFIER 15.62 +#define TOK_INTEGER 25.63 +#define TOK_STRING 35.64 +#define TOK_ACTION 45.65 +#define TOK_EOF 55.66 +#define TOK_ERROR 65.67 +#define TOK_LPAREN 75.68 +#define TOK_RPAREN 85.69 +#define TOK_LBRACE 95.70 +#define TOK_RBRACE 105.71 +#define TOK_COMMA 115.72 +#define TOK_COLON 125.73 +#define TOK_SEMI 135.74 +#define TOK_PERIOD 145.75 +#define TOK_RANGE 155.76 +#define TOK_LSQUARE 165.77 +#define TOK_RSQUARE 175.78 +#define TOK_EQUALS 185.79 +#define TOK_ACCESS 195.80 +#define TOK_AT 205.81 +#define TOK_ENDIAN 215.82 +#define TOK_FILL 225.83 +#define TOK_INCLUDE 235.84 +#define TOK_MASK 245.85 +#define TOK_REGISTERS 255.86 +#define TOK_SPACE 265.87 +#define TOK_STRIDE 275.88 +#define TOK_TEST 285.89 +#define TOK_TRACE 295.90 +#define TOK_UNDEFINED 305.91 +5.92 +5.93 +#define FIRST_KEYWORD TOK_ACCESS5.94 +#define LAST_KEYWORD TOK_UNDEFINED5.95 +static const char *TOKEN_NAMES[] = {"NULL", "IDENTIFIER", "INTEGER", "STRING", "ACTION", "EOF", "ERROR",5.96 + "(", ")", "{", "}", ",", ":", ";", ".", "..", "[", "]", "=",5.97 + "ACCESS", "AT", "ENDIAN", "FILL", "INCLUDE", "MASK", "REGISTERS", "SPACE", "STRIDE", "TEST", "TRACE", "UNDEFINED" };5.98 +static const char *MODE_NAMES[] = {"const", "rw", "ro", "wo", "mirror"};5.99 +static const char *TYPE_NAMES[] = {"i8", "i16", "i32", "i64", "f32", "f64", "string"};5.100 +static int TYPE_SIZES[] = {1,2,4,8,4,8,0};5.101 +static const char *ENDIAN_NAMES[] = {"default", "little", "big"};5.102 +static const char *ACCESS_NAMES[] = {"default", "any", "nooffset", "exact"};5.103 +static const char *TRACE_NAMES[] = {"default", "off", "on"};5.104 +5.105 +#define elementsof(x) (sizeof(x)/sizeof(x[0]))5.106 +5.107 +typedef struct token_data {5.108 + char *yytext;5.109 + int yylength;5.110 + int yyline;5.111 + int yycol;5.112 + union {5.113 + long i;5.114 + char *s;5.115 + } v;5.116 + int slen;5.117 +} token_data;5.118 +5.119 +static char *yybuffer;5.120 +static char *yyposn, *yylineposn;5.121 +static char *yyend;5.122 +static int yyline;5.123 +static struct token_data yytok;5.124 +5.125 +#define YYPARSE_ERROR( msg, ... ) \5.126 + do { \5.127 + fprintf( stderr, "Parse error at %d:%d: " msg "\n", yytok.yyline, yytok.yycol, __VA_ARGS__ ); \5.128 + exit(2); \5.129 + } while(0)5.130 +5.131 +#define READ(x) \5.132 +{ int _tok = iolex(x); \5.133 + if( _tok != (x) ) { \5.134 + YYPARSE_ERROR( "Expected %s but got %s", TOKEN_NAMES[x], TOKEN_NAMES[_tok] ); \5.135 + } \5.136 +}5.137 +5.138 +static int iolex( int expectToken );5.139 +static int iolex_open( const char *filename );5.140 +static void iolex_close();5.141 +5.142 +static inline char *yystrdup()5.143 +{5.144 + char *str = g_malloc0(yytok.yylength+1);5.145 + memcpy( str, yytok.yytext, yytok.yylength);5.146 + return str;5.147 +}5.148 +5.149 +static inline int yystrcasecmp(const char *cmp)5.150 +{5.151 + int len = strlen(cmp);5.152 + if( len != yytok.yylength ) {5.153 + return yytok.yylength - len;5.154 + }5.155 + return strncasecmp(yytok.yytext, cmp, yytok.yylength);5.156 +}5.157 +5.158 +static int yymatch( const char *arr[], unsigned numOptions )5.159 +{5.160 + for( unsigned i=0; i<numOptions; i++ ) {5.161 + if( yystrcasecmp( arr[i] ) == 0 ) {5.162 + return i;5.163 + }5.164 + }5.165 + return -1;5.166 +}5.167 +5.168 +static gint register_block_sort_cb( gconstpointer a, gconstpointer b )5.169 +{5.170 + struct regblock *blocka = (struct regblock *)a;5.171 + struct regblock *blockb = (struct regblock *)b;5.172 + return blocka->address - blockb->address;5.173 +}5.174 +5.175 +static int register_ptr_sort_cb( const void *a, const void *b )5.176 +{5.177 + regdef_t *ptra = (regdef_t *)a;5.178 + regdef_t *ptrb = (regdef_t *)b;5.179 + if( (*ptra)->offset != (*ptrb)->offset )5.180 + return (*ptra)->offset - (*ptrb)->offset;5.181 + return (*ptra)->type - (*ptrb)->type;5.182 +}5.183 +5.184 +static void ioparse_apval(int tok, union apval *apv, unsigned *numBytes)5.185 +{5.186 + if( tok == TOK_INTEGER ) {5.187 + apv->i = yytok.v.i;5.188 + if( *numBytes == 0 ) {5.189 + YYPARSE_ERROR( "Expected string initializer but was an integer (0x%x)", yytok.v.i );5.190 + }5.191 + } else if( tok = TOK_STRING ) {5.192 + if( *numBytes == 0 ) {5.193 + *numBytes = yytok.slen;5.194 + apv->s = yytok.v.s;5.195 + } else {5.196 + if( *numBytes != yytok.slen ) {5.197 + YYPARSE_ERROR( "Expected %d byte initializer but was %d", *numBytes, yytok.slen );5.198 + }5.199 + assert( *numBytes < sizeof(uint64_t) );5.200 + apv->i = 0;5.201 + /* FIXME: handle endian mismatches */5.202 + memcpy( &apv->i, yytok.v.s, yytok.slen );5.203 + }5.204 + } else {5.205 + YYPARSE_ERROR( "Expected literal (integer or string), but got %s", TOKEN_NAMES[tok] );5.206 + }5.207 +}5.208 +5.209 +static void ioparse_regflags( regflags_t flags, unsigned *numBytes )5.210 +{5.211 + do {5.212 + int tok = iolex(TOK_RPAREN);5.213 + switch(tok) {5.214 + case TOK_FILL:5.215 + READ(TOK_EQUALS);5.216 + tok = iolex(TOK_INTEGER);5.217 + flags->fillSizeBytes = 4;5.218 + ioparse_apval( tok, &flags->fillValue, &flags->fillSizeBytes );5.219 + break;5.220 + case TOK_ACCESS:5.221 + READ(TOK_EQUALS);5.222 + READ(TOK_IDENTIFIER);5.223 + flags->access = yymatch(ACCESS_NAMES,elementsof(ACCESS_NAMES));5.224 + if( flags->access == -1 ) {5.225 + YYPARSE_ERROR("Unknown access mode '%s'", yystrdup());5.226 + }5.227 + break;5.228 + case TOK_MASK:5.229 + if( numBytes ) {5.230 + READ(TOK_EQUALS);5.231 + tok = iolex(TOK_INTEGER);5.232 + ioparse_apval( tok, &flags->maskValue, numBytes );5.233 + } else {5.234 + YYPARSE_ERROR("mask is not valid on a register block",0);5.235 + }5.236 + break;5.237 + case TOK_ENDIAN:5.238 + READ(TOK_EQUALS);5.239 + READ(TOK_IDENTIFIER);5.240 + flags->endian = yymatch(ENDIAN_NAMES,elementsof(ENDIAN_NAMES));5.241 + if( flags->endian == -1 ) {5.242 + YYPARSE_ERROR("Unknown endianness '%s'", yystrdup());5.243 + }5.244 + break;5.245 + case TOK_TRACE:5.246 + READ(TOK_EQUALS);5.247 + READ(TOK_IDENTIFIER);5.248 + flags->traceFlag = yymatch(TRACE_NAMES,elementsof(TRACE_NAMES));5.249 + if( flags->traceFlag == -1 ) {5.250 + YYPARSE_ERROR("Unknown trace flag '%s'", yystrdup());5.251 + }5.252 + break;5.253 + case TOK_TEST:5.254 + READ(TOK_EQUALS);5.255 + READ(TOK_IDENTIFIER);5.256 + flags->testFlag = yymatch(TRACE_NAMES,elementsof(TRACE_NAMES));5.257 + if( flags->testFlag == -1 ) {5.258 + YYPARSE_ERROR("Unknown test flag '%s'", yystrdup());5.259 + }5.260 + break;5.261 + case TOK_COMMA:5.262 + break;5.263 + case TOK_RPAREN:5.264 + return;5.265 + default:5.266 + YYPARSE_ERROR("Expected flag or ')' but was %s", TOKEN_NAMES[tok]);5.267 + }5.268 + } while(1);5.269 +}5.270 +5.271 +static void ioparse_regdef( struct regdef *reg )5.272 +{5.273 + reg->offset = yytok.v.i;5.274 + reg->numElements = 1;5.275 + reg->numBytes = 0;5.276 + reg->initValue.i = 0;5.277 + reg->flags.maskValue.i = -1;5.278 + unsigned rangeOffset = reg->offset;5.279 +5.280 + int tok = iolex(TOK_COLON);5.281 + if( tok == TOK_RANGE ) {5.282 + READ(TOK_INTEGER);5.283 + rangeOffset = yytok.v.i;5.284 + if( rangeOffset < reg->offset ) {5.285 + YYPARSE_ERROR( "Range end (0x%x) must be greater than the range start (0x%x)", rangeOffset, reg->offset );5.286 + }5.287 + READ(TOK_COLON);5.288 + } else if( tok != TOK_COLON ) {5.289 + YYPARSE_ERROR( "Expected ':' but was %s\n", TOKEN_NAMES[tok] );5.290 + }5.291 + READ(TOK_IDENTIFIER);5.292 + reg->mode = yymatch(MODE_NAMES, elementsof(MODE_NAMES));5.293 + if( reg->mode == -1 ) {5.294 + YYPARSE_ERROR( "Unknown register mode '%s'", yystrdup() );5.295 + }5.296 + if( reg->mode == REG_MIRROR ) {5.297 + /* Mirror regions have a target range only */5.298 + READ(TOK_INTEGER);5.299 + reg->initValue.i = yytok.v.i;5.300 + reg->type = REG_I8;5.301 + tok = iolex(TOK_RANGE);5.302 + if( tok == TOK_RANGE ) {5.303 + READ(TOK_INTEGER);5.304 + if( yytok.v.i < reg->initValue.i ) {5.305 + YYPARSE_ERROR( "Invalid mirror target range 0x%x..0x%x", reg->initValue.i, yytok.v.i );5.306 + }5.307 + reg->numBytes = yytok.v.i - reg->initValue.i + 1;5.308 + tok = iolex(TOK_STRIDE);5.309 + }5.310 + if( tok == TOK_STRIDE ) {5.311 + READ(TOK_INTEGER);5.312 + reg->stride = yytok.v.i;5.313 + tok = iolex(TOK_ACTION);5.314 + } else {5.315 + reg->stride = reg->numBytes;5.316 + }5.317 +5.318 + if( tok != TOK_SEMI ) {5.319 + YYPARSE_ERROR( "Expected ; but gut %s", TOKEN_NAMES[tok] );5.320 + }5.321 +5.322 + if( reg->stride < reg->numBytes ) {5.323 + YYPARSE_ERROR( "Invalid mirror stride: %x is less than block size %x\n", reg->stride, reg->numBytes );5.324 + }5.325 +5.326 + if( rangeOffset != reg->offset ) {5.327 + reg->numElements *= ((rangeOffset - reg->offset) + reg->stride - 1) / reg->stride;5.328 + }5.329 +5.330 + } else {5.331 + READ(TOK_IDENTIFIER);5.332 + reg->type = yymatch(TYPE_NAMES, elementsof(TYPE_NAMES));5.333 + if( reg->type == -1 ) {5.334 + YYPARSE_ERROR( "Unknown register type '%s'", yystrdup() );5.335 + }5.336 + reg->numBytes = TYPE_SIZES[reg->type];5.337 + tok = iolex(TOK_IDENTIFIER);5.338 + if( tok == TOK_IDENTIFIER ) {5.339 + reg->name = yystrdup();5.340 + tok = iolex(TOK_ACTION);5.341 + }5.342 + if( tok == TOK_STRING ) {5.343 + reg->description = yytok.v.s;5.344 + tok = iolex(TOK_ACTION);5.345 + }5.346 + if( tok == TOK_LPAREN ) {5.347 + ioparse_regflags(®->flags, ®->numBytes);5.348 + tok = iolex(TOK_ACTION);5.349 + }5.350 + if( tok == TOK_EQUALS ) {5.351 + tok = iolex(TOK_INTEGER);5.352 + if( tok == TOK_UNDEFINED ) {5.353 + reg->initValue.i = 0xDEADBEEFDEADBEEF;5.354 + reg->initUndefined = TRUE;5.355 + } else {5.356 + ioparse_apval(tok, ®->initValue, ®->numBytes);5.357 + }5.358 + tok = iolex(TOK_ACTION);5.359 + } else if( reg->type == REG_STRING ) {5.360 + YYPARSE_ERROR( "String declarations must have an initializer (ie = 'abcd')",0 );5.361 + }5.362 + if( tok == TOK_ACTION ) {5.363 + // reg->action = yystrdup();5.364 + } else if( tok != TOK_SEMI ) {5.365 + YYPARSE_ERROR( "Expected ; or {, but got %s", TOKEN_NAMES[tok] );5.366 + }5.367 +5.368 + if( rangeOffset != reg->offset ) {5.369 + reg->numElements *= ((rangeOffset - reg->offset) + reg->numBytes - 1) / reg->numBytes;5.370 + }5.371 + }5.372 +5.373 +}5.374 +5.375 +static struct regblock *ioparse_regblock( )5.376 +{5.377 + unsigned regsAllocSize = 128;5.378 + struct regblock *block = g_malloc0(sizeof(struct regblock) + sizeof(regdef_t)*regsAllocSize);5.379 + block->numRegs = 0;5.380 +5.381 + READ(TOK_IDENTIFIER);5.382 + block->name = yystrdup();5.383 + int tok = iolex(TOK_AT);5.384 + if( tok == TOK_STRING ) {5.385 + block->description = yytok.v.s;5.386 + tok = iolex(TOK_AT);5.387 + }5.388 + if( tok != TOK_AT ) {5.389 + YYPARSE_ERROR("Expected AT but got %s\n", TOKEN_NAMES[tok] );5.390 + }5.391 + READ(TOK_INTEGER);5.392 + block->address = yytok.v.i;5.393 +5.394 + tok = iolex(TOK_LBRACE);5.395 + if( tok == TOK_LPAREN) {5.396 + ioparse_regflags(&block->flags, NULL);5.397 + READ(TOK_LBRACE);5.398 + } else if( tok != TOK_LBRACE ) {5.399 + YYPARSE_ERROR("Expected { but got %s\n", TOKEN_NAMES[tok] );5.400 + }5.401 +5.402 + tok = iolex(TOK_INTEGER);5.403 + while( tok != TOK_RBRACE ) {5.404 + if( tok != TOK_INTEGER ) {5.405 + YYPARSE_ERROR("Expected INTEGER or } but got %s\n", TOKEN_NAMES[tok]);5.406 + }5.407 + struct regdef *regdef = g_malloc0(sizeof(struct regdef));5.408 + if( block->numRegs >= regsAllocSize ) {5.409 + regsAllocSize *= 2;5.410 + block = g_realloc(block, sizeof(struct regblock) + sizeof(regdef_t)*regsAllocSize);5.411 + }5.412 + block->regs[block->numRegs++] = regdef;5.413 + ioparse_regdef(regdef);5.414 +5.415 + tok = iolex(TOK_INTEGER);5.416 + }5.417 +5.418 + qsort( &block->regs[0], block->numRegs, sizeof(block->regs[0]), register_ptr_sort_cb );5.419 +5.420 + return block;5.421 +}5.422 +5.423 +GList *ioparse( const char *filename, GList *list )5.424 +{5.425 + GList *blocks = list;5.426 + int count = 0;5.427 +5.428 + if( iolex_open(filename) != 0 )5.429 + return blocks;5.430 +5.431 + int tok;5.432 + do {5.433 + tok = iolex(TOK_REGISTERS);5.434 + if( tok == TOK_EOF ) {5.435 + return blocks;5.436 + } else if( tok == TOK_INCLUDE) {5.437 + READ(TOK_STRING);5.438 +5.439 + } else if( tok == TOK_SPACE ) {5.440 + } else if( tok == TOK_REGISTERS ) {5.441 + struct regblock *block = ioparse_regblock(block);5.442 + count++;5.443 + blocks = g_list_insert_sorted(blocks, block, register_block_sort_cb);5.444 + } else {5.445 + YYPARSE_ERROR("Expected REGISTERS but got %s\n", TOKEN_NAMES[tok] );5.446 + }5.447 + } while( tok != TOK_EOF );5.448 +5.449 + iolex_close();5.450 + if( count == 0 ) {5.451 + fprintf( stderr, "Warning: input file '%s' did not contain any register definitions\n" );5.452 + }5.453 +5.454 + return blocks;5.455 +}5.456 +5.457 +/**************************** Lexical analyser ***************************/5.458 +5.459 +static int iolex_open( const char *filename )5.460 +{5.461 + struct stat st;5.462 + int fd = open( filename, O_RDONLY );5.463 + if( fd == -1 ) {5.464 + fprintf( stderr, "Error opening file '%s': %s\n", filename, strerror(errno) );5.465 + return -1;5.466 + }5.467 +5.468 + if( fstat( fd, &st ) != 0 ) {5.469 + fprintf( stderr, "Error statting file '%s': %s\n", filename, strerror(errno) );5.470 + close(fd);5.471 + return -1;5.472 + }5.473 +5.474 + char *data = g_malloc( st.st_size + 1 );5.475 + if( read(fd, data, st.st_size) != st.st_size ) {5.476 + fprintf( stderr, "Error reading file '%s': %s\n", filename, strerror(errno) );5.477 + close(fd);5.478 + return -1;5.479 + }5.480 + close(fd);5.481 + data[st.st_size] = 0;5.482 +5.483 + yybuffer = yyposn = data;5.484 + yyend = data + st.st_size;5.485 + yyline = 1;5.486 + yylineposn = yyposn;5.487 + return 0;5.488 +}5.489 +5.490 +static void iolex_close()5.491 +{5.492 + g_free(yybuffer);5.493 + yybuffer = yyend = NULL;5.494 +}5.495 +5.496 +#define YYRETURN(x) do{ \5.497 + yytok.yylength = yyposn - yystart; \5.498 + return (x); \5.499 +} while(0)5.500 +5.501 +static int iolex_readhex(char *p, int digits)5.502 +{5.503 + int result = 0;5.504 + for( int i=0; i < digits; i++ ) {5.505 + result <<= 4;5.506 + if( isdigit(p[i]) ) {5.507 + result += p[i]-'0';5.508 + } else if( p[i] >= 'a' && p[i] <= 'f' ) {5.509 + result += p[i]-'a'+10;5.510 + } else if( p[i] >= 'A' && p[i] <= 'F' ) {5.511 + result += p[i]-'A'+10;5.512 + } else {5.513 + return (result >> 4);5.514 + }5.515 +5.516 + }5.517 + return result;5.518 +}5.519 +5.520 +static int iolex_readoctal(char *p, int digits)5.521 +{5.522 + int result = 0;5.523 + for( int i=0; i < digits; i++ ) {5.524 + result <<= 3;5.525 + if( p[i] >= '0' && p[i] <= '7' ) {5.526 + result += p[i]-'0';5.527 + } else {5.528 + return (result >> 4);5.529 + }5.530 + }5.531 + return result;5.532 +}5.533 +5.534 +/**5.535 + * Copy and interpret the string segment as a C string, replacing escape5.536 + * expressions with the corresponding value.5.537 + */5.538 +static char *iolex_getcstring( char *start, char *end, int *len )5.539 +{5.540 + char *result = g_malloc0(end-start+1); /* Allocate enough memory for the string as-is */5.541 + char *q = result;5.542 +5.543 + for( char *p = start; p != end; p++ ) {5.544 + if( *p == '\\' ) {5.545 + if( ++p == end ) {5.546 + *q++ = '\\';5.547 + break;5.548 + }5.549 + if( p[0] >= '0' && p[0] <= '3' && p+3 <= end &&5.550 + p[1] >= '0' && p[1] <= '7' &&5.551 + p[2] >= '0' && p[2] <= '7' ) {5.552 + *q++ = (char)iolex_readoctal(p,3);5.553 + p+=2;5.554 + } else {5.555 + switch( *p ) {5.556 + case 'n':5.557 + *q++ = '\n';5.558 + break;5.559 + case 'r':5.560 + *q++ = '\r';5.561 + break;5.562 + case 't':5.563 + *q++ = '\t';5.564 + break;5.565 + case 'x': /* hex */5.566 + if( p + 3 > end || !isxdigit(p[1]) || !isxdigit(p[2]) ) {5.567 + *q++ = '\\';5.568 + *q++ = *p;5.569 + } else {5.570 + *q++ = (char)iolex_readhex(p+1, 2);5.571 + p+=2;5.572 + }5.573 + break;5.574 + default:5.575 + *q++ = '\\';5.576 + *q++ = *p;5.577 + }5.578 + }5.579 + } else {5.580 + *q++ = *p;5.581 + }5.582 + }5.583 + *len = q - result;5.584 + return result;5.585 +}5.586 +5.587 +int iolex( int expectToken )5.588 +{5.589 + int count = 0;5.590 + while( yyposn < yyend ) {5.591 + char *yystart = yytok.yytext = yyposn;5.592 + yytok.yylength = 1;5.593 + yytok.yyline = yyline;5.594 + yytok.yycol = yyposn - yylineposn+1;5.595 + int ch = *yyposn++;5.596 + if( isdigit(ch) ) {5.597 + /* INTEGER */5.598 + if( ch == '0' ) {5.599 + if( *yyposn == 'x' ) {5.600 + while( yyposn < yyend && isxdigit(*++yyposn) ) ;5.601 + } else {5.602 + while( yyposn < yyend && *yyposn >= '0' && *yyposn <= '7' )5.603 + yyposn++;5.604 + }5.605 + } else {5.606 + while( yyposn < yyend && isdigit(*yyposn) )5.607 + yyposn++;5.608 + }5.609 + yytok.v.i = strtol( yystart, NULL, 0 );5.610 + YYRETURN(TOK_INTEGER);5.611 + } else if( isalpha(ch) || ch == '_' ) {5.612 + /* IDENTIFIER */5.613 + while( yyposn < yyend && (isalnum(*yyposn) || *yyposn == '_') )5.614 + yyposn++;5.615 + yytok.yylength = yyposn - yystart;5.616 + if( expectToken == TOK_IDENTIFIER ) {5.617 + YYRETURN(TOK_IDENTIFIER);5.618 + }5.619 + /* Otherwise check for keywords */5.620 + for( int i=FIRST_KEYWORD; i <= LAST_KEYWORD; i++ ) {5.621 + if( strlen(TOKEN_NAMES[i]) == yytok.yylength &&5.622 + strncasecmp(TOKEN_NAMES[i], yystart, yytok.yylength ) == 0 ) {5.623 + YYRETURN(i);5.624 + }5.625 + }5.626 + YYRETURN(TOK_IDENTIFIER);5.627 + } else if( isspace(ch) ) {5.628 + if( ch == '\n' ) {5.629 + yyline++;5.630 + yylineposn = yyposn;5.631 + }5.632 + while( isspace(*yyposn) ) {5.633 + if( *yyposn == '\n' ) {5.634 + yyline++;5.635 + yylineposn = yyposn+1;5.636 + }5.637 + yyposn++;5.638 + }5.639 + } else {5.640 + switch( ch ) {5.641 + case '(': YYRETURN(TOK_LPAREN);5.642 + case ')': YYRETURN(TOK_RPAREN);5.643 + case '[': YYRETURN(TOK_LSQUARE);5.644 + case ']': YYRETURN(TOK_RSQUARE);5.645 + case ',': YYRETURN(TOK_COMMA);5.646 + case ':': YYRETURN(TOK_COLON);5.647 + case ';': YYRETURN(TOK_SEMI);5.648 + case '=': YYRETURN(TOK_EQUALS);5.649 + case '/':5.650 + if( *yyposn == '/' ) { /* Line comment */5.651 + while( yyposn < yyend && *++yyposn != '\n' ) ;5.652 + } else if( *yyposn == '*' ) { /* C comment */5.653 + while( yyposn < yyend && (*++yyposn != '*' || *++yyposn != '/' ) ) {5.654 + if( *yyposn == '\n' ) {5.655 + yyline++;5.656 + yylineposn = yyposn+1;5.657 + }5.658 + }5.659 + }5.660 + break;5.661 + case '\'': /* STRING */5.662 + while( *yyposn != '\'' ) {5.663 + if( *yyposn == '\n' ) {5.664 + fprintf( stderr, "Unexpected newline in string constant!\n" );5.665 + YYRETURN(TOK_ERROR);5.666 + } else if( yyposn >= yyend ) {5.667 + fprintf( stderr, "Unexpected EOF in string constant!\n" );5.668 + YYRETURN(TOK_ERROR);5.669 + } else if( *yyposn == '\\' && yyposn[1] == '\'' ) {5.670 + yyposn++;5.671 + }5.672 + yyposn++;5.673 + }5.674 + yyposn++;5.675 + yytok.v.s = iolex_getcstring(yystart+1, yyposn-1, &yytok.slen);5.676 + YYRETURN(TOK_STRING);5.677 + case '\"': /* STRING */5.678 + while( *yyposn != '\"' ) {5.679 + if( *yyposn == '\n' ) {5.680 + fprintf( stderr, "Unexpected newline in string constant!\n" );5.681 + YYRETURN(TOK_ERROR);5.682 + } else if( yyposn >= yyend ) {5.683 + fprintf( stderr, "Unexpected EOF in string constant!\n" );5.684 + YYRETURN(TOK_ERROR);5.685 + } else if( *yyposn == '\\' && yyposn[1] == '\"' ) {5.686 + yyposn++;5.687 + }5.688 + yyposn++;5.689 + }5.690 + yyposn++;5.691 + yytok.v.s = iolex_getcstring(yystart+1, yyposn-1, &yytok.slen);5.692 + YYRETURN(TOK_STRING);5.693 + case '}':5.694 + YYRETURN(TOK_RBRACE);5.695 + case '{': /* ACTION or LBRACE */5.696 + if( expectToken == TOK_LBRACE ) {5.697 + YYRETURN(TOK_LBRACE);5.698 + } else {5.699 + count++;5.700 + while( count > 0 && yyposn < yyend ) {5.701 + if( *yyposn == '{' )5.702 + count++;5.703 + if( *yyposn == '}' )5.704 + count--;5.705 + yyposn++;5.706 + }5.707 + YYRETURN(TOK_ACTION);5.708 + }5.709 + case '.':5.710 + if( *yyposn == '.' ) {5.711 + yyposn++;5.712 + YYRETURN(TOK_RANGE);5.713 + } else {5.714 + YYRETURN(TOK_PERIOD);5.715 + }5.716 + default:5.717 + fprintf( stderr, "Illegal character: '%c'\n", ch );5.718 + YYRETURN(TOK_ERROR);5.719 + }5.720 + }5.721 +5.722 + }5.723 + return TOK_EOF;5.724 +}
.