diff -Naru fuse-1.1.1-vanilla/fuse.c fuse-1.1.1/fuse.c --- fuse-1.1.1-vanilla/fuse.c 2013-05-16 22:26:23.000000000 +0200 +++ fuse-1.1.1/fuse.c 2014-02-21 12:46:19.947908386 +0100 @@ -274,6 +274,7 @@ rzx_init(); psg_init(); beta_init(); + tim397_init(); opus_init(); plusd_init(); disciple_init(); diff -Naru fuse-1.1.1-vanilla/machines/machines_periph.c fuse-1.1.1/machines/machines_periph.c --- fuse-1.1.1-vanilla/machines/machines_periph.c 2013-05-16 22:26:11.000000000 +0200 +++ fuse-1.1.1/machines/machines_periph.c 2014-02-21 12:46:19.947908386 +0100 @@ -201,6 +201,7 @@ periph_set_present( PERIPH_TYPE_FULLER, PERIPH_PRESENT_OPTIONAL ); periph_set_present( PERIPH_TYPE_ZXPRINTER, PERIPH_PRESENT_OPTIONAL ); periph_set_present( PERIPH_TYPE_DISCIPLE, PERIPH_PRESENT_OPTIONAL ); + periph_set_present( PERIPH_TYPE_TIM397, PERIPH_PRESENT_OPTIONAL ); } /* The set of peripherals available on the 128K and similar machines */ diff -Naru fuse-1.1.1-vanilla/Makefile.in fuse-1.1.1/Makefile.in --- fuse-1.1.1-vanilla/Makefile.in 2013-05-30 00:21:33.000000000 +0200 +++ fuse-1.1.1/Makefile.in 2014-02-21 12:46:19.947908386 +0100 @@ -232,7 +232,7 @@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBPNG_CONFIG = @LIBPNG_CONFIG@ -LIBS = @LIBS@ +LIBS = @LIBS@ -lrt LIBSPEC_CFLAGS = @LIBSPEC_CFLAGS@ LIBSPEC_HAVE_AUDIOFILE = @LIBSPEC_HAVE_AUDIOFILE@ LIBSPEC_HAVE_BZ2 = @LIBSPEC_HAVE_BZ2@ diff -Naru fuse-1.1.1-vanilla/memory.c fuse-1.1.1/memory.c --- fuse-1.1.1-vanilla/memory.c 2013-05-16 22:26:23.000000000 +0200 +++ fuse-1.1.1/memory.c 2014-02-21 12:46:19.947908386 +0100 @@ -37,6 +37,7 @@ #include "memory.h" #include "module.h" #include "peripherals/disk/opus.h" +#include "peripherals/disk/ti_m397.h" #include "peripherals/spectranet.h" #include "peripherals/ula.h" #include "settings.h" diff -Naru fuse-1.1.1-vanilla/menu.c fuse-1.1.1/menu.c --- fuse-1.1.1-vanilla/menu.c 2013-05-16 22:26:23.000000000 +0200 +++ fuse-1.1.1/menu.c 2014-02-21 12:46:19.947908386 +0100 @@ -36,6 +36,7 @@ #include "peripherals/disk/beta.h" #include "peripherals/disk/disciple.h" #include "peripherals/disk/opus.h" +#include "peripherals/disk/ti_m397.h" #include "peripherals/disk/plusd.h" #include "peripherals/ide/divide.h" #include "peripherals/ide/simpleide.h" @@ -224,7 +225,8 @@ case 18: menu_select_roms_with_title( "+D", 42, 1 ); return; case 19: menu_select_roms_with_title( "DISCiPLE", 43, 1 ); return; case 20: menu_select_roms_with_title( "Opus Discovery", 44, 1 ); return; - case 21: menu_select_roms_with_title( "SpeccyBoot", 45, 1 ); return; + case 21: menu_select_roms_with_title( "Timex M397", 45, 1 ); return; + case 22: menu_select_roms_with_title( "SpeccyBoot", 46, 1 ); return; } diff -Naru fuse-1.1.1-vanilla/menu_data.dat fuse-1.1.1/menu_data.dat --- fuse-1.1.1-vanilla/menu_data.dat 2013-05-16 22:26:23.000000000 +0200 +++ fuse-1.1.1/menu_data.dat 2014-02-21 12:46:19.947908386 +0100 @@ -101,7 +101,8 @@ Options/Select ROMs/+_D..., Item,, menu_options_selectroms_select,, 18 Options/Select ROMs/DISCiP_LE..., Item,, menu_options_selectroms_select,, 19 Options/Select ROMs/_Opus Discovery..., Item,, menu_options_selectroms_select,, 20 -Options/Select ROMs/Specc_yBoot..., Item,, menu_options_selectroms_select,, 21 +Options/Select ROMs/_Timex M397..., Item,, menu_options_selectroms_select,, 21 +Options/Select ROMs/Specc_yBoot..., Item,, menu_options_selectroms_select,, 22 Options/_Filter..., Item,,, menu_filter_detail diff -Naru fuse-1.1.1-vanilla/peripherals/disk/Makefile.am fuse-1.1.1/peripherals/disk/Makefile.am --- fuse-1.1.1-vanilla/peripherals/disk/Makefile.am 2013-05-16 22:26:03.000000000 +0200 +++ fuse-1.1.1/peripherals/disk/Makefile.am 2014-02-21 11:33:59.000000000 +0100 @@ -37,6 +37,8 @@ opus.c \ plusd.c \ upd_fdc.c \ + ti_m397.c \ + ti_m397ipc.c \ wd_fdc.c noinst_HEADERS = beta.h \ @@ -47,4 +49,6 @@ opus.h \ plusd.h \ upd_fdc.h \ + ti_m397.h \ + ti_m397ipc.h \ wd_fdc.h diff -Naru fuse-1.1.1-vanilla/peripherals/disk/Makefile.in fuse-1.1.1/peripherals/disk/Makefile.in --- fuse-1.1.1-vanilla/peripherals/disk/Makefile.in 2013-05-24 22:56:08.000000000 +0200 +++ fuse-1.1.1/peripherals/disk/Makefile.in 2014-02-21 11:36:56.000000000 +0100 @@ -75,7 +75,7 @@ libdisk_a_LIBADD = am_libdisk_a_OBJECTS = beta.$(OBJEXT) crc.$(OBJEXT) disciple.$(OBJEXT) \ disk.$(OBJEXT) fdd.$(OBJEXT) opus.$(OBJEXT) plusd.$(OBJEXT) \ - upd_fdc.$(OBJEXT) wd_fdc.$(OBJEXT) + upd_fdc.$(OBJEXT) ti_m397.$(OBJEXT) ti_m397ipc.$(OBJEXT) wd_fdc.$(OBJEXT) libdisk_a_OBJECTS = $(am_libdisk_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp @@ -281,6 +281,8 @@ opus.c \ plusd.c \ upd_fdc.c \ + ti_m397.c \ + ti_m397ipc.c \ wd_fdc.c noinst_HEADERS = beta.h \ @@ -291,6 +293,8 @@ opus.h \ plusd.h \ upd_fdc.h \ + ti_m397.h \ + ti_m397ipc.h \ wd_fdc.h all: all-am @@ -349,6 +353,8 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opus.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plusd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upd_fdc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ti_m397.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ti_m397ipc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wd_fdc.Po@am__quote@ .c.o: diff -Naru fuse-1.1.1-vanilla/peripherals/disk/ti_m397.c fuse-1.1.1/peripherals/disk/ti_m397.c --- fuse-1.1.1-vanilla/peripherals/disk/ti_m397.c 1970-01-01 01:00:00.000000000 +0100 +++ fuse-1.1.1/peripherals/disk/ti_m397.c 2014-02-21 12:53:49.314520701 +0100 @@ -0,0 +1,263 @@ +/****************************************************************************** + This file is a part od FDD3000 Emulator + + Copyright (C) 2013,2014 by SÅ‚awomir Szczyrba + Copyright (C) 2014 by Stefano Bodrato + + This program 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. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see +******************************************************************************/ + +//#define DEBUG 1 +#undef DEBUG + +#ifdef DEBUG + #define MSG(format, ...) fprintf (stderr, format, ## __VA_ARGS__) +#else + #define MSG(...) +#endif + +#include +#include +#include "settings.h" +#include "ui/ui.h" +#include "module.h" +#include "unittests/unittests.h" + +#include "ti_m397.h" +#include "ti_m397ipc.h" + +/*************************************************************************/ + +libspectrum_byte tim397_io_read( libspectrum_word port, int *attached ) { + libspectrum_byte b = 0; + if(ipc&&connected) { +//MSG("Reading from port: %u,",port&0xff); + if(fddIsAlive()) { b=fddRead(); } else { connected=0; /*semResetAll();*/ return 0; } + *attached = 1; + } +//MSG("%u\n",b&0xff); + return b; +} + +void tim397_io_write( libspectrum_word port, libspectrum_byte b ) { + if(ipc&&connected) { +//MSG("Writing %u to port: %u\n",b&0xff,port&0xff); + if(fddIsAlive()) { fddWrite(b); } else { connected=0; /*semResetAll();*/ } + } +} + +/*************************************************************************/ + +static void tim397_reset( int hard_reset ); +static void tim397_memory_map( void ); +static void tim397_enabled_snapshot( libspectrum_snap *snap ); +static void tim397_from_snapshot( libspectrum_snap *snap ); +static void tim397_to_snapshot( libspectrum_snap *snap ); +static void tim397_activate( void ); + + +/* Two 8Kb memory chunks accessible by the Z80 when /ROMCS is low */ +static memory_page tim397_memory_map_romcs_rom[ MEMORY_PAGES_IN_8K ]; +static memory_page tim397_memory_map_romcs_ram[ MEMORY_PAGES_IN_8K ]; +static int tim397_memory_source; + +int tim397_available = 0; +int tim397_active = 0; + +static libspectrum_byte *tim397_ram; +static int memory_allocated = 0; + +static module_info_t tim397_module_info = { + tim397_reset, + tim397_memory_map, + tim397_enabled_snapshot, + tim397_from_snapshot, + tim397_to_snapshot +}; + +void +tim397_page( void ) +{ + tim397_active = 1; + machine_current->ram.romcs = 1; + machine_current->memory_map(); + ui_statusbar_update( UI_STATUSBAR_ITEM_DISK, UI_STATUSBAR_STATE_ACTIVE ); + MSG("tim397_page\n"); +} + +void +tim397_unpage( void ) +{ + tim397_active = 0; + machine_current->ram.romcs = 0; + machine_current->memory_map(); + ui_statusbar_update( UI_STATUSBAR_ITEM_DISK, UI_STATUSBAR_STATE_INACTIVE ); + MSG("tim397_unpage\n"); +} + +static void +tim397_memory_map( void ) +{ + if( !tim397_active ) return; + memory_map_romcs_8k( 0x0000, tim397_memory_map_romcs_rom ); + memory_map_romcs_8k( 0x2000, tim397_memory_map_romcs_ram ); + MSG("tim397_memory_map\n"); +} + +static const periph_port_t tim397_ports[] = { + { 0x00ff, 0x00ef, tim397_io_read, tim397_io_write }, + { 0, 0, NULL, NULL } +}; + +static const periph_t tim397_periph = { + &settings_current.ti_m397, + tim397_ports, + 1, + tim397_activate +}; + +int +tim397_init( void ) +{ + int i; + module_register( &tim397_module_info ); + + tim397_memory_source = memory_source_register( "TI_M397" ); + for( i = 0; i < MEMORY_PAGES_IN_8K; i++ ) + tim397_memory_map_romcs_rom[ i ].source = tim397_memory_source; + for( i = 0; i < MEMORY_PAGES_IN_8K; i++ ) + tim397_memory_map_romcs_ram[ i ].source = tim397_memory_source; + periph_register( PERIPH_TYPE_TIM397, &tim397_periph ); + + ipc=0; + + MSG("tim397_init\n"); + + return 0; +} + + +static void +tim397_reset( int hard_reset ) +{ + int i; + + tim397_active = 0; + tim397_available = 0; + + if( !periph_is_active( PERIPH_TYPE_TIM397 ) ) { + ui_statusbar_update( UI_STATUSBAR_ITEM_DISK, + UI_STATUSBAR_STATE_NOT_AVAILABLE ); + MSG("FDD3000 is inactive\n"); + return; + } + + if (openShm()!=0) { +// settings_current.ti_m397 = 0; +// periph_activate_type( PERIPH_TYPE_TIM397, 0 ); + MSG("Link to FDD3000 emulator failed\n"); +// return; + } + + if( machine_load_rom_bank( tim397_memory_map_romcs_rom, 0, + settings_current.rom_tim397, + settings_default.rom_tim397, 0x1000 ) || + machine_load_rom_bank( tim397_memory_map_romcs_rom, 0x1000, + settings_current.rom_tim397, + settings_default.rom_tim397, 0x1000 ) ) { + settings_current.ti_m397 = 0; + periph_activate_type( PERIPH_TYPE_TIM397, 0 ); + ui_statusbar_update( UI_STATUSBAR_ITEM_DISK, + UI_STATUSBAR_STATE_NOT_AVAILABLE ); + MSG("Cannot load ROM file (%s, nor %s)\n",settings_current.rom_tim397,settings_default.rom_tim397); + return; + } + + machine_current->ram.romcs = 0; + + for( i = 0; i < MEMORY_PAGES_IN_8K; i++ ) { + tim397_memory_map_romcs_ram[ i ].page = &tim397_ram[ i * MEMORY_PAGE_SIZE ]; + tim397_memory_map_romcs_ram[ i ].writable = 1; + } + + tim397_available = 1; + tim397_active = 0; + + if( hard_reset ) { + memset( tim397_ram, 0, 0x2000 ); + } + + machine_current->memory_map(); + + ui_statusbar_update( UI_STATUSBAR_ITEM_DISK, UI_STATUSBAR_STATE_INACTIVE ); + MSG("tim397_reset\n"); +} + +void +tim397_end( void ) +{ + tim397_available = 0; + closeShm(); // ? // + cleanUp(); + MSG("tim397_end\n"); +} + +static void +tim397_activate( void ) +{ + if( !memory_allocated ) { + tim397_ram = memory_pool_allocate_persistent( 0x2000, 1 ); + memory_allocated = 1; + } + MSG("tim397_activate\n"); +} + +int +tim397_unittest( void ) +{ + int r = 0; + + tim397_page(); + + r += unittests_assert_16k_page( 0x0000, tim397_memory_source, 0 ); + r += unittests_assert_16k_ram_page( 0x4000, 5 ); + r += unittests_assert_16k_ram_page( 0x8000, 2 ); + r += unittests_assert_16k_ram_page( 0xc000, 0 ); + + tim397_unpage(); + + r += unittests_paging_test_48( 2 ); + + return r; +} + + +static void +tim397_enabled_snapshot( libspectrum_snap *snap ) +{ + return; +} + +static void +tim397_from_snapshot( libspectrum_snap *snap ) +{ + return; +} + +static void +tim397_to_snapshot( libspectrum_snap *snap GCC_UNUSED ) +{ + return; +} + diff -Naru fuse-1.1.1-vanilla/peripherals/disk/ti_m397.h fuse-1.1.1/peripherals/disk/ti_m397.h --- fuse-1.1.1-vanilla/peripherals/disk/ti_m397.h 1970-01-01 01:00:00.000000000 +0100 +++ fuse-1.1.1/peripherals/disk/ti_m397.h 2014-02-21 08:40:00.000000000 +0100 @@ -0,0 +1,24 @@ +/* + TIM397.h: Routines for handling the Timex TIM397 +*/ + +#ifndef FUSE_TIM397_H +#define FUSE_TIM397_H + +#include + +extern int tim397_available; /* Is the tim397 available for use? */ +extern int tim397_active; /* tim397 enabled? */ + +int tim397_init( void ); +void tim397_end( void ); + +void tim397_page( void ); +void tim397_unpage( void ); + +libspectrum_byte tim397_io_read( libspectrum_word port, int *attached ); +void tim397_io_write( libspectrum_word port, libspectrum_byte b ); + +int tim397_unittest( void ); + +#endif /* #ifndef FUSE_tim397_H */ diff -Naru fuse-1.1.1-vanilla/peripherals/disk/ti_m397ipc.c fuse-1.1.1/peripherals/disk/ti_m397ipc.c --- fuse-1.1.1-vanilla/peripherals/disk/ti_m397ipc.c 1970-01-01 01:00:00.000000000 +0100 +++ fuse-1.1.1/peripherals/disk/ti_m397ipc.c 2014-02-21 12:54:02.208140764 +0100 @@ -0,0 +1,360 @@ +/****************************************************************************** + This file is a part od FDD3000 Emulator + + Copyright (C) 2013,2014 by SÅ‚awomir Szczyrba + Copyright (C) 2014 by Stefano Bodrato + + This program 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. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see +******************************************************************************/ + +//#define DEBUG 1 +#undef DEBUG + +#ifdef DEBUG + #define MSG(format, ...) fprintf (stderr, format, ## __VA_ARGS__) +#else + #define MSG(...) +#endif + + +#include +#include + +#include +#include +#include +#include +#include /* For mode constants */ +#include +#include + + +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) + +#include +#include + +#else + +#include +#ifndef SEM_FAILED +#define SEM_FAILED -1 +#endif +#include +#include +#include +#include + +#endif + + + +/* IPC */ + +typedef struct tFdd2TiLink { + uint8_t fdd2ti; + uint8_t ti2fdd; + uint8_t fddAlive; + uint8_t tiAlive; +} fdd2TiLink; + +fdd2TiLink * fddlink; + +uint8_t data; +int ipc; +int connected; +char *path; + +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) + +HANDLE fdd2tiF, fdd2tiE, ti2fddF, ti2fddE, fddAlive; +HANDLE shm, shmf; +DWORD dwRetVal = 0; + +TCHAR *shmId = _T("\\fdd.data"); +TCHAR szTempFileName[MAX_PATH]; +TCHAR lpTempPathBuffer[MAX_PATH]; + +//char shmId[512]; +TCHAR fdd2tiE_Id[]=TEXT("Global\\fdd.fdd2ti.empty"); +TCHAR fdd2tiF_Id[]=TEXT("Global\\fdd.fdd2ti.full"); +TCHAR ti2fddE_Id[]=TEXT("Global\\fdd.ti2fdd.empty"); +TCHAR ti2fddF_Id[]=TEXT("Global\\fdd.ti2fdd.full"); +TCHAR fddAlive_Id[]=TEXT("Global\\fdd.alive"); + +#else + +int shm; +sem_t *fdd2tiF,*fdd2tiE,*ti2fddF,*ti2fddE,*fddAlive; +const char * shmId = "fdd.data"; +const char * fddAlive_Id = "fdd.alive"; +const char * fdd2tiE_Id = "fdd.fdd2ti.empty"; +const char * fdd2tiF_Id = "fdd.fdd2ti.full"; +const char * ti2fddE_Id = "fdd.ti2fdd.empty"; +const char * ti2fddF_Id = "fdd.ti2fdd.full"; + +#endif + +uint8_t fddRead() { + uint8_t data=0; +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) + if (WaitForSingleObject(fdd2tiF,INFINITE) == 0 ) { + data=fddlink->fdd2ti; + ReleaseSemaphore(fdd2tiE,1,NULL); + } else { connected = 0; } +#else + sem_wait(fdd2tiF); + data=fddlink->fdd2ti; + sem_post(fdd2tiE); +#endif + return data; +} + +void fddWrite(int8_t d) { +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) + if(WaitForSingleObject(ti2fddE,INFINITE) == 0 ) { + fddlink->ti2fdd=d; + ReleaseSemaphore(ti2fddF,1,NULL); + } else { connected = 0; } +#else + sem_wait(ti2fddE); + fddlink->ti2fdd=d; + sem_post(ti2fddF); +#endif +} + +uint8_t fddIsAlive() { + uint8_t ok; +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) + WaitForSingleObject(fddAlive,INFINITE); + ok=fddlink->fddAlive&fddlink->tiAlive; + ReleaseSemaphore(fddAlive,1,NULL); +#else + sem_wait(fddAlive); + ok=fddlink->fddAlive&fddlink->tiAlive; + sem_post(fddAlive); +#endif + return ok; +} + +void cleanUp() { + int i; + + connected=0; + if(!ipc) { return; } + ipc=0; + +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) + + WaitForSingleObject(fddAlive,INFINITE); + fddlink->tiAlive=0; + i=fddlink->fddAlive; + ReleaseSemaphore(fddAlive,1,NULL); + +// semResetAll(); + CloseHandle(fddAlive); + CloseHandle(ti2fddF); + CloseHandle(ti2fddE); + CloseHandle(fdd2tiF); + CloseHandle(fdd2tiE); + + UnmapViewOfFile(fddlink); + if(!i) { + CloseHandle(shm); + CloseHandle(shmf); + } + +#else + + sem_wait(fddAlive); + fddlink->tiAlive=0; + i=fddlink->fddAlive; + sem_post(fddAlive); + + sem_close(fddAlive); + sem_close(ti2fddF); + sem_close(ti2fddE); + sem_close(fdd2tiF); + sem_close(fdd2tiE); + + munmap(fddlink,sizeof(fdd2TiLink)); + if(!i) { + sem_unlink(fdd2tiE_Id); + sem_unlink(fdd2tiF_Id); + sem_unlink(ti2fddE_Id); + sem_unlink(ti2fddF_Id); + sem_unlink(fddAlive_Id); + shm_unlink(shmId); + } + +#endif + +} + +int openShm() { + int trunc; + int i; + + if(!ipc) { +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) + char * tmp; + +// tmp=getenv("TMP"); +// if(tmp==NULL) tmp=getenv("TEMP"); +// if(tmp==NULL) tmp="."; + +// strcpy(shmId,tmp); +// strcat(shmId,"\\fdd.data"); + dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer); // buffer for path + if (dwRetVal > MAX_PATH || (dwRetVal == 0)) { + MSG("tim397_openShm: GetTempPath failed\n"); + return -5; + } + snprintf(szTempFileName,MAX_PATH,"%s%s",lpTempPathBuffer,shmId); + + MSG("TMP Shm file : %s\n",szTempFileName); + + shmf = CreateFile( + szTempFileName, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + + if (shmf == NULL) { + MSG("failed to open file %s. ErrorCode: %d\n",shmId,GetLastError()); + return -1; + } + + shm = CreateFileMapping( + shmf, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // maximum object size (high-order DWORD) + 256, // maximum object size (low-order DWORD) + NULL + ); + + if(shm==NULL){ + MSG("failed to map file. ErrorCode: %d\n",GetLastError()); + CloseHandle(shmf); + return -2; + } + //fddlink=(fdd2TiLink*)mmap(0,sizeof(fdd2TiLink),PROT_READ|PROT_WRITE,MAP_SHARED,shm,0); + fddlink = (fdd2TiLink*)MapViewOfFile(shm, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + sizeof(fdd2TiLink) + ); + + if(fddlink==NULL){ + MSG("tim397_openShm: MapViewOfFile (mmap) failed\n"); + CloseHandle(shm); + CloseHandle(shmf); + return -3; + } + + fdd2tiE=OpenSemaphore(SEMAPHORE_MODIFY_STATE|SYNCHRONIZE,TRUE,fdd2tiE_Id); + if(fdd2tiE==NULL){MSG("failed to create sem fdd2tie. ErrorCode: %d\n",GetLastError()); } + + fdd2tiF=OpenSemaphore(SEMAPHORE_MODIFY_STATE|SYNCHRONIZE,TRUE,fdd2tiF_Id); + if(fdd2tiF==NULL){MSG("failed to create sem fdd2tif. ErrorCode: %d\n",GetLastError()); } + + ti2fddE=OpenSemaphore(SEMAPHORE_MODIFY_STATE|SYNCHRONIZE,TRUE,ti2fddE_Id); + if(ti2fddE==NULL){MSG("failed to create sem ti2fdde. ErrorCode: %d\n",GetLastError()); } + + ti2fddF=OpenSemaphore(SEMAPHORE_MODIFY_STATE|SYNCHRONIZE,TRUE,ti2fddF_Id); + if(ti2fddF==NULL){MSG("failed to create sem ti2fddf. ErrorCode: %d\n",GetLastError()); } + + fddAlive=OpenSemaphore(SEMAPHORE_MODIFY_STATE|SYNCHRONIZE,TRUE,fddAlive_Id); + if(fddAlive==NULL){MSG("failed to create sem sync. ErrorCode: %d\n",GetLastError()); } + + if ((fdd2tiE==NULL) || (fdd2tiF==NULL) || (ti2fddE==NULL) || (ti2fddF==NULL) || (fddAlive==NULL)) { + MSG("tim397_openShm: semaphore creation failed\n"); + return -4; + } + +#else + + shm = shm_open(shmId, O_RDWR, 0666); + if (-1==shm) { + MSG("tim397_openShm: shm_open file %s failed\n",shmId); + return -1; + } + trunc=ftruncate(shm,sizeof(fdd2TiLink)); + if (-1==trunc) { + MSG("tim397_openShm: ftruncate failed\n"); + return -2; + } + fddlink=(fdd2TiLink*)mmap(0,sizeof(fdd2TiLink),PROT_READ|PROT_WRITE,MAP_SHARED,shm,0); + if(fddlink==MAP_FAILED) { + MSG("tim397_openShm: mmap failed\n"); + return -3; + } + close(shm); + + fdd2tiE=sem_open(fdd2tiE_Id,O_RDWR,0666,1); + if( SEM_FAILED == fdd2tiE) { MSG("fdd2tiE open failed\n"); } + + fdd2tiF=sem_open(fdd2tiF_Id,O_RDWR,0666,0); + if( SEM_FAILED == fdd2tiF) { MSG("fdd2tiF open failed\n"); } + + ti2fddE=sem_open(ti2fddE_Id,O_RDWR,0666,1); + if( SEM_FAILED == ti2fddE) { MSG("ti2fddE open failed\n"); } + + ti2fddF=sem_open(ti2fddF_Id,O_RDWR,0666,0); + if( SEM_FAILED == ti2fddF) { MSG("ti2fddF open failed\n"); } + + fddAlive=sem_open(fddAlive_Id,O_RDWR,0666,1); + if( SEM_FAILED == fddAlive){ MSG("fddAlive open failed\n"); } + + if ((fdd2tiE==SEM_FAILED) || (fdd2tiF==SEM_FAILED) || (ti2fddE==SEM_FAILED) || (ti2fddF==SEM_FAILED) || (fddAlive==SEM_FAILED)) { + MSG("tim397_openShm: semaphore creation failed\n"); + return -4; + } +#endif + ipc=1; + } + if(ipc&&(!connected)) { +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) + WaitForSingleObject(fddAlive,INFINITE); + if(fddlink->fddAlive){ fddlink->tiAlive=1; connected=1; } + ReleaseSemaphore(fddAlive,1,NULL); +#else + sem_wait(fddAlive); + if(fddlink->fddAlive){ fddlink->tiAlive=1; connected=1; } + sem_post(fddAlive); +#endif + } + return (0); +} + + +void closeShm(void) { + if(ipc&&connected) { +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__) + WaitForSingleObject(fddAlive,INFINITE); + fddlink->tiAlive=0; + ReleaseSemaphore(fddAlive,1,NULL); +#else + sem_wait(fddAlive); + fddlink->tiAlive=0; + sem_post(fddAlive); +#endif + } +} diff -Naru fuse-1.1.1-vanilla/peripherals/disk/ti_m397ipc.h fuse-1.1.1/peripherals/disk/ti_m397ipc.h --- fuse-1.1.1-vanilla/peripherals/disk/ti_m397ipc.h 1970-01-01 01:00:00.000000000 +0100 +++ fuse-1.1.1/peripherals/disk/ti_m397ipc.h 2014-02-21 09:59:00.000000000 +0100 @@ -0,0 +1,21 @@ +/* + TIM397.h: Routines for handling the Timex TIM397 +*/ + +#ifndef FUSE_TIM397IPC_H +#define FUSE_TIM397IPC_H + +#include + +extern int ipc; +extern int connected; + +int openShm(void); +void closeShm(void); +void cleanUp(void); + +int fddIsAlive(void); +uint8_t fddRead(void); +void fddWrite(uint8_t); + +#endif /* #ifndef FUSE_tim397ipc_H */ diff -Naru fuse-1.1.1-vanilla/periph.h fuse-1.1.1/periph.h --- fuse-1.1.1-vanilla/periph.h 2013-05-24 22:42:22.000000000 +0200 +++ fuse-1.1.1/periph.h 2014-02-21 12:46:19.951241793 +0100 @@ -65,6 +65,7 @@ PERIPH_TYPE_SPECCYBOOT, /* SpeccyBoot interface */ PERIPH_TYPE_SPECDRUM, /* SpecDrum interface */ PERIPH_TYPE_SPECTRANET, /* Spectranet interface */ + PERIPH_TYPE_TIM397, /* FDD3000 disk interface */ PERIPH_TYPE_ULA, /* Standard ULA */ PERIPH_TYPE_ULA_FULL_DECODE,/* Standard ULA responding only to 0xfe */ PERIPH_TYPE_UPD765, /* +3 uPD765 FDC */ diff -Naru fuse-1.1.1-vanilla/settings.dat fuse-1.1.1/settings.dat --- fuse-1.1.1-vanilla/settings.dat 2013-05-16 22:26:23.000000000 +0200 +++ fuse-1.1.1/settings.dat 2014-02-21 12:46:19.951241793 +0100 @@ -64,6 +64,7 @@ interface2, boolean, 1 snapsasz80, null, 0 opus, boolean, 0 +ti_m397, boolean, 0 pal_tv2x, boolean, 0 movie_compr, string, NULL movie_start, string, NULL @@ -235,6 +236,7 @@ rom_plusd, string, "plusd.rom", rom_disciple, string, "disciple.rom", rom_opus, string, "opus.rom", +rom_tim397, string, "ti_m397.rom", rom_speccyboot, string, "speccyboot-1.4.rom", drive_plus3a_type, string, NULL diff -Naru fuse-1.1.1-vanilla/settings.pl fuse-1.1.1/settings.pl --- fuse-1.1.1-vanilla/settings.pl 2013-05-24 22:42:22.000000000 +0200 +++ fuse-1.1.1/settings.pl 2014-02-21 12:46:19.951241793 +0100 @@ -762,7 +762,8 @@ case 42: return &( settings->rom_plusd ); case 43: return &( settings->rom_disciple ); case 44: return &( settings->rom_opus ); - case 45: return &( settings->rom_speccyboot ); + case 45: return &( settings->rom_tim397 ); + case 46: return &( settings->rom_speccyboot ); default: return NULL; } } diff -Naru fuse-1.1.1-vanilla/ui/options.dat fuse-1.1.1/ui/options.dat --- fuse-1.1.1-vanilla/ui/options.dat 2013-05-24 22:42:22.000000000 +0200 +++ fuse-1.1.1/ui/options.dat 2014-02-21 12:46:19.951241793 +0100 @@ -64,6 +64,7 @@ Checkbox, (B)eta 128 interface, beta128, INPUT_KEY_b Checkbox, Beta 128 (a)uto-boot in 48K machines, beta128_48boot, INPUT_KEY_a Checkbox, (O)pus Discovery interface, opus, INPUT_KEY_o +Checkbox, FDD(3)000 / M397 interface, ti_m397, INPUT_KEY_3 Postcheck, periph_postcheck Posthook, periph_posthook diff -Naru fuse-1.1.1-vanilla/ui/ui.h fuse-1.1.1/ui/ui.h --- fuse-1.1.1-vanilla/ui/ui.h 2013-05-16 22:26:23.000000000 +0200 +++ fuse-1.1.1/ui/ui.h 2014-02-21 12:46:19.951241793 +0100 @@ -39,6 +39,7 @@ #include "peripherals/disk/beta.h" #include "peripherals/disk/disciple.h" #include "peripherals/disk/opus.h" +#include "peripherals/disk/ti_m397.h" #include "peripherals/disk/plusd.h" #include "ui/scaler/scaler.h" @@ -211,6 +212,7 @@ UI_MENU_ITEM_MEDIA_DISK_OPUS_2_EJECT, UI_MENU_ITEM_MEDIA_DISK_OPUS_2_FLIP_SET, UI_MENU_ITEM_MEDIA_DISK_OPUS_2_WP_SET, + UI_MENU_ITEM_MEDIA_DISK_TIM397, UI_MENU_ITEM_MEDIA_IDE, UI_MENU_ITEM_MEDIA_IDE_SIMPLE8BIT, UI_MENU_ITEM_MEDIA_IDE_SIMPLE8BIT_MASTER_EJECT, diff -Naru fuse-1.1.1-vanilla/ui.c fuse-1.1.1/ui.c --- fuse-1.1.1-vanilla/ui.c 2013-05-16 22:26:23.000000000 +0200 +++ fuse-1.1.1/ui.c 2014-02-21 12:46:19.951241793 +0100 @@ -548,6 +548,8 @@ "/Media/Disk/Opus/Drive 2/Write protect/Enable", "/Media/Disk/Opus/Drive 2/Write protect/Disable", 1 }, + { UI_MENU_ITEM_MEDIA_DISK_TIM397, "/Media/Disk/Timex M397" }, + { UI_MENU_ITEM_MEDIA_IDE, "/Media/IDE" }, { UI_MENU_ITEM_MEDIA_IDE_SIMPLE8BIT, "/Media/IDE/Simple 8-bit" }, diff -Naru fuse-1.1.1-vanilla/z80/coretest.c fuse-1.1.1/z80/coretest.c --- fuse-1.1.1-vanilla/z80/coretest.c 2013-05-16 22:26:16.000000000 +0200 +++ fuse-1.1.1/z80/coretest.c 2014-02-21 12:46:19.951241793 +0100 @@ -459,6 +459,21 @@ abort(); } +int tim397_available = 0; +int tim397_active = 0; + +void +tim397_page( void ) +{ + abort(); +} + +void +tim397_unpage( void ) +{ + abort(); +} + int plusd_available = 0; int plusd_active = 0; diff -Naru fuse-1.1.1-vanilla/z80/z80_checks.h fuse-1.1.1/z80/z80_checks.h --- fuse-1.1.1-vanilla/z80/z80_checks.h 2013-05-16 22:26:16.000000000 +0200 +++ fuse-1.1.1/z80/z80_checks.h 2014-02-21 12:46:19.951241793 +0100 @@ -2,6 +2,7 @@ SETUP_CHECK( rzx, rzx_playback ) SETUP_CHECK( debugger, debugger_mode != DEBUGGER_MODE_INACTIVE ) SETUP_CHECK( beta, beta_available ) +SETUP_CHECK( tim397, tim397_available ) SETUP_CHECK( plusd, plusd_available ) SETUP_CHECK( disciple, disciple_available ) SETUP_CHECK( if1p, if1_available ) diff -Naru fuse-1.1.1-vanilla/z80/z80_ops.c fuse-1.1.1/z80/z80_ops.c --- fuse-1.1.1-vanilla/z80/z80_ops.c 2013-05-16 22:26:16.000000000 +0200 +++ fuse-1.1.1/z80/z80_ops.c 2014-02-21 12:46:19.951241793 +0100 @@ -36,6 +36,7 @@ #include "peripherals/disk/disciple.h" #include "peripherals/disk/opus.h" #include "peripherals/disk/plusd.h" +#include "peripherals/disk/ti_m397.h" #include "peripherals/ide/divide.h" #include "peripherals/if1.h" #include "peripherals/spectranet.h" @@ -176,6 +177,18 @@ } END_CHECK + + CHECK( tim397, tim397_available ) + + if( tim397_active ) { + if( PC == 0x0604 ) { + tim397_unpage(); + } + } else if( PC == 0x0000 || PC == 0x0008 ) { + tim397_page(); + } + + END_CHECK CHECK( plusd, plusd_available )