diff -Nru xroar-0.31.1/ChangeLog xroar-0.32/ChangeLog --- xroar-0.31.1/ChangeLog 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/ChangeLog 2014-04-22 10:58:56.000000000 +0000 @@ -1,3 +1,21 @@ +Version 0.32, Tue Apr 22 2014 + + * Fix keyboard handling - CoCo Tetris now playable again. + * SDL, CoreAudio: allow -ao-fragments more than 1. + * Binary file loading no longer assumes 64K RAM organisation. + * Warn about use of deprecated options. + * Add joystick menus to GTK+ interface. + * New option -ao-format to select audio sample format. + * Fix 6309 timing issue (CMPU, CMPS). + * Fix issue with 6309 STBT instruction. + * Use endian.h where available. + * Preserve extra VDK header information in rewritten images. + * New Windows UI adding menus to the SDL window. + * Detect headerless JVC image geometry from OS-9 filesystem information. + * New option -no-disk-auto-os9 disables automatic geometry detection. + * Recognise ".os9" as extension for JVC images, ignores -no-disk-auto-os9. + * Deprecated option -disk-jvc-hack (now ignored in favour of above). + Version 0.31, Thu Nov 28 2013 * New option -timeout quits emulator after number of seconds. diff -Nru xroar-0.31.1/common.mak xroar-0.32/common.mak --- xroar-0.31.1/common.mak 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/common.mak 2014-04-22 10:58:56.000000000 +0000 @@ -2,8 +2,8 @@ #VERBOSE = 1 VERSION_MAJOR = 0 -VERSION_MINOR = 31 -VERSION_PATCH = 1 +VERSION_MINOR = 32 +VERSION_PATCH = 0 VERSION_SUBPATCH = 0 VERSION = $(VERSION_MAJOR).$(VERSION_MINOR) @@ -20,7 +20,7 @@ endif endif -DISTNAME = xroar-$(VERSION) +distdir = xroar-$(VERSION) .PHONY: profile-generate profile-use profile-generate: CFLAGS += -fprofile-generate -ftest-coverage diff -Nru xroar-0.31.1/configure xroar-0.32/configure --- xroar-0.31.1/configure 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/configure 2014-04-22 10:58:56.000000000 +0000 @@ -18,6 +18,7 @@ unset _have_audio_driver all_opt=" +endian_h endian strsep zlib @@ -618,10 +619,41 @@ ######## -# Test endianness if not specified and not cross-compiling. +# Prefer endian.h if found. -echocheck Endianness -if test -z "$_endian" -a -z "$_cross"; then +if test -z "$_endian_h" -a -z "$_endian"; then + echocheck endian.h + cat > $TMPC < +#include +#undef VALUE +#if __BYTE_ORDER == __BIG_ENDIAN +#define VALUE (EXIT_SUCCESS) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define VALUE (EXIT_SUCCESS) +#endif +int main(int argc, char **argv) { + return VALUE; +} +EOF + _endian_h=no + target_cc_check "" "" && _endian_h=yes + rm -f $TMPC + echo "$_endian_h" +else + _endian_h=no +fi +if test "$_endian_h" = "yes"; then + _endian_h_def="#define HAVE_ENDIAN_H" +else + _endian_h_def="#undef HAVE_ENDIAN_H" +fi + +# Test endianness if endian.h doesn't exist and not cross-compiling. If cross +# compiling, assume endianness based on arch. + +if test "$_endian_h" \!= "yes" -a -z "$_endian" -a -z "$_cross"; then + echocheck Endianness # I only care about 16-bit values at the moment. There's a whole host # of potential wrongness for larger types... cat > $TMPC < Wed, 04 Jun 2014 19:09:17 +0200 + xroar (0.31.1-0~tormod) lucid; urgency=low * New upstream bug fix release diff -Nru xroar-0.31.1/debian/patches/20_makefile_subdirs_fix.patch xroar-0.32/debian/patches/20_makefile_subdirs_fix.patch --- xroar-0.31.1/debian/patches/20_makefile_subdirs_fix.patch 2013-11-30 08:54:21.000000000 +0000 +++ xroar-0.32/debian/patches/20_makefile_subdirs_fix.patch 2014-06-04 17:09:00.000000000 +0000 @@ -2,23 +2,12 @@ =================================================================== --- xroar-0.31.orig/Makefile 2013-11-28 09:19:01.000000000 +0100 +++ xroar-0.31/Makefile 2013-11-30 09:54:17.884420203 +0100 -@@ -3,12 +3,16 @@ +@@ -3,7 +3,7 @@ # Run with "VERBOSE=1" for normal output. -SUBDIRS = portalib src doc -+#SUBDIRS = portalib src doc +SUBDIRS = src doc DIST_SUBDIRS = portalib src doc tools .PHONY: all --all: -- @for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@; done -+all: $(SUBDIRS) -+ -+.PHONY: $(SUBDIRS) -+$(SUBDIRS): -+ $(MAKE) -C $@ - - .PHONY: profile-generate profile-use - profile-generate profile-use: diff -Nru xroar-0.31.1/debian/watch xroar-0.32/debian/watch --- xroar-0.31.1/debian/watch 2013-09-19 19:24:24.000000000 +0000 +++ xroar-0.32/debian/watch 2014-06-04 17:04:57.000000000 +0000 @@ -1,2 +1,2 @@ version=3 -http://www.6809.org.uk/dragon/xroar.shtml xroar-(.*)\.tar\.gz +http://www.6809.org.uk/xroar/download/xroar-(.*)\.tar.gz diff -Nru xroar-0.31.1/doc/Makefile xroar-0.32/doc/Makefile --- xroar-0.31.1/doc/Makefile 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/doc/Makefile 2014-04-22 10:58:56.000000000 +0000 @@ -8,7 +8,7 @@ -include ../config.mak -SRCROOT ?= $(dir $(lastword $(MAKEFILE_LIST))) +SRCROOT ?= .. include $(SRCROOT)/common.mak SRCROOT := $(SRCROOT)/doc @@ -66,6 +66,8 @@ install-info: xroar.info $(INSTALL_DIR) $(DESTDIR)$(infodir) $(INSTALL_FILE) xroar.info $(DESTDIR)$(infodir) + $(INSTALL_FILE) xroar-screens.png $(DESTDIR)$(infodir) + $(INSTALL_FILE) xroar-timebandit-af.png $(DESTDIR)$(infodir) .PHONY: uninstall-info uninstall-info: Binary files /tmp/zELbdNhhG3/xroar-0.31.1/doc/timebandit-af.png and /tmp/3zWNEp7ObQ/xroar-0.32/doc/timebandit-af.png differ diff -Nru xroar-0.31.1/doc/xroar.texi xroar-0.32/doc/xroar.texi --- xroar-0.31.1/doc/xroar.texi 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/doc/xroar.texi 2014-04-22 10:58:56.000000000 +0000 @@ -33,7 +33,7 @@ This manual is for XRoar (version @value{VERSION}), a Dragon and Tandy Colour Computer emulator. -Copyright @copyright{} 2013 +Copyright @copyright{} 2014 Ciaran Anscomb. @end copying @@ -148,6 +148,8 @@ of printing to the console, useful information will end up in files called @file{stdout.txt} or @file{stderr.txt}. +The Windows build provides menu-based access to certain features. + @node Building from source @section Building from source @@ -190,14 +192,14 @@ used to provide video output. Otherwise, it can provide a file requester for use by other user interfaces. -@myuref{http://www.libsdl.org/, SDL}, Simple Directmedia Layer, provides a more -basic user experience, with most functionality only available through the -keyboard shortcuts. Under Mac OS X, a special case of the SDL UI is built that -also provides some menus. Unless you are building for Linux, SDL is required -to use joysticks. +@myuref{http://www.libsdl.org/, SDL}, Simple Directmedia Layer, provides a +slightly more basic user experience. Menus are added using native code under +Mac OS X and Windows; any other target using SDL will support only keyboard +shortcuts. Unless you are building for Linux, SDL is required to use +joysticks. -Other supported audio APIs: OSS, ALSA, PulseAudio, CoreAudio, JACK, Sun audio -(not tested in quite a while). +Other supported audio APIs: OSS, ALSA, PulseAudio, CoreAudio. Some other +options are still in the code base, but have not been tested in a while. @myuref{http://www.mega-nerd.com/libsndfile/, libsndfile} is recommended to enable support for using audio files as cassette images. @@ -517,9 +519,9 @@ automatically selecting one. The IP and port to connect to can be specified with the @option{-becker-ip} and -@option{-becker-port} options. These default to ``localhost'' and ``65504'' -respectively, matching the defaults for DriveWire 4, the most popular server -application used to provide such facilities. +@option{-becker-port} options. These default to @samp{127.0.0.1} and +@samp{65504} respectively, matching the defaults for DriveWire 4, the most +popular server application used to provide such facilities. @node Files @@ -570,23 +572,23 @@ The @option{-tape-fast} option accelerates tape loading by intercepting ROM calls. Disable with @option{-no-tape-fast}. On by default. -The @option{-tape-pad} option tries to make loading more reliable by -intercepting ROM calls and inserting extra leader bytes where appropriate. -Disable with @option{-no-tape-pad}. +The @option{-tape-rewrite} option enables rewriting of anything read from the +input tape to the output tape. This is useful for creating ``well formed'' +@file{.cas} files. The remaining options affect how XRoar attempts to cope with bad tape images (images that, were they simply converted to audio files, would not load on a real Dragon): +The @option{-tape-pad} option tries to make loading more reliable by +intercepting ROM calls and assuming extra leader bytes where appropriate. +Disable with @option{-no-tape-pad}. + The @option{-tape-pad-auto} option will, for @file{.cas} files, automatically switch on leader padding when insufficient initial leader bytes are found at the beginning of the file, otherwise it is left alone. Disable with @option{-no-tape-pad-auto}. On by default. -The @option{-tape-rewrite} option enables rewriting of anything read from the -input tape to the output tape. This is useful for creating ``well formed'' -@file{.cas} files. - Where available, these options can be changed on the fly in the GUI. @@ -596,14 +598,14 @@ If a disk interface cartridge is selected, XRoar supports virtual disks. Three virtual disk formats are supported: -@multitable @columnfractions .15 .80 +@multitable @columnfractions .20 .75 @headitem Extension @tab Description @item @file{.dmk} @tab Disk image file in a format defined by David Keil. They store a lot of information about the structure of a disk and support both single and double density data. All disk images are manipulated internally in (near enough) this format. -@item @file{.jvc}, @file{.dsk} +@item @file{.jvc}, @file{.os9}, @file{.dsk} @tab Disk image file in a basic sector-by-sector format with optional header information. @item @file{.vdk} @@ -627,10 +629,13 @@ command line option. The JVC format specifies that the default number of sides in a headerless image -is 1, but some disk images are distributed without headers that are 40 track, -double-sided. As these cannot be distinguished from 80 track single-sided -disks, an option is provided to force the issue. If you're having such -problems, run with the @option{-disk-jvc-hack} option. +is 1, but some disk images are distributed without headers that are +double-sided. These cannot normally be distinguished from a single-sided disk +with double the number of tracks, but if an OS-9 filesystem is present, the +information is contained within the first sector. Because this information may +be confused with other valid disk contents, the behaviour can be disabled with +@option{-no-disk-auto-os9}. Disk images with the extension @file{.os9} without +headers always ignore this option, however. You can create a new blank disk in a virtual drive by pressing @kbd{Ctrl}+@kbd{Shift}+@var{[1-4]}. You will be a prompted for a filename, @@ -702,13 +707,14 @@ usually refers to a ROM list which contains all the corresponding filenames seen ``in the wild'': -@multitable {RS-DOS with becker port} {Xdragondos_compat} {dplus49b, sdose6, ddos40, cdos20XXXXX} +@multitable {RS-DOS with becker port} {Xdragondos_compatxx} {dplus49b, sdose6, ddos40, cdos20XXXXX} @headitem Firmware ROM @tab ROM list @tab Canonical image names @item Dragon 32 BASIC @tab @samp{@@dragon32} @tab @file{d32} @item Dragon 64 32K BASIC @tab @samp{@@dragon64} @tab @file{d64_1} @item Dragon 64 64K BASIC @tab @samp{@@dragon64_alt} @tab @file{d64_2} @item Dragon 200-E 32K BASIC @tab @samp{@@dragon200e} @tab @file{d200e_1} @item Dragon 200-E 64K BASIC @tab @samp{@@dragon200e_alt} @tab @file{d200e_2} +@item Dragon 200-E Charset@tab @samp{@@dragon200e_charset} @tab @file{d200e_26} @item Tandy Colour BASIC @tab @samp{@@coco} @tab @file{bas13}, @file{bas12}, @file{bas11}, @file{bas10} @item Tandy Extended BASIC @tab @samp{@@coco_ext} @tab @file{extbas11}, @file{extbas10} @item DragonDOS @tab @samp{@@dragondos_compat} @tab @file{dplus49b}, @file{sdose6}, @file{ddos40}, @file{cdos20} @@ -783,25 +789,18 @@ @subsection SDL user interface -Select with @option{-ui sdl}. - -A basic interface that provides no menus or control dialogues. All actions are -performed through keyboard shortcuts. Provides three video output modules: -@samp{sdlgl} (OpenGL, preferred), @samp{sdlyuv} (YUV, often accelerated under -X11) and @samp{sdl}. @option{-vo sdl} is the least capable, but most -compatible; try this if you are having problems with OpenGL. - -This is the only available user interface in the Windows binary distribution. - -@subsection Mac OS X user interface - -Select with @option{-ui macosx}. +Select with @option{-ui macosx} (Mac OS X menus), @option{-ui windows32} +(Windows menus) or @option{-ui sdl} (no menus). -This is actually a special case of the SDL user interface. A basic set of -menus are created, and many operations are usable by pressing -@kbd{Command}+@var{key} instead of @kbd{Ctrl}+@var{key}. +A more limited interface, still including an amount of menu-based control under +Mac OS X and Windows. Other actions require the use of XRoar's keyboard +shortcuts. Provides three video output modules: @samp{sdlgl} (OpenGL, +preferred), @samp{sdlyuv} (YUV, often accelerated under X11) and @samp{sdl}. +@option{-vo sdl} is the least capable, but most compatible; try this if you are +having problems with OpenGL. -This is the only available user interface in the Mac OS X binary distribution. +Under Mac OS X, many operations are usable by pressing @kbd{Command}+@var{key} +as well as the usual shortcut of @kbd{Ctrl}+@var{key}. @node Video output @@ -859,10 +858,14 @@ Module-specific device specifier. e.g., @file{/dev/dsp} for OSS. +@item -ao-format @var{format} + +Specify audio sample format. @option{-ao-format help} for a list. + @item -ao-rate @var{hz} -Specify sample rate, where supported. The default is taken from the operating -system if possible, otherwise it will usually be @samp{48000}. +Specify audio frame rate, where supported. The default is taken from the +operating system if possible, otherwise it will usually be @samp{48000}. @item -ao-channels @var{n} @@ -901,10 +904,9 @@ Audio latency is a concern for emulators, so XRoar allows the buffering characteristics to be configured with the fragment and buffer options above. Not all audio modules support all options, but setting the total audio buffer -size will usually have an effect. ALSA and OSS modules allow very fine-grained -control. Bear in mind that any figures reported by XRoar reflect what it was -able to request, and won't include any extra buffering introduced by the -underlying sound system. +size will usually have an effect. Bear in mind that any figures reported by +XRoar reflect what it was able to request, and won't include any extra +buffering introduced by the underlying sound system. When the Orchestra 90-CC cartridge is attached, audio levels will be reduced due to the need to mix in a stereo output. @@ -1052,7 +1054,7 @@ @myuref{http://www.gnu.org/software/gdb/documentation/, GDB Documentation}. Enable the GDB remote target with @option{-gdb}. The default IP and port for -the target are @samp{localhost} and @samp{65520}. These can be overridden with +the target are @samp{127.0.0.1} and @samp{65520}. These can be overridden with the @option{-gdb-ip} and @option{-gdb-port} options. XRoar also supports a simpler ``trace mode'', where it will dump a disassembly @@ -1109,6 +1111,22 @@ The special value argument of -1 parses as ``all bits set'', and so enables all corresponding debug options. +XRoar prints various other informational messages to standard output by +default, including when the state of certain toggles is modified. Verbosity +can be changed with the @option{-verbose @var{level}} option. @option{-quiet} +is equivalent to @option{-verbose 0}. Levels are: + +@table @asis +@item 0 +Quiet. Only warnings and errors printed. +@item 1 +Print startup diagnostics and emulator state changes (default). +@item 2 +Report some emulated machine state changes. +@item 3 +Miscellaneous internal debugging. +@end table + XRoar can be told to exit after a number of (emulated) seconds with the @option{-timeout @var{seconds}} option. @@ -1211,7 +1229,7 @@ @option{-default-machine tano} or @option{-default-machine cocous}. @float Figure,fig:artifacts -@image{timebandit-af, 6.25in,, @cite{Time Bandit, Dunlevy & Lafnear, 1983} in different artifact modes, png} +@image{xroar-timebandit-af, 6.25in,, @cite{Time Bandit, Dunlevy & Lafnear, 1983} in different artifact modes, png} @caption{@cite{Time Bandit, Dunlevy & Lafnear, 1983} in different artifact modes} @end float Binary files /tmp/zELbdNhhG3/xroar-0.31.1/doc/xroar-timebandit-af.png and /tmp/3zWNEp7ObQ/xroar-0.32/doc/xroar-timebandit-af.png differ diff -Nru xroar-0.31.1/Makefile xroar-0.32/Makefile --- xroar-0.31.1/Makefile 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/Makefile 2014-04-22 10:58:56.000000000 +0000 @@ -8,11 +8,11 @@ .PHONY: all all: - @for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@; done + @$(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@ && ) true .PHONY: profile-generate profile-use profile-generate profile-use: - @for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@; done + @$(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@ && ) true -include config.mak @@ -25,11 +25,11 @@ .PHONY: install install: - @for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@; done + @$(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@ && ) true .PHONY: uninstall uninstall: - @for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@; done + @$(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@ && ) true ############################################################################ # Specific targets @@ -67,32 +67,26 @@ .PHONY: dist dist: - git archive --format=tar --output=../$(DISTNAME).tar --prefix=$(DISTNAME)/ HEAD - gzip -f9 ../$(DISTNAME).tar + git archive --format=tar --output=$(distdir).tar --prefix=$(distdir)/ HEAD + gzip -f9 $(distdir).tar .PHONY: dist-w64 dist-w64: all doc/xroar.pdf - mkdir $(DISTNAME)-w64 - cp $(SRCROOT)/COPYING.GPL $(SRCROOT)/ChangeLog $(SRCROOT)/README doc/xroar.pdf src/xroar.exe $(prefix)/bin/SDL.dll $(prefix)/bin/libsndfile-1.dll $(DISTNAME)-w64/ - cp $(SRCROOT)/COPYING.LGPL-2.1 $(DISTNAME)-w64/COPYING.LGPL-2.1 - $(TOOL_PREFIX)strip $(DISTNAME)-w64/xroar.exe - $(TOOL_PREFIX)strip $(DISTNAME)-w64/SDL.dll - $(TOOL_PREFIX)strip $(DISTNAME)-w64/libsndfile-1.dll - rm -f ../$(DISTNAME)-w64.zip - zip -r ../$(DISTNAME)-w64.zip $(DISTNAME)-w64 - rm -rf $(DISTNAME)-w64/ + mkdir $(distdir)-w64 + cp $(SRCROOT)/COPYING.GPL $(SRCROOT)/ChangeLog $(SRCROOT)/README doc/xroar.pdf src/xroar.exe $(distdir)-w64/ + $(TOOL_PREFIX)strip $(distdir)-w64/xroar.exe + rm -f ../$(distdir)-w64.zip + zip -r ../$(distdir)-w64.zip $(distdir)-w64 + rm -rf $(distdir)-w64/ .PHONY: dist-w32 dist-w32: all doc/xroar.pdf - mkdir $(DISTNAME)-w32 - cp $(SRCROOT)/COPYING.GPL $(SRCROOT)/ChangeLog $(SRCROOT)/README doc/xroar.pdf src/xroar.exe $(prefix)/bin/SDL.dll $(prefix)/bin/libsndfile-1.dll $(DISTNAME)-w32/ - cp $(SRCROOT)/COPYING.LGPL-2.1 $(DISTNAME)-w32/COPYING.LGPL-2.1 - $(TOOL_PREFIX)strip $(DISTNAME)-w32/xroar.exe - $(TOOL_PREFIX)strip $(DISTNAME)-w32/SDL.dll - $(TOOL_PREFIX)strip $(DISTNAME)-w32/libsndfile-1.dll - rm -f ../$(DISTNAME)-w32.zip - zip -r ../$(DISTNAME)-w32.zip $(DISTNAME)-w32 - rm -rf $(DISTNAME)-w32/ + mkdir $(distdir)-w32 + cp $(SRCROOT)/COPYING.GPL $(SRCROOT)/ChangeLog $(SRCROOT)/README doc/xroar.pdf src/xroar.exe $(distdir)-w32/ + $(TOOL_PREFIX)strip $(distdir)-w32/xroar.exe + rm -f ../$(distdir)-w32.zip + zip -r ../$(distdir)-w32.zip $(distdir)-w32 + rm -rf $(distdir)-w32/ .PHONY: dist-macosx dist-macos dist-macosx dist-macos: all doc/xroar.pdf @@ -118,28 +112,28 @@ .PHONY: debuild debuild: dist - -cd ..; rm -rf $(DISTNAME)/ $(DISTNAME).orig/ - cd ..; mv $(DISTNAME).tar.gz xroar_$(VERSION).orig.tar.gz + -cd ..; rm -rf $(distdir)/ $(distdir).orig/ + cd ..; mv $(distdir).tar.gz xroar_$(VERSION).orig.tar.gz cd ..; tar xfz xroar_$(VERSION).orig.tar.gz - rsync -axH debian --exclude='debian/.git/' --exclude='debian/_darcs/' ../$(DISTNAME)/ - cd ../$(DISTNAME); debuild + rsync -axH debian --exclude='debian/.git/' --exclude='debian/_darcs/' ../$(distdir)/ + cd ../$(distdir); debuild ############################################################################ # Clean-up, etc. .PHONY: clean clean: - @for dir in $(DIST_SUBDIRS); do $(MAKE) -C $$dir $@; done + @$(foreach dir, $(DIST_SUBDIRS), $(MAKE) -C $(dir) $@ && ) true .PHONY: profile-clean profile-clean: - @for dir in $(DIST_SUBDIRS); do $(MAKE) -C $$dir $@; done + @$(foreach dir, $(DIST_SUBDIRS), $(MAKE) -C $(dir) $@ && ) true .PHONY: distclean distclean: - @for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@; done + @$(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@ && ) true rm -f config.h config.mak config.log .PHONY: depend depend: - @for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@; done + @$(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@ && ) true diff -Nru xroar-0.31.1/portalib/array.h xroar-0.32/portalib/array.h --- xroar-0.31.1/portalib/array.h 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/array.h 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,20 @@ +/* + +C array handling +Copyright 2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +Just the one macro for now. + +*/ + +#ifndef ARRAY_H__DJnCHtnGSsoak +#define ARRAY_H__DJnCHtnGSsoak + +#define ARRAY_N_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) + +#endif /* ARRAY_H__DJnCHtnGSsoak */ diff -Nru xroar-0.31.1/portalib/c-ctype.c xroar-0.32/portalib/c-ctype.c --- xroar-0.31.1/portalib/c-ctype.c 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/c-ctype.c 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,29 @@ +/* + +C locale character handling +Copyright 2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +Assumes ASCII. + +*/ + +#include "config.h" + +#include "c-ctype.h" + +int c_tolower(int c) { + if (c_isupper(c)) + return c | 0x20; + return c; +} + +int c_toupper(int c) { + if (c_islower(c)) + return c & ~0x20; + return c; +} diff -Nru xroar-0.31.1/portalib/c-ctype.h xroar-0.32/portalib/c-ctype.h --- xroar-0.31.1/portalib/c-ctype.h 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/c-ctype.h 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,33 @@ +/* + +C locale character handling +Copyright 2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +A small subset of ctype.h functions that act as if the locale were 'C'. +See Gnulib for a far more complete implementation that also handles edge +cases like non-ASCII-compatible chars in the execution environment. + +*/ + +#ifndef C_CTYPE_H__GHh4ag1cA5ckI +#define C_CTYPE_H__GHh4ag1cA5ckI + +#include + +int c_tolower(int c); +int c_toupper(int c); + +static inline bool c_islower(int c) { + return (c >= 'a' && c <= 'z'); +} + +static inline bool c_isupper(int c) { + return (c >= 'A' && c <= 'Z'); +} + +#endif /* C_CTYPE_H__GHh4ag1cA5ckI */ diff -Nru xroar-0.31.1/portalib/c-strcasecmp.c xroar-0.32/portalib/c-strcasecmp.c --- xroar-0.31.1/portalib/c-strcasecmp.c 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/c-strcasecmp.c 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,30 @@ +/* + +C locale string functions +Copyright 2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +Assumes ASCII. + +*/ + +#include "config.h" + +#include + +#include "c-ctype.h" +#include "c-strcase.h" + +int c_strcasecmp(const char *s1, const char *s2) { + if (!s1 || !s2) + return 0; + while (*s1 && *s2 && (*s1 == *s2 || c_tolower(*s1) == c_tolower(*s2))) { + s1++; + s2++; + } + return c_tolower(*s1) - c_tolower(*s2); +} diff -Nru xroar-0.31.1/portalib/c-strcase.h xroar-0.32/portalib/c-strcase.h --- xroar-0.31.1/portalib/c-strcase.h 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/c-strcase.h 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,25 @@ +/* + +C locale string functions +Copyright 2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +String functions that act as if the locale were 'C'. See Gnulib for +a far more complete implementation that also handles edge cases like +non-ASCII-compatible chars in the execution environment. + +*/ + +#ifndef C_STRCASE_H__vD9hqIMCxQQDM +#define C_STRCASE_H__vD9hqIMCxQQDM + +#include + +int c_strcasecmp(const char *s1, const char *s2); +int c_strncasecmp(const char *s1, const char *s2, size_t n); + +#endif /* C_STRCASE_H__vD9hqIMCxQQDM */ diff -Nru xroar-0.31.1/portalib/c-strncasecmp.c xroar-0.32/portalib/c-strncasecmp.c --- xroar-0.31.1/portalib/c-strncasecmp.c 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/c-strncasecmp.c 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,32 @@ +/* + +C locale string functions +Copyright 2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +Assumes ASCII. + +*/ + +#include "config.h" + +#include + +#include "c-ctype.h" +#include "c-strcase.h" + +int c_strncasecmp(const char *s1, const char *s2, size_t n) { + if (!s1 || !s2) + return 0; + while (n > 0 && *s1 && *s2 && + (*s1 == *s2 || c_tolower(*s1) == c_tolower(*s2))) { + s1++; + s2++; + n--; + } + return (n == 0) ? 0 : c_tolower(*s1) - c_tolower(*s2); +} diff -Nru xroar-0.31.1/portalib/delegate.c xroar-0.32/portalib/delegate.c --- xroar-0.31.1/portalib/delegate.c 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/delegate.c 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,28 @@ +/* + +Delegates in C +Copyright 2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +Implement the default no-op functions for defined delegate types. + +*/ + +#include "config.h" + +#include + +#include "delegate.h" + +DELEGATE_DEF_FUNC0(void, void) +DELEGATE_DEF_FUNC1(void, void, _Bool, bool) +DELEGATE_DEF_FUNC1(void, void, int, int) +DELEGATE_DEF_FUNC1(void, void, unsigned, unsigned) +DELEGATE_DEF_FUNC1(void, void, float, float) +DELEGATE_DEF_FUNC0(uint8_t, uint8) +DELEGATE_DEF_FUNC1(void, void, uint8_t, uint8) +DELEGATE_DEF_FUNC2(void, void, int, int, uint8_t *, uint8p) diff -Nru xroar-0.31.1/portalib/delegate.h xroar-0.32/portalib/delegate.h --- xroar-0.31.1/portalib/delegate.h 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/delegate.h 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,84 @@ +/* + +Delegates in C +Copyright 2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +*/ + +#ifndef DELEGATE_H__oeW3udTBnzIVk +#define DELEGATE_H__oeW3udTBnzIVk + +#include + +/* Underlying struct def for delegates. */ + +#define DELEGATE_S0(T) struct { T (*func)(void *); void *sptr; } +#define DELEGATE_S1(T,T0) struct { T (*func)(void *, T0); void *sptr; } +#define DELEGATE_S2(T,T0,T1) struct { T (*func)(void *, T0, T1); void *sptr; } + +/* Type name for delegates. */ + +#define DELEGATE_T0(N) delegate_##N +#define DELEGATE_T1(N,N0) delegate_##N##_##N0 +#define DELEGATE_T2(N,N0,N1) delegate_##N##_##N0##_##N1 + +/* Define a set of delegate types. */ + +typedef DELEGATE_S0(void) DELEGATE_T0(void); +typedef DELEGATE_S1(void, _Bool) DELEGATE_T1(void, bool); +typedef DELEGATE_S1(void, int) DELEGATE_T1(void, int); +typedef DELEGATE_S1(void, unsigned) DELEGATE_T1(void, unsigned); +typedef DELEGATE_S1(void, float) DELEGATE_T1(void, float); +typedef DELEGATE_S0(uint8_t) DELEGATE_T0(uint8); +typedef DELEGATE_S1(void, uint8_t) DELEGATE_T1(void, uint8); +typedef DELEGATE_S2(void, int, uint8_t *) DELEGATE_T2(void, int, uint8p); + +/* Convenience function for declaring anonymous structs. */ + +#define DELEGATE_AS0(N,f,s) (DELEGATE_T0(N)){f,s} +#define DELEGATE_AS1(N,N0,f,s) (DELEGATE_T1(N,N0)){f,s} +#define DELEGATE_AS2(N,N0,N1,f,s) (DELEGATE_T2(N,N0,N1)){f,s} + +/* Delegate default function names. */ + +#define DELEGATE_DEFAULT_F0(N) delegate_##N##_default +#define DELEGATE_DEFAULT_F1(N,N0) delegate_##N##_default_##N0 +#define DELEGATE_DEFAULT_F2(N,N0,N1) delegate_##N##_default_##N0##_##N1 + +/* Default no-op functions for defined delegate types. */ + +#define DELEGATE_DEF_PROTO0(T,N) T DELEGATE_DEFAULT_F0(N)(void *) +#define DELEGATE_DEF_PROTO1(T,N,T0,N0) T DELEGATE_DEFAULT_F1(N,N0)(void *, T0) +#define DELEGATE_DEF_PROTO2(T,N,T0,N0,T1,N1) T DELEGATE_DEFAULT_F2(N,N0,N1)(void *, T0, T1) + +#define DELEGATE_DEF_FUNC0(T,N) T DELEGATE_DEFAULT_F0(N)(void *sptr) { (void)sptr; } +#define DELEGATE_DEF_FUNC1(T,N,T0,N0) T DELEGATE_DEFAULT_F1(N,N0)(void *sptr, T0 v0) { (void)sptr; (void)v0; } +#define DELEGATE_DEF_FUNC2(T,N,T0,N0,T1,N1) T DELEGATE_DEFAULT_F2(N,N0,N1)(void *sptr, T0 v0, T1 v1) { (void)sptr; (void)v0; (void)v1; } + +DELEGATE_DEF_PROTO0(void, void); +DELEGATE_DEF_PROTO1(void, void, _Bool, bool); +DELEGATE_DEF_PROTO1(void, void, int, int); +DELEGATE_DEF_PROTO1(void, void, unsigned, unsigned); +DELEGATE_DEF_PROTO1(void, void, float, float); +DELEGATE_DEF_PROTO0(uint8_t, uint8); +DELEGATE_DEF_PROTO1(void, void, uint8_t, uint8); +DELEGATE_DEF_PROTO2(void, void, int, int, uint8_t *, uint8p); + +#define DELEGATE_DEFAULT0(N) DELEGATE_AS0(N, DELEGATE_DEFAULT_F0(N), NULL) +#define DELEGATE_DEFAULT1(N,N0) DELEGATE_AS1(N, N0, DELEGATE_DEFAULT_F1(N, N0), NULL) +#define DELEGATE_DEFAULT2(N,N0,N1) DELEGATE_AS2(N, N0, N1, DELEGATE_DEFAULT_F2(N, N0, N1), NULL) + +/* Calling interface. */ + +#define DELEGATE_CALL0(d) ((d).func((d).sptr)) +#define DELEGATE_CALL1(d,v0) ((d).func((d).sptr,(v0))) +#define DELEGATE_CALL2(d,v0,v1) ((d).func((d).sptr,(v0),(v1))) +#define DELEGATE_SAFE_CALL0(d) do { if ((d).func) { DELEGATE_CALL0((d)); } } while (0) +#define DELEGATE_SAFE_CALL1(d,v0) do { if ((d).func) { DELEGATE_CALL1((d),(v0)); } } while (0) + +#endif /* DELEGATE_H__oeW3udTBnzIVk */ diff -Nru xroar-0.31.1/portalib/Makefile xroar-0.32/portalib/Makefile --- xroar-0.31.1/portalib/Makefile 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/portalib/Makefile 2014-04-22 10:58:56.000000000 +0000 @@ -8,7 +8,7 @@ -include ../config.mak -SRCROOT ?= $(dir $(lastword $(MAKEFILE_LIST))) +SRCROOT ?= .. include $(SRCROOT)/common.mak SRCROOT := $(SRCROOT)/portalib @@ -29,7 +29,13 @@ $(WARN) portalib_BASE_C = \ - strsep.c + c-ctype.c \ + c-strcasecmp.c \ + c-strncasecmp.c \ + delegate.c \ + slist.c \ + strsep.c \ + xmalloc.c portalib_BASE_C_O = $(portalib_BASE_C:.c=.o) # portalib_SOURCES_C += $(portalib_BASE_C) @@ -39,18 +45,6 @@ ############################################################################ # Options -portalib_glib2_C = \ - pl_glib/gmem.c \ - pl_glib/gslist.c \ - pl_glib/gstrfuncs.c -portalib_glib2_C_O = $(portalib_glib2_C:.c=.o) -# -portalib_SOURCES_C += $(portalib_glib2_C) -portalib_CLEAN_O += $(portalib_glib2_C_O) -ifneq ($(opt_glib2),yes) - portalib_C_O += $(portalib_glib2_C_O) -endif - ############################################################################ # Build diff -Nru xroar-0.31.1/portalib/pl-endian.h xroar-0.32/portalib/pl-endian.h --- xroar-0.31.1/portalib/pl-endian.h 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/pl-endian.h 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,38 @@ +/* + +Missing endian.h +Copyright 2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +If endian.h was not found by configure, it should have performed a test +or made an assumption, and HAVE_BIG_ENDIAN will be defined accordingly. + +*/ + +#ifndef PL_ENDIAN_H__ubnPKXx9bODus +#define PL_ENDIAN_H__ubnPKXx9bODus + +#ifdef HAVE_ENDIAN_H +#include +#endif + +#ifndef __BIG_ENDIAN +#define __BIG_ENDIAN 4321 +#endif +#ifndef __BIG_ENDIAN +#define __LITTLE_ENDIAN 1234 +#endif + +#ifndef __BYTE_ORDER +#ifdef HAVE_BIG_ENDIAN +#define __BYTE_ORDER __BIG_ENDIAN +#else +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif +#endif + +#endif /* PL_ENDIAN_H__ubnPKXx9bODus */ diff -Nru xroar-0.31.1/portalib/pl_glib/galloca.h xroar-0.32/portalib/pl_glib/galloca.h --- xroar-0.31.1/portalib/pl_glib/galloca.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/portalib/pl_glib/galloca.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -/* - * pl_glib is a set of public domain work-a-likes for some GLib functions and - * macros. It is not even slightly close to a complete reimplementation of - * GLib. - * - * This header includes either alloca.h (normal systems) or malloc.h (windows - * systems) for the prototype of alloca(), and aliases the appropriate GLib - * equivalents. - */ - -#ifndef PL_GLIB_GALLOCA_H_ -#define PL_GLIB_GALLOCA_H_ - -#ifndef WINDOWS32 -# include -#else -# include -#endif - -#define g_alloca(size) alloca(size) - -#endif /* def PL_GLIB_GALLOCA_H_ */ diff -Nru xroar-0.31.1/portalib/pl_glib/gmem.c xroar-0.32/portalib/pl_glib/gmem.c --- xroar-0.31.1/portalib/pl_glib/gmem.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/portalib/pl_glib/gmem.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -/* - * pl_glib is a set of public domain work-a-likes for some GLib functions and - * macros. It is not even slightly close to a complete reimplementation of - * GLib. - * - * Memory management. - * - * GLib proper has its own slice allocation stuff that makes this more - * efficient. These replacements mostly just wrap the equivalent standard C - * library functions. - */ - -#include "config.h" - -#include -#include -#include - -#include "pl_glib.h" - -gpointer g_try_malloc(gsize n_bytes) { - return malloc(n_bytes); -} - -gpointer g_try_malloc0(gsize n_bytes) { - gpointer mem = malloc(n_bytes); - if (mem) - memset(mem, 0, n_bytes); - return mem; -} - -gpointer g_try_realloc(gpointer mem, gsize n_bytes) { - if (n_bytes == 0) { - if (mem) - g_free(mem); - return NULL; - } - return realloc(mem, n_bytes); -} - -gpointer g_malloc(gsize n_bytes) { - void *mem = g_try_malloc(n_bytes); - if (!mem) { - perror(NULL); - exit(EXIT_FAILURE); - } - return mem; -} - -gpointer g_malloc0(gsize n_bytes) { - void *mem = g_malloc(n_bytes); - memset(mem, 0, n_bytes); - return mem; -} - -gpointer g_realloc(gpointer mem, gsize n_bytes) { - void *new_mem = g_try_realloc(mem, n_bytes); - if (!new_mem && n_bytes != 0) { - perror(NULL); - exit(EXIT_FAILURE); - } - return new_mem; -} - -void g_free(gpointer mem) { - if (mem) - free(mem); -} - -gpointer g_memdup(gconstpointer mem, guint byte_size) { - if (!mem) - return NULL; - void *new_mem = g_malloc(byte_size); - memcpy(new_mem, mem, byte_size); - return new_mem; -} diff -Nru xroar-0.31.1/portalib/pl_glib/gmem.h xroar-0.32/portalib/pl_glib/gmem.h --- xroar-0.31.1/portalib/pl_glib/gmem.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/portalib/pl_glib/gmem.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -/* - * pl_glib is a set of public domain work-a-likes for some GLib functions and - * macros. It is not even slightly close to a complete reimplementation of - * GLib. - * - * Memory management. - */ - -#ifndef PL_GLIB_GMEM_H_ -#define PL_GLIB_GMEM_H_ - -#include "pl_glib/gtypes.h" - -gpointer g_try_malloc(gsize n_bytes); -gpointer g_try_malloc0(gsize n_bytes); -gpointer g_try_realloc(gpointer mem, gsize n_bytes); -gpointer g_malloc(gsize n_bytes); -gpointer g_malloc0(gsize n_bytes); -gpointer g_realloc(gpointer mem, gsize n_bytes); -void g_free(gpointer mem); -gpointer g_memdup(gconstpointer mem, guint byte_size); - -#endif /* def PL_GLIB_GMEM_H_ */ diff -Nru xroar-0.31.1/portalib/pl_glib/gslist.c xroar-0.32/portalib/pl_glib/gslist.c --- xroar-0.31.1/portalib/pl_glib/gslist.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/portalib/pl_glib/gslist.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,127 +0,0 @@ -/* - * pl_glib is a set of public domain work-a-likes for some GLib functions and - * macros. It is not even slightly close to a complete reimplementation of - * GLib. - * - * Singly-linked lists. - */ - -#include "config.h" - -#include - -#include "pl_glib.h" - -/* Wrap data in a new list container */ -static GSList *g_slist_new(void *data) { - GSList *new; - new = malloc(sizeof(GSList)); - if (!new) return NULL; - new->next = NULL; - new->data = data; - return new; -} - -/* Insert new data before given position */ -GSList *g_slist_insert_before(GSList *list, GSList *before, void *data) { - GSList *elem = g_slist_new(data); - GSList *iter; - if (!elem) return list; - if (!list) return elem; - elem->next = before; - if (before == list) return elem; - for (iter = list; iter; iter = iter->next) { - if (!iter->next || iter->next == before) { - iter->next = elem; - break; - } - } - return list; -} - -/* Add new data to head of list */ -GSList *g_slist_prepend(GSList *list, void *data) { - return g_slist_insert_before(list, list, data); -} - -/* Add new data to tail of list */ -GSList *g_slist_append(GSList *list, void *data) { - return g_slist_insert_before(list, NULL, data); -} - -GSList *g_slist_concat(GSList *list1, GSList *list2) { - if (!list1) return list2; - if (!list2) return list1; - GSList *iter; - for (iter = list1; iter->next; iter = iter->next); - iter->next = list2; - return list1; -} - -void g_slist_foreach(GSList *list, GFunc func, gpointer user_data) { - GSList *iter; - for (iter = list; iter; iter = iter->next) { - func(iter->data, user_data); - } -} - -/* Using compare function, insert item at appropriate place in list */ -GSList *g_slist_insert_sorted(GSList *list, gpointer data, GCompareFunc func) { - GSList *elem; - if (!func) - return g_slist_prepend(list, data); - for (elem = list; elem; elem = elem->next) { - if (func(data, elem->data) <= 0) - break; - } - return g_slist_insert_before(list, elem, data); -} - -/* Delete list element containing data */ -GSList *g_slist_remove(GSList *list, void *data) { - GSList **elemp; - if (!data) return list; - for (elemp = &list; *elemp; elemp = &(*elemp)->next) { - if ((*elemp)->data == data) break; - } - if (*elemp) { - GSList *elem = *elemp; - *elemp = elem->next; - free(elem); - } - return list; -} - -/* Move existing list element containing data to head of list */ -GSList *g_slist_to_head(GSList *list, void *data) { - if (!data) return list; - list = g_slist_remove(list, data); - return g_slist_prepend(list, data); -} - -/* Move existing list element containing data to tail of list */ -GSList *g_slist_to_tail(GSList *list, void *data) { - if (!data) return list; - list = g_slist_remove(list, data); - return g_slist_append(list, data); -} - -/* Find list element containing data */ -GSList *g_slist_find(GSList *list, gconstpointer data) { - GSList *elem; - for (elem = list; elem; elem = elem->next) { - if (elem->data == data) - return elem; - } - return NULL; -} - -/* Find list element containing data */ -GSList *g_slist_find_custom(GSList *list, gconstpointer data, GCompareFunc func) { - GSList *elem; - for (elem = list; elem; elem = elem->next) { - if (func(elem->data, data) == 0) - return elem; - } - return NULL; -} diff -Nru xroar-0.31.1/portalib/pl_glib/gslist.h xroar-0.32/portalib/pl_glib/gslist.h --- xroar-0.31.1/portalib/pl_glib/gslist.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/portalib/pl_glib/gslist.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -/* - * pl_glib is a set of public domain work-a-likes for some GLib functions and - * macros. It is not even slightly close to a complete reimplementation of - * GLib. - * - * Singly-linked lists. - */ - -#ifndef PL_GSLIST_H_ -#define PL_GSLIST_H_ - -struct GSList; -typedef struct GSList GSList; - -struct GSList { - GSList *next; - void *data; -}; - -/* Each of these return the new pointer to the head of the list: */ -GSList *g_slist_insert_before(GSList *list, GSList *before, void *data); -GSList *g_slist_prepend(GSList *list, void *data); -GSList *g_slist_append(GSList *list, void *data); -GSList *g_slist_concat(GSList *list1, GSList *list2); -void g_slist_foreach(GSList *list, GFunc func, gpointer user_data); -GSList *g_slist_insert_sorted(GSList *list, gpointer data, GCompareFunc func); -GSList *g_slist_remove(GSList *list, void *data); -GSList *g_slist_to_head(GSList *list, void *data); -GSList *g_slist_to_tail(GSList *list, void *data); - -/* Returns element in list: */ -GSList *g_slist_find(GSList *list, gconstpointer data); -GSList *g_slist_find_custom(GSList *list, gconstpointer data, GCompareFunc func); - -#define g_slist_next(slist) ((slist) ? (((GSList *)(slist))->next) : NULL) - -#endif /* def PL_GSLIST_H_ */ diff -Nru xroar-0.31.1/portalib/pl_glib/gstrfuncs.c xroar-0.32/portalib/pl_glib/gstrfuncs.c --- xroar-0.31.1/portalib/pl_glib/gstrfuncs.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/portalib/pl_glib/gstrfuncs.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/* - * pl_glib is a set of public domain work-a-likes for some GLib functions and - * macros. It is not even slightly close to a complete reimplementation of - * GLib. - * - * String utility functions. - */ - -#include "config.h" - -#include -#include -#include - -#include "pl_glib.h" - -gchar *g_strdup(const gchar *str) { - if (!str) return NULL; - gsize len = strlen(str); - return g_memdup(str, len + 1); -} - -gint g_ascii_strcasecmp(const gchar *s1, const gchar *s2) { - if (!s1 || !s2) - return 0; - while (*s1 && *s2 && (*s1 == *s2 || g_ascii_tolower(*s1) == g_ascii_tolower(*s2))) { - s1++; - s2++; - } - return g_ascii_tolower(*s1) - g_ascii_tolower(*s2); -} - -gint g_ascii_strncasecmp(const gchar *s1, const gchar *s2, gsize n) { - if (!s1 || !s2) - return 0; - while (n > 0 && *s1 && *s2 && - (*s1 == *s2 || g_ascii_tolower(*s1) == g_ascii_tolower(*s2))) { - s1++; - s2++; - n--; - } - return (n == 0) ? 0 : g_ascii_tolower(*s1) - g_ascii_tolower(*s2); -} - -gchar g_ascii_tolower(gchar c) { - if (g_ascii_isupper(c)) - return c | 0x20; - return c; -} - -gchar g_ascii_toupper(gchar c) { - if (g_ascii_islower(c)) - return c & ~0x20; - return c; -} diff -Nru xroar-0.31.1/portalib/pl_glib/gstrfuncs.h xroar-0.32/portalib/pl_glib/gstrfuncs.h --- xroar-0.31.1/portalib/pl_glib/gstrfuncs.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/portalib/pl_glib/gstrfuncs.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -/* - * pl_glib is a set of public domain work-a-likes for some GLib functions and - * macros. It is not even slightly close to a complete reimplementation of - * GLib. - * - * String utility functions. - */ - -#ifndef PL_GLIB_GSTRFUNCS_H_ -#define PL_GLIB_GSTRFUNCS_H_ - -#include "pl_glib/gtypes.h" - -gchar *g_strdup(const gchar *str); -gint g_ascii_strcasecmp(const gchar *s1, const gchar *s2); -gint g_ascii_strncasecmp(const gchar *s1, const gchar *s2, gsize n); -gchar g_ascii_tolower(gchar c); -gchar g_ascii_toupper(gchar c); - -static inline gboolean g_ascii_islower(gchar c) { - return (c >= 'a' && c <= 'z'); -} - -static inline gboolean g_ascii_isupper(gchar c) { - return (c >= 'A' && c <= 'Z'); -} - -#endif /* def PL_GLIB_GSTRFUNCS_H_ */ diff -Nru xroar-0.31.1/portalib/pl_glib/gtypes.h xroar-0.32/portalib/pl_glib/gtypes.h --- xroar-0.31.1/portalib/pl_glib/gtypes.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/portalib/pl_glib/gtypes.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/* - * pl_glib is a set of public domain work-a-likes for some GLib functions and - * macros. It is not even slightly close to a complete reimplementation of - * GLib. - * - * This header defines types and macros used throughout. Most GLib types are - * just aliases to standard C types. - */ - -#ifndef PL_GLIB_GTYPES_H_ -#define PL_GLIB_GTYPES_H_ - -#ifndef FALSE -#define FALSE (0) -#endif - -#ifndef TRUE -#define TRUE (!FALSE) -#endif - -#define G_N_ELEMENTS(arr) (sizeof(arr)/sizeof((arr)[0])) - -typedef char gchar; -typedef short gshort; -typedef long glong; -typedef int gint; -typedef int gboolean; - -typedef unsigned char guchar; -typedef unsigned short gushort; -typedef unsigned long gulong; -typedef unsigned int guint; - -typedef void *gpointer; -typedef const void *gconstpointer; - -typedef unsigned long gsize; - -typedef gint (*GCompareFunc)(gconstpointer a, gconstpointer b); -typedef gboolean (*GEqualFunc)(gconstpointer a, gconstpointer b); -typedef void (*GFunc)(gpointer data, gpointer user_data); -typedef guint (*GHashFunc)(gconstpointer key); -typedef void (*GHFunc)(gpointer key, gpointer value, gpointer user_data); - -#endif /* def PL_GLIB_GTYPES_H_ */ diff -Nru xroar-0.31.1/portalib/pl_glib.h xroar-0.32/portalib/pl_glib.h --- xroar-0.31.1/portalib/pl_glib.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/portalib/pl_glib.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -/* - * pl_glib is a set of public domain work-a-likes for some GLib functions and - * macros. It is not even slightly close to a complete reimplementation of - * GLib. - * - * This header will simply wrap the normal GLib headers if HAVE_GLIB2 is - * defined. - * - * On systems with GLib, use GLib. For others, this lets you use some GLib - * functions without delving into the crazy world of GLib circular - * dependencies. - */ - -#ifndef PL_GLIB_H_ -#define PL_GLIB_H_ - -#include "config.h" - -#ifdef HAVE_GLIB2 -#include -#endif - -#ifndef HAVE_GLIB2 -/* Common macros, typedefs, etc. */ -#include "pl_glib/gtypes.h" - -/* Data types */ -#include "pl_glib/gslist.h" - -/* Utilities */ -#include "pl_glib/galloca.h" -#include "pl_glib/gmem.h" -#include "pl_glib/gstrfuncs.h" -#endif - -#endif /* PL_GLIB_H_ */ diff -Nru xroar-0.31.1/portalib/pl_string.h xroar-0.32/portalib/pl_string.h --- xroar-0.31.1/portalib/pl_string.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/portalib/pl_string.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -/* - * pl_string.h supplies prototypes for string utility functions that were found - * not to be supported by the target's libc. - * - * It is still necessary to define the appropriate feature macro (e.g., - * _BSD_SOURCE) before inclusion to get the right set of prototypes. - * - * Of course there's only one function here so far, so that doesn't mean much. - */ - -#ifndef PL_STRING_H_ -#define PL_STRING_H_ - -#include "config.h" - -#ifdef _BSD_SOURCE - -#ifdef NEED_STRSEP -char *strsep(char **, const char *); -#endif - -#endif - -#endif /* PL_STRING_H_ */ diff -Nru xroar-0.31.1/portalib/pl-string.h xroar-0.32/portalib/pl-string.h --- xroar-0.31.1/portalib/pl-string.h 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/pl-string.h 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,32 @@ +/* + +Missing string handling functions +Copyright 2012-2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +Supplies prototypes for string utility functions that were found to be +missing in the target's libc. + +It is still necessary to define the appropriate feature macro (e.g., +_BSD_SOURCE) before inclusion to get the right set of prototypes. + +*/ + +#ifndef PL_STRING_H__7RCESJQ89DzWE +#define PL_STRING_H__7RCESJQ89DzWE + +#include "config.h" + +#ifdef _BSD_SOURCE + +#ifdef NEED_STRSEP +char *strsep(char **, const char *); +#endif + +#endif + +#endif /* PL_STRING_H__7RCESJQ89DzWE */ diff -Nru xroar-0.31.1/portalib/slist.c xroar-0.32/portalib/slist.c --- xroar-0.31.1/portalib/slist.c 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/slist.c 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,203 @@ +/* + +Singly linked lists +Copyright 2009-2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +*/ + +#include "config.h" + +#include + +#include "slist.h" +#include "xalloc.h" + +/* Wrap data in a new list container */ +static struct slist *slist_new(void *data) { + struct slist *new = malloc(sizeof(*new)); + if (!new) return NULL; + new->next = NULL; + new->data = data; + return new; +} + +/* Add new data to tail of list */ +struct slist *slist_append(struct slist *list, void *data) { + return slist_insert_before(list, NULL, data); +} + +/* Add new data to head of list */ +struct slist *slist_prepend(struct slist *list, void *data) { + return slist_insert_before(list, list, data); +} + +/* Insert new data before given position */ +struct slist *slist_insert_before(struct slist *list, struct slist *before, void *data) { + struct slist *ent = slist_new(data); + struct slist *iter; + if (!ent) return list; + if (!list) return ent; + ent->next = before; + if (before == list) return ent; + for (iter = list; iter; iter = iter->next) { + if (!iter->next || iter->next == before) { + iter->next = ent; + break; + } + } + return list; +} + +/* Remove list entry containing data. */ +struct slist *slist_remove(struct slist *list, void *data) { + struct slist **entp; + if (!data) return list; + for (entp = &list; *entp; entp = &(*entp)->next) { + if ((*entp)->data == data) break; + } + if (*entp) { + struct slist *ent = *entp; + *entp = ent->next; + free(ent); + } + return list; +} + +/* Free entire list (not data). */ +void slist_free(struct slist *list) { + slist_free_full(list, NULL); +} + +/* Free entire list, calling function to free data. */ +void slist_free_full(struct slist *list, slist_free_func free_func) { + while (list) { + struct slist *next = list->next; + if (free_func && list->data) + free_func(list->data); + free(list); + list = next; + } +} + +/* Free one list element. */ +void slist_free_1(struct slist *list) { + free(list); +} + +/* Copy a list, new elements reference same data. */ +struct slist *slist_copy(struct slist *list) { + struct slist *new = NULL; + struct slist **entp = &new; + for (; list; list = list->next) { + *entp = slist_new(list->data); + entp = &(*entp)->next; + } + return new; +} + +/* Copy a list, new elements are copied with user function. */ +struct slist *slist_copy_deep(struct slist *list, slist_copy_func copy_func, void *copy_data) { + struct slist *new = slist_copy(list); + for (struct slist *l = new; l; l = l->next) { + l->data = copy_func(l->data, copy_data); + } + return new; +} + +/* Helper function for slist_sort(). Merges left and right into a single + * sorted list, assuming inputs are sorted. In-place. */ +static struct slist *slist_merge(struct slist *left, struct slist *right, slist_cmp_func cmp_func) { + struct slist *new = NULL; + struct slist **newp = &new; + while (left || right) { + if (left && right) { + if (cmp_func(left->data, right->data) <= 0) { + *newp = left; + left = left->next; + } else { + *newp = right; + right = right->next; + } + } else if (left) { + *newp = left; + left = left->next; + } else { + *newp = right; + right = right->next; + } + newp = &(*newp)->next; + } + *newp = NULL; + return new; +} + +/* Sort list in-place, the old list order is lost. */ + +/* In-place merge sort. This part breaks the list into trivially + * sorted lists on the heap, then calls slist_merge() to merge the result. */ +struct slist *slist_sort(struct slist *list, slist_cmp_func cmp_func) { + if (!list || !list->next) + return list; + struct slist *left = NULL; + struct slist **leftp = &left; + struct slist *right = NULL; + struct slist **rightp = &right; + while (list) { + *leftp = list; + list = list->next; + leftp = &(*leftp)->next; + if (list) { + *rightp = list; + list = list->next; + rightp = &(*rightp)->next; + } + } + *leftp = *rightp = NULL; + left = slist_sort(left, cmp_func); + right = slist_sort(right, cmp_func); + return slist_merge(left, right, cmp_func); +} + +/* Attach head of one list to the end of another (no copying). */ +struct slist *slist_concat(struct slist *list1, struct slist *list2) { + if (!list2) + return list1; + if (!list1) + return list2; + while (list1->next) + list1 = list1->next; + list1->next = list2; + return list1; +} + +/* Call a user function for each member of the list. */ +void slist_foreach(struct slist *list, slist_iter_func iter_func, void *data) { + struct slist *ent; + for (ent = list; ent; ent = ent->next) + iter_func(ent->data, data); +} + +/* Find element with exactly the supplied data (pointer compare). */ +struct slist *slist_find(struct slist *list, const void *data) { + struct slist *ent; + for (ent = list; ent; ent = ent->next) { + if (ent->data == data) + return ent; + } + return NULL; +} + +/* Find element using compare function against supplied data. */ +struct slist *slist_find_custom(struct slist *list, const void *data, slist_cmp_func cmp_func) { + struct slist *ent; + for (ent = list; ent; ent = ent->next) { + if (cmp_func(ent->data, data) == 0) + return ent; + } + return NULL; +} diff -Nru xroar-0.31.1/portalib/slist.h xroar-0.32/portalib/slist.h --- xroar-0.31.1/portalib/slist.h 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/slist.h 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,79 @@ +/* + +Singly linked lists +Copyright 2009-2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +A simple singly-linked list implementation. The interfaces are similar +to other such implementations, but are implemented from scratch. A list +is simply a pointer to its first member. In general, functions returning +a list are returning the new head of the list after an operation has +been performed. Exceptions to this include copying. + +*/ + +#ifndef SLIST_H__chqkIizgkKbjw +#define SLIST_H__chqkIizgkKbjw + +/* Each list element is of this deliberately transparent type. */ +struct slist { + struct slist *next; + void *data; +}; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* Some operations want a user function as an argument. Use these prototypes, + * and cast accordingly. */ + +/* Used by iterators. First arg is element data, second is user supplied. */ +typedef void (*slist_iter_func)(void *, void *); + +/* Used by slist_free_full() to free element data. */ +typedef void (*slist_free_func)(void *); + +/* Used by slist_copy_deep() to copy element data. */ +typedef void *(*slist_copy_func)(const void *, void *); + +/* Compare two structures, return <0, 0 or >0. Used in sorting and finding. */ +typedef int (*slist_cmp_func)(const void *, const void *); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* Each of these return the new pointer to the head of the list. */ +struct slist *slist_append(struct slist *, void *); +struct slist *slist_prepend(struct slist *, void *); +struct slist *slist_insert_before(struct slist *, struct slist *, void *); +struct slist *slist_remove(struct slist *, void *); + +/* Free entire list (not data). */ +void slist_free(struct slist *); +/* Free entire list, calling function to free data. */ +void slist_free_full(struct slist *, slist_free_func); +/* Free one list element. */ +void slist_free_1(struct slist *); + +/* Copy a list, new elements reference same data. */ +struct slist *slist_copy(struct slist *); +/* Copy a list, new elements are copied with user function. */ +struct slist *slist_copy_deep(struct slist *, slist_copy_func, void *); + +/* Sort list in-place, the old list order is lost. */ +struct slist *slist_sort(struct slist *, slist_cmp_func); + +/* Attach head of one list to the end of another (no copying). */ +struct slist *slist_concat(struct slist *, struct slist *); + +/* Call a user function for each member of the list. */ +void slist_foreach(struct slist *, slist_iter_func, void *); + +/* Find element with exactly the supplied data (pointer compare). */ +struct slist *slist_find(struct slist *, const void *); +/* Find element using compare function against supplied data. */ +struct slist *slist_find_custom(struct slist *, const void *, slist_cmp_func); + +#endif /* SLIST_H__chqkIizgkKbjw */ diff -Nru xroar-0.31.1/portalib/strsep.c xroar-0.32/portalib/strsep.c --- xroar-0.31.1/portalib/strsep.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/portalib/strsep.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,16 +1,20 @@ -/* Taken from musl libc v0.8.10, © 2005-2012 Rich Felker. */ +/* -/* This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - */ +Taken from musl libc v0.8.10 +Copyright 2005-2012 Rich Felker + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +*/ #include "config.h" #include -#include "pl_string.h" +#include "pl-string.h" #ifdef NEED_STRSEP char *strsep(char **str, const char *sep) { diff -Nru xroar-0.31.1/portalib/xalloc.h xroar-0.32/portalib/xalloc.h --- xroar-0.31.1/portalib/xalloc.h 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/xalloc.h 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,28 @@ +/* + +Memory allocation with checking +Copyright 2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +A small set of convenience functions that wrap standard system calls and +provide out of memory checking. See Gnulib for a far more complete set. + +*/ + +#ifndef XALLOC_H__yqbm4hifLvT2k +#define XALLOC_H__yqbm4hifLvT2k + +#include + +void *xmalloc(size_t s); +void *xzalloc(size_t s); +void *xrealloc(void *p, size_t s); + +void *xmemdup(const void *p, size_t s); +char *xstrdup(const char *str); + +#endif /* XALLOC_H__yqbm4hifLvT2k */ diff -Nru xroar-0.31.1/portalib/xmalloc.c xroar-0.32/portalib/xmalloc.c --- xroar-0.31.1/portalib/xmalloc.c 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/portalib/xmalloc.c 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,55 @@ +/* + +Memory allocation with checking +Copyright 2014, Ciaran Anscomb + +This is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +*/ + +#include "config.h" + +#include +#include +#include + +#include "xalloc.h" + +void *xmalloc(size_t s) { + void *mem = malloc(s); + if (!mem) { + perror(NULL); + exit(EXIT_FAILURE); + } + return mem; +} + +void *xzalloc(size_t s) { + void *mem = xmalloc(s); + memset(mem, 0, s); + return mem; +} + +void *xrealloc(void *p, size_t s) { + void *mem = realloc(p, s); + if (!mem && s != 0) { + perror(NULL); + exit(EXIT_FAILURE); + } + return mem; +} + +void *xmemdup(const void *p, size_t s) { + if (!p) + return NULL; + void *mem = xmalloc(s); + memcpy(mem, p, s); + return mem; +} + +char *xstrdup(const char *str) { + return xmemdup(str, strlen(str) + 1); +} diff -Nru xroar-0.31.1/README xroar-0.32/README --- xroar-0.31.1/README 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/README 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ XRoar - a Dragon/Tandy Coco emulator -Copyright 2003-2013 Ciaran Anscomb +Copyright 2003-2014 Ciaran Anscomb XRoar is a Dragon emulator that runs on a wide variety of platforms. @@ -112,8 +112,8 @@ Once you have the dependencies, building XRoar follows a familiar procedure: - $ gzip -dc xroar-0.31.1.tar.gz | tar xvf - - $ cd xroar-0.31.1 + $ gzip -dc xroar-0.32.tar.gz | tar xvf - + $ cd xroar-0.32 $ ./configure $ make $ sudo make install diff -Nru xroar-0.31.1/src/alsa/ao_alsa.c xroar-0.32/src/alsa/ao_alsa.c --- xroar-0.31.1/src/alsa/ao_alsa.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/alsa/ao_alsa.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -28,7 +28,7 @@ #include -#include "pl_glib.h" +#include "xalloc.h" #include "events.h" #include "logging.h" @@ -56,7 +56,34 @@ const char *device = xroar_cfg.ao_device ? xroar_cfg.ao_device : "default"; int err; snd_pcm_hw_params_t *hw_params; - snd_pcm_format_t format = SND_PCM_FORMAT_S16; + snd_pcm_format_t format; + + switch (xroar_cfg.ao_format) { + case SOUND_FMT_U8: + format = SND_PCM_FORMAT_U8; + break; + case SOUND_FMT_S8: + format = SND_PCM_FORMAT_S8; + break; + case SOUND_FMT_S16_BE: + format = SND_PCM_FORMAT_S16_BE; + break; + case SOUND_FMT_S16_LE: + format = SND_PCM_FORMAT_S16_LE; + break; + case SOUND_FMT_S16_HE: default: + format = SND_PCM_FORMAT_S16; + break; + case SOUND_FMT_S16_SE: + if (SND_PCM_FORMAT_S16 == SND_PCM_FORMAT_S16_LE) + format = SND_PCM_FORMAT_S16_BE; + else + format = SND_PCM_FORMAT_S16_LE; + break; + case SOUND_FMT_FLOAT: + format = SND_PCM_FORMAT_FLOAT; + break; + } unsigned nchannels = xroar_cfg.ao_channels; if (nchannels < 1 || nchannels > 2) nchannels = 2; @@ -84,7 +111,6 @@ if ((err = snd_pcm_hw_params_set_channels_near(pcm_handle, hw_params, &nchannels)) < 0) goto failed; - snd_pcm_uframes_t buffer_nframes = 0; fragment_nframes = 0; if (xroar_cfg.ao_fragment_ms > 0) { fragment_nframes = (rate * xroar_cfg.ao_fragment_ms) / 1000; @@ -96,8 +122,6 @@ LOG_ERROR("ALSA: snd_pcm_hw_params_set_period_size_near() failed\n"); goto failed; } - } else { - buffer_nframes = 1024; } unsigned nfragments = 0; @@ -112,11 +136,15 @@ } } + snd_pcm_uframes_t buffer_nframes = 0; if (xroar_cfg.ao_buffer_ms > 0) { buffer_nframes = (rate * xroar_cfg.ao_buffer_ms) / 1000; } else if (xroar_cfg.ao_buffer_nframes > 0) { buffer_nframes = xroar_cfg.ao_buffer_nframes; } + /* Pick a sensible default: */ + if (nfragments == 0 && buffer_nframes == 0) + buffer_nframes = (rate * 20) / 1000; if (buffer_nframes > 0) { if ((err = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hw_params, &buffer_nframes)) < 0) { LOG_ERROR("ALSA: snd_pcm_hw_params_set_buffer_size_near() failed\n"); @@ -176,15 +204,19 @@ buffer_fmt = SOUND_FMT_S16_BE; sample_nbytes = 2; break; + case SND_PCM_FORMAT_FLOAT: + buffer_fmt = SOUND_FMT_FLOAT; + sample_nbytes = sizeof(float); + break; default: LOG_ERROR("Unhandled audio format.\n"); goto failed; } unsigned buffer_size = fragment_nframes * nchannels * sample_nbytes; - audio_buffer = g_malloc(buffer_size); + audio_buffer = xmalloc(buffer_size); sound_init(audio_buffer, buffer_fmt, rate, nchannels, fragment_nframes); - LOG_DEBUG(2, "\t%u frags * %ld frames/frag = %ld frames buffer (%ldms)\n", nfragments, fragment_nframes, buffer_nframes, (buffer_nframes * 1000) / rate); + LOG_DEBUG(1, "\t%u frags * %ld frames/frag = %ld frames buffer (%ldms)\n", nfragments, fragment_nframes, buffer_nframes, (buffer_nframes * 1000) / rate); /* snd_pcm_writei(pcm_handle, buffer, fragment_nframes); */ return 1; @@ -195,7 +227,7 @@ static void shutdown(void) { snd_pcm_close(pcm_handle); - g_free(audio_buffer); + free(audio_buffer); } static void *write_buffer(void *buffer) { diff -Nru xroar-0.31.1/src/ao_null.c xroar-0.32/src/ao_null.c --- xroar-0.31.1/src/ao_null.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/ao_null.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * diff -Nru xroar-0.31.1/src/becker.c xroar-0.32/src/becker.c --- xroar-0.31.1/src/becker.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/becker.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -73,7 +73,7 @@ _Bool becker_open(void) { struct addrinfo hints, *info; - const char *hostname = xroar_cfg.becker_ip ? xroar_cfg.becker_ip : "localhost"; + const char *hostname = xroar_cfg.becker_ip ? xroar_cfg.becker_ip : "127.0.0.1"; const char *portname = xroar_cfg.becker_port ? xroar_cfg.becker_port : "65504"; // Find the server diff -Nru xroar-0.31.1/src/becker.h xroar-0.32/src/becker.h --- xroar-0.31.1/src/becker.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/becker.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/breakpoint.c xroar-0.32/src/breakpoint.c --- xroar-0.31.1/src/breakpoint.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/breakpoint.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -22,7 +22,8 @@ #include #include -#include "pl_glib.h" +#include "slist.h" +#include "xalloc.h" #include "breakpoint.h" #include "crclist.h" @@ -32,20 +33,20 @@ #include "sam.h" #include "xroar.h" -static GSList *bp_instruction_list = NULL; +static struct slist *bp_instruction_list = NULL; -static GSList *wp_read_list = NULL; -static GSList *wp_write_list = NULL; -static GSList *wp_access_list = NULL; +static struct slist *wp_read_list = NULL; +static struct slist *wp_write_list = NULL; +static struct slist *wp_access_list = NULL; -static GSList *iter_next = NULL; +static struct slist *iter_next = NULL; -static void bp_instruction_hook(void *dptr); +static void bp_instruction_hook(void *); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static _Bool is_in_list(GSList *bp_list, struct breakpoint *bp) { - for (GSList *iter = bp_list; iter; iter = iter->next) { +static _Bool is_in_list(struct slist *bp_list, struct breakpoint *bp) { + for (struct slist *iter = bp_list; iter; iter = iter->next) { if (bp == iter->data) return 1; } @@ -56,10 +57,9 @@ if (is_in_list(bp_instruction_list, bp)) return; bp->address_end = bp->address; - bp_instruction_list = g_slist_prepend(bp_instruction_list, bp); + bp_instruction_list = slist_prepend(bp_instruction_list, bp); struct MC6809 *cpu = machine_get_cpu(0); - cpu->instruction_hook = bp_instruction_hook; - cpu->instr_hook_dptr = cpu; + cpu->instruction_hook = DELEGATE_AS0(void, bp_instruction_hook, cpu); } void bp_add_n(struct breakpoint *bp, int n) { @@ -82,10 +82,10 @@ void bp_remove(struct breakpoint *bp) { if (iter_next && iter_next->data == bp) iter_next = iter_next->next; - bp_instruction_list = g_slist_remove(bp_instruction_list, bp); + bp_instruction_list = slist_remove(bp_instruction_list, bp); if (!bp_instruction_list) { struct MC6809 *cpu = machine_get_cpu(0); - cpu->instruction_hook = NULL; + cpu->instruction_hook.func = NULL; } } @@ -96,9 +96,9 @@ } } -static struct breakpoint *trap_find(GSList *bp_list, unsigned addr, unsigned addr_end, +static struct breakpoint *trap_find(struct slist *bp_list, unsigned addr, unsigned addr_end, unsigned match_mask, unsigned match_cond) { - for (GSList *iter = bp_list; iter; iter = iter->next) { + for (struct slist *iter = bp_list; iter; iter = iter->next) { struct breakpoint *bp = iter->data; if (bp->address == addr && bp->address_end == addr_end && bp->match_mask == match_mask @@ -109,27 +109,27 @@ return NULL; } -static void trap_add(GSList **bp_list, unsigned addr, unsigned addr_end, +static void trap_add(struct slist **bp_list, unsigned addr, unsigned addr_end, unsigned match_mask, unsigned match_cond) { if (trap_find(*bp_list, addr, addr_end, match_mask, match_cond)) return; - struct breakpoint *new = g_malloc(sizeof(*new)); + struct breakpoint *new = xmalloc(sizeof(*new)); new->match_mask = match_mask; new->match_cond = match_cond; new->address = addr; new->address_end = addr_end; new->handler = xroar_machine_trap; - *bp_list = g_slist_prepend(*bp_list, new); + *bp_list = slist_prepend(*bp_list, new); } -static void trap_remove(GSList **bp_list, unsigned addr, unsigned addr_end, +static void trap_remove(struct slist **bp_list, unsigned addr, unsigned addr_end, unsigned match_mask, unsigned match_cond) { struct breakpoint *bp = trap_find(*bp_list, addr, addr_end, match_mask, match_cond); if (bp) { if (iter_next && iter_next->data == bp) iter_next = iter_next->next; - *bp_list = g_slist_remove(*bp_list, bp); - g_free(bp); + *bp_list = slist_remove(*bp_list, bp); + free(bp); } } @@ -137,8 +137,7 @@ trap_add(&bp_instruction_list, addr, addr, match_mask, match_cond); if (bp_instruction_list) { struct MC6809 *cpu = machine_get_cpu(0); - cpu->instruction_hook = bp_instruction_hook; - cpu->instr_hook_dptr = cpu; + cpu->instruction_hook = DELEGATE_AS0(void, bp_instruction_hook, cpu); } } @@ -146,7 +145,7 @@ trap_remove(&bp_instruction_list, addr, addr, match_mask, match_cond); if (!bp_instruction_list) { struct MC6809 *cpu = machine_get_cpu(0); - cpu->instruction_hook = NULL; + cpu->instruction_hook.func = NULL; } } @@ -188,10 +187,10 @@ * addded to a new list for dispatch, as the handler may call routines that * alter the original list. */ -static void bp_hook(GSList *bp_list, unsigned address) { +static void bp_hook(struct slist *bp_list, unsigned address) { unsigned sam_register = sam_get_register(); unsigned cond = sam_register & 0x8400; - for (GSList *iter = bp_list; iter; iter = iter_next) { + for (struct slist *iter = bp_list; iter; iter = iter_next) { iter_next = iter->next; struct breakpoint *bp = iter->data; if ((cond & bp->match_mask) != bp->match_cond) @@ -205,8 +204,8 @@ iter_next = NULL; } -static void bp_instruction_hook(void *dptr) { - struct MC6809 *cpu = dptr; +static void bp_instruction_hook(void *sptr) { + struct MC6809 *cpu = sptr; uint16_t old_pc; do { old_pc = cpu->reg_pc; diff -Nru xroar-0.31.1/src/breakpoint.h xroar-0.32/src/breakpoint.h --- xroar-0.31.1/src/breakpoint.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/breakpoint.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/cart.c xroar-0.32/src/cart.c --- xroar-0.31.1/src/cart.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/cart.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -24,10 +24,13 @@ #include #include -#include "pl_glib.h" +#include "array.h" +#include "slist.h" +#include "xalloc.h" #include "cart.h" #include "crc32.h" +#include "delegate.h" #include "deltados.h" #include "dragondos.h" #include "events.h" @@ -38,7 +41,7 @@ #include "rsdos.h" #include "xroar.h" -static GSList *config_list = NULL; +static struct slist *config_list = NULL; static int num_configs = 0; /* Single config for auto-defined ROM carts */ @@ -54,11 +57,11 @@ struct cart_config *cart_config_new(void) { struct cart_config *new; - new = g_malloc0(sizeof(*new)); + new = xzalloc(sizeof(*new)); new->index = num_configs; new->type = CART_ROM; new->autorun = ANY_AUTO; - config_list = g_slist_append(config_list, new); + config_list = slist_append(config_list, new); num_configs++; return new; } @@ -68,7 +71,7 @@ } struct cart_config *cart_config_index(int i) { - for (GSList *l = config_list; l; l = l->next) { + for (struct slist *l = config_list; l; l = l->next) { struct cart_config *cc = l->data; if (cc->index == i) return cc; @@ -78,7 +81,7 @@ struct cart_config *cart_config_by_name(const char *name) { if (!name) return NULL; - for (GSList *l = config_list; l; l = l->next) { + for (struct slist *l = config_list; l; l = l->next) { struct cart_config *cc = l->data; if (0 == strcmp(cc->name, name)) { return cc; @@ -91,13 +94,13 @@ if (!(rom_cart_config = cart_config_new())) { return NULL; } - rom_cart_config->name = g_strdup("romcart"); + rom_cart_config->name = xstrdup("romcart"); } if (rom_cart_config->description) { - g_free(rom_cart_config->description); + free(rom_cart_config->description); } /* Make up a description from filename */ - char *tmp_name = g_alloca(strlen(name) + 1); + char tmp_name[strlen(name) + 1]; strcpy(tmp_name, name); char *bname = basename(tmp_name); if (bname && *bname) { @@ -112,13 +115,13 @@ break; } } - rom_cart_config->description = g_strdup(bname); + rom_cart_config->description = xstrdup(bname); } else { - rom_cart_config->description = g_strdup("ROM cartridge"); + rom_cart_config->description = xstrdup("ROM cartridge"); } rom_cart_config->type = CART_ROM; - if (rom_cart_config->rom) g_free(rom_cart_config->rom); - rom_cart_config->rom = g_strdup(name); + if (rom_cart_config->rom) free(rom_cart_config->rom); + rom_cart_config->rom = xstrdup(name); rom_cart_config->autorun = 1; return rom_cart_config; } @@ -144,13 +147,13 @@ } } if (tmp) - g_free(tmp); + free(tmp); return cc; } void cart_config_complete(struct cart_config *cc) { if (!cc->description) { - cc->description = g_strdup(cc->name); + cc->description = xstrdup(cc->name); } if (cc->autorun == ANY_AUTO) { if (cc->type == CART_ROM) { @@ -161,7 +164,7 @@ } } -static const char *cart_type_string[] = { +static char const * const cart_type_string[] = { "rom", "dragondos", "rsdos", @@ -170,11 +173,11 @@ }; void cart_config_print_all(void) { - for (GSList *l = config_list; l; l = l->next) { + for (struct slist *l = config_list; l; l = l->next) { struct cart_config *cc = l->data; printf("cart %s\n", cc->name); if (cc->description) printf(" cart-desc %s\n", cc->description); - if (cc->type >= 0 && cc->type < G_N_ELEMENTS(cart_type_string)) + if (cc->type >= 0 && cc->type < ARRAY_N_ELEMENTS(cart_type_string)) printf(" cart-type %s\n", cart_type_string[cc->type]); if (cc->rom) printf(" cart-rom %s\n", cc->rom); if (cc->rom2) printf(" cart-rom2 %s\n", cc->rom2); @@ -190,7 +193,7 @@ struct cart *cart_new(struct cart_config *cc) { if (!cc) return NULL; if (cc->description) { - LOG_DEBUG(2, "Cartridge: %s\n", cc->description); + LOG_DEBUG(1, "Cartridge: %s\n", cc->description); } cart_config_complete(cc); struct cart *c; @@ -216,7 +219,7 @@ if (!c) return; if (c->detach) c->detach(c); - g_free(c); + free(c); } /* ROM cart routines */ @@ -232,37 +235,43 @@ c->attach = dummy_cart; c->detach = cart_rom_detach; c->attach = cart_rom_attach; - c->rom_data = g_malloc0(0x4000); + c->rom_data = xzalloc(0x4000); if (cc->rom) { char *tmp = romlist_find(cc->rom); if (tmp) { int size = machine_load_rom(tmp, c->rom_data, 0x4000); + (void)size; // avoid warnings if... +#ifdef LOGGING if (size > 0) { uint32_t crc = crc32_block(CRC32_RESET, c->rom_data, size); - LOG_DEBUG(2, "\tCRC = 0x%08x\n", crc); + LOG_DEBUG(1, "\tCRC = 0x%08x\n", crc); } - g_free(tmp); +#endif + free(tmp); } } if (cc->rom2) { char *tmp = romlist_find(cc->rom2); if (tmp) { int size = machine_load_rom(tmp, c->rom_data + 0x2000, 0x2000); + (void)size; // avoid warnings if... +#ifdef LOGGING if (size > 0) { uint32_t crc = crc32_block(CRC32_RESET, c->rom_data + 0x2000, size); - LOG_DEBUG(2, "\tCRC = 0x%08x\n", crc); + LOG_DEBUG(1, "\tCRC = 0x%08x\n", crc); } - g_free(tmp); +#endif + free(tmp); } } - c->signal_firq = (cart_signal_delegate){ NULL, NULL }; - c->signal_nmi = (cart_signal_delegate){ NULL, NULL }; - c->signal_halt = (cart_signal_delegate){ NULL, NULL }; + c->signal_firq = DELEGATE_DEFAULT1(void, bool); + c->signal_nmi = DELEGATE_DEFAULT1(void, bool); + c->signal_halt = DELEGATE_DEFAULT1(void, bool); } struct cart *cart_rom_new(struct cart_config *cc) { if (!cc) return NULL; - struct cart *c = g_malloc(sizeof(*c)); + struct cart *c = xmalloc(sizeof(*c)); c->config = cc; cart_rom_init(c); return c; @@ -283,7 +292,7 @@ void cart_rom_attach(struct cart *c) { struct cart_config *cc = c->config; if (cc->autorun) { - c->firq_event = event_new(do_firq, c); + c->firq_event = event_new(DELEGATE_AS0(void, do_firq, c)); c->firq_event->at_tick = event_current_tick + (OSCILLATOR_RATE/10); event_queue(&MACHINE_EVENT_LIST, c->firq_event); } else { @@ -298,15 +307,14 @@ c->firq_event = NULL; } if (c->rom_data) { - g_free(c->rom_data); + free(c->rom_data); c->rom_data = NULL; } } static void do_firq(void *data) { struct cart *c = data; - if (c->signal_firq.delegate) - c->signal_firq.delegate(c->signal_firq.dptr, 1); + DELEGATE_SAFE_CALL1(c->signal_firq, 1); c->firq_event->at_tick = event_current_tick + (OSCILLATOR_RATE/10); event_queue(&MACHINE_EVENT_LIST, c->firq_event); } diff -Nru xroar-0.31.1/src/cart.h xroar-0.32/src/cart.h --- xroar-0.31.1/src/cart.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/cart.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -8,6 +8,8 @@ #include +#include "delegate.h" + struct machine_config; struct event; @@ -30,11 +32,6 @@ int autorun; }; -typedef struct { - void (*delegate)(void *, _Bool); - void *dptr; -} cart_signal_delegate; - struct cart { struct cart_config *config; void (*read)(struct cart *c, uint16_t A, _Bool P2, uint8_t *D); @@ -43,9 +40,9 @@ void (*attach)(struct cart *c); void (*detach)(struct cart *c); uint8_t *rom_data; - cart_signal_delegate signal_firq; - cart_signal_delegate signal_nmi; - cart_signal_delegate signal_halt; + DELEGATE_T1(void, bool) signal_firq; + DELEGATE_T1(void, bool) signal_nmi; + DELEGATE_T1(void, bool) signal_halt; struct event *firq_event; }; diff -Nru xroar-0.31.1/src/crclist.c xroar-0.32/src/crclist.c --- xroar-0.31.1/src/crclist.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/crclist.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -23,7 +23,8 @@ #include #include -#include "pl_glib.h" +#include "slist.h" +#include "xalloc.h" #include "crclist.h" #include "xroar.h" @@ -31,12 +32,12 @@ /* User defined CRC lists */ struct crclist { char *name; - GSList *list; + struct slist *list; _Bool flag; }; /* List containing all defined CRC lists */ -static GSList *crclist_list = NULL; +static struct slist *crclist_list = NULL; static int compare_entry(struct crclist *a, char *b) { return strcmp(a->name, b); @@ -45,8 +46,8 @@ /**************************************************************************/ static struct crclist *new_crclist(const char *name) { - struct crclist *new = g_malloc(sizeof(*new)); - new->name = g_strdup(name); + struct crclist *new = xmalloc(sizeof(*new)); + new->name = xstrdup(name); new->list = NULL; new->flag = 0; return new; @@ -54,18 +55,18 @@ static void free_crclist(struct crclist *crclist) { if (!crclist) return; - GSList *list = crclist->list; + struct slist *list = crclist->list; while (list) { - gpointer data = list->data; - list = g_slist_remove(list, data); - g_free(data); + void *data = list->data; + list = slist_remove(list, data); + free(data); } - g_free(crclist->name); - g_free(crclist); + free(crclist->name); + free(crclist); } static struct crclist *find_crclist(const char *name) { - GSList *entry = g_slist_find_custom(crclist_list, name, (GCompareFunc)compare_entry); + struct slist *entry = slist_find_custom(crclist_list, name, (slist_cmp_func)compare_entry); if (!entry) return NULL; return entry->data; } @@ -74,7 +75,7 @@ * Overwrites any existing list with name LIST. */ void crclist_assign(const char *astring) { if (!astring) return; - char *tmp = g_alloca(strlen(astring) + 1); + char tmp[strlen(astring) + 1]; strcpy(tmp, astring); char *name = strtok(tmp, "="); if (!name) return; @@ -83,26 +84,26 @@ struct crclist *old_list = find_crclist(name); if (old_list) { /* if so, remove its reference in crclist_list */ - crclist_list = g_slist_remove(crclist_list, old_list); + crclist_list = slist_remove(crclist_list, old_list); } char *value; while ((value = strtok(NULL, "\n\v\f\r,"))) { if (value[0] == '@' && 0 == strcmp(value+1, name)) { /* reference to this list - append current contents */ if (old_list) { - new_list->list = g_slist_concat(new_list->list, old_list->list); + new_list->list = slist_concat(new_list->list, old_list->list); old_list->list = NULL; } } else { /* otherwise just add a new entry */ - new_list->list = g_slist_append(new_list->list, g_strdup(value)); + new_list->list = slist_append(new_list->list, xstrdup(value)); } } if (old_list) { free_crclist(old_list); } /* add new list to crclist_list */ - crclist_list = g_slist_append(crclist_list, new_list); + crclist_list = slist_append(crclist_list, new_list); } /* convert a string to integer and compare against CRC */ @@ -122,7 +123,7 @@ /* found an appropriate list? flag it and start scanning it */ if (!crclist) return 0; - GSList *iter; + struct slist *iter; if (crclist->flag) return 0; crclist->flag = 1; @@ -143,7 +144,7 @@ } static void print_crclist_entry(struct crclist *list, void *user_data) { - GSList *jter; + struct slist *jter; if (user_data) { printf("crclist %s=", list->name); } else { @@ -164,12 +165,12 @@ /* Print a list of defined ROM lists to stdout */ void crclist_print_all(void) { - g_slist_foreach(crclist_list, (GFunc)print_crclist_entry, (void *)1); + slist_foreach(crclist_list, (slist_iter_func)print_crclist_entry, (void *)1); } /* Print list and exit */ void crclist_print(void) { printf("CRC lists:\n"); - g_slist_foreach(crclist_list, (GFunc)print_crclist_entry, NULL); + slist_foreach(crclist_list, (slist_iter_func)print_crclist_entry, NULL); exit(EXIT_SUCCESS); } diff -Nru xroar-0.31.1/src/crclist.h xroar-0.32/src/crclist.h --- xroar-0.31.1/src/crclist.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/crclist.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/deltados.c xroar-0.32/src/deltados.c --- xroar-0.31.1/src/deltados.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/deltados.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -29,9 +29,10 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "cart.h" +#include "delegate.h" #include "deltados.h" #include "logging.h" #include "machine.h" @@ -62,10 +63,18 @@ c->reset = deltados_reset; c->detach = deltados_detach; d->fdc = wd279x_new(WD2791); + d->fdc->set_dirc = (DELEGATE_T1(void,int)){vdrive_set_dirc, NULL}; + d->fdc->set_dden = (DELEGATE_T1(void,bool)){vdrive_set_dden, NULL}; + vdrive_ready = DELEGATE_AS1(void, bool, wd279x_ready, d->fdc); + vdrive_tr00 = DELEGATE_AS1(void, bool, wd279x_tr00, d->fdc); + vdrive_index_pulse = DELEGATE_AS1(void, bool, wd279x_index_pulse, d->fdc); + vdrive_write_protect = DELEGATE_AS1(void, bool, wd279x_write_protect, d->fdc); + wd279x_update_connection(d->fdc); + vdrive_update_connection(); } struct cart *deltados_new(struct cart_config *cc) { - struct deltados *d = g_malloc(sizeof(*d)); + struct deltados *d = xmalloc(sizeof(*d)); d->cart.config = cc; deltados_init(d); return (struct cart *)d; @@ -107,23 +116,23 @@ /* Delta cartridge circuitry */ static void ff44_write(struct deltados *d, uint8_t octet) { if (octet != d->ic1_old) { - LOG_DEBUG(4, "Delta: Write to FF44: "); + LOG_DEBUG(2, "Delta: Write to FF44: "); if ((octet ^ d->ic1_old) & 0x03) { - LOG_DEBUG(4, "DRIVE SELECT %01d, ", octet & 0x03); + LOG_DEBUG(2, "DRIVE SELECT %01d, ", octet & 0x03); } if ((octet ^ d->ic1_old) & 0x04) { - LOG_DEBUG(4, "SIDE %s, ", (octet & 0x04)?"1":"0"); + LOG_DEBUG(2, "SIDE %s, ", (octet & 0x04)?"1":"0"); } if ((octet ^ d->ic1_old) & 0x08) { - LOG_DEBUG(4, "DENSITY %s, ", (octet & 0x08)?"DOUBLE":"SINGLE"); + LOG_DEBUG(2, "DENSITY %s, ", (octet & 0x08)?"DOUBLE":"SINGLE"); } - LOG_DEBUG(4, "\n"); + LOG_DEBUG(2, "\n"); d->ic1_old = octet; } d->ic1_drive_select = octet & 0x03; vdrive_set_drive(d->ic1_drive_select); d->ic1_side_select = octet & 0x04; - vdrive_set_head(d->ic1_side_select ? 1 : 0); + vdrive_set_sso(NULL, d->ic1_side_select ? 1 : 0); d->ic1_density = !(octet & 0x08); wd279x_set_dden(d->fdc, !d->ic1_density); } diff -Nru xroar-0.31.1/src/deltados.h xroar-0.32/src/deltados.h --- xroar-0.31.1/src/deltados.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/deltados.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/dkbd.c xroar-0.32/src/dkbd.c --- xroar-0.31.1/src/dkbd.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/dkbd.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -22,7 +22,7 @@ #include #include -#include "pl_glib.h" +#include "array.h" #include "dkbd.h" @@ -87,7 +87,7 @@ { DKBD_U_F2, { DSCAN_F2, 0 } }, }; -#define CMAPPING(m) .num_chord_mappings = G_N_ELEMENTS(m), .chord_mappings = (m) +#define CMAPPING(m) .num_chord_mappings = ARRAY_N_ELEMENTS(m), .chord_mappings = (m) static struct dkbd_layout_variant dkbd_layout_variants[] = { { .base_layout = dkbd_layout_dragon, CMAPPING(dragon_chord_mappings), }, @@ -102,7 +102,7 @@ * for a normal Dragon. CoCo map requires a small translation. */ void dkbd_map_init(struct dkbd_map *map, enum dkbd_layout layout) { - assert(layout >= 0 && layout < G_N_ELEMENTS(dkbd_layout_variants)); + assert(layout >= 0 && layout < ARRAY_N_ELEMENTS(dkbd_layout_variants)); struct dkbd_layout_variant *variant = &dkbd_layout_variants[layout]; map->layout = layout; @@ -129,7 +129,7 @@ /* Populate the unicode_to_dkey map */ // Clear table - for (int i = 0; i < G_N_ELEMENTS(map->unicode_to_dkey); i++) { + for (int i = 0; i < ARRAY_N_ELEMENTS(map->unicode_to_dkey); i++) { map->unicode_to_dkey[i] = (struct dkey_chord){DSCAN_INVALID, 0}; } // "1!" - "9)", ":*", ";+" diff -Nru xroar-0.31.1/src/dkbd.h xroar-0.32/src/dkbd.h --- xroar-0.31.1/src/dkbd.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/dkbd.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/dragondos.c xroar-0.32/src/dragondos.c --- xroar-0.31.1/src/dragondos.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/dragondos.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -30,10 +30,11 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "becker.h" #include "cart.h" +#include "delegate.h" #include "dragondos.h" #include "logging.h" #include "machine.h" @@ -54,10 +55,8 @@ }; /* Handle signals from WD2797 */ -static void set_drq_handler(void *dptr); -static void reset_drq_handler(void *dptr); -static void set_intrq_handler(void *dptr); -static void reset_intrq_handler(void *dptr); +static void set_drq(void *, _Bool); +static void set_intrq(void *, _Bool); static void dragondos_read(struct cart *c, uint16_t A, _Bool P2, uint8_t *D); static void dragondos_write(struct cart *c, uint16_t A, _Bool P2, uint8_t D); @@ -75,16 +74,21 @@ c->detach = dragondos_detach; d->have_becker = (cc->becker_port && becker_open()); d->fdc = wd279x_new(WD2797); - d->fdc->set_drq_handler = set_drq_handler; - d->fdc->reset_drq_handler = reset_drq_handler; - d->fdc->drq_data = c; - d->fdc->set_intrq_handler = set_intrq_handler; - d->fdc->reset_intrq_handler = reset_intrq_handler; - d->fdc->intrq_data = c; + d->fdc->set_dirc = DELEGATE_AS1(void, int, vdrive_set_dirc, NULL); + d->fdc->set_dden = DELEGATE_AS1(void, bool, vdrive_set_dden, NULL); + d->fdc->set_sso = DELEGATE_AS1(void, unsigned, vdrive_set_sso, NULL); + d->fdc->set_drq = DELEGATE_AS1(void, bool, set_drq, c); + d->fdc->set_intrq = DELEGATE_AS1(void, bool, set_intrq, c); + vdrive_ready = DELEGATE_AS1(void, bool, wd279x_ready, d->fdc); + vdrive_tr00 = DELEGATE_AS1(void, bool, wd279x_tr00, d->fdc); + vdrive_index_pulse = DELEGATE_AS1(void, bool, wd279x_index_pulse, d->fdc); + vdrive_write_protect = DELEGATE_AS1(void, bool, wd279x_write_protect, d->fdc); + wd279x_update_connection(d->fdc); + vdrive_update_connection(); } struct cart *dragondos_new(struct cart_config *cc) { - struct dragondos *d = g_malloc(sizeof(*d)); + struct dragondos *d = xmalloc(sizeof(*d)); d->cart.config = cc; dragondos_init(d); return (struct cart *)d; @@ -163,23 +167,23 @@ /* DragonDOS cartridge circuitry */ static void ff48_write(struct dragondos *d, int octet) { if (octet != d->ic1_old) { - LOG_DEBUG(4, "DragonDOS: Write to FF48: "); + LOG_DEBUG(2, "DragonDOS: Write to FF48: "); if ((octet ^ d->ic1_old) & 0x03) { - LOG_DEBUG(4, "DRIVE SELECT %01d, ", octet & 0x03); + LOG_DEBUG(2, "DRIVE SELECT %01d, ", octet & 0x03); } if ((octet ^ d->ic1_old) & 0x04) { - LOG_DEBUG(4, "MOTOR %s, ", (octet & 0x04)?"ON":"OFF"); + LOG_DEBUG(2, "MOTOR %s, ", (octet & 0x04)?"ON":"OFF"); } if ((octet ^ d->ic1_old) & 0x08) { - LOG_DEBUG(4, "DENSITY %s, ", (octet & 0x08)?"SINGLE":"DOUBLE"); + LOG_DEBUG(2, "DENSITY %s, ", (octet & 0x08)?"SINGLE":"DOUBLE"); } if ((octet ^ d->ic1_old) & 0x10) { - LOG_DEBUG(4, "PRECOMP %s, ", (octet & 0x10)?"ON":"OFF"); + LOG_DEBUG(2, "PRECOMP %s, ", (octet & 0x10)?"ON":"OFF"); } if ((octet ^ d->ic1_old) & 0x20) { - LOG_DEBUG(4, "NMI %s, ", (octet & 0x20)?"ENABLED":"DISABLED"); + LOG_DEBUG(2, "NMI %s, ", (octet & 0x20)?"ENABLED":"DISABLED"); } - LOG_DEBUG(4, "\n"); + LOG_DEBUG(2, "\n"); d->ic1_old = octet; } d->ic1_drive_select = octet & 0x03; @@ -191,29 +195,19 @@ d->ic1_nmi_enable = octet & 0x20; } -static void set_drq_handler(void *dptr) { - struct cart *c = dptr; - if (c->signal_firq.delegate) - c->signal_firq.delegate(c->signal_firq.dptr, 1); +static void set_drq(void *sptr, _Bool value) { + struct cart *c = sptr; + DELEGATE_CALL1(c->signal_firq, value); } -static void reset_drq_handler(void *dptr) { - struct cart *c = dptr; - if (c->signal_firq.delegate) - c->signal_firq.delegate(c->signal_firq.dptr, 0); -} - -static void set_intrq_handler(void *dptr) { - struct cart *c = dptr; - struct dragondos *d = dptr; - if (d->ic1_nmi_enable) { - if (c->signal_nmi.delegate) - c->signal_nmi.delegate(c->signal_nmi.dptr, 1); +static void set_intrq(void *sptr, _Bool value) { + struct cart *c = sptr; + struct dragondos *d = sptr; + if (value) { + if (d->ic1_nmi_enable) { + DELEGATE_CALL1(c->signal_nmi, 1); + } + } else { + DELEGATE_CALL1(c->signal_nmi, 0); } } - -static void reset_intrq_handler(void *dptr) { - struct cart *c = dptr; - if (c->signal_nmi.delegate) - c->signal_nmi.delegate(c->signal_nmi.dptr, 0); -} diff -Nru xroar-0.31.1/src/dragondos.h xroar-0.32/src/dragondos.h --- xroar-0.31.1/src/dragondos.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/dragondos.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/events.c xroar-0.32/src/events.c --- xroar-0.31.1/src/events.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/events.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -20,24 +20,23 @@ #include -#include "pl_glib.h" +#include "xalloc.h" #include "events.h" #include "logging.h" event_ticks event_current_tick = 0; -struct event *event_new(event_delegate delegate, void *delegate_data) { - struct event *new = g_malloc(sizeof(*new)); - event_init(new, delegate, delegate_data); +struct event *event_new(DELEGATE_T0(void) delegate) { + struct event *new = xmalloc(sizeof(*new)); + event_init(new, delegate); return new; } -void event_init(struct event *event, event_delegate delegate, void *delegate_data) { +void event_init(struct event *event, DELEGATE_T0(void) delegate) { if (event == NULL) return; event->at_tick = event_current_tick; event->delegate = delegate; - event->delegate_data = delegate_data; event->queued = 0; event->list = NULL; event->next = NULL; @@ -45,7 +44,7 @@ void event_free(struct event *event) { event_dequeue(event); - g_free(event); + free(event); } void event_queue(struct event **list, struct event *event) { diff -Nru xroar-0.31.1/src/events.h xroar-0.32/src/events.h --- xroar-0.31.1/src/events.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/events.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -8,6 +8,8 @@ #include +#include "delegate.h" + /* Maintains queues of events. Each event has a tick number at which its * delegate is scheduled to run. */ @@ -16,19 +18,16 @@ /* Current "time". */ extern event_ticks event_current_tick; -typedef void (*event_delegate)(void *); - struct event { event_ticks at_tick; - event_delegate delegate; - void *delegate_data; + DELEGATE_T0(void) delegate; _Bool queued; struct event **list; struct event *next; }; -struct event *event_new(event_delegate delegate, void *delegate_data); -void event_init(struct event *event, event_delegate delegate, void *delegate_data); +struct event *event_new(DELEGATE_T0(void)); +void event_init(struct event *event, DELEGATE_T0(void)); void event_free(struct event *event); void event_queue(struct event **list, struct event *event); @@ -42,7 +41,7 @@ struct event *e = *list; *list = e->next; e->queued = 0; - e->delegate(e->delegate_data); + DELEGATE_CALL0(e->delegate); } static inline void event_run_queue(struct event **list) { diff -Nru xroar-0.31.1/src/filereq_cli.c xroar-0.32/src/filereq_cli.c --- xroar-0.31.1/src/filereq_cli.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/filereq_cli.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -25,7 +25,7 @@ #include "logging.h" #include "module.h" -static char *get_filename(const char **extensions); +static char *get_filename(char const * const *extensions); FileReqModule filereq_cli_module = { .common = { .name = "cli", @@ -35,7 +35,7 @@ static char fnbuf[256]; -static char *get_filename(const char **extensions) { +static char *get_filename(char const * const *extensions) { char *in, *cr; _Bool was_fullscreen; (void)extensions; /* unused */ diff -Nru xroar-0.31.1/src/fs.c xroar-0.32/src/fs.c --- xroar-0.31.1/src/fs.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/fs.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * diff -Nru xroar-0.31.1/src/fs.h xroar-0.32/src/fs.h --- xroar-0.31.1/src/fs.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/fs.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/gdb.c xroar-0.32/src/gdb.c --- xroar-0.31.1/src/gdb.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/gdb.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2013 Ciaran Anscomb + * Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -74,8 +74,7 @@ #include #include -#include "pl_glib.h" -#include "pl_string.h" +#include "pl-string.h" #ifndef WINDOWS32 @@ -156,7 +155,7 @@ int gdb_init(void) { struct addrinfo hints; - const char *hostname = xroar_cfg.gdb_ip ? xroar_cfg.gdb_ip : "localhost"; + const char *hostname = xroar_cfg.gdb_ip ? xroar_cfg.gdb_ip : "127.0.0.1"; const char *portname = xroar_cfg.gdb_port ? xroar_cfg.gdb_port : "65520"; // Find the interface @@ -194,7 +193,7 @@ pthread_create(&sock_thread, NULL, handle_tcp_sock, NULL); pthread_detach(sock_thread); - LOG_DEBUG(2, "gdb: target listening on %s:%s\n", hostname, portname); + LOG_DEBUG(1, "gdb: target listening on %s:%s\n", hostname, portname); return 0; @@ -216,14 +215,21 @@ (void)data; for (;;) { - sockfd = accept(listenfd, info->ai_addr, &info->ai_addrlen); + + /* Work around an oddness in Windows or MinGW where (struct + * addrinfo).ai_addrlen is size_t instead of sockaddr_t, but + * accept() takes an (int *). Raises a warning when compiling + * 64-bit. */ + socklen_t ai_addrlen = info->ai_addrlen; + sockfd = accept(listenfd, info->ai_addr, &ai_addrlen); + if (sockfd < 0) { LOG_WARN("gdb: accept() failed\n"); continue; } { int flag = 1; - setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); + setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void const *)&flag, sizeof(flag)); } if (xroar_cfg.debug_gdb & XROAR_DEBUG_GDB_CONNECT) { LOG_PRINT("gdb: connection accepted\n"); diff -Nru xroar-0.31.1/src/gdb.h xroar-0.32/src/gdb.h --- xroar-0.31.1/src/gdb.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/gdb.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,6 +1,6 @@ /* * XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/gtk2/drivecontrol.c xroar-0.32/src/gtk2/drivecontrol.c --- xroar-0.31.1/src/gtk2/drivecontrol.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/gtk2/drivecontrol.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -214,6 +214,6 @@ static void update_drive_cyl_head(unsigned drive, unsigned cyl, unsigned head) { char string[16]; - snprintf(string, sizeof(string), "Dr %01d Tr %02d He %01d", drive + 1, cyl, head); + snprintf(string, sizeof(string), "Dr %01u Tr %02u He %01u", drive + 1, cyl, head); gtk_label_set_text(GTK_LABEL(dc_drive_cyl_head), string); } diff -Nru xroar-0.31.1/src/gtk2/drivecontrol.h xroar-0.32/src/gtk2/drivecontrol.h --- xroar-0.31.1/src/gtk2/drivecontrol.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/gtk2/drivecontrol.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/gtk2/filereq_gtk2.c xroar-0.32/src/gtk2/filereq_gtk2.c --- xroar-0.31.1/src/gtk2/filereq_gtk2.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/gtk2/filereq_gtk2.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -31,8 +31,8 @@ #include "gtk2/ui_gtk2.h" static _Bool init(void); -static char *load_filename(const char **extensions); -static char *save_filename(const char **extensions); +static char *load_filename(char const * const *extensions); +static char *save_filename(char const * const *extensions); FileReqModule filereq_gtk2_module = { .common = { .name = "gtk2", .description = "GTK+-2 file requester", @@ -53,7 +53,7 @@ static GtkWidget *save_dialog = NULL; static gchar *filename = NULL; -static char *load_filename(const char **extensions) { +static char *load_filename(char const * const *extensions) { (void)extensions; /* unused */ if (filename) { g_free(filename); @@ -77,7 +77,7 @@ return filename; } -static char *save_filename(const char **extensions) { +static char *save_filename(char const * const *extensions) { (void)extensions; /* unused */ if (filename) { g_free(filename); diff -Nru xroar-0.31.1/src/gtk2/keyboard_gtk2.c xroar-0.32/src/gtk2/keyboard_gtk2.c --- xroar-0.31.1/src/gtk2/keyboard_gtk2.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/gtk2/keyboard_gtk2.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -30,7 +30,7 @@ #include #include -#include "pl_string.h" +#include "pl-string.h" #include "joystick.h" #include "keyboard.h" @@ -240,7 +240,7 @@ for (int i = 0; i < G_N_ELEMENTS(keymaps); i++) { if (0 == strcmp(keymap_option, keymaps[i].name)) { selected_keymap = &keymaps[i]; - LOG_DEBUG(2,"\tSelecting '%s' keymap\n",keymap_option); + LOG_DEBUG(1, "\tSelecting '%s' keymap\n", keymap_option); } } } @@ -278,7 +278,7 @@ xroar_toggle_cart(); break; case GDK_KEY_f: - xroar_fullscreen(XROAR_TOGGLE); + xroar_set_fullscreen(1, XROAR_TOGGLE); break; case GDK_KEY_h: if (shift) @@ -292,9 +292,9 @@ break; case GDK_KEY_j: if (shift) { - joystick_swap(); + xroar_swap_joysticks(1); } else { - joystick_cycle(); + xroar_cycle_joysticks(1); } break; case GDK_KEY_k: diff -Nru xroar-0.31.1/src/gtk2/keyboard_gtk2_mappings.c xroar-0.32/src/gtk2/keyboard_gtk2_mappings.c --- xroar-0.31.1/src/gtk2/keyboard_gtk2_mappings.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/gtk2/keyboard_gtk2_mappings.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * diff -Nru xroar-0.31.1/src/gtk2/tapecontrol.c xroar-0.32/src/gtk2/tapecontrol.c --- xroar-0.31.1/src/gtk2/tapecontrol.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/gtk2/tapecontrol.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -150,7 +150,7 @@ gtk_builder_connect_signals(builder, NULL); g_object_unref(builder); - event_init(&update_tape_counters_event, update_tape_counters, NULL); + event_init(&update_tape_counters_event, DELEGATE_AS0(void, update_tape_counters, NULL)); update_tape_counters_event.at_tick = event_current_tick + OSCILLATOR_RATE / 2; event_queue(&UI_EVENT_LIST, &update_tape_counters_event); } diff -Nru xroar-0.31.1/src/gtk2/tapecontrol.h xroar-0.32/src/gtk2/tapecontrol.h --- xroar-0.31.1/src/gtk2/tapecontrol.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/gtk2/tapecontrol.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/gtk2/ui_gtk2.c xroar-0.32/src/gtk2/ui_gtk2.c --- xroar-0.31.1/src/gtk2/ui_gtk2.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/gtk2/ui_gtk2.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -28,7 +28,7 @@ #include #include -#include "pl_string.h" +#include "pl-string.h" #include "cart.h" #include "events.h" @@ -56,7 +56,7 @@ extern VideoModule video_gtkgl_module; extern VideoModule video_null_module; -static VideoModule *gtk2_video_module_list[] = { +static VideoModule * const gtk2_video_module_list[] = { #ifdef HAVE_GTKGL &video_gtkgl_module, #endif @@ -65,7 +65,7 @@ }; extern KeyboardModule keyboard_gtk2_module; -static KeyboardModule *gtk2_keyboard_module_list[] = { +static KeyboardModule * const gtk2_keyboard_module_list[] = { &keyboard_gtk2_module, NULL }; @@ -97,12 +97,12 @@ NULL }; -JoystickModule gtk2_js_internal = { +struct joystick_module gtk2_js_internal = { .common = { .name = "gtk2", .description = "GTK+ joystick" }, - .interface_list = js_iflist, + .intf_list = js_iflist, }; -static JoystickModule *gtk2_js_modlist[] = { +static struct joystick_module *gtk2_js_modlist[] = { >k2_js_internal, NULL }; @@ -110,11 +110,14 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* Module callbacks */ +static void fullscreen_changed_cb(_Bool fullscreen); static void cross_colour_changed_cb(int cc); static void vdg_inverse_cb(_Bool inverse); static void machine_changed_cb(int machine_type); static void cart_changed_cb(int cart_index); static void keymap_changed_cb(int map); +static void joystick_changed_cb(int port, const char *name); +static void kbd_translate_changed_cb(_Bool kbd_translate); static void fast_sound_changed_cb(_Bool fast); UIModule ui_gtk2_module = { @@ -124,11 +127,14 @@ .video_module_list = gtk2_video_module_list, .keyboard_module_list = gtk2_keyboard_module_list, .joystick_module_list = gtk2_js_modlist, + .fullscreen_changed_cb = fullscreen_changed_cb, .cross_colour_changed_cb = cross_colour_changed_cb, .vdg_inverse_cb = vdg_inverse_cb, .machine_changed_cb = machine_changed_cb, .cart_changed_cb = cart_changed_cb, .keymap_changed_cb = keymap_changed_cb, + .joystick_changed_cb = joystick_changed_cb, + .kbd_translate_changed_cb = kbd_translate_changed_cb, .fast_sound_changed_cb = fast_sound_changed_cb, .input_tape_filename_cb = gtk2_input_tape_filename_cb, .output_tape_filename_cb = gtk2_output_tape_filename_cb, @@ -158,10 +164,6 @@ static gboolean hide_cursor(GtkWidget *widget, GdkEventMotion *event, gpointer data); static gboolean show_cursor(GtkWidget *widget, GdkEventMotion *event, gpointer data); -/* UI-specific callbacks */ -static void fullscreen_changed_cb(_Bool fullscreen); -static void kbd_translate_changed_cb(_Bool kbd_translate); - static gboolean run_cpu(gpointer data); /* Helpers */ @@ -215,7 +217,7 @@ static void set_fullscreen(GtkToggleAction *current, gpointer user_data) { gboolean val = gtk_toggle_action_get_active(current); (void)user_data; - xroar_fullscreen(val); + xroar_set_fullscreen(0, val); } static void zoom_1_1(void) { @@ -299,10 +301,34 @@ xroar_set_keymap(val); } +static char const * const joystick_name[] = { + NULL, "joy0", "joy1", "kjoy0", "mjoy0" +}; + +static void set_joy_right(GtkRadioAction *action, GtkRadioAction *current, gpointer user_data) { + gint val = gtk_radio_action_get_current_value(current); + (void)action; + (void)user_data; + if (val >= 0 && val <= 4) + xroar_set_joystick(0, 0, joystick_name[val]); +} + +static void set_joy_left(GtkRadioAction *action, GtkRadioAction *current, gpointer user_data) { + gint val = gtk_radio_action_get_current_value(current); + (void)action; + (void)user_data; + if (val >= 0 && val <= 4) + xroar_set_joystick(0, 1, joystick_name[val]); +} + +static void swap_joysticks(void) { + xroar_swap_joysticks(1); +} + static void toggle_keyboard_translation(GtkToggleAction *current, gpointer user_data) { gboolean val = gtk_toggle_action_get_active(current); (void)user_data; - xroar_set_kbd_translate(val); + xroar_set_kbd_translate(0, val); } static void toggle_fast_sound(GtkToggleAction *current, gpointer user_data) { @@ -323,7 +349,7 @@ (void)data; GtkAboutDialog *dialog = (GtkAboutDialog *)gtk_about_dialog_new(); gtk_about_dialog_set_version(dialog, VERSION); - gtk_about_dialog_set_copyright(dialog, "Copyright © 2003–2013 Ciaran Anscomb "); + gtk_about_dialog_set_copyright(dialog, "Copyright © 2003–2014 Ciaran Anscomb "); gtk_about_dialog_set_license(dialog, "XRoar is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" @@ -388,6 +414,22 @@ "" "" "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" "" "" "" @@ -405,7 +447,7 @@ "" ""; -static GtkActionEntry ui_entries[] = { +static GtkActionEntry const ui_entries[] = { /* Top level */ { .name = "FileMenuAction", .label = "_File" }, { .name = "ViewMenuAction", .label = "_View" }, @@ -455,6 +497,11 @@ .callback = G_CALLBACK(zoom_2_1) }, /* Machine */ { .name = "KeymapMenuAction", .label = "_Keyboard Map" }, + { .name = "JoyRightMenuAction", .label = "_Right Joystick" }, + { .name = "JoyLeftMenuAction", .label = "_Left Joystick" }, + { .name = "JoySwapAction", .label = "Swap _Joysticks", + .accelerator = "J", + .callback = G_CALLBACK(swap_joysticks) }, { .name = "SoftResetAction", .label = "_Soft Reset", .accelerator = "R", .tooltip = "Soft Reset", @@ -471,7 +518,7 @@ }; static guint ui_n_entries = G_N_ELEMENTS(ui_entries); -static GtkToggleActionEntry ui_toggles[] = { +static GtkToggleActionEntry const ui_toggles[] = { /* View */ { .name = "InverseTextAction", .label = "_Inverse Text", .accelerator = "I", @@ -494,18 +541,34 @@ }; static guint ui_n_toggles = G_N_ELEMENTS(ui_toggles); -static GtkRadioActionEntry cross_colour_radio_entries[] = { +static GtkRadioActionEntry const cross_colour_radio_entries[] = { { .name = "cc-none", .label = "None", .value = CROSS_COLOUR_OFF }, { .name = "cc-blue-red", .label = "Blue-red", .value = CROSS_COLOUR_KBRW }, { .name = "cc-red-blue", .label = "Red-blue", .value = CROSS_COLOUR_KRBW }, }; -static GtkRadioActionEntry keymap_radio_entries[] = { +static GtkRadioActionEntry const keymap_radio_entries[] = { { .name = "keymap_dragon", .label = "Dragon Layout", .value = KEYMAP_DRAGON }, { .name = "keymap_dragon200e", .label = "Dragon 200-E Layout", .value = KEYMAP_DRAGON200E }, { .name = "keymap_coco", .label = "CoCo Layout", .value = KEYMAP_COCO }, }; +static GtkRadioActionEntry const joy_right_radio_entries[] = { + { .name = "joy_right_none", .label = "None", .value = 0 }, + { .name = "joy_right_joy0", .label = "Joystick 0", .value = 1 }, + { .name = "joy_right_joy1", .label = "Joystick 1", .value = 2 }, + { .name = "joy_right_kjoy0", .label = "Keyboard", .value = 3 }, + { .name = "joy_right_mjoy0", .label = "Mouse", .value = 4 }, +}; + +static GtkRadioActionEntry const joy_left_radio_entries[] = { + { .name = "joy_left_none", .label = "None", .value = 0 }, + { .name = "joy_left_joy0", .label = "Joystick 0", .value = 1 }, + { .name = "joy_left_joy1", .label = "Joystick 1", .value = 2 }, + { .name = "joy_left_kjoy0", .label = "Keyboard", .value = 3 }, + { .name = "joy_left_mjoy0", .label = "Mouse", .value = 4 }, +}; + static _Bool init(void) { gtk_init(NULL, NULL); @@ -548,6 +611,8 @@ gtk_action_group_add_actions(main_action_group, ui_entries, ui_n_entries, NULL); gtk_action_group_add_toggle_actions(main_action_group, ui_toggles, ui_n_toggles, NULL); gtk_action_group_add_radio_actions(main_action_group, keymap_radio_entries, 3, 0, (GCallback)set_keymap, NULL); + gtk_action_group_add_radio_actions(main_action_group, joy_right_radio_entries, 5, 0, (GCallback)set_joy_right, NULL); + gtk_action_group_add_radio_actions(main_action_group, joy_left_radio_entries, 5, 0, (GCallback)set_joy_left, NULL); gtk_action_group_add_radio_actions(main_action_group, cross_colour_radio_entries, 3, 0, (GCallback)set_cc, NULL); /* Menu merge points */ @@ -578,11 +643,6 @@ gtk_window_parse_geometry(GTK_WINDOW(gtk2_top_window), xroar_cfg.geometry); } - /* Now up to video module to do something with this drawing_area */ - - xroar_fullscreen_changed_cb = fullscreen_changed_cb; - xroar_kbd_translate_changed_cb = kbd_translate_changed_cb; - /* Cursor hiding */ blank_cursor = gdk_cursor_new(GDK_BLANK_CURSOR); gtk_widget_add_events(gtk2_drawing_area, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); @@ -749,6 +809,25 @@ gtk_radio_action_set_current_value(radio, map); } +static void joystick_changed_cb(int port, const char *name) { + GtkRadioAction *radio; + if (port == 0) { + radio = (GtkRadioAction *)gtk_ui_manager_get_action(gtk2_menu_manager, "/MainMenu/MachineMenu/JoyRightMenu/joy_right_none"); + } else { + radio = (GtkRadioAction *)gtk_ui_manager_get_action(gtk2_menu_manager, "/MainMenu/MachineMenu/JoyLeftMenu/joy_left_none"); + } + int joy = 0; + if (name) { + for (int i = 1; i < 5; i++) { + if (0 == strcmp(name, joystick_name[i])) { + joy = i; + break; + } + } + } + gtk_radio_action_set_current_value(radio, joy); +} + /* Tool callbacks */ static void kbd_translate_changed_cb(_Bool kbd_translate) { diff -Nru xroar-0.31.1/src/gtk2/ui_gtk2.h xroar-0.32/src/gtk2/ui_gtk2.h --- xroar-0.31.1/src/gtk2/ui_gtk2.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/gtk2/ui_gtk2.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/gtk2/vo_gtkgl.c xroar-0.32/src/gtk2/vo_gtkgl.c --- xroar-0.31.1/src/gtk2/vo_gtkgl.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/gtk2/vo_gtkgl.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -79,11 +79,8 @@ /* Show top window first so that drawing area is realised to the * right size even if we then fullscreen. */ gtk_widget_show(gtk2_top_window); - /* Set fullscreen and update UI. */ + /* Set fullscreen. */ set_fullscreen(xroar_cfg.fullscreen); - if (xroar_fullscreen_changed_cb) { - xroar_fullscreen_changed_cb(xroar_cfg.fullscreen); - } vsync(); diff -Nru xroar-0.31.1/src/hd6309.c xroar-0.32/src/hd6309.c --- xroar-0.31.1/src/hd6309.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/hd6309.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -34,8 +34,9 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" +#include "delegate.h" #include "hd6309.h" #include "mc6809.h" @@ -183,7 +184,6 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#define QUAD_IMMEDIATE(a,v1,v2) { (void)a; v1 = fetch_byte(cpu, REG_PC) << 8; v1 |= fetch_byte(cpu, REG_PC+1); v2 = fetch_byte(cpu, REG_PC+2) << 8; v2 |= fetch_byte(cpu, REG_PC+3); REG_PC += 4; } #define QUAD_DIRECT(a,v1,v2) { a = ea_direct(cpu); v1 = fetch_byte(cpu, a) << 8; v1 |= fetch_byte(cpu, a+1); v2 = fetch_byte(cpu, a+2) << 8; v2 |= fetch_byte(cpu, a+3); } #define QUAD_INDEXED(a,v1,v2) { a = ea_indexed(cpu); v1 = fetch_byte(cpu, a) << 8; v1 |= fetch_byte(cpu, a+1); v2 = fetch_byte(cpu, a+2) << 8; v2 |= fetch_byte(cpu, a+3); } #define QUAD_EXTENDED(a,v1,v2) { a = ea_extended(cpu); v1 = fetch_byte(cpu, a) << 8; v1 |= fetch_byte(cpu, a+1); v2 = fetch_byte(cpu, a+2) << 8; v2 |= fetch_byte(cpu, a+3); } @@ -199,7 +199,7 @@ static void dummy_write_cycle(uint16_t a, uint8_t v) { (void)a; (void)v; } struct MC6809 *hd6309_new(void) { - struct HD6309 *hcpu = g_malloc0(sizeof(*hcpu)); + struct HD6309 *hcpu = xzalloc(sizeof(*hcpu)); struct MC6809 *cpu = (struct MC6809 *)hcpu; cpu->free = hd6309_free; cpu->reset = hd6309_reset; @@ -214,7 +214,7 @@ static void hd6309_free(struct MC6809 *cpu) { struct HD6309 *hcpu = (struct HD6309 *)cpu; - g_free(hcpu); + free(hcpu); } static void hd6309_reset(struct MC6809 *cpu) { @@ -297,9 +297,7 @@ hcpu->state = hd6309_state_next_instruction; // Instruction fetch hook called here so that machine // can be stopped beforehand. - if (cpu->instruction_hook) { - cpu->instruction_hook(cpu->instr_hook_dptr); - } + DELEGATE_SAFE_CALL0(cpu->instruction_hook); continue; case hd6309_state_dispatch_irq: @@ -1016,8 +1014,11 @@ // 0xcd LDQ immediate case 0xcd: { - unsigned ea; - QUAD_IMMEDIATE(ea, REG_D, REG_W); + REG_D = fetch_byte(cpu, REG_PC) << 8; + REG_D |= fetch_byte(cpu, REG_PC+1); + REG_W = fetch_byte(cpu, REG_PC+2) << 8; + REG_W |= fetch_byte(cpu, REG_PC+3); + REG_PC += 4; CLR_NZV; SET_N16(REG_D); if (REG_D == 0 && REG_W == 0) @@ -1527,7 +1528,7 @@ break; default: out = 0; break; } - if ((op & 3) == 7) { + if ((op & 7) == 7) { // STBT out |= (mem_byte & ~dst_mask); store_byte(cpu, ea, out); @@ -1710,7 +1711,7 @@ case 3: tmp2 = word_extended(cpu); break; default: tmp2 = 0; break; } - (void)op_sub16(cpu, tmp1, tmp2); break; // CMPU, CMPS + (void)op_sub16(cpu, tmp1, tmp2); // CMPU, CMPS if (!NATIVE_MODE) NVMA_CYCLE; } break; @@ -2056,8 +2057,7 @@ static void take_interrupt(struct MC6809 *cpu, uint8_t mask, uint16_t vec) { REG_CC |= mask; NVMA_CYCLE; - if (cpu->interrupt_hook) - cpu->interrupt_hook(cpu->intr_dptr, vec); + DELEGATE_SAFE_CALL1(cpu->interrupt_hook, vec); unsigned new_pc = fetch_byte(cpu, vec) << 8; new_pc |= fetch_byte(cpu, vec+1); REG_PC = new_pc; @@ -2065,8 +2065,7 @@ } static void instruction_posthook(struct MC6809 *cpu) { - if (cpu->instruction_posthook) - cpu->instruction_posthook(cpu->instr_posthook_dptr); + DELEGATE_SAFE_CALL0(cpu->instruction_posthook); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru xroar-0.31.1/src/hd6309.h xroar-0.32/src/hd6309.h --- xroar-0.31.1/src/hd6309.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/hd6309.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/hd6309_trace.c xroar-0.32/src/hd6309_trace.c --- xroar-0.31.1/src/hd6309_trace.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/hd6309_trace.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -43,7 +43,7 @@ static struct { const char *mnemonic; int type; -} instructions[3][256] = { +} const instructions[3][256] = { { // 0x00 - 0x0F @@ -886,16 +886,16 @@ /* Sequences of expected bytes */ -static const int state_list_irq[] = { WANT_VALUE, WANT_NOTHING, WANT_PRINT }; -static const int state_list_inherent[] = { WANT_PRINT }; -static const int state_list_idx[] = { WANT_IDX_POSTBYTE }; -static const int state_list_imm8[] = { WANT_VALUE, WANT_PRINT }; -static const int state_list_imm16[] = { WANT_VALUE, WANT_VALUE, WANT_PRINT }; -static const int state_list_imm32[] = { WANT_VALUE, WANT_VALUE, WANT_VALUE, WANT_VALUE, WANT_PRINT }; -static const int state_list_mb[] = { WANT_MEMBIT_POSTBYTE, WANT_VALUE, WANT_PRINT }; -static const int state_list_inmem_idx[] = { WANT_IM_VALUE, WANT_IDX_POSTBYTE }; -static const int state_list_inmem8[] = { WANT_IM_VALUE, WANT_VALUE, WANT_PRINT }; -static const int state_list_inmem16[] = { WANT_IM_VALUE, WANT_VALUE, WANT_VALUE, WANT_PRINT }; +static int const state_list_irq[] = { WANT_VALUE, WANT_NOTHING, WANT_PRINT }; +static int const state_list_inherent[] = { WANT_PRINT }; +static int const state_list_idx[] = { WANT_IDX_POSTBYTE }; +static int const state_list_imm8[] = { WANT_VALUE, WANT_PRINT }; +static int const state_list_imm16[] = { WANT_VALUE, WANT_VALUE, WANT_PRINT }; +static int const state_list_imm32[] = { WANT_VALUE, WANT_VALUE, WANT_VALUE, WANT_VALUE, WANT_PRINT }; +static int const state_list_mb[] = { WANT_MEMBIT_POSTBYTE, WANT_VALUE, WANT_PRINT }; +static int const state_list_inmem_idx[] = { WANT_IM_VALUE, WANT_IDX_POSTBYTE }; +static int const state_list_inmem8[] = { WANT_IM_VALUE, WANT_VALUE, WANT_PRINT }; +static int const state_list_inmem16[] = { WANT_IM_VALUE, WANT_VALUE, WANT_VALUE, WANT_PRINT }; /* Indexed addressing modes */ @@ -911,7 +911,7 @@ * optional brackets in indirect modes. 8-bit offsets include an extra %s to * indicate sign. 5-bit offsets are printed in decimal. */ -static const char *idx_fmts[17] = { +static char const * const idx_fmts[17] = { "%s,%s+%s", "%s,%s++%s", "%s,-%s%s", @@ -933,7 +933,7 @@ /* Indexed mode may well fetch more data after initial postbyte */ -static const int *idx_state_lists[17] = { +static int const * const idx_state_lists[17] = { state_list_inherent, state_list_inherent, state_list_inherent, @@ -955,7 +955,7 @@ /* TFM instruction format strings */ -static const char *tfm_fmts[4] = { +static char const * const tfm_fmts[4] = { "%s+,%s+", "%s-,%s-", "%s+,%s", @@ -965,19 +965,19 @@ /* Names */ // Inter-register operation postbyte -static const char *tfr_regs[16] = { +static char const * const tfr_regs[16] = { "D", "X", "Y", "U", "S", "PC", "W", "V", "A", "B", "CC", "DP", "0", "0", "E", "F" }; // Indexed addressing postbyte -static const char *idx_regs[4] = { "X", "Y", "U", "S" }; +static char const * const idx_regs[4] = { "X", "Y", "U", "S" }; // Memory with bit postbyte -static const char *membit_regs[4] = { "CC", "A", "B", "*" }; +static char const * const membit_regs[4] = { "CC", "A", "B", "*" }; // Interrupt vector names -static const char *irq_names[8] = { +static char const * const irq_names[8] = { "[ILLEGAL]", "[SWI3]", "[SWI2]", "[FIRQ]", "[IRQ]", "[SWI]", "[NMI]", "[RESET]" }; @@ -1311,8 +1311,8 @@ /* Called just before an IRQ vector fetch */ -void hd6309_trace_irq(void *dptr, uint16_t vector) { - (void)dptr; +void hd6309_trace_irq(void *sptr, int vector) { + (void)sptr; reset_state(); state = WANT_IRQ_VECTOR; bytes_count = 0; diff -Nru xroar-0.31.1/src/hd6309_trace.h xroar-0.32/src/hd6309_trace.h --- xroar-0.31.1/src/hd6309_trace.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/hd6309_trace.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -10,7 +10,7 @@ void hd6309_trace_reset(void); void hd6309_trace_byte(uint8_t byte, uint16_t pc); -void hd6309_trace_irq(void *dptr, uint16_t vector); +void hd6309_trace_irq(void *sptr, int vector); void hd6309_trace_print(struct MC6809 *cpu); #endif /* XROAR_HD6309_TRACE_H_ */ diff -Nru xroar-0.31.1/src/hexs19.c xroar-0.32/src/hexs19.c --- xroar-0.31.1/src/hexs19.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/hexs19.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -67,7 +67,7 @@ int intel_hex_read(const char *filename, int autorun) { FILE *fd; - int data, length, addr, type, sum; + int data; uint8_t rsum; uint16_t exec = 0; struct log_handle *log_hex = NULL; @@ -75,7 +75,7 @@ return -1; if (!(fd = fopen(filename, "rb"))) return -1; - LOG_DEBUG(2, "Reading Intel HEX record file\n"); + LOG_DEBUG(1, "Reading Intel HEX record file\n"); if (xroar_cfg.debug_file & XROAR_DEBUG_FILE_BIN_DATA) log_open_hexdump(&log_hex, "Intel HEX read: "); while ((data = fs_read_uint8(fd)) >= 0) { @@ -87,9 +87,9 @@ } return -1; } - length = read_byte(fd); - addr = read_word(fd); - type = read_byte(fd); + int length = read_byte(fd); + int addr = read_word(fd); + int type = read_byte(fd); if (type == 0 && (xroar_cfg.debug_file & XROAR_DEBUG_FILE_BIN_DATA)) log_hexdump_set_addr(log_hex, addr); rsum = length + (length >> 8) + addr + (addr >> 8) + type; @@ -103,7 +103,7 @@ addr++; } } - sum = read_byte(fd); + int sum = read_byte(fd); rsum = ~rsum + 1; if (sum != rsum) { if (xroar_cfg.debug_file & XROAR_DEBUG_FILE_BIN_DATA) @@ -151,7 +151,7 @@ default: break; } - LOG_DEBUG(2, "Unknown binary file type.\n"); + LOG_DEBUG(1, "Unknown binary file type.\n"); fclose(fd); return -1; } @@ -159,7 +159,7 @@ static int dragon_bin_load(FILE *fd, int autorun) { int filetype, load, exec; size_t length; - LOG_DEBUG(2, "Reading Dragon BIN file\n"); + LOG_DEBUG(1, "Reading Dragon BIN file\n"); filetype = fs_read_uint8(fd); (void)filetype; // XXX verify this makes sense load = fs_read_uint16(fd); @@ -168,16 +168,23 @@ (void)fs_read_uint8(fd); if (xroar_cfg.debug_file & XROAR_DEBUG_FILE_BIN) LOG_PRINT("Dragon BIN: LOAD $%04zx bytes to $%04x, EXEC $%04x\n", length, load, exec); - fread(&machine_ram[load], length, 1, fd); + struct log_handle *log_bin = NULL; if (xroar_cfg.debug_file & XROAR_DEBUG_FILE_BIN_DATA) { - struct log_handle *log_bin = NULL; log_open_hexdump(&log_bin, "Dragon BIN read: "); log_hexdump_set_addr(log_bin, load); - for (size_t i = 0; i < length; i++) { - log_hexdump_byte(log_bin, machine_ram[load + i]); + } + for (size_t i = 0; i < length; i++) { + int data = fs_read_uint8(fd); + if (data < 0) { + log_hexdump_flag(log_bin); + log_close(&log_bin); + LOG_WARN("Dragon BIN: short read\n"); + break; } - log_close(&log_bin); + machine_write_byte((load + i) & 0xffff, data); + log_hexdump_byte(log_bin, data); } + log_close(&log_bin); if (autorun) { struct MC6809 *cpu = machine_get_cpu(0); if (xroar_cfg.debug_file & XROAR_DEBUG_FILE_BIN) @@ -193,35 +200,41 @@ static int coco_bin_load(FILE *fd, int autorun) { size_t length; - int data, load, exec; - LOG_DEBUG(2, "Reading CoCo BIN file\n"); + int chunk, load, exec; + LOG_DEBUG(1, "Reading CoCo BIN file\n"); fseek(fd, 0, SEEK_SET); - while ((data = fs_read_uint8(fd)) >= 0) { - if (data == 0) { + while ((chunk = fs_read_uint8(fd)) >= 0) { + if (chunk == 0) { length = fs_read_uint16(fd); load = fs_read_uint16(fd); if (xroar_cfg.debug_file & XROAR_DEBUG_FILE_BIN) LOG_PRINT("CoCo BIN: LOAD $%04zx bytes to $%04x\n", length, load); - size_t nread = fread(&machine_ram[load], 1, length, fd); - if (nread < length) - LOG_WARN("CoCo BIN: short read in chunk data\n"); // Generate a hex dump per chunk + struct log_handle *log_bin = NULL; if (xroar_cfg.debug_file & XROAR_DEBUG_FILE_BIN_DATA) { - struct log_handle *log_bin = NULL; log_open_hexdump(&log_bin, "CoCo BIN: read: "); log_hexdump_set_addr(log_bin, load); - for (size_t i = 0; i < nread; i++) { - log_hexdump_byte(log_bin, machine_ram[load + i]); - } - if (nread < length) + } + for (size_t i = 0; i < length; i++) { + int data = fs_read_uint8(fd); + if (data < 0) { log_hexdump_flag(log_bin); - log_close(&log_bin); + log_close(&log_bin); + LOG_WARN("CoCo BIN: short read in data chunk\n"); + break; + } + machine_write_byte((load + i) & 0xffff, data); + log_hexdump_byte(log_bin, data); } + log_close(&log_bin); continue; - } - if (data == 0xff) { + } else if (chunk == 0xff) { (void)fs_read_uint16(fd); // skip 0 exec = fs_read_uint16(fd); + if (exec < 0) { + LOG_WARN("CoCo BIN: short read in exec chunk\n"); + break; + } if (autorun) { struct MC6809 *cpu = machine_get_cpu(0); if (xroar_cfg.debug_file & XROAR_DEBUG_FILE_BIN) @@ -232,6 +245,9 @@ LOG_PRINT("CoCo BIN: EXEC $%04x - not autorunning\n", exec); } break; + } else { + LOG_WARN("CoCo BIN: unknown chunk type 0x%02x\n", chunk); + break; } } fclose(fd); diff -Nru xroar-0.31.1/src/hexs19.h xroar-0.32/src/hexs19.h --- xroar-0.31.1/src/hexs19.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/hexs19.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/jack/ao_jack.c xroar-0.32/src/jack/ao_jack.c --- xroar-0.31.1/src/jack/ao_jack.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/jack/ao_jack.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -76,7 +76,7 @@ return 0; } /* connect up to 2 ports (stereo output) */ - for (i = 0; ports[i] && i < 2; i++) { + for (i = 0; i < 2 && ports[i]; i++) { if (jack_connect(client, jack_port_name(output_port[i]), ports[i])) { LOG_ERROR("Cannot connect output ports\n"); free(ports); @@ -92,7 +92,7 @@ size_t buffer_nbytes = buffer_nframes * sizeof(float); audio_buffer = g_malloc(buffer_nbytes); sound_init(audio_buffer, SOUND_FMT_FLOAT, rate, 1, buffer_nframes); - LOG_DEBUG(2, "\t%dms (%d frames) buffer\n", (buffer_nframes * 1000) / rate, buffer_nframes); + LOG_DEBUG(1, "\t%dms (%d frames) buffer\n", (buffer_nframes * 1000) / rate, buffer_nframes); pthread_mutex_init(&haltflag, NULL); @@ -117,9 +117,9 @@ static int jack_callback(jack_nframes_t nframes, void *arg) { int i; - jack_default_audio_sample_t *out; (void)arg; /* unused */ for (i = 0; i < num_output_ports; i++) { + jack_default_audio_sample_t *out; out = (float *)jack_port_get_buffer(output_port[i], nframes); memcpy(out, audio_buffer, nframes * sizeof(float)); } diff -Nru xroar-0.31.1/src/joystick.c xroar-0.32/src/joystick.c --- xroar-0.31.1/src/joystick.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/joystick.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -21,23 +21,37 @@ // For strsep() #define _BSD_SOURCE +#include #include -#include "pl_glib.h" -#include "pl_string.h" +#include "pl-string.h" +#include "slist.h" +#include "xalloc.h" #include "joystick.h" #include "logging.h" #include "machine.h" #include "module.h" +extern struct joystick_module linux_js_mod; +extern struct joystick_module sdl_js_mod_exported; +static struct joystick_module * const joystick_module_list[] = { +#ifdef HAVE_LINUX_JOYSTICK + &linux_js_mod, +#endif +#ifdef HAVE_SDL + &sdl_js_mod_exported, +#endif + NULL +}; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static GSList *config_list = NULL; +static struct slist *config_list = NULL; static unsigned num_configs = 0; // Current configuration, per-port: -struct joystick_config *joystick_port_config[JOYSTICK_NUM_PORTS]; +struct joystick_config const *joystick_port_config[JOYSTICK_NUM_PORTS]; static struct joystick_interface *selected_interface = NULL; @@ -51,9 +65,9 @@ static struct joystick *joystick_port[JOYSTICK_NUM_PORTS]; // Support the swap/cycle shortcuts: -static struct joystick_config *virtual_joystick_config; -static struct joystick *virtual_joystick = NULL; -static struct joystick_config *cycled_config[JOYSTICK_NUM_PORTS]; +static struct joystick_config const *virtual_joystick_config; +static struct joystick const *virtual_joystick = NULL; +static struct joystick_config const *cycled_config[JOYSTICK_NUM_PORTS]; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -74,9 +88,9 @@ struct joystick_config *joystick_config_new(void) { struct joystick_config *new; - new = g_malloc0(sizeof(*new)); + new = xzalloc(sizeof(*new)); new->index = num_configs; - config_list = g_slist_append(config_list, new); + config_list = slist_append(config_list, new); num_configs++; return new; } @@ -86,7 +100,7 @@ } struct joystick_config *joystick_config_index(unsigned i) { - for (GSList *l = config_list; l; l = l->next) { + for (struct slist *l = config_list; l; l = l->next) { struct joystick_config *jc = l->data; if (jc->index == i) return jc; @@ -96,7 +110,7 @@ struct joystick_config *joystick_config_by_name(const char *name) { if (!name) return NULL; - for (GSList *l = config_list; l; l = l->next) { + for (struct slist *l = config_list; l; l = l->next) { struct joystick_config *jc = l->data; if (0 == strcmp(jc->name, name)) { return jc; @@ -106,7 +120,7 @@ } void joystick_config_print_all(void) { - for (GSList *l = config_list; l; l = l->next) { + for (struct slist *l = config_list; l; l = l->next) { struct joystick_config *jc = l->data; printf("joy %s\n", jc->name); if (jc->description) printf(" joy-desc %s\n", jc->description); @@ -124,17 +138,17 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static struct joystick_interface *find_if_in_mod(JoystickModule *module, const char *if_name) { +static struct joystick_interface *find_if_in_mod(struct joystick_module *module, const char *if_name) { if (!module || !if_name) return NULL; - for (unsigned i = 0; module->interface_list[i]; i++) { - if (0 == strcmp(module->interface_list[i]->name, if_name)) - return module->interface_list[i]; + for (unsigned i = 0; module->intf_list[i]; i++) { + if (0 == strcmp(module->intf_list[i]->name, if_name)) + return module->intf_list[i]; } return NULL; } -static struct joystick_interface *find_if_in_modlist(JoystickModule **list, const char *if_name) { +static struct joystick_interface *find_if_in_modlist(struct joystick_module * const *list, const char *if_name) { if (!list || !if_name) return NULL; for (unsigned i = 0; list[i]; i++) { @@ -163,9 +177,9 @@ if_name = strsep(spec, ":"); } if (mod_name) { - JoystickModule *m = (JoystickModule *)module_select_by_arg((struct module **)ui_module->joystick_module_list, mod_name); + struct joystick_module *m = (struct joystick_module *)module_select_by_arg((struct module **)ui_module->joystick_module_list, mod_name); if (!m) { - m = (JoystickModule *)module_select_by_arg((struct module **)joystick_module_list, mod_name); + m = (struct joystick_module *)module_select_by_arg((struct module **)joystick_module_list, mod_name); } selected_interface = find_if_in_mod(m, if_name); } else if (if_name) { @@ -175,64 +189,64 @@ } } -void joystick_map(struct joystick_config *jc, unsigned port) { +void joystick_map(struct joystick_config const *jc, unsigned port) { selected_interface = NULL; if (port >= JOYSTICK_NUM_PORTS) return; joystick_unmap(port); if (!jc) return; - struct joystick *j = g_malloc0(sizeof(*j)); + struct joystick *j = xzalloc(sizeof(*j)); _Bool valid_joystick = 0; for (unsigned i = 0; i < JOYSTICK_NUM_AXES; i++) { - char *spec_copy = g_strdup(jc->axis_specs[i]); + char *spec_copy = xstrdup(jc->axis_specs[i]); char *spec = spec_copy; select_interface(&spec); if (!selected_interface) { - g_free(spec_copy); + free(spec_copy); return; } struct joystick_axis *axis = selected_interface->configure_axis(spec, i); j->axes[i] = axis; if (axis) { - axis->interface = selected_interface; + axis->intf = selected_interface; valid_joystick = 1; } - g_free(spec_copy); + free(spec_copy); } for (unsigned i = 0; i < JOYSTICK_NUM_BUTTONS; i++) { - char *spec_copy = g_strdup(jc->button_specs[i]); + char *spec_copy = xstrdup(jc->button_specs[i]); char *spec = spec_copy; select_interface(&spec); if (!selected_interface) { - g_free(spec_copy); + free(spec_copy); return; } struct joystick_button *button = selected_interface->configure_button(spec, i); j->buttons[i] = button; if (button) { - button->interface = selected_interface; + button->intf = selected_interface; valid_joystick = 1; } - g_free(spec_copy); + free(spec_copy); } if (!valid_joystick) { - g_free(j); + free(j); return; } - LOG_DEBUG(2, "Joystick port %d = %s [ ", port, jc->name); + LOG_DEBUG(1, "Joystick port %u = %s [ ", port, jc->name); for (unsigned i = 0; i < JOYSTICK_NUM_AXES; i++) { if (j->axes[i]) - LOG_DEBUG(2, "%d=%s:", i, j->axes[i]->interface->name); - LOG_DEBUG(2, ", "); + LOG_DEBUG(1, "%u=%s:", i, j->axes[i]->intf->name); + LOG_DEBUG(1, ", "); } for (unsigned i = 0; i < JOYSTICK_NUM_BUTTONS; i++) { if (j->buttons[i]) - LOG_DEBUG(2, "%d=%s:", i, j->buttons[i]->interface->name); + LOG_DEBUG(1, "%u=%s:", i, j->buttons[i]->intf->name); if ((i + 1) < JOYSTICK_NUM_BUTTONS) - LOG_DEBUG(2, ", "); + LOG_DEBUG(1, ", "); } - LOG_DEBUG(2, " ]\n"); + LOG_DEBUG(1, " ]\n"); joystick_port[port] = j; joystick_port_config[port] = jc; } @@ -248,29 +262,29 @@ for (unsigned a = 0; a < JOYSTICK_NUM_AXES; a++) { struct joystick_axis *axis = j->axes[a]; if (axis) { - struct joystick_interface *interface = axis->interface; + struct joystick_interface *interface = axis->intf; if (interface->unmap_axis) { interface->unmap_axis(axis); } else { - g_free(j->axes[a]); + free(j->axes[a]); } } } for (unsigned b = 0; b < JOYSTICK_NUM_BUTTONS; b++) { struct joystick_button *button = j->buttons[b]; if (button) { - struct joystick_interface *interface = button->interface; + struct joystick_interface *interface = button->intf; if (interface->unmap_button) { interface->unmap_button(button); } else { - g_free(j->buttons[b]); + free(j->buttons[b]); } } } - g_free(j); + free(j); } -void joystick_set_virtual(struct joystick_config *jc) { +void joystick_set_virtual(struct joystick_config const *jc) { int remap_virtual_to = -1; if (virtual_joystick) { if (joystick_port[0] == virtual_joystick) { @@ -289,10 +303,10 @@ // Swap the right & left joysticks void joystick_swap(void) { - struct joystick_config *tmp_jc = joystick_port_config[0]; + struct joystick_config const *tmp_jc = joystick_port_config[0]; joystick_port_config[0] = joystick_port_config[1]; joystick_port_config[1] = tmp_jc; - struct joystick_config *tmp_cc = cycled_config[0]; + struct joystick_config const *tmp_cc = cycled_config[0]; cycled_config[0] = cycled_config[1]; cycled_config[1] = tmp_cc; struct joystick *tmp_j = joystick_port[0]; diff -Nru xroar-0.31.1/src/joystick.h xroar-0.32/src/joystick.h --- xroar-0.31.1/src/joystick.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/joystick.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,11 +1,13 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ #ifndef XROAR_JOYSTICK_H_ #define XROAR_JOYSTICK_H_ +#include "module.h" + // Each joystick module contains a list of interfaces, with standard names: // // physical - interface reads from a real joystick @@ -17,6 +19,13 @@ // for in both lists. This allows both modules that can exist standalone and // modules that require a specific active UI to be available. +struct joystick_interface; + +struct joystick_module { + struct module common; + struct joystick_interface **intf_list; +}; + // Specs are of the form [[MODULE:]INTERFACE:]CONTROL-SPEC. // The CONTROL-SPEC will vary by interface: @@ -44,7 +53,7 @@ char *button_specs[JOYSTICK_NUM_BUTTONS]; }; -extern struct joystick_config *joystick_port_config[JOYSTICK_NUM_PORTS]; +extern struct joystick_config const *joystick_port_config[JOYSTICK_NUM_PORTS]; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -53,26 +62,24 @@ typedef unsigned (*js_read_axis_func)(void *); typedef _Bool (*js_read_button_func)(void *); -struct joystick_interface; - struct joystick_axis { js_read_axis_func read; void *data; - struct joystick_interface *interface; + struct joystick_interface *intf; }; struct joystick_button { js_read_button_func read; void *data; - struct joystick_interface *interface; + struct joystick_interface *intf; }; struct joystick_interface { const char *name; - struct joystick_axis *(*configure_axis)(char *spec, unsigned jaxis); - struct joystick_button *(*configure_button)(char *spec, unsigned jbutton); - void (*unmap_axis)(struct joystick_axis *); - void (*unmap_button)(struct joystick_button *); + struct joystick_axis *(* const configure_axis)(char *spec, unsigned jaxis); + struct joystick_button *(* const configure_button)(char *spec, unsigned jbutton); + void (* const unmap_axis)(struct joystick_axis *); + void (* const unmap_button)(struct joystick_button *); }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -86,9 +93,9 @@ void joystick_init(void); void joystick_shutdown(void); -void joystick_map(struct joystick_config *, unsigned port); +void joystick_map(struct joystick_config const *, unsigned port); void joystick_unmap(unsigned port); -void joystick_set_virtual(struct joystick_config *); +void joystick_set_virtual(struct joystick_config const *); void joystick_swap(void); void joystick_cycle(void); diff -Nru xroar-0.31.1/src/keyboard.c xroar-0.32/src/keyboard.c --- xroar-0.31.1/src/keyboard.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/keyboard.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -21,7 +21,8 @@ #include #include -#include "pl_glib.h" +#include "slist.h" +#include "xalloc.h" #include "breakpoint.h" #include "dkbd.h" @@ -70,44 +71,50 @@ } } -/* Compute which rows & columns are to act as sinks based on inputs to the - * matrix and the current state of depressed keys. */ +/* Compute sources & sinks based on inputs to the matrix and the current state + * of depressed keys. */ -void keyboard_read_matrix(int row_in, int col_in, int *row_sink, int *col_sink) { - /* Pull low any directly connected rows & columns */ - for (int i = 0; i < 8; i++) { - if (!(col_in & (1 << i))) { - *row_sink &= keyboard_column[i]; - } - } - for (int i = 0; i < 7; i++) { - if (!(row_in & (1 << i))) { - *col_sink &= keyboard_row[i]; - } - } - /* Ghosting: pull low column inputs that share any pulled low rows, and - * merge that column's direct row connections. Repeat until no change - * in the row mask. */ +void keyboard_read_matrix(struct keyboard_state *state) { + /* Ghosting: combine columns that share any pressed rows. Repeat until + * no change in the row mask. */ int old; do { - old = *row_sink; + old = state->row_sink; for (int i = 0; i < 8; i++) { - if (~*row_sink & ~keyboard_column[i]) { - *col_sink &= ~(1 << i); - *row_sink &= keyboard_column[i]; + if (~state->row_sink & ~keyboard_column[i]) { + state->col_sink &= ~(1 << i); + state->row_sink &= keyboard_column[i]; } } - } while (old != *row_sink); - /* Likewise the other way around. */ + } while (old != state->row_sink); + /* Likewise combining rows. */ do { - old = *col_sink; + old = state->col_sink; for (int i = 0; i < 7; i++) { - if (~*col_sink & ~keyboard_row[i]) { - *row_sink &= ~(1 << i); - *col_sink &= keyboard_row[i]; + if (~state->col_sink & ~keyboard_row[i]) { + state->row_sink &= ~(1 << i); + state->col_sink &= keyboard_row[i]; } } - } while (old != *col_sink); + } while (old != state->col_sink); + + /* Sink & source any directly connected rows & columns */ + for (int i = 0; i < 8; i++) { + if (!(state->col_sink & (1 << i))) { + state->row_sink &= keyboard_column[i]; + } + if (state->col_source & (1 << i)) { + state->row_source |= ~keyboard_column[i]; + } + } + for (int i = 0; i < 7; i++) { + if (!(state->row_sink & (1 << i))) { + state->col_sink &= keyboard_row[i]; + } + if (state->row_source & (1 << i)) { + state->col_source |= ~keyboard_row[i]; + } + } } void keyboard_unicode_press(unsigned unicode) { @@ -136,7 +143,7 @@ return; } -static GSList *basic_command_list = NULL; +static struct slist *basic_command_list = NULL; static const uint8_t *basic_command = NULL; static void type_command(struct MC6809 *cpu); @@ -231,8 +238,8 @@ if (!basic_command) { if (basic_command_list) { void *data = basic_command_list->data; - basic_command_list = g_slist_remove(basic_command_list, data); - g_free(data); + basic_command_list = slist_remove(basic_command_list, data); + free(data); } if (basic_command_list) { basic_command = basic_command_list->data; @@ -248,8 +255,8 @@ char *data = NULL; bp_remove_list(basic_command_breakpoint); if (s) { - data = g_strdup(s); - basic_command_list = g_slist_append(basic_command_list, data); + data = xstrdup(s); + basic_command_list = slist_append(basic_command_list, data); } if (!basic_command) { basic_command = data; diff -Nru xroar-0.31.1/src/keyboard.h xroar-0.32/src/keyboard.h --- xroar-0.31.1/src/keyboard.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/keyboard.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -25,6 +25,13 @@ extern unsigned keyboard_column[9]; extern unsigned keyboard_row[9]; +struct keyboard_state { + unsigned row_source; + unsigned row_sink; + unsigned col_source; + unsigned col_sink; +}; + /* Press or release a key at the the matrix position (col,row). */ static inline void keyboard_press_matrix(int col, int row) { @@ -68,7 +75,7 @@ void keyboard_set_chord_mode(enum keyboard_chord_mode mode); -void keyboard_read_matrix(int row_out, int col_out, int *row_in, int *col_in); +void keyboard_read_matrix(struct keyboard_state *); void keyboard_unicode_press(unsigned unicode); void keyboard_unicode_release(unsigned unicode); void keyboard_queue_basic(const uint8_t *s); diff -Nru xroar-0.31.1/src/linux/joystick_linux.c xroar-0.32/src/linux/joystick_linux.c --- xroar-0.31.1/src/linux/joystick_linux.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/linux/joystick_linux.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -30,8 +30,9 @@ #include #include -#include "pl_glib.h" -#include "pl_string.h" +#include "pl-string.h" +#include "slist.h" +#include "xalloc.h" #include "events.h" #include "joystick.h" @@ -63,9 +64,9 @@ NULL }; -JoystickModule linux_js_mod = { +struct joystick_module linux_js_mod = { .common = { .name = "linux", .description = "Linux joystick input" }, - .interface_list = js_iflist, + .intf_list = js_iflist, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -80,7 +81,7 @@ _Bool *button_value; }; -static GSList *device_list = NULL; +static struct slist *device_list = NULL; struct control { struct device *device; @@ -92,7 +93,7 @@ static struct device *open_device(int joystick_index) { // If the device is already open, just up its count and return it - for (GSList *iter = device_list; iter; iter = iter->next) { + for (struct slist *iter = device_list; iter; iter = iter->next) { struct device *d = iter->data; if (d->joystick_index == joystick_index) { d->open_count++; @@ -110,7 +111,7 @@ } if (fd < 0) return NULL; - struct device *d = g_malloc(sizeof(*d)); + struct device *d = xmalloc(sizeof(*d)); d->joystick_index = joystick_index; d->fd = fd; char tmp; @@ -119,15 +120,15 @@ ioctl(fd, JSIOCGBUTTONS, &tmp); d->num_buttons = tmp; if (d->num_axes > 0) - d->axis_value = g_malloc0(d->num_axes * sizeof(*d->axis_value)); + d->axis_value = xzalloc(d->num_axes * sizeof(*d->axis_value)); if (d->num_buttons > 0) - d->button_value = g_malloc0(d->num_buttons * sizeof(*d->button_value)); + d->button_value = xzalloc(d->num_buttons * sizeof(*d->button_value)); char namebuf[128]; ioctl(fd, JSIOCGNAME(sizeof(namebuf)), namebuf); LOG_DEBUG(1, "Opened joystick %d: %s\n", joystick_index, namebuf); - LOG_DEBUG(2, "\t%d axes, %d buttons\n", d->num_axes, d->num_buttons); + LOG_DEBUG(1, "\t%d axes, %d buttons\n", d->num_axes, d->num_buttons); d->open_count = 1; - device_list = g_slist_prepend(device_list, d); + device_list = slist_prepend(device_list, d); return d; } @@ -135,17 +136,17 @@ d->open_count--; if (d->open_count == 0) { close(d->fd); - g_free(d->axis_value); - g_free(d->button_value); - device_list = g_slist_remove(device_list, d); - g_free(d); + free(d->axis_value); + free(d->button_value); + device_list = slist_remove(device_list, d); + free(d); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static void poll_devices(void) { - for (GSList *iter = device_list; iter; iter = iter->next) { + for (struct slist *iter = device_list; iter; iter = iter->next) { struct device *d = iter->data; struct js_event e; while (read(d->fd, &e, sizeof(e)) == sizeof(e)) { @@ -208,7 +209,7 @@ struct device *d = open_device(joystick); if (!d) return NULL; - struct control *c = g_malloc(sizeof(*c)); + struct control *c = xmalloc(sizeof(*c)); c->device = d; c->control = control; c->inverted = inverted; @@ -221,10 +222,10 @@ return NULL; if (c->control >= c->device->num_axes) { close_device(c->device); - g_free(c); + free(c); return NULL; } - struct joystick_axis *axis = g_malloc(sizeof(*axis)); + struct joystick_axis *axis = xmalloc(sizeof(*axis)); axis->read = (js_read_axis_func)read_axis; axis->data = c; return axis; @@ -236,10 +237,10 @@ return NULL; if (c->control >= c->device->num_buttons) { close_device(c->device); - g_free(c); + free(c); return NULL; } - struct joystick_button *button = g_malloc(sizeof(*button)); + struct joystick_button *button = xmalloc(sizeof(*button)); button->read = (js_read_button_func)read_button; button->data = c; return button; @@ -250,8 +251,8 @@ return; struct control *c = axis->data; close_device(c->device); - g_free(c); - g_free(axis); + free(c); + free(axis); } static void unmap_button(struct joystick_button *button) { @@ -259,6 +260,6 @@ return; struct control *c = button->data; close_device(c->device); - g_free(c); - g_free(button); + free(c); + free(button); } diff -Nru xroar-0.31.1/src/logging.c xroar-0.32/src/logging.c --- xroar-0.31.1/src/logging.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/logging.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -22,12 +22,15 @@ #include #include #include +#include -#include "pl_glib.h" +#include "xalloc.h" #include "logging.h" #include "xroar.h" +int log_level = 1; + enum log_type { LOG_HEXDUMP, }; @@ -48,7 +51,7 @@ static void log_open(struct log_handle **lp, const char *prefix, enum log_type type) { assert(lp != NULL); log_close(lp); - struct log_handle *l = g_malloc0(sizeof(*l)); + struct log_handle *l = xzalloc(sizeof(*l)); l->type = type; l->prefix = prefix; *lp = l; @@ -74,12 +77,13 @@ default: break; } - g_free(l); + free(l); *lp = NULL; } void log_hexdump_set_addr(struct log_handle *l, unsigned addr) { - assert(l != NULL); + if (!l) + return; if (l->ctx.hexdump.address != addr) { log_hexdump_line(l); l->ctx.hexdump.address = addr; @@ -87,7 +91,8 @@ } void log_hexdump_line(struct log_handle *l) { - assert(l != NULL); + if (!l) + return; assert(l->prefix != NULL); assert(l->type == LOG_HEXDUMP); if (l->ctx.hexdump.nbytes == 0) @@ -117,7 +122,8 @@ } void log_hexdump_byte(struct log_handle *l, uint8_t b) { - assert(l != NULL); + if (!l) + return; assert(l->type == LOG_HEXDUMP); if (l->ctx.hexdump.nbytes >= 16) log_hexdump_line(l); @@ -125,7 +131,8 @@ } void log_hexdump_flag(struct log_handle *l) { - assert(l != NULL); + if (!l) + return; assert(l->type == LOG_HEXDUMP); l->ctx.hexdump.flag = l->ctx.hexdump.nbytes; } diff -Nru xroar-0.31.1/src/logging.h xroar-0.32/src/logging.h --- xroar-0.31.1/src/logging.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/logging.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -20,19 +20,18 @@ #include -/* 0 - Silent, 1 - Title, 2 - Info, 3 - Details, 4 - Verbose, 5 - Silly */ -/* Normally 3 */ -#ifndef DEBUG_LEVEL -# define DEBUG_LEVEL 2 -#endif +/* Log levels: + * 0 - Quiet, 1 - Info, 2 - Events, 3 - Debug */ -#define LOG_DEBUG(l,...) do { if (DEBUG_LEVEL >= l) { fprintf(stderr, __VA_ARGS__); } } while (0) +#define LOG_DEBUG(l,...) do { if (log_level >= l) { fprintf(stderr, __VA_ARGS__); } } while (0) #define LOG_PRINT(...) printf(__VA_ARGS__) #define LOG_WARN(...) fprintf(stderr, "WARNING: " __VA_ARGS__) #define LOG_ERROR(...) fprintf(stderr, "ERROR: " __VA_ARGS__) #endif +extern int log_level; + struct log_handle; // close any open log diff -Nru xroar-0.31.1/src/machine.c xroar-0.32/src/machine.c --- xroar-0.31.1/src/machine.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/machine.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -27,7 +27,10 @@ #include #include -#include "pl_glib.h" +#include "array.h" +#include "c-strcase.h" +#include "slist.h" +#include "xalloc.h" #include "breakpoint.h" #include "cart.h" @@ -90,7 +93,7 @@ { "@coco", "@coco_ext", NULL } }; -static GSList *config_list = NULL; +static struct slist *config_list = NULL; static int num_configs = 0; static void initialise_ram(void); @@ -98,9 +101,9 @@ static int cycles; static uint8_t read_cycle(uint16_t A); static void write_cycle(uint16_t A, uint8_t D); -static void vdg_fetch_handler(int nbytes, uint8_t *dest); +static void vdg_fetch_handler(void *sptr, int nbytes, uint8_t *dest); -static void machine_instruction_posthook(void *dptr); +static void machine_instruction_posthook(void *); static _Bool single_step = 0; static int stop_signal = 0; @@ -108,7 +111,7 @@ struct machine_config *machine_config_new(void) { struct machine_config *new; - new = g_malloc0(sizeof(*new)); + new = xzalloc(sizeof(*new)); new->index = num_configs; new->architecture = ANY_AUTO; new->cpu = CPU_MC6809; @@ -117,7 +120,7 @@ new->vdg_type = ANY_AUTO; new->ram = ANY_AUTO; new->cart_enabled = 1; - config_list = g_slist_append(config_list, new); + config_list = slist_append(config_list, new); num_configs++; return new; } @@ -127,7 +130,7 @@ } struct machine_config *machine_config_index(int i) { - for (GSList *l = config_list; l; l = l->next) { + for (struct slist *l = config_list; l; l = l->next) { struct machine_config *mc = l->data; if (mc->index == i) return mc; @@ -137,7 +140,7 @@ struct machine_config *machine_config_by_name(const char *name) { if (!name) return NULL; - for (GSList *l = config_list; l; l = l->next) { + for (struct slist *l = config_list; l; l = l->next) { struct machine_config *mc = l->data; if (0 == strcmp(mc->name, name)) { return mc; @@ -147,7 +150,7 @@ } struct machine_config *machine_config_by_arch(int arch) { - for (GSList *l = config_list; l; l = l->next) { + for (struct slist *l = config_list; l; l = l->next) { struct machine_config *mc = l->data; if (mc->architecture == arch) { return mc; @@ -171,7 +174,7 @@ arch = ARCH_DRAGON64; } if (tmp) - g_free(tmp); + free(tmp); return arch; } @@ -181,7 +184,7 @@ void machine_config_complete(struct machine_config *mc) { if (!mc->description) { - mc->description = g_strdup(mc->name); + mc->description = xstrdup(mc->name); } if (mc->tv_standard == ANY_AUTO) mc->tv_standard = TV_PAL; @@ -228,51 +231,51 @@ } /* Now find which ROMs we're actually going to use */ if (!mc->nobas && !mc->bas_rom && rom_list[mc->architecture].bas) { - mc->bas_rom = g_strdup(rom_list[mc->architecture].bas); + mc->bas_rom = xstrdup(rom_list[mc->architecture].bas); } if (!mc->noextbas && !mc->extbas_rom && rom_list[mc->architecture].extbas) { - mc->extbas_rom = g_strdup(rom_list[mc->architecture].extbas); + mc->extbas_rom = xstrdup(rom_list[mc->architecture].extbas); } if (!mc->noaltbas && !mc->altbas_rom && rom_list[mc->architecture].altbas) { - mc->altbas_rom = g_strdup(rom_list[mc->architecture].altbas); + mc->altbas_rom = xstrdup(rom_list[mc->architecture].altbas); } // Determine a default DOS cartridge if necessary if (!mc->default_cart) { struct cart_config *cc = cart_find_working_dos(mc); if (cc) - mc->default_cart = g_strdup(cc->name); + mc->default_cart = xstrdup(cc->name); } } -static const char *machine_arch_string[] = { +static char const * const machine_arch_string[] = { "dragon32", "dragon64", "coco", }; -static const char *machine_cpu_string[] = { +static char const * const machine_cpu_string[] = { "6809", "6309", }; -static const char *machine_tv_type_string[] = { +static char const * const machine_tv_type_string[] = { "pal", "ntsc", }; -static const char *machine_vdg_type_string[] = { +static char const * const machine_vdg_type_string[] = { "6847", "6847t1", }; void machine_config_print_all(void) { - for (GSList *l = config_list; l; l = l->next) { + for (struct slist *l = config_list; l; l = l->next) { struct machine_config *mc = l->data; printf("machine %s\n", mc->name); if (mc->description) printf(" machine-desc %s\n", mc->description); - if (mc->architecture >= 0 && mc->architecture < G_N_ELEMENTS(machine_arch_string)) + if (mc->architecture >= 0 && mc->architecture < ARRAY_N_ELEMENTS(machine_arch_string)) printf(" machine-arch %s\n", machine_arch_string[mc->architecture]); - if (mc->cpu >= 0 && mc->cpu < G_N_ELEMENTS(machine_cpu_string)) + if (mc->cpu >= 0 && mc->cpu < ARRAY_N_ELEMENTS(machine_cpu_string)) printf(" machine-cpu %s\n", machine_cpu_string[mc->cpu]); if (mc->vdg_palette) printf(" machine-palette %s\n", mc->vdg_palette); if (mc->bas_rom) printf(" bas %s\n", mc->bas_rom); @@ -282,9 +285,9 @@ if (mc->noextbas) printf(" noextbas\n"); if (mc->noaltbas) printf(" noaltbas\n"); if (mc->ext_charset_rom) printf(" ext-charset %s\n", mc->ext_charset_rom); - if (mc->tv_standard >= 0 && mc->tv_standard < G_N_ELEMENTS(machine_tv_type_string)) + if (mc->tv_standard >= 0 && mc->tv_standard < ARRAY_N_ELEMENTS(machine_tv_type_string)) printf(" tv-type %s\n", machine_tv_type_string[mc->tv_standard]); - if (mc->vdg_type >= 0 && mc->vdg_type < G_N_ELEMENTS(machine_vdg_type_string)) + if (mc->vdg_type >= 0 && mc->vdg_type < ARRAY_N_ELEMENTS(machine_vdg_type_string)) printf(" vdg-type %s\n", machine_vdg_type_string[mc->vdg_type]); if (mc->ram >= 0) printf(" ram %d\n", mc->ram); if (mc->default_cart) printf(" machine-cart %s\n", mc->default_cart); @@ -296,12 +299,17 @@ /* ---------------------------------------------------------------------- */ static void keyboard_update(void) { - int row = PIA0->a.out_sink; - int col = PIA0->b.out_source & PIA0->b.out_sink; - int row_sink = 0xff, col_sink = 0xff; - keyboard_read_matrix(row, col, &row_sink, &col_sink); - PIA0->a.in_sink = (PIA0->a.in_sink & 0x80) | (row_sink & 0x7f); - PIA0->b.in_sink = col_sink; + unsigned buttons = ~(joystick_read_buttons() & 3); + struct keyboard_state state = { + .row_source = PIA0->a.out_sink, + .row_sink = PIA0->a.out_sink & buttons, + .col_source = PIA0->b.out_source, + .col_sink = PIA0->b.out_sink, + }; + keyboard_read_matrix(&state); + PIA0->a.in_sink = state.row_sink; + PIA0->b.in_source = state.col_source; + PIA0->b.in_sink = state.col_sink; } static void joystick_update(void) { @@ -313,7 +321,6 @@ PIA0->a.in_sink |= 0x80; else PIA0->a.in_sink &= 0x7f; - PIA0->a.in_sink &= ~(joystick_read_buttons() & 3); } static void update_sound_mux_source(void) { @@ -428,8 +435,8 @@ /* VDG edge delegates */ -static void vdg_hs(void *dptr, _Bool level) { - (void)dptr; +static void vdg_hs(void *sptr, _Bool level) { + (void)sptr; if (level) mc6821_set_cx1(&PIA0->a); else @@ -438,8 +445,8 @@ } // PAL CoCos invert HS -static void vdg_hs_pal_coco(void *dptr, _Bool level) { - (void)dptr; +static void vdg_hs_pal_coco(void *sptr, _Bool level) { + (void)sptr; if (level) mc6821_reset_cx1(&PIA0->a); else @@ -447,8 +454,8 @@ sam_vdg_hsync(level); } -static void vdg_fs(void *dptr, _Bool level) { - (void)dptr; +static void vdg_fs(void *sptr, _Bool level) { + (void)sptr; if (level) { mc6821_set_cx1(&PIA0->b); } else { @@ -460,8 +467,8 @@ /* Dragon parallel printer line delegate. */ //ACK is active low -static void printer_ack(void *dptr, _Bool ack) { - (void)dptr; +static void printer_ack(void *sptr, _Bool ack) { + (void)sptr; if (ack) mc6821_reset_cx1(&PIA1->a); else @@ -471,8 +478,8 @@ /* Sound output can feed back into the single bit sound pin when it's * configured as an input. */ -static void single_bit_feedback(void *dptr, _Bool level) { - (void)dptr; +static void single_bit_feedback(void *sptr, _Bool level) { + (void)sptr; if (level) { PIA1->b.in_source &= ~(1<<1); PIA1->b.in_sink &= ~(1<<1); @@ -484,8 +491,8 @@ /* Tape audio delegate */ -static void update_audio_from_tape(void *dptr, float value) { - (void)dptr; +static void update_audio_from_tape(void *sptr, float value) { + (void)sptr; sound_set_tape_level(value); if (value >= 0.5) PIA1->a.in_sink &= ~(1<<0); @@ -495,21 +502,21 @@ /* Catridge signalling */ -static void cart_firq(void *dptr, _Bool level) { - (void)dptr; +static void cart_firq(void *sptr, _Bool level) { + (void)sptr; if (level) mc6821_set_cx1(&PIA1->b); else mc6821_reset_cx1(&PIA1->b); } -static void cart_nmi(void *dptr, _Bool level) { - (void)dptr; +static void cart_nmi(void *sptr, _Bool level) { + (void)sptr; MC6809_NMI_SET(CPU0, level); } -static void cart_halt(void *dptr, _Bool level) { - (void)dptr; +static void cart_halt(void *sptr, _Bool level) { + (void)sptr; MC6809_HALT_SET(CPU0, level); } @@ -519,7 +526,7 @@ if (!mc) return; machine_config_complete(mc); if (mc->description) { - LOG_DEBUG(2, "Machine: %s\n", mc->description); + LOG_DEBUG(1, "Machine: %s\n", mc->description); } // CPU if (CPU0) { @@ -536,7 +543,6 @@ } CPU0->read_cycle = read_cycle; CPU0->write_cycle = write_cycle; - CPU0->instr_posthook_dptr = CPU0; // PIAs if (PIA0) { mc6821_free(PIA0); @@ -563,11 +569,11 @@ // Single-bit sound feedback #ifndef FAST_SOUND - sound_sbs_feedback = (sound_feedback_delegate){single_bit_feedback, NULL}; + sound_sbs_feedback = DELEGATE_AS1(void, bool, single_bit_feedback, NULL); #endif // Tape - tape_update_audio = (tape_audio_delegate){update_audio_from_tape, NULL}; + tape_update_audio = DELEGATE_AS1(void, float, update_audio_from_tape, NULL); // VDG if (VDG0) @@ -575,16 +581,16 @@ VDG0 = mc6847_new(mc->vdg_type == VDG_6847T1); if (IS_COCO && IS_PAL) { - mc6847_set_signal_hs(VDG0, (vdg_edge_delegate){vdg_hs_pal_coco, NULL}); + VDG0->signal_hs = DELEGATE_AS1(void, bool, vdg_hs_pal_coco, NULL); } else { - mc6847_set_signal_hs(VDG0, (vdg_edge_delegate){vdg_hs, NULL}); + VDG0->signal_hs = DELEGATE_AS1(void, bool, vdg_hs, NULL); } - mc6847_set_signal_fs(VDG0, (vdg_edge_delegate){vdg_fs, NULL}); - mc6847_set_fetch_bytes(VDG0, vdg_fetch_handler); + VDG0->signal_fs = DELEGATE_AS1(void, bool, vdg_fs, NULL); + VDG0->fetch_bytes = DELEGATE_AS2(void, int, uint8p, vdg_fetch_handler, NULL); mc6847_set_inverted_text(VDG0, inverted_text); // Printer - printer_signal_ack = (printer_line_delegate){printer_ack, NULL}; + printer_signal_ack = DELEGATE_AS1(void, bool, printer_ack, NULL); /* Load appropriate ROMs */ memset(rom0, 0, sizeof(rom0)); @@ -627,7 +633,7 @@ has_bas = 1; has_combined = 1; } - g_free(tmp); + free(tmp); } } @@ -638,7 +644,7 @@ int size = machine_load_rom(tmp, rom0 + 0x2000, sizeof(rom0) - 0x2000); if (size > 0) has_bas = 1; - g_free(tmp); + free(tmp); } } @@ -649,7 +655,7 @@ int size = machine_load_rom(tmp, rom1, sizeof(rom1)); if (size > 0) has_altbas = 1; - g_free(tmp); + free(tmp); } } machine_ram_size = mc->ram * 1024; @@ -662,7 +668,7 @@ int size = machine_load_rom(tmp, ext_charset, sizeof(ext_charset)); if (size > 0) has_ext_charset = 1; - g_free(tmp); + free(tmp); } } @@ -678,7 +684,8 @@ } else { crc_combined = crc32_block(CRC32_RESET, rom0, 0x4000); } - LOG_DEBUG(2, "\t32K mode BASIC CRC = 0x%08x%s\n", crc_combined, forced ? " (forced)" : ""); + (void)forced; // avoid warning if no logging + LOG_DEBUG(1, "\t32K mode BASIC CRC = 0x%08x%s\n", crc_combined, forced ? " (forced)" : ""); } if (has_altbas) { _Bool forced = 0; @@ -688,7 +695,8 @@ } else { crc_altbas = crc32_block(CRC32_RESET, rom1, 0x4000); } - LOG_DEBUG(2, "\t64K mode BASIC CRC = 0x%08x%s\n", crc_altbas, forced ? " (forced)" : ""); + (void)forced; // avoid warning if no logging + LOG_DEBUG(1, "\t64K mode BASIC CRC = 0x%08x%s\n", crc_altbas, forced ? " (forced)" : ""); } if (has_bas) { _Bool forced = 0; @@ -698,7 +706,8 @@ } else { crc_bas = crc32_block(CRC32_RESET, rom0 + 0x2000, 0x2000); } - LOG_DEBUG(2, "\tBASIC CRC = 0x%08x%s\n", crc_bas, forced ? " (forced)" : ""); + (void)forced; // avoid warning if no logging + LOG_DEBUG(1, "\tBASIC CRC = 0x%08x%s\n", crc_bas, forced ? " (forced)" : ""); } if (has_extbas) { _Bool forced = 0; @@ -708,11 +717,12 @@ } else { crc_extbas = crc32_block(CRC32_RESET, rom0, 0x2000); } - LOG_DEBUG(2, "\tExtended BASIC CRC = 0x%08x%s\n", crc_extbas, forced ? " (forced)" : ""); + (void)forced; // avoid warning if no logging + LOG_DEBUG(1, "\tExtended BASIC CRC = 0x%08x%s\n", crc_extbas, forced ? " (forced)" : ""); } if (has_ext_charset) { crc_ext_charset = crc32_block(CRC32_RESET, ext_charset, 0x1000); - LOG_DEBUG(2, "\tExternal charset CRC = 0x%08x\n", crc_ext_charset); + LOG_DEBUG(1, "\tExternal charset CRC = 0x%08x\n", crc_ext_charset); } /* VDG external charset */ @@ -827,13 +837,13 @@ void machine_single_step(void) { single_step = 1; CPU0->running = 0; - CPU0->instruction_posthook = machine_instruction_posthook; + CPU0->instruction_posthook = DELEGATE_AS0(void, machine_instruction_posthook, CPU0); do { CPU0->run(CPU0); } while (single_step); update_vdg_mode(); if (xroar_cfg.trace_enabled) - CPU0->instruction_posthook = NULL; + CPU0->instruction_posthook.func = NULL; } /* @@ -848,9 +858,9 @@ void machine_set_trace(_Bool trace_on) { if (trace_on || single_step) - CPU0->instruction_posthook = machine_instruction_posthook; + CPU0->instruction_posthook = DELEGATE_AS0(void, machine_instruction_posthook, CPU0); else - CPU0->instruction_posthook = NULL; + CPU0->instruction_posthook.func = NULL; } /* @@ -883,8 +893,8 @@ * Used when single-stepping or tracing. */ -static void machine_instruction_posthook(void *dptr) { - struct MC6809 *cpu = dptr; +static void machine_instruction_posthook(void *sptr) { + struct MC6809 *cpu = sptr; if (xroar_cfg.trace_enabled) { switch (xroar_machine_config->cpu) { case CPU_MC6809: default: @@ -1064,7 +1074,8 @@ bp_wp_write_hook(A); } -static void vdg_fetch_handler(int nbytes, uint8_t *dest) { +static void vdg_fetch_handler(void *sptr, int nbytes, uint8_t *dest) { + (void)sptr; while (nbytes > 0) { uint16_t V = 0; _Bool valid; @@ -1235,9 +1246,9 @@ assert(c->read != NULL); assert(c->write != NULL); machine_cart = c; - c->signal_firq = (cart_signal_delegate){cart_firq, NULL}; - c->signal_nmi = (cart_signal_delegate){cart_nmi, NULL}; - c->signal_halt = (cart_signal_delegate){cart_halt, NULL}; + c->signal_firq = DELEGATE_AS1(void, bool, cart_firq, NULL); + c->signal_nmi = DELEGATE_AS1(void, bool, cart_nmi, NULL); + c->signal_halt = DELEGATE_AS1(void, bool, cart_halt, NULL); } } @@ -1273,11 +1284,15 @@ if (!(fd = fopen(path, "rb"))) { return -1; } - if (dot && g_ascii_strcasecmp(dot, ".dgn") == 0) { - LOG_DEBUG(2, "Loading DGN: %s\n", path); - fread(dest, 1, 16, fd); + if (dot && c_strcasecmp(dot, ".dgn") == 0) { + LOG_DEBUG(1, "Loading DGN: %s\n", path); + if (fread(dest, 16, 1, fd) < 1) { + LOG_WARN("Failed to read DGN header in '%s'\n", path); + fclose(fd); + return -1; + } } else { - LOG_DEBUG(2, "Loading ROM: %s\n", path); + LOG_DEBUG(1, "Loading ROM: %s\n", path); } size = fread(dest, 1, max_size, fd); fclose(fd); diff -Nru xroar-0.31.1/src/machine.h xroar-0.32/src/machine.h --- xroar-0.31.1/src/machine.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/machine.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/macosx/ao_macosx.c xroar-0.32/src/macosx/ao_macosx.c --- xroar-0.31.1/src/macosx/ao_macosx.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/macosx/ao_macosx.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -16,6 +16,12 @@ * along with XRoar. If not, see . */ +/* Core Audio processes audio in a separate thread, using a callback to request + * more data. When the configured number of audio fragments (nfragments) is 1, + * write directly into the buffer provided by Core Audio. When nfragments > 1, + * maintain a queue of fragment buffers; the callback takes the next filled + * buffer from the queue and copies its data into place. */ + #include "config.h" #include @@ -25,7 +31,7 @@ #include -#include "pl_glib.h" +#include "xalloc.h" #include "logging.h" #include "machine.h" @@ -48,20 +54,23 @@ static AudioDeviceIOProcID aprocid; #endif -static float *audio_buffer; -static _Bool halt; +static void *callback_buffer; static _Bool shutting_down; -static pthread_mutex_t audio_buffer_mutex; -static pthread_cond_t audio_buffer_cv; -static pthread_mutex_t halt_mutex; -static pthread_cond_t halt_cv; +static unsigned nfragments; +static unsigned fragment_nbytes; -static OSStatus callback(AudioDeviceID inDevice, const AudioTimeStamp *inNow, - const AudioBufferList *inInputData, - const AudioTimeStamp *inInputTime, - AudioBufferList *outOutputData, - const AudioTimeStamp *inOutputTime, void *defptr); +static pthread_mutex_t fragment_mutex; +static pthread_cond_t fragment_cv; +static void **fragment_buffer; +static unsigned fragment_queue_length; +static unsigned write_fragment; +static unsigned play_fragment; + +static OSStatus callback(AudioDeviceID, const AudioTimeStamp *, const AudioBufferList *, + const AudioTimeStamp *, AudioBufferList *, const AudioTimeStamp *, void *); +static OSStatus callback_1(AudioDeviceID, const AudioTimeStamp *, const AudioBufferList *, + const AudioTimeStamp *, AudioBufferList *, const AudioTimeStamp *, void *); static _Bool init(void) { AudioObjectPropertyAddress propertyAddress; @@ -88,58 +97,80 @@ if (!(deviceFormat.mFormatFlags & kLinearPCMFormatFlagIsFloat)) goto failed; - /* More than one fragment not currently supported. */ + nfragments = 2; + if (xroar_cfg.ao_fragments > 0 && xroar_cfg.ao_fragments <= 64) + nfragments = xroar_cfg.ao_fragments; unsigned rate = deviceFormat.mSampleRate; unsigned nchannels = deviceFormat.mChannelsPerFrame; - unsigned fragment_nframes = 1024; + unsigned fragment_nframes; + unsigned buffer_nframes; + enum sound_fmt sample_fmt = SOUND_FMT_FLOAT; + unsigned sample_nbytes = sizeof(float); + unsigned frame_nbytes = nchannels * sample_nbytes; if (xroar_cfg.ao_fragment_ms > 0) { fragment_nframes = (rate * xroar_cfg.ao_fragment_ms) / 1000; } else if (xroar_cfg.ao_fragment_nframes > 0) { fragment_nframes = xroar_cfg.ao_fragment_nframes; - } else if (xroar_cfg.ao_buffer_ms > 0) { - fragment_nframes = (rate * xroar_cfg.ao_buffer_ms) / 1000; - } else if (xroar_cfg.ao_buffer_nframes > 0) { - fragment_nframes = xroar_cfg.ao_buffer_nframes; } else { - fragment_nframes = 1024; + if (xroar_cfg.ao_buffer_ms > 0) { + buffer_nframes = (rate * xroar_cfg.ao_buffer_ms) / 1000; + } else if (xroar_cfg.ao_buffer_nframes > 0) { + buffer_nframes = xroar_cfg.ao_buffer_nframes; + } else { + buffer_nframes = 1024; + } + fragment_nframes = buffer_nframes / nfragments; } - unsigned buffer_nsamples = fragment_nframes * nchannels; - UInt32 buffer_nbytes = buffer_nsamples * sizeof(float); - propertySize = sizeof(buffer_nbytes); + UInt32 prop_buf_size = fragment_nframes * frame_nbytes; + propertySize = sizeof(prop_buf_size); propertyAddress.mSelector = kAudioDevicePropertyBufferSize; - if (AudioObjectSetPropertyData(device, &propertyAddress, 0, NULL, propertySize, &buffer_nbytes) != kAudioHardwareNoError) + if (AudioObjectSetPropertyData(device, &propertyAddress, 0, NULL, propertySize, &prop_buf_size) != kAudioHardwareNoError) goto failed; - buffer_nsamples = buffer_nbytes / sizeof(float); - fragment_nframes = buffer_nsamples / nchannels; + fragment_nframes = prop_buf_size / frame_nbytes; #ifdef MAC_OS_X_VERSION_10_5 - AudioDeviceCreateIOProcID(device, callback, NULL, &aprocid); + AudioDeviceCreateIOProcID(device, (nfragments == 1) ? callback_1 : callback, NULL, &aprocid); #else - AudioDeviceAddIOProc(device, callback, NULL); + AudioDeviceAddIOProc(device, (nfragments == 1) ? callback_1 : callback, NULL); #endif - pthread_mutex_init(&audio_buffer_mutex, NULL); - pthread_cond_init(&audio_buffer_cv, NULL); - pthread_mutex_init(&halt_mutex, NULL); - pthread_cond_init(&halt_cv, NULL); + buffer_nframes = fragment_nframes * nfragments; + fragment_nbytes = fragment_nframes * nchannels * sample_nbytes; + + pthread_mutex_init(&fragment_mutex, NULL); + pthread_cond_init(&fragment_cv, NULL); - audio_buffer = NULL; - halt = 1; shutting_down = 0; + fragment_queue_length = 0; + write_fragment = 0; + play_fragment = 0; + callback_buffer = NULL; + + // allocate fragment buffers + fragment_buffer = xmalloc(nfragments * sizeof(void *)); + if (nfragments > 1) { + for (unsigned i = 0; i < nfragments; i++) { + fragment_buffer[i] = xzalloc(fragment_nbytes); + } + } + + AudioDeviceStart(device, (nfragments == 1) ? callback_1 : callback); - pthread_mutex_lock(&audio_buffer_mutex); - AudioDeviceStart(device, callback); - // wait for initial buffer from audio thread - while (!audio_buffer) - pthread_cond_wait(&audio_buffer_cv, &audio_buffer_mutex); - - sound_init(audio_buffer, SOUND_FMT_FLOAT, rate, nchannels, fragment_nframes); - audio_buffer = NULL; - pthread_mutex_unlock(&audio_buffer_mutex); - LOG_DEBUG(2, "\t%dms (%d samples) buffer\n", (fragment_nframes * 1000) / rate, fragment_nframes); + if (nfragments == 1) { + pthread_mutex_lock(&fragment_mutex); + while (callback_buffer == NULL) { + pthread_cond_wait(&fragment_cv, &fragment_mutex); + } + fragment_buffer[0] = callback_buffer; + callback_buffer = NULL; + pthread_mutex_unlock(&fragment_mutex); + } + + sound_init(fragment_buffer[0], sample_fmt, rate, nchannels, fragment_nframes); + LOG_DEBUG(1, "\t%u frags * %u frames/frag = %u frames buffer (%.1fms)\n", nfragments, fragment_nframes, buffer_nframes, (float)(buffer_nframes * 1000) / rate); return 1; failed: @@ -147,44 +178,68 @@ } static void shutdown(void) { - pthread_mutex_lock(&halt_mutex); - halt = 0; shutting_down = 1; - pthread_cond_signal(&halt_cv); - pthread_mutex_unlock(&halt_mutex); - AudioDeviceStop(device, callback); + // unblock audio thread + pthread_mutex_lock(&fragment_mutex); + fragment_queue_length = 1; + pthread_cond_signal(&fragment_cv); + pthread_mutex_unlock(&fragment_mutex); + + AudioDeviceStop(device, (nfragments == 1) ? callback_1 : callback); #ifdef MAC_OS_X_VERSION_10_5 AudioDeviceDestroyIOProcID(device, aprocid); #else - AudioDeviceRemoveIOProc(device, callback); + AudioDeviceRemoveIOProc(device, (nfragments == 1) ? callback_1 : callback); #endif - pthread_mutex_destroy(&audio_buffer_mutex); - pthread_cond_destroy(&audio_buffer_cv); - pthread_mutex_destroy(&halt_mutex); - pthread_cond_destroy(&halt_cv); + pthread_mutex_destroy(&fragment_mutex); + pthread_cond_destroy(&fragment_cv); + + if (nfragments > 1) { + for (unsigned i = 0; i < nfragments; i++) { + free(fragment_buffer[i]); + } + } + + free(fragment_buffer); } static void *write_buffer(void *buffer) { (void)buffer; - // unblock audio thread - pthread_mutex_lock(&halt_mutex); - halt = 0; - pthread_cond_signal(&halt_cv); - pthread_mutex_unlock(&halt_mutex); - if (xroar_noratelimit) + pthread_mutex_lock(&fragment_mutex); + + /* For nfragments == 1, a non-NULL buffer means we've finished writing + * to the buffer provided by the callback. Otherwise, one fragment + * buffer is now full. Either way, signal the callback in case it is + * waiting for data to be available. */ + + if (buffer) { + write_fragment = (write_fragment + 1) % nfragments; + fragment_queue_length++; + pthread_cond_signal(&fragment_cv); + } + + if (xroar_noratelimit) { + pthread_mutex_unlock(&fragment_mutex); return NULL; + } - // wait for audio thread to pass a buffer pointer - pthread_mutex_lock(&audio_buffer_mutex); - while (!audio_buffer) - pthread_cond_wait(&audio_buffer_cv, &audio_buffer_mutex); - void *r = audio_buffer; - audio_buffer = NULL; - pthread_mutex_unlock(&audio_buffer_mutex); - return r; + if (nfragments == 1) { + // for nfragments == 1, wait for callback to send buffer + while (callback_buffer == NULL) + pthread_cond_wait(&fragment_cv, &fragment_mutex); + fragment_buffer[0] = callback_buffer; + callback_buffer = NULL; + } else { + // for nfragments > 1, wait until a fragment buffer is available + while (fragment_queue_length == nfragments) + pthread_cond_wait(&fragment_cv, &fragment_mutex); + } + + pthread_mutex_unlock(&fragment_mutex); + return fragment_buffer[write_fragment]; } static OSStatus callback(AudioDeviceID inDevice, const AudioTimeStamp *inNow, @@ -199,22 +254,53 @@ (void)inOutputTime; /* unused */ (void)defptr; /* unused */ - if (!shutting_down) { - pthread_mutex_lock(&halt_mutex); - halt = 1; - } - - // pass buffer pointer back to main thread - pthread_mutex_lock(&audio_buffer_mutex); - audio_buffer = (float *)outOutputData->mBuffers[0].mData; - pthread_cond_signal(&audio_buffer_cv); - pthread_mutex_unlock(&audio_buffer_mutex); - - // wait for main thread to be done with buffer - if (!shutting_down) { - while (halt) - pthread_cond_wait(&halt_cv, &halt_mutex); - pthread_mutex_unlock(&halt_mutex); - } + if (shutting_down) + return kAudioHardwareNoError; + pthread_mutex_lock(&fragment_mutex); + + // wait until at least one fragment buffer is filled + while (fragment_queue_length == 0) + pthread_cond_wait(&fragment_cv, &fragment_mutex); + + // copy it to callback buffer + memcpy(outOutputData->mBuffers[0].mData, fragment_buffer[play_fragment], fragment_nbytes); + play_fragment = (play_fragment + 1) % nfragments; + + // signal main thread that a fragment buffer is available + fragment_queue_length--; + pthread_cond_signal(&fragment_cv); + + pthread_mutex_unlock(&fragment_mutex); + return kAudioHardwareNoError; +} + +static OSStatus callback_1(AudioDeviceID inDevice, const AudioTimeStamp *inNow, + const AudioBufferList *inInputData, + const AudioTimeStamp *inInputTime, + AudioBufferList *outOutputData, + const AudioTimeStamp *inOutputTime, void *defptr) { + (void)inDevice; /* unused */ + (void)inNow; /* unused */ + (void)inInputData; /* unused */ + (void)inInputTime; /* unused */ + (void)inOutputTime; /* unused */ + (void)defptr; /* unused */ + + if (shutting_down) + return kAudioHardwareNoError; + pthread_mutex_lock(&fragment_mutex); + + // pass callback buffer to main thread + callback_buffer = outOutputData->mBuffers[0].mData; + pthread_cond_signal(&fragment_cv); + + // wait until main thread signals filled buffer + while (fragment_queue_length == 0) + pthread_cond_wait(&fragment_cv, &fragment_mutex); + + // set to 0 so next callback will wait + fragment_queue_length = 0; + + pthread_mutex_unlock(&fragment_mutex); return kAudioHardwareNoError; } diff -Nru xroar-0.31.1/src/macosx/filereq_cocoa.m xroar-0.32/src/macosx/filereq_cocoa.m --- xroar-0.31.1/src/macosx/filereq_cocoa.m 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/macosx/filereq_cocoa.m 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * 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 @@ -21,12 +21,12 @@ #import -#include "pl_glib.h" +#include "xalloc.h" #include "module.h" -static char *load_filename(const char **extensions); -static char *save_filename(const char **extensions); +static char *load_filename(char const * const *extensions); +static char *save_filename(char const * const *extensions); FileReqModule filereq_cocoa_module = { .common = { .name = "cocoa", .description = "Cocoa file requester" }, @@ -39,31 +39,31 @@ /* Assuming filenames are UTF8 strings seems to do the job */ -static char *load_filename(const char **extensions) { +static char *load_filename(char const * const *extensions) { NSOpenPanel *dialog = [NSOpenPanel openPanel]; (void)extensions; cocoa_super_all_keys = 1; if (filename) { - g_free(filename); + free(filename); filename = NULL; } if ([dialog runModal] == NSFileHandlingPanelOKButton) { - filename = g_strdup([[[[dialog URLs] objectAtIndex:0] path] UTF8String]); + filename = xstrdup([[[[dialog URLs] objectAtIndex:0] path] UTF8String]); } cocoa_super_all_keys = 0; return filename; } -static char *save_filename(const char **extensions) { +static char *save_filename(char const * const *extensions) { NSSavePanel *dialog = [NSSavePanel savePanel]; (void)extensions; cocoa_super_all_keys = 1; if (filename) { - g_free(filename); + free(filename); filename = NULL; } if ([dialog runModal] == NSFileHandlingPanelOKButton) { - filename = g_strdup([[[dialog URL] path] UTF8String]); + filename = xstrdup([[[dialog URL] path] UTF8String]); } cocoa_super_all_keys = 0; return filename; diff -Nru xroar-0.31.1/src/macosx/ui_macosx.m xroar-0.32/src/macosx/ui_macosx.m --- xroar-0.31.1/src/macosx/ui_macosx.m 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/macosx/ui_macosx.m 2014-04-22 10:58:56.000000000 +0000 @@ -264,7 +264,7 @@ /* Video: */ case TAG_FULLSCREEN: is_fullscreen = !is_fullscreen; - xroar_fullscreen(is_fullscreen); + xroar_set_fullscreen(0, is_fullscreen); break; case TAG_CROSS_COLOUR: current_cc = tag; @@ -287,7 +287,7 @@ break; case TAG_KBD_TRANSLATE: is_kbd_translate = !is_kbd_translate; - xroar_set_kbd_translate(is_kbd_translate); + xroar_set_kbd_translate(0, is_kbd_translate); break; /* Joysticks: */ @@ -518,7 +518,7 @@ submenu = [[NSMenu alloc] initWithTitle:title]; - tmp = [NSString stringWithFormat:@"Input Disk%C", 0x2026]; + tmp = [NSString stringWithFormat:@"Insert Disk%C", 0x2026]; item = [[NSMenuItem alloc] initWithTitle:tmp action:@selector(do_set_state:) keyEquivalent:key1]; [item setTag:(TAG_INSERT_DISK | drive)]; [submenu addItem:item]; @@ -631,7 +631,7 @@ [view_menu addItem:item]; [item release]; - view_menu_item = [[NSMenuItem alloc] initWithTitle:@"Machine" action:nil keyEquivalent:@""]; + view_menu_item = [[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""]; [view_menu_item setSubmenu:view_menu]; [[NSApp mainMenu] addItem:view_menu_item]; [view_menu_item release]; @@ -938,12 +938,13 @@ /* XRoar UI definition */ static _Bool init(void); +static void shutdown(void); static void cross_colour_changed_cb(int cc); static void machine_changed_cb(int machine_type); static void keymap_changed_cb(int map); +static void kbd_translate_changed_cb(_Bool kbd_translate); static void cart_changed_cb(int cart_index); static void fullscreen_changed_cb(_Bool fullscreen); -static void kbd_translate_changed_cb(_Bool kbd_translate); static void fast_sound_changed_cb(_Bool fast_sound); static void update_drive_write_enable(int drive, _Bool write_enable); static void update_drive_write_back(int drive, _Bool write_back); @@ -953,14 +954,16 @@ UIModule ui_macosx_module = { .common = { .name = "macosx", .description = "Mac OS X SDL UI", - .init = init }, + .init = init, .shutdown = shutdown }, .video_module_list = sdl_video_module_list, .keyboard_module_list = sdl_keyboard_module_list, .joystick_module_list = sdl_js_modlist, .run = sdl_run, + .fullscreen_changed_cb = fullscreen_changed_cb, .cross_colour_changed_cb = cross_colour_changed_cb, .machine_changed_cb = machine_changed_cb, .keymap_changed_cb = keymap_changed_cb, + .kbd_translate_changed_cb = kbd_translate_changed_cb, .fast_sound_changed_cb = fast_sound_changed_cb, .cart_changed_cb = cart_changed_cb, .update_drive_write_enable = update_drive_write_enable, @@ -968,13 +971,28 @@ }; static _Bool init(void) { + if (!SDL_WasInit(SDL_INIT_NOPARACHUTE)) { + if (SDL_Init(SDL_INIT_NOPARACHUTE) < 0) { + LOG_ERROR("Failed to initialise SDL: %s\n", SDL_GetError()); + return 0; + } + } + + if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { + LOG_ERROR("Failed to initialise SDL video: %s\n", SDL_GetError()); + return 0; + } + update_machine_menu(); update_cartridge_menu(); - xroar_fullscreen_changed_cb = fullscreen_changed_cb; - xroar_kbd_translate_changed_cb = kbd_translate_changed_cb; + return 1; } +static void shutdown(void) { + SDL_QuitSubSystem(SDL_INIT_VIDEO); +} + static void update_machine_menu(void) { int num_machines = machine_config_count(); int i; @@ -1030,6 +1048,10 @@ current_keymap = TAG_KEYMAP | (map & TAG_VALUE_MASK); } +static void kbd_translate_changed_cb(_Bool kbd_translate) { + is_kbd_translate = kbd_translate; +} + static void cart_changed_cb(int cart_index) { current_cartridge = TAG_CARTRIDGE | (cart_index & TAG_VALUE_MASK); } @@ -1038,10 +1060,6 @@ is_fullscreen = fullscreen; } -static void kbd_translate_changed_cb(_Bool kbd_translate) { - is_kbd_translate = kbd_translate; -} - static void fast_sound_changed_cb(_Bool fast_sound) { is_fast_sound = fast_sound; } diff -Nru xroar-0.31.1/src/main_unix.c xroar-0.32/src/main_unix.c --- xroar-0.31.1/src/main_unix.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/main_unix.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * diff -Nru xroar-0.31.1/src/Makefile xroar-0.32/src/Makefile --- xroar-0.31.1/src/Makefile 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/Makefile 2014-04-22 10:58:56.000000000 +0000 @@ -11,7 +11,7 @@ -include ../config.mak -SRCROOT ?= $(dir $(lastword $(MAKEFILE_LIST))) +SRCROOT ?= .. include $(SRCROOT)/common.mak SRCROOT := $(SRCROOT)/src @@ -333,7 +333,8 @@ xroar_mingw_C = \ windows32/ao_windows32.c \ windows32/common_windows32.c \ - windows32/filereq_windows32.c + windows32/filereq_windows32.c \ + windows32/ui_windows32.c xroar_mingw_C_O = $(xroar_mingw_C:.c=.o) xroar_mingw_RC = windows32/xroar.rc xroar_mingw_RC_RES = $(xroar_mingw_RC:.rc=.res) diff -Nru xroar-0.31.1/src/mc6809.c xroar-0.32/src/mc6809.c --- xroar-0.31.1/src/mc6809.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/mc6809.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -34,8 +34,9 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" +#include "delegate.h" #include "mc6809.h" /* @@ -157,7 +158,7 @@ static void dummy_write_cycle(uint16_t a, uint8_t v) { (void)a; (void)v; } struct MC6809 *mc6809_new(void) { - struct MC6809 *cpu = g_malloc0(sizeof(*cpu)); + struct MC6809 *cpu = xzalloc(sizeof(*cpu)); cpu->free = mc6809_free; cpu->reset = mc6809_reset; cpu->run = mc6809_run; @@ -170,7 +171,7 @@ } static void mc6809_free(struct MC6809 *cpu) { - g_free(cpu); + free(cpu); } static void mc6809_reset(struct MC6809 *cpu) { @@ -251,9 +252,7 @@ cpu->state = mc6809_state_next_instruction; // Instruction fetch hook called here so that machine // can be stopped beforehand. - if (cpu->instruction_hook) { - cpu->instruction_hook(cpu->instr_hook_dptr); - } + DELEGATE_SAFE_CALL0(cpu->instruction_hook); continue; case mc6809_state_dispatch_irq: @@ -1216,8 +1215,7 @@ static void take_interrupt(struct MC6809 *cpu, uint8_t mask, uint16_t vec) { REG_CC |= mask; NVMA_CYCLE; - if (cpu->interrupt_hook) - cpu->interrupt_hook(cpu->intr_dptr, vec); + DELEGATE_SAFE_CALL1(cpu->interrupt_hook, vec); unsigned new_pc = fetch_byte(cpu, vec) << 8; new_pc |= fetch_byte(cpu, vec+1); REG_PC = new_pc; @@ -1225,8 +1223,7 @@ } static void instruction_posthook(struct MC6809 *cpu) { - if (cpu->instruction_posthook) - cpu->instruction_posthook(cpu->instr_posthook_dptr); + DELEGATE_SAFE_CALL0(cpu->instruction_posthook); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru xroar-0.31.1/src/mc6809_common.c xroar-0.32/src/mc6809_common.c --- xroar-0.31.1/src/mc6809_common.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/mc6809_common.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -274,7 +274,7 @@ #define N_EOR_V ((REG_CC & CC_N)^((REG_CC & CC_V)<<2)) /* Determine branch condition from op-code */ -static _Bool branch_condition(struct MC6809 *cpu, unsigned op) { +static _Bool branch_condition(struct MC6809 const *cpu, unsigned op) { _Bool cond; switch (op & 0xf) { default: diff -Nru xroar-0.31.1/src/mc6809_common.h xroar-0.32/src/mc6809_common.h --- xroar-0.31.1/src/mc6809_common.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/mc6809_common.h 2014-04-22 10:58:56.000000000 +0000 @@ -61,5 +61,5 @@ static uint16_t sex5(uint16_t v); static uint16_t sex8(uint8_t v); -static _Bool branch_condition(struct MC6809 *cpu, unsigned op); +static _Bool branch_condition(struct MC6809 const *cpu, unsigned op); diff -Nru xroar-0.31.1/src/mc6809.h xroar-0.32/src/mc6809.h --- xroar-0.31.1/src/mc6809.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/mc6809.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,14 +1,18 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ #ifndef XROAR_MC6809_H_ #define XROAR_MC6809_H_ +#include "config.h" + #include -#include "config.h" +#include "pl-endian.h" + +#include "delegate.h" #define MC6809_INT_VEC_RESET (0xfffe) #define MC6809_INT_VEC_NMI (0xfffc) @@ -61,14 +65,11 @@ /* Perform a byte write cycle */ void (*write_cycle)(uint16_t addr, uint8_t value); /* Called just before instruction fetch if non-NULL */ - void (*instruction_hook)(void *); - void *instr_hook_dptr; + DELEGATE_T0(void) instruction_hook; /* Called after instruction is executed */ - void (*instruction_posthook)(void *); - void *instr_posthook_dptr; + DELEGATE_T0(void) instruction_posthook; /* Called just before an interrupt vector is read */ - void (*interrupt_hook)(void *, uint16_t vector); - void *intr_dptr; + DELEGATE_T1(void, int) interrupt_hook; /* Internal state */ @@ -88,7 +89,7 @@ unsigned nmi_cycle, firq_cycle, irq_cycle; }; -#ifdef HAVE_BIG_ENDIAN +#if __BYTE_ORDER == __BIG_ENDIAN # define MC6809_REG_HI (0) # define MC6809_REG_LO (1) #else diff -Nru xroar-0.31.1/src/mc6809_trace.c xroar-0.32/src/mc6809_trace.c --- xroar-0.31.1/src/mc6809_trace.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/mc6809_trace.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -40,7 +40,7 @@ static struct { const char *mnemonic; int type; -} instructions[3][256] = { +} const instructions[3][256] = { { // 0x00 - 0x0F @@ -881,11 +881,11 @@ /* Sequences of expected bytes */ -static const int state_list_irq[] = { WANT_VALUE, WANT_NOTHING, WANT_PRINT }; -static const int state_list_inherent[] = { WANT_PRINT }; -static const int state_list_idx[] = { WANT_IDX_POSTBYTE }; -static const int state_list_imm8[] = { WANT_VALUE, WANT_PRINT }; -static const int state_list_imm16[] = { WANT_VALUE, WANT_VALUE, WANT_PRINT }; +static int const state_list_irq[] = { WANT_VALUE, WANT_NOTHING, WANT_PRINT }; +static int const state_list_inherent[] = { WANT_PRINT }; +static int const state_list_idx[] = { WANT_IDX_POSTBYTE }; +static int const state_list_imm8[] = { WANT_VALUE, WANT_PRINT }; +static int const state_list_imm16[] = { WANT_VALUE, WANT_VALUE, WANT_PRINT }; /* Indexed addressing modes */ @@ -901,7 +901,7 @@ * optional brackets in indirect modes. 8-bit offsets include an extra %s to * indicate sign. 5-bit offsets are printed in decimal. */ -static const char *idx_fmts[17] = { +static char const * const idx_fmts[17] = { "%s,%s+%s", "%s,%s++%s", "%s,-%s%s", @@ -923,7 +923,7 @@ /* Indexed mode may well fetch more data after initial postbyte */ -static const int *idx_state_lists[17] = { +static int const * const idx_state_lists[17] = { state_list_inherent, state_list_inherent, state_list_inherent, @@ -946,16 +946,16 @@ /* Names */ // Inter-register operation postbyte -static const char *tfr_regs[16] = { +static char const * const tfr_regs[16] = { "D", "X", "Y", "U", "S", "PC", "*", "*", "A", "B", "CC", "DP", "*", "*", "*", "*" }; // Indexed addressing postbyte -static const char *idx_regs[4] = { "X", "Y", "U", "S" }; +static char const * const idx_regs[4] = { "X", "Y", "U", "S" }; // Interrupt vector names -static const char *irq_names[8] = { +static char const * const irq_names[8] = { "[?]", "[SWI3]", "[SWI2]", "[FIRQ]", "[IRQ]", "[SWI]", "[NMI]", "[RESET]" }; @@ -1223,8 +1223,8 @@ /* Called just before an IRQ vector fetch */ -void mc6809_trace_irq(void *dptr, uint16_t vector) { - (void)dptr; +void mc6809_trace_irq(void *sptr, int vector) { + (void)sptr; reset_state(); state = WANT_IRQ_VECTOR; bytes_count = 0; diff -Nru xroar-0.31.1/src/mc6809_trace.h xroar-0.32/src/mc6809_trace.h --- xroar-0.31.1/src/mc6809_trace.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/mc6809_trace.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -10,7 +10,7 @@ void mc6809_trace_reset(void); void mc6809_trace_byte(uint8_t byte, uint16_t pc); -void mc6809_trace_irq(void *dptr, uint16_t vector); +void mc6809_trace_irq(void *sptr, int vector); void mc6809_trace_print(struct MC6809 *cpu); #endif /* XROAR_MC6809_TRACE_H_ */ diff -Nru xroar-0.31.1/src/mc6821.c xroar-0.32/src/mc6821.c --- xroar-0.31.1/src/mc6821.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/mc6821.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -21,12 +21,12 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "mc6821.h" struct MC6821 *mc6821_new(void) { - struct MC6821 *new = g_malloc(sizeof(*new)); + struct MC6821 *new = xmalloc(sizeof(*new)); mc6821_init(new); return new; } @@ -39,7 +39,7 @@ void mc6821_free(struct MC6821 *pia) { if (pia == NULL) return; - g_free(pia); + free(pia); } #define INTERRUPT_ENABLED(p) (p.control_register & 0x01) diff -Nru xroar-0.31.1/src/mc6821.h xroar-0.32/src/mc6821.h --- xroar-0.31.1/src/mc6821.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/mc6821.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/mc6847.c xroar-0.32/src/mc6847.c --- xroar-0.31.1/src/mc6847.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/mc6847.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -23,8 +23,9 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" +#include "delegate.h" #include "events.h" #include "logging.h" #include "machine.h" @@ -69,14 +70,6 @@ uint8_t *pixel; int frame; // frameskip counter - /* Delegates to notify on signal edges */ - vdg_edge_delegate signal_hs; - vdg_edge_delegate signal_fs; - - /* External handler to fetch data for display. First arg is number of bytes, - * second a pointer to a buffer to receive them. */ - void (*fetch_bytes)(int, uint8_t *); - /* Internal state */ _Bool is_32byte; uint8_t s_fg_colour; @@ -145,7 +138,7 @@ } // HS falling edge. - vdg->signal_hs.delegate(vdg->signal_hs.dptr, 0); + DELEGATE_CALL1(vdg->public.signal_hs, 0); vdg->scanline_start = vdg->hs_fall_event.at_tick; // Next HS rise and fall @@ -161,10 +154,10 @@ if (IS_PAL && IS_COCO) { if (vdg->scanline == SCANLINE(VDG_ACTIVE_AREA_END + 25)) { vdg->pal_padding = 26; - vdg->hs_fall_event.delegate = do_hs_fall_pal_coco; + vdg->hs_fall_event.delegate.func = do_hs_fall_pal_coco; } else if (vdg->scanline == SCANLINE(VDG_ACTIVE_AREA_END + 47)) { vdg->pal_padding = 24; - vdg->hs_fall_event.delegate = do_hs_fall_pal_coco; + vdg->hs_fall_event.delegate.func = do_hs_fall_pal_coco; } } else if (IS_PAL && IS_DRAGON) { if (vdg->scanline == SCANLINE(VDG_ACTIVE_AREA_END + 24) @@ -193,12 +186,12 @@ if (vdg->scanline == VDG_ACTIVE_AREA_END) { // FS falling edge - vdg->signal_fs.delegate(vdg->signal_fs.dptr, 0); + DELEGATE_CALL1(vdg->public.signal_fs, 0); } if (vdg->scanline == VDG_VBLANK_START) { // FS rising edge - vdg->signal_fs.delegate(vdg->signal_fs.dptr, 1); + DELEGATE_CALL1(vdg->public.signal_fs, 1); vdg->frame--; if (vdg->frame < 0) vdg->frame = xroar_frameskip; @@ -211,13 +204,13 @@ static void do_hs_rise(void *data) { struct MC6847_private *vdg = data; // HS rising edge. - vdg->signal_hs.delegate(vdg->signal_hs.dptr, 1); + DELEGATE_CALL1(vdg->public.signal_hs, 1); } static void do_hs_fall_pal_coco(void *data) { struct MC6847_private *vdg = data; // HS falling edge - vdg->signal_hs.delegate(vdg->signal_hs.dptr, 0); + DELEGATE_CALL1(vdg->public.signal_hs, 0); vdg->scanline_start = vdg->hs_fall_event.at_tick; // Next HS rise and fall @@ -226,7 +219,7 @@ vdg->pal_padding--; if (vdg->pal_padding == 0) - vdg->hs_fall_event.delegate = do_hs_fall; + vdg->hs_fall_event.delegate.func = do_hs_fall; event_queue(&MACHINE_EVENT_LIST, &vdg->hs_rise_event); event_queue(&MACHINE_EVENT_LIST, &vdg->hs_fall_event); @@ -239,7 +232,7 @@ if (nbytes > 42) nbytes = 42; if (nbytes > vdg->vram_nbytes) { - vdg->fetch_bytes(nbytes - vdg->vram_nbytes, vdg->vram + vdg->vram_nbytes*2); + DELEGATE_CALL2(vdg->public.fetch_bytes, nbytes - vdg->vram_nbytes, vdg->vram + vdg->vram_nbytes*2); vdg->vram_nbytes = nbytes; } } else if (!vdg->is_32byte && beam_to >= 102) { @@ -247,7 +240,7 @@ if (nbytes > 22) nbytes = 22; if (nbytes > vdg->vram_nbytes) { - vdg->fetch_bytes(nbytes - vdg->vram_nbytes, vdg->vram + vdg->vram_nbytes*2); + DELEGATE_CALL2(vdg->public.fetch_bytes, nbytes - vdg->vram_nbytes, vdg->vram + vdg->vram_nbytes*2); vdg->vram_nbytes = nbytes; } } @@ -402,27 +395,16 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static void dummy_signal(void *data, _Bool level) { - (void)data; - (void)level; -} - -static void dummy_fetch_bytes(int nbytes, uint8_t *dest) { - memset(dest, 0, nbytes * 2); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - struct MC6847 *mc6847_new(_Bool t1) { - struct MC6847_private *vdg = g_malloc0(sizeof(*vdg)); + struct MC6847_private *vdg = xzalloc(sizeof(*vdg)); vdg->is_t1 = t1; vdg->vram_ptr = vdg->vram; vdg->pixel = vdg->pixel_data + VDG_LEFT_BORDER_START; - vdg->signal_hs = (vdg_edge_delegate){dummy_signal, NULL}; - vdg->signal_hs = (vdg_edge_delegate){dummy_signal, NULL}; - vdg->fetch_bytes = dummy_fetch_bytes; - event_init(&vdg->hs_fall_event, do_hs_fall, vdg); - event_init(&vdg->hs_rise_event, do_hs_rise, vdg); + vdg->public.signal_hs = DELEGATE_DEFAULT1(void, bool); + vdg->public.signal_fs = DELEGATE_DEFAULT1(void, bool); + vdg->public.fetch_bytes = DELEGATE_DEFAULT2(void, int, uint8p); + event_init(&vdg->hs_fall_event, DELEGATE_AS0(void, do_hs_fall, vdg)); + event_init(&vdg->hs_rise_event, DELEGATE_AS0(void, do_hs_rise, vdg)); return (struct MC6847 *)vdg; } @@ -430,22 +412,7 @@ struct MC6847_private *vdg = (struct MC6847_private *)vdgp; event_dequeue(&vdg->hs_fall_event); event_dequeue(&vdg->hs_rise_event); - g_free(vdg); -} - -void mc6847_set_fetch_bytes(struct MC6847 *vdgp, void (*d)(int, uint8_t *)) { - struct MC6847_private *vdg = (struct MC6847_private *)vdgp; - vdg->fetch_bytes = d; -} - -void mc6847_set_signal_hs(struct MC6847 *vdgp, vdg_edge_delegate d) { - struct MC6847_private *vdg = (struct MC6847_private *)vdgp; - vdg->signal_hs = d; -} - -void mc6847_set_signal_fs(struct MC6847 *vdgp, vdg_edge_delegate d) { - struct MC6847_private *vdg = (struct MC6847_private *)vdgp; - vdg->signal_fs = d; + free(vdg); } void mc6847_reset(struct MC6847 *vdgp) { diff -Nru xroar-0.31.1/src/mc6847.h xroar-0.32/src/mc6847.h --- xroar-0.31.1/src/mc6847.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/mc6847.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -8,6 +8,8 @@ #include +#include "delegate.h" + // Horizontal timing, all measured in half-VDG-clocks (i.e., pixels) #define VDG_tFP (17) // 14 @@ -50,23 +52,19 @@ VDG_BLACK, VDG_DARK_GREEN, VDG_DARK_ORANGE, VDG_BRIGHT_ORANGE }; -/* Delegates for signalling HS/FS fall/rise */ -typedef struct { - void (*delegate)(void *, _Bool level); - void *dptr; -} vdg_edge_delegate; - /* Nothing in this struct yet, might expose some things in future. */ struct MC6847 { + /* Delegates to notify on signal edges */ + DELEGATE_T1(void, bool) signal_hs; + DELEGATE_T1(void, bool) signal_fs; + /* External handler to fetch data for display. First arg is number of bytes, + * second a pointer to a buffer to receive them. */ + DELEGATE_T2(void, int, uint8p) fetch_bytes; }; struct MC6847 *mc6847_new(_Bool t1); void mc6847_free(struct MC6847 *); -void mc6847_set_fetch_bytes(struct MC6847 *, void (*)(int, uint8_t *)); -void mc6847_set_signal_hs(struct MC6847 *, vdg_edge_delegate); -void mc6847_set_signal_fs(struct MC6847 *, vdg_edge_delegate); - void mc6847_reset(struct MC6847 *); void mc6847_set_inverted_text(struct MC6847 *, _Bool); diff -Nru xroar-0.31.1/src/module.c xroar-0.32/src/module.c --- xroar-0.31.1/src/module.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/module.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -29,9 +29,10 @@ extern UIModule ui_gtk2_module; extern UIModule ui_macosx_module; -extern UIModule ui_sdl_module; extern UIModule ui_null_module; -static UIModule *default_ui_module_list[] = { +extern UIModule ui_sdl_module; +extern UIModule ui_windows32_module; +static UIModule * const default_ui_module_list[] = { #ifdef HAVE_GTK2 #ifdef HAVE_GTKGL &ui_gtk2_module, @@ -41,6 +42,9 @@ #ifdef HAVE_COCOA &ui_macosx_module, #else +#ifdef WINDOWS32 + &ui_windows32_module, +#endif &ui_sdl_module, #endif #endif @@ -55,7 +59,7 @@ extern FileReqModule filereq_gtk2_module; extern FileReqModule filereq_cli_module; extern FileReqModule filereq_null_module; -static FileReqModule *default_filereq_module_list[] = { +static FileReqModule * const default_filereq_module_list[] = { #ifdef HAVE_COCOA &filereq_cocoa_module, #endif @@ -83,7 +87,7 @@ extern SoundModule sound_alsa_module; extern SoundModule sound_jack_module; extern SoundModule sound_null_module; -static SoundModule *default_sound_module_list[] = { +static SoundModule * const default_sound_module_list[] = { #ifdef HAVE_MACOSX_AUDIO &sound_macosx_module, #endif @@ -117,37 +121,21 @@ }; extern VideoModule video_null_module; -static VideoModule *default_video_module_list[] = { +static VideoModule * const default_video_module_list[] = { &video_null_module, NULL }; -/**** Default joystick module list ****/ - -extern JoystickModule linux_js_mod; -extern JoystickModule sdl_js_mod_exported; -static JoystickModule *default_joystick_module_list[] = { -#ifdef HAVE_LINUX_JOYSTICK - &linux_js_mod, -#endif -#ifdef HAVE_SDL - &sdl_js_mod_exported, -#endif - NULL -}; - -UIModule **ui_module_list = default_ui_module_list; +UIModule * const *ui_module_list = default_ui_module_list; UIModule *ui_module = NULL; -FileReqModule **filereq_module_list = default_filereq_module_list; +FileReqModule * const *filereq_module_list = default_filereq_module_list; FileReqModule *filereq_module = NULL; -VideoModule **video_module_list = default_video_module_list; +VideoModule * const *video_module_list = default_video_module_list; VideoModule *video_module = NULL; -SoundModule **sound_module_list = default_sound_module_list; +SoundModule * const *sound_module_list = default_sound_module_list; SoundModule *sound_module = NULL; -KeyboardModule **keyboard_module_list = NULL; +KeyboardModule * const *keyboard_module_list = NULL; KeyboardModule *keyboard_module = NULL; -JoystickModule **joystick_module_list = default_joystick_module_list; -JoystickModule *joystick_module = NULL; void module_print_list(struct module **list) { int i; @@ -186,14 +174,14 @@ return NULL; int have_description = (module->description != NULL); if (have_description) { - LOG_DEBUG(2, "Module init: %s\n", module->description); + LOG_DEBUG(1, "Module init: %s\n", module->description); } if (!module->init || module->init()) { module->initialised = 1; return module; } if (have_description) { - LOG_DEBUG(2, "Module init failed: %s\n", module->description); + LOG_DEBUG(1, "Module init failed: %s\n", module->description); } return NULL; } @@ -217,7 +205,7 @@ if (!module || !module->initialised) return; if (module->description) { - LOG_DEBUG(2, "Module shutdown: %s\n", module->description); + LOG_DEBUG(1, "Module shutdown: %s\n", module->description); } if (module->shutdown) module->shutdown(); diff -Nru xroar-0.31.1/src/module.h xroar-0.32/src/module.h --- xroar-0.31.1/src/module.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/module.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -8,21 +8,21 @@ #include -struct joystick_interface; +struct joystick_module; struct vdisk; struct module { const char *name; const char *description; - _Bool (*init)(void); + _Bool (* const init)(void); _Bool initialised; - void (*shutdown)(void); + void (* const shutdown)(void); }; typedef struct { struct module common; - char *(*load_filename)(const char **extensions); - char *(*save_filename)(const char **extensions); + char *(* const load_filename)(char const * const *extensions); + char *(* const save_filename)(char const * const *extensions); } FileReqModule; typedef struct { @@ -30,65 +30,61 @@ int scanline; int window_x, window_y; int window_w, window_h; - void (*update_palette)(void); - void (*resize)(unsigned int w, unsigned int h); - int (*set_fullscreen)(_Bool fullscreen); + void (* const update_palette)(void); + void (* const resize)(unsigned int w, unsigned int h); + int (* const set_fullscreen)(_Bool fullscreen); _Bool is_fullscreen; - void (*render_scanline)(uint8_t *scanline_data); - void (*vsync)(void); - void (*refresh)(void); - void (*update_cross_colour_phase)(void); + void (*render_scanline)(uint8_t const *scanline_data); + void (* const vsync)(void); + void (* const refresh)(void); + void (* const update_cross_colour_phase)(void); } VideoModule; typedef struct { struct module common; - void *(*write_buffer)(void *buffer); + void *(* const write_buffer)(void *buffer); } SoundModule; typedef struct { struct module common; - void (*update_kbd_translate)(void); + void (* const update_kbd_translate)(void); } KeyboardModule; typedef struct { struct module common; - struct joystick_interface **interface_list; -} JoystickModule; - -typedef struct { - struct module common; - FileReqModule **filereq_module_list; - VideoModule **video_module_list; - SoundModule **sound_module_list; - KeyboardModule **keyboard_module_list; - JoystickModule **joystick_module_list; - void (*run)(void); - void (*cross_colour_changed_cb)(int cc); - void (*vdg_inverse_cb)(_Bool inverse); - void (*machine_changed_cb)(int machine_type); - void (*cart_changed_cb)(int cart_index); - void (*keymap_changed_cb)(int map); - void (*fast_sound_changed_cb)(_Bool fast); - void (*input_tape_filename_cb)(const char *filename); - void (*output_tape_filename_cb)(const char *filename); - void (*update_tape_state)(int flags); /* flag bits from tape.h */ - void (*update_drive_disk)(int drive, struct vdisk *disk); - void (*update_drive_write_enable)(int drive, _Bool write_enable); - void (*update_drive_write_back)(int drive, _Bool write_back); + FileReqModule * const *filereq_module_list; + VideoModule * const *video_module_list; + SoundModule * const *sound_module_list; + KeyboardModule * const *keyboard_module_list; + struct joystick_module * const *joystick_module_list; + void (* const run)(void); + void (* const fullscreen_changed_cb)(_Bool fullscreen); + void (* const cross_colour_changed_cb)(int cc); + void (* const vdg_inverse_cb)(_Bool inverse); + void (* const machine_changed_cb)(int machine_type); + void (* const cart_changed_cb)(int cart_index); + void (* const keymap_changed_cb)(int map); + void (* const joystick_changed_cb)(int port, const char *name); + void (* const kbd_translate_changed_cb)(_Bool translate); + void (* const fast_sound_changed_cb)(_Bool fast); + void (* const input_tape_filename_cb)(const char *filename); + void (* const output_tape_filename_cb)(const char *filename); + void (* const update_tape_state)(int flags); /* flag bits from tape.h */ + void (* const update_drive_disk)(int drive, struct vdisk *disk); + void (* const update_drive_write_enable)(int drive, _Bool write_enable); + void (* const update_drive_write_back)(int drive, _Bool write_back); } UIModule; -extern UIModule **ui_module_list; +extern UIModule * const *ui_module_list; extern UIModule *ui_module; -extern FileReqModule **filereq_module_list; +extern FileReqModule * const *filereq_module_list; extern FileReqModule *filereq_module; -extern VideoModule **video_module_list; +extern VideoModule * const *video_module_list; extern VideoModule *video_module; -extern SoundModule **sound_module_list; +extern SoundModule * const *sound_module_list; extern SoundModule *sound_module; -extern KeyboardModule **keyboard_module_list; +extern KeyboardModule * const *keyboard_module_list; extern KeyboardModule *keyboard_module; -extern JoystickModule **joystick_module_list; -extern JoystickModule *joystick_module; void module_print_list(struct module **list); struct module *module_select(struct module **list, const char *name); diff -Nru xroar-0.31.1/src/orch90.c xroar-0.32/src/orch90.c --- xroar-0.31.1/src/orch90.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/orch90.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -22,7 +22,7 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "cart.h" #include "logging.h" @@ -51,7 +51,7 @@ } struct cart *orch90_new(struct cart_config *cc) { - struct orch90 *o = g_malloc(sizeof(*o)); + struct orch90 *o = xmalloc(sizeof(*o)); o->cart.config = cc; orch90_init(o); return (struct cart *)o; diff -Nru xroar-0.31.1/src/orch90.h xroar-0.32/src/orch90.h --- xroar-0.31.1/src/orch90.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/orch90.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/oss/ao_oss.c xroar-0.32/src/oss/ao_oss.c --- xroar-0.31.1/src/oss/ao_oss.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/oss/ao_oss.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -27,7 +27,7 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "logging.h" #include "machine.h" @@ -65,6 +65,31 @@ * sample rate, and setting channels can affect rate. */ // Find a supported format + int desired_format; + switch (xroar_cfg.ao_format) { + case SOUND_FMT_U8: + desired_format = AFMT_U8; + break; + case SOUND_FMT_S8: + desired_format = AFMT_S8; + break; + case SOUND_FMT_S16_BE: + desired_format = AFMT_S16_BE; + break; + case SOUND_FMT_S16_LE: + desired_format = AFMT_S16_LE; + break; + case SOUND_FMT_S16_HE: + default: + desired_format = AFMT_S16_NE; + break; + case SOUND_FMT_S16_SE: + if (AFMT_S16_NE == AFMT_S16_LE) + desired_format = AFMT_S16_BE; + else + desired_format = AFMT_S16_LE; + break; + } enum sound_fmt buffer_fmt; int format; int bytes_per_sample; @@ -76,6 +101,10 @@ LOG_ERROR("No desired audio formats supported by device\n"); goto failed; } + // if desired_format is one of those returned, use it: + if (format & desired_format) { + format = desired_format; + } if (format & AFMT_S16_NE) { format = AFMT_S16_NE; buffer_fmt = SOUND_FMT_S16_HE; @@ -173,9 +202,9 @@ fragment_nframes = fragment_nbytes / (bytes_per_sample * nchannels); buffer_nframes = fragment_nframes * nfragments; - audio_buffer = g_malloc(fragment_nbytes); + audio_buffer = xmalloc(fragment_nbytes); sound_init(audio_buffer, buffer_fmt, rate, nchannels, fragment_nframes); - LOG_DEBUG(2, "\t%u frags * %d frames/frag = %d frames buffer (%.1fms)\n", nfragments, fragment_nframes, buffer_nframes, (float)(buffer_nframes * 1000) / rate); + LOG_DEBUG(1, "\t%d frags * %d frames/frag = %d frames buffer (%.1fms)\n", nfragments, fragment_nframes, buffer_nframes, (float)(buffer_nframes * 1000) / rate); ioctl(sound_fd, SNDCTL_DSP_RESET, 0); return 1; @@ -188,7 +217,7 @@ static void shutdown(void) { ioctl(sound_fd, SNDCTL_DSP_RESET, 0); close(sound_fd); - g_free(audio_buffer); + free(audio_buffer); } static void *write_buffer(void *buffer) { diff -Nru xroar-0.31.1/src/path.c xroar-0.32/src/path.c --- xroar-0.31.1/src/path.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/path.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -26,7 +26,7 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "path.h" @@ -60,7 +60,7 @@ * access. This is NOT a security check, it's * purely for usability. */ if (access(filename, R_OK) == 0) { - return g_strdup(filename); + return xstrdup(filename); } } } @@ -77,7 +77,7 @@ if (home) { buf_size += strlen(home) - 1; } - buf = g_try_malloc(buf_size); + buf = malloc(buf_size); if (buf == NULL) return NULL; for (;;) { @@ -113,7 +113,7 @@ break; path++; } - g_free(buf); + free(buf); return NULL; } diff -Nru xroar-0.31.1/src/path.h xroar-0.32/src/path.h --- xroar-0.31.1/src/path.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/path.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/printer.c xroar-0.32/src/printer.c --- xroar-0.31.1/src/printer.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/printer.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -24,9 +24,10 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "breakpoint.h" +#include "delegate.h" #include "events.h" #include "logging.h" #include "machine.h" @@ -38,10 +39,10 @@ static char *stream_dest; static int is_pipe; static struct event ack_clear_event; -static int strobe_state; +static _Bool strobe_state = 1; static _Bool busy; -printer_line_delegate printer_signal_ack = { NULL, NULL }; +DELEGATE_T1(void, bool) printer_signal_ack = { NULL, NULL }; static void do_ack_clear(void *); static void open_stream(void); @@ -56,7 +57,7 @@ stream = NULL; stream_dest = NULL; is_pipe = 0; - event_init(&ack_clear_event, do_ack_clear, NULL); + event_init(&ack_clear_event, DELEGATE_AS0(void, do_ack_clear, NULL)); strobe_state = 1; busy = 0; } @@ -71,8 +72,8 @@ void printer_open_file(const char *filename) { printer_close(); - if (stream_dest) g_free(stream_dest); - stream_dest = g_strdup(filename); + if (stream_dest) free(stream_dest); + stream_dest = xstrdup(filename); is_pipe = 0; busy = 0; bp_add_list(coco_print_breakpoint); @@ -80,8 +81,8 @@ void printer_open_pipe(const char *command) { printer_close(); - if (stream_dest) g_free(stream_dest); - stream_dest = g_strdup(command); + if (stream_dest) free(stream_dest); + stream_dest = xstrdup(command); is_pipe = 1; busy = 0; bp_add_list(coco_print_breakpoint); @@ -90,7 +91,7 @@ void printer_close(void) { /* flush stream, but destroy stream_dest so it won't be reopened */ printer_flush(); - if (stream_dest) g_free(stream_dest); + if (stream_dest) free(stream_dest); stream_dest = NULL; is_pipe = 0; busy = 1; @@ -122,8 +123,7 @@ fputc(data, stream); } /* ACK, and schedule !ACK */ - if (printer_signal_ack.delegate) - printer_signal_ack.delegate(printer_signal_ack.dptr, 1); + DELEGATE_SAFE_CALL1(printer_signal_ack, 1); ack_clear_event.at_tick = event_current_tick + (OSCILLATOR_RATE / 150000); event_queue(&MACHINE_EVENT_LIST, &ack_clear_event); } @@ -156,8 +156,7 @@ static void do_ack_clear(void *data) { (void)data; - if (printer_signal_ack.delegate) - printer_signal_ack.delegate(printer_signal_ack.dptr, 0); + DELEGATE_SAFE_CALL1(printer_signal_ack, 0); } _Bool printer_busy(void) { diff -Nru xroar-0.31.1/src/printer.h xroar-0.32/src/printer.h --- xroar-0.31.1/src/printer.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/printer.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,21 +1,17 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ #ifndef XROAR_PRINTER_H_ #define XROAR_PRINTER_H_ +#include "delegate.h" + void printer_init(void); void printer_reset(void); -/* Printer ACK delegate is passed its data pointer and ACK state as _Bool */ -typedef struct { - void (*delegate)(void *, _Bool); - void *dptr; -} printer_line_delegate; - -extern printer_line_delegate printer_signal_ack; +extern DELEGATE_T1(void, bool) printer_signal_ack; void printer_open_file(const char *filename); void printer_open_pipe(const char *command); diff -Nru xroar-0.31.1/src/pulseaudio/ao_pulse.c xroar-0.32/src/pulseaudio/ao_pulse.c --- xroar-0.31.1/src/pulseaudio/ao_pulse.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/pulseaudio/ao_pulse.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -26,7 +26,7 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "logging.h" #include "machine.h" @@ -110,9 +110,9 @@ } fragment_nbytes = fragment_nframes * sample_nbytes * nchannels; - audio_buffer = g_malloc(fragment_nbytes); + audio_buffer = xmalloc(fragment_nbytes); sound_init(audio_buffer, request_fmt, rate, nchannels, fragment_nframes); - LOG_DEBUG(2, "\t%dms (%d samples) buffer\n", (fragment_nframes * 1000) / rate, fragment_nframes); + LOG_DEBUG(1, "\t%dms (%d samples) buffer\n", (fragment_nframes * 1000) / rate, fragment_nframes); return 1; failed: return 0; @@ -122,7 +122,7 @@ int error; pa_simple_flush(pa, &error); pa_simple_free(pa); - g_free(audio_buffer); + free(audio_buffer); } static void *write_buffer(void *buffer) { diff -Nru xroar-0.31.1/src/romlist.c xroar-0.32/src/romlist.c --- xroar-0.31.1/src/romlist.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/romlist.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -22,7 +22,9 @@ #include #include -#include "pl_glib.h" +#include "array.h" +#include "slist.h" +#include "xalloc.h" #include "path.h" #include "romlist.h" @@ -31,14 +33,14 @@ /* User defined rom lists */ struct romlist { char *name; - GSList *list; + struct slist *list; _Bool flag; }; /* List containing all defined rom lists */ -static GSList *romlist_list = NULL; +static struct slist *romlist_list = NULL; -static const char *rom_extensions[] = { +static char const * const rom_extensions[] = { "", ".rom", ".ROM", ".dgn", ".DGN" }; @@ -49,8 +51,8 @@ /**************************************************************************/ static struct romlist *new_romlist(const char *name) { - struct romlist *new = g_malloc(sizeof(*new)); - new->name = g_strdup(name); + struct romlist *new = xmalloc(sizeof(*new)); + new->name = xstrdup(name); new->list = NULL; new->flag = 0; return new; @@ -58,18 +60,18 @@ static void free_romlist(struct romlist *romlist) { if (!romlist) return; - GSList *list = romlist->list; + struct slist *list = romlist->list; while (list) { - gpointer data = list->data; - list = g_slist_remove(list, data); - g_free(data); + void *data = list->data; + list = slist_remove(list, data); + free(data); } - g_free(romlist->name); - g_free(romlist); + free(romlist->name); + free(romlist); } static struct romlist *find_romlist(const char *name) { - GSList *entry = g_slist_find_custom(romlist_list, name, (GCompareFunc)compare_entry); + struct slist *entry = slist_find_custom(romlist_list, name, (slist_cmp_func)compare_entry); if (!entry) return NULL; return entry->data; } @@ -78,7 +80,7 @@ * Overwrites any existing list with name LIST. */ void romlist_assign(const char *astring) { if (!astring) return; - char *tmp = g_alloca(strlen(astring) + 1); + char tmp[strlen(astring) + 1]; strcpy(tmp, astring); char *name = strtok(tmp, "="); if (!name) return; @@ -87,35 +89,34 @@ struct romlist *old_list = find_romlist(name); if (old_list) { /* if so, remove its reference in romlist_list */ - romlist_list = g_slist_remove(romlist_list, old_list); + romlist_list = slist_remove(romlist_list, old_list); } char *value; while ((value = strtok(NULL, "\n\v\f\r,"))) { if (value[0] == '@' && 0 == strcmp(value+1, name)) { /* reference to this list - append current contents */ if (old_list) { - new_list->list = g_slist_concat(new_list->list, old_list->list); + new_list->list = slist_concat(new_list->list, old_list->list); old_list->list = NULL; } } else { /* otherwise just add a new entry */ - new_list->list = g_slist_append(new_list->list, g_strdup(value)); + new_list->list = slist_append(new_list->list, xstrdup(value)); } } if (old_list) { free_romlist(old_list); } /* add new list to romlist_list */ - romlist_list = g_slist_append(romlist_list, new_list); + romlist_list = slist_append(romlist_list, new_list); } /* Find a ROM within ROMPATH */ static char *find_rom(const char *romname) { - char *filename; char *path = NULL; if (!romname) return NULL; - filename = g_alloca(strlen(romname) + 5); - for (unsigned i = 0; i < G_N_ELEMENTS(rom_extensions); i++) { + char filename[strlen(romname) + 5]; + for (unsigned i = 0; i < ARRAY_N_ELEMENTS(rom_extensions); i++) { strcpy(filename, romname); strcat(filename, rom_extensions[i]); path = find_in_path(xroar_rom_path, filename); @@ -137,7 +138,7 @@ /* found an appropriate list? flag it and start scanning it */ if (!romlist) return NULL; - GSList *iter; + struct slist *iter; if (romlist->flag) return NULL; romlist->flag = 1; @@ -158,7 +159,7 @@ } static void print_romlist_entry(struct romlist *list, void *user_data) { - GSList *jter; + struct slist *jter; if (user_data) { printf("romlist %s=", list->name); } else { @@ -179,12 +180,12 @@ /* Print a list of defined ROM lists to stdout */ void romlist_print_all(void) { - g_slist_foreach(romlist_list, (GFunc)print_romlist_entry, (void *)1); + slist_foreach(romlist_list, (slist_iter_func)print_romlist_entry, (void *)1); } /* Print list and exit */ void romlist_print(void) { printf("ROM lists:\n"); - g_slist_foreach(romlist_list, (GFunc)print_romlist_entry, NULL); + slist_foreach(romlist_list, (slist_iter_func)print_romlist_entry, NULL); exit(EXIT_SUCCESS); } diff -Nru xroar-0.31.1/src/romlist.h xroar-0.32/src/romlist.h --- xroar-0.31.1/src/romlist.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/romlist.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/rsdos.c xroar-0.32/src/rsdos.c --- xroar-0.31.1/src/rsdos.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/rsdos.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -27,10 +27,11 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "becker.h" #include "cart.h" +#include "delegate.h" #include "logging.h" #include "machine.h" #include "rsdos.h" @@ -56,10 +57,8 @@ static void rsdos_detach(struct cart *c); /* Handle signals from WD2793 */ -static void set_drq_handler(void *dptr); -static void reset_drq_handler(void *dptr); -static void set_intrq_handler(void *dptr); -static void reset_intrq_handler(void *dptr); +static void set_drq(void *, _Bool); +static void set_intrq(void *, _Bool); static void ff40_write(struct rsdos *r, int octet); @@ -73,16 +72,20 @@ c->detach = rsdos_detach; r->have_becker = (cc->becker_port && becker_open()); r->fdc = wd279x_new(WD2793); - r->fdc->set_drq_handler = set_drq_handler; - r->fdc->reset_drq_handler = reset_drq_handler; - r->fdc->drq_data = c; - r->fdc->set_intrq_handler = set_intrq_handler; - r->fdc->reset_intrq_handler = reset_intrq_handler; - r->fdc->intrq_data = c; + r->fdc->set_dirc = DELEGATE_AS1(void, int, vdrive_set_dirc, NULL); + r->fdc->set_dden = DELEGATE_AS1(void, bool, vdrive_set_dden, NULL); + r->fdc->set_drq = DELEGATE_AS1(void, bool, set_drq, c); + r->fdc->set_intrq = DELEGATE_AS1(void, bool, set_intrq, c); + vdrive_ready = DELEGATE_AS1(void, bool, wd279x_ready, r->fdc); + vdrive_tr00 = DELEGATE_AS1(void, bool, wd279x_tr00, r->fdc); + vdrive_index_pulse = DELEGATE_AS1(void, bool, wd279x_index_pulse, r->fdc); + vdrive_write_protect = DELEGATE_AS1(void, bool, wd279x_write_protect, r->fdc); + wd279x_update_connection(r->fdc); + vdrive_update_connection(); } struct cart *rsdos_new(struct cart_config *cc) { - struct rsdos *r = g_malloc(sizeof(*r)); + struct rsdos *r = xmalloc(sizeof(*r)); r->cart.config = cc; rsdos_init(r); return (struct cart *)r; @@ -171,28 +174,28 @@ } else if (octet & 0x04) { new_drive_select = 2; } - vdrive_set_head(octet & 0x40 ? 1 : 0); + vdrive_set_sso(NULL, octet & 0x40 ? 1 : 0); if (octet != r->ic1_old) { - LOG_DEBUG(4, "RSDOS: Write to FF40: "); + LOG_DEBUG(2, "RSDOS: Write to FF40: "); if (new_drive_select != r->ic1_drive_select) { - LOG_DEBUG(4, "DRIVE SELECT %d, ", new_drive_select); + LOG_DEBUG(2, "DRIVE SELECT %d, ", new_drive_select); } if ((octet ^ r->ic1_old) & 0x08) { - LOG_DEBUG(4, "MOTOR %s, ", (octet & 0x08)?"ON":"OFF"); + LOG_DEBUG(2, "MOTOR %s, ", (octet & 0x08)?"ON":"OFF"); } if ((octet ^ r->ic1_old) & 0x20) { - LOG_DEBUG(4, "DENSITY %s, ", (octet & 0x20)?"SINGLE":"DOUBLE"); + LOG_DEBUG(2, "DENSITY %s, ", (octet & 0x20)?"SINGLE":"DOUBLE"); } if ((octet ^ r->ic1_old) & 0x10) { - LOG_DEBUG(4, "PRECOMP %s, ", (octet & 0x10)?"ON":"OFF"); + LOG_DEBUG(2, "PRECOMP %s, ", (octet & 0x10)?"ON":"OFF"); } if ((octet ^ r->ic1_old) & 0x40) { - LOG_DEBUG(4, "SIDE %d, ", (octet & 0x40) >> 6); + LOG_DEBUG(2, "SIDE %d, ", (octet & 0x40) >> 6); } if ((octet ^ r->ic1_old) & 0x80) { - LOG_DEBUG(4, "HALT %s, ", (octet & 0x80)?"ENABLED":"DISABLED"); + LOG_DEBUG(2, "HALT %s, ", (octet & 0x80)?"ENABLED":"DISABLED"); } - LOG_DEBUG(4, "\n"); + LOG_DEBUG(2, "\n"); r->ic1_old = octet; } r->ic1_drive_select = new_drive_select; @@ -200,50 +203,37 @@ r->ic1_density = octet & 0x20; wd279x_set_dden(r->fdc, !r->ic1_density); if (r->ic1_density && r->intrq_flag) { - if (c->signal_nmi.delegate) - c->signal_nmi.delegate(c->signal_nmi.dptr, 1); + DELEGATE_CALL1(c->signal_nmi, 1); } r->halt_enable = octet & 0x80; if (r->intrq_flag) r->halt_enable = 0; - if (c->signal_halt.delegate) - c->signal_halt.delegate(c->signal_halt.dptr, r->halt_enable && !r->drq_flag); + DELEGATE_CALL1(c->signal_halt, r->halt_enable && !r->drq_flag); } -static void set_drq_handler(void *dptr) { - struct cart *c = dptr; - struct rsdos *r = dptr; - r->drq_flag = 1; - if (c->signal_halt.delegate) - c->signal_halt.delegate(c->signal_halt.dptr, 0); -} - -static void reset_drq_handler(void *dptr) { - struct cart *c = dptr; - struct rsdos *r = dptr; - r->drq_flag = 0; - if (r->halt_enable) { - if (c->signal_halt.delegate) - c->signal_halt.delegate(c->signal_halt.dptr, 1); +static void set_drq(void *sptr, _Bool value) { + struct cart *c = sptr; + struct rsdos *r = sptr; + r->drq_flag = value; + if (value) { + DELEGATE_CALL1(c->signal_halt, 0); + } else { + if (r->halt_enable) { + DELEGATE_CALL1(c->signal_halt, 1); + } } } -static void set_intrq_handler(void *dptr) { - struct cart *c = dptr; - struct rsdos *r = dptr; - r->intrq_flag = 1; - r->halt_enable = 0; - if (c->signal_halt.delegate) - c->signal_halt.delegate(c->signal_halt.dptr, 0); - if (!r->ic1_density && r->intrq_flag) { - if (c->signal_nmi.delegate) - c->signal_nmi.delegate(c->signal_nmi.dptr, 1); +static void set_intrq(void *sptr, _Bool value) { + struct cart *c = sptr; + struct rsdos *r = sptr; + r->intrq_flag = value; + if (value) { + r->halt_enable = 0; + DELEGATE_CALL1(c->signal_halt, 0); + if (!r->ic1_density && r->intrq_flag) { + DELEGATE_CALL1(c->signal_nmi, 1); + } + } else { + DELEGATE_CALL1(c->signal_nmi, 0); } } - -static void reset_intrq_handler(void *dptr) { - struct cart *c = dptr; - struct rsdos *r = dptr; - r->intrq_flag = 0; - if (c->signal_nmi.delegate) - c->signal_nmi.delegate(c->signal_nmi.dptr, 0); -} diff -Nru xroar-0.31.1/src/rsdos.h xroar-0.32/src/rsdos.h --- xroar-0.31.1/src/rsdos.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/rsdos.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/sam.c xroar-0.32/src/sam.c --- xroar-0.31.1/src/sam.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sam.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -29,18 +29,18 @@ static _Bool odd_cycle; /* Constants for tracking VDG address counter */ -static int vdg_mod_xdivs[8] = { 1, 3, 1, 2, 1, 1, 1, 1 }; -static int vdg_mod_ydivs[8] = { 12, 1, 3, 1, 2, 1, 1, 1 }; -static int vdg_mod_adds[8] = { 16, 8, 16, 8, 16, 8, 16, 0 }; -static uint16_t vdg_mod_clears[8] = { ~30, ~14, ~30, ~14, ~30, ~14, ~30, ~0 }; +static int const vdg_mod_xdivs[8] = { 1, 3, 1, 2, 1, 1, 1, 1 }; +static int const vdg_mod_ydivs[8] = { 12, 1, 3, 1, 2, 1, 1, 1 }; +static int const vdg_mod_adds[8] = { 16, 8, 16, 8, 16, 8, 16, 0 }; +static uint16_t const vdg_mod_clears[8] = { ~30, ~14, ~30, ~14, ~30, ~14, ~30, ~0 }; /* Constants for address multiplexer * SAM Data Sheet, * Figure 6 - Signal routing for address multiplexer */ -static uint16_t ram_row_masks[4] = { 0x007f, 0x007f, 0x00ff, 0x00ff }; -static int ram_col_shifts[4] = { 2, 1, 0, 0 }; -static uint16_t ram_col_masks[4] = { 0x3f00, 0x7f00, 0xff00, 0xff00 }; -static uint16_t ram_ras1_bits[4] = { 0x1000, 0x4000, 0, 0 }; +static uint16_t const ram_row_masks[4] = { 0x007f, 0x007f, 0x00ff, 0x00ff }; +static int const ram_col_shifts[4] = { 2, 1, 0, 0 }; +static uint16_t const ram_col_masks[4] = { 0x3f00, 0x7f00, 0xff00, 0xff00 }; +static uint16_t const ram_ras1_bits[4] = { 0x1000, 0x4000, 0, 0 }; /* VDG address counter */ static uint16_t vdg_base; diff -Nru xroar-0.31.1/src/sam.h xroar-0.32/src/sam.h --- xroar-0.31.1/src/sam.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sam.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/sdl/ao_sdl.c xroar-0.32/src/sdl/ao_sdl.c --- xroar-0.31.1/src/sdl/ao_sdl.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sdl/ao_sdl.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -16,6 +16,12 @@ * along with XRoar. If not, see . */ +/* SDL processes audio in a separate thread, using a callback to request more + * data. When the configured number of audio fragments (nfragments) is 1, + * write directly into the buffer provided by SDL. When nfragments > 1, + * maintain a queue of fragment buffers; the callback takes the next filled + * buffer from the queue and copies its data into place. */ + #include "config.h" #include @@ -25,7 +31,7 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "logging.h" #include "machine.h" @@ -45,20 +51,27 @@ static SDL_AudioSpec audiospec; -static Uint8 *audio_buffer; -static _Bool halt; +static void *callback_buffer; static _Bool shutting_down; -static SDL_mutex *audio_buffer_mutex; -static SDL_cond *audio_buffer_cv; -static SDL_mutex *halt_mutex; -static SDL_cond *halt_cv; -static Uint32 timeout_ms; +static unsigned nfragments; +static unsigned fragment_nbytes; + +static SDL_mutex *fragment_mutex; +static SDL_cond *fragment_cv; +static void **fragment_buffer; +static unsigned fragment_queue_length; +static unsigned write_fragment; +static unsigned play_fragment; + +static unsigned timeout_ms; -static void callback(void *userdata, Uint8 *stream, int len); +static void callback(void *, Uint8 *, int); +static void callback_1(void *, Uint8 *, int); static _Bool init(void) { static SDL_AudioSpec desired; + if (!SDL_WasInit(SDL_INIT_NOPARACHUTE)) { if (SDL_Init(SDL_INIT_NOPARACHUTE) < 0) { LOG_ERROR("Failed to initialise SDL\n"); @@ -69,65 +82,118 @@ LOG_ERROR("Failed to initialise SDL audio\n"); return 0; } - desired.freq = (xroar_cfg.ao_rate > 0) ? xroar_cfg.ao_rate : 48000; - desired.format = AUDIO_S16; - /* More than one fragment not currently supported. */ + unsigned rate = 48000; + unsigned nchannels = 2; + unsigned fragment_nframes; + unsigned buffer_nframes; + unsigned sample_nbytes; + enum sound_fmt sample_fmt; + + if (xroar_cfg.ao_rate > 0) + rate = xroar_cfg.ao_rate; + + if (xroar_cfg.ao_channels >= 1 && xroar_cfg.ao_channels <= 2) + nchannels = xroar_cfg.ao_channels; + + nfragments = 2; + if (xroar_cfg.ao_fragments > 0 && xroar_cfg.ao_fragments <= 64) + nfragments = xroar_cfg.ao_fragments; if (xroar_cfg.ao_fragment_ms > 0) { - desired.samples = (desired.freq * xroar_cfg.ao_fragment_ms) / 1000; + fragment_nframes = (rate * xroar_cfg.ao_fragment_ms) / 1000; } else if (xroar_cfg.ao_fragment_nframes > 0) { - desired.samples = xroar_cfg.ao_fragment_nframes; - } else if (xroar_cfg.ao_buffer_ms > 0) { - desired.samples = (desired.freq * xroar_cfg.ao_buffer_ms) / 1000; - } else if (xroar_cfg.ao_buffer_nframes > 0) { - desired.samples = xroar_cfg.ao_buffer_nframes; + fragment_nframes = xroar_cfg.ao_fragment_nframes; } else { - desired.samples = 1024; + if (xroar_cfg.ao_buffer_ms > 0) { + buffer_nframes = (rate * xroar_cfg.ao_buffer_ms) / 1000; + } else if (xroar_cfg.ao_buffer_nframes > 0) { + buffer_nframes = xroar_cfg.ao_buffer_nframes; + } else { + buffer_nframes = 1024; + } + fragment_nframes = buffer_nframes / nfragments; } - desired.channels = xroar_cfg.ao_channels; - if (desired.channels < 1 || desired.channels > 2) - desired.channels = 2; - desired.callback = callback; + + desired.freq = rate; + desired.channels = nchannels; + desired.samples = fragment_nframes; + desired.callback = (nfragments == 1) ? callback_1 : callback; desired.userdata = NULL; + + switch (xroar_cfg.ao_format) { + case SOUND_FMT_U8: + desired.format = AUDIO_U8; + break; + case SOUND_FMT_S8: + desired.format = AUDIO_S8; + break; + case SOUND_FMT_S16_BE: + desired.format = AUDIO_S16MSB; + break; + case SOUND_FMT_S16_LE: + desired.format = AUDIO_S16LSB; + break; + case SOUND_FMT_S16_HE: + default: + desired.format = AUDIO_S16SYS; + break; + case SOUND_FMT_S16_SE: + if (AUDIO_S16SYS == AUDIO_S16LSB) + desired.format = AUDIO_S16MSB; + else + desired.format = AUDIO_S16LSB; + break; + } + if (SDL_OpenAudio(&desired, &audiospec) < 0) { LOG_ERROR("Couldn't open audio: %s\n", SDL_GetError()); SDL_QuitSubSystem(SDL_INIT_AUDIO); return 0; } + rate = audiospec.freq; + nchannels = audiospec.channels; + fragment_nframes = audiospec.samples; - int buffer_fmt; switch (audiospec.format) { - case AUDIO_U8: buffer_fmt = SOUND_FMT_U8; break; - case AUDIO_S8: buffer_fmt = SOUND_FMT_S8; break; - case AUDIO_S16LSB: buffer_fmt = SOUND_FMT_S16_LE; break; - case AUDIO_S16MSB: buffer_fmt = SOUND_FMT_S16_BE; break; + case AUDIO_U8: sample_fmt = SOUND_FMT_U8; sample_nbytes = 1; break; + case AUDIO_S8: sample_fmt = SOUND_FMT_S8; sample_nbytes = 1; break; + case AUDIO_S16LSB: sample_fmt = SOUND_FMT_S16_LE; sample_nbytes = 2; break; + case AUDIO_S16MSB: sample_fmt = SOUND_FMT_S16_BE; sample_nbytes = 2; break; default: LOG_WARN("Unhandled audio format."); goto failed; } - int buffer_nframes = audiospec.samples; - timeout_ms = (buffer_nframes * 1500) / audiospec.freq; + timeout_ms = (fragment_nframes * 1500) / rate; - audio_buffer_mutex = SDL_CreateMutex(); - audio_buffer_cv = SDL_CreateCond(); - halt_mutex = SDL_CreateMutex(); - halt_cv = SDL_CreateCond(); + buffer_nframes = fragment_nframes * nfragments; + fragment_nbytes = fragment_nframes * nchannels * sample_nbytes; + + fragment_mutex = SDL_CreateMutex(); + fragment_cv = SDL_CreateCond(); - audio_buffer = NULL; - halt = 1; shutting_down = 0; + fragment_queue_length = 0; + write_fragment = 0; + play_fragment = 0; + callback_buffer = NULL; + + // allocate fragment buffers + fragment_buffer = xmalloc(nfragments * sizeof(void *)); + if (nfragments == 1) { + fragment_buffer[0] = NULL; + } else { + for (unsigned i = 0; i < nfragments; i++) { + fragment_buffer[i] = xzalloc(fragment_nbytes); + } + } - SDL_LockMutex(audio_buffer_mutex); - SDL_PauseAudio(0); - while (!audio_buffer) - SDL_CondWait(audio_buffer_cv, audio_buffer_mutex); - sound_init(audio_buffer, buffer_fmt, audiospec.freq, audiospec.channels, buffer_nframes); - audio_buffer = NULL; - SDL_UnlockMutex(audio_buffer_mutex); - LOG_DEBUG(2, "\t%dms (%d samples) buffer\n", (buffer_nframes * 1000) / audiospec.freq, buffer_nframes); + sound_init(fragment_buffer[0], sample_fmt, rate, nchannels, fragment_nframes); + LOG_DEBUG(1, "\t%u frags * %u frames/frag = %u frames buffer (%.1fms)\n", nfragments, fragment_nframes, buffer_nframes, (float)(buffer_nframes * 1000) / rate); + SDL_PauseAudio(0); return 1; + failed: SDL_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); @@ -135,69 +201,114 @@ } static void _shutdown(void) { + shutting_down = 1; + // no more audio SDL_PauseAudio(1); // unblock audio thread - SDL_LockMutex(halt_mutex); - halt = 0; - shutting_down = 1; - SDL_CondSignal(halt_cv); - SDL_UnlockMutex(halt_mutex); + SDL_LockMutex(fragment_mutex); + fragment_queue_length = 1; + SDL_CondSignal(fragment_cv); + SDL_UnlockMutex(fragment_mutex); SDL_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); - SDL_DestroyCond(audio_buffer_cv); - SDL_DestroyMutex(audio_buffer_mutex); - SDL_DestroyCond(halt_cv); - SDL_DestroyMutex(halt_mutex); + SDL_DestroyCond(fragment_cv); + SDL_DestroyMutex(fragment_mutex); + + if (nfragments > 1) { + for (unsigned i = 0; i < nfragments; i++) { + free(fragment_buffer[i]); + } + } + + free(fragment_buffer); } static void *write_buffer(void *buffer) { (void)buffer; - // unblock audio thread - SDL_LockMutex(halt_mutex); - halt = 0; - SDL_CondSignal(halt_cv); - SDL_UnlockMutex(halt_mutex); - if (xroar_noratelimit) + SDL_LockMutex(fragment_mutex); + + /* For nfragments == 1, a non-NULL buffer means we've finished writing + * to the buffer provided by the callback. Otherwise, one fragment + * buffer is now full. Either way, signal the callback in case it is + * waiting for data to be available. */ + + if (buffer) { + write_fragment = (write_fragment + 1) % nfragments; + fragment_queue_length++; + SDL_CondSignal(fragment_cv); + } + + if (xroar_noratelimit) { + SDL_UnlockMutex(fragment_mutex); return NULL; + } - // wait for audio thread to pass a buffer pointer - SDL_LockMutex(audio_buffer_mutex); - while (!audio_buffer) { - if (SDL_CondWaitTimeout(audio_buffer_cv, audio_buffer_mutex, timeout_ms) == SDL_MUTEX_TIMEDOUT) { - SDL_UnlockMutex(audio_buffer_mutex); - return NULL; + if (nfragments == 1) { + // for nfragments == 1, wait for callback to send buffer + while (callback_buffer == NULL) { + if (SDL_CondWaitTimeout(fragment_cv, fragment_mutex, timeout_ms) == SDL_MUTEX_TIMEDOUT) { + SDL_UnlockMutex(fragment_mutex); + return NULL; + } + } + fragment_buffer[0] = callback_buffer; + callback_buffer = NULL; + } else { + // for nfragments > 1, wait until a fragment buffer is available + while (fragment_queue_length == nfragments) { + if (SDL_CondWaitTimeout(fragment_cv, fragment_mutex, timeout_ms) == SDL_MUTEX_TIMEDOUT) { + SDL_UnlockMutex(fragment_mutex); + return NULL; + } } } - void *r = audio_buffer; - audio_buffer = NULL; - SDL_UnlockMutex(audio_buffer_mutex); - return r; + SDL_UnlockMutex(fragment_mutex); + return fragment_buffer[write_fragment]; } static void callback(void *userdata, Uint8 *stream, int len) { (void)userdata; /* unused */ + if (shutting_down) + return; + SDL_LockMutex(fragment_mutex); + + // wait until at least one fragment buffer is filled + while (fragment_queue_length == 0) + SDL_CondWait(fragment_cv, fragment_mutex); + + // copy it to callback buffer + memcpy(stream, fragment_buffer[play_fragment], fragment_nbytes); + play_fragment = (play_fragment + 1) % nfragments; + + // signal main thread that a fragment buffer is available + fragment_queue_length--; + SDL_CondSignal(fragment_cv); - if (!shutting_down) { - SDL_LockMutex(halt_mutex); - halt = 1; - } - - // pass buffer pointer back to main thread - SDL_LockMutex(audio_buffer_mutex); - audio_buffer = stream; - SDL_CondSignal(audio_buffer_cv); - SDL_UnlockMutex(audio_buffer_mutex); - - // wait for main thread to be done with buffer - if (!shutting_down) { - while (halt) - SDL_CondWait(halt_cv, halt_mutex); - SDL_UnlockMutex(halt_mutex); - } + SDL_UnlockMutex(fragment_mutex); +} + +static void callback_1(void *userdata, Uint8 *stream, int len) { + (void)userdata; /* unused */ + if (shutting_down) + return; + SDL_LockMutex(fragment_mutex); + + // pass callback buffer to main thread + callback_buffer = stream; + SDL_CondSignal(fragment_cv); + + // wait until main thread signals filled buffer + while (fragment_queue_length == 0) + SDL_CondWait(fragment_cv, fragment_mutex); + + // set to 0 so next callback will wait + fragment_queue_length = 0; + + SDL_UnlockMutex(fragment_mutex); } diff -Nru xroar-0.31.1/src/sdl/common.c xroar-0.32/src/sdl/common.c --- xroar-0.31.1/src/sdl/common.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sdl/common.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -27,8 +27,8 @@ #include -#include "pl_glib.h" -#include "pl_string.h" +#include "pl-string.h" +#include "xalloc.h" #include "events.h" #include "joystick.h" @@ -43,7 +43,7 @@ unsigned sdl_window_x = 0, sdl_window_y = 0; unsigned sdl_window_w = 320, sdl_window_h = 240; -VideoModule *sdl_video_module_list[] = { +VideoModule * const sdl_video_module_list[] = { #ifdef HAVE_SDLGL &video_sdlgl_module, #endif @@ -58,7 +58,7 @@ NULL }; -KeyboardModule *sdl_keyboard_module_list[] = { +KeyboardModule * const sdl_keyboard_module_list[] = { &keyboard_sdl_module, NULL }; @@ -95,13 +95,13 @@ NULL }; -JoystickModule sdl_js_internal = { +struct joystick_module sdl_js_internal = { .common = { .name = "sdl", .description = "SDL joystick input", .shutdown = sdl_js_shutdown }, - .interface_list = js_iflist, + .intf_list = js_iflist, }; -JoystickModule *sdl_js_modlist[] = { +struct joystick_module * const sdl_js_modlist[] = { &sdl_js_internal, NULL }; @@ -133,6 +133,11 @@ case SDL_KEYUP: sdl_keyrelease(&event.key.keysym); break; +#ifdef WINDOWS32 + case SDL_SYSWMEVENT: + sdl_windows32_handle_syswmevent(event.syswm.msg); + break; +#endif default: break; } @@ -196,7 +201,7 @@ mouse_yoffset = off0 + 24.0; mouse_ydiv = off1 - off0; } - struct joystick_axis *axis = g_malloc(sizeof(*axis)); + struct joystick_axis *axis = xmalloc(sizeof(*axis)); axis->read = (js_read_axis_func)read_axis; axis->data = &mouse_axis[jaxis]; return axis; @@ -208,7 +213,7 @@ jbutton = strtol(spec, NULL, 0) - 1; if (jbutton >= 3) return NULL; - struct joystick_button *button = g_malloc(sizeof(*button)); + struct joystick_button *button = xmalloc(sizeof(*button)); button->read = (js_read_button_func)read_button; button->data = &mouse_button[jbutton]; return button; diff -Nru xroar-0.31.1/src/sdl/common.h xroar-0.32/src/sdl/common.h --- xroar-0.31.1/src/sdl/common.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sdl/common.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -7,6 +7,7 @@ #define XROAR_SDL_COMMON_H_ #include "module.h" +struct joystick_module; extern unsigned sdl_window_x, sdl_window_y; extern unsigned sdl_window_w, sdl_window_h; @@ -19,11 +20,11 @@ extern struct joystick_interface sdl_js_if_physical; extern struct joystick_interface sdl_js_if_keyboard; -extern JoystickModule sdl_js_internal; +extern struct joystick_module sdl_js_internal; -extern VideoModule *sdl_video_module_list[]; -extern KeyboardModule *sdl_keyboard_module_list[]; -extern JoystickModule *sdl_js_modlist[]; +extern VideoModule * const sdl_video_module_list[]; +extern KeyboardModule * const sdl_keyboard_module_list[]; +extern struct joystick_module * const sdl_js_modlist[]; void sdl_run(void); void sdl_keypress(SDL_keysym *keysym); @@ -33,4 +34,7 @@ void sdl_zoom_in(void); void sdl_zoom_out(void); +void sdl_windows32_update_menu(_Bool fullscreen); +void sdl_windows32_handle_syswmevent(void *data); + #endif /* XROAR_SDL_COMMON_H_ */ diff -Nru xroar-0.31.1/src/sdl/joystick_sdl.c xroar-0.32/src/sdl/joystick_sdl.c --- xroar-0.31.1/src/sdl/joystick_sdl.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sdl/joystick_sdl.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -25,8 +25,9 @@ #include -#include "pl_glib.h" -#include "pl_string.h" +#include "pl-string.h" +#include "slist.h" +#include "xalloc.h" #include "joystick.h" #include "logging.h" @@ -56,10 +57,10 @@ NULL }; -JoystickModule sdl_js_mod_exported = { +struct joystick_module sdl_js_mod_exported = { .common = { .name = "sdl", .description = "SDL joystick input", .shutdown = sdl_js_physical_shutdown }, - .interface_list = js_iflist, + .intf_list = js_iflist, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -77,7 +78,7 @@ unsigned open_count; }; -static GSList *device_list = NULL; +static struct slist *device_list = NULL; struct control { struct device *device; @@ -93,9 +94,9 @@ SDL_InitSubSystem(SDL_INIT_JOYSTICK); num_joysticks = SDL_NumJoysticks(); if (num_joysticks < 1) { - LOG_DEBUG(2, "\tNo joysticks found\n"); + LOG_DEBUG(1, "\tNo joysticks found\n"); } else { - LOG_DEBUG(2, "\t%d joysticks found\n", num_joysticks); + LOG_DEBUG(1, "\t%u joysticks found\n", num_joysticks); } initialised = 1; } @@ -111,7 +112,7 @@ static struct device *open_device(int joystick_index) { // If the device is already open, just up its count and return it - for (GSList *iter = device_list; iter; iter = iter->next) { + for (struct slist *iter = device_list; iter; iter = iter->next) { struct device *d = iter->data; if (d->joystick_index == joystick_index) { d->open_count++; @@ -122,13 +123,13 @@ SDL_Joystick *j = SDL_JoystickOpen(joystick_index); if (!j) return NULL; - struct device *d = g_malloc(sizeof(*d)); + struct device *d = xmalloc(sizeof(*d)); d->joystick_index = joystick_index; d->joystick = j; d->num_axes = SDL_JoystickNumAxes(j); d->num_buttons = SDL_JoystickNumButtons(j); d->open_count = 1; - device_list = g_slist_prepend(device_list, d); + device_list = slist_prepend(device_list, d); return d; } @@ -136,8 +137,8 @@ d->open_count--; if (d->open_count == 0) { SDL_JoystickClose(d->joystick); - device_list = g_slist_remove(device_list, d); - g_free(d); + device_list = slist_remove(device_list, d); + free(d); } } @@ -180,7 +181,7 @@ struct device *d = open_device(joystick); if (!d) return NULL; - struct control *c = g_malloc(sizeof(*c)); + struct control *c = xmalloc(sizeof(*c)); c->device = d; c->control = control; c->inverted = inverted; @@ -194,10 +195,10 @@ return NULL; if (c->control >= c->device->num_axes) { close_device(c->device); - g_free(c); + free(c); return NULL; } - struct joystick_axis *axis = g_malloc(sizeof(*axis)); + struct joystick_axis *axis = xmalloc(sizeof(*axis)); axis->read = (js_read_axis_func)read_axis; axis->data = c; return axis; @@ -210,10 +211,10 @@ return NULL; if (c->control >= c->device->num_buttons) { close_device(c->device); - g_free(c); + free(c); return NULL; } - struct joystick_button *button = g_malloc(sizeof(*button)); + struct joystick_button *button = xmalloc(sizeof(*button)); button->read = (js_read_button_func)read_button; button->data = c; return button; @@ -224,8 +225,8 @@ return; struct control *c = axis->data; close_device(c->device); - g_free(c); - g_free(axis); + free(c); + free(axis); } static void unmap_button(struct joystick_button *button) { @@ -233,6 +234,6 @@ return; struct control *c = button->data; close_device(c->device); - g_free(c); - g_free(button); + free(c); + free(button); } diff -Nru xroar-0.31.1/src/sdl/keyboard_sdl.c xroar-0.32/src/sdl/keyboard_sdl.c --- xroar-0.31.1/src/sdl/keyboard_sdl.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sdl/keyboard_sdl.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -27,8 +27,10 @@ #include -#include "pl_glib.h" -#include "pl_string.h" +#include "array.h" +#include "c-strcase.h" +#include "pl-string.h" +#include "xalloc.h" #include "dkbd.h" #include "joystick.h" @@ -151,7 +153,7 @@ sym_to_dkey[i] = DSCAN_INVALID; sym_priority[i] = 0; } - for (int i = 0; i < G_N_ELEMENTS(sym_dkey_default); i++) { + for (int i = 0; i < ARRAY_N_ELEMENTS(sym_dkey_default); i++) { sym_to_dkey[sym_dkey_default[i].sym] = sym_dkey_default[i].dkey; sym_priority[sym_dkey_default[i].sym] = sym_dkey_default[i].priority; } @@ -181,16 +183,16 @@ struct keymap *selected_keymap = &keymaps[0]; if (keymap_option) { if (0 == strcmp(keymap_option, "help")) { - for (int i = 0; i < G_N_ELEMENTS(keymaps); i++) { + for (int i = 0; i < ARRAY_N_ELEMENTS(keymaps); i++) { if (keymaps[i].description) printf("\t%-10s %s\n", keymaps[i].name, keymaps[i].description); } exit(EXIT_SUCCESS); } - for (int i = 0; i < G_N_ELEMENTS(keymaps); i++) { + for (int i = 0; i < ARRAY_N_ELEMENTS(keymaps); i++) { if (0 == strcmp(keymap_option, keymaps[i].name)) { selected_keymap = &keymaps[i]; - LOG_DEBUG(2,"\tSelecting '%s' keymap\n",keymap_option); + LOG_DEBUG(1, "\tSelecting '%s' keymap\n",keymap_option); } } } @@ -236,7 +238,7 @@ xroar_toggle_cart(); break; case SDLK_f: - xroar_fullscreen(XROAR_TOGGLE); + xroar_set_fullscreen(1, XROAR_TOGGLE); break; case SDLK_h: if (shift) @@ -250,9 +252,9 @@ break; case SDLK_j: if (shift) { - joystick_swap(); + xroar_swap_joysticks(1); } else { - joystick_cycle(); + xroar_cycle_joysticks(1); } break; case SDLK_k: @@ -290,7 +292,7 @@ break; #endif case SDLK_z: /* running out of letters... */ - xroar_set_kbd_translate(XROAR_TOGGLE); + xroar_set_kbd_translate(1, XROAR_TOGGLE); break; default: break; @@ -336,7 +338,7 @@ return; } if (sym == SDLK_F11) { - xroar_fullscreen(XROAR_TOGGLE); + xroar_set_fullscreen(1, XROAR_TOGGLE); return; } if (sym == SDLK_F12) { @@ -483,7 +485,7 @@ if (isdigit(name[0])) return strtol(name, NULL, 0); for (SDLKey i = SDLK_FIRST; i < SDLK_LAST; i++) { - if (0 == g_ascii_strcasecmp(name, SDL_GetKeyName(i))) + if (0 == c_strcasecmp(name, SDL_GetKeyName(i))) return i; } return SDLK_UNKNOWN; @@ -509,11 +511,11 @@ key0 = get_key_by_name(a0); if (a1 && *a1) key1 = get_key_by_name(a1); - struct axis *axis_data = g_malloc(sizeof(*axis_data)); + struct axis *axis_data = xmalloc(sizeof(*axis_data)); axis_data->key0 = key0; axis_data->key1 = key1; axis_data->value = 127; - struct joystick_axis *axis = g_malloc(sizeof(*axis)); + struct joystick_axis *axis = xmalloc(sizeof(*axis)); axis->read = (js_read_axis_func)read_axis; axis->data = axis_data; for (unsigned i = 0; i < MAX_AXES; i++) { @@ -529,10 +531,10 @@ SDLKey key = (jbutton == 0) ? SDLK_LALT : SDLK_UNKNOWN; if (spec && *spec) key = get_key_by_name(spec); - struct button *button_data = g_malloc(sizeof(*button_data)); + struct button *button_data = xmalloc(sizeof(*button_data)); button_data->key = key; button_data->value = 0; - struct joystick_button *button = g_malloc(sizeof(*button)); + struct joystick_button *button = xmalloc(sizeof(*button)); button->read = (js_read_button_func)read_button; button->data = button_data; for (unsigned i = 0; i < MAX_BUTTONS; i++) { @@ -552,8 +554,8 @@ enabled_axis[i] = NULL; } } - g_free(axis->data); - g_free(axis); + free(axis->data); + free(axis); } static void unmap_button(struct joystick_button *button) { @@ -564,6 +566,6 @@ enabled_button[i] = NULL; } } - g_free(button->data); - g_free(button); + free(button->data); + free(button); } diff -Nru xroar-0.31.1/src/sdl/keyboard_sdl_mappings.c xroar-0.32/src/sdl/keyboard_sdl_mappings.c --- xroar-0.31.1/src/sdl/keyboard_sdl_mappings.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sdl/keyboard_sdl_mappings.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -425,7 +425,7 @@ { SDLK_z, DSCAN_SLASH }, }; -#define MAPPING(m) .num_mappings = G_N_ELEMENTS(m), .mappings = (m) +#define MAPPING(m) .num_mappings = ARRAY_N_ELEMENTS(m), .mappings = (m) static struct keymap keymaps[] = { { .name = "uk", MAPPING(keymap_uk), .description = "UK" }, diff -Nru xroar-0.31.1/src/sdl/ui_sdl.c xroar-0.32/src/sdl/ui_sdl.c --- xroar-0.31.1/src/sdl/ui_sdl.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sdl/ui_sdl.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -23,6 +23,7 @@ #include #include +#include #include "events.h" #include "keyboard.h" @@ -35,13 +36,57 @@ #include "sdl/common.h" +#ifdef WINDOWS32 +#include "windows32/common_windows32.h" +#endif + /* Note: prefer the default order for sound and joystick modules, which * will include the SDL options. */ +static _Bool init(void); +static void shutdown(void); + UIModule ui_sdl_module = { - .common = { .name = "sdl", .description = "SDL UI" }, + .common = { .name = "sdl", .description = "SDL UI", + .init = init, .shutdown = shutdown }, .video_module_list = sdl_video_module_list, .keyboard_module_list = sdl_keyboard_module_list, .joystick_module_list = sdl_js_modlist, .run = sdl_run, }; + +static _Bool init(void) { +#ifdef WINDOWS32 + if (!getenv("SDL_VIDEODRIVER")) + putenv("SDL_VIDEODRIVER=windib"); +#endif + + if (!SDL_WasInit(SDL_INIT_NOPARACHUTE)) { + if (SDL_Init(SDL_INIT_NOPARACHUTE) < 0) { + LOG_ERROR("Failed to initialise SDL: %s\n", SDL_GetError()); + return 0; + } + } + + if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { + LOG_ERROR("Failed to initialise SDL video: %s\n", SDL_GetError()); + return 0; + } + +#ifdef WINDOWS32 + { + SDL_version sdlver; + SDL_SysWMinfo sdlinfo; + SDL_VERSION(&sdlver); + sdlinfo.version = sdlver; + SDL_GetWMInfo(&sdlinfo); + windows32_main_hwnd = sdlinfo.window; + } +#endif + + return 1; +} + +static void shutdown(void) { + SDL_QuitSubSystem(SDL_INIT_VIDEO); +} diff -Nru xroar-0.31.1/src/sdl/vo_sdl.c xroar-0.32/src/sdl/vo_sdl.c --- xroar-0.31.1/src/sdl/vo_sdl.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sdl/vo_sdl.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -23,7 +23,6 @@ #include #include -#include #include "logging.h" #include "mc6847.h" @@ -32,15 +31,11 @@ #include "sdl/common.h" -#ifdef WINDOWS32 -#include "windows32/common_windows32.h" -#endif - static _Bool init(void); static void shutdown(void); static void alloc_colours(void); static void vsync(void); -static void render_scanline(uint8_t *scanline_data); +static void render_scanline(uint8_t const *scanline_data); static int set_fullscreen(_Bool fullscreen); static void update_cross_colour_phase(void); @@ -88,32 +83,8 @@ #include "vo_generic_ops.c" static _Bool init(void) { -#ifdef WINDOWS32 - if (!getenv("SDL_VIDEODRIVER")) - putenv("SDL_VIDEODRIVER=windib"); -#endif - if (!SDL_WasInit(SDL_INIT_NOPARACHUTE)) { - if (SDL_Init(SDL_INIT_NOPARACHUTE) < 0) { - LOG_ERROR("Failed to initialise SDL: %s\n", SDL_GetError()); - return 0; - } - } - if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { - LOG_ERROR("Failed to initialise SDL video: %s\n", SDL_GetError()); - return 0; - } if (set_fullscreen(xroar_cfg.fullscreen)) return 0; -#ifdef WINDOWS32 - { - SDL_version sdlver; - SDL_SysWMinfo sdlinfo; - SDL_VERSION(&sdlver); - sdlinfo.version = sdlver; - SDL_GetWMInfo(&sdlinfo); - windows32_main_hwnd = sdlinfo.window; - } -#endif vsync(); return 1; } @@ -121,10 +92,12 @@ static void shutdown(void) { set_fullscreen(0); /* Should not be freed by caller: SDL_FreeSurface(screen); */ - SDL_QuitSubSystem(SDL_INIT_VIDEO); } static int set_fullscreen(_Bool fullscreen) { +#ifdef WINDOWS32 + sdl_windows32_update_menu(fullscreen); +#endif screen = SDL_SetVideoMode(320, 240, 8, SDL_HWSURFACE|(fullscreen?SDL_FULLSCREEN:0)); if (screen == NULL) { LOG_ERROR("Failed to allocate SDL surface for display\n"); diff -Nru xroar-0.31.1/src/sdl/vo_sdlgl.c xroar-0.32/src/sdl/vo_sdlgl.c --- xroar-0.31.1/src/sdl/vo_sdlgl.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sdl/vo_sdlgl.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -23,7 +23,6 @@ #include #include -#include #include "logging.h" #include "mc6847.h" @@ -33,10 +32,6 @@ #include "sdl/common.h" -#ifdef WINDOWS32 -#include "windows32/common_windows32.h" -#endif - static _Bool init(void); static void shutdown(void); static void refresh(void); @@ -62,21 +57,6 @@ static _Bool init(void) { const SDL_VideoInfo *video_info; -#ifdef WINDOWS32 - if (!getenv("SDL_VIDEODRIVER")) - putenv("SDL_VIDEODRIVER=windib"); -#endif - if (!SDL_WasInit(SDL_INIT_NOPARACHUTE)) { - if (SDL_Init(SDL_INIT_NOPARACHUTE) < 0) { - LOG_ERROR("Failed to initialise SDL: %s\n", SDL_GetError()); - return 0; - } - } - if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { - LOG_ERROR("Failed to initialise SDL video: %s\n", SDL_GetError()); - return 0; - } - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); @@ -93,16 +73,6 @@ if (set_fullscreen(xroar_cfg.fullscreen)) return 0; -#ifdef WINDOWS32 - { - SDL_version sdlver; - SDL_SysWMinfo sdlinfo; - SDL_VERSION(&sdlver); - sdlinfo.version = sdlver; - SDL_GetWMInfo(&sdlinfo); - windows32_main_hwnd = sdlinfo.window; - } -#endif vsync(); return 1; } @@ -111,7 +81,6 @@ set_fullscreen(0); vo_opengl_shutdown(); /* Should not be freed by caller: SDL_FreeSurface(screen); */ - SDL_QuitSubSystem(SDL_INIT_VIDEO); } static void resize(unsigned int w, unsigned int h) { @@ -123,6 +92,10 @@ static int set_fullscreen(_Bool fullscreen) { unsigned int want_width, want_height; +#ifdef WINDOWS32 + sdl_windows32_update_menu(fullscreen); +#endif + if (fullscreen) { want_width = screen_width; want_height = screen_height; diff -Nru xroar-0.31.1/src/sdl/vo_sdlyuv.c xroar-0.32/src/sdl/vo_sdlyuv.c --- xroar-0.31.1/src/sdl/vo_sdlyuv.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sdl/vo_sdlyuv.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -23,7 +23,6 @@ #include #include -#include #include "logging.h" #include "mc6847.h" @@ -32,15 +31,11 @@ #include "sdl/common.h" -#ifdef WINDOWS32 -#include "windows32/common_windows32.h" -#endif - static _Bool init(void); static void shutdown(void); static void alloc_colours(void); static void vsync(void); -static void render_scanline(uint8_t *scanline_data); +static void render_scanline(uint8_t const *scanline_data); static void resize(unsigned int w, unsigned int h); static int set_fullscreen(_Bool fullscreen); static void update_cross_colour_phase(void); @@ -77,7 +72,7 @@ #include "vo_generic_ops.c" /* The packed modes supported by SDL: */ -static Uint32 try_overlay_format[] = { +static const Uint32 try_overlay_format[] = { SDL_YUY2_OVERLAY, SDL_UYVY_OVERLAY, SDL_YVYU_OVERLAY, @@ -89,21 +84,6 @@ const SDL_VideoInfo *video_info; int i; -#ifdef WINDOWS32 - if (!getenv("SDL_VIDEODRIVER")) - putenv("SDL_VIDEODRIVER=windib"); -#endif - if (!SDL_WasInit(SDL_INIT_NOPARACHUTE)) { - if (SDL_Init(SDL_INIT_NOPARACHUTE) < 0) { - LOG_ERROR("Failed to initialise SDL: %s\n", SDL_GetError()); - return 0; - } - } - if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { - LOG_ERROR("Failed to initialise SDL video: %s\n", SDL_GetError()); - return 0; - } - video_info = SDL_GetVideoInfo(); screen_width = video_info->current_w; screen_height = video_info->current_h; @@ -146,16 +126,7 @@ video_module->window_y = VDG_TOP_BORDER_START + 1; video_module->window_w = 320; video_module->window_h = 240; -#ifdef WINDOWS32 - { - SDL_version sdlver; - SDL_SysWMinfo sdlinfo; - SDL_VERSION(&sdlver); - sdlinfo.version = sdlver; - SDL_GetWMInfo(&sdlinfo); - windows32_main_hwnd = sdlinfo.window; - } -#endif + vsync(); return 1; } @@ -164,7 +135,6 @@ set_fullscreen(0); SDL_FreeYUVOverlay(overlay); /* Should not be freed by caller: SDL_FreeSurface(screen); */ - SDL_QuitSubSystem(SDL_INIT_VIDEO); } static Uint32 map_colour(int r, int g, int b) { @@ -203,6 +173,10 @@ static int set_fullscreen(_Bool fullscreen) { unsigned int want_width, want_height; +#ifdef WINDOWS32 + sdl_windows32_update_menu(fullscreen); +#endif + if (fullscreen) { want_width = screen_width; want_height = screen_height; diff -Nru xroar-0.31.1/src/snapshot.c xroar-0.32/src/snapshot.c --- xroar-0.31.1/src/snapshot.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/snapshot.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -22,8 +22,6 @@ #include #include -#include "pl_glib.h" - #include "cart.h" #include "fs.h" #include "keyboard.h" @@ -193,9 +191,8 @@ fs_write_uint16(fd, sam_get_register()); // Attached virtual disk filenames { - struct vdisk *disk; for (unsigned drive = 0; drive < VDRIVE_MAX_DRIVES; drive++) { - disk = vdrive_disk_in_drive(drive); + struct vdisk *disk = vdrive_disk_in_drive(drive); if (disk != NULL && disk->filename != NULL) { int length = strlen(disk->filename) + 1; write_chunk_header(fd, ID_VDISK_FILE, 1 + length); @@ -209,7 +206,7 @@ return 0; } -static int old_arch_mapping[4] = { +static const int old_arch_mapping[4] = { MACHINE_DRAGON32, MACHINE_DRAGON64, MACHINE_TANO, @@ -259,13 +256,17 @@ int read_snapshot(const char *filename) { FILE *fd; uint8_t buffer[17]; - int section, size, tmp; + int section, tmp; int version_major = 1, version_minor = 0; if (filename == NULL) return -1; if (!(fd = fopen(filename, "rb"))) return -1; - fread(buffer, 17, 1, fd); + if (fread(buffer, 17, 1, fd) < 1) { + LOG_WARN("Snapshot format not recognised.\n"); + fclose(fd); + return -1; + } if (strncmp((char *)buffer, "XRoar snapshot.\012\000", 17)) { // Very old-style snapshot. Register dump always came first. // Also, it used to be written out as only taking 12 bytes. @@ -284,9 +285,8 @@ if (buffer[0] != 'X') { old_set_registers(buffer + 3); } - struct HD6309 *hcpu = NULL; while ((section = fs_read_uint8(fd)) >= 0) { - size = fs_read_uint16(fd); + int size = fs_read_uint16(fd); if (size == 0) size = 0x10000; switch (section) { case ID_ARCHITECTURE: @@ -371,7 +371,7 @@ break; } struct MC6809 *cpu = machine_get_cpu(0); - hcpu = (struct HD6309 *)cpu; + struct HD6309 *hcpu = (struct HD6309 *)cpu; cpu->reg_cc = fs_read_uint8(fd); MC6809_REG_A(cpu) = fs_read_uint8(fd); MC6809_REG_B(cpu) = fs_read_uint8(fd); @@ -490,7 +490,7 @@ drive = fs_read_uint8(fd); vdrive_eject_disk(drive); if (size > 0) { - char *name = g_try_malloc(size); + char *name = malloc(size); if (name != NULL) { size -= fread(name, 1, size, fd); vdrive_insert_disk(drive, vdisk_load(name)); diff -Nru xroar-0.31.1/src/snapshot.h xroar-0.32/src/snapshot.h --- xroar-0.31.1/src/snapshot.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/snapshot.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/sound.c xroar-0.32/src/sound.c --- xroar-0.31.1/src/sound.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sound.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -23,8 +23,7 @@ #include #include -#include "pl_glib.h" - +#include "delegate.h" #include "events.h" #include "logging.h" #include "machine.h" @@ -113,7 +112,7 @@ static float external_level[2] = { 0.0, 0.0 }; // Feedback to the single-bit audio pin -sound_feedback_delegate sound_sbs_feedback = { NULL, NULL }; +DELEGATE_T1(void, bool) sound_sbs_feedback = { NULL, NULL }; void sound_init(void *buf, enum sound_fmt fmt, unsigned rate, unsigned nchannels, unsigned nframes) { uint16_t test = 0x0123; @@ -147,34 +146,35 @@ fmt_big_endian = !big_endian; } - LOG_DEBUG(2, "\t"); + (void)fmt_big_endian; // suppress unused warning + LOG_DEBUG(1, "\t"); switch (fmt) { case SOUND_FMT_U8: - LOG_DEBUG(2, "8-bit unsigned, "); + LOG_DEBUG(1, "8-bit unsigned, "); break; case SOUND_FMT_S8: - LOG_DEBUG(2, "8-bit signed, "); + LOG_DEBUG(1, "8-bit signed, "); break; case SOUND_FMT_S16_HE: case SOUND_FMT_S16_SE: - LOG_DEBUG(2, "16-bit signed %s-endian, ", fmt_big_endian ? "big" : "little" ); + LOG_DEBUG(1, "16-bit signed %s-endian, ", fmt_big_endian ? "big" : "little" ); break; case SOUND_FMT_FLOAT: - LOG_DEBUG(2, "Floating point, "); + LOG_DEBUG(1, "Floating point, "); break; case SOUND_FMT_NULL: default: fmt = SOUND_FMT_NULL; - LOG_DEBUG(2, "No audio\n"); + LOG_DEBUG(1, "No audio\n"); break; } if (fmt != SOUND_FMT_NULL) { switch (nchannels) { - case 1: LOG_DEBUG(2, "mono, "); break; - case 2: LOG_DEBUG(2, "stereo, "); break; - default: LOG_DEBUG(2, "%d channel, ", nchannels); break; + case 1: LOG_DEBUG(1, "mono, "); break; + case 2: LOG_DEBUG(1, "stereo, "); break; + default: LOG_DEBUG(1, "%u channel, ", nchannels); break; } - LOG_DEBUG(2, "%dHz\n", rate); + LOG_DEBUG(1, "%uHz\n", rate); } output_level[0] = output_level[1] = 0.0; @@ -186,7 +186,7 @@ ticks_per_buffer = ticks_per_frame * nframes; last_cycle = event_current_tick; - event_init(&flush_event, flush_frame, NULL); + event_init(&flush_event, DELEGATE_AS0(void, flush_frame, NULL)); flush_event.at_tick = event_current_tick + ticks_per_buffer; event_queue(&MACHINE_EVENT_LIST, &flush_event); } @@ -198,7 +198,6 @@ } static void fill_int8(int nframes) { - uint8_t *ptr = (uint8_t *)buffer + buffer_frame * buffer_nchannels; while (nframes > 0) { int count; if ((buffer_frame + nframes) > buffer_nframes) @@ -206,28 +205,28 @@ else count = nframes; nframes -= count; - if (buffer_nchannels == 1) { - /* special case for single channel 8-bit */ - memset(ptr, last_sample.as_int8[0], count); - } else { - for (int i = 0; i < count; i++) { - for (int j = 0; j < buffer_nchannels; j++) { - *(ptr++) = last_sample.as_int8[j]; + if (buffer) { + uint8_t *ptr = (uint8_t *)buffer + buffer_frame * buffer_nchannels; + if (buffer_nchannels == 1) { + /* special case for single channel 8-bit */ + memset(ptr, last_sample.as_int8[0], count); + } else { + for (int i = 0; i < count; i++) { + for (int j = 0; j < buffer_nchannels; j++) { + *(ptr++) = last_sample.as_int8[j]; + } } } } buffer_frame += count; if (buffer_frame >= buffer_nframes) { - ptr = buffer = sound_module->write_buffer(buffer); + buffer = sound_module->write_buffer(buffer); buffer_frame = 0; - if (!buffer) - return; } } } static void fill_int16(int nframes) { - uint16_t *ptr = (uint16_t *)buffer + buffer_frame * buffer_nchannels; while (nframes > 0) { int count; if ((buffer_frame + nframes) > buffer_nframes) @@ -235,23 +234,23 @@ else count = nframes; nframes -= count; - for (int i = 0; i < count; i++) { - for (int j = 0; j < buffer_nchannels; j++) { - *(ptr++) = last_sample.as_int16[j]; + if (buffer) { + uint16_t *ptr = (uint16_t *)buffer + buffer_frame * buffer_nchannels; + for (int i = 0; i < count; i++) { + for (int j = 0; j < buffer_nchannels; j++) { + *(ptr++) = last_sample.as_int16[j]; + } } } buffer_frame += count; if (buffer_frame >= buffer_nframes) { - ptr = buffer = sound_module->write_buffer(buffer); + buffer = sound_module->write_buffer(buffer); buffer_frame = 0; - if (!buffer) - return; } } } static void fill_float(int nframes) { - float *ptr = (float *)buffer + buffer_frame * buffer_nchannels; while (nframes > 0) { int count; if ((buffer_frame + nframes) > buffer_nframes) @@ -259,17 +258,18 @@ else count = nframes; nframes -= count; - for (int i = 0; i < count; i++) { - for (int j = 0; j < buffer_nchannels; j++) { - *(ptr++) = last_sample.as_float[j]; + if (buffer) { + float *ptr = (float *)buffer + buffer_frame * buffer_nchannels; + for (int i = 0; i < count; i++) { + for (int j = 0; j < buffer_nchannels; j++) { + *(ptr++) = last_sample.as_float[j]; + } } } buffer_frame += count; if (buffer_frame >= buffer_nframes) { - ptr = buffer = sound_module->write_buffer(buffer); + buffer = sound_module->write_buffer(buffer); buffer_frame = 0; - if (!buffer) - return; } } } @@ -321,25 +321,21 @@ } /* Fill buffer */ - if (buffer) { - switch (buffer_fmt) { - case SOUND_FMT_U8: - case SOUND_FMT_S8: - fill_int8(nframes); - break; - case SOUND_FMT_S16_HE: - case SOUND_FMT_S16_SE: - fill_int16(nframes); - break; - case SOUND_FMT_FLOAT: - fill_float(nframes); - break; - default: - null_frames(nframes); - break; - } - } else { + switch (buffer_fmt) { + case SOUND_FMT_U8: + case SOUND_FMT_S8: + fill_int8(nframes); + break; + case SOUND_FMT_S16_HE: + case SOUND_FMT_S16_SE: + fill_int16(nframes); + break; + case SOUND_FMT_FLOAT: + fill_float(nframes); + break; + default: null_frames(nframes); + break; } last_cycle = event_current_tick; @@ -372,9 +368,7 @@ /* Feed back bus level to single bit pin */ #ifndef FAST_SOUND - if (sound_sbs_feedback.delegate) - sound_sbs_feedback.delegate(sound_sbs_feedback.dptr, - sbs_enabled || bus_level >= 1.414); + DELEGATE_SAFE_CALL1(sound_sbs_feedback, sbs_enabled || bus_level >= 1.414); #endif /* Mix bus & external sound */ diff -Nru xroar-0.31.1/src/sound.h xroar-0.32/src/sound.h --- xroar-0.31.1/src/sound.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sound.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,11 +1,13 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ #ifndef XROAR_SOUND_H_ #define XROAR_SOUND_H_ +#include "delegate.h" + enum sound_fmt { SOUND_FMT_NULL, SOUND_FMT_U8, @@ -17,16 +19,7 @@ SOUND_FMT_FLOAT, }; -// Input from tape -extern float sound_tape_level; - -// Feedback to the single-bit audio pin -typedef struct { - void (*delegate)(void *, _Bool level); - void *dptr; -} sound_feedback_delegate; - -extern sound_feedback_delegate sound_sbs_feedback; +extern DELEGATE_T1(void, bool) sound_sbs_feedback; void sound_init(void *buf, enum sound_fmt fmt, unsigned rate, unsigned nchannels, unsigned nframes); void sound_set_volume(int v); diff -Nru xroar-0.31.1/src/sunos/ao_sun.c xroar-0.32/src/sunos/ao_sun.c --- xroar-0.31.1/src/sunos/ao_sun.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/sunos/ao_sun.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -97,7 +97,7 @@ } sound_init(device_info.play.sample_rate, device_info.play.channels, SOUND_FMT_U8, frame_nbytes); - LOG_DEBUG(2, "\t%dms (%d frames) buffer\n", (frame_nbytes * 1000) / device_info.play.sample_rate, frame_nbytes); + LOG_DEBUG(1, "\t%dms (%d frames) buffer\n", (frame_nbytes * 1000) / device_info.play.sample_rate, frame_nbytes); ioctl(sound_fd, I_FLUSH, FLUSHW); ioctl(sound_fd, AUDIO_GETINFO, &device_info); diff -Nru xroar-0.31.1/src/tape.c xroar-0.32/src/tape.c --- xroar-0.31.1/src/tape.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/tape.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -23,9 +23,10 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "breakpoint.h" +#include "delegate.h" #include "events.h" #include "fs.h" #include "keyboard.h" @@ -39,7 +40,7 @@ /* Tape output delegate. Called when the output from the tape unit (i.e., the * input to the machine) changes. */ -tape_audio_delegate tape_update_audio = { NULL, NULL }; +DELEGATE_T1(void, float) tape_update_audio; struct tape *tape_input = NULL; struct tape *tape_output = NULL; @@ -91,11 +92,11 @@ static int tape_bit_in(struct tape *t) { if (!t) return -1; - int phase, pulse0_width, pulse1_width, cycle_width; + int phase, pulse1_width, cycle_width; if (tape_pulse_in(t, &pulse1_width) == -1) return -1; do { - pulse0_width = pulse1_width; + int pulse0_width = pulse1_width; if ((phase = tape_pulse_in(t, &pulse1_width)) == -1) return -1; cycle_width = pulse0_width + pulse1_width; @@ -127,6 +128,7 @@ tape_sample_out(t, 0x00, TAPE_BIT0_LENGTH / 2); } rewrite_bit_count = (rewrite_bit_count + 1) & 7; + last_tape_output = 0; } static void tape_byte_out(struct tape *t, int byte) { @@ -185,6 +187,7 @@ long offset; for (;;) { + long start = tape_tell(t); int type = block_in(t, &sum, &offset, block); if (type == -1) return NULL; @@ -196,8 +199,8 @@ } if (type != 0 || block[1] < 15) continue; - f = g_malloc(sizeof(*f)); - f->offset = offset; + f = xmalloc(sizeof(*f)); + f->offset = start; memcpy(f->name, &block[2], 8); int i = 8; do { @@ -213,7 +216,7 @@ } } -void tape_seek_to_file(struct tape *t, struct tape_file *f) { +void tape_seek_to_file(struct tape *t, struct tape_file const *f) { if (!t || !f) return; tape_seek(t, f->offset, SEEK_SET); } @@ -221,21 +224,21 @@ /**************************************************************************/ struct tape *tape_new(void) { - struct tape *new = g_malloc0(sizeof(*new)); + struct tape *new = xzalloc(sizeof(*new)); return new; } void tape_free(struct tape *t) { - g_free(t); + free(t); } /**************************************************************************/ void tape_init(void) { - if (tape_update_audio.delegate) - tape_update_audio.delegate(tape_update_audio.dptr, 0.5); - event_init(&waggle_event, waggle_bit, NULL); - event_init(&flush_event, flush_output, NULL); + tape_update_audio = DELEGATE_DEFAULT1(void, float); + DELEGATE_CALL1(tape_update_audio, 0.5); + event_init(&waggle_event, DELEGATE_AS0(void, waggle_bit, NULL)); + event_init(&flush_event, DELEGATE_AS0(void, flush_output, NULL)); } void tape_reset(void) { @@ -293,7 +296,7 @@ tape_desync(256); tape_update_motor(motor); - LOG_DEBUG(2,"Attached virtual cassette '%s'\n", filename); + LOG_DEBUG(1, "Tape: Attached '%s' for reading\n", filename); return 0; } @@ -304,7 +307,6 @@ } int tape_open_writing(const char *filename) { - (void)filename; tape_close_writing(); int type = xroar_filetype_by_ext(filename); switch (type) { @@ -330,7 +332,7 @@ tape_update_motor(motor); rewrite_bit_count = 0; - LOG_DEBUG(2,"Attached virtual cassette '%s' for writing.\n", filename); + LOG_DEBUG(1, "Tape: Attached '%s' for writing.\n", filename); return 0; } @@ -362,7 +364,7 @@ return -1; } int type = f->type; - g_free(f); + free(f); switch (type) { case 0: keyboard_queue_basic("\003CLOAD\rRUN\r"); @@ -401,17 +403,20 @@ tape_desync(256); } } + if (motor != state) { + LOG_DEBUG(2, "Tape: motor %s\n", state ? "ON" : "OFF"); + } motor = state; set_breakpoints(); } /* Called whenever the DAC is written to. */ void tape_update_output(uint8_t value) { - if (!motor || !tape_output || tape_rewrite) - return; - int length = event_current_tick - tape_output->last_write_cycle; - tape_output->module->sample_out(tape_output, value, length); - tape_output->last_write_cycle = event_current_tick; + if (motor && tape_output && !tape_rewrite) { + int length = event_current_tick - tape_output->last_write_cycle; + tape_output->module->sample_out(tape_output, last_tape_output, length); + tape_output->last_write_cycle = event_current_tick; + } last_tape_output = value; } @@ -422,17 +427,14 @@ switch (in_pulse) { default: case -1: - if (tape_update_audio.delegate) - tape_update_audio.delegate(tape_update_audio.dptr, 0.5); + DELEGATE_CALL1(tape_update_audio, 0.5); event_dequeue(&waggle_event); return; case 0: - if (tape_update_audio.delegate) - tape_update_audio.delegate(tape_update_audio.dptr, 0.0); + DELEGATE_CALL1(tape_update_audio, 0.0); break; case 1: - if (tape_update_audio.delegate) - tape_update_audio.delegate(tape_update_audio.dptr, 1.0); + DELEGATE_CALL1(tape_update_audio, 1.0); break; } waggle_event.at_tick += in_pulse_width; @@ -462,8 +464,7 @@ pskip = 0; waggle_event.at_tick = event_current_tick + in_pulse_width; event_queue(&MACHINE_EVENT_LIST, &waggle_event); - if (tape_update_audio.delegate) - tape_update_audio.delegate(tape_update_audio.dptr, in_pulse ? 1.0 : 0.0); + DELEGATE_CALL1(tape_update_audio, in_pulse ? 1.0 : 0.0); return in_pulse; } pskip -= in_pulse_width; @@ -732,7 +733,6 @@ /* Leader padding & tape rewriting */ static void tape_desync(int leader) { - (void)leader; if (tape_rewrite) { /* complete last byte */ while (rewrite_bit_count) @@ -746,10 +746,9 @@ static void rewrite_sync(struct MC6809 *cpu) { /* BLKIN, having read sync byte $3C */ (void)cpu; - int i; if (rewrite_have_sync) return; if (tape_rewrite) { - for (i = 0; i < rewrite_leader_count; i++) + for (int i = 0; i < rewrite_leader_count; i++) tape_byte_out(tape_output, 0x55); tape_byte_out(tape_output, 0x3c); rewrite_have_sync = 1; diff -Nru xroar-0.31.1/src/tape_cas.c xroar-0.32/src/tape_cas.c --- xroar-0.31.1/src/tape_cas.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/tape_cas.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -24,7 +24,7 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "fs.h" #include "machine.h" @@ -53,10 +53,10 @@ }; static void cas_close(struct tape *t); -static long cas_tell(struct tape *t); +static long cas_tell(struct tape const *t); static int cas_seek(struct tape *t, long offset, int whence); -static int cas_to_ms(struct tape *t, long pos); -static long cas_ms_to(struct tape *t, int ms); +static int cas_to_ms(struct tape const *t, long pos); +static long cas_ms_to(struct tape const *t, int ms); static int cas_pulse_in(struct tape *t, int *pulse_width); static int cas_sample_out(struct tape *t, uint8_t sample, int length); static void cas_motor_off(struct tape *t); @@ -109,7 +109,7 @@ t = tape_new(); t->module = &tape_cas_module; - cas = g_malloc(sizeof(*cas)); + cas = xmalloc(sizeof(*cas)); t->data = cas; t->leader_count = 0; /* initialise cas */ @@ -125,8 +125,8 @@ * based on this */ if (!is_ascii) { int lb = fs_read_uint8(cas->fd); - int nb; if (lb == 0x55 || lb == 0xaa) { + int nb; do { t->leader_count++; nb = fs_read_uint8(cas->fd); @@ -164,7 +164,7 @@ struct tape_cas *cas = t->data; cas_motor_off(t); fclose(cas->fd); - g_free(cas); + free(cas); tape_free(t); } @@ -227,7 +227,7 @@ } /* measures in number of pulses */ -static long cas_tell(struct tape *t) { +static long cas_tell(struct tape const *t) { return t->offset; } @@ -269,12 +269,12 @@ } /* approximate time based on av. pulse length */ -static int cas_to_ms(struct tape *t, long pos) { +static int cas_to_ms(struct tape const *t, long pos) { (void)t; return (pos * 10) / 32; } -static long cas_ms_to(struct tape *t, int ms) { +static long cas_ms_to(struct tape const *t, int ms) { (void)t; return (ms * 32) / 10; } diff -Nru xroar-0.31.1/src/tape.h xroar-0.32/src/tape.h --- xroar-0.31.1/src/tape.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/tape.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -8,6 +8,7 @@ #include +#include "delegate.h" #include "events.h" #include "sam.h" @@ -29,15 +30,14 @@ }; struct tape_module { - void (*close)(struct tape *t); - long (*size)(struct tape *t); - long (*tell)(struct tape *t); - int (*seek)(struct tape *t, long offset, int whence); - int (*to_ms)(struct tape *t, long pos); - long (*ms_to)(struct tape *t, int ms); - int (*pulse_in)(struct tape *t, int *pulse_width); - int (*sample_out)(struct tape *t, uint8_t sample, int length); - void (*motor_off)(struct tape *t); + void (* const close)(struct tape *t); + long (* const tell)(struct tape const *t); + int (* const seek)(struct tape *t, long offset, int whence); + int (* const to_ms)(struct tape const *t, long pos); + long (* const ms_to)(struct tape const *t, int ms); + int (* const pulse_in)(struct tape *t, int *pulse_width); + int (* const sample_out)(struct tape *t, uint8_t sample, int length); + void (* const motor_off)(struct tape *t); }; extern struct tape *tape_input; @@ -68,7 +68,7 @@ /* find next tape file */ struct tape_file *tape_file_next(struct tape *t, int skip_bad); /* seek to a tape file */ -void tape_seek_to_file(struct tape *t, struct tape_file *f); +void tape_seek_to_file(struct tape *t, struct tape_file const *f); /* Module-specific open() calls */ struct tape *tape_cas_open(const char *filename, const char *mode); @@ -86,12 +86,7 @@ void tape_shutdown(void); /* Delegate for tape output updates */ -typedef struct { - void (*delegate)(void *, float value); - void *dptr; -} tape_audio_delegate; - -extern tape_audio_delegate tape_update_audio; +extern DELEGATE_T1(void, float) tape_update_audio; int tape_open_reading(const char *filename); void tape_close_reading(void); diff -Nru xroar-0.31.1/src/tape_sndfile.c xroar-0.32/src/tape_sndfile.c --- xroar-0.31.1/src/tape_sndfile.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/tape_sndfile.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -23,7 +23,7 @@ #include -#include "pl_glib.h" +#include "xalloc.h" #include "fs.h" #include "logging.h" @@ -44,10 +44,10 @@ }; static void sndfile_close(struct tape *t); -static long sndfile_tell(struct tape *t); +static long sndfile_tell(struct tape const *t); static int sndfile_seek(struct tape *t, long offset, int whence); -static int sndfile_to_ms(struct tape *t, long pos); -static long sndfile_ms_to(struct tape *t, int ms); +static int sndfile_to_ms(struct tape const *t, long pos); +static long sndfile_ms_to(struct tape const *t, int ms); static int sndfile_pulse_in(struct tape *t, int *pulse_width); static int sndfile_sample_out(struct tape *t, uint8_t sample, int length); static void sndfile_motor_off(struct tape *t); @@ -64,7 +64,7 @@ struct tape_sndfile *sndfile; t = tape_new(); t->module = &tape_sndfile_module; - sndfile = g_malloc(sizeof(*sndfile)); + sndfile = xmalloc(sizeof(*sndfile)); t->data = sndfile; /* initialise sndfile */ sndfile->info.format = 0; @@ -80,7 +80,7 @@ } if (!sndfile->fd) { LOG_WARN("libsndfile error: %s\n", sf_strerror(NULL)); - g_free(sndfile); + free(sndfile); tape_free(t); return NULL; } @@ -89,7 +89,7 @@ return NULL; } sndfile->cycles_per_frame = OSCILLATOR_RATE / sndfile->info.samplerate; - sndfile->block = g_malloc(BLOCK_LENGTH * sizeof(*sndfile->block) * sndfile->info.channels); + sndfile->block = xmalloc(BLOCK_LENGTH * sizeof(*sndfile->block) * sndfile->info.channels); sndfile->block_length = 0; sndfile->cursor = 0; /* find size */ @@ -106,13 +106,13 @@ static void sndfile_close(struct tape *t) { struct tape_sndfile *sndfile = t->data; sndfile_motor_off(t); - g_free(sndfile->block); + free(sndfile->block); sf_close(sndfile->fd); - g_free(sndfile); + free(sndfile); tape_free(t); } -static long sndfile_tell(struct tape *t) { +static long sndfile_tell(struct tape const *t) { return t->offset; } @@ -127,13 +127,13 @@ return 0; } -static int sndfile_to_ms(struct tape *t, long pos) { +static int sndfile_to_ms(struct tape const *t, long pos) { struct tape_sndfile *sndfile = t->data; float ms = (float)pos * 1000. / (float)sndfile->info.samplerate; return (int)ms; } -static long sndfile_ms_to(struct tape *t, int ms) { +static long sndfile_ms_to(struct tape const *t, int ms) { struct tape_sndfile *sndfile = t->data; float pos = (float)ms * (float)sndfile->info.samplerate / 1000.; return (long)pos; diff -Nru xroar-0.31.1/src/ui_null.c xroar-0.32/src/ui_null.c --- xroar-0.31.1/src/ui_null.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/ui_null.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -22,18 +22,18 @@ #include "module.h" -static char *filereq_noop(const char **extensions); +static char *filereq_noop(char const * const *extensions); FileReqModule filereq_null_module = { .common = { .name = "null", .description = "No file requester" }, .load_filename = filereq_noop, .save_filename = filereq_noop }; -static FileReqModule *null_filereq_module_list[] = { +static FileReqModule * const null_filereq_module_list[] = { &filereq_null_module, NULL }; extern VideoModule video_null_module; -static VideoModule *null_video_module_list[] = { +static VideoModule * const null_video_module_list[] = { &video_null_module, NULL }; @@ -42,7 +42,7 @@ .common = { .name = "null", .description = "No keyboard" }, }; -static KeyboardModule *null_keyboard_module_list[] = { +static KeyboardModule * const null_keyboard_module_list[] = { &keyboard_null_module, NULL }; @@ -56,7 +56,7 @@ /* */ -static char *filereq_noop(const char **extensions) { +static char *filereq_noop(char const * const *extensions) { (void)extensions; return NULL; } diff -Nru xroar-0.31.1/src/vdg_palette.c xroar-0.32/src/vdg_palette.c --- xroar-0.31.1/src/vdg_palette.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/vdg_palette.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -22,7 +22,7 @@ #include #include -#include "pl_glib.h" +#include "array.h" #include "vdg_palette.h" @@ -80,7 +80,7 @@ }; -static int num_palettes = G_N_ELEMENTS(palette_templates); +static int num_palettes = ARRAY_N_ELEMENTS(palette_templates); /**************************************************************************/ diff -Nru xroar-0.31.1/src/vdg_palette.h xroar-0.32/src/vdg_palette.h --- xroar-0.31.1/src/vdg_palette.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/vdg_palette.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/vdisk.c xroar-0.32/src/vdisk.c --- xroar-0.31.1/src/vdisk.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/vdisk.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -32,8 +32,9 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" +#include "array.h" #include "crc16.h" #include "fs.h" #include "logging.h" @@ -47,20 +48,21 @@ static struct vdisk *vdisk_load_vdk(const char *filename); static struct vdisk *vdisk_load_jvc(const char *filename); +static struct vdisk *vdisk_load_os9(const char *filename); static struct vdisk *vdisk_load_dmk(const char *filename); static int vdisk_save_vdk(struct vdisk *disk); static int vdisk_save_jvc(struct vdisk *disk); static int vdisk_save_dmk(struct vdisk *disk); static struct { - int filetype; - struct vdisk *(*load_func)(const char *); - int (*save_func)(struct vdisk *); -} dispatch[] = { + enum xroar_filetype filetype; + struct vdisk *(* const load_func)(const char *); + int (* const save_func)(struct vdisk *); +} const dispatch[] = { { FILETYPE_VDK, vdisk_load_vdk, vdisk_save_vdk }, { FILETYPE_JVC, vdisk_load_jvc, vdisk_save_jvc }, + { FILETYPE_OS9, vdisk_load_os9, vdisk_save_jvc }, { FILETYPE_DMK, vdisk_load_dmk, vdisk_save_dmk }, - { -1, NULL, NULL } }; struct vdisk *vdisk_blank_disk(unsigned ncyls, unsigned nheads, @@ -75,17 +77,20 @@ || track_length < 129 || track_length > 0x2940) { return NULL; } - if (!(disk = g_try_malloc(sizeof(*disk)))) + if (!(disk = malloc(sizeof(*disk)))) return NULL; - if (!(side_data = g_try_malloc0(nheads * sizeof(*side_data)))) + if (!(side_data = calloc(nheads, sizeof(*side_data)))) goto cleanup; unsigned side_length = ncyls * track_length; for (unsigned i = 0; i < nheads; i++) { - if (!(side_data[i] = g_try_malloc0(side_length))) + if (!(side_data[i] = calloc(side_length, 1))) goto cleanup_sides; } disk->filetype = FILETYPE_DMK; disk->filename = NULL; + disk->fmt.vdk.extra_length = 0; + disk->fmt.vdk.filename_length = 0; + disk->fmt.vdk.extra = NULL; disk->write_back = xroar_cfg.disk_write_back; disk->write_protect = 0; disk->num_cylinders = ncyls; @@ -96,26 +101,30 @@ cleanup_sides: for (unsigned i = 0; i < nheads; i++) { if (side_data[i]) - g_free(side_data[i]); + free(side_data[i]); } - g_free(side_data); + free(side_data); cleanup: - g_free(disk); + free(disk); return NULL; } void vdisk_destroy(struct vdisk *disk) { if (disk == NULL) return; if (disk->filename) { - g_free(disk->filename); + free(disk->filename); disk->filename = NULL; } + if (disk->fmt.vdk.extra) { + free(disk->fmt.vdk.extra); + disk->fmt.vdk.extra_length = 0; + } for (unsigned i = 0; i < disk->num_heads; i++) { if (disk->side_data[i]) - g_free(disk->side_data[i]); + free(disk->side_data[i]); } - g_free(disk->side_data); - g_free(disk); + free(disk->side_data); + free(disk); } struct vdisk *vdisk_load(const char *filename) { @@ -123,21 +132,21 @@ int i; if (filename == NULL) return NULL; filetype = xroar_filetype_by_ext(filename); - for (i = 0; dispatch[i].filetype >= 0 && dispatch[i].filetype != filetype; i++); - if (dispatch[i].load_func == NULL) { - LOG_WARN("No reader for virtual disk file type.\n"); - return NULL; + for (i = 0; i < ARRAY_N_ELEMENTS(dispatch); i++) { + if (dispatch[i].filetype == filetype) { + return dispatch[i].load_func(filename); + } } - return dispatch[i].load_func(filename); + LOG_WARN("No reader for virtual disk file type.\n"); + return NULL; } int vdisk_save(struct vdisk *disk, _Bool force) { - char *backup_filename; int i; if (!disk) return -1; if (!force && !disk->write_back) { - LOG_DEBUG(2, "Not saving disk file: write-back is disabled.\n"); + LOG_DEBUG(1, "Not saving disk file: write-back is disabled.\n"); // This is the requested behaviour, so success: return 0; } @@ -155,14 +164,12 @@ return -1; } int bf_len = strlen(disk->filename) + 5; - backup_filename = g_alloca(bf_len); + char backup_filename[bf_len]; // Rename old file to filename.bak if that .bak does not already exist - if (backup_filename != NULL) { - snprintf(backup_filename, bf_len, "%s.bak", disk->filename); - struct stat statbuf; - if (stat(backup_filename, &statbuf) != 0) { - rename(disk->filename, backup_filename); - } + snprintf(backup_filename, bf_len, "%s.bak", disk->filename); + struct stat statbuf; + if (stat(backup_filename, &statbuf) != 0) { + rename(disk->filename, backup_filename); } return dispatch[i].save_func(disk); } @@ -184,11 +191,11 @@ * [11] Compression flags (bits 0-2) and name length (bits 3-7) * PC-Dragon then reserves 31 bytes for a disk name, the number of significant - * characaters in which are indicated in the name length bitfield of byte 11. + * characters in which are indicated in the name length bitfield of byte 11. * * The only flag used by XRoar is bit 0 which indicates write protect. - * Compressed data in VDK disk images is not supported. XRoar will not write a - * disk name. + * Compressed data in VDK disk images is not supported. XRoar will store extra + * header bytes and rewrite them verbatim. */ static struct vdisk *vdisk_load_vdk(const char *filename) { @@ -200,6 +207,7 @@ unsigned nsectors = 18; unsigned ssize_code = 1, ssize; _Bool write_protect; + int vdk_filename_length; uint8_t buf[1024]; FILE *fd; struct stat statbuf; @@ -208,23 +216,40 @@ file_size = statbuf.st_size; if (!(fd = fopen(filename, "rb"))) return NULL; - fread(buf, 12, 1, fd); + if (fread(buf, 12, 1, fd) < 1) { + LOG_WARN("Failed to read VDK header in '%s'\n", filename); + fclose(fd); + return NULL; + } file_size -= 12; (void)file_size; // TODO: check this matches what's going to be read if (buf[0] != 'd' || buf[1] != 'k') { fclose(fd); return NULL; } + if ((buf[11] & 7) != 0) { + LOG_WARN("Compressed VDK not supported: '%s'\n", filename); + fclose(fd); + return NULL; + } header_size = (buf[2] | (buf[3]<<8)) - 12; ncyls = buf[8]; nheads = buf[9]; write_protect = buf[10] & 1; + vdk_filename_length = buf[11] >> 3; + uint8_t *vdk_extra = NULL; if (header_size > 0) { - if (header_size > sizeof(buf)) { + vdk_extra = malloc(header_size); + if (!vdk_extra) { + fclose(fd); + return NULL; + } + if (fread(vdk_extra, header_size, 1, fd) < 1) { + LOG_WARN("Failed to read VDK header in '%s'\n", filename); + free(vdk_extra); fclose(fd); return NULL; } - fread(buf, header_size, 1, fd); } ssize = 128 << ssize_code; disk = vdisk_blank_disk(ncyls, nheads, VDISK_LENGTH_5_25); @@ -233,19 +258,24 @@ return NULL; } disk->filetype = FILETYPE_VDK; - disk->filename = g_strdup(filename); + disk->filename = xstrdup(filename); disk->write_protect = write_protect; + disk->fmt.vdk.extra_length = header_size; + disk->fmt.vdk.filename_length = vdk_filename_length; + disk->fmt.vdk.extra = vdk_extra; if (vdisk_format_disk(disk, 1, nsectors, 1, ssize_code) != 0) { fclose(fd); vdisk_destroy(disk); return NULL; } - LOG_DEBUG(2,"Loading VDK virtual disk: %dC %dH %dS (%d-byte)\n", ncyls, nheads, nsectors, ssize); + LOG_DEBUG(1, "Loading VDK virtual disk: %uC %uH %uS (%u-byte)\n", ncyls, nheads, nsectors, ssize); for (unsigned cyl = 0; cyl < ncyls; cyl++) { for (unsigned head = 0; head < nheads; head++) { for (unsigned sector = 0; sector < nsectors; sector++) { - fread(buf, ssize, 1, fd); + if (fread(buf, ssize, 1, fd) < 1) { + memset(buf, 0, ssize); + } vdisk_update_sector(disk, cyl, head, sector + 1, ssize, buf); } } @@ -261,11 +291,10 @@ return -1; if (!(fd = fopen(disk->filename, "wb"))) return -1; - LOG_DEBUG(2,"Writing VDK virtual disk: %dC %dH (%d-byte)\n", disk->num_cylinders, disk->num_heads, disk->track_length); + LOG_DEBUG(1, "Writing VDK virtual disk: %uC %uH (%u-byte)\n", disk->num_cylinders, disk->num_heads, disk->track_length); + uint16_t header_length = 12; buf[0] = 'd'; // magic buf[1] = 'k'; // magic - buf[2] = 12; // header size LSB - buf[3] = 0; // header size MSB buf[4] = 0x10; // VDK version buf[5] = 0x10; // VDK backwards compatibility version buf[6] = 'X'; // file source - 'X' for XRoar @@ -273,8 +302,15 @@ buf[8] = disk->num_cylinders; buf[9] = disk->num_heads; buf[10] = 0; // flags - buf[11] = 0; // name length & compression flag (we write neither) + buf[11] = disk->fmt.vdk.filename_length << 3; // name length & compression flag + if (disk->fmt.vdk.extra_length > 0) + header_length += disk->fmt.vdk.extra_length; + buf[2] = header_length & 0xff; + buf[3] = header_length >> 8; fwrite(buf, 12, 1, fd); + if (disk->fmt.vdk.extra_length > 0) { + fwrite(disk->fmt.vdk.extra, disk->fmt.vdk.extra_length, 1, fd); + } for (unsigned cyl = 0; cyl < disk->num_cylinders; cyl++) { for (unsigned head = 0; head < disk->num_heads; head++) { for (unsigned sector = 0; sector < 18; sector++) { @@ -325,69 +361,99 @@ * of the track as is available. * * Some images seen in the wild are double-sided without containing header - * information. If started with the "-disk-jvc-hack" option, XRoar will - * identify any headerless disk that appears to be longer than 43 track - * single-sided as double-sided instead. + * information. If it looks like such an image contains an OS-9 filesystem, + * XRoar will try and extract geometry information from the first sector. This + * can be disabled with the "-no-disk-auto-os9" option, but if the filename + * ends in ".os9", the check is performed regardless. */ -static const uint8_t jvc_defaults[] = { 18, 1, 1, 1, 0 }; +static uint8_t const jvc_defaults[] = { 18, 1, 1, 1, 0 }; -static struct vdisk *vdisk_load_jvc(const char *filename) { - struct vdisk *disk; - ssize_t file_size; - unsigned header_size; - unsigned ncyls; - unsigned nheads = 1; +static struct vdisk *do_load_jvc(const char *filename, _Bool auto_os9) { unsigned nsectors = 18; - unsigned ssize_code = 1, ssize; + unsigned nheads = 1; + unsigned ssize_code = 1; unsigned first_sector = 1; _Bool sector_attr_flag = 0; + _Bool headerless_os9 = 0; + uint8_t buf[1024]; FILE *fd; struct stat statbuf; if (stat(filename, &statbuf) != 0) return NULL; - file_size = statbuf.st_size; - header_size = file_size % 128; + off_t file_size = statbuf.st_size; + unsigned header_size = file_size % 128; file_size -= header_size; if (!(fd = fopen(filename, "rb"))) return NULL; - memcpy(buf, jvc_defaults, sizeof(jvc_defaults)); - if (xroar_cfg.disk_jvc_hack && file_size > 198144) - buf[1] = 2; - if (header_size > 0) - fread(buf, header_size, 1, fd); - nsectors = buf[0]; - nheads = buf[1]; - ssize_code = buf[2] & 3; - first_sector = buf[3]; - sector_attr_flag = buf[4]; + if (header_size > 0) { + if (fread(buf, header_size, 1, fd) < 1) { + LOG_WARN("Failed to read JVC header in '%s'\n", filename); + fclose(fd); + return NULL; + } + nsectors = buf[0]; + if (header_size >= 2) + nheads = buf[1]; + if (header_size >= 3) + ssize_code = buf[2] & 3; + if (header_size >= 4) + first_sector = buf[3]; + if (header_size >= 5) + sector_attr_flag = buf[4]; + } else if (auto_os9) { + /* read first sector & check it makes sense */ + if (fread(buf + 256, 256, 1, fd) < 1) { + LOG_WARN("Failed to read from JVC '%s'\n", filename); + fclose(fd); + return NULL; + } + unsigned dd_tot = (buf[0x100+0] << 16) | (buf[0x100+1] << 8) | buf[0x100+2]; + off_t os9_file_size = dd_tot * 256; + unsigned dd_tks = buf[0x100+0x03]; + uint8_t dd_fmt = buf[0x100+0x10]; + unsigned dd_fmt_sides = (dd_fmt & 1) + 1; + unsigned dd_spt = (buf[0x100+0x11] << 8) | buf[0x100+0x12]; + + if (os9_file_size >= file_size && dd_tks == dd_spt) { + nsectors = dd_tks; + nheads = dd_fmt_sides; + headerless_os9 = 1; + } + fseek(fd, 0, SEEK_SET); + } - ssize = 128 << ssize_code; + unsigned ssize = 128 << ssize_code; unsigned bytes_per_sector = ssize + sector_attr_flag; unsigned bytes_per_cyl = nsectors * bytes_per_sector * nheads; - ncyls = file_size / bytes_per_cyl; + unsigned ncyls = file_size / bytes_per_cyl; // if there is at least one more sector of data, allow an extra track if ((file_size % bytes_per_cyl) >= bytes_per_sector) { ncyls++; } - disk = vdisk_blank_disk(ncyls, nheads, VDISK_LENGTH_5_25); + struct vdisk *disk = vdisk_blank_disk(ncyls, nheads, VDISK_LENGTH_5_25); if (!disk) { fclose(fd); return NULL; } disk->filetype = FILETYPE_JVC; - disk->filename = g_strdup(filename); + disk->filename = xstrdup(filename); + disk->fmt.jvc.headerless_os9 = headerless_os9; if (vdisk_format_disk(disk, 1, nsectors, first_sector, ssize_code) != 0) { fclose(fd); vdisk_destroy(disk); return NULL; } - LOG_DEBUG(2,"Loading JVC virtual disk: %dC %dH %dS (%d-byte)\n", ncyls, nheads, nsectors, ssize); + if (headerless_os9) { + LOG_DEBUG(1, "Loading headerless OS-9 virtual disk: %uC %uH %uS (%u-byte)\n", ncyls, nheads, nsectors, ssize); + } else { + LOG_DEBUG(1, "Loading JVC virtual disk: %uC %uH %uS (%u-byte)\n", ncyls, nheads, nsectors, ssize); + } for (unsigned cyl = 0; cyl < ncyls; cyl++) { for (unsigned head = 0; head < nheads; head++) { for (unsigned sector = 0; sector < nsectors; sector++) { @@ -407,6 +473,14 @@ return disk; } +static struct vdisk *vdisk_load_jvc(const char *filename) { + return do_load_jvc(filename, xroar_cfg.disk_auto_os9); +} + +static struct vdisk *vdisk_load_os9(const char *filename) { + return do_load_jvc(filename, 1); +} + static int vdisk_save_jvc(struct vdisk *disk) { unsigned nsectors = 18; uint8_t buf[1024]; @@ -415,7 +489,7 @@ return -1; if (!(fd = fopen(disk->filename, "wb"))) return -1; - LOG_DEBUG(2,"Writing JVC virtual disk: %dC %dH (%d-byte)\n", disk->num_cylinders, disk->num_heads, disk->track_length); + LOG_DEBUG(1, "Writing JVC virtual disk: %uC %uH (%u-byte)\n", disk->num_cylinders, disk->num_heads, disk->track_length); // TODO: scan the disk to potentially correct these assumptions buf[0] = nsectors; // assumed @@ -424,8 +498,9 @@ buf[3] = 1; // assumed first sector == 1 buf[4] = 0; + // don't write a header if OS-9 detection didn't find one unsigned header_size = 0; - if (disk->num_heads != 1) + if (disk->num_heads != 1 && !disk->fmt.jvc.headerless_os9) header_size = 2; if (header_size > 0) { @@ -491,7 +566,11 @@ if (!(fd = fopen(filename, "rb"))) return NULL; - fread(header, 16, 1, fd); + if (fread(header, 16, 1, fd) < 1) { + LOG_WARN("Failed to read DMK header in '%s'\n", filename); + fclose(fd); + return NULL; + } ncyls = header[1]; track_length = (header[3] << 8) | header[2]; // yes, little-endian! nheads = (header[4] & 0x10) ? 1 : 2; @@ -506,9 +585,9 @@ fclose(fd); return NULL; } - LOG_DEBUG(2,"Loading DMK virtual disk: %dC %dH (%d-byte)\n", ncyls, nheads, track_length); + LOG_DEBUG(1, "Loading DMK virtual disk: %uC %uH (%u-byte)\n", ncyls, nheads, track_length); disk->filetype = FILETYPE_DMK; - disk->filename = g_strdup(filename); + disk->filename = xstrdup(filename); disk->write_back = header[0] ? 0 : 1; if (header[11] == 0 || header[11] == 0xff) { disk->write_protect = header[11] ? 1 : 0; @@ -527,7 +606,9 @@ for (unsigned i = 0; i < 64; i++) { idams[i] = fs_read_uint16_le(fd); } - fread(buf, track_length - 128, 1, fd); + if (fread(buf, track_length - 128, 1, fd) < 1) { + memset(buf, 0, track_length - 128); + } } } fclose(fd); @@ -541,7 +622,7 @@ return -1; if (!(fd = fopen(disk->filename, "wb"))) return -1; - LOG_DEBUG(2,"Writing DMK virtual disk: %dC %dH (%d-byte)\n", disk->num_cylinders, disk->num_heads, disk->track_length); + LOG_DEBUG(1, "Writing DMK virtual disk: %uC %uH (%u-byte)\n", disk->num_cylinders, disk->num_heads, disk->track_length); memset(header, 0, sizeof(header)); if (!disk->write_back) header[0] = 0xff; @@ -575,7 +656,7 @@ * (void *) because track data is manipulated in 8-bit and 16-bit chunks. */ -void *vdisk_track_base(struct vdisk *disk, unsigned cyl, unsigned head) { +void *vdisk_track_base(struct vdisk const *disk, unsigned cyl, unsigned head) { if (disk == NULL || head >= disk->num_heads || cyl >= disk->num_cylinders) { return NULL; } @@ -623,7 +704,7 @@ if (ncyls > disk->num_cylinders) { // Allocate and clear new tracks for (unsigned s = 0; s < disk->num_heads; s++) { - uint8_t *new_side = g_realloc(side_data[s], ncyls * tlength); + uint8_t *new_side = xrealloc(side_data[s], ncyls * tlength); if (!new_side) return NULL; side_data[s] = new_side; @@ -636,13 +717,13 @@ } if (nheads > disk->num_heads) { // Increase size of side_data array - side_data = g_realloc(side_data, nheads * sizeof(*side_data)); + side_data = xrealloc(side_data, nheads * sizeof(*side_data)); if (!side_data) return NULL; disk->side_data = side_data; // Allocate new empty side data for (unsigned s = disk->num_heads; s < nheads; s++) { - side_data[s] = g_try_malloc0(ncyls * tlength); + side_data[s] = calloc(ncyls, tlength); if (!side_data[s]) return NULL; } @@ -794,7 +875,7 @@ * Similarly, locate a sector and copy out its data. */ -int vdisk_fetch_sector(struct vdisk *disk, unsigned cyl, unsigned head, +int vdisk_fetch_sector(struct vdisk const *disk, unsigned cyl, unsigned head, unsigned sector, unsigned sector_length, uint8_t *buf) { uint8_t *data; uint16_t *idams; diff -Nru xroar-0.31.1/src/vdisk.h xroar-0.32/src/vdisk.h --- xroar-0.31.1/src/vdisk.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/vdisk.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -34,6 +34,17 @@ unsigned num_heads; unsigned track_length; uint8_t **side_data; + /* format specific data, kept only for use when rewriting: */ + union { + struct { + int extra_length; + int filename_length; + uint8_t *extra; + } vdk; + struct { + _Bool headerless_os9; + } jvc; + } fmt; }; struct vdisk *vdisk_blank_disk(unsigned ncyls, unsigned nheads, @@ -50,7 +61,7 @@ * currently configured values. NULL return indicates error. */ -void *vdisk_track_base(struct vdisk *disk, unsigned cyl, unsigned head); +void *vdisk_track_base(struct vdisk const *disk, unsigned cyl, unsigned head); void *vdisk_extend_disk(struct vdisk *disk, unsigned cyl, unsigned head); int vdisk_format_track(struct vdisk *disk, _Bool double_density, @@ -60,7 +71,7 @@ unsigned nsectors, unsigned first_sector, unsigned ssize_code); int vdisk_update_sector(struct vdisk *disk, unsigned cyl, unsigned head, unsigned sector, unsigned sector_length, uint8_t *buf); -int vdisk_fetch_sector(struct vdisk *disk, unsigned cyl, unsigned head, +int vdisk_fetch_sector(struct vdisk const *disk, unsigned cyl, unsigned head, unsigned sector, unsigned sector_length, uint8_t *buf); #endif /* XROAR_VDISK_H_ */ diff -Nru xroar-0.31.1/src/vdrive.c xroar-0.32/src/vdrive.c --- xroar-0.31.1/src/vdrive.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/vdrive.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -36,15 +36,18 @@ #define MAX_TRACKS (256) struct drive_data { - _Bool disk_present; struct vdisk *disk; unsigned current_cyl; }; -_Bool vdrive_ready = 0; -_Bool vdrive_tr00 = 1; -_Bool vdrive_index_pulse = 0; -_Bool vdrive_write_protect = 0; +DELEGATE_T1(void,bool) vdrive_ready; +static _Bool ready_state = 0; +DELEGATE_T1(void,bool) vdrive_tr00; +static _Bool tr00_state = 1; +DELEGATE_T1(void,bool) vdrive_index_pulse; +static _Bool index_state = 0; +DELEGATE_T1(void,bool) vdrive_write_protect; +static _Bool write_protect_state = 0; void (*vdrive_update_drive_cyl_head)(unsigned drive, unsigned cyl, unsigned head) = NULL; static struct drive_data drives[MAX_DRIVES]; @@ -58,6 +61,10 @@ static uint16_t *idamptr = NULL; // likewise, but different data size static unsigned head_pos = 0; // index into current track for read/write +static void set_ready_state(_Bool state); +static void set_tr00_state(_Bool state); +static void set_index_state(_Bool state); +static void set_write_protect_state(_Bool state); static void update_signals(void); static event_ticks last_update_cycle; @@ -70,50 +77,55 @@ void vdrive_init(void) { for (unsigned i = 0; i < MAX_DRIVES; i++) { drives[i].disk = NULL; - drives[i].disk_present = 0; drives[i].current_cyl = 0; } - vdrive_set_dden(1); + vdrive_ready = DELEGATE_DEFAULT1(void, bool); + vdrive_tr00 = DELEGATE_DEFAULT1(void, bool); + vdrive_index_pulse = DELEGATE_DEFAULT1(void, bool); + vdrive_set_dden(NULL, 1); vdrive_set_drive(0); - event_init(&index_pulse_event, do_index_pulse, NULL); - event_init(&reset_index_pulse_event, do_reset_index_pulse, NULL); + event_init(&index_pulse_event, DELEGATE_AS0(void, do_index_pulse, NULL)); + event_init(&reset_index_pulse_event, DELEGATE_AS0(void, do_reset_index_pulse, NULL)); } void vdrive_shutdown(void) { for (unsigned i = 0; i < MAX_DRIVES; i++) { - if (drives[i].disk != NULL && drives[i].disk_present) { + if (drives[i].disk) { vdrive_eject_disk(i); } } } +void vdrive_update_connection(void) { + DELEGATE_CALL1(vdrive_ready, ready_state); + DELEGATE_CALL1(vdrive_tr00, tr00_state); + DELEGATE_CALL1(vdrive_index_pulse, index_state); + DELEGATE_CALL1(vdrive_write_protect, write_protect_state); +} + void vdrive_insert_disk(unsigned drive, struct vdisk *disk) { assert(drive < MAX_DRIVES); - if (drives[drive].disk_present) { + if (drives[drive].disk) { vdrive_eject_disk(drive); } if (disk == NULL) return; drives[drive].disk = disk; - drives[drive].disk_present = 1; update_signals(); } void vdrive_eject_disk(unsigned drive) { assert(drive < MAX_DRIVES); - if (!drives[drive].disk_present) + if (!drives[drive].disk) return; vdisk_save(drives[drive].disk, 0); vdisk_destroy(drives[drive].disk); drives[drive].disk = NULL; - drives[drive].disk_present = 0; update_signals(); } struct vdisk *vdrive_disk_in_drive(unsigned drive) { assert(drive < MAX_DRIVES); - if (!drives[drive].disk_present) - return NULL; return drives[drive].disk; } @@ -150,34 +162,66 @@ } /* Lines from controller sent to all drives */ -void vdrive_set_direction(int direction) { +void vdrive_set_dirc(void *sptr, int direction) { + (void)sptr; cur_direction = (direction > 0) ? 1 : -1; } -void vdrive_set_head(unsigned head) { - if (head >= MAX_SIDES) return; +void vdrive_set_dden(void *sptr, _Bool dden) { + (void)sptr; + cur_density = dden ? VDISK_DOUBLE_DENSITY : VDISK_SINGLE_DENSITY; + head_incr = dden ? 1 : 2; +} + +void vdrive_set_sso(void *sptr, unsigned head) { + (void)sptr; + if (head >= MAX_SIDES) + return; cur_head = head; update_signals(); } -void vdrive_set_dden(_Bool dden) { - cur_density = dden ? VDISK_DOUBLE_DENSITY : VDISK_SINGLE_DENSITY; - head_incr = dden ? 1 : 2; +static void set_ready_state(_Bool state) { + if (ready_state == state) + return; + ready_state = state; + DELEGATE_CALL1(vdrive_ready, state); +} + +static void set_tr00_state(_Bool state) { + if (tr00_state == state) + return; + tr00_state = state; + DELEGATE_CALL1(vdrive_tr00, state); +} + +static void set_index_state(_Bool state) { + if (index_state == state) + return; + index_state = state; + DELEGATE_CALL1(vdrive_index_pulse, state); +} + +static void set_write_protect_state(_Bool state) { + if (write_protect_state == state) + return; + write_protect_state = state; + DELEGATE_CALL1(vdrive_write_protect, state); } static void update_signals(void) { - vdrive_ready = current_drive->disk_present; - vdrive_tr00 = (current_drive->current_cyl == 0); + set_ready_state(current_drive->disk != NULL); + set_tr00_state(current_drive->current_cyl == 0); if (vdrive_update_drive_cyl_head) { vdrive_update_drive_cyl_head(cur_drive_number, current_drive->current_cyl, cur_head); } - if (!vdrive_ready) { - vdrive_write_protect = 0; + if (!ready_state) { + set_write_protect_state(0); track_base = NULL; idamptr = NULL; return; } - vdrive_write_protect = current_drive->disk->write_protect; + set_write_protect_state(current_drive->disk->write_protect); if (cur_head < current_drive->disk->num_heads) { idamptr = vdisk_track_base(current_drive->disk, current_drive->current_cyl, cur_head); } else { @@ -202,7 +246,7 @@ /* Drive-specific actions */ void vdrive_step(void) { - if (vdrive_ready) { + if (ready_state) { if (cur_direction > 0 || current_drive->current_cyl > 0) current_drive->current_cyl += cur_direction; if (current_drive->current_cyl >= MAX_TRACKS) @@ -224,7 +268,7 @@ } void vdrive_write(uint8_t data) { - if (!vdrive_ready) return; + if (!ready_state) return; if (!track_base) { idamptr = vdisk_extend_disk(current_drive->disk, current_drive->current_cyl, cur_head); track_base = (uint8_t *)idamptr; @@ -242,27 +286,27 @@ head_pos++; } if (head_pos >= current_drive->disk->track_length) { - vdrive_index_pulse = 1; + set_index_state(1); } } void vdrive_skip(void) { - if (!vdrive_ready) return; + if (!ready_state) return; head_pos += head_incr; if (head_pos >= current_drive->disk->track_length) { - vdrive_index_pulse = 1; + set_index_state(1); } } uint8_t vdrive_read(void) { uint8_t ret = 0; - if (!vdrive_ready) return 0; + if (!ready_state) return 0; if (track_base && head_pos < current_drive->disk->track_length) { ret = track_base[head_pos] & 0xff; } head_pos += head_incr; if (head_pos >= current_drive->disk->track_length) { - vdrive_index_pulse = 1; + set_index_state(1); } return ret; } @@ -290,7 +334,7 @@ } head_pos += head_incr; if (head_pos >= current_drive->disk->track_length) { - vdrive_index_pulse = 1; + set_index_state(1); } } @@ -298,7 +342,7 @@ event_ticks next_cycle = track_start_cycle + (head_pos - 128) * BYTE_TIME; unsigned to_time = next_cycle - event_current_tick; if (to_time > (UINT_MAX/2)) { - LOG_DEBUG(4, "Negative time to next byte!\n"); + LOG_DEBUG(3, "Negative time to next byte!\n"); return 1; } return to_time + 1; @@ -309,10 +353,9 @@ unsigned vdrive_time_to_next_idam(void) { event_ticks next_cycle; - if (!vdrive_ready) return OSCILLATOR_RATE / 5; + if (!ready_state) return OSCILLATOR_RATE / 5; /* Update head_pos based on time elapsed since track start */ head_pos = 128 + ((event_current_tick - track_start_cycle) / BYTE_TIME); - (void)vdrive_new_index_pulse(); unsigned next_head_pos = current_drive->disk->track_length; if (idamptr) { for (unsigned i = 0; i < 64; i++) { @@ -328,7 +371,7 @@ next_cycle = track_start_cycle + (next_head_pos - 128) * BYTE_TIME; unsigned to_time = next_cycle - event_current_tick; if (to_time > (UINT_MAX/2)) { - LOG_DEBUG(4, "Negative time to next IDAM!\n"); + LOG_DEBUG(3, "Negative time to next IDAM!\n"); return 1; } return to_time + 1; @@ -340,7 +383,7 @@ uint8_t *vdrive_next_idam(void) { unsigned next_head_pos; - if (!vdrive_ready) return NULL; + if (!ready_state) return NULL; next_head_pos = current_drive->disk->track_length; if (idamptr) { for (unsigned i = 0; i < 64; i++) { @@ -352,28 +395,20 @@ } } if (next_head_pos >= current_drive->disk->track_length) { - vdrive_index_pulse = 1; + set_index_state(1); return NULL; } head_pos = next_head_pos; return track_base + next_head_pos; } -/* Returns 1 on active transition of index pulse */ -_Bool vdrive_new_index_pulse(void) { - static _Bool last_index_pulse = 0; - _Bool last = last_index_pulse; - last_index_pulse = vdrive_index_pulse; - return (!last && vdrive_index_pulse); -} - static void do_index_pulse(void *data) { (void)data; - if (!vdrive_ready) { - vdrive_index_pulse = 0; + if (!ready_state) { + set_index_state(0); return; } - vdrive_index_pulse = 1; + set_index_state(1); head_pos = 128; last_update_cycle = index_pulse_event.at_tick; track_start_cycle = index_pulse_event.at_tick; @@ -385,7 +420,5 @@ static void do_reset_index_pulse(void *data) { (void)data; - vdrive_index_pulse = 0; - /* reset latch */ - (void)vdrive_new_index_pulse(); + set_index_state(0); } diff -Nru xroar-0.31.1/src/vdrive.h xroar-0.32/src/vdrive.h --- xroar-0.31.1/src/vdrive.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/vdrive.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -10,19 +10,23 @@ #include +#include "delegate.h" + struct vdisk; #define VDRIVE_MAX_DRIVES (4) -extern _Bool vdrive_ready; -extern _Bool vdrive_tr00; -extern _Bool vdrive_index_pulse; -extern _Bool vdrive_write_protect; +extern DELEGATE_T1(void,bool) vdrive_ready; +extern DELEGATE_T1(void,bool) vdrive_tr00; +extern DELEGATE_T1(void,bool) vdrive_index_pulse; +extern DELEGATE_T1(void,bool) vdrive_write_protect; extern void (*vdrive_update_drive_cyl_head)(unsigned drive, unsigned cyl, unsigned head); void vdrive_init(void); void vdrive_shutdown(void); +void vdrive_update_connection(void); + void vdrive_insert_disk(unsigned drive, struct vdisk *disk); void vdrive_eject_disk(unsigned drive); struct vdisk *vdrive_disk_in_drive(unsigned drive); @@ -32,9 +36,9 @@ unsigned vdrive_head_pos(void); /* Lines from controller sent to all drives */ -void vdrive_set_direction(int direction); -void vdrive_set_head(unsigned head); -void vdrive_set_dden(_Bool dden); +void vdrive_set_dirc(void *, int); +void vdrive_set_dden(void *, _Bool); +void vdrive_set_sso(void *, unsigned); /* Drive select */ void vdrive_set_drive(unsigned drive); @@ -45,7 +49,6 @@ void vdrive_skip(void); uint8_t vdrive_read(void); void vdrive_write_idam(void); -_Bool vdrive_new_index_pulse(void); /* Has there been one? */ unsigned vdrive_time_to_next_byte(void); unsigned vdrive_time_to_next_idam(void); uint8_t *vdrive_next_idam(void); diff -Nru xroar-0.31.1/src/vo_generic_ops.c xroar-0.32/src/vo_generic_ops.c --- xroar-0.31.1/src/vo_generic_ops.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/vo_generic_ops.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -127,7 +127,7 @@ } /* Render colour line using palette */ -static void render_scanline(uint8_t *scanline_data) { +static void render_scanline(uint8_t const *scanline_data) { if (video_module->scanline >= video_module->window_y && video_module->scanline < (video_module->window_y + video_module->window_h)) { scanline_data += video_module->window_x; @@ -143,7 +143,7 @@ } /* Render artifacted colours - simple 4-colour lookup */ -static void render_ccr_simple(uint8_t *scanline_data) { +static void render_ccr_simple(uint8_t const *scanline_data) { if (video_module->scanline >= video_module->window_y && video_module->scanline < (video_module->window_y + video_module->window_h)) { int phase = xroar_machine_config->cross_colour_phase - 1; @@ -169,7 +169,7 @@ } /* Render artifacted colours - 5-bit lookup table */ -static void render_ccr_5bit(uint8_t *scanline_data) { +static void render_ccr_5bit(uint8_t const *scanline_data) { if (video_module->scanline >= video_module->window_y && video_module->scanline < (video_module->window_y + video_module->window_h)) { int phase = xroar_machine_config->cross_colour_phase - 1; diff -Nru xroar-0.31.1/src/vo_null.c xroar-0.32/src/vo_null.c --- xroar-0.31.1/src/vo_null.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/vo_null.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -23,7 +23,7 @@ #include "module.h" static void no_op(void); -static void no_op_render(uint8_t *); +static void no_op_render(uint8_t const *); VideoModule video_null_module = { .common = { .name = "null", .description = "No video" }, @@ -34,6 +34,6 @@ static void no_op(void) { } -static void no_op_render(uint8_t *scanline_data) { +static void no_op_render(uint8_t const *scanline_data) { (void)scanline_data; } diff -Nru xroar-0.31.1/src/vo_opengl.c xroar-0.32/src/vo_opengl.c --- xroar-0.31.1/src/vo_opengl.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/vo_opengl.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -33,7 +33,7 @@ # include #endif -#include "pl_glib.h" +#include "xalloc.h" #ifdef WINDOWS32 #include "windows32/common_windows32.h" @@ -90,7 +90,7 @@ }; _Bool vo_opengl_init(void) { - screen_tex = g_malloc(320 * 240 * sizeof(Pixel)); + screen_tex = xmalloc(320 * 240 * sizeof(Pixel)); window_width = 640; window_height = 480; vo_opengl_x = vo_opengl_y = 0; @@ -119,7 +119,7 @@ void vo_opengl_shutdown(void) { glDeleteTextures(1, &texnum); - g_free(screen_tex); + free(screen_tex); } void vo_opengl_alloc_colours(void) { @@ -213,7 +213,7 @@ video_module->scanline = 0; } -void vo_opengl_render_scanline(uint8_t *scanline_data) { +void vo_opengl_render_scanline(uint8_t const *scanline_data) { render_scanline(scanline_data); } diff -Nru xroar-0.31.1/src/vo_opengl.h xroar-0.32/src/vo_opengl.h --- xroar-0.31.1/src/vo_opengl.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/vo_opengl.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -20,7 +20,7 @@ void vo_opengl_refresh(void); void vo_opengl_vsync(void); void vo_opengl_set_window_size(unsigned w, unsigned h); -void vo_opengl_render_scanline(uint8_t *scanline_data); +void vo_opengl_render_scanline(uint8_t const *scanline_data); void vo_opengl_update_cross_colour_phase(void); #endif /* XROAR_VO_OPENGL_H_ */ diff -Nru xroar-0.31.1/src/wd279x.c xroar-0.32/src/wd279x.c --- xroar-0.31.1/src/wd279x.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/wd279x.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -28,7 +28,7 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "crc16.h" #include "events.h" @@ -58,21 +58,17 @@ #define SET_DRQ do { \ fdc->status_register |= STATUS_DRQ; \ - if (fdc->set_drq_handler) \ - fdc->set_drq_handler(fdc->drq_data); \ + DELEGATE_CALL1(fdc->set_drq, 1); \ } while (0) #define RESET_DRQ do { \ fdc->status_register &= ~(STATUS_DRQ); \ - if (fdc->reset_drq_handler) \ - fdc->reset_drq_handler(fdc->drq_data); \ + DELEGATE_CALL1(fdc->set_drq, 0); \ } while (0) #define SET_INTRQ do { \ - if (fdc->set_intrq_handler) \ - fdc->set_intrq_handler(fdc->intrq_data); \ + DELEGATE_CALL1(fdc->set_intrq, 1); \ } while (0) #define RESET_INTRQ do { \ - if (fdc->reset_intrq_handler) \ - fdc->reset_intrq_handler(fdc->intrq_data); \ + DELEGATE_CALL1(fdc->set_intrq, 0); \ } while (0) #define NEXT_STATE(f,t) do { \ @@ -85,20 +81,20 @@ #define IS_DOUBLE_DENSITY (fdc->double_density) #define IS_SINGLE_DENSITY (!fdc->double_density) -#define SET_DIRECTION do { fdc->direction = 1; vdrive_set_direction(1); } while (0) +#define SET_DIRECTION do { fdc->direction = 1; DELEGATE_CALL1(fdc->set_dirc, 1); } while (0) #define RESET_DIRECTION do { \ - fdc->direction = -1; vdrive_set_direction(-1); \ + fdc->direction = -1; DELEGATE_CALL1(fdc->set_dirc, -1); \ } while (0) #define SET_SIDE(s) do { \ fdc->side = (s) ? 1 : 0; \ if (fdc->has_sso) \ - vdrive_set_head(fdc->side); \ + DELEGATE_CALL1(fdc->set_sso, fdc->side); \ } while (0) -static void state_machine(WD279X *fdc); +static void state_machine(void *); -static int stepping_rate[4] = { 6, 12, 20, 30 }; -static int sector_size[2][4] = { +static int const stepping_rate[4] = { 6, 12, 20, 30 }; +static int const sector_size[2][4] = { { 256, 512, 1024, 128 }, { 128, 256, 512, 1024 } }; @@ -135,17 +131,18 @@ fdc->type = type; fdc->has_sso = (type == WD2795 || type == WD2797); fdc->has_length_flag = (type == WD2795 || type == WD2797); - fdc->has_inverted_data = (type == WD2791 || type == WD2795); - fdc->set_drq_handler = NULL; - fdc->reset_drq_handler = NULL; - fdc->set_intrq_handler = NULL; - fdc->reset_intrq_handler = NULL; + fdc->invert_data = (type == WD2791 || type == WD2795) ? 0xff : 0; + fdc->set_dirc = DELEGATE_DEFAULT1(void, int); + fdc->set_dden = DELEGATE_DEFAULT1(void, bool); + fdc->set_sso = DELEGATE_DEFAULT1(void, unsigned); + fdc->set_drq = DELEGATE_DEFAULT1(void, bool); + fdc->set_intrq = DELEGATE_DEFAULT1(void, bool); fdc->state = WD279X_state_accept_command; - event_init(&fdc->state_event, (event_delegate)state_machine, fdc); + event_init(&fdc->state_event, DELEGATE_AS0(void, state_machine, fdc)); } WD279X *wd279x_new(enum WD279X_type type) { - WD279X *new = g_malloc(sizeof(WD279X)); + WD279X *new = xmalloc(sizeof(WD279X)); wd279x_init(new, type); return new; } @@ -157,7 +154,7 @@ void wd279x_free(WD279X *fdc) { assert(fdc != NULL); wd279x_deinit(fdc); - g_free(fdc); + free(fdc); } void wd279x_reset(WD279X *fdc) { @@ -172,9 +169,59 @@ SET_SIDE(0); } +void wd279x_ready(void *sptr, _Bool state) { + WD279X *fdc = sptr; + if (fdc->ready_state == state) + return; + fdc->ready_state = state; + if (state && fdc->intrq_nready_to_ready) { + event_dequeue(&fdc->state_event); + SET_INTRQ; + } + if (!state && fdc->intrq_ready_to_nready) { + event_dequeue(&fdc->state_event); + SET_INTRQ; + } +} + +void wd279x_tr00(void *sptr, _Bool state) { + WD279X *fdc = sptr; + if (fdc->tr00_state == state) + return; + fdc->tr00_state = state; +} + +void wd279x_index_pulse(void *sptr, _Bool state) { + WD279X *fdc = sptr; + if (fdc->index_state == state) + return; + fdc->index_state = state; + if (state) { + fdc->index_holes_count++; + if (fdc->intrq_index_pulse) { + event_dequeue(&fdc->state_event); + SET_INTRQ; + } + } +} + +void wd279x_write_protect(void *sptr, _Bool state) { + WD279X *fdc = sptr; + if (fdc->write_protect_state == state) + return; + fdc->write_protect_state = state; +} + void wd279x_set_dden(WD279X *fdc, _Bool dden) { fdc->double_density = dden; - vdrive_set_dden(dden); + DELEGATE_CALL1(fdc->set_dden, dden); +} + +void wd279x_update_connection(WD279X *fdc) { + DELEGATE_CALL1(fdc->set_dden, fdc->double_density); + if (fdc->has_sso) + DELEGATE_CALL1(fdc->set_sso, fdc->side); + DELEGATE_CALL1(fdc->set_dirc, fdc->direction); \ } uint8_t wd279x_read(WD279X *fdc, uint16_t A) { @@ -182,20 +229,18 @@ switch (A & 3) { default: case 0: - RESET_INTRQ; - if (vdrive_ready) + if (!fdc->intrq_immediate) + RESET_INTRQ; + if (fdc->ready_state) fdc->status_register &= ~STATUS_NOT_READY; else fdc->status_register |= STATUS_NOT_READY; - if ((fdc->command_register & 0xf0) == 0xd0 || (fdc->command_register & 0x80) == 0x00) { - if (vdrive_tr00) + if (fdc->status_type1) { + fdc->status_register &= ~(STATUS_TRACK_0|STATUS_INDEX_PULSE); + if (fdc->tr00_state) fdc->status_register |= STATUS_TRACK_0; - else - fdc->status_register &= ~STATUS_TRACK_0; - if (vdrive_index_pulse) + if (fdc->index_state) fdc->status_register |= STATUS_INDEX_PULSE; - else - fdc->status_register &= ~STATUS_INDEX_PULSE; } D = fdc->status_register; break; @@ -210,42 +255,42 @@ D = fdc->data_register; break; } - if (fdc->has_inverted_data) - return ~D; - return D; + return D ^ fdc->invert_data; } void wd279x_write(WD279X *fdc, uint16_t A, uint8_t D) { - if (fdc->has_inverted_data) - D = ~D; + D ^= fdc->invert_data; switch (A & 3) { default: case 0: - RESET_INTRQ; fdc->command_register = D; /* FORCE INTERRUPT */ - if ((fdc->command_register & 0xf0) == 0xd0) { + if ((D & 0xf0) == 0xd0) { if (xroar_cfg.debug_fdc & XROAR_DEBUG_FDC_STATE) { debug_state(fdc); } - if ((fdc->command_register & 0x0f) == 0) { - event_dequeue(&fdc->state_event); - fdc->status_register &= ~(STATUS_BUSY); - return; + fdc->intrq_nready_to_ready = D & 1; + fdc->intrq_ready_to_nready = D & 2; + fdc->intrq_index_pulse = D & 4; + /* XXX Data sheet wording implies that *only* + * 0xd0 can clear this. Needs testing... */ + fdc->intrq_immediate = D & 8; + if (!(fdc->status_register & STATUS_BUSY)) { + fdc->status_type1 = 1; } - if (fdc->command_register & 0x08) { - event_dequeue(&fdc->state_event); - fdc->status_register &= ~(STATUS_BUSY); + event_dequeue(&fdc->state_event); + fdc->status_register &= ~(STATUS_BUSY); + if (fdc->intrq_immediate) SET_INTRQ; - return; - } return; } /* Ignore any other command if busy */ if (fdc->status_register & STATUS_BUSY) { - LOG_DEBUG(4,"WD279X: Command received while busy!\n"); + LOG_DEBUG(3, "WD279X: Command received while busy!\n"); return; } + if (!fdc->intrq_immediate) + RESET_INTRQ; fdc->state = WD279X_state_accept_command; state_machine(fdc); break; @@ -265,7 +310,8 @@ /* One big state machine. This is called from an event dispatch and from the * write command function. */ -static void state_machine(WD279X *fdc) { +static void state_machine(void *sptr) { + WD279X *fdc = (WD279X *)sptr; uint8_t *idam; uint8_t data; int i; @@ -285,6 +331,7 @@ case WD279X_state_accept_command: /* 0xxxxxxx = RESTORE / SEEK / STEP / STEP-IN / STEP-OUT */ if ((fdc->command_register & 0x80) == 0x00) { + fdc->status_type1 = 1; fdc->status_register |= STATUS_BUSY; fdc->status_register &= ~(STATUS_CRC_ERROR|STATUS_SEEK_ERROR); RESET_DRQ; @@ -314,10 +361,11 @@ /* 10xxxxxx = READ/WRITE SECTOR */ if ((fdc->command_register & 0xc0) == 0x80) { + fdc->status_type1 = 0; fdc->status_register |= STATUS_BUSY; fdc->status_register &= ~(STATUS_LOST_DATA|STATUS_RNF|(1<<5)|(1<<6)); RESET_DRQ; - if (!vdrive_ready) { + if (!fdc->ready_state) { fdc->status_register &= ~(STATUS_BUSY); SET_INTRQ; return; @@ -339,11 +387,12 @@ if (((fdc->command_register & 0xf9) == 0xc0) || ((fdc->command_register & 0xf9) == 0xe0) || ((fdc->command_register & 0xf9) == 0xf0)) { + fdc->status_type1 = 0; fdc->status_register |= STATUS_BUSY; fdc->status_register &= ~(STATUS_LOST_DATA|(1<<4)|(1<<5)); if ((fdc->command_register & 0xf0) == 0xf0) RESET_DRQ; - if (!vdrive_ready) { + if (!fdc->ready_state) { fdc->status_register &= ~(STATUS_BUSY); SET_INTRQ; return; @@ -379,8 +428,8 @@ case WD279X_state_type1_3: - if (vdrive_tr00 && fdc->direction == -1) { - LOG_DEBUG(4,"WD279X: TR00!\n"); + if (fdc->tr00_state && fdc->direction == -1) { + LOG_DEBUG(3, "WD279X: TR00!\n"); fdc->track_register = 0; // The WD279x flow chart implies this delay is // not incurred in this situation, but real @@ -410,18 +459,15 @@ case WD279X_state_verify_track_2: idam = vdrive_next_idam(); - if (vdrive_new_index_pulse()) { - fdc->index_holes_count++; - if (fdc->index_holes_count >= 5) { - LOG_DEBUG(5, "index_holes_count >= 5: seek error\n"); - fdc->status_register &= ~(STATUS_BUSY); - fdc->status_register |= STATUS_SEEK_ERROR; - SET_INTRQ; - return; - } + if (fdc->index_holes_count >= 5) { + LOG_DEBUG(3, "WD279X: index_holes_count >= 5: seek error\n"); + fdc->status_register &= ~(STATUS_BUSY); + fdc->status_register |= STATUS_SEEK_ERROR; + SET_INTRQ; + return; } if (idam == NULL) { - LOG_DEBUG(5, "null IDAM: -> WD279X_state_verify_track_2\n"); + LOG_DEBUG(3, "WD279X: null IDAM: -> WD279X_state_verify_track_2\n"); NEXT_STATE(WD279X_state_verify_track_2, vdrive_time_to_next_idam()); return; } @@ -433,7 +479,7 @@ } (void)_vdrive_read(fdc); /* Include IDAM in CRC */ if (fdc->track_register != _vdrive_read(fdc)) { - LOG_DEBUG(5, "track_register != idam[1]: -> WD279X_state_verify_track_2\n"); + LOG_DEBUG(3, "WD279X: track_register != idam[1]: -> WD279X_state_verify_track_2\n"); NEXT_STATE(WD279X_state_verify_track_2, vdrive_time_to_next_idam()); return; } @@ -441,19 +487,18 @@ for (i = 0; i < 5; i++) (void)_vdrive_read(fdc); if (fdc->crc != 0) { - LOG_DEBUG(3, "Verify track %d CRC16 error: $%04x != 0\n", fdc->track_register, fdc->crc); + LOG_DEBUG(3, "WD279X: Verify track %d CRC16 error: $%04x != 0\n", fdc->track_register, fdc->crc); fdc->status_register |= STATUS_CRC_ERROR; NEXT_STATE(WD279X_state_verify_track_2, vdrive_time_to_next_idam()); return; } - LOG_DEBUG(5, "finished.\n"); fdc->status_register &= ~(STATUS_CRC_ERROR|STATUS_BUSY); SET_INTRQ; return; case WD279X_state_type2_1: - if ((fdc->command_register & 0x20) && vdrive_write_protect) { + if ((fdc->command_register & 0x20) && fdc->write_protect_state) { fdc->status_register &= ~(STATUS_BUSY); fdc->status_register |= STATUS_WRITE_PROTECT; SET_INTRQ; @@ -466,14 +511,11 @@ case WD279X_state_type2_2: idam = vdrive_next_idam(); - if (vdrive_new_index_pulse()) { - fdc->index_holes_count++; - if (fdc->index_holes_count >= 5) { - fdc->status_register &= ~(STATUS_BUSY); - fdc->status_register |= STATUS_RNF; - SET_INTRQ; - return; - } + if (fdc->index_holes_count >= 5) { + fdc->status_register &= ~(STATUS_BUSY); + fdc->status_register |= STATUS_RNF; + SET_INTRQ; + return; } if (idam == NULL) { NEXT_STATE(WD279X_state_type2_2, vdrive_time_to_next_idam()); @@ -511,13 +553,13 @@ (void)_vdrive_read(fdc); if (fdc->crc != 0) { fdc->status_register |= STATUS_CRC_ERROR; - LOG_DEBUG(3, "Type 2 tr %d se %d CRC16 error: $%04x != 0\n", fdc->track_register, fdc->sector_register, fdc->crc); + LOG_DEBUG(3, "WD279X: Type 2 tr %d se %d CRC16 error: $%04x != 0\n", fdc->track_register, fdc->sector_register, fdc->crc); NEXT_STATE(WD279X_state_type2_2, vdrive_time_to_next_idam()); return; } if ((fdc->command_register & 0x20) == 0) { - int bytes_to_scan, j, tmp; + int bytes_to_scan, j; if (IS_SINGLE_DENSITY) bytes_to_scan = 30; else @@ -531,7 +573,7 @@ fdc->crc = crc16_byte(fdc->crc, 0xa1); fdc->crc = crc16_byte(fdc->crc, 0xa1); } - tmp = _vdrive_read(fdc); + int tmp = _vdrive_read(fdc); if (tmp == 0xfb || tmp == 0xf8) fdc->dam = tmp; j++; @@ -550,7 +592,7 @@ case WD279X_state_read_sector_1: - LOG_DEBUG(4,"Reading %d-byte sector (Tr %d, Se %d) from head_pos=%04x\n", fdc->bytes_left, fdc->track_register, fdc->sector_register, vdrive_head_pos()); + LOG_DEBUG(3, "WD279X: Reading %d-byte sector (Tr %d, Se %d) from head_pos=%04x\n", fdc->bytes_left, fdc->track_register, fdc->sector_register, vdrive_head_pos()); if (xroar_cfg.debug_fdc & XROAR_DEBUG_FDC_DATA) log_open_hexdump(&log_rsec_hex, "WD279X: read-sector"); fdc->status_register |= ((~fdc->dam & 1) << 5); @@ -589,12 +631,12 @@ case WD279X_state_read_sector_3: if (fdc->crc != 0) { - LOG_DEBUG(3, "Read sector data tr %d se %d CRC16 error: $%04x != 0\n", fdc->track_register, fdc->sector_register, fdc->crc); + LOG_DEBUG(3, "WD279X: Read sector data tr %d se %d CRC16 error: $%04x != 0\n", fdc->track_register, fdc->sector_register, fdc->crc); fdc->status_register |= STATUS_CRC_ERROR; } /* TODO: M == 1 */ if (fdc->command_register & 0x10) { - LOG_DEBUG(2, "WD279X: TODO: multi-sector read will fail.\n"); + LOG_DEBUG(3, "WD279X: TODO: multi-sector read will fail.\n"); } fdc->status_register &= ~(STATUS_BUSY); SET_INTRQ; @@ -706,14 +748,11 @@ case WD279X_state_read_address_1: idam = vdrive_next_idam(); - if (vdrive_new_index_pulse()) { - fdc->index_holes_count++; - if (fdc->index_holes_count >= 6) { - fdc->status_register &= ~(STATUS_BUSY); - fdc->status_register |= STATUS_RNF; - SET_INTRQ; - return; - } + if (fdc->index_holes_count >= 6) { + fdc->status_register &= ~(STATUS_BUSY); + fdc->status_register |= STATUS_RNF; + SET_INTRQ; + return; } if (idam == NULL) { NEXT_STATE(WD279X_state_read_address_1, vdrive_time_to_next_idam()); @@ -760,7 +799,7 @@ case WD279X_state_write_track_1: - if (vdrive_write_protect) { + if (fdc->write_protect_state) { fdc->status_register &= ~(STATUS_BUSY); fdc->status_register |= STATUS_WRITE_PROTECT; SET_INTRQ; @@ -781,17 +820,19 @@ SET_INTRQ; return; } + fdc->index_holes_count = 0; NEXT_STATE(WD279X_state_write_track_2b, vdrive_time_to_next_idam()); return; case WD279X_state_write_track_2b: - if (!vdrive_new_index_pulse()) { - LOG_DEBUG(4,"Waiting for index pulse, head_pos=%04x\n", vdrive_head_pos()); + if (fdc->index_holes_count == 0) { + LOG_DEBUG(3, "WD279X: Waiting for index pulse, head_pos=%04x\n", vdrive_head_pos()); NEXT_STATE(WD279X_state_write_track_2b, vdrive_time_to_next_idam()); return; } - LOG_DEBUG(4,"Writing track from head_pos=%04x\n", vdrive_head_pos()); + fdc->index_holes_count = 0; + LOG_DEBUG(3, "WD279X: Writing track from head_pos=%04x\n", vdrive_head_pos()); if (xroar_cfg.debug_fdc & XROAR_DEBUG_FDC_DATA) log_open_hexdump(&log_wtrk_hex, "WD279X: write-track"); GOTO_STATE(WD279X_state_write_track_3); @@ -799,10 +840,10 @@ case WD279X_state_write_track_3: data = fdc->data_register; - if (vdrive_new_index_pulse()) { + if (fdc->index_holes_count > 0) { if (xroar_cfg.debug_fdc & XROAR_DEBUG_FDC_DATA) log_close(&log_wtrk_hex); - LOG_DEBUG(4,"Finished writing track at head_pos=%04x\n", vdrive_head_pos()); + LOG_DEBUG(3, "WD279X: Finished writing track at head_pos=%04x\n", vdrive_head_pos()); RESET_DRQ; /* XXX */ fdc->status_register &= ~(STATUS_BUSY); SET_INTRQ; @@ -820,7 +861,7 @@ if (IS_SINGLE_DENSITY) { /* Single density */ if (data == 0xf5 || data == 0xf6) { - LOG_DEBUG(4, "Illegal value in single-density track write: %02x\n", data); + LOG_DEBUG(3, "WD279X: Illegal value in single-density track write: %02x\n", data); } if (data == 0xf7) { VDRIVE_WRITE_CRC16; @@ -834,7 +875,7 @@ return; } if (data == 0xfe) { - LOG_DEBUG(4,"IDAM at head_pos=%04x\n", vdrive_head_pos()); + LOG_DEBUG(3, "WD279X: IDAM at head_pos=%04x\n", vdrive_head_pos()); fdc->crc = CRC16_RESET; vdrive_write_idam(); fdc->crc = crc16_byte(fdc->crc, 0xfe); @@ -852,7 +893,7 @@ return; } if (data == 0xfe) { - LOG_DEBUG(4,"IDAM at head_pos=%04x\n", vdrive_head_pos()); + LOG_DEBUG(3, "WD279X: IDAM at head_pos=%04x\n", vdrive_head_pos()); vdrive_write_idam(); fdc->crc = crc16_byte(fdc->crc, 0xfe); NEXT_STATE(WD279X_state_write_track_3, vdrive_time_to_next_byte()); @@ -883,7 +924,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Debugging -static const char *debug_state_name[] = { +static char const * const debug_state_name[] = { "accept_command", "type1_1", "type1_2", @@ -911,7 +952,7 @@ "write_track_3", }; -static const char *debug_command[] = { +static char const * const debug_command[] = { "restore", "seek", "step", diff -Nru xroar-0.31.1/src/wd279x.h xroar-0.32/src/wd279x.h --- xroar-0.31.1/src/wd279x.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/wd279x.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -8,6 +8,7 @@ #include +#include "delegate.h" #include "events.h" enum WD279X_type { @@ -55,13 +56,12 @@ uint8_t data_register; uint8_t command_register; - /* External handlers */ - void (*set_drq_handler)(void *); - void (*reset_drq_handler)(void *); - void *drq_data; - void (*set_intrq_handler)(void *); - void (*reset_intrq_handler)(void *); - void *intrq_data; + /* External interface */ + DELEGATE_T1(void, int) set_dirc; + DELEGATE_T1(void, bool) set_dden; + DELEGATE_T1(void, unsigned) set_sso; + DELEGATE_T1(void, bool) set_drq; + DELEGATE_T1(void, bool) set_intrq; /* WD279X internal state */ enum WD279X_state state; @@ -70,6 +70,18 @@ int side; int step_delay; _Bool double_density; + _Bool ready_state; + _Bool tr00_state; + _Bool index_state; + _Bool write_protect_state; + /* During & after type 1 commands, and sometimes after a forced + * interrupt, status reads reflect tr00 & index status: */ + _Bool status_type1; + /* Forced interrupts: */ + _Bool intrq_nready_to_ready; + _Bool intrq_ready_to_nready; + _Bool intrq_index_pulse; + _Bool intrq_immediate; _Bool is_step_cmd; uint16_t crc; @@ -82,13 +94,21 @@ _Bool has_sso; _Bool has_length_flag; - _Bool has_inverted_data; + uint8_t invert_data; }; WD279X *wd279x_new(enum WD279X_type type); void wd279x_free(WD279X *fdc); void wd279x_reset(WD279X *fdc); + +/* Signal all connected delegates */ +void wd279x_update_connection(WD279X *fdc); + +void wd279x_ready(void *sptr, _Bool state); +void wd279x_tr00(void *sptr, _Bool state); +void wd279x_index_pulse(void *sptr, _Bool state); +void wd279x_write_protect(void *sptr, _Bool state); void wd279x_set_dden(WD279X *fdc, _Bool dden); /* 1 = Double density, 0 = Single */ uint8_t wd279x_read(WD279X *fdc, uint16_t A); void wd279x_write(WD279X *fdc, uint16_t A, uint8_t D); diff -Nru xroar-0.31.1/src/windows32/ao_windows32.c xroar-0.32/src/windows32/ao_windows32.c --- xroar-0.31.1/src/windows32/ao_windows32.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/windows32/ao_windows32.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -20,7 +20,7 @@ #include -#include "pl_glib.h" +#include "xalloc.h" #include "logging.h" #include "module.h" @@ -100,9 +100,9 @@ waveOutPrepareHeader(device, wavehdr_p[i], sizeof(WAVEHDR)); } - audio_buffer = g_malloc(buffer_nbytes); + audio_buffer = xmalloc(buffer_nbytes); sound_init(audio_buffer, request_fmt, rate, nchannels, buffer_nframes); - LOG_DEBUG(2, "\t%dms (%d samples) buffer\n", (buffer_nframes * 1000) / rate, buffer_nframes); + LOG_DEBUG(1, "\t%dms (%d samples) buffer\n", (buffer_nframes * 1000) / rate, buffer_nframes); cursor = 0; buffer_num = 0; @@ -119,7 +119,7 @@ GlobalUnlock(data_alloc[i]); GlobalFree(data_alloc[i]); } - g_free(audio_buffer); + free(audio_buffer); } static void *write_buffer(void *buffer) { diff -Nru xroar-0.31.1/src/windows32/common_windows32.c xroar-0.32/src/windows32/common_windows32.c --- xroar-0.31.1/src/windows32/common_windows32.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/windows32/common_windows32.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * diff -Nru xroar-0.31.1/src/windows32/common_windows32.h xroar-0.32/src/windows32/common_windows32.h --- xroar-0.31.1/src/windows32/common_windows32.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/windows32/common_windows32.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ diff -Nru xroar-0.31.1/src/windows32/filereq_windows32.c xroar-0.32/src/windows32/filereq_windows32.c --- xroar-0.31.1/src/windows32/filereq_windows32.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/windows32/filereq_windows32.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -23,7 +23,7 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" /* Windows has a habit of making include order important: */ #include @@ -35,19 +35,19 @@ #include "windows32/common_windows32.h" -static char *load_filename(const char **extensions); -static char *save_filename(const char **extensions); +static char *load_filename(char const * const *extensions); +static char *save_filename(char const * const *extensions); FileReqModule filereq_windows32_module = { .common = { .name = "windows32", - .description = "Windows32 file requester" }, + .description = "Windows file requester" }, .load_filename = load_filename, .save_filename = save_filename }; static char *filename = NULL; -static char *load_filename(const char **extensions) { +static char *load_filename(char const * const *extensions) { OPENFILENAME ofn; char fn_buf[260]; int was_fullscreen; @@ -72,17 +72,17 @@ | OFN_HIDEREADONLY; if (filename) - g_free(filename); + free(filename); filename = NULL; if (GetOpenFileName(&ofn)==TRUE) { - filename = g_strdup(ofn.lpstrFile); + filename = xstrdup(ofn.lpstrFile); } if (video_module->set_fullscreen && was_fullscreen) video_module->set_fullscreen(1); return filename; } -static char *save_filename(const char **extensions) { +static char *save_filename(char const * const *extensions) { OPENFILENAME ofn; char fn_buf[260]; int was_fullscreen; @@ -107,10 +107,10 @@ | OFN_OVERWRITEPROMPT; if (filename) - g_free(filename); + free(filename); filename = NULL; if (GetSaveFileName(&ofn)==TRUE) { - filename = g_strdup(ofn.lpstrFile); + filename = xstrdup(ofn.lpstrFile); } if (video_module->set_fullscreen && was_fullscreen) video_module->set_fullscreen(1); diff -Nru xroar-0.31.1/src/windows32/ui_windows32.c xroar-0.32/src/windows32/ui_windows32.c --- xroar-0.31.1/src/windows32/ui_windows32.c 1970-01-01 00:00:00.000000000 +0000 +++ xroar-0.32/src/windows32/ui_windows32.c 2014-04-22 10:58:56.000000000 +0000 @@ -0,0 +1,544 @@ +/* + +XRoar, Dragon and Tandy CoCo 1/2 emulator +Copyright 2003-2014 Ciaran Anscomb + +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. + +*/ + +#include "config.h" + +#include + +#include +#include +#include + +#include +#include + +#include "array.h" + +#include "cart.h" +#include "events.h" +#include "joystick.h" +#include "keyboard.h" +#include "logging.h" +#include "machine.h" +#include "mc6847.h" +#include "module.h" +#include "sam.h" +#include "tape.h" +#include "vdisk.h" +#include "xroar.h" + +#include "sdl/common.h" +#include "windows32/common_windows32.h" + +#define TAG_TYPE_MASK (0x7f << 8) +#define TAG_VALUE_MASK (0xff) + +#define TAG_SIMPLE_ACTION (1 << 8) + +#define TAG_MACHINE (2 << 8) + +#define TAG_CARTRIDGE (3 << 8) + +#define TAG_TAPE_FLAGS (4 << 8) + +#define TAG_INSERT_DISK (5 << 8) +#define TAG_NEW_DISK (6 << 8) +#define TAG_WRITE_ENABLE (7 << 8) +#define TAG_WRITE_BACK (8 << 8) + +#define TAG_FULLSCREEN (9 << 8) +#define TAG_VDG_INVERSE (16 << 8) +#define TAG_CROSS_COLOUR (10 << 8) + +#define TAG_FAST_SOUND (11 << 8) + +#define TAG_KEYMAP (12 << 8) +#define TAG_KBD_TRANSLATE (13 << 8) +#define TAG_JOY_RIGHT (14 << 8) +#define TAG_JOY_LEFT (15 << 8) + +enum { + TAG_QUIT, + TAG_RESET_SOFT, + TAG_RESET_HARD, + TAG_FILE_LOAD, + TAG_FILE_RUN, + TAG_FILE_SAVE_SNAPSHOT, + TAG_TAPE_INPUT, + TAG_TAPE_OUTPUT, + TAG_TAPE_INPUT_REWIND, + TAG_ZOOM_IN, + TAG_ZOOM_OUT, + TAG_JOY_SWAP, +}; + +static int num_machines = 0; +static int num_cartridges = 0; +static int is_kbd_translate = 0; +static _Bool is_fast_sound = 0; + +static struct { + const char *name; + const char *description; +} const joystick_names[] = { + { NULL, "None" }, + { "joy0", "Joystick 0" }, + { "joy1", "Joystick 1" }, + { "kjoy0", "Keyboard" }, + { "mjoy0", "Mouse" }, +}; +#define NUM_JOYSTICK_NAMES ARRAY_N_ELEMENTS(joystick_names) + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +static _Bool init(void); +static void ui_shutdown(void); +static void fullscreen_changed_cb(_Bool); +static void cross_colour_changed_cb(int); +static void vdg_inverse_cb(_Bool); +static void machine_changed_cb(int); +static void cart_changed_cb(int); +static void keymap_changed_cb(int); +static void joystick_changed_cb(int, const char *); +static void kbd_translate_changed_cb(_Bool); +static void fast_sound_changed_cb(_Bool); +static void update_tape_state(int); +static void update_drive_disk(int, struct vdisk *); +static void update_drive_write_enable(int, _Bool); +static void update_drive_write_back(int, _Bool); + +/* Note: prefer the default order for sound and joystick modules, which + * will include the SDL options. */ + +UIModule ui_windows32_module = { + .common = { .name = "windows32", .description = "Windows SDL UI", + .init = init, .shutdown = ui_shutdown }, + .video_module_list = sdl_video_module_list, + .keyboard_module_list = sdl_keyboard_module_list, + .joystick_module_list = sdl_js_modlist, + .run = sdl_run, + .fullscreen_changed_cb = fullscreen_changed_cb, + .cross_colour_changed_cb = cross_colour_changed_cb, + .vdg_inverse_cb = vdg_inverse_cb, + .machine_changed_cb = machine_changed_cb, + .cart_changed_cb = cart_changed_cb, + .keymap_changed_cb = keymap_changed_cb, + .joystick_changed_cb = joystick_changed_cb, + .kbd_translate_changed_cb = kbd_translate_changed_cb, + .fast_sound_changed_cb = fast_sound_changed_cb, + .update_tape_state = update_tape_state, + .update_drive_disk = update_drive_disk, + .update_drive_write_enable = update_drive_write_enable, + .update_drive_write_back = update_drive_write_back, +}; + +static HMENU top_menu; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +static void setup_file_menu(void); +static void setup_view_menu(void); +static void setup_machine_menu(void); +static void setup_cartridge_menu(void); +static void setup_tool_menu(void); + +static _Bool init(void) { + if (!getenv("SDL_VIDEODRIVER")) + putenv("SDL_VIDEODRIVER=windib"); + + if (!SDL_WasInit(SDL_INIT_NOPARACHUTE)) { + if (SDL_Init(SDL_INIT_NOPARACHUTE) < 0) { + LOG_ERROR("Failed to initialise SDL: %s\n", SDL_GetError()); + return 0; + } + } + if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { + LOG_ERROR("Failed to initialise SDL video: %s\n", SDL_GetError()); + return 0; + } + + SDL_version sdlver; + SDL_SysWMinfo sdlinfo; + SDL_VERSION(&sdlver); + sdlinfo.version = sdlver; + SDL_GetWMInfo(&sdlinfo); + windows32_main_hwnd = sdlinfo.window; + + SetFocus(windows32_main_hwnd); + + top_menu = CreateMenu(); + setup_file_menu(); + setup_view_menu(); + setup_machine_menu(); + setup_cartridge_menu(); + setup_tool_menu(); + + return 1; +} + +static void ui_shutdown(void) { + SDL_QuitSubSystem(SDL_INIT_VIDEO); +} + +void sdl_windows32_update_menu(_Bool fullscreen) { + if (fullscreen) { + SetMenu(windows32_main_hwnd, NULL); + SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE); + } else { + SetMenu(windows32_main_hwnd, top_menu); + SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +static void setup_file_menu(void) { + HMENU file_menu; + HMENU submenu; + + file_menu = CreatePopupMenu(); + + AppendMenu(file_menu, MF_STRING, TAG_SIMPLE_ACTION | TAG_FILE_RUN, "&Run..."); + AppendMenu(file_menu, MF_STRING, TAG_SIMPLE_ACTION | TAG_FILE_LOAD, "&Load..."); + + AppendMenu(file_menu, MF_SEPARATOR, 0, NULL); + + submenu = CreatePopupMenu(); + AppendMenu(file_menu, MF_STRING | MF_POPUP, (uintptr_t)submenu, "Cassette"); + AppendMenu(submenu, MF_STRING, TAG_SIMPLE_ACTION | TAG_TAPE_INPUT, "Input Tape..."); + AppendMenu(submenu, MF_STRING, TAG_SIMPLE_ACTION | TAG_TAPE_OUTPUT, "Output Tape..."); + AppendMenu(submenu, MF_SEPARATOR, 0, NULL); + AppendMenu(submenu, MF_STRING, TAG_SIMPLE_ACTION | TAG_TAPE_INPUT_REWIND, "Rewind Input Tape"); + AppendMenu(submenu, MF_SEPARATOR, 0, NULL); + AppendMenu(submenu, MF_STRING, TAG_TAPE_FLAGS | TAPE_FAST, "Fast Loading"); + AppendMenu(submenu, MF_STRING, TAG_TAPE_FLAGS | TAPE_PAD, "Leader Padding"); + AppendMenu(submenu, MF_STRING, TAG_TAPE_FLAGS | TAPE_PAD_AUTO, "Automatic Padding"); + AppendMenu(submenu, MF_STRING, TAG_TAPE_FLAGS | TAPE_REWRITE, "Rewrite"); + + AppendMenu(file_menu, MF_SEPARATOR, 0, NULL); + + for (int drive = 0; drive < 4; drive++) { + char title[9]; + snprintf(title, sizeof(title), "Drive &%c", '1' + drive); + submenu = CreatePopupMenu(); + AppendMenu(file_menu, MF_STRING | MF_POPUP, (uintptr_t)submenu, title); + AppendMenu(submenu, MF_STRING, TAG_INSERT_DISK | drive, "Insert Disk..."); + AppendMenu(submenu, MF_STRING, TAG_NEW_DISK | drive, "New Disk..."); + AppendMenu(submenu, MF_SEPARATOR, 0, NULL); + AppendMenu(submenu, MF_STRING, TAG_WRITE_ENABLE | drive, "Write Enable"); + AppendMenu(submenu, MF_STRING, TAG_WRITE_BACK | drive, "Write Back"); + } + + AppendMenu(file_menu, MF_SEPARATOR, 0, NULL); + AppendMenu(file_menu, MF_STRING, TAG_SIMPLE_ACTION | TAG_FILE_SAVE_SNAPSHOT, "&Save Snapshot..."); + AppendMenu(file_menu, MF_STRING, TAG_SIMPLE_ACTION | TAG_QUIT, "&Quit"); + + AppendMenu(top_menu, MF_STRING | MF_POPUP, (uintptr_t)file_menu, "&File"); +} + +static void setup_view_menu(void) { + HMENU view_menu; + HMENU submenu; + + view_menu = CreatePopupMenu(); + + submenu = CreatePopupMenu(); + AppendMenu(view_menu, MF_STRING | MF_POPUP, (uintptr_t)submenu, "Zoom"); + AppendMenu(submenu, MF_STRING, TAG_SIMPLE_ACTION | TAG_ZOOM_IN, "Zoom In"); + AppendMenu(submenu, MF_STRING, TAG_SIMPLE_ACTION | TAG_ZOOM_OUT, "Zoom Out"); + + AppendMenu(view_menu, MF_SEPARATOR, 0, NULL); + AppendMenu(view_menu, MF_STRING, TAG_FULLSCREEN, "Full Screen"); + AppendMenu(view_menu, MF_SEPARATOR, 0, NULL); + AppendMenu(view_menu, MF_STRING, TAG_VDG_INVERSE, "Inverse Text"); + + submenu = CreatePopupMenu(); + AppendMenu(view_menu, MF_STRING | MF_POPUP, (uintptr_t)submenu, "Cross-colour"); + for (int i = 0; xroar_cross_colour_list[i].name; i++) { + AppendMenu(submenu, MF_STRING, TAG_CROSS_COLOUR | xroar_cross_colour_list[i].value, xroar_cross_colour_list[i].description); + } + + AppendMenu(top_menu, MF_STRING | MF_POPUP, (uintptr_t)view_menu, "&View"); +} + +static void setup_machine_menu(void) { + HMENU machine_menu; + HMENU submenu; + + machine_menu = CreatePopupMenu(); + num_machines = machine_config_count(); + for (int i = 0; i < num_machines; i++) { + struct machine_config *mc = machine_config_index(i); + AppendMenu(machine_menu, MF_STRING, TAG_MACHINE | mc->index, mc->description); + } + + AppendMenu(machine_menu, MF_SEPARATOR, 0, NULL); + submenu = CreatePopupMenu(); + AppendMenu(machine_menu, MF_STRING | MF_POPUP, (uintptr_t)submenu, "Keyboard Map"); + AppendMenu(submenu, MF_STRING, TAG_KEYMAP | KEYMAP_DRAGON, "Dragon Layout"); + AppendMenu(submenu, MF_STRING, TAG_KEYMAP | KEYMAP_DRAGON200E, "Dragon 200-E Layout"); + AppendMenu(submenu, MF_STRING, TAG_KEYMAP | KEYMAP_COCO, "CoCo Layout"); + + AppendMenu(machine_menu, MF_SEPARATOR, 0, NULL); + submenu = CreatePopupMenu(); + AppendMenu(machine_menu, MF_STRING | MF_POPUP, (uintptr_t)submenu, "Right Joystick"); + for (int i = 0; i < NUM_JOYSTICK_NAMES; i++) { + AppendMenu(submenu, MF_STRING, TAG_JOY_RIGHT | i, joystick_names[i].description); + } + submenu = CreatePopupMenu(); + AppendMenu(machine_menu, MF_STRING | MF_POPUP, (uintptr_t)submenu, "Left Joystick"); + for (int i = 0; i < NUM_JOYSTICK_NAMES; i++) { + AppendMenu(submenu, MF_STRING, TAG_JOY_LEFT | i, joystick_names[i].description); + } + AppendMenu(machine_menu, MF_STRING, TAG_SIMPLE_ACTION | TAG_JOY_SWAP, "Swap Joysticks"); + + AppendMenu(machine_menu, MF_SEPARATOR, 0, NULL); + AppendMenu(machine_menu, MF_STRING, TAG_SIMPLE_ACTION | TAG_RESET_SOFT, "Soft Reset"); + AppendMenu(machine_menu, MF_STRING, TAG_SIMPLE_ACTION | TAG_RESET_HARD, "Hard Reset"); + + AppendMenu(top_menu, MF_STRING | MF_POPUP, (uintptr_t)machine_menu, "&Machine"); + + machine_changed_cb(xroar_machine_config ? xroar_machine_config->index : 0); +} + +static void setup_cartridge_menu(void) { + HMENU cartridge_menu; + + cartridge_menu = CreatePopupMenu(); + AppendMenu(cartridge_menu, MF_STRING, TAG_CARTRIDGE, "None"); + num_cartridges = cart_config_count(); + for (int i = 0; i < num_cartridges; i++) { + struct cart_config *cc = cart_config_index(i); + AppendMenu(cartridge_menu, MF_STRING, TAG_CARTRIDGE | (cc->index + 1), cc->description); + } + + AppendMenu(top_menu, MF_STRING | MF_POPUP, (uintptr_t)cartridge_menu, "&Cartridge"); + + cart_changed_cb(xroar_cart ? xroar_cart->config->index : 0); +} + +static void setup_tool_menu(void) { + HMENU tool_menu; + + tool_menu = CreatePopupMenu(); + AppendMenu(tool_menu, MF_STRING, TAG_KBD_TRANSLATE, "Keyboard Translation"); + AppendMenu(tool_menu, MF_STRING, TAG_FAST_SOUND, "Fast Sound"); + + AppendMenu(top_menu, MF_STRING | MF_POPUP, (uintptr_t)tool_menu, "&Tool"); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +void sdl_windows32_handle_syswmevent(void *data) { + SDL_SysWMmsg *msg = data; + int tag = LOWORD(msg->wParam); + int tag_type = tag & TAG_TYPE_MASK; + int tag_value = tag & TAG_VALUE_MASK; + switch (msg->msg) { + case WM_COMMAND: + switch (tag_type) { + + /* Simple actions: */ + case TAG_SIMPLE_ACTION: + switch (tag_value) { + case TAG_QUIT: + { + SDL_Event event; + event.type = SDL_QUIT; + SDL_PushEvent(&event); + } + break; + case TAG_RESET_SOFT: + xroar_soft_reset(); + break; + case TAG_RESET_HARD: + xroar_hard_reset(); + break; + case TAG_FILE_RUN: + xroar_run_file(NULL); + break; + case TAG_FILE_LOAD: + xroar_load_file(NULL); + break; + case TAG_FILE_SAVE_SNAPSHOT: + xroar_save_snapshot(); + break; + case TAG_TAPE_INPUT: + xroar_select_tape_input(); + break; + case TAG_TAPE_OUTPUT: + xroar_select_tape_output(); + break; + case TAG_TAPE_INPUT_REWIND: + if (tape_input) + tape_rewind(tape_input); + break; + case TAG_ZOOM_IN: + sdl_zoom_in(); + break; + case TAG_ZOOM_OUT: + sdl_zoom_out(); + break; + case TAG_JOY_SWAP: + xroar_swap_joysticks(1); + break; + default: + break; + } + break; + + /* Machines: */ + case TAG_MACHINE: + xroar_set_machine(tag_value); + break; + + /* Cartridges: */ + case TAG_CARTRIDGE: + { + struct cart_config *cc = cart_config_index(tag_value - 1); + xroar_set_cart(cc ? cc->name : NULL); + } + break; + + /* Cassettes: */ + case TAG_TAPE_FLAGS: + tape_select_state(tape_get_state() ^ tag_value); + break; + + /* Disks: */ + case TAG_INSERT_DISK: + xroar_insert_disk(tag_value); + break; + case TAG_NEW_DISK: + xroar_new_disk(tag_value); + break; + case TAG_WRITE_ENABLE: + xroar_set_write_enable(1, tag_value, XROAR_TOGGLE); + break; + case TAG_WRITE_BACK: + xroar_set_write_back(1, tag_value, XROAR_TOGGLE); + break; + + /* Video: */ + case TAG_FULLSCREEN: + xroar_set_fullscreen(1, XROAR_TOGGLE); + break; + case TAG_CROSS_COLOUR: + xroar_set_cross_colour(1, tag_value); + break; + case TAG_VDG_INVERSE: + xroar_set_vdg_inverted_text(1, XROAR_TOGGLE); + break; + /* Audio: */ + case TAG_FAST_SOUND: + machine_select_fast_sound(!xroar_cfg.fast_sound); + break; + + /* Keyboard: */ + case TAG_KEYMAP: + xroar_set_keymap(tag_value); + break; + case TAG_KBD_TRANSLATE: + xroar_set_kbd_translate(1, XROAR_TOGGLE); + break; + + /* Joysticks: */ + case TAG_JOY_RIGHT: + xroar_set_joystick(1, 0, joystick_names[tag_value].name); + break; + case TAG_JOY_LEFT: + xroar_set_joystick(1, 1, joystick_names[tag_value].name); + break; + + default: + break; + } + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +static void fullscreen_changed_cb(_Bool fs) { + CheckMenuItem(top_menu, TAG_FULLSCREEN, MF_BYCOMMAND | (fs ? MF_CHECKED : MF_UNCHECKED)); +} + +static void cross_colour_changed_cb(int cc) { + CheckMenuRadioItem(top_menu, TAG_CROSS_COLOUR, TAG_CROSS_COLOUR | 2, TAG_CROSS_COLOUR | cc, MF_BYCOMMAND); +} + +static void vdg_inverse_cb(_Bool i) { + CheckMenuItem(top_menu, TAG_VDG_INVERSE, MF_BYCOMMAND | (i ? MF_CHECKED : MF_UNCHECKED)); +} + +static void machine_changed_cb(int machine_type) { + CheckMenuRadioItem(top_menu, TAG_MACHINE, TAG_MACHINE | (num_machines - 1), TAG_MACHINE | machine_type, MF_BYCOMMAND); +} + +static void cart_changed_cb(int cart_index) { + cart_index++; + CheckMenuRadioItem(top_menu, TAG_CARTRIDGE, TAG_CARTRIDGE | num_cartridges, TAG_CARTRIDGE | cart_index, MF_BYCOMMAND); +} + +static void keymap_changed_cb(int map) { + CheckMenuRadioItem(top_menu, TAG_KEYMAP, TAG_KEYMAP | (NUM_KEYMAPS - 1), TAG_KEYMAP | map, MF_BYCOMMAND); +} + +static void joystick_changed_cb(int port, const char *name) { + int tag_base = (port == 0) ? TAG_JOY_RIGHT : TAG_JOY_LEFT; + int sel = 0; + if (name) { + for (int i = 1; i < NUM_JOYSTICK_NAMES; i++) + if (0 == strcmp(name, joystick_names[i].name)) { + sel = i; + break; + } + } + CheckMenuRadioItem(top_menu, tag_base, tag_base | (NUM_JOYSTICK_NAMES - 1), tag_base | sel, MF_BYCOMMAND); +} + +static void kbd_translate_changed_cb(_Bool state) { + CheckMenuItem(top_menu, TAG_KBD_TRANSLATE, MF_BYCOMMAND | (state ? MF_CHECKED : MF_UNCHECKED)); +} + +static void fast_sound_changed_cb(_Bool state) { + CheckMenuItem(top_menu, TAG_FAST_SOUND, MF_BYCOMMAND | (state ? MF_CHECKED : MF_UNCHECKED)); +} + +static void update_tape_state(int flags) { + for (int i = 0; i < 4; i++) { + int f = flags & (1 << i); + int tag = TAG_TAPE_FLAGS | (1 << i); + CheckMenuItem(top_menu, tag, MF_BYCOMMAND | (f ? MF_CHECKED : MF_UNCHECKED)); + } +} + +static void update_drive_disk(int drive, struct vdisk *disk) { + _Bool we = 1, wb = 0; + if (disk) { + we = !disk->write_protect; + wb = disk->write_back; + } + update_drive_write_enable(drive, we); + update_drive_write_back(drive, wb); +} + +static void update_drive_write_enable(int drive, _Bool state) { + if (drive < 0 || drive > 3) + return; + CheckMenuItem(top_menu, TAG_WRITE_ENABLE | drive, MF_BYCOMMAND | (state ? MF_CHECKED : MF_UNCHECKED)); +} + +static void update_drive_write_back(int drive, _Bool state) { + if (drive < 0 || drive > 3) + return; + CheckMenuItem(top_menu, TAG_WRITE_BACK | drive, MF_BYCOMMAND | (state ? MF_CHECKED : MF_UNCHECKED)); +} diff -Nru xroar-0.31.1/src/windows32/xroar.rc xroar-0.32/src/windows32/xroar.rc --- xroar-0.31.1/src/windows32/xroar.rc 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/windows32/xroar.rc 2014-04-22 10:58:56.000000000 +0000 @@ -20,7 +20,7 @@ VALUE "FileDescription", "Dragon/Tandy CoCo emulator" VALUE "FileVersion", "0.0" VALUE "InternalName", "xroar" - VALUE "LegalCopyright", "Copyright 2003-2013 Ciaran Anscomb. GNU GPL 2 or later." + VALUE "LegalCopyright", "Copyright 2003-2014 Ciaran Anscomb. GNU GPL 2 or later." VALUE "OriginalFilename", "xroar.exe" VALUE "ProductName", "XRoar" VALUE "ProductVersion", to_str(VERSION) diff -Nru xroar-0.31.1/src/xconfig.c xroar-0.32/src/xconfig.c --- xroar-0.31.1/src/xconfig.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/xconfig.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -23,12 +23,12 @@ #include #include -#include "pl_glib.h" +#include "xalloc.h" #include "logging.h" #include "xconfig.h" -static struct xconfig_option *find_option(struct xconfig_option *options, +static struct xconfig_option const *find_option(struct xconfig_option const *options, const char *opt) { int i; for (i = 0; options[i].type != XCONFIG_END; i++) { @@ -56,7 +56,7 @@ return -1; } -static void set_option(struct xconfig_option *option, char *arg) { +static void set_option(struct xconfig_option const *option, char *arg) { switch (option->type) { case XCONFIG_BOOL: if (option->call) @@ -105,8 +105,8 @@ option->dest.func_string(arg); } else { if (*(char **)option->dest.object) - g_free(*(char **)option->dest.object); - *(char **)option->dest.object = g_strdup(arg); + free(*(char **)option->dest.object); + *(char **)option->dest.object = xstrdup(arg); } break; case XCONFIG_NULL: @@ -127,7 +127,7 @@ } /* returns 0 if it's a value option to unset */ -static int unset_option(struct xconfig_option *option) { +static int unset_option(struct xconfig_option const *option) { switch (option->type) { case XCONFIG_BOOL: if (option->call) @@ -157,7 +157,7 @@ if (option->call) { option->dest.func_string(NULL); } else if (*(char **)option->dest.object) { - g_free(*(char **)option->dest.object); + free(*(char **)option->dest.object); *(char **)option->dest.object = NULL; } return 0; @@ -168,7 +168,7 @@ } /* Simple parser: one directive per line, "option argument" */ -enum xconfig_result xconfig_parse_file(struct xconfig_option *options, +enum xconfig_result xconfig_parse_file(struct xconfig_option const *options, const char *filename) { char *line; FILE *cfg; @@ -186,11 +186,12 @@ return ret; } -enum xconfig_result xconfig_parse_line(struct xconfig_option *options, const char *line) { - struct xconfig_option *option; +enum xconfig_result xconfig_parse_line(struct xconfig_option const *options, const char *line) { + struct xconfig_option const *option; char *opt, *arg; - gsize line_len = strlen(line) + 1; - char *cline = g_alloca(line_len); + size_t line_len = strlen(line) + 1; + char cline_buf[line_len]; + char *cline = cline_buf; strncpy(cline, line, line_len); cline[line_len-1] = 0; while (isspace((int)*cline)) @@ -210,6 +211,9 @@ } return XCONFIG_BAD_OPTION; } + if (option->deprecated) { + LOG_WARN("Deprecated option `%s'\n", opt); + } if (option->type == XCONFIG_STRING) { /* preserve spaces */ arg = strtok(NULL, "\n\v\f\r"); @@ -244,13 +248,9 @@ return XCONFIG_OK; } -enum xconfig_result xconfig_parse_cli(struct xconfig_option *options, +enum xconfig_result xconfig_parse_cli(struct xconfig_option const *options, int argc, char **argv, int *argn) { - struct xconfig_option *option; - int _argn; - char *opt; - - _argn = argn ? *argn : 1; + int _argn = argn ? *argn : 1; while (_argn < argc) { if (argv[_argn][0] != '-') { break; @@ -259,9 +259,9 @@ _argn++; break; } - opt = argv[_argn]+1; + char *opt = argv[_argn]+1; if (*opt == '-') opt++; - option = find_option(options, opt); + struct xconfig_option const *option = find_option(options, opt); if (option == NULL) { if (0 == strncmp(opt, "no-", 3)) { option = find_option(options, opt + 3); @@ -274,6 +274,9 @@ LOG_ERROR("Unrecognised option `%s'\n", opt); return XCONFIG_BAD_OPTION; } + if (option->deprecated) { + LOG_WARN("Deprecated option `%s'\n", opt); + } if (option->type == XCONFIG_BOOL || option->type == XCONFIG_BOOL0 || option->type == XCONFIG_INT0 || diff -Nru xroar-0.31.1/src/xconfig.h xroar-0.32/src/xconfig.h --- xroar-0.31.1/src/xconfig.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/xconfig.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,33 +1,33 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ #ifndef XROAR_XCONFIG_H_ #define XROAR_XCONFIG_H_ -#define XC_SET_BOOL(o,d) { .type = XCONFIG_BOOL, .name = (o), .dest.object = (d) } -#define XC_SET_BOOL0(o,d) { .type = XCONFIG_BOOL0, .name = (o), .dest.object = (d) } -#define XC_SET_INT(o,d) { .type = XCONFIG_INT, .name = (o), .dest.object = (d) } -#define XC_SET_INT0(o,d) { .type = XCONFIG_INT0, .name = (o), .dest.object = (d) } -#define XC_SET_INT1(o,d) { .type = XCONFIG_INT1, .name = (o), .dest.object = (d) } -#define XC_SET_DOUBLE(o,d) { .type = XCONFIG_DOUBLE, .name = (o), .dest.object = (d) } -#define XC_SET_STRING(o,d) { .type = XCONFIG_STRING, .name = (o), .dest.object = (d) } -#define XC_SET_ENUM(o,d,e) { .type = XCONFIG_ENUM, .name = (o), .ref = (e), .dest.object = (d) } - -#define XC_CALL_BOOL(o,d) { .type = XCONFIG_BOOL, .name = (o), .dest.func_bool = (d), .call = 1 } -#define XC_CALL_BOOL0(o,d) { .type = XCONFIG_BOOL0, .name = (o), .dest.func_bool = (d), .call = 1 } -#define XC_CALL_INT(o,d) { .type = XCONFIG_INT, .name = (o), .dest.func_int = (d), .call = 1 } -#define XC_CALL_INT0(o,d) { .type = XCONFIG_INT0, .name = (o), .dest.func_int = (d), .call = 1 } -#define XC_CALL_INT1(o,d) { .type = XCONFIG_INT1, .name = (o), .dest.func_int = (d), .call = 1 } -#define XC_CALL_DOUBLE(o) { .type = XCONFIG_DOUBLE, .name = (o), .dest.func_double = (d), .call = 1 } -#define XC_CALL_STRING(o,d) { .type = XCONFIG_STRING, .name = (o), .dest.func_string = (xconfig_func_string)(d), .call = 1 } -#define XC_CALL_NULL(o,d) { .type = XCONFIG_NULL, .name = (o), .dest.func_null = (d), .call = 1 } -#define XC_CALL_ENUM(o,d,e) { .type = XCONFIG_ENUM, .name = (o), .ref = (e), .dest.func_int = (d), .call = 1 } +#define XC_SET_BOOL(o,d) .type = XCONFIG_BOOL, .name = (o), .dest.object = (d) +#define XC_SET_BOOL0(o,d) .type = XCONFIG_BOOL0, .name = (o), .dest.object = (d) +#define XC_SET_INT(o,d) .type = XCONFIG_INT, .name = (o), .dest.object = (d) +#define XC_SET_INT0(o,d) .type = XCONFIG_INT0, .name = (o), .dest.object = (d) +#define XC_SET_INT1(o,d) .type = XCONFIG_INT1, .name = (o), .dest.object = (d) +#define XC_SET_DOUBLE(o,d) .type = XCONFIG_DOUBLE, .name = (o), .dest.object = (d) +#define XC_SET_STRING(o,d) .type = XCONFIG_STRING, .name = (o), .dest.object = (d) +#define XC_SET_ENUM(o,d,e) .type = XCONFIG_ENUM, .name = (o), .ref = (e), .dest.object = (d) + +#define XC_CALL_BOOL(o,d) .type = XCONFIG_BOOL, .name = (o), .dest.func_bool = (d), .call = 1 +#define XC_CALL_BOOL0(o,d) .type = XCONFIG_BOOL0, .name = (o), .dest.func_bool = (d), .call = 1 +#define XC_CALL_INT(o,d) .type = XCONFIG_INT, .name = (o), .dest.func_int = (d), .call = 1 +#define XC_CALL_INT0(o,d) .type = XCONFIG_INT0, .name = (o), .dest.func_int = (d), .call = 1 +#define XC_CALL_INT1(o,d) .type = XCONFIG_INT1, .name = (o), .dest.func_int = (d), .call = 1 +#define XC_CALL_DOUBLE(o) .type = XCONFIG_DOUBLE, .name = (o), .dest.func_double = (d), .call = 1 +#define XC_CALL_STRING(o,d) .type = XCONFIG_STRING, .name = (o), .dest.func_string = (xconfig_func_string)(d), .call = 1 +#define XC_CALL_NULL(o,d) .type = XCONFIG_NULL, .name = (o), .dest.func_null = (d), .call = 1 +#define XC_CALL_ENUM(o,d,e) .type = XCONFIG_ENUM, .name = (o), .ref = (e), .dest.func_int = (d), .call = 1 -#define XC_OPT_END() { .type = XCONFIG_END } +#define XC_OPT_END() .type = XCONFIG_END -#define XC_ENUM_END() { .name = NULL } +#define XC_ENUM_END() .name = NULL enum xconfig_result { XCONFIG_OK = 0, @@ -68,6 +68,7 @@ } dest; void *ref; _Bool call; + _Bool deprecated; }; struct xconfig_enum { @@ -80,13 +81,13 @@ extern char *xconfig_option; extern int xconfig_line_number; -enum xconfig_result xconfig_parse_file(struct xconfig_option *options, +enum xconfig_result xconfig_parse_file(struct xconfig_option const *options, const char *filename); -enum xconfig_result xconfig_parse_line(struct xconfig_option *options, +enum xconfig_result xconfig_parse_line(struct xconfig_option const *options, const char *line); -enum xconfig_result xconfig_parse_cli(struct xconfig_option *options, +enum xconfig_result xconfig_parse_cli(struct xconfig_option const *options, int argc, char **argv, int *argn); #endif /* XROAR_XCONFIG_H_ */ diff -Nru xroar-0.31.1/src/xroar.c xroar-0.32/src/xroar.c --- xroar-0.31.1/src/xroar.c 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/xroar.c 2014-04-22 10:58:56.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright 2003-2013 Ciaran Anscomb +/* Copyright 2003-2014 Ciaran Anscomb * * This file is part of XRoar. * @@ -33,8 +33,11 @@ #include #endif -#include "pl_glib.h" -#include "pl_string.h" +#include "array.h" +#include "c-strcase.h" +#include "pl-string.h" +#include "slist.h" +#include "xalloc.h" #include "cart.h" #include "crclist.h" @@ -73,6 +76,7 @@ // Public struct xroar_cfg xroar_cfg = { + .disk_auto_os9 = 1, .gl_filter = ANY_AUTO, .ccr = CROSS_COLOUR_5BIT, }; @@ -107,14 +111,16 @@ char *cart_rom2; int cart_becker; int cart_autorun; + /* Deprecated */ + char *dos_option; /* Attach files */ char *run; char *tape_write; char *lp_file; char *lp_pipe; - GSList *load_list; - GSList *type_list; + struct slist *load_list; + struct slist *type_list; /* Emulator interface */ char *ui; @@ -182,7 +188,7 @@ static struct joystick_config *cur_joy_config = NULL; -static struct xconfig_option xroar_options[]; +static struct xconfig_option const xroar_options[]; /**************************************************************************/ /* Global flags */ @@ -199,7 +205,7 @@ /* Default configuration */ -static const char *default_config[] = { +static char const * const default_config[] = { // Dragon 32 "machine dragon32", "machine-desc Dragon 32", @@ -225,7 +231,7 @@ "machine-keyboard dragon200e", "extbas @dragon200e", "altbas @dragon200e_alt", - "ext-charset d200e_26", + "ext-charset @dragon200e_charset", "tv-type pal", "ram 64", // CoCo @@ -296,14 +302,15 @@ "romlist d64_1=d64_1,d64rom1,Dragon Data Ltd - Dragon 64 - IC17,Dragon Data Ltd - TANO IC18,Eurohard S.A. - Dragon 200 IC18,dragrom", "romlist d64_2=d64_2,d64rom2,Dragon Data Ltd - Dragon 64 - IC18,Dragon Data Ltd - TANO IC17,Eurohard S.A. - Dragon 200 IC17", "romlist d32=d32,dragon32,d32rom,Dragon Data Ltd - Dragon 32 - IC17", - "romlist d200e_1=d200e_1,d200e_rom1", - "romlist d200e_2=d200e_2,d200e_rom2", + "romlist d200e_1=d200e_1,d200e_rom1,ic18_v1.4e.ic34", + "romlist d200e_2=d200e_2,d200e_rom2,ic17_v1.4e.ic37", // Specific Dragon BASIC "romlist dragon64=@d64_1,@dragon", "romlist dragon64_alt=@d64_2", "romlist dragon32=@d32,@dragon", "romlist dragon200e=@d200e_1,@d64_1,@dragon", "romlist dragon200e_alt=@d200e_2,@d64_2", + "romlist dragon200e_charset=d200e_26,rom26.ic1", // Fallback CoCo BASIC "romlist coco=bas13,bas12,bas11,bas10", "romlist coco_ext=extbas11,extbas10", @@ -397,10 +404,10 @@ static struct event timeout_event; static void handle_timeout_event(void *); -const char *xroar_disk_exts[] = { "DMK", "JVC", "VDK", "DSK", NULL }; -const char *xroar_tape_exts[] = { "CAS", NULL }; -const char *xroar_snap_exts[] = { "SNA", NULL }; -const char *xroar_cart_exts[] = { "ROM", NULL }; +char const * const xroar_disk_exts[] = { "DMK", "JVC", "OS9", "VDK", "DSK", NULL }; +char const * const xroar_tape_exts[] = { "CAS", NULL }; +char const * const xroar_snap_exts[] = { "SNA", NULL }; +char const * const xroar_cart_exts[] = { "ROM", NULL }; static struct { const char *ext; @@ -409,6 +416,7 @@ { "VDK", FILETYPE_VDK }, { "JVC", FILETYPE_JVC }, { "DSK", FILETYPE_JVC }, + { "OS9", FILETYPE_OS9 }, { "DMK", FILETYPE_DMK }, { "BIN", FILETYPE_BIN }, { "HEX", FILETYPE_HEX }, @@ -422,8 +430,6 @@ { NULL, FILETYPE_UNKNOWN } }; -void (*xroar_fullscreen_changed_cb)(_Bool fullscreen) = NULL; -void (*xroar_kbd_translate_changed_cb)(_Bool kbd_translate) = NULL; static struct vdg_palette *get_machine_palette(void); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -451,7 +457,7 @@ // If the very first argument is -c, override conffile. if ((argn + 1) <= argc && 0 == strcmp(argv[argn], "-c")) { - conffile = g_strdup(argv[argn+1]); + conffile = xstrdup(argv[argn+1]); argn += 2; } @@ -469,7 +475,7 @@ private_cfg.joy_button[i] = NULL; // Default configuration. - for (unsigned i = 0; i < G_N_ELEMENTS(default_config); i++) { + for (unsigned i = 0; i < ARRAY_N_ELEMENTS(default_config); i++) { xconfig_parse_line(xroar_options, default_config[i]); } // Finish any machine or cart config in defaults. @@ -485,7 +491,7 @@ conffile = find_in_path(xroar_conf_path, "xroar.conf"); if (conffile) { (void)xconfig_parse_file(xroar_options, conffile); - g_free(conffile); + free(conffile); } // Finish any machine or cart config in config file. set_machine(NULL); @@ -540,17 +546,12 @@ sound_module_list = ui_module->sound_module_list; if (ui_module->keyboard_module_list != NULL) keyboard_module_list = ui_module->keyboard_module_list; - /* - if (ui_module->joystick_module_list != NULL) - joystick_module_list = ui_module->joystick_module_list; - */ // Select file requester, video & sound modules filereq_module = (FileReqModule *)module_select_by_arg((struct module **)filereq_module_list, private_cfg.filereq); video_module = (VideoModule *)module_select_by_arg((struct module **)video_module_list, private_cfg.vo); sound_module = (SoundModule *)module_select_by_arg((struct module **)sound_module_list, private_cfg.ao); // Keyboard & joystick modules keyboard_module = NULL; - joystick_module = NULL; /* Check other command-line options */ if (xroar_cfg.frameskip < 0) @@ -582,7 +583,7 @@ _Bool no_auto_dos = xroar_machine_config->nodos; _Bool definitely_dos = 0; - for (GSList *tmp_list = private_cfg.load_list; tmp_list; tmp_list = tmp_list->next) { + for (struct slist *tmp_list = private_cfg.load_list; tmp_list; tmp_list = tmp_list->next) { char *load_file = tmp_list->data; int load_file_type = xroar_filetype_by_ext(load_file); _Bool autorun = (load_file == private_cfg.run); @@ -597,6 +598,7 @@ // disks - flag that DOS should *definitely* be attempted case FILETYPE_VDK: case FILETYPE_JVC: + case FILETYPE_OS9: case FILETYPE_DMK: // unless explicitly disabled if (!xroar_machine_config->nodos) @@ -614,6 +616,24 @@ } if (definitely_dos) no_auto_dos = 0; + /* Deprecated option overrides -cart-rom, forces DOS based on machine + * arch if not already chosen. */ + if (private_cfg.dos_option) { + if (!selected_cart_config) { + if (xroar_machine_config->architecture == ARCH_COCO) { + selected_cart_config = cart_config_by_name("rsdos"); + } else { + selected_cart_config = cart_config_by_name("dragondos"); + } + } + if (selected_cart_config) { + if (selected_cart_config->rom) + free(selected_cart_config->rom); + selected_cart_config->rom = private_cfg.dos_option; + private_cfg.dos_option = NULL; + } + } + // Disable cart if necessary. if (!selected_cart_config && no_auto_dos) { xroar_machine_config->cart_enabled = 0; @@ -621,8 +641,8 @@ // If any cart still configured, make it default for machine. if (selected_cart_config) { if (xroar_machine_config->default_cart) - g_free(xroar_machine_config->default_cart); - xroar_machine_config->default_cart = g_strdup(selected_cart_config->name); + free(xroar_machine_config->default_cart); + xroar_machine_config->default_cart = xstrdup(selected_cart_config->name); } /* Initial palette */ @@ -650,10 +670,6 @@ if (keyboard_module == NULL && keyboard_module_list != NULL) { LOG_WARN("No keyboard module initialised.\n"); } - joystick_module = (JoystickModule *)module_init_from_list((struct module **)joystick_module_list, (struct module *)joystick_module); - if (joystick_module == NULL && joystick_module_list != NULL) { - LOG_WARN("No joystick module initialised.\n"); - } /* ... subsystems */ keyboard_init(); joystick_init(); @@ -662,14 +678,14 @@ // Default joystick mapping if (private_cfg.joy_right) { - joystick_map(joystick_config_by_name(private_cfg.joy_right), 0); + xroar_set_joystick(1, 0, private_cfg.joy_right); } else { - joystick_map(joystick_config_by_name("joy0"), 0); + xroar_set_joystick(1, 0, "joy0"); } if (private_cfg.joy_left) { - joystick_map(joystick_config_by_name(private_cfg.joy_left), 1); + xroar_set_joystick(1, 1, private_cfg.joy_left); } else { - joystick_map(joystick_config_by_name("joy1"), 1); + xroar_set_joystick(1, 1, "joy1"); } if (private_cfg.joy_virtual) { joystick_set_virtual(joystick_config_by_name(private_cfg.joy_virtual)); @@ -678,7 +694,10 @@ } /* Notify UI of starting options: */ - xroar_set_kbd_translate(xroar_cfg.kbd_translate); + if (ui_module->fullscreen_changed_cb) { + ui_module->fullscreen_changed_cb(xroar_cfg.fullscreen); + } + xroar_set_kbd_translate(1, xroar_cfg.kbd_translate); /* Configure machine */ machine_configure(xroar_machine_config); @@ -704,7 +723,7 @@ // delay loading binary files by 2s case FILETYPE_BIN: case FILETYPE_HEX: - event_init(&load_file_event, do_load_file, load_file); + event_init(&load_file_event, DELEGATE_AS0(void, do_load_file, load_file)); load_file_event.at_tick = event_current_tick + OSCILLATOR_RATE * 2; event_queue(&UI_EVENT_LIST, &load_file_event); autorun_loaded_file = autorun; @@ -712,6 +731,7 @@ // load disks then advice drive number case FILETYPE_VDK: case FILETYPE_JVC: + case FILETYPE_OS9: case FILETYPE_DMK: xroar_load_file_by_type(load_file, autorun); load_disk_to_drive++; @@ -723,7 +743,7 @@ xroar_load_file_by_type(load_file, autorun); break; } - private_cfg.load_list = g_slist_remove(private_cfg.load_list, private_cfg.load_list->data); + private_cfg.load_list = slist_remove(private_cfg.load_list, private_cfg.load_list->data); } load_disk_to_drive = 0; @@ -757,7 +777,7 @@ if (t >= 0.0) { timeout_seconds = (int)t; timeout_cycles = OSCILLATOR_RATE * (t - timeout_seconds); - event_init(&timeout_event, handle_timeout_event, NULL); + event_init(&timeout_event, DELEGATE_AS0(void, handle_timeout_event, NULL)); /* handler can set up the first call for us... */ timeout_seconds++; handle_timeout_event(NULL); @@ -766,7 +786,7 @@ while (private_cfg.type_list) { keyboard_queue_basic(private_cfg.type_list->data); - private_cfg.type_list = g_slist_remove(private_cfg.type_list, private_cfg.type_list->data); + private_cfg.type_list = slist_remove(private_cfg.type_list, private_cfg.type_list->data); } if (private_cfg.lp_file) { printer_open_file(private_cfg.lp_file); @@ -788,7 +808,6 @@ pthread_cond_destroy(&run_state_cv); #endif machine_shutdown(); - module_shutdown((struct module *)joystick_module); module_shutdown((struct module *)keyboard_module); module_shutdown((struct module *)sound_module); module_shutdown((struct module *)video_module); @@ -905,7 +924,7 @@ return FILETYPE_UNKNOWN; ext++; for (i = 0; filetypes[i].ext; i++) { - if (!g_ascii_strncasecmp(ext, filetypes[i].ext, strlen(filetypes[i].ext))) + if (!c_strncasecmp(ext, filetypes[i].ext, strlen(filetypes[i].ext))) return filetypes[i].filetype; } return FILETYPE_UNKNOWN; @@ -920,6 +939,7 @@ switch (filetype) { case FILETYPE_VDK: case FILETYPE_JVC: + case FILETYPE_OS9: case FILETYPE_DMK: xroar_insert_disk_file(load_disk_to_drive, filename); if (autorun && vdrive_disk_in_drive(0)) { @@ -972,8 +992,8 @@ xroar_load_file_by_type(load_file, autorun_loaded_file); } -static void handle_timeout_event(void *dptr) { - (void)dptr; +static void handle_timeout_event(void *sptr) { + (void)sptr; if (timeout_seconds == 0) { xroar_quit(); return; @@ -1015,17 +1035,17 @@ if (xroar_cfg.trace_enabled) { switch (xroar_machine_config->cpu) { case CPU_MC6809: default: - cpu->interrupt_hook = mc6809_trace_irq; + cpu->interrupt_hook = DELEGATE_AS1(void, int, mc6809_trace_irq, NULL); break; case CPU_HD6309: - cpu->interrupt_hook = hd6309_trace_irq; + cpu->interrupt_hook = DELEGATE_AS1(void, int, hd6309_trace_irq, NULL); break; } } else { - cpu->interrupt_hook = NULL; + cpu->interrupt_hook.func = NULL; } #else - cpu->interrupt_hook = NULL; + cpu->interrupt_hook.func = NULL; #endif } @@ -1040,10 +1060,11 @@ struct vdisk *new_disk = vdisk_blank_disk(34, 1, VDISK_LENGTH_5_25); if (new_disk == NULL) return; - LOG_DEBUG(4, "Creating blank disk in drive %d\n", 1 + drive); + LOG_DEBUG(1, "Creating blank disk in drive %d\n", 1 + drive); switch (filetype) { case FILETYPE_VDK: case FILETYPE_JVC: + case FILETYPE_OS9: case FILETYPE_DMK: break; default: @@ -1051,7 +1072,7 @@ break; } new_disk->filetype = filetype; - new_disk->filename = g_strdup(filename); + new_disk->filename = xstrdup(filename); new_disk->write_back = 1; vdrive_insert_disk(drive, new_disk); if (ui_module && ui_module->update_drive_disk) { @@ -1083,9 +1104,9 @@ _Bool xroar_set_write_enable(_Bool notify, int drive, int action) { _Bool we = vdrive_set_write_enable(drive, action); if (we) { - LOG_DEBUG(2, "Disk in drive %d write enabled.\n", drive); + LOG_DEBUG(1, "Disk in drive %d write enabled.\n", drive); } else { - LOG_DEBUG(2, "Disk in drive %d write protected.\n", drive); + LOG_DEBUG(1, "Disk in drive %d write protected.\n", drive); } if (notify && ui_module && ui_module->update_drive_write_enable) { ui_module->update_drive_write_enable(drive, we); @@ -1096,9 +1117,9 @@ _Bool xroar_set_write_back(_Bool notify, int drive, int action) { _Bool wb = vdrive_set_write_back(drive, action); if (wb) { - LOG_DEBUG(2, "Write back enabled for disk in drive %d.\n", drive); + LOG_DEBUG(1, "Write back enabled for disk in drive %d.\n", drive); } else { - LOG_DEBUG(2, "Write back disabled for disk in drive %d.\n", drive); + LOG_DEBUG(1, "Write back disabled for disk in drive %d.\n", drive); } if (notify && ui_module && ui_module->update_drive_write_back) { ui_module->update_drive_write_back(drive, wb); @@ -1144,10 +1165,7 @@ exit(EXIT_SUCCESS); } -void xroar_fullscreen(int action) { - static int lock = 0; - if (lock) return; - lock = 1; +void xroar_set_fullscreen(_Bool notify, int action) { _Bool set_to; switch (action) { case XROAR_OFF: @@ -1161,21 +1179,22 @@ set_to = !video_module->is_fullscreen; break; } - video_module->set_fullscreen(set_to); - if (xroar_fullscreen_changed_cb) { - xroar_fullscreen_changed_cb(set_to); + if (video_module->set_fullscreen) { + video_module->set_fullscreen(set_to); + } + if (notify && ui_module->fullscreen_changed_cb) { + ui_module->fullscreen_changed_cb(set_to); } - lock = 0; } -void xroar_load_file(const char **exts) { +void xroar_load_file(char const * const *exts) { char *filename = filereq_module->load_filename(exts); if (filename) { xroar_load_file_by_type(filename, 0); } } -void xroar_run_file(const char **exts) { +void xroar_run_file(char const * const *exts) { char *filename = filereq_module->load_filename(exts); if (filename) { xroar_load_file_by_type(filename, 1); @@ -1216,10 +1235,7 @@ lock = 0; } -void xroar_set_kbd_translate(int kbd_translate) { - static int lock = 0; - if (lock) return; - lock = 1; +void xroar_set_kbd_translate(_Bool notify, int kbd_translate) { switch (kbd_translate) { case XROAR_TOGGLE: case XROAR_CYCLE: xroar_cfg.kbd_translate = !xroar_cfg.kbd_translate; @@ -1228,13 +1244,50 @@ xroar_cfg.kbd_translate = kbd_translate; break; } - if (xroar_kbd_translate_changed_cb) { - xroar_kbd_translate_changed_cb(xroar_cfg.kbd_translate); - } if (keyboard_module->update_kbd_translate) { keyboard_module->update_kbd_translate(); } - lock = 0; + if (notify && ui_module->kbd_translate_changed_cb) { + ui_module->kbd_translate_changed_cb(xroar_cfg.kbd_translate); + } +} + +static void update_ui_joysticks(int port) { + if (!ui_module->joystick_changed_cb) + return; + const char *name = NULL; + if (joystick_port_config[port] && joystick_port_config[port]->name) { + name = joystick_port_config[port]->name; + } + ui_module->joystick_changed_cb(port, name); +} + +void xroar_set_joystick(_Bool notify, int port, const char *name) { + if (port < 0 || port > 1) + return; + if (name) { + joystick_map(joystick_config_by_name(name), port); + } else { + joystick_unmap(port); + } + if (notify) + update_ui_joysticks(port); +} + +void xroar_swap_joysticks(_Bool notify) { + joystick_swap(); + if (notify) { + update_ui_joysticks(0); + update_ui_joysticks(1); + } +} + +void xroar_cycle_joysticks(_Bool notify) { + joystick_cycle(); + if (notify) { + update_ui_joysticks(0); + update_ui_joysticks(1); + } } void xroar_set_machine(int machine_type) { @@ -1296,8 +1349,8 @@ xroar_machine_config->cart_enabled = 0; } else { if (xroar_machine_config->default_cart != cc_name) { - g_free(xroar_machine_config->default_cart); - xroar_machine_config->default_cart = g_strdup(cc_name); + free(xroar_machine_config->default_cart); + xroar_machine_config->default_cart = xstrdup(cc_name); } xroar_machine_config->cart_enabled = 1; machine_insert_cart(cart_new_named(cc_name)); @@ -1480,8 +1533,8 @@ } if (private_cfg.machine_cart) { if (xroar_machine_config->default_cart) - g_free(xroar_machine_config->default_cart); - xroar_machine_config->default_cart = g_strdup(private_cfg.machine_cart); + free(xroar_machine_config->default_cart); + xroar_machine_config->default_cart = xstrdup(private_cfg.machine_cart); private_cfg.machine_cart = NULL; } if (private_cfg.nodos != -1) { @@ -1494,7 +1547,7 @@ xroar_machine_config = machine_config_by_name(name); if (!xroar_machine_config) { xroar_machine_config = machine_config_new(); - xroar_machine_config->name = g_strdup(name); + xroar_machine_config->name = xstrdup(name); } } } @@ -1553,7 +1606,7 @@ selected_cart_config = cart_config_by_name(name); if (!selected_cart_config) { selected_cart_config = cart_config_new(); - selected_cart_config->name = g_strdup(name); + selected_cart_config->name = xstrdup(name); } } } @@ -1569,7 +1622,7 @@ for (unsigned i = 0; i < JOYSTICK_NUM_AXES; i++) { if (private_cfg.joy_axis[i]) { if (cur_joy_config->axis_specs[i]) - g_free(cur_joy_config->axis_specs[i]); + free(cur_joy_config->axis_specs[i]); cur_joy_config->axis_specs[i] = private_cfg.joy_axis[i]; private_cfg.joy_axis[i] = NULL; } @@ -1577,7 +1630,7 @@ for (unsigned i = 0; i < JOYSTICK_NUM_BUTTONS; i++) { if (private_cfg.joy_button[i]) { if (cur_joy_config->button_specs[i]) - g_free(cur_joy_config->button_specs[i]); + free(cur_joy_config->button_specs[i]); cur_joy_config->button_specs[i] = private_cfg.joy_button[i]; private_cfg.joy_button[i] = NULL; } @@ -1598,13 +1651,13 @@ cur_joy_config = joystick_config_by_name(name); if (!cur_joy_config) { cur_joy_config = joystick_config_new(); - cur_joy_config->name = g_strdup(name); + cur_joy_config->name = xstrdup(name); } } } static void set_joystick_axis(const char *spec) { - char *spec_copy = g_strdup(spec); + char *spec_copy = xstrdup(spec); char *cspec = spec_copy; unsigned axis = 0; char *tmp = strsep(&cspec, "="); @@ -1617,38 +1670,38 @@ axis = strtol(tmp, NULL, 0); } if (axis > JOYSTICK_NUM_AXES) { - LOG_WARN("Invalid axis number '%d'\n", axis); + LOG_WARN("Invalid axis number '%u'\n", axis); axis = 0; } tmp = cspec; } - private_cfg.joy_axis[axis] = g_strdup(tmp); - g_free(spec_copy); + private_cfg.joy_axis[axis] = xstrdup(tmp); + free(spec_copy); } static void set_joystick_button(const char *spec) { - char *spec_copy = g_strdup(spec); + char *spec_copy = xstrdup(spec); char *cspec = spec_copy; unsigned button = 0; char *tmp = strsep(&cspec, "="); if (cspec) { button = strtol(tmp, NULL, 0); if (button > JOYSTICK_NUM_AXES) { - LOG_WARN("Invalid button number '%d'\n", button); + LOG_WARN("Invalid button number '%u'\n", button); button = 0; } tmp = cspec; } - private_cfg.joy_button[button] = g_strdup(tmp); - g_free(spec_copy); + private_cfg.joy_button[button] = xstrdup(tmp); + free(spec_copy); } static void type_command(char *string) { - private_cfg.type_list = g_slist_append(private_cfg.type_list, string); + private_cfg.type_list = slist_append(private_cfg.type_list, string); } static void add_load(char *string) { - private_cfg.load_list = g_slist_append(private_cfg.load_list, string); + private_cfg.load_list = slist_append(private_cfg.load_list, string); } /* Enumeration lists used by configuration directives */ @@ -1657,33 +1710,33 @@ { .value = ARCH_DRAGON64, .name = "dragon64", .description = "Dragon 64" }, { .value = ARCH_DRAGON32, .name = "dragon32", .description = "Dragon 32" }, { .value = ARCH_COCO, .name = "coco", .description = "Tandy CoCo" }, - XC_ENUM_END() + { XC_ENUM_END() } }; static struct xconfig_enum keyboard_list[] = { { .value = dkbd_layout_dragon, .name = "dragon", .description = "Dragon" }, { .value = dkbd_layout_dragon200e, .name = "dragon200e", .description = "Dragon 200-E" }, { .value = dkbd_layout_coco, .name = "coco", .description = "Tandy CoCo" }, - XC_ENUM_END() + { XC_ENUM_END() } }; static struct xconfig_enum cpu_list[] = { { .value = CPU_MC6809, .name = "6809", .description = "Motorola 6809" }, { .value = CPU_HD6309, .name = "6309", .description = "Hitachi 6309 - UNVERIFIED" }, - XC_ENUM_END() + { XC_ENUM_END() } }; static struct xconfig_enum tv_type_list[] = { { .value = TV_PAL, .name = "pal", .description = "PAL (50Hz)" }, { .value = TV_NTSC, .name = "ntsc", .description = "NTSC (60Hz)" }, { .value = TV_NTSC, .name = "pal-m", .description = "PAL-M (60Hz)" }, - XC_ENUM_END() + { XC_ENUM_END() } }; static struct xconfig_enum vdg_type_list[] = { { .value = VDG_6847, .name = "6847", .description = "Original 6847" }, { .value = VDG_6847T1, .name = "6847t1", .description = "6847T1 with lowercase" }, - XC_ENUM_END() + { XC_ENUM_END() } }; static struct xconfig_enum cart_type_list[] = { @@ -1692,178 +1745,199 @@ { .value = CART_DELTADOS, .name = "delta", .description = "Delta System" }, { .value = CART_RSDOS, .name = "rsdos", .description = "RS-DOS" }, { .value = CART_ORCH90, .name = "orch90", .description = "Orchestra 90-CC" }, - XC_ENUM_END() + { XC_ENUM_END() } }; static struct xconfig_enum gl_filter_list[] = { { .value = ANY_AUTO, .name = "auto", .description = "Automatic" }, { .value = XROAR_GL_FILTER_NEAREST, .name = "nearest", .description = "Nearest-neighbour filtering" }, { .value = XROAR_GL_FILTER_LINEAR, .name = "linear", .description = "Linear filter" }, - XC_ENUM_END() + { XC_ENUM_END() } }; static struct xconfig_enum ccr_list[] = { { .value = CROSS_COLOUR_SIMPLE, .name = "simple", .description = "four colour palette" }, { .value = CROSS_COLOUR_5BIT, .name = "5bit", .description = "5-bit lookup table" }, - XC_ENUM_END() + { XC_ENUM_END() } }; struct xconfig_enum xroar_cross_colour_list[] = { { .value = CROSS_COLOUR_OFF, .name = "none", .description = "None" }, { .value = CROSS_COLOUR_KBRW, .name = "blue-red", .description = "Blue-red" }, { .value = CROSS_COLOUR_KRBW, .name = "red-blue", .description = "Red-blue" }, - XC_ENUM_END() + { XC_ENUM_END() } +}; + +static struct xconfig_enum ao_format_list[] = { + { .value = SOUND_FMT_U8, .name = "u8", .description = "8-bit unsigned" }, + { .value = SOUND_FMT_S8, .name = "s8", .description = "8-bit signed" }, + { .value = SOUND_FMT_S16_HE, .name = "s16", .description = "16-bit signed host-endian" }, + { .value = SOUND_FMT_S16_SE, .name = "s16se", .description = "16-bit signed swapped-endian" }, + { .value = SOUND_FMT_S16_BE, .name = "s16be", .description = "16-bit signed big-endian" }, + { .value = SOUND_FMT_S16_LE, .name = "s16le", .description = "16-bit signed little-endian" }, + { .value = SOUND_FMT_FLOAT, .name = "float", .description = "Floating point" }, + { XC_ENUM_END() } }; /* Configuration directives */ -static struct xconfig_option xroar_options[] = { +static _Bool dummy_bool; + +static struct xconfig_option const xroar_options[] = { /* Machines: */ - XC_SET_STRING("default-machine", &private_cfg.default_machine), - XC_CALL_STRING("machine", &set_machine), - XC_SET_STRING("machine-desc", &private_cfg.machine_desc), - XC_SET_ENUM("machine-arch", &private_cfg.machine_arch, arch_list), - XC_SET_ENUM("machine-keyboard", &private_cfg.machine_keymap, keyboard_list), - XC_SET_ENUM("machine-cpu", &private_cfg.machine_cpu, cpu_list), - XC_SET_STRING("bas", &private_cfg.bas), - XC_SET_STRING("extbas", &private_cfg.extbas), - XC_SET_STRING("altbas", &private_cfg.altbas), - XC_SET_INT1("nobas", &private_cfg.nobas), - XC_SET_INT1("noextbas", &private_cfg.noextbas), - XC_SET_INT1("noaltbas", &private_cfg.noaltbas), - XC_SET_STRING("ext-charset", &private_cfg.ext_charset), - XC_SET_ENUM("tv-type", &private_cfg.tv, tv_type_list), - XC_SET_ENUM("vdg-type", &private_cfg.vdg_type, vdg_type_list), - XC_SET_INT("ram", &private_cfg.ram), - XC_SET_STRING("machine-cart", &private_cfg.machine_cart), - XC_SET_INT1("nodos", &private_cfg.nodos), + { XC_SET_STRING("default-machine", &private_cfg.default_machine) }, + { XC_CALL_STRING("machine", &set_machine) }, + { XC_SET_STRING("machine-desc", &private_cfg.machine_desc) }, + { XC_SET_ENUM("machine-arch", &private_cfg.machine_arch, arch_list) }, + { XC_SET_ENUM("machine-keyboard", &private_cfg.machine_keymap, keyboard_list) }, + { XC_SET_ENUM("machine-cpu", &private_cfg.machine_cpu, cpu_list) }, + { XC_SET_STRING("bas", &private_cfg.bas) }, + { XC_SET_STRING("extbas", &private_cfg.extbas) }, + { XC_SET_STRING("altbas", &private_cfg.altbas) }, + { XC_SET_INT1("nobas", &private_cfg.nobas) }, + { XC_SET_INT1("noextbas", &private_cfg.noextbas) }, + { XC_SET_INT1("noaltbas", &private_cfg.noaltbas) }, + { XC_SET_STRING("ext-charset", &private_cfg.ext_charset) }, + { XC_SET_ENUM("tv-type", &private_cfg.tv, tv_type_list) }, + { XC_SET_ENUM("vdg-type", &private_cfg.vdg_type, vdg_type_list) }, + { XC_SET_INT("ram", &private_cfg.ram) }, + { XC_SET_STRING("machine-cart", &private_cfg.machine_cart) }, + { XC_SET_INT1("nodos", &private_cfg.nodos) }, + /* Shorthand: */ + { XC_CALL_NULL("pal", &set_pal) }, + { XC_CALL_NULL("ntsc", &set_ntsc) }, /* Deliberately undocumented: */ - XC_SET_STRING("machine-palette", &private_cfg.machine_palette), - /* Backwards-compatibility: */ - XC_CALL_NULL("pal", &set_pal), - XC_CALL_NULL("ntsc", &set_ntsc), + { XC_SET_STRING("machine-palette", &private_cfg.machine_palette) }, /* Cartridges: */ - XC_CALL_STRING("cart", &set_cart), - XC_SET_STRING("cart-desc", &private_cfg.cart_desc), - XC_SET_ENUM("cart-type", &private_cfg.cart_type, cart_type_list), - XC_SET_STRING("cart-rom", &private_cfg.cart_rom), - XC_SET_STRING("cart-rom2", &private_cfg.cart_rom2), - XC_SET_INT1("cart-autorun", &private_cfg.cart_autorun), - XC_SET_INT1("cart-becker", &private_cfg.cart_becker), + { XC_CALL_STRING("cart", &set_cart) }, + { XC_SET_STRING("cart-desc", &private_cfg.cart_desc) }, + { XC_SET_ENUM("cart-type", &private_cfg.cart_type, cart_type_list) }, + { XC_SET_STRING("cart-rom", &private_cfg.cart_rom) }, + { XC_SET_STRING("cart-rom2", &private_cfg.cart_rom2) }, + { XC_SET_INT1("cart-autorun", &private_cfg.cart_autorun) }, + { XC_SET_INT1("cart-becker", &private_cfg.cart_becker) }, /* Backwards compatibility: */ - XC_SET_ENUM("dostype", &private_cfg.cart_type, cart_type_list), - XC_SET_STRING("dos", &private_cfg.cart_rom), + { XC_SET_ENUM("dostype", &private_cfg.cart_type, cart_type_list), .deprecated = 1 }, + { XC_SET_STRING("dos", &private_cfg.dos_option), .deprecated = 1 }, /* Becker port: */ - XC_SET_BOOL("becker", &xroar_cfg.becker), - XC_SET_STRING("becker-ip", &xroar_cfg.becker_ip), - XC_SET_STRING("becker-port", &xroar_cfg.becker_port), + { XC_SET_BOOL("becker", &xroar_cfg.becker) }, + { XC_SET_STRING("becker-ip", &xroar_cfg.becker_ip) }, + { XC_SET_STRING("becker-port", &xroar_cfg.becker_port) }, /* Backwards-compatibility: */ - XC_SET_STRING("dw4-ip", &xroar_cfg.becker_ip), - XC_SET_STRING("dw4-port", &xroar_cfg.becker_port), + { XC_SET_STRING("dw4-ip", &xroar_cfg.becker_ip), .deprecated = 1 }, + { XC_SET_STRING("dw4-port", &xroar_cfg.becker_port), .deprecated = 1 }, /* Files: */ - XC_CALL_STRING("load", &add_load), - XC_SET_STRING("run", &private_cfg.run), + { XC_CALL_STRING("load", &add_load) }, + { XC_SET_STRING("run", &private_cfg.run) }, /* Backwards-compatibility: */ - XC_CALL_STRING("cartna", &add_load), - XC_CALL_STRING("snap", &add_load), + { XC_CALL_STRING("cartna", &add_load), .deprecated = 1 }, + { XC_CALL_STRING("snap", &add_load), .deprecated = 1 }, /* Cassettes: */ - XC_SET_STRING("tape-write", &private_cfg.tape_write), - XC_SET_INT1("tape-fast", &private_cfg.tape_fast), - XC_SET_INT1("tape-pad", &private_cfg.tape_pad), - XC_SET_INT1("tape-pad-auto", &private_cfg.tape_pad_auto), - XC_SET_INT1("tape-rewrite", &private_cfg.tape_rewrite), + { XC_SET_STRING("tape-write", &private_cfg.tape_write) }, + { XC_SET_INT1("tape-fast", &private_cfg.tape_fast) }, + { XC_SET_INT1("tape-pad", &private_cfg.tape_pad) }, + { XC_SET_INT1("tape-pad-auto", &private_cfg.tape_pad_auto) }, + { XC_SET_INT1("tape-rewrite", &private_cfg.tape_rewrite) }, /* Backwards-compatibility: */ - XC_SET_INT1("tapehack", &private_cfg.tape_rewrite), + { XC_SET_INT1("tapehack", &private_cfg.tape_rewrite), .deprecated = 1 }, /* Disks: */ - XC_SET_BOOL("disk-write-back", &xroar_cfg.disk_write_back), - XC_SET_BOOL("disk-jvc-hack", &xroar_cfg.disk_jvc_hack), + { XC_SET_BOOL("disk-write-back", &xroar_cfg.disk_write_back) }, + { XC_SET_BOOL("disk-auto-os9", &xroar_cfg.disk_auto_os9) }, + /* Backwards-compatibility: */ + { XC_SET_BOOL("disk-jvc-hack", &dummy_bool), .deprecated = 1 }, /* Firmware ROM images: */ - XC_SET_STRING("rompath", &xroar_rom_path), - XC_CALL_STRING("romlist", &romlist_assign), - XC_CALL_NULL("romlist-print", &romlist_print), - XC_CALL_STRING("crclist", &crclist_assign), - XC_CALL_NULL("crclist-print", &crclist_print), - XC_SET_BOOL("force-crc-match", &xroar_cfg.force_crc_match), + { XC_SET_STRING("rompath", &xroar_rom_path) }, + { XC_CALL_STRING("romlist", &romlist_assign) }, + { XC_CALL_NULL("romlist-print", &romlist_print) }, + { XC_CALL_STRING("crclist", &crclist_assign) }, + { XC_CALL_NULL("crclist-print", &crclist_print) }, + { XC_SET_BOOL("force-crc-match", &xroar_cfg.force_crc_match) }, /* User interface: */ - XC_SET_STRING("ui", &private_cfg.ui), + { XC_SET_STRING("ui", &private_cfg.ui) }, /* Deliberately undocumented: */ - XC_SET_STRING("filereq", &private_cfg.filereq), + { XC_SET_STRING("filereq", &private_cfg.filereq) }, /* Video: */ - XC_SET_STRING("vo", &private_cfg.vo), - XC_SET_BOOL("fs", &xroar_cfg.fullscreen), - XC_SET_INT("fskip", &xroar_cfg.frameskip), - XC_SET_ENUM("ccr", &xroar_cfg.ccr, ccr_list), - XC_SET_ENUM("gl-filter", &xroar_cfg.gl_filter, gl_filter_list), - XC_SET_STRING("geometry", &xroar_cfg.geometry), - XC_SET_STRING("g", &xroar_cfg.geometry), - XC_SET_BOOL("invert-text", &xroar_cfg.vdg_inverted_text), + { XC_SET_STRING("vo", &private_cfg.vo) }, + { XC_SET_BOOL("fs", &xroar_cfg.fullscreen) }, + { XC_SET_INT("fskip", &xroar_cfg.frameskip) }, + { XC_SET_ENUM("ccr", &xroar_cfg.ccr, ccr_list) }, + { XC_SET_ENUM("gl-filter", &xroar_cfg.gl_filter, gl_filter_list) }, + { XC_SET_STRING("geometry", &xroar_cfg.geometry) }, + { XC_SET_STRING("g", &xroar_cfg.geometry) }, + { XC_SET_BOOL("invert-text", &xroar_cfg.vdg_inverted_text) }, /* Audio: */ - XC_SET_STRING("ao", &private_cfg.ao), - XC_SET_STRING("ao-device", &xroar_cfg.ao_device), - XC_SET_INT("ao-rate", &xroar_cfg.ao_rate), - XC_SET_INT("ao-channels", &xroar_cfg.ao_channels), - XC_SET_INT("ao-fragments", &xroar_cfg.ao_fragments), - XC_SET_INT("ao-fragment-ms", &xroar_cfg.ao_fragment_ms), - XC_SET_INT("ao-fragment-frames", &xroar_cfg.ao_fragment_nframes), - XC_SET_INT("ao-buffer-ms", &xroar_cfg.ao_buffer_ms), - XC_SET_INT("ao-buffer-frames", &xroar_cfg.ao_buffer_nframes), - XC_SET_INT("volume", &private_cfg.volume), + { XC_SET_STRING("ao", &private_cfg.ao) }, + { XC_SET_STRING("ao-device", &xroar_cfg.ao_device) }, + { XC_SET_ENUM("ao-format", &xroar_cfg.ao_format, ao_format_list) }, + { XC_SET_INT("ao-rate", &xroar_cfg.ao_rate) }, + { XC_SET_INT("ao-channels", &xroar_cfg.ao_channels) }, + { XC_SET_INT("ao-fragments", &xroar_cfg.ao_fragments) }, + { XC_SET_INT("ao-fragment-ms", &xroar_cfg.ao_fragment_ms) }, + { XC_SET_INT("ao-fragment-frames", &xroar_cfg.ao_fragment_nframes) }, + { XC_SET_INT("ao-buffer-ms", &xroar_cfg.ao_buffer_ms) }, + { XC_SET_INT("ao-buffer-frames", &xroar_cfg.ao_buffer_nframes) }, + { XC_SET_INT("volume", &private_cfg.volume) }, #ifndef FAST_SOUND - XC_SET_BOOL("fast-sound", &xroar_cfg.fast_sound), + { XC_SET_BOOL("fast-sound", &xroar_cfg.fast_sound) }, #endif /* Backwards-compatibility: */ - XC_SET_INT("ao-buffer-samples", &xroar_cfg.ao_buffer_nframes), + { XC_SET_INT("ao-buffer-samples", &xroar_cfg.ao_buffer_nframes), .deprecated = 1 }, /* Keyboard: */ - XC_SET_STRING("keymap", &xroar_cfg.keymap), - XC_SET_BOOL("kbd-translate", &xroar_cfg.kbd_translate), - XC_CALL_STRING("type", &type_command), + { XC_SET_STRING("keymap", &xroar_cfg.keymap) }, + { XC_SET_BOOL("kbd-translate", &xroar_cfg.kbd_translate) }, + { XC_CALL_STRING("type", &type_command) }, /* Joysticks: */ - XC_CALL_STRING("joy", &set_joystick), - XC_SET_STRING("joy-desc", &private_cfg.joy_desc), - XC_CALL_STRING("joy-axis", &set_joystick_axis), - XC_CALL_STRING("joy-button", &set_joystick_button), - XC_SET_STRING("joy-right", &private_cfg.joy_right), - XC_SET_STRING("joy-left", &private_cfg.joy_left), - XC_SET_STRING("joy-virtual", &private_cfg.joy_virtual), + { XC_CALL_STRING("joy", &set_joystick) }, + { XC_SET_STRING("joy-desc", &private_cfg.joy_desc) }, + { XC_CALL_STRING("joy-axis", &set_joystick_axis) }, + { XC_CALL_STRING("joy-button", &set_joystick_button) }, + { XC_SET_STRING("joy-right", &private_cfg.joy_right) }, + { XC_SET_STRING("joy-left", &private_cfg.joy_left) }, + { XC_SET_STRING("joy-virtual", &private_cfg.joy_virtual) }, /* Printing: */ - XC_SET_STRING("lp-file", &private_cfg.lp_file), - XC_SET_STRING("lp-pipe", &private_cfg.lp_pipe), + { XC_SET_STRING("lp-file", &private_cfg.lp_file) }, + { XC_SET_STRING("lp-pipe", &private_cfg.lp_pipe) }, /* Debugging: */ #ifdef WANT_GDB_TARGET - XC_SET_BOOL("gdb", &private_cfg.gdb), - XC_SET_STRING("gdb-ip", &xroar_cfg.gdb_ip), - XC_SET_STRING("gdb-port", &xroar_cfg.gdb_port), + { XC_SET_BOOL("gdb", &private_cfg.gdb) }, + { XC_SET_STRING("gdb-ip", &xroar_cfg.gdb_ip) }, + { XC_SET_STRING("gdb-port", &xroar_cfg.gdb_port) }, #endif #ifdef TRACE - XC_SET_INT1("trace", &xroar_cfg.trace_enabled), + { XC_SET_INT1("trace", &xroar_cfg.trace_enabled) }, #endif - XC_SET_INT("debug-ui", &xroar_cfg.debug_ui), - XC_SET_INT("debug-file", &xroar_cfg.debug_file), - XC_SET_INT("debug-fdc", &xroar_cfg.debug_fdc), + { XC_SET_INT("debug-ui", &xroar_cfg.debug_ui) }, + { XC_SET_INT("debug-file", &xroar_cfg.debug_file) }, + { XC_SET_INT("debug-fdc", &xroar_cfg.debug_fdc) }, #ifdef WANT_GDB_TARGET - XC_SET_INT("debug-gdb", &xroar_cfg.debug_gdb), + { XC_SET_INT("debug-gdb", &xroar_cfg.debug_gdb) }, #endif - XC_SET_STRING("timeout", &private_cfg.timeout), + { XC_SET_STRING("timeout", &private_cfg.timeout) }, /* Other options: */ - XC_SET_BOOL("config-print", &private_cfg.config_print), - XC_CALL_NULL("help", &helptext), - XC_CALL_NULL("h", &helptext), - XC_CALL_NULL("version", &versiontext), - XC_OPT_END() + { XC_SET_BOOL("config-print", &private_cfg.config_print) }, + { XC_SET_INT0("quiet", &log_level) }, + { XC_SET_INT0("q", &log_level) }, + { XC_SET_INT("verbose", &log_level) }, + { XC_SET_INT("v", &log_level) }, + { XC_CALL_NULL("help", &helptext) }, + { XC_CALL_NULL("h", &helptext) }, + { XC_CALL_NULL("version", &versiontext) }, + { XC_CALL_NULL("V", &versiontext) }, + { XC_OPT_END() } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1927,7 +2001,7 @@ "\n Disks:\n" " -disk-write-back default to enabling write-back for disk images\n" -" -disk-jvc-hack autodetect headerless double-sided JVC images\n" +" -no-disk-auto-os9 don't try to detect headerless OS-9 JVC disk images\n" "\n Firmware ROM images:\n" " -rompath PATH ROM search path (colon-separated list)\n" @@ -1954,6 +2028,7 @@ "\n Audio:\n" " -ao MODULE audio module (-ao help for list)\n" " -ao-device STRING device to use for audio module\n" +" -ao-format FMT set audio sample format (-ao-format help for list)\n" " -ao-rate HZ set audio frame rate (if supported by module)\n" " -ao-channels N set number of audio channels, 1 or 2\n" " -ao-fragments N set number of audio fragments\n" @@ -1986,9 +2061,9 @@ "\n Debugging:\n" #ifdef WANT_GDB_TARGET -" -gdb disable GDB target\n" -" -gdb-ip address of interface for GDB target [localhost]\n" -" -gdb-port port for GDB target to listen on [65520]\n" +" -gdb enable GDB target\n" +" -gdb-ip ADDRESS address of interface for GDB target [127.0.0.1]\n" +" -gdb-port PORT port for GDB target to listen on [65520]\n" #endif #ifdef TRACE " -trace start with trace mode on\n" @@ -1997,12 +2072,14 @@ " -debug-file FLAGS file debugging (see manual, or -1 for all)\n" " -debug-fdc FLAGS FDC debugging (see manual, or -1 for all)\n" " -debug-gdb FLAGS GDB target debugging (see manual, or -1 for all)\n" +" -v, --verbose LEVEL general debug verbosity (0-3) [1]\n" +" -q, --quiet equivalent to --verbose 0\n" " -timeout SECONDS run for SECONDS then quit\n" "\n Other options:\n" " -config-print print full configuration to standard output\n" " -h, --help display this help and exit\n" -" --version output version information and exit\n" +" -V, --version output version information and exit\n" "\nJoystick SPECs are of the form [INTERFACE:][ARG[,ARG]...], from:\n" @@ -2024,11 +2101,11 @@ #ifdef LOGGING puts( "XRoar " VERSION "\n" -"Copyright (C) 2003-2013 Ciaran Anscomb\n" -"This is free software. You may redistribute copies of it under the terms of\n" -"the GNU General Public License .\n" +"Copyright (C) 2014 Ciaran Anscomb\n" +"License: GNU GPL version 2 or later .\n" +"This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law." - ); + ); #endif exit(EXIT_SUCCESS); } @@ -2057,7 +2134,7 @@ putchar('\n'); puts("# Files"); - for (GSList *l = private_cfg.load_list; l; l = l->next) { + for (struct slist *l = private_cfg.load_list; l; l = l->next) { const char *s = l->data; printf("load %s\n", s); } @@ -2078,7 +2155,7 @@ puts("# Disks"); if (xroar_cfg.disk_write_back) puts("disk-write-back"); - if (xroar_cfg.disk_jvc_hack) puts("disk-jvc-hack"); + if (!xroar_cfg.disk_auto_os9) puts("no-disk-auto-os9"); puts(""); puts("# Firmware ROM images"); @@ -2115,6 +2192,16 @@ puts("# Audio"); if (private_cfg.ao) printf("ao %s\n", private_cfg.ao); if (xroar_cfg.ao_device) printf("ao-device %s\n", xroar_cfg.ao_device); + switch (xroar_cfg.ao_format) { + case SOUND_FMT_U8: puts("ao-format u8"); break; + case SOUND_FMT_S8: puts("ao-format u8"); break; + case SOUND_FMT_S16_HE: puts("ao-format s16"); break; + case SOUND_FMT_S16_SE: puts("ao-format s16se"); break; + case SOUND_FMT_S16_BE: puts("ao-format s16be"); break; + case SOUND_FMT_S16_LE: puts("ao-format s16le"); break; + case SOUND_FMT_FLOAT: puts("ao-format float"); break; + default: break; + } if (xroar_cfg.ao_rate != 0) printf("ao-rate %d\n", xroar_cfg.ao_rate); if (xroar_cfg.ao_channels != 0) printf("ao-channels %d\n", xroar_cfg.ao_channels); if (xroar_cfg.ao_fragments != 0) printf("ao-fragments %d\n", xroar_cfg.ao_fragments); @@ -2131,7 +2218,7 @@ puts("# Keyboard"); if (xroar_cfg.keymap) printf("keymap %s\n", xroar_cfg.keymap); if (xroar_cfg.kbd_translate) puts("kbd-translate"); - for (GSList *l = private_cfg.type_list; l; l = l->next) { + for (struct slist *l = private_cfg.type_list; l; l = l->next) { const char *s = l->data; printf("type %s\n", s); } diff -Nru xroar-0.31.1/src/xroar.h xroar-0.32/src/xroar.h --- xroar-0.31.1/src/xroar.h 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/src/xroar.h 2014-04-22 10:58:56.000000000 +0000 @@ -1,5 +1,5 @@ /* XRoar - a Dragon/Tandy Coco emulator - * Copyright (C) 2003-2013 Ciaran Anscomb + * Copyright (C) 2003-2014 Ciaran Anscomb * * See COPYING.GPL for redistribution conditions. */ @@ -28,25 +28,25 @@ #define XROAR_TOGGLE (-2) #define XROAR_CYCLE (-3) -#define FILETYPE_UNKNOWN (0) -#define FILETYPE_VDK (1) -#define FILETYPE_JVC (2) -#define FILETYPE_DMK (3) -#define FILETYPE_BIN (4) -#define FILETYPE_HEX (5) -#define FILETYPE_CAS (6) -#define FILETYPE_WAV (7) -#define FILETYPE_SNA (8) -#define FILETYPE_ROM (9) -#define FILETYPE_ASC (10) - -extern const char *xroar_disk_exts[]; -extern const char *xroar_tape_exts[]; -extern const char *xroar_snap_exts[]; -extern const char *xroar_cart_exts[]; +enum xroar_filetype { + FILETYPE_UNKNOWN, + FILETYPE_VDK, + FILETYPE_JVC, + FILETYPE_OS9, // special type of JVC + FILETYPE_DMK, + FILETYPE_BIN, + FILETYPE_HEX, + FILETYPE_CAS, + FILETYPE_WAV, + FILETYPE_SNA, + FILETYPE_ROM, + FILETYPE_ASC, +}; -extern void (*xroar_fullscreen_changed_cb)(_Bool fullscreen); -extern void (*xroar_kbd_translate_changed_cb)(_Bool kbd_translate); +extern char const * const xroar_disk_exts[]; +extern char const * const xroar_tape_exts[]; +extern char const * const xroar_snap_exts[]; +extern char const * const xroar_cart_exts[]; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -82,6 +82,7 @@ _Bool vdg_inverted_text; // Audio char *ao_device; + int ao_format; int ao_rate; int ao_channels; int ao_fragments; @@ -101,7 +102,7 @@ char *becker_port; // Disks _Bool disk_write_back; - _Bool disk_jvc_hack; + _Bool disk_auto_os9; // CRC lists _Bool force_crc_match; // GDB target @@ -196,11 +197,14 @@ void xroar_set_cross_colour(_Bool notify, int action); void xroar_set_vdg_inverted_text(_Bool notify, int action); void xroar_quit(void); -void xroar_fullscreen(int action); -void xroar_load_file(const char **exts); -void xroar_run_file(const char **exts); +void xroar_set_fullscreen(_Bool notify, int action); +void xroar_load_file(const char * const *exts); +void xroar_run_file(const char * const *exts); void xroar_set_keymap(int map); -void xroar_set_kbd_translate(int kbd_translate); +void xroar_set_kbd_translate(_Bool notify, int kbd_translate); +void xroar_set_joystick(_Bool notify, int port, const char *name); +void xroar_swap_joysticks(_Bool notify); +void xroar_cycle_joysticks(_Bool notify); void xroar_set_machine(int machine); void xroar_toggle_cart(void); void xroar_set_cart(const char *cc_name); diff -Nru xroar-0.31.1/tools/Makefile xroar-0.32/tools/Makefile --- xroar-0.31.1/tools/Makefile 2013-12-04 07:38:24.000000000 +0000 +++ xroar-0.32/tools/Makefile 2014-04-22 10:58:56.000000000 +0000 @@ -8,7 +8,7 @@ -include ../config.mak -SRCROOT ?= $(dir $(lastword $(MAKEFILE_LIST))) +SRCROOT ?= .. include $(SRCROOT)/common.mak SRCROOT := $(SRCROOT)/tools