Search
lxdream.org :: lxdream :: r1104:700e16c321e5
lxdream 0.9.1
released Jun 29
Download Now
changeset1104:700e16c321e5
parent1103:de9ad2c0cf56
child1105:73da8fd129fb
authornkeynes
dateMon Mar 15 22:10:24 2010 +1000 (14 years ago)
Commit genmach work-in-progress
src/Makefile.am
src/Makefile.in
src/tools/genmach.c
src/tools/genmach.h
src/tools/mdparse.c
1.1 --- a/src/Makefile.am Sun Feb 21 11:19:59 2010 +1000
1.2 +++ b/src/Makefile.am Mon Mar 15 22:10:24 2010 +1000
1.3 @@ -12,7 +12,7 @@
1.4 PLUGINCFLAGS = @PLUGINCFLAGS@
1.5 PLUGINLDFLAGS = @PLUGINLDFLAGS@
1.6 bin_PROGRAMS = lxdream
1.7 -noinst_PROGRAMS = gendec genglsl
1.8 +noinst_PROGRAMS = gendec genglsl genmach
1.9 check_PROGRAMS = test/testxlt test/testisoread
1.10
1.11 pkglib_PROGRAMS=
1.12 @@ -36,6 +36,7 @@
1.13 #all-am: checkversion
1.14
1.15 gendec_SOURCES = tools/gendec.c tools/gendec.h tools/insparse.c tools/actparse.c
1.16 +genmach_SOURCES = tools/genmach.c tools/genmach.h tools/mdparse.c
1.17 genglsl_SOURCES = tools/genglsl.c
1.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.21
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.25
1.26
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 +1000
2.2 +++ b/src/Makefile.in Mon Mar 15 22:10:24 2010 +1000
2.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 = etags
2.42 CTAGS = ctags
2.43 @@ -555,6 +558,7 @@
2.44
2.45 #all-am: checkversion
2.46 gendec_SOURCES = tools/gendec.c tools/gendec.h tools/insparse.c tools/actparse.c
2.47 +genmach_SOURCES = tools/genmach.c tools/genmach.h tools/mdparse.c
2.48 genglsl_SOURCES = tools/genglsl.c
2.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.h
2.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.88
2.89 +genmach.o: tools/genmach.c
2.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; fi
2.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.c
2.95 +
2.96 +genmach.obj: tools/genmach.c
2.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; fi
2.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.c
2.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; fi
2.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.c
2.109 +
2.110 +mdparse.obj: tools/mdparse.c
2.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; fi
2.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.c
2.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 +0000
3.2 +++ b/src/tools/genmach.c Mon Mar 15 22:10:24 2010 +1000
3.3 @@ -0,0 +1,372 @@
3.4 +/**
3.5 + * $Id$
3.6 + *
3.7 + * mmio register code generator
3.8 + *
3.9 + * Copyright (c) 2010 Nathan Keynes.
3.10 + *
3.11 + * This program is free software; you can redistribute it and/or modify
3.12 + * it under the terms of the GNU General Public License as published by
3.13 + * the Free Software Foundation; either version 2 of the License, or
3.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 of
3.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.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 4096
3.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", return
3.64 + * a newly allocated string "file<ext>" where <ext> is the second
3.65 + * parameter.
3.66 + *
3.67 + * @param baseName a non-null filename
3.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 operation
3.86 + * is well-defined.
3.87 + * 2. Replaces transitive mirror groups with a set of equivalent direct
3.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 and
3.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 there
3.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 + else
3.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 +0000
4.2 +++ b/src/tools/genmach.h Mon Mar 15 22:10:24 2010 +1000
4.3 @@ -0,0 +1,127 @@
4.4 +/**
4.5 + * $Id$
4.6 + *
4.7 + * mmio register code generator
4.8 + *
4.9 + * Copyright (c) 2010 Nathan Keynes.
4.10 + *
4.11 + * This program is free software; you can redistribute it and/or modify
4.12 + * it under the terms of the GNU General Public License as published by
4.13 + * the Free Software Foundation; either version 2 of the License, or
4.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 of
4.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4.19 + * GNU General Public License for more details.
4.20 + */
4.21 +
4.22 +#ifndef lxdream_genmmio_H
4.23 +#define lxdream_genmmio_H 1
4.24 +
4.25 +#include <stdint.h>
4.26 +#include <glib/glist.h>
4.27 +
4.28 +#ifdef __cplusplus
4.29 +extern "C" {
4.30 +#endif
4.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_BIG
4.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_EXACT
4.61 +} register_access_t;
4.62 +
4.63 +typedef enum {
4.64 + TRACE_DEFAULT,
4.65 + TRACE_NEVER,
4.66 + TRACE_ALWAYS
4.67 +} register_trace_t;
4.68 +
4.69 +typedef enum {
4.70 + TEST_DEFAULT,
4.71 + TEST_OFF,
4.72 + TEST_ON
4.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 __cplusplus
4.127 +}
4.128 +#endif
4.129 +
4.130 +#endif /* !lxdream_genmmio_H */
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/src/tools/mdparse.c Mon Mar 15 22:10:24 2010 +1000
5.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 modify
5.12 + * it under the terms of the GNU General Public License as published by
5.13 + * the Free Software Foundation; either version 2 of the License, or
5.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 of
5.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5.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 memory
5.43 + * | 'access' '=' 'nooffset' // Recognize any size access (zero-ext or trunc) as long as the address is exactly the same
5.44 + * | 'access' '=' 'exact' // Recognize only the exact access type at the exact address
5.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 1
5.62 +#define TOK_INTEGER 2
5.63 +#define TOK_STRING 3
5.64 +#define TOK_ACTION 4
5.65 +#define TOK_EOF 5
5.66 +#define TOK_ERROR 6
5.67 +#define TOK_LPAREN 7
5.68 +#define TOK_RPAREN 8
5.69 +#define TOK_LBRACE 9
5.70 +#define TOK_RBRACE 10
5.71 +#define TOK_COMMA 11
5.72 +#define TOK_COLON 12
5.73 +#define TOK_SEMI 13
5.74 +#define TOK_PERIOD 14
5.75 +#define TOK_RANGE 15
5.76 +#define TOK_LSQUARE 16
5.77 +#define TOK_RSQUARE 17
5.78 +#define TOK_EQUALS 18
5.79 +#define TOK_ACCESS 19
5.80 +#define TOK_AT 20
5.81 +#define TOK_ENDIAN 21
5.82 +#define TOK_FILL 22
5.83 +#define TOK_INCLUDE 23
5.84 +#define TOK_MASK 24
5.85 +#define TOK_REGISTERS 25
5.86 +#define TOK_SPACE 26
5.87 +#define TOK_STRIDE 27
5.88 +#define TOK_TEST 28
5.89 +#define TOK_TRACE 29
5.90 +#define TOK_UNDEFINED 30
5.91 +
5.92 +
5.93 +#define FIRST_KEYWORD TOK_ACCESS
5.94 +#define LAST_KEYWORD TOK_UNDEFINED
5.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(&reg->flags, &reg->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, &reg->initValue, &reg->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 escape
5.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 +}
.