1 diff -Naru fuse-1.1.1/fuse.c fuse-1.1.1.fdd3000/fuse.c
2 --- fuse-1.1.1/fuse.c 2013-05-16 22:26:23.000000000 +0200
3 +++ fuse-1.1.1.fdd3000/fuse.c 2014-02-14 08:28:21.228997802 +0100
12 diff -Naru fuse-1.1.1/machines/machines_periph.c fuse-1.1.1.fdd3000/machines/machines_periph.c
13 --- fuse-1.1.1/machines/machines_periph.c 2013-05-16 22:26:11.000000000 +0200
14 +++ fuse-1.1.1.fdd3000/machines/machines_periph.c 2014-02-14 08:30:34.228014927 +0100
16 periph_set_present( PERIPH_TYPE_FULLER, PERIPH_PRESENT_OPTIONAL );
17 periph_set_present( PERIPH_TYPE_ZXPRINTER, PERIPH_PRESENT_OPTIONAL );
18 periph_set_present( PERIPH_TYPE_DISCIPLE, PERIPH_PRESENT_OPTIONAL );
19 + periph_set_present( PERIPH_TYPE_TIM397, PERIPH_PRESENT_OPTIONAL );
22 /* The set of peripherals available on the 128K and similar machines */
23 diff -Naru fuse-1.1.1/Makefile.in fuse-1.1.1.fdd3000/Makefile.in
24 --- fuse-1.1.1/Makefile.in 2013-05-30 00:21:33.000000000 +0200
25 +++ fuse-1.1.1.fdd3000/Makefile.in 2014-02-14 08:33:02.997237928 +0100
27 LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
29 LIBPNG_CONFIG = @LIBPNG_CONFIG@
32 LIBSPEC_CFLAGS = @LIBSPEC_CFLAGS@
33 LIBSPEC_HAVE_AUDIOFILE = @LIBSPEC_HAVE_AUDIOFILE@
34 LIBSPEC_HAVE_BZ2 = @LIBSPEC_HAVE_BZ2@
35 diff -Naru fuse-1.1.1/memory.c fuse-1.1.1.fdd3000/memory.c
36 --- fuse-1.1.1/memory.c 2013-05-16 22:26:23.000000000 +0200
37 +++ fuse-1.1.1.fdd3000/memory.c 2014-02-14 08:21:36.769616238 +0100
41 #include "peripherals/disk/opus.h"
42 +#include "peripherals/disk/ti_m397.h"
43 #include "peripherals/spectranet.h"
44 #include "peripherals/ula.h"
46 diff -Naru fuse-1.1.1/menu.c fuse-1.1.1.fdd3000/menu.c
47 --- fuse-1.1.1/menu.c 2013-05-16 22:26:23.000000000 +0200
48 +++ fuse-1.1.1.fdd3000/menu.c 2014-02-14 08:21:36.769616238 +0100
50 #include "peripherals/disk/beta.h"
51 #include "peripherals/disk/disciple.h"
52 #include "peripherals/disk/opus.h"
53 +#include "peripherals/disk/ti_m397.h"
54 #include "peripherals/disk/plusd.h"
55 #include "peripherals/ide/divide.h"
56 #include "peripherals/ide/simpleide.h"
58 case 18: menu_select_roms_with_title( "+D", 42, 1 ); return;
59 case 19: menu_select_roms_with_title( "DISCiPLE", 43, 1 ); return;
60 case 20: menu_select_roms_with_title( "Opus Discovery", 44, 1 ); return;
61 - case 21: menu_select_roms_with_title( "SpeccyBoot", 45, 1 ); return;
62 + case 21: menu_select_roms_with_title( "Timex M397", 45, 1 ); return;
63 + case 22: menu_select_roms_with_title( "SpeccyBoot", 46, 1 ); return;
67 diff -Naru fuse-1.1.1/menu_data.dat fuse-1.1.1.fdd3000/menu_data.dat
68 --- fuse-1.1.1/menu_data.dat 2013-05-16 22:26:23.000000000 +0200
69 +++ fuse-1.1.1.fdd3000/menu_data.dat 2014-02-14 08:21:36.769616238 +0100
71 Options/Select ROMs/+_D..., Item,, menu_options_selectroms_select,, 18
72 Options/Select ROMs/DISCiP_LE..., Item,, menu_options_selectroms_select,, 19
73 Options/Select ROMs/_Opus Discovery..., Item,, menu_options_selectroms_select,, 20
74 -Options/Select ROMs/Specc_yBoot..., Item,, menu_options_selectroms_select,, 21
75 +Options/Select ROMs/_Timex M397..., Item,, menu_options_selectroms_select,, 21
76 +Options/Select ROMs/Specc_yBoot..., Item,, menu_options_selectroms_select,, 22
78 Options/_Filter..., Item,,, menu_filter_detail
80 diff -Naru fuse-1.1.1/peripherals/disk/Makefile.am fuse-1.1.1.fdd3000/peripherals/disk/Makefile.am
81 --- fuse-1.1.1/peripherals/disk/Makefile.am 2013-05-16 22:26:03.000000000 +0200
82 +++ fuse-1.1.1.fdd3000/peripherals/disk/Makefile.am 2014-02-14 08:21:36.769616238 +0100
90 noinst_HEADERS = beta.h \
97 diff -Naru fuse-1.1.1/peripherals/disk/Makefile.in fuse-1.1.1.fdd3000/peripherals/disk/Makefile.in
98 --- fuse-1.1.1/peripherals/disk/Makefile.in 2013-05-24 22:56:08.000000000 +0200
99 +++ fuse-1.1.1.fdd3000/peripherals/disk/Makefile.in 2014-02-14 08:32:46.900294664 +0100
102 am_libdisk_a_OBJECTS = beta.$(OBJEXT) crc.$(OBJEXT) disciple.$(OBJEXT) \
103 disk.$(OBJEXT) fdd.$(OBJEXT) opus.$(OBJEXT) plusd.$(OBJEXT) \
104 - upd_fdc.$(OBJEXT) wd_fdc.$(OBJEXT)
105 + upd_fdc.$(OBJEXT) ti_m397.$(OBJEXT) wd_fdc.$(OBJEXT)
106 libdisk_a_OBJECTS = $(am_libdisk_a_OBJECTS)
107 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
108 depcomp = $(SHELL) $(top_srcdir)/depcomp
116 noinst_HEADERS = beta.h \
126 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opus.Po@am__quote@
127 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plusd.Po@am__quote@
128 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upd_fdc.Po@am__quote@
129 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ti_m397.Po@am__quote@
130 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wd_fdc.Po@am__quote@
133 diff -Naru fuse-1.1.1/peripherals/disk/ti_m397.c fuse-1.1.1.fdd3000/peripherals/disk/ti_m397.c
134 --- fuse-1.1.1/peripherals/disk/ti_m397.c 1970-01-01 01:00:00.000000000 +0100
135 +++ fuse-1.1.1.fdd3000/peripherals/disk/ti_m397.c 2014-02-14 08:53:54.159789884 +0100
137 +/******************************************************************************
138 + This file is a part od FDD3000 Emulator
140 + Copyright (C) 2013 by SÅ‚awomir Szczyrba <sszczyrba@gmail.com>
141 + Copyright (C) 2014 by Stefano Bodrato <stefano_bodrato hotmail dt com>
143 + This program is free software: you can redistribute it and/or modify it under
144 + the terms of the GNU Lesser General Public License as published by the Free
145 + Software Foundation, either version 2 of the License, or (at your option) any
148 + This program is distributed in the hope that it will be useful, but WITHOUT
149 + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
150 + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
153 + You should have received a copy of the GNU Lesser General Public License
154 + along with this program. If not, see <http://www.gnu.org/licenses/lgpl.html>
155 +******************************************************************************/
160 +#include <libspectrum.h>
165 +#include "machine.h"
167 +#include "ti_m397.h"
168 +#include "peripherals/printer.h"
169 +#include "settings.h"
171 +#include "unittests/unittests.h"
172 +//#include "utils.h"
174 +#include "options.h" /* needed for get combo options */
175 +#include "z80/z80.h"
183 +#include <sys/stat.h> /* For mode constants */
184 +#include <sys/types.h>
188 +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__)
190 +#include <windows.h>
195 +#include <semaphore.h>
197 +#define SEM_FAILED -1
199 +#include <sys/mman.h>
200 +#include <sys/ipc.h>
201 +#include <sys/msg.h>
202 +#include <sys/socket.h>
210 +typedef struct tFdd2TiLink {
217 +fdd2TiLink * fddlink;
226 +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__)
228 +HANDLE fdd2tiF, fdd2tiE, ti2fddF, ti2fddE, fddAlive;
232 +TCHAR *shmId = _T("\\fdd.data");
233 +//TCHAR shmId[]=TEXT("Global\\fdd.data");
234 +TCHAR szTempFileName[MAX_PATH];
235 +TCHAR lpTempPathBuffer[MAX_PATH];
237 +TCHAR fdd2tiE_Id[]=TEXT("Global\\fdd.fdd2ti.empty");
238 +TCHAR fdd2tiF_Id[]=TEXT("Global\\fdd.fdd2ti.full");
239 +TCHAR ti2fddE_Id[]=TEXT("Global\\fdd.ti2fdd.empty");
240 +TCHAR ti2fddF_Id[]=TEXT("Global\\fdd.ti2fdd.full");
241 +TCHAR fddAlive_Id[]=TEXT("Global\\fdd.alive");
243 +TCHAR * fddAlive_Id = "fdd.alive";
244 +TCHAR * fdd2tiE_Id = "fdd.fdd2ti.empty";
245 +TCHAR * fdd2tiF_Id = "fdd.fdd2ti.full";
246 +TCHAR * ti2fddE_Id = "fdd.ti2fdd.empty";
247 +TCHAR * ti2fddF_Id = "fdd.ti2fdd.full";
251 +sem_t *fdd2tiF,*fdd2tiE,*ti2fddF,*ti2fddE,*fddAlive;
253 +const char * shmId = "fdd.data";
255 +const char * fddAlive_Id = "fdd.alive";
256 +const char * fdd2tiE_Id = "fdd.fdd2ti.empty";
257 +const char * fdd2tiF_Id = "fdd.fdd2ti.full";
258 +const char * ti2fddE_Id = "fdd.ti2fdd.empty";
259 +const char * ti2fddF_Id = "fdd.ti2fdd.full";
265 +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__)
266 + WaitForSingleObject(ti2fddF,INFINITE);
267 + data=fddlink->fdd2ti;
268 + ReleaseSemaphore(ti2fddE,1,NULL);
271 + data=fddlink->fdd2ti;
277 +void fddWrite(int8_t d) {
278 +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__)
279 + WaitForSingleObject(ti2fddE,INFINITE);
281 + ReleaseSemaphore(ti2fddF,1,NULL);
289 +uint8_t fddIsAlive() {
291 +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__)
292 + WaitForSingleObject(fddAlive,INFINITE);
293 + ok=fddlink->fddAlive&fddlink->tiAlive;
294 + ReleaseSemaphore(fddAlive,1,NULL);
296 + sem_wait(fddAlive);
297 + ok=fddlink->fddAlive&fddlink->tiAlive;
298 + sem_post(fddAlive);
305 + if(!ipc) { return; }
309 +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__)
311 + WaitForSingleObject(fddAlive,INFINITE);
312 + fddlink->tiAlive=0;
313 + i=fddlink->fddAlive;
314 + ReleaseSemaphore(fddAlive,1,NULL);
317 + CloseHandle(fddAlive);
318 + CloseHandle(ti2fddF);
319 + CloseHandle(ti2fddE);
320 + CloseHandle(fdd2tiF);
321 + CloseHandle(fdd2tiE);
323 + UnmapViewOfFile(fddlink);
331 + sem_wait(fddAlive);
332 + fddlink->tiAlive=0;
333 + i=fddlink->fddAlive;
334 + sem_post(fddAlive);
337 + sem_close(fddAlive);
338 + sem_close(ti2fddF);
339 + sem_close(ti2fddE);
340 + sem_close(fdd2tiF);
341 + sem_close(fdd2tiE);
343 + munmap(fddlink,sizeof(fdd2TiLink));
345 + sem_unlink(fdd2tiE_Id);
346 + sem_unlink(fdd2tiF_Id);
347 + sem_unlink(ti2fddE_Id);
348 + sem_unlink(ti2fddF_Id);
349 + sem_unlink(fddAlive_Id);
360 +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__)
361 + //shmfile=ev.value("TMP",ev.value("TEMP","."))+"\\fdd.data";
363 + // Gets the temp path env string (no guarantee it's a valid path).
364 + dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer); // buffer for path
365 + if (dwRetVal > MAX_PATH || (dwRetVal == 0))
367 +// fprintf(stderr,"tim397_openShm: GetTempPath failed\n");
370 + snprintf(szTempFileName,MAX_PATH,"%s%s",lpTempPathBuffer,shmId);
372 + shmf = CreateFile(szTempFileName, GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
374 + if (shmf == INVALID_HANDLE_VALUE)
376 + //ui_error( UI_ERROR_ERROR, "tim397_openShm: CreateFile failed\n");
380 + shm = CreateFileMapping(
381 + shmf,//INVALID_HANDLE_VALUE, // use paging file
382 + NULL, // default security
383 + PAGE_READWRITE, // read/write access
384 + 0, // maximum object size (high-order DWORD)
385 + 256, // maximum object size (low-order DWORD)
386 + NULL);//TEXT("Global\\shmFdd")); // name of mapping object
388 + //ui_error( UI_ERROR_ERROR, "tim397_openShm: CreateFileMapping failed\n");
392 + //fddlink=(fdd2TiLink*)mmap(0,sizeof(fdd2TiLink),PROT_READ|PROT_WRITE,MAP_SHARED,shm,0);
393 + fddlink = (fdd2TiLink*)MapViewOfFile(shm, // handle to map object
394 + FILE_MAP_ALL_ACCESS, // read/write permission
397 + sizeof(fdd2TiLink));
399 + //ui_error( UI_ERROR_ERROR, "tim397_openShm: MapViewOfFile (mmap) failed\n");
405 + fdd2tiE=OpenSemaphore(SEMAPHORE_MODIFY_STATE|SYNCHRONIZE, TRUE, fdd2tiE_Id);
406 + fdd2tiF=OpenSemaphore(SEMAPHORE_MODIFY_STATE|SYNCHRONIZE, TRUE, fdd2tiF_Id);
407 + ti2fddE=OpenSemaphore(SEMAPHORE_MODIFY_STATE|SYNCHRONIZE, TRUE, ti2fddE_Id);
408 + ti2fddF=OpenSemaphore(SEMAPHORE_MODIFY_STATE|SYNCHRONIZE, TRUE, ti2fddF_Id);
409 + fddAlive=OpenSemaphore(SEMAPHORE_MODIFY_STATE|SYNCHRONIZE, TRUE, fddAlive_Id);
411 + if ((fdd2tiE==NULL) || (fdd2tiF==NULL) ||
412 + (ti2fddE==NULL) || (ti2fddF==NULL) || (fddAlive==NULL)) {
413 + //ui_error( UI_ERROR_ERROR, "tim397_openShm: semaphore creation failed\n");
418 + shm = shm_open(shmId, O_RDWR, 0666);
420 + //ui_error( UI_ERROR_ERROR, "tim397_openShm: shm_open failed\n");
423 + trunc=ftruncate(shm,sizeof(fdd2TiLink));
425 + //ui_error( UI_ERROR_ERROR, "tim397_openShm: ftruncate failed\n");
428 + fddlink=(fdd2TiLink*)mmap(0,sizeof(fdd2TiLink),PROT_READ|PROT_WRITE,MAP_SHARED,shm,0);
429 + if(fddlink==MAP_FAILED) {
430 + //ui_error( UI_ERROR_ERROR, "tim397_openShm: mmap failed\n");
435 + fdd2tiE=sem_open(fdd2tiE_Id,O_RDWR,0666,1);
436 + fdd2tiF=sem_open(fdd2tiF_Id,O_RDWR,0666,0);
437 + ti2fddE=sem_open(ti2fddE_Id,O_RDWR,0666,1);
438 + ti2fddF=sem_open(ti2fddF_Id,O_RDWR,0666,0);
439 + fddAlive=sem_open(fddAlive_Id,O_RDWR,0666,1);
440 + if ((fdd2tiE==SEM_FAILED) || (fdd2tiF==SEM_FAILED) ||
441 + (ti2fddE==SEM_FAILED) || (ti2fddF==SEM_FAILED) || (fddAlive==SEM_FAILED)) {
442 + //ui_error( UI_ERROR_ERROR, "tim397_openShm: semaphore creation failed\n");
449 + if(ipc&&(!connected)) {
450 +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__)
451 + WaitForSingleObject(fddAlive,INFINITE);
452 + if(fddlink->fddAlive){ fddlink->tiAlive=1; connected=1; }
453 + ReleaseSemaphore(fddAlive,1,NULL);
455 + sem_wait(fddAlive);
456 + if(fddlink->fddAlive){ fddlink->tiAlive=1; connected=1; }
457 + sem_post(fddAlive);
465 +/*************************************************************************/
467 +libspectrum_byte tim397_io_read( libspectrum_word port, int *attached ) {
468 + libspectrum_byte b = 0;
469 +//ui_error( UI_ERROR_ERROR, "Reading from port: %u\n",port);
470 + if(ipc&&connected) {
471 +//ui_error( UI_ERROR_ERROR, "Reading from port: %u\n",port);
472 + if(fddIsAlive()) { b=fddRead(); } else { connected=0; /*semResetAll();*/ return 0; }
478 +void tim397_io_write( libspectrum_word port, libspectrum_byte b ) {
479 +//ui_error( UI_ERROR_ERROR, "Writing %u to port: %u\n",b,port);
480 + if(ipc&&connected) {
481 +//ui_error( UI_ERROR_ERROR, "Writing %u to port: %u\n",b,port);
482 +// if ((port&&0xff) == 0xef)
483 + if(fddIsAlive()) { fddWrite(b); } else { connected=0; /*semResetAll();*/ }
487 +/*************************************************************************/
489 +static void tim397_reset( int hard_reset );
490 +static void tim397_memory_map( void );
491 +static void tim397_enabled_snapshot( libspectrum_snap *snap );
492 +static void tim397_from_snapshot( libspectrum_snap *snap );
493 +static void tim397_to_snapshot( libspectrum_snap *snap );
494 +static void tim397_activate( void );
497 +/* Two 8Kb memory chunks accessible by the Z80 when /ROMCS is low */
498 +static memory_page tim397_memory_map_romcs_rom[ MEMORY_PAGES_IN_8K ];
499 +static memory_page tim397_memory_map_romcs_ram[ MEMORY_PAGES_IN_8K ];
500 +static int tim397_memory_source;
502 +int tim397_available = 0;
503 +int tim397_active = 0;
505 +static libspectrum_byte *tim397_ram;
506 +static int memory_allocated = 0;
508 +static module_info_t tim397_module_info = {
511 + tim397_enabled_snapshot,
512 + tim397_from_snapshot,
520 + machine_current->ram.romcs = 1;
521 + machine_current->memory_map();
522 + //ui_error( UI_ERROR_ERROR, "tim397_page, PC: $%x\n",m397_pageflag);
523 + ui_statusbar_update( UI_STATUSBAR_ITEM_DISK, UI_STATUSBAR_STATE_ACTIVE );
527 +tim397_unpage( void )
530 + machine_current->ram.romcs = 0;
531 + machine_current->memory_map();
532 + //ui_error( UI_ERROR_ERROR, "tim397_unpage, PC: $%x\n",z80.pc.w);
533 + ui_statusbar_update( UI_STATUSBAR_ITEM_DISK, UI_STATUSBAR_STATE_INACTIVE );
537 +tim397_memory_map( void )
539 + if( !tim397_active ) return;
540 + memory_map_romcs_8k( 0x0000, tim397_memory_map_romcs_rom );
541 + memory_map_romcs_8k( 0x2000, tim397_memory_map_romcs_ram );
542 +// ui_error( UI_ERROR_ERROR, "tim397_memory_map, PC: $%x\n",z80.pc.w);
545 +static const periph_port_t tim397_ports[] = {
546 + { 0x00ff, 0x00ef, tim397_io_read, tim397_io_write },
547 + { 0, 0, NULL, NULL }
550 +static const periph_t tim397_periph = {
551 + &settings_current.ti_m397,
561 + module_register( &tim397_module_info );
563 + tim397_memory_source = memory_source_register( "TI_M397" );
565 + for( i = 0; i < MEMORY_PAGES_IN_8K; i++ )
566 + tim397_memory_map_romcs_rom[ i ].source = tim397_memory_source;
567 + for( i = 0; i < MEMORY_PAGES_IN_8K; i++ )
568 + tim397_memory_map_romcs_ram[ i ].source = tim397_memory_source;
570 + periph_register( PERIPH_TYPE_TIM397, &tim397_periph );
573 + fprintf(stderr,"tim397_init\n");
580 +tim397_reset( int hard_reset )
584 + tim397_available = 0;
587 + if( !periph_is_active( PERIPH_TYPE_TIM397 ) ) {
588 + ui_statusbar_update( UI_STATUSBAR_ITEM_DISK,
589 + UI_STATUSBAR_STATE_NOT_AVAILABLE );
593 + if (openShm()!=0) {
594 + settings_current.ti_m397 = 0;
595 + periph_activate_type( PERIPH_TYPE_TIM397, 0 );
596 +// ui_error( UI_ERROR_ERROR, "Link to FDD3000 emulator failed\n");
600 + if( machine_load_rom_bank( tim397_memory_map_romcs_rom, 0,
601 + settings_current.rom_tim397,
602 + settings_default.rom_tim397, 0x2000 ) ) {
603 + settings_current.ti_m397 = 0;
604 + periph_activate_type( PERIPH_TYPE_TIM397, 0 );
605 + ui_statusbar_update( UI_STATUSBAR_ITEM_DISK,
606 + UI_STATUSBAR_STATE_NOT_AVAILABLE );
610 + machine_current->ram.romcs = 0;
612 + for( i = 0; i < MEMORY_PAGES_IN_8K; i++ ) {
613 + tim397_memory_map_romcs_ram[ i ].page = &tim397_ram[ i * MEMORY_PAGE_SIZE ];
614 + tim397_memory_map_romcs_ram[ i ].writable = 1;
617 + tim397_available = 1;
621 + memset( tim397_ram, 0, 0x2000 );
624 + machine_current->memory_map();
625 + ui_statusbar_update( UI_STATUSBAR_ITEM_DISK, UI_STATUSBAR_STATE_INACTIVE );
626 + fprintf(stderr,"tim397_reset\n");
632 + tim397_available = 0;
634 + if(ipc&&connected) {
635 +#if defined (__MINGW32__) || defined (_WIN32) || defined (_WIN32_) || defined (__WIN32__)
636 + WaitForSingleObject(fddAlive,INFINITE);
637 + fddlink->tiAlive=0;
638 + ReleaseSemaphore(fddAlive,1,NULL);
640 + sem_wait(fddAlive);
641 + fddlink->tiAlive=0;
642 + sem_post(fddAlive);
648 + fprintf(stderr,"tim397_end\n");
652 +tim397_activate( void )
654 + if( !memory_allocated ) {
655 + tim397_ram = memory_pool_allocate_persistent( 0x2000, 1 );
656 + memory_allocated = 1;
661 +tim397_unittest( void )
667 + r += unittests_assert_16k_page( 0x0000, tim397_memory_source, 0 );
668 + r += unittests_assert_16k_ram_page( 0x4000, 5 );
669 + r += unittests_assert_16k_ram_page( 0x8000, 2 );
670 + r += unittests_assert_16k_ram_page( 0xc000, 0 );
674 + r += unittests_paging_test_48( 2 );
681 +tim397_enabled_snapshot( libspectrum_snap *snap )
687 +tim397_from_snapshot( libspectrum_snap *snap )
693 +tim397_to_snapshot( libspectrum_snap *snap GCC_UNUSED )
695 + //if( !periph_is_active( PERIPH_TYPE_TIM397 ) ) return;
699 diff -Naru fuse-1.1.1/peripherals/disk/ti_m397.h fuse-1.1.1.fdd3000/peripherals/disk/ti_m397.h
700 --- fuse-1.1.1/peripherals/disk/ti_m397.h 1970-01-01 01:00:00.000000000 +0100
701 +++ fuse-1.1.1.fdd3000/peripherals/disk/ti_m397.h 2014-02-14 08:31:43.972546695 +0100
704 + TIM397.h: Routines for handling the Timex TIM397
707 +#ifndef FUSE_TIM397_H
708 +#define FUSE_TIM397_H
712 +#include <libspectrum.h>
716 +extern int tim397_available; /* Is the tim397 available for use? */
717 +extern int tim397_active; /* tim397 enabled? */
719 +int tim397_init( void );
720 +void tim397_end( void );
722 +void tim397_page( void );
723 +void tim397_unpage( void );
725 +libspectrum_byte tim397_io_read( libspectrum_word port, int *attached );
726 +void tim397_io_write( libspectrum_word port, libspectrum_byte b );
728 +int tim397_unittest( void );
730 +#endif /* #ifndef FUSE_tim397_H */
731 diff -Naru fuse-1.1.1/periph.h fuse-1.1.1.fdd3000/periph.h
732 --- fuse-1.1.1/periph.h 2013-05-24 22:42:22.000000000 +0200
733 +++ fuse-1.1.1.fdd3000/periph.h 2014-02-14 08:21:36.769616238 +0100
735 PERIPH_TYPE_SPECCYBOOT, /* SpeccyBoot interface */
736 PERIPH_TYPE_SPECDRUM, /* SpecDrum interface */
737 PERIPH_TYPE_SPECTRANET, /* Spectranet interface */
738 + PERIPH_TYPE_TIM397, /* FDD3000 disk interface */
739 PERIPH_TYPE_ULA, /* Standard ULA */
740 PERIPH_TYPE_ULA_FULL_DECODE,/* Standard ULA responding only to 0xfe */
741 PERIPH_TYPE_UPD765, /* +3 uPD765 FDC */
742 diff -Naru fuse-1.1.1/settings.dat fuse-1.1.1.fdd3000/settings.dat
743 --- fuse-1.1.1/settings.dat 2013-05-16 22:26:23.000000000 +0200
744 +++ fuse-1.1.1.fdd3000/settings.dat 2014-02-14 08:27:14.978179040 +0100
746 interface2, boolean, 1
751 movie_compr, string, NULL
752 movie_start, string, NULL
754 rom_plusd, string, "plusd.rom",
755 rom_disciple, string, "disciple.rom",
756 rom_opus, string, "opus.rom",
757 +rom_tim397, string, "ti_m397.rom",
758 rom_speccyboot, string, "speccyboot-1.4.rom",
760 drive_plus3a_type, string, NULL
761 diff -Naru fuse-1.1.1/settings.pl fuse-1.1.1.fdd3000/settings.pl
762 --- fuse-1.1.1/settings.pl 2013-05-24 22:42:22.000000000 +0200
763 +++ fuse-1.1.1.fdd3000/settings.pl 2014-02-14 08:25:30.881179995 +0100
765 case 42: return &( settings->rom_plusd );
766 case 43: return &( settings->rom_disciple );
767 case 44: return &( settings->rom_opus );
768 - case 45: return &( settings->rom_speccyboot );
769 + case 45: return &( settings->rom_tim397 );
770 + case 46: return &( settings->rom_speccyboot );
771 default: return NULL;
774 diff -Naru fuse-1.1.1/ui/options.dat fuse-1.1.1.fdd3000/ui/options.dat
775 --- fuse-1.1.1/ui/options.dat 2013-05-24 22:42:22.000000000 +0200
776 +++ fuse-1.1.1.fdd3000/ui/options.dat 2014-02-14 08:21:36.769616238 +0100
778 Checkbox, (B)eta 128 interface, beta128, INPUT_KEY_b
779 Checkbox, Beta 128 (a)uto-boot in 48K machines, beta128_48boot, INPUT_KEY_a
780 Checkbox, (O)pus Discovery interface, opus, INPUT_KEY_o
781 +Checkbox, FDD(3)000 / M397 interface, ti_m397, INPUT_KEY_3
782 Postcheck, periph_postcheck
783 Posthook, periph_posthook
785 diff -Naru fuse-1.1.1/ui/ui.h fuse-1.1.1.fdd3000/ui/ui.h
786 --- fuse-1.1.1/ui/ui.h 2013-05-16 22:26:23.000000000 +0200
787 +++ fuse-1.1.1.fdd3000/ui/ui.h 2014-02-14 08:21:36.769616238 +0100
789 #include "peripherals/disk/beta.h"
790 #include "peripherals/disk/disciple.h"
791 #include "peripherals/disk/opus.h"
792 +#include "peripherals/disk/ti_m397.h"
793 #include "peripherals/disk/plusd.h"
794 #include "ui/scaler/scaler.h"
797 UI_MENU_ITEM_MEDIA_DISK_OPUS_2_EJECT,
798 UI_MENU_ITEM_MEDIA_DISK_OPUS_2_FLIP_SET,
799 UI_MENU_ITEM_MEDIA_DISK_OPUS_2_WP_SET,
800 + UI_MENU_ITEM_MEDIA_DISK_TIM397,
801 UI_MENU_ITEM_MEDIA_IDE,
802 UI_MENU_ITEM_MEDIA_IDE_SIMPLE8BIT,
803 UI_MENU_ITEM_MEDIA_IDE_SIMPLE8BIT_MASTER_EJECT,
804 diff -Naru fuse-1.1.1/ui.c fuse-1.1.1.fdd3000/ui.c
805 --- fuse-1.1.1/ui.c 2013-05-16 22:26:23.000000000 +0200
806 +++ fuse-1.1.1.fdd3000/ui.c 2014-02-14 08:51:58.576646341 +0100
808 "/Media/Disk/Opus/Drive 2/Write protect/Enable",
809 "/Media/Disk/Opus/Drive 2/Write protect/Disable", 1 },
811 + { UI_MENU_ITEM_MEDIA_DISK_TIM397, "/Media/Disk/Timex M397" },
813 { UI_MENU_ITEM_MEDIA_IDE, "/Media/IDE" },
815 { UI_MENU_ITEM_MEDIA_IDE_SIMPLE8BIT, "/Media/IDE/Simple 8-bit" },
816 diff -Naru fuse-1.1.1/z80/coretest.c fuse-1.1.1.fdd3000/z80/coretest.c
817 --- fuse-1.1.1/z80/coretest.c 2013-05-16 22:26:16.000000000 +0200
818 +++ fuse-1.1.1.fdd3000/z80/coretest.c 2014-02-14 08:21:36.769616238 +0100
823 +int tim397_available = 0;
824 +int tim397_active = 0;
833 +tim397_unpage( void )
838 int plusd_available = 0;
839 int plusd_active = 0;
841 diff -Naru fuse-1.1.1/z80/z80_checks.h fuse-1.1.1.fdd3000/z80/z80_checks.h
842 --- fuse-1.1.1/z80/z80_checks.h 2013-05-16 22:26:16.000000000 +0200
843 +++ fuse-1.1.1.fdd3000/z80/z80_checks.h 2014-02-14 08:23:42.063410052 +0100
845 SETUP_CHECK( rzx, rzx_playback )
846 SETUP_CHECK( debugger, debugger_mode != DEBUGGER_MODE_INACTIVE )
847 SETUP_CHECK( beta, beta_available )
848 +SETUP_CHECK( tim397, tim397_available )
849 SETUP_CHECK( plusd, plusd_available )
850 SETUP_CHECK( disciple, disciple_available )
851 SETUP_CHECK( if1p, if1_available )
852 diff -Naru fuse-1.1.1/z80/z80_ops.c fuse-1.1.1.fdd3000/z80/z80_ops.c
853 --- fuse-1.1.1/z80/z80_ops.c 2013-05-16 22:26:16.000000000 +0200
854 +++ fuse-1.1.1.fdd3000/z80/z80_ops.c 2014-02-14 08:23:33.485342586 +0100
856 #include "peripherals/disk/disciple.h"
857 #include "peripherals/disk/opus.h"
858 #include "peripherals/disk/plusd.h"
859 +#include "peripherals/disk/ti_m397.h"
860 #include "peripherals/ide/divide.h"
861 #include "peripherals/if1.h"
862 #include "peripherals/spectranet.h"
868 + CHECK( tim397, tim397_available )
870 + if( tim397_active ) {
871 + if( PC == 0x0604 ) {
874 + } else if( PC == 0x0000 || PC == 0x0008 ) {
880 CHECK( plusd, plusd_available )