<html>
<body>
  <div id="body" style="background-color:#ffffff;" >
<table cellspacing="0" cellpadding="0" border="0" rules="cols">
<tr class="head" style="border-bottom-width:1px;border-bottom-style:solid;" ><td class="headtd" style="padding:0;padding-top:.2em;" colspan="4">Commit in <b><tt>lxdream/src</tt></b></td></tr>
<tr><td><tt><a href="#file1">Makefile.am</a></tt></td><td id="added" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ddffdd;" align="right">+3</td><td id="removed" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ffdddd;" align="right">-1</td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" nowrap="nowrap">de9ad2c0cf56 -> 700e16c321e5</td></tr>
<tr class="alt" style=";" ><td><tt><a href="#file2">Makefile.in</a></tt></td><td id="addedalt" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ccf7cc;" align="right">+43</td><td id="removed" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ffdddd;" align="right">-5</td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" nowrap="nowrap">de9ad2c0cf56 -> 700e16c321e5</td></tr>
<tr><td><tt>tools/<a href="#file3"><span id="added" style="background-color:#ddffdd;" >genmach.c</span></a></tt></td><td id="added" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ddffdd;" align="right">+372</td><td></td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" align="right" nowrap="nowrap">added 700e16c321e5</td></tr>
<tr class="alt" style=";" ><td><tt>     /<a href="#file4"><span id="addedalt" style="background-color:#ccf7cc;" >genmach.h</span></a></tt></td><td id="addedalt" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ccf7cc;" align="right">+127</td><td></td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" align="right" nowrap="nowrap">added 700e16c321e5</td></tr>
<tr><td><tt>     /<a href="#file5"><span id="added" style="background-color:#ddffdd;" >mdparse.c</span></a></tt></td><td id="added" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ddffdd;" align="right">+721</td><td></td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" align="right" nowrap="nowrap">added 700e16c321e5</td></tr>
<tr><td></td><td id="added" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ddffdd;" align="right">+1266</td><td id="removed" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ffdddd;" align="right">-6</td><td></td></tr>
</table>
<small id="info" style="color: #888888;" >3 added + 2 modified, total 5 files</small><br />
<div class="tasklist" style="padding:4px;border:1px dashed #000000;margin-top:1em;" ><ul>
<li><a href="#task1">FIXME: handle endian mismatches */</a></li>
</ul></div>
<pre class="comment" style="white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;white-space:pre-wrap;word-wrap:break-word;padding:4px;border:1px dashed #000000;background-color:#ffffdd;" >
Commit genmach work-in-progress
</pre>
<hr /><a name="file1" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span class="pathname" style="font-family:monospace; float:right;" >lxdream/src</span><br />
<div class="fileheader" style="margin-bottom:.5em;" ><big><b>Makefile.am</b></big> <small id="info" style="color: #888888;" >de9ad2c0cf56 -> 700e16c321e5</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/Makefile.am
+++ lxdream/src/Makefile.am
@@ -12,7 +12,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > PLUGINCFLAGS = @PLUGINCFLAGS@ 
 PLUGINLDFLAGS = @PLUGINLDFLAGS@
 bin_PROGRAMS = lxdream
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-noinst_PROGRAMS = gendec genglsl
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+noinst_PROGRAMS = gendec genglsl<span id="addedchars" style="background-color:#99ff99;font-weight:bolder;" > genmach</span>
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > check_PROGRAMS = test/testxlt test/testisoread
 
 pkglib_PROGRAMS=
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -36,6 +36,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > #all-am: checkversion
 
 gendec_SOURCES = tools/gendec.c tools/gendec.h tools/insparse.c tools/actparse.c
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+genmach_SOURCES = tools/genmach.c tools/genmach.h tools/mdparse.c
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > genglsl_SOURCES = tools/genglsl.c
 lxdream_LINK = $(LINK) @LXDREAMLDFLAGS@
 lxdream_LDADD = @LXDREAM_LIBS@ @GLIB_LIBS@ @GTK_LIBS@ @LIBPNG_LIBS@ $(INTLLIBS)
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -236,6 +237,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
 gendec_LDADD = @GLIB_LIBS@ @GTK_LIBS@ $(INTLLIBS)
 genglsl_LDADD = @GLIB_LIBS@ @GTK_LIBS@ $(INTLLIBS)
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+genmach_LDADD = @GLIB_LIBS@ @GTK_LIBS@ $(INTLLIBS)
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
 
 test_testxlt_SOURCES = test/testxlt.c xlat/xltcache.c xlat/xltcache.h
</pre></div>
<hr /><a name="file2" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span class="pathname" style="font-family:monospace; float:right;" >lxdream/src</span><br />
<div class="fileheader" style="margin-bottom:.5em;" ><big><b>Makefile.in</b></big> <small id="info" style="color: #888888;" >de9ad2c0cf56 -> 700e16c321e5</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/Makefile.in
+++ lxdream/src/Makefile.in
@@ -37,7 +37,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > build_triplet = @build@
 host_triplet = @host@
 bin_PROGRAMS = lxdream$(EXEEXT)
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-noinst_PROGRAMS = gendec$(EXEEXT) genglsl$(EXEEXT)
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+noinst_PROGRAMS = gendec$(EXEEXT) genglsl$(EXEEXT)<span id="addedchars" style="background-color:#99ff99;font-weight:bolder;" > genmach$(EXEEXT)</span>
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > check_PROGRAMS = test/testxlt$(EXEEXT) test/testisoread$(EXEEXT) \
        $(am__EXEEXT_1)
 pkglib_PROGRAMS = $(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4) \
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -135,6 +135,9 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > am_genglsl_OBJECTS = genglsl.$(OBJEXT)
 genglsl_OBJECTS = $(am_genglsl_OBJECTS)
 genglsl_DEPENDENCIES = $(am__DEPENDENCIES_1)
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+am_genmach_OBJECTS = genmach.$(OBJEXT) mdparse.$(OBJEXT)
+genmach_OBJECTS = $(am_genmach_OBJECTS)
+genmach_DEPENDENCIES = $(am__DEPENDENCIES_1)
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > am_input_lirc_@SOEXT@_OBJECTS =
 input_lirc_@SOEXT@_OBJECTS = $(am_input_lirc_@SOEXT@_OBJECTS)
 @BUILD_SHARED_TRUE@@INPUT_LIRC_TRUE@input_lirc_@SOEXT@_DEPENDENCIES =  \
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -336,16 +339,16 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >      $(LDFLAGS) -o $@
 SOURCES = $(audio_alsa_@SOEXT@_SOURCES) $(audio_esd_@SOEXT@_SOURCES) \
        $(audio_pulse_@SOEXT@_SOURCES) $(audio_sdl_@SOEXT@_SOURCES) \
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-   $(gendec_SOURCES) $(genglsl_SOURCES) \
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+     $(gendec_SOURCES) $(genglsl_SOURCES) <span id="addedchars" style="background-color:#99ff99;font-weight:bolder;" >$(genmach_SOURCES) </span>\
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >    $(input_lirc_@SOEXT@_SOURCES) $(lxdream_SOURCES) \
        $(lxdream_dummy_@SOEXT@_SOURCES) $(test_testisoread_SOURCES) \
        $(test_testsh4x86_SOURCES) $(test_testxlt_SOURCES)
 DIST_SOURCES = $(audio_alsa_@SOEXT@_SOURCES) \
        $(audio_esd_@SOEXT@_SOURCES) $(audio_pulse_@SOEXT@_SOURCES) \
        $(audio_sdl_@SOEXT@_SOURCES) $(gendec_SOURCES) \
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-   $(genglsl_SOURCES) $(input_lirc_@SOEXT@_SOURCES) \
-       $(am__lxdream_SOURCES_DIST) $(lxdream_dummy_@SOEXT@_SOURCES) \
-       $(test_testisoread_SOURCES) \
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+     $(genglsl_SOURCES) $(genmach_SOURCES) \
+       $(input_lirc_@SOEXT@_SOURCES) $(am__lxdream_SOURCES_DIST) \
+       $(lxdream_dummy_@SOEXT@_SOURCES) $(test_testisoread_SOURCES) \
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >    $(am__test_testsh4x86_SOURCES_DIST) $(test_testxlt_SOURCES)
 ETAGS = etags
 CTAGS = ctags
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -555,6 +558,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
 #all-am: checkversion
 gendec_SOURCES = tools/gendec.c tools/gendec.h tools/insparse.c tools/actparse.c
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+genmach_SOURCES = tools/genmach.c tools/genmach.h tools/mdparse.c
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > genglsl_SOURCES = tools/genglsl.c
 lxdream_LINK = $(LINK) @LXDREAMLDFLAGS@
 lxdream_LDADD = @LXDREAM_LIBS@ @GLIB_LIBS@ @GTK_LIBS@ @LIBPNG_LIBS@ \
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -631,6 +635,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > @BUILD_SHARED_TRUE@@INPUT_LIRC_TRUE@input_lirc_@SOEXT@_LDFLAGS = $(PLUGINLDFLAGS)
 gendec_LDADD = @GLIB_LIBS@ @GTK_LIBS@ $(INTLLIBS)
 genglsl_LDADD = @GLIB_LIBS@ @GTK_LIBS@ $(INTLLIBS)
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+genmach_LDADD = @GLIB_LIBS@ @GTK_LIBS@ $(INTLLIBS)
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > test_testxlt_SOURCES = test/testxlt.c xlat/xltcache.c xlat/xltcache.h
 test_testisoread_SOURCES = test/testisoread.c drivers/cdrom/isoread.c \
        drivers/cdrom/isoread.h drivers/cdrom/isofs_impl.h drivers/cdrom/ecc.h \
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -746,6 +751,9 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > genglsl$(EXEEXT): $(genglsl_OBJECTS) $(genglsl_DEPENDENCIES) 
        @rm -f genglsl$(EXEEXT)
        $(LINK) $(genglsl_LDFLAGS) $(genglsl_OBJECTS) $(genglsl_LDADD) $(LIBS)
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+genmach$(EXEEXT): $(genmach_OBJECTS) $(genmach_DEPENDENCIES) 
+       @rm -f genmach$(EXEEXT)
+       $(LINK) $(genmach_LDFLAGS) $(genmach_OBJECTS) $(genmach_LDADD) $(LIBS)
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > input_lirc.@SOEXT@$(EXEEXT): $(input_lirc_@SOEXT@_OBJECTS) $(input_lirc_@SOEXT@_DEPENDENCIES) 
        @rm -f input_lirc.@SOEXT@$(EXEEXT)
        $(LINK) $(input_lirc_@SOEXT@_LDFLAGS) $(input_lirc_@SOEXT@_OBJECTS) $(input_lirc_@SOEXT@_LDADD) $(LIBS)
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -783,6 +791,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edc_ecc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gendec.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genglsl.Po@am__quote@
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genmach.Po@am__quote@
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/insparse.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isoread.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-aica.Po@am__quote@
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -905,6 +914,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-x86dasm.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-xltcache.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-yuv.Po@am__quote@
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mdparse.Po@am__quote@
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sector.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testsh4x86-cpu.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testsh4x86-dis-buf.Po@am__quote@
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -992,6 +1002,34 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > @AMDEP_TRUE@@am__fastdepCC_FALSE@    DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @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`
 
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+genmach.o: tools/genmach.c
+@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; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/genmach.Tpo" "$(DEPDIR)/genmach.Po"; else rm -f "$(DEPDIR)/genmach.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='tools/genmach.c' object='genmach.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@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
+
+genmach.obj: tools/genmach.c
+@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`; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/genmach.Tpo" "$(DEPDIR)/genmach.Po"; else rm -f "$(DEPDIR)/genmach.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='tools/genmach.c' object='genmach.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@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`
+
+mdparse.o: tools/mdparse.c
+@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; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/mdparse.Tpo" "$(DEPDIR)/mdparse.Po"; else rm -f "$(DEPDIR)/mdparse.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='tools/mdparse.c' object='mdparse.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@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
+
+mdparse.obj: tools/mdparse.c
+@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`; \
+@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/mdparse.Tpo" "$(DEPDIR)/mdparse.Po"; else rm -f "$(DEPDIR)/mdparse.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='tools/mdparse.c' object='mdparse.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@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`
+
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > lxdream-main.o: main.c
 @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; \
 @am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/lxdream-main.Tpo" "$(DEPDIR)/lxdream-main.Po"; else rm -f "$(DEPDIR)/lxdream-main.Tpo"; exit 1; fi
</pre></div>
<hr /><a name="file3" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span id="added" class="pathname" style="font-family:monospace; float:right; background-color:#ddffdd;" >lxdream/src/tools</span><br />
<div id="added" class="fileheader" style="margin-bottom:.5em; background-color:#ddffdd;" ><big><b>genmach.c</b></big> <small id="info" style="color: #888888;" >added at 700e16c321e5</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/tools/genmach.c
+++ lxdream/src/tools/genmach.c
@@ -0,0 +1,372 @@
</small></pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+/**
+ * $Id$
+ *
+ * mmio register code generator
+ *
+ * Copyright (c) 2010 Nathan Keynes.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <errno.h>
+#include <glib/gstrfuncs.h>
+#include <glib/glist.h>
+#include "gettext.h"
+#include "genmach.h"
+
+#define LXDREAM_PAGE_SIZE 4096
+
+const char *short_options = "cd:ho:v";
+struct option long_options[] = {
+        { "output", required_argument, NULL, 'o' },
+        { "header", required_argument, NULL, 'd' },
+        { "check-only", no_argument, NULL, 'c' },
+        { "help", no_argument, NULL, 'h' },
+        { "verbose", no_argument, NULL, 'v' },
+        { NULL, 0, 0, 0 } };
+
+static void print_version()
+{
+    printf( "genmmio 0.1\n" );
+}
+
+static void print_usage()
+{
+    print_version();
+    printf( "Usage: genmmio [options] <input-register-files>\n" );
+    printf( "Options:\n" );
+    printf( "   -c, --check-only       %s\n", _("Check specification files but don't write any output") );
+    printf( "   -d, --header=FILE      %s\n", _("Specify header output file [corresponding .h for .c file]") );
+    printf( "   -h, --help             %s\n", _("Display this usage information") );
+    printf( "   -o, --output=FILE      %s\n", _("Specify main output file [corresponding .c for input file]") );
+    printf( "   -v, --verbose          %s\n", _("Print verbose output") );
+}
+
+/**
+ * Given an input baseName of the form "path/file.blah", return
+ * a newly allocated string "file<ext>" where <ext> is the second
+ * parameter.
+ *
+ * @param baseName a non-null filename
+ * @param ext a file extension including leading '.'
+ */
+char *makeFilename( const char *baseName, const char *ext )
+{
+    const char *p = strrchr(baseName, '/');
+    if( p == NULL )
+        p = baseName;
+    const char *q = strchr(p, '.');
+    if( q == NULL ) {
+        return g_strdup_printf("%s%s", p, ext);
+    } else {
+        return g_strdup_printf("%.*s%s", q-p, p, ext );
+    }
+}
+
+/**
+ * Process all registers after parsing is complete. This does a few things:
+ *   1. Ensures that there are no overlapping registers, so that every operation
+ *      is well-defined.
+ *   2. Replaces transitive mirror groups with a set of equivalent direct
+ *      mirrors so that later processing doesn't need to check for this case.
+ *      This also checks for cycles in the graph.
+ *   3. Organises the memory map(s) into page-size quantities (combining and
+ *      splitting groups where necessary).
+ */
+GList *postprocess_registers( GList *blocks )
+{
+    for( GList *ptr = blocks; ptr != NULL; ptr = ptr->next ) {
+        regblock_t block = (regblock_t)ptr->data;
+        for( unsigned i=0; i<block->numRegs; i++ ) {
+            regdef_t reg = block->regs[i];
+            if( reg->mode == REG_MIRROR ) {
+            }
+        }
+    }
+    return blocks;
+}
+
+/**
+ * Check register definition semantics. Primarily this verifies that there
+ * are no overlapping definitions.
+ * @return number of errors found.
+ */
+int check_registers( GList *registers )
+{
+    return 0;
+}
+
+/**
+ * Dump the high-level register map to the given file.
+ */
+void dump_register_blocks( FILE *f, GList *blocks, gboolean detail )
+{
+    const char *mode_names[] = { "--", "RW", "RO", "RW" };
+    for( GList *ptr = blocks; ptr != NULL; ptr=ptr->next ) {
+        regblock_t block = (regblock_t)ptr->data;
+        fprintf( f, "%08X: %s - %s\n", block->address,
+                 block->name,
+                 (block->description == NULL ? "<no description>" : block->description) );
+        if( detail ) {
+            for( unsigned i=0; i<block->numRegs; i++ ) {
+                regdef_t reg = block->regs[i];
+                fprintf( f, "    %04X: %s %s", reg->offset,
+                        mode_names[reg->mode],
+                        reg->name == NULL ? "<anon>" : reg->name );
+                if( reg->numElements > 1 ) {
+                    fprintf( f, "[%d]", reg->numElements );
+                }
+                fprintf( f, " - %s\n",
+                         (reg->description == NULL ? "<no description>" : reg->description) );
+            }
+        }
+    }
+}
+
+char *build_page_initializer( regblock_t block )
+{
+    char *page = g_malloc(LXDREAM_PAGE_SIZE);
+
+    /* First, background fill if any */
+    if( block->flags.fillSizeBytes == 0 ) {
+        memset(page, 0, LXDREAM_PAGE_SIZE);
+    } else {
+        for( unsigned i=0; i<LXDREAM_PAGE_SIZE; i++ ) {
+            page[i] = block->flags.fillValue.a[i%block->flags.fillSizeBytes];
+        }
+    }
+
+    /* Next, set register initializer (except for wo + mirror regs) */
+    for( unsigned i=0; i<block->numRegs; i++ ) {
+        regdef_t reg = block->regs[i];
+        if( reg->mode != REG_WO && reg->mode != REG_MIRROR ) {
+            unsigned offset = reg->offset;
+            for( unsigned j=0; j<reg->numElements; j++ ) {
+                if( reg->type == REG_STRING ) {
+                    memcpy( &page[offset], reg->initValue.s, reg->numBytes );
+                } else {
+                    memcpy( &page[offset], reg->initValue.a, reg->numBytes );
+                }
+                offset += reg->numBytes;
+            }
+        }
+    }
+
+    /* Finally clone mirror groups */
+    for( unsigned i=0; i<block->numRegs; i++ ) {
+        regdef_t reg = block->regs[i];
+        if( reg->mode == REG_MIRROR ) {
+            unsigned offset = reg->offset;
+            unsigned target = reg->initValue.i;
+            for( unsigned i=0; i<reg->numElements; i++ ) {
+                memcpy( &page[offset], &page[target], reg->numBytes );
+                offset += reg->stride;
+            }
+        }
+    }
+
+    return page;
+}
+
+
+void fwrite_dump( unsigned char *data, unsigned int length, FILE *f )
+{
+    unsigned int i, j;
+    int skipped = 0;
+    for( i =0; i<length; i+=16 ) {
+        if( i >= 16 && i < length-16 && memcmp( &data[i], &data[i-16], 16) == 0 ) {
+            skipped++;
+            continue;
+        }
+        if( skipped ) {
+            fprintf( f, "   **    \n" );
+            skipped = 0;
+        }
+        fprintf( f, "%08X:", i);
+        for( j=i; j<i+16; j++ ) {
+            if( j != i && (j % 4) == 0 )
+                fprintf( f, " " );
+            if( j < length )
+                fprintf( f, " %02X", (unsigned int)(data[j]) );
+            else
+                fprintf( f, "   " );
+        }
+        fprintf( f, "  " );
+        for( j=i; j<i+16 && j<length; j++ ) {
+            fprintf( f, "%c", isprint(data[j]) ? data[j] : '.' );
+        }
+        fprintf( f, "\n" );
+    }
+}
+
+static const char *file_top = "/**\n"
+        " * This file was automatically generated by genmmio, do not edit\n"
+        " */\n";
+
+void write_source( FILE *f, GList *blocks, const char *header_filename )
+{
+    fputs( file_top, f );
+    fprintf( f, "\n#include \"%s\"\n\n", header_filename );
+
+    for( GList *ptr = blocks; ptr != NULL; ptr = ptr->next ) {
+        regblock_t block = (regblock_t)ptr->data;
+        /* Generate the mmio region struct */
+        fprintf( f, "void FASTCALL mmio_region_%s_write(uint32_t, uint32_t);\n", block->name );
+        fprintf( f, "void FASTCALL mmio_region_%s_write_word(uint32_t, uint32_t);\n", block->name );
+        fprintf( f, "void FASTCALL mmio_region_%s_write_byte(uint32_t, uint32_t);\n", block->name );
+        fprintf( f, "void FASTCALL mmio_region_%s_write_burst(uint32_t, unsigned char *);\n", block->name );
+        fprintf( f, "int32_t FASTCALL mmio_region_%s_read(uint32_t);\n", block->name );
+        fprintf( f, "int32_t FASTCALL mmio_region_%s_read_word(uint32_t);\n", block->name );
+        fprintf( f, "int32_t FASTCALL mmio_region_%s_read_byte(uint32_t);\n", block->name );
+        fprintf( f, "void FASTCALL mmio_region_%s_read_burst(unsigned char *, uint32_t);\n", block->name );
+        fprintf( f, "struct mmio_region mmio_region_%s = {\n", block->name );
+        fprintf( f, "    \"%s\", \"%s\", %08x, {\n", block->name,
+                block->description == NULL ? block->name : block->description,
+                block->address );
+        fprintf( f, "        mmio_region_%s_read, mmio_region_%s_write,\n", block->name, block->name );
+        fprintf( f, "        mmio_region_%s_read_word, mmio_region_%s_write_word,\n", block->name, block->name );
+        fprintf( f, "        mmio_region_%s_read_byte, mmio_region_%s_write_byte,\n", block->name, block->name );
+        fprintf( f, "        mmio_region_%s_read_burst, mmio_region_%s_write_burst,\n", block->name, block->name );
+        fprintf( f, "        unmapped_prefetch, mmio_region_%s_read_byte },\n", block->name, block->name );
+        fprintf( f, "    NULL, NULL, {\n" );
+        for( unsigned i=0; i<block->numRegs; i++ ) {
+            regdef_t reg = block->regs[i];
+            if( reg->mode != REG_CONST ) {
+                char tmp[32];
+                const char *regname = reg->name;
+                if( regname == NULL ) {
+                    regname = tmp;
+                    snprintf( tmp, sizeof(tmp), "%s_%03X", block->name, reg->offset );
+                }
+
+                fprintf( f, "        { \"%s\", \"%s\", %d, 0x%03x, 0x%08x, %s },\n", regname,
+                         reg->description == NULL ? regname : reg->description,
+                                 reg->numBytes*8, reg->offset, (unsigned)reg->initValue.i,
+                                 (reg->mode == REG_RW ? "PORT_MRW" : (reg->mode == REG_WO ? "PORT_W" : "PORT_R")) );
+            }
+        }
+        fprintf( f, "    }, NULL };\n" );
+    }
+
+}
+
+void write_header( FILE *f, GList *blocks )
+{
+    fputs( file_top, f );
+
+    fputs( "\n#include \"mmio.h\"\n\n", f );
+
+    for( GList *ptr = blocks; ptr != NULL; ptr = ptr->next ) {
+        regblock_t block = (regblock_t)ptr->data;
+        fprintf( f, "extern struct mmio_region mmio_region_%s;\n", block->name );
+        fprintf( f, "enum mmio_region_%s_port_t {\n", block->name );
+        for( unsigned i=0; i<block->numRegs; i++ ) {
+            regdef_t reg = block->regs[i];
+            if( reg->name != NULL ) {
+                fprintf( f, "    %s = 0x%03x,\n", reg->name, reg->offset );
+            }
+        }
+        fprintf( f, "};\n" );
+    }
+}
+
+void write_test( FILE *f, GList *blocks )
+{
+
+
+}
+
+int main(int argc, char *argv[])
+{
+    const char *header = NULL;
+    const char *output = NULL;
+    gboolean check_only = FALSE;
+    int verbose = 0, opt;
+    GList *block_list = NULL;
+
+    while( (opt = getopt_long( argc, argv, short_options, long_options, NULL )) != -1 ) {
+        switch(opt) {
+        case 'c':
+            check_only = TRUE;
+            break;
+        case 'd':
+            header = optarg;
+            break;
+        case 'h':
+            print_usage();
+            exit(0);
+        case 'o':
+            output = optarg;
+            break;
+        case 'v':
+            verbose++;
+            break;
+        }
+    }
+
+    if( optind == argc ) {
+        print_usage();
+        exit(1);
+    }
+
+    if( output == NULL ) {
+        output = makeFilename(argv[optind],".c");
+    }
+    if( header == NULL ) {
+        header = makeFilename(argv[optind],".h");
+    }
+
+    for( ; optind < argc; optind++ ) {
+        block_list = ioparse(argv[optind], block_list);
+    }
+
+    if( verbose ) {
+        dump_register_blocks(stdout, block_list, verbose>1);
+    }
+
+    int errors = check_registers(block_list);
+    if( errors != 0 ) {
+        fprintf( stderr, "Aborting due to validation errors\n" );
+        return 2;
+    }
+
+    if( !check_only ) {
+        FILE *f = fopen( output, "wo" );
+        if( f == NULL ) {
+            fprintf( stderr, "Unable to open output file '%s': %s\n", output, strerror(errno) );
+            return 3;
+        }
+        write_source( f, block_list, header );
+        fclose(f);
+
+        f = fopen( header, "wo" );
+        if( f == NULL ) {
+            fprintf( stderr, "Unable to open header file '%s': %s\n", header, strerror(errno) );
+            return 4;
+        }
+        write_header( f, block_list );
+        fclose(f);
+    }
+
+    for( GList *ptr = block_list; ptr != NULL; ptr = ptr->next ) {
+        char *data = build_page_initializer((regblock_t)ptr->data);
+        fwrite_dump( data, LXDREAM_PAGE_SIZE, stdout );
+        g_free(data);
+    }
+    return 0;
+}
+
</pre></div>
<hr /><a name="file4" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span id="added" class="pathname" style="font-family:monospace; float:right; background-color:#ddffdd;" >lxdream/src/tools</span><br />
<div id="added" class="fileheader" style="margin-bottom:.5em; background-color:#ddffdd;" ><big><b>genmach.h</b></big> <small id="info" style="color: #888888;" >added at 700e16c321e5</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/tools/genmach.h
+++ lxdream/src/tools/genmach.h
@@ -0,0 +1,127 @@
</small></pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+/**
+ * $Id$
+ *
+ * mmio register code generator
+ *
+ * Copyright (c) 2010 Nathan Keynes.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef lxdream_genmmio_H
+#define lxdream_genmmio_H 1
+
+#include <stdint.h>
+#include <glib/glist.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    REG_CONST,
+    REG_RW,
+    REG_RO,
+    REG_WO,
+    REG_MIRROR, /* Additional address for an existing register - value is the offset of the target reg */
+} register_mode_t;
+
+typedef enum {
+    REG_I8,
+    REG_I16,
+    REG_I32,
+    REG_I64,
+    REG_F32,
+    REG_F64,
+    REG_STRING,
+} register_type_t;
+
+typedef enum {
+    ENDIAN_DEFAULT,
+    ENDIAN_LITTLE,
+    ENDIAN_BIG
+} register_endian_t;
+
+typedef enum {
+    ACCESS_DEFAULT,
+    ACCESS_ANY,
+    ACCESS_NOOFFSET,
+    ACCESS_EXACT
+} register_access_t;
+
+typedef enum {
+    TRACE_DEFAULT,
+    TRACE_NEVER,
+    TRACE_ALWAYS
+} register_trace_t;
+
+typedef enum {
+    TEST_DEFAULT,
+    TEST_OFF,
+    TEST_ON
+} register_test_t;
+
+union apval {
+    uint64_t i;
+    char a[8];
+    const char *s;
+};
+
+struct action {
+    const char *filename;
+    int lineno;
+    const char *text;
+};
+
+typedef struct regflags {
+    register_endian_t endian;
+    register_access_t access;
+    register_trace_t traceFlag;
+    register_test_t testFlag;
+    union apval maskValue;
+    unsigned int fillSizeBytes;
+    union apval fillValue;
+} *regflags_t;
+
+typedef struct regdef {
+    const char *name;
+    const char *description;
+    uint32_t offset;
+    unsigned numBytes;
+    unsigned numElements;
+    unsigned stride;
+    register_mode_t mode;
+    register_type_t type;
+    gboolean initUndefined;
+    union apval initValue;
+    struct regflags flags;
+    struct action *action;
+} *regdef_t;
+
+typedef struct regblock {
+    const char *name;
+    const char *description;
+    uint32_t address;
+    struct regflags flags;
+    unsigned numRegs;
+    unsigned blockSize;
+    regdef_t regs[];
+} *regblock_t;
+
+
+
+GList *ioparse( const char *filename, GList *list );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !lxdream_genmmio_H */
</pre></div>
<hr /><a name="file5" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span id="added" class="pathname" style="font-family:monospace; float:right; background-color:#ddffdd;" >lxdream/src/tools</span><br />
<div id="added" class="fileheader" style="margin-bottom:.5em; background-color:#ddffdd;" ><big><b>mdparse.c</b></big> <small id="info" style="color: #888888;" >added at 700e16c321e5</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/tools/mdparse.c
+++ lxdream/src/tools/mdparse.c
@@ -0,0 +1,721 @@
</small></pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+/**
+ * $Id$
+ *
+ * genmmio I/O register definition parser.
+ *
+ * Copyright (c) 2010 Nathan Keynes.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <glib/gmem.h>
+
+#include "genmach.h"
+/*
+ * Grammar:
+ *
+ * start: start register_block |  ;
+ * register_block: 'registers' IDENTIFIER 'at' INTEGER opt_paramlist '{' register_list '}';
+ * opt_paramlist: '(' param_list ')' | '(' ')' |  ;
+ * param_list: param_list ',' param | param ;
+ * param: access_param | fill_param | endian_param | mask_param ;
+ * access_param: 'access' '=' 'any'  // Behaves as if it were memory
+ *        | 'access' '=' 'nooffset' // Recognize any size access (zero-ext or trunc) as long as the address is exactly the same
+ *        | 'access' '=' 'exact'    // Recognize only the exact access type at the exact address
+ *        ;
+ * fill_param: 'fill' '=' literal;
+ * endian_param: 'endian' '=' 'little'
+ *        | 'endian' '=' 'big'
+ *        ;
+ * mask_param: 'mask' '=' literal;
+ *
+ * register_list: register_list register_desc | ;
+ * register_desc: INTEGER ':' mode_spec type_spec IDENTIFIER opt_paramlist [ '=' literal ] [ ACTION ]
+ * mode_spec: 'const' | 'rw' | 'ro' | 'wo';
+ * type_spec: 'i8' | 'i16' | 'i32' | 'i64' | 'f32' | 'f64' | 'string' | 'cstring';
+ * literal: INTEGER | STRING | 'undefined' ;
+ *
+ * C-style comments are recognized as such.
+ */
+
+#define TOK_IDENTIFIER 1
+#define TOK_INTEGER    2
+#define TOK_STRING     3
+#define TOK_ACTION     4
+#define TOK_EOF        5
+#define TOK_ERROR      6
+#define TOK_LPAREN     7
+#define TOK_RPAREN     8
+#define TOK_LBRACE     9
+#define TOK_RBRACE    10
+#define TOK_COMMA     11
+#define TOK_COLON     12
+#define TOK_SEMI      13
+#define TOK_PERIOD    14
+#define TOK_RANGE     15
+#define TOK_LSQUARE   16
+#define TOK_RSQUARE   17
+#define TOK_EQUALS    18
+#define TOK_ACCESS    19
+#define TOK_AT        20
+#define TOK_ENDIAN    21
+#define TOK_FILL      22
+#define TOK_INCLUDE   23
+#define TOK_MASK      24
+#define TOK_REGISTERS 25
+#define TOK_SPACE     26
+#define TOK_STRIDE    27
+#define TOK_TEST      28
+#define TOK_TRACE     29
+#define TOK_UNDEFINED 30
+
+
+#define FIRST_KEYWORD TOK_ACCESS
+#define LAST_KEYWORD  TOK_UNDEFINED
+static const char *TOKEN_NAMES[] = {"NULL", "IDENTIFIER", "INTEGER", "STRING", "ACTION", "EOF", "ERROR",
+        "(", ")", "{", "}", ",", ":", ";", ".", "..", "[", "]", "=",
+        "ACCESS", "AT", "ENDIAN", "FILL", "INCLUDE", "MASK", "REGISTERS", "SPACE", "STRIDE", "TEST", "TRACE", "UNDEFINED" };
+static const char *MODE_NAMES[] = {"const", "rw", "ro", "wo", "mirror"};
+static const char *TYPE_NAMES[] = {"i8", "i16", "i32", "i64", "f32", "f64", "string"};
+static int TYPE_SIZES[] = {1,2,4,8,4,8,0};
+static const char *ENDIAN_NAMES[] = {"default", "little", "big"};
+static const char *ACCESS_NAMES[] = {"default", "any", "nooffset", "exact"};
+static const char *TRACE_NAMES[] = {"default", "off", "on"};
+
+#define elementsof(x) (sizeof(x)/sizeof(x[0]))
+
+typedef struct token_data {
+    char *yytext;
+    int yylength;
+    int yyline;
+    int yycol;
+    union {
+        long i;
+        char *s;
+    } v;
+    int slen;
+} token_data;
+
+static char *yybuffer;
+static char *yyposn, *yylineposn;
+static char *yyend;
+static int yyline;
+static struct token_data yytok;
+
+#define YYPARSE_ERROR( msg, ... ) \
+    do { \
+        fprintf( stderr, "Parse error at %d:%d: " msg "\n", yytok.yyline, yytok.yycol, __VA_ARGS__ ); \
+        exit(2); \
+    } while(0)
+
+#define READ(x) \
+{   int _tok = iolex(x); \
+    if( _tok != (x) ) { \
+        YYPARSE_ERROR( "Expected %s but got %s", TOKEN_NAMES[x], TOKEN_NAMES[_tok] ); \
+    } \
+}
+
+static int iolex( int expectToken );
+static int iolex_open( const char *filename );
+static void iolex_close();
+
+static inline char *yystrdup()
+{
+    char *str = g_malloc0(yytok.yylength+1);
+    memcpy( str, yytok.yytext, yytok.yylength);
+    return str;
+}
+
+static inline int yystrcasecmp(const char *cmp)
+{
+    int len = strlen(cmp);
+    if( len != yytok.yylength ) {
+        return yytok.yylength - len;
+    }
+    return strncasecmp(yytok.yytext, cmp, yytok.yylength);
+}
+
+static int yymatch( const char *arr[], unsigned numOptions )
+{
+    for( unsigned i=0; i<numOptions; i++ ) {
+        if( yystrcasecmp( arr[i] ) == 0 ) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+static gint register_block_sort_cb( gconstpointer a, gconstpointer b )
+{
+    struct regblock *blocka = (struct regblock *)a;
+    struct regblock *blockb = (struct regblock *)b;
+    return blocka->address - blockb->address;
+}
+
+static int register_ptr_sort_cb( const void *a, const void *b )
+{
+    regdef_t *ptra = (regdef_t *)a;
+    regdef_t *ptrb = (regdef_t *)b;
+    if( (*ptra)->offset != (*ptrb)->offset )
+        return (*ptra)->offset - (*ptrb)->offset;
+    return (*ptra)->type - (*ptrb)->type;
+}
+
+static void ioparse_apval(int tok, union apval *apv, unsigned *numBytes)
+{
+    if( tok == TOK_INTEGER ) {
+        apv->i = yytok.v.i;
+        if( *numBytes == 0 ) {
+            YYPARSE_ERROR( "Expected string initializer but was an integer (0x%x)", yytok.v.i );
+        }
+    } else if( tok = TOK_STRING ) {
+        if( *numBytes == 0 ) {
+            *numBytes = yytok.slen;
+            apv->s = yytok.v.s;
+        } else {
+            if( *numBytes != yytok.slen ) {
+                YYPARSE_ERROR( "Expected %d byte initializer but was %d", *numBytes, yytok.slen );
+            }
+            assert( *numBytes < sizeof(uint64_t) );
+            apv->i = 0;
<a name="task1" />+            /* <span class="task" style="background-color:#ffff00;" >FIXME</span>: handle endian mismatches */
+            memcpy( &apv->i, yytok.v.s, yytok.slen );
+        }
+    } else {
+        YYPARSE_ERROR( "Expected literal (integer or string), but got %s", TOKEN_NAMES[tok] );
+    }
+}
+
+static void ioparse_regflags( regflags_t flags, unsigned *numBytes )
+{
+    do {
+        int tok = iolex(TOK_RPAREN);
+        switch(tok) {
+        case TOK_FILL:
+            READ(TOK_EQUALS);
+            tok = iolex(TOK_INTEGER);
+            flags->fillSizeBytes = 4;
+            ioparse_apval( tok, &flags->fillValue, &flags->fillSizeBytes );
+            break;
+        case TOK_ACCESS:
+            READ(TOK_EQUALS);
+            READ(TOK_IDENTIFIER);
+            flags->access = yymatch(ACCESS_NAMES,elementsof(ACCESS_NAMES));
+            if( flags->access == -1 ) {
+                YYPARSE_ERROR("Unknown access mode '%s'", yystrdup());
+            }
+            break;
+        case TOK_MASK:
+            if( numBytes ) {
+                READ(TOK_EQUALS);
+                tok = iolex(TOK_INTEGER);
+                ioparse_apval( tok, &flags->maskValue, numBytes );
+            } else {
+                YYPARSE_ERROR("mask is not valid on a register block",0);
+            }
+            break;
+        case TOK_ENDIAN:
+            READ(TOK_EQUALS);
+            READ(TOK_IDENTIFIER);
+            flags->endian = yymatch(ENDIAN_NAMES,elementsof(ENDIAN_NAMES));
+            if( flags->endian == -1 ) {
+                YYPARSE_ERROR("Unknown endianness '%s'", yystrdup());
+            }
+            break;
+        case TOK_TRACE:
+            READ(TOK_EQUALS);
+            READ(TOK_IDENTIFIER);
+            flags->traceFlag = yymatch(TRACE_NAMES,elementsof(TRACE_NAMES));
+            if( flags->traceFlag == -1 ) {
+                YYPARSE_ERROR("Unknown trace flag '%s'", yystrdup());
+            }
+            break;
+        case TOK_TEST:
+            READ(TOK_EQUALS);
+            READ(TOK_IDENTIFIER);
+            flags->testFlag = yymatch(TRACE_NAMES,elementsof(TRACE_NAMES));
+            if( flags->testFlag == -1 ) {
+                YYPARSE_ERROR("Unknown test flag '%s'", yystrdup());
+            }
+            break;
+        case TOK_COMMA:
+            break;
+        case TOK_RPAREN:
+            return;
+        default:
+            YYPARSE_ERROR("Expected flag or ')' but was %s", TOKEN_NAMES[tok]);
+        }
+    } while(1);
+}
+
+static void ioparse_regdef( struct regdef *reg )
+{
+    reg->offset = yytok.v.i;
+    reg->numElements = 1;
+    reg->numBytes = 0;
+    reg->initValue.i = 0;
+    reg->flags.maskValue.i = -1;
+    unsigned rangeOffset = reg->offset;
+
+    int tok = iolex(TOK_COLON);
+    if( tok == TOK_RANGE ) {
+        READ(TOK_INTEGER);
+        rangeOffset = yytok.v.i;
+        if( rangeOffset < reg->offset ) {
+            YYPARSE_ERROR( "Range end (0x%x) must be greater than the range start (0x%x)", rangeOffset, reg->offset );
+        }
+        READ(TOK_COLON);
+    } else if( tok != TOK_COLON ) {
+        YYPARSE_ERROR( "Expected ':' but was %s\n", TOKEN_NAMES[tok] );
+    }
+    READ(TOK_IDENTIFIER);
+    reg->mode = yymatch(MODE_NAMES, elementsof(MODE_NAMES));
+    if( reg->mode == -1 ) {
+        YYPARSE_ERROR( "Unknown register mode '%s'", yystrdup() );
+    }
+    if( reg->mode == REG_MIRROR ) {
+        /* Mirror regions have a target range only */
+        READ(TOK_INTEGER);
+        reg->initValue.i = yytok.v.i;
+        reg->type = REG_I8;
+        tok = iolex(TOK_RANGE);
+        if( tok == TOK_RANGE ) {
+            READ(TOK_INTEGER);
+            if( yytok.v.i < reg->initValue.i ) {
+                YYPARSE_ERROR( "Invalid mirror target range 0x%x..0x%x", reg->initValue.i, yytok.v.i );
+            }
+            reg->numBytes = yytok.v.i - reg->initValue.i + 1;
+            tok = iolex(TOK_STRIDE);
+        }
+        if( tok == TOK_STRIDE ) {
+            READ(TOK_INTEGER);
+            reg->stride = yytok.v.i;
+            tok = iolex(TOK_ACTION);
+        } else {
+            reg->stride = reg->numBytes;
+        }
+
+        if( tok != TOK_SEMI ) {
+            YYPARSE_ERROR( "Expected ; but gut %s", TOKEN_NAMES[tok] );
+        }
+
+        if( reg->stride < reg->numBytes ) {
+            YYPARSE_ERROR( "Invalid mirror stride: %x is less than block size %x\n", reg->stride, reg->numBytes );
+        }
+
+        if( rangeOffset != reg->offset ) {
+            reg->numElements *= ((rangeOffset - reg->offset) + reg->stride - 1) / reg->stride;
+        }
+
+    } else {
+        READ(TOK_IDENTIFIER);
+        reg->type = yymatch(TYPE_NAMES, elementsof(TYPE_NAMES));
+        if( reg->type == -1 ) {
+            YYPARSE_ERROR( "Unknown register type '%s'", yystrdup() );
+        }
+        reg->numBytes = TYPE_SIZES[reg->type];
+        tok = iolex(TOK_IDENTIFIER);
+        if( tok == TOK_IDENTIFIER ) {
+            reg->name = yystrdup();
+            tok = iolex(TOK_ACTION);
+        }
+        if( tok == TOK_STRING ) {
+            reg->description = yytok.v.s;
+            tok = iolex(TOK_ACTION);
+        }
+        if( tok == TOK_LPAREN ) {
+            ioparse_regflags(&reg->flags, &reg->numBytes);
+            tok = iolex(TOK_ACTION);
+        }
+        if( tok == TOK_EQUALS ) {
+            tok = iolex(TOK_INTEGER);
+            if( tok == TOK_UNDEFINED ) {
+                reg->initValue.i = 0xDEADBEEFDEADBEEF;
+                reg->initUndefined = TRUE;
+            } else {
+                ioparse_apval(tok, &reg->initValue, &reg->numBytes);
+            }
+            tok = iolex(TOK_ACTION);
+        } else if( reg->type == REG_STRING ) {
+            YYPARSE_ERROR( "String declarations must have an initializer (ie = 'abcd')",0 );
+        }
+        if( tok == TOK_ACTION ) {
+            // reg->action = yystrdup();
+        } else if( tok != TOK_SEMI ) {
+            YYPARSE_ERROR( "Expected ; or {, but got %s", TOKEN_NAMES[tok] );
+        }
+
+        if( rangeOffset != reg->offset ) {
+            reg->numElements *= ((rangeOffset - reg->offset) + reg->numBytes - 1) / reg->numBytes;
+        }
+    }
+
+}
+
+static struct regblock *ioparse_regblock( )
+{
+    unsigned regsAllocSize = 128;
+    struct regblock *block = g_malloc0(sizeof(struct regblock) + sizeof(regdef_t)*regsAllocSize);
+    block->numRegs = 0;
+
+    READ(TOK_IDENTIFIER);
+    block->name = yystrdup();
+    int tok = iolex(TOK_AT);
+    if( tok == TOK_STRING ) {
+        block->description = yytok.v.s;
+        tok = iolex(TOK_AT);
+    }
+    if( tok != TOK_AT ) {
+        YYPARSE_ERROR("Expected AT but got %s\n", TOKEN_NAMES[tok] );
+    }
+    READ(TOK_INTEGER);
+    block->address = yytok.v.i;
+
+    tok = iolex(TOK_LBRACE);
+    if( tok == TOK_LPAREN) {
+        ioparse_regflags(&block->flags, NULL);
+        READ(TOK_LBRACE);
+    } else if( tok != TOK_LBRACE ) {
+        YYPARSE_ERROR("Expected { but got %s\n", TOKEN_NAMES[tok] );
+    }
+
+    tok = iolex(TOK_INTEGER);
+    while( tok != TOK_RBRACE ) {
+        if( tok != TOK_INTEGER ) {
+            YYPARSE_ERROR("Expected INTEGER or } but got %s\n", TOKEN_NAMES[tok]);
+        }
+        struct regdef *regdef = g_malloc0(sizeof(struct regdef));
+        if( block->numRegs >= regsAllocSize ) {
+            regsAllocSize *= 2;
+            block = g_realloc(block, sizeof(struct regblock) + sizeof(regdef_t)*regsAllocSize);
+        }
+        block->regs[block->numRegs++] = regdef;
+        ioparse_regdef(regdef);
+
+        tok = iolex(TOK_INTEGER);
+    }
+
+    qsort( &block->regs[0], block->numRegs, sizeof(block->regs[0]), register_ptr_sort_cb );
+
+    return block;
+}
+
+GList *ioparse( const char *filename, GList *list )
+{
+    GList *blocks = list;
+    int count = 0;
+
+    if( iolex_open(filename) != 0  )
+        return blocks;
+
+    int tok;
+    do {
+        tok = iolex(TOK_REGISTERS);
+        if( tok == TOK_EOF ) {
+            return blocks;
+        } else if( tok == TOK_INCLUDE) {
+            READ(TOK_STRING);
+
+        } else if( tok == TOK_SPACE ) {
+        } else if( tok == TOK_REGISTERS ) {
+            struct regblock *block = ioparse_regblock(block);
+            count++;
+            blocks = g_list_insert_sorted(blocks, block, register_block_sort_cb);
+        } else {
+            YYPARSE_ERROR("Expected REGISTERS but got %s\n", TOKEN_NAMES[tok] );
+        }
+    } while( tok != TOK_EOF );
+
+    iolex_close();
+    if( count == 0 ) {
+        fprintf( stderr, "Warning: input file '%s' did not contain any register definitions\n" );
+    }
+
+    return blocks;
+}
+
+/**************************** Lexical analyser ***************************/
+
+static int iolex_open( const char *filename )
+{
+    struct stat st;
+    int fd = open( filename, O_RDONLY );
+    if( fd == -1 ) {
+        fprintf( stderr, "Error opening file '%s': %s\n", filename, strerror(errno) );
+        return -1;
+    }
+
+    if( fstat( fd, &st ) != 0 ) {
+        fprintf( stderr, "Error statting file '%s': %s\n", filename, strerror(errno) );
+        close(fd);
+        return -1;
+    }
+
+    char *data = g_malloc( st.st_size + 1 );
+    if( read(fd, data, st.st_size) != st.st_size ) {
+        fprintf( stderr, "Error reading file '%s': %s\n", filename, strerror(errno) );
+        close(fd);
+        return -1;
+    }
+    close(fd);
+    data[st.st_size] = 0;
+
+    yybuffer = yyposn = data;
+    yyend = data + st.st_size;
+    yyline = 1;
+    yylineposn = yyposn;
+    return 0;
+}
+
+static void iolex_close()
+{
+    g_free(yybuffer);
+    yybuffer = yyend = NULL;
+}
+
+#define YYRETURN(x) do{ \
+    yytok.yylength = yyposn - yystart; \
+    return (x); \
+} while(0)
+
+static int iolex_readhex(char *p, int digits)
+{
+    int result = 0;
+    for( int i=0; i < digits; i++ ) {
+        result <<= 4;
+        if( isdigit(p[i]) ) {
+            result += p[i]-'0';
+        } else if( p[i] >= 'a' && p[i] <= 'f' ) {
+            result += p[i]-'a'+10;
+        } else if( p[i] >= 'A' && p[i] <= 'F' ) {
+            result += p[i]-'A'+10;
+        } else {
+            return (result >> 4);
+        }
+
+    }
+    return result;
+}
+
+static int iolex_readoctal(char *p, int digits)
+{
+    int result = 0;
+    for( int i=0; i < digits; i++ ) {
+        result <<= 3;
+        if( p[i] >= '0' && p[i] <= '7' ) {
+            result += p[i]-'0';
+        } else {
+            return (result >> 4);
+        }
+    }
+    return result;
+}
+
+/**
+ * Copy and interpret the string segment as a C string, replacing escape
+ * expressions with the corresponding value.
+ */
+static char *iolex_getcstring( char *start, char *end, int *len )
+{
+   char *result = g_malloc0(end-start+1); /* Allocate enough memory for the string as-is */
+   char *q = result;
+
+   for( char *p = start; p != end; p++ ) {
+       if( *p == '\\' ) {
+           if( ++p == end ) {
+               *q++ = '\\';
+               break;
+           }
+           if( p[0] >= '0' && p[0] <= '3' && p+3 <= end &&
+               p[1] >= '0' && p[1] <= '7' &&
+               p[2] >= '0' && p[2] <= '7' ) {
+               *q++ = (char)iolex_readoctal(p,3);
+               p+=2;
+           } else {
+               switch( *p ) {
+               case 'n':
+                   *q++ = '\n';
+                   break;
+               case 'r':
+                   *q++ = '\r';
+                   break;
+               case 't':
+                   *q++ = '\t';
+                   break;
+               case 'x': /* hex */
+                   if( p + 3 > end || !isxdigit(p[1]) || !isxdigit(p[2]) ) {
+                       *q++ = '\\';
+                       *q++ = *p;
+                   } else {
+                       *q++ = (char)iolex_readhex(p+1, 2);
+                       p+=2;
+                   }
+                   break;
+               default:
+                   *q++ = '\\';
+                   *q++ = *p;
+               }
+           }
+       } else {
+           *q++ = *p;
+       }
+   }
+   *len = q - result;
+   return result;
+}
+
+int iolex( int expectToken )
+{
+    int count = 0;
+    while( yyposn < yyend ) {
+        char *yystart = yytok.yytext = yyposn;
+        yytok.yylength = 1;
+        yytok.yyline = yyline;
+        yytok.yycol = yyposn - yylineposn+1;
+        int ch = *yyposn++;
+        if( isdigit(ch) ) {
+            /* INTEGER */
+            if( ch == '0' ) {
+                if( *yyposn == 'x' ) {
+                    while( yyposn < yyend && isxdigit(*++yyposn) ) ;
+                } else {
+                    while( yyposn < yyend && *yyposn >= '0' && *yyposn <= '7' )
+                        yyposn++;
+                }
+            } else {
+                while( yyposn < yyend && isdigit(*yyposn) )
+                    yyposn++;
+            }
+            yytok.v.i = strtol( yystart, NULL, 0 );
+            YYRETURN(TOK_INTEGER);
+        } else if( isalpha(ch) || ch == '_' ) {
+            /* IDENTIFIER */
+            while( yyposn < yyend && (isalnum(*yyposn) || *yyposn == '_') )
+                yyposn++;
+            yytok.yylength = yyposn - yystart;
+            if( expectToken == TOK_IDENTIFIER ) {
+                YYRETURN(TOK_IDENTIFIER);
+            }
+            /* Otherwise check for keywords */
+            for( int i=FIRST_KEYWORD; i <= LAST_KEYWORD; i++ ) {
+                if( strlen(TOKEN_NAMES[i]) == yytok.yylength &&
+                    strncasecmp(TOKEN_NAMES[i], yystart, yytok.yylength ) == 0 ) {
+                    YYRETURN(i);
+                }
+            }
+            YYRETURN(TOK_IDENTIFIER);
+        } else if( isspace(ch) ) {
+            if( ch == '\n' ) {
+                yyline++;
+                yylineposn = yyposn;
+            }
+            while( isspace(*yyposn) ) {
+                if( *yyposn == '\n' ) {
+                    yyline++;
+                    yylineposn = yyposn+1;
+                }
+                yyposn++;
+            }
+        } else {
+            switch( ch ) {
+            case '(': YYRETURN(TOK_LPAREN);
+            case ')': YYRETURN(TOK_RPAREN);
+            case '[': YYRETURN(TOK_LSQUARE);
+            case ']': YYRETURN(TOK_RSQUARE);
+            case ',': YYRETURN(TOK_COMMA);
+            case ':': YYRETURN(TOK_COLON);
+            case ';': YYRETURN(TOK_SEMI);
+            case '=': YYRETURN(TOK_EQUALS);
+            case '/':
+                if( *yyposn == '/' ) { /* Line comment */
+                    while( yyposn < yyend && *++yyposn != '\n' ) ;
+                } else if( *yyposn == '*' ) { /* C comment */
+                    while( yyposn < yyend && (*++yyposn != '*' || *++yyposn != '/' ) ) {
+                        if( *yyposn == '\n' ) {
+                            yyline++;
+                            yylineposn = yyposn+1;
+                        }
+                    }
+                }
+                break;
+            case '\'': /* STRING */
+                while( *yyposn != '\'' ) {
+                    if( *yyposn == '\n' ) {
+                        fprintf( stderr, "Unexpected newline in string constant!\n" );
+                        YYRETURN(TOK_ERROR);
+                    } else if( yyposn >= yyend ) {
+                        fprintf( stderr, "Unexpected EOF in string constant!\n" );
+                        YYRETURN(TOK_ERROR);
+                    } else if( *yyposn == '\\' && yyposn[1] == '\'' ) {
+                        yyposn++;
+                    }
+                    yyposn++;
+                }
+                yyposn++;
+                yytok.v.s = iolex_getcstring(yystart+1, yyposn-1, &yytok.slen);
+                YYRETURN(TOK_STRING);
+            case '\"': /* STRING */
+                while( *yyposn != '\"' ) {
+                    if( *yyposn == '\n' ) {
+                        fprintf( stderr, "Unexpected newline in string constant!\n" );
+                        YYRETURN(TOK_ERROR);
+                    } else if( yyposn >= yyend ) {
+                        fprintf( stderr, "Unexpected EOF in string constant!\n" );
+                        YYRETURN(TOK_ERROR);
+                    } else if( *yyposn == '\\' && yyposn[1] == '\"' ) {
+                        yyposn++;
+                    }
+                    yyposn++;
+                }
+                yyposn++;
+                yytok.v.s = iolex_getcstring(yystart+1, yyposn-1, &yytok.slen);
+                YYRETURN(TOK_STRING);
+            case '}':
+                YYRETURN(TOK_RBRACE);
+            case '{': /* ACTION or LBRACE */
+                if( expectToken == TOK_LBRACE ) {
+                    YYRETURN(TOK_LBRACE);
+                } else {
+                    count++;
+                    while( count > 0 && yyposn < yyend ) {
+                        if( *yyposn == '{' )
+                            count++;
+                        if( *yyposn == '}' )
+                            count--;
+                        yyposn++;
+                    }
+                    YYRETURN(TOK_ACTION);
+                }
+            case '.':
+                if( *yyposn == '.' ) {
+                    yyposn++;
+                    YYRETURN(TOK_RANGE);
+                } else {
+                    YYRETURN(TOK_PERIOD);
+                }
+            default:
+                fprintf( stderr, "Illegal character: '%c'\n", ch );
+                YYRETURN(TOK_ERROR);
+            }
+        }
+
+    }
+    return TOK_EOF;
+}
</pre></div>
<center><small>Chaos Theory</small></center>
</div></body></html>