1 /* didaktik.c: Routines for handling the Didaktik 40/80 disk interface
2    Copyright (c) 2015-2016 Gergely Szasz, Philip Kendall
3    Copyright (c) 2015 Stuart Brady
4    Copyright (c) 2016 Sergio Baldoví
5    Copyright (c) 2016 Fredrick Meunier
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License along
18    with this program; if not, write to the Free Software Foundation, Inc.,
19    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 
21    Author contact information:
22 
23    szaszg@hu.inter.net
24 
25 */
26 
27 #include <config.h>
28 
29 #include <libspectrum.h>
30 
31 #include <string.h>
32 
33 #include "compat.h"
34 #include "debugger/debugger.h"
35 #include "didaktik.h"
36 #include "infrastructure/startup_manager.h"
37 #include "machine.h"
38 #include "module.h"
39 #include "peripherals/printer.h"
40 #include "settings.h"
41 #include "ui/ui.h"
42 #include "ui/uimedia.h"
43 #include "unittests/unittests.h"
44 #include "utils.h"
45 #include "wd_fdc.h"
46 #include "options.h"	/* needed for get combo options */
47 #include "z80/z80.h"
48 
49 #define INTRQ_ENABLED  0x80
50 #define DATARQ_ENABLED 0x40
51 /* 2KB RAM */
52 #define RAM_SIZE 0x0800
53 /* 14KB ROM */
54 #define ROM_SIZE 0x3800
55 
56 static int didaktik_rom_memory_source, didaktik_ram_memory_source;
57 
58 /* Two memory chunks accessible by the Z80 when /ROMCS is low */
59 static memory_page didaktik_memory_map_romcs_rom[ MEMORY_PAGES_IN_14K ];
60 static memory_page didaktik_memory_map_romcs_ram[ MEMORY_PAGES_IN_2K ];
61 
62 int didaktik80_available = 0;
63 int didaktik80_active = 0;
64 int didaktik80_snap = 0;
65 
66 static wd_fdc *didaktik_fdc;
67 static fdd_t didaktik_drives[ DIDAKTIK80_NUM_DRIVES ];
68 static ui_media_drive_info_t didaktik_ui_drives[ DIDAKTIK80_NUM_DRIVES ];
69 
70 static libspectrum_byte ram[ RAM_SIZE ];
71 
72 /* AUX byte */
73 static libspectrum_byte aux_register;
74 
75 static void didaktik_reset( int hard_reset );
76 static void didaktik_memory_map( void );
77 static void didaktik_enabled_snapshot( libspectrum_snap *snap );
78 static void didaktik_from_snapshot( libspectrum_snap *snap );
79 static void didaktik_to_snapshot( libspectrum_snap *snap );
80 static libspectrum_byte didaktik_sr_read( libspectrum_word port GCC_UNUSED, libspectrum_byte *attached );
81 static void didaktik_cr_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b );
82 static libspectrum_byte didaktik_tr_read( libspectrum_word port GCC_UNUSED, libspectrum_byte *attached );
83 static void didaktik_tr_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b );
84 static libspectrum_byte didaktik_sec_read( libspectrum_word port GCC_UNUSED, libspectrum_byte *attached );
85 static void didaktik_sec_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b );
86 static libspectrum_byte didaktik_dr_read( libspectrum_word port GCC_UNUSED, libspectrum_byte *attached );
87 static void didaktik_dr_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b );
88 static libspectrum_byte didaktik_8255_read( libspectrum_word port GCC_UNUSED, libspectrum_byte *attached );
89 static void didaktik_8255_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b );
90 static void didaktik_aux_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b );
91 
92 static module_info_t didaktik_module_info = {
93 
94   /* .reset = */ didaktik_reset,
95   /* .romcs = */ didaktik_memory_map,
96   /* .snapshot_enabled = */ didaktik_enabled_snapshot,
97   /* .snapshot_from = */ didaktik_from_snapshot,
98   /* .snapshot_to = */ didaktik_to_snapshot,
99 
100 };
101 
102 static const periph_port_t didaktik_ports[] = {
103   /* ---- ---- 1000 0001 */
104   { 0x00ff, 0x0081, didaktik_sr_read, didaktik_cr_write },
105   /* ---- ---- 1000 0011 */
106   { 0x00ff, 0x0083, didaktik_tr_read, didaktik_tr_write },
107   /* ---- ---- 1000 0101 */
108   { 0x00ff, 0x0085, didaktik_sec_read, didaktik_sec_write },
109   /* ---- ---- 1000 0111 */
110   { 0x00ff, 0x0087, didaktik_dr_read, didaktik_dr_write },
111 
112   /* ---- ---- 0xx- ---- */
113   { 0x0080, 0x0000, didaktik_8255_read, didaktik_8255_write },
114 
115   /* ---- ---- 1000 1--1 */
116   { 0x00f9, 0x0089, NULL, didaktik_aux_write },
117 
118   { 0, 0, NULL, NULL }
119 };
120 
121 static const periph_t didaktik_periph = {
122   /* .option = */ &settings_current.didaktik80,
123   /* .ports = */ didaktik_ports,
124   /* .hard_reset = */ 1,
125   /* .activate = */ NULL,
126 };
127 
128 /* Debugger events */
129 static const char * const event_type_string = "didaktik80";
130 static int page_event, unpage_event;
131 
132 void
didaktik80_page(void)133 didaktik80_page( void )
134 {
135   didaktik80_active = 1;
136   machine_current->ram.romcs = 1;
137   machine_current->memory_map();
138   debugger_event( page_event );
139 }
140 
141 void
didaktik80_unpage(void)142 didaktik80_unpage( void )
143 {
144   didaktik80_active = 0;
145   machine_current->ram.romcs = 0;
146   machine_current->memory_map();
147   debugger_event( unpage_event );
148 }
149 
150 static void
didaktik_memory_map(void)151 didaktik_memory_map( void )
152 {
153   if( !didaktik80_active ) return;
154 
155   memory_map_romcs_8k( 0x0000, didaktik_memory_map_romcs_rom );
156   memory_map_romcs_4k( 0x2000,
157                        didaktik_memory_map_romcs_rom + MEMORY_PAGES_IN_8K );
158   memory_map_romcs_2k( 0x3000,
159                        didaktik_memory_map_romcs_rom + MEMORY_PAGES_IN_12K );
160   memory_map_romcs_2k( 0x3800, didaktik_memory_map_romcs_ram );
161 }
162 
163 static void
didaktik_set_datarq(struct wd_fdc * f)164 didaktik_set_datarq( struct wd_fdc *f )
165 {
166   if( aux_register & DATARQ_ENABLED )
167     event_add( 0, z80_nmi_event );
168 }
169 
170 static void
didaktik_set_intrq(struct wd_fdc * f)171 didaktik_set_intrq( struct wd_fdc *f )
172 {
173   if( aux_register & INTRQ_ENABLED )
174     event_add( 0, z80_nmi_event );
175 }
176 
177 static int
didaktik80_init(void * context)178 didaktik80_init( void *context )
179 {
180   int i;
181   fdd_t *d;
182 
183   didaktik_fdc = wd_fdc_alloc_fdc( WD2797, 0, WD_FLAG_DRQ | WD_FLAG_RDY );
184 
185   for( i = 0; i < DIDAKTIK80_NUM_DRIVES; i++ ) {
186     d = &didaktik_drives[ i ];
187     fdd_init( d, FDD_SHUGART, NULL, 0 );       /* drive geometry 'autodetect' */
188     d->disk.flag = DISK_FLAG_NONE;
189   }
190 
191   didaktik_fdc->current_drive = &didaktik_drives[ 0 ];
192   fdd_select( &didaktik_drives[ 0 ], 1 );
193   didaktik_fdc->extra_signal = 1;
194   didaktik_fdc->dden = 1;
195   didaktik_fdc->set_intrq = didaktik_set_intrq;
196   didaktik_fdc->reset_intrq = NULL;
197   didaktik_fdc->set_datarq = didaktik_set_datarq;
198   didaktik_fdc->reset_datarq = NULL;
199 
200   module_register( &didaktik_module_info );
201 
202   didaktik_rom_memory_source = memory_source_register( "Didaktik 80 ROM" );
203   didaktik_ram_memory_source = memory_source_register( "Didaktik 80 RAM" );
204   for( i = 0; i < MEMORY_PAGES_IN_14K; i++ )
205     didaktik_memory_map_romcs_rom[i].source = didaktik_rom_memory_source;
206 
207   for( i = 0; i < MEMORY_PAGES_IN_2K; i++ )
208     didaktik_memory_map_romcs_ram[i].source = didaktik_ram_memory_source;
209 
210   periph_register( PERIPH_TYPE_DIDAKTIK80, &didaktik_periph );
211   for( i = 0; i < DIDAKTIK80_NUM_DRIVES; i++ ) {
212     didaktik_ui_drives[ i ].fdd = &didaktik_drives[ i ];
213     ui_media_drive_register( &didaktik_ui_drives[ i ] );
214   }
215 
216   periph_register_paging_events( event_type_string, &page_event,
217                                  &unpage_event );
218 
219   return 0;
220 }
221 
222 static void
didaktik_reset(int hard_reset)223 didaktik_reset( int hard_reset )
224 {
225   int i;
226 
227   didaktik80_active = 0;
228   didaktik80_available = 0;
229 
230   ui_menu_activate( UI_MENU_ITEM_MACHINE_DIDAKTIK80_SNAP, 0 );
231   if( !periph_is_active( PERIPH_TYPE_DIDAKTIK80 ) ) {
232     return;
233   }
234 
235   if( machine_load_rom_bank( didaktik_memory_map_romcs_rom, 0,
236                              settings_current.rom_didaktik80,
237                              settings_default.rom_didaktik80, ROM_SIZE ) ) {
238     settings_current.didaktik80 = 0;
239     periph_activate_type( PERIPH_TYPE_DIDAKTIK80, 0 );
240     return;
241   }
242 
243   ui_menu_activate( UI_MENU_ITEM_MACHINE_DIDAKTIK80_SNAP, 1 );
244 
245   for( i = 0; i < MEMORY_PAGES_IN_2K; i++ ) {
246     struct memory_page *page =
247       &didaktik_memory_map_romcs_ram[ i ];
248     page->page = ram + i * MEMORY_PAGE_SIZE;
249     page->offset = i * MEMORY_PAGE_SIZE;
250     page->writable = 1;
251   }
252 
253   machine_current->ram.romcs = 0;
254 
255   aux_register = 0;
256 
257   didaktik80_available = 1;
258 
259   if( hard_reset )
260     memset( ram, 0, sizeof( ram ) );
261 
262   wd_fdc_master_reset( didaktik_fdc );
263 
264   for( i = 0; i < DIDAKTIK80_NUM_DRIVES; i++ ) {
265     ui_media_drive_update_menus( &didaktik_ui_drives[ i ],
266                                  UI_MEDIA_DRIVE_UPDATE_ALL );
267   }
268 
269   didaktik_fdc->current_drive = &didaktik_drives[ 0 ];
270   fdd_select( &didaktik_drives[ 0 ], 1 );
271   fdd_select( &didaktik_drives[ 1 ], 0 );
272   machine_current->memory_map();
273 
274 }
275 
276 static void
didaktik80_end(void)277 didaktik80_end( void )
278 {
279   didaktik80_available = 0;
280   libspectrum_free( didaktik_fdc );
281 }
282 
283 void
didaktik80_register_startup(void)284 didaktik80_register_startup( void )
285 {
286   startup_manager_module dependencies[] = {
287     STARTUP_MANAGER_MODULE_DEBUGGER,
288     STARTUP_MANAGER_MODULE_MEMORY,
289     STARTUP_MANAGER_MODULE_SETUID,
290   };
291   startup_manager_register( STARTUP_MANAGER_MODULE_DIDAKTIK, dependencies,
292                             ARRAY_SIZE( dependencies ), didaktik80_init, NULL,
293                             didaktik80_end );
294 }
295 
296 static libspectrum_byte
didaktik_sr_read(libspectrum_word port GCC_UNUSED,libspectrum_byte * attached)297 didaktik_sr_read( libspectrum_word port GCC_UNUSED, libspectrum_byte *attached )
298 {
299   *attached = 0xff;
300   return wd_fdc_sr_read( didaktik_fdc );
301 }
302 
303 static void
didaktik_cr_write(libspectrum_word port GCC_UNUSED,libspectrum_byte b)304 didaktik_cr_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
305 {
306   wd_fdc_cr_write( didaktik_fdc, b );
307 }
308 
309 static libspectrum_byte
didaktik_tr_read(libspectrum_word port GCC_UNUSED,libspectrum_byte * attached)310 didaktik_tr_read( libspectrum_word port GCC_UNUSED, libspectrum_byte *attached )
311 {
312   *attached = 0xff;
313   return wd_fdc_tr_read( didaktik_fdc );
314 }
315 
316 static void
didaktik_tr_write(libspectrum_word port GCC_UNUSED,libspectrum_byte b)317 didaktik_tr_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
318 {
319   wd_fdc_tr_write( didaktik_fdc, b );
320 }
321 
322 static libspectrum_byte
didaktik_sec_read(libspectrum_word port GCC_UNUSED,libspectrum_byte * attached)323 didaktik_sec_read( libspectrum_word port GCC_UNUSED, libspectrum_byte *attached )
324 {
325   *attached = 0xff;
326   return wd_fdc_sec_read( didaktik_fdc );
327 }
328 
329 static void
didaktik_sec_write(libspectrum_word port GCC_UNUSED,libspectrum_byte b)330 didaktik_sec_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
331 {
332   wd_fdc_sec_write( didaktik_fdc, b );
333 }
334 
335 static libspectrum_byte
didaktik_dr_read(libspectrum_word port GCC_UNUSED,libspectrum_byte * attached)336 didaktik_dr_read( libspectrum_word port GCC_UNUSED, libspectrum_byte *attached )
337 {
338   *attached = 0xff;
339   return wd_fdc_dr_read( didaktik_fdc );
340 }
341 
342 static void
didaktik_dr_write(libspectrum_word port GCC_UNUSED,libspectrum_byte b)343 didaktik_dr_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
344 {
345   wd_fdc_dr_write( didaktik_fdc, b );
346 }
347 
348 static libspectrum_byte
didaktik_8255_read(libspectrum_word port,libspectrum_byte * attached)349 didaktik_8255_read( libspectrum_word port, libspectrum_byte *attached )
350 {
351   *attached = 0xff; /* TODO: check this */
352   return 0xff;
353 }
354 
355 static void
didaktik_8255_write(libspectrum_word port GCC_UNUSED,libspectrum_byte b)356 didaktik_8255_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
357 {
358   return;
359 }
360 
361 static void
didaktik_aux_write(libspectrum_word port GCC_UNUSED,libspectrum_byte b)362 didaktik_aux_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
363 {
364   if( ( b & 0x01 ) != ( aux_register & 0x01 ) )
365     fdd_select( &didaktik_drives[ 0 ], b & 0x01 ? 1 : 0 );
366   if( ( b & 0x02 ) != ( aux_register & 0x02 ) )
367     fdd_select( &didaktik_drives[ 1 ], b & 0x02 ? 1 : 0 );
368   didaktik_fdc->current_drive = &didaktik_drives[ b & 0x02 ? 1 : 0 ];
369 
370   if( ( b & 0x04 ) != ( aux_register & 0x04 ) )
371     fdd_motoron( &didaktik_drives[ 0 ], b & 0x04 ? 1 : 0 );
372   if( ( b & 0x08 ) != ( aux_register & 0x08 ) )
373     fdd_motoron( &didaktik_drives[ 1 ], b & 0x08 ? 1 : 0 );
374 
375   aux_register = b;
376 }
377 
378 int
didaktik80_disk_insert(didaktik80_drive_number which,const char * filename,int autoload)379 didaktik80_disk_insert( didaktik80_drive_number which, const char *filename,
380 		   int autoload )
381 {
382   if( which >= DIDAKTIK80_NUM_DRIVES ) {
383     ui_error( UI_ERROR_ERROR, "didaktik80_insert: unknown drive %d",
384 	      which );
385     fuse_abort();
386   }
387 
388   return ui_media_drive_insert( &didaktik_ui_drives[ which ], filename, autoload );
389 }
390 
391 fdd_t *
didaktik80_get_fdd(didaktik80_drive_number which)392 didaktik80_get_fdd( didaktik80_drive_number which )
393 {
394   return &( didaktik_drives[ which ] );
395 }
396 
397 int
didaktik80_unittest(void)398 didaktik80_unittest( void )
399 {
400   int r = 0;
401 
402   didaktik80_page();
403 
404   r += unittests_assert_8k_page( 0x0000, didaktik_rom_memory_source, 0 );
405   r += unittests_assert_4k_page( 0x2000, didaktik_rom_memory_source, 0 );
406   r += unittests_assert_2k_page( 0x3000, didaktik_rom_memory_source, 0 );
407   r += unittests_assert_2k_page( 0x3800, didaktik_ram_memory_source, 0 );
408   r += unittests_assert_16k_ram_page( 0x4000, 5 );
409   r += unittests_assert_16k_ram_page( 0x8000, 2 );
410   r += unittests_assert_16k_ram_page( 0xc000, 0 );
411 
412   didaktik80_unpage();
413 
414   r += unittests_paging_test_48( 2 );
415 
416   return r;
417 }
418 
419 static int
ui_drive_is_available(void)420 ui_drive_is_available( void )
421 {
422   return didaktik80_available;
423 }
424 
425 static const fdd_params_t *
ui_drive_get_params_a(void)426 ui_drive_get_params_a( void )
427 {
428   /* +1 => there is no `Disabled' */
429   return &fdd_params[ option_enumerate_diskoptions_drive_didaktik80a_type() + 1 ];
430 }
431 
432 static const fdd_params_t *
ui_drive_get_params_b(void)433 ui_drive_get_params_b( void )
434 {
435   return &fdd_params[ option_enumerate_diskoptions_drive_didaktik80b_type() ];
436 }
437 
438 static ui_media_drive_info_t didaktik_ui_drives[ DIDAKTIK80_NUM_DRIVES ] = {
439   {
440     /* .name = */ "Didaktik Disk A",
441     /* .controller_index = */ UI_MEDIA_CONTROLLER_DIDAKTIK,
442     /* .drive_index = */ DIDAKTIK80_DRIVE_A,
443     /* .menu_item_parent = */ UI_MENU_ITEM_MEDIA_DISK_DIDAKTIK,
444     /* .menu_item_top = */ UI_MENU_ITEM_MEDIA_DISK_DIDAKTIK_A,
445     /* .menu_item_eject = */ UI_MENU_ITEM_MEDIA_DISK_DIDAKTIK_A_EJECT,
446     /* .menu_item_flip = */ UI_MENU_ITEM_MEDIA_DISK_DIDAKTIK_A_FLIP_SET,
447     /* .menu_item_wp = */ UI_MENU_ITEM_MEDIA_DISK_DIDAKTIK_A_WP_SET,
448     /* .is_available = */ &ui_drive_is_available,
449     /* .get_params = */ &ui_drive_get_params_a,
450   },
451   {
452     /* .name = */ "Didaktik Disk B",
453     /* .controller_index = */ UI_MEDIA_CONTROLLER_DIDAKTIK,
454     /* .drive_index = */ DIDAKTIK80_DRIVE_B,
455     /* .menu_item_parent = */ UI_MENU_ITEM_MEDIA_DISK_DIDAKTIK,
456     /* .menu_item_top = */ UI_MENU_ITEM_MEDIA_DISK_DIDAKTIK_B,
457     /* .menu_item_eject = */ UI_MENU_ITEM_MEDIA_DISK_DIDAKTIK_B_EJECT,
458     /* .menu_item_flip = */ UI_MENU_ITEM_MEDIA_DISK_DIDAKTIK_B_FLIP_SET,
459     /* .menu_item_wp = */ UI_MENU_ITEM_MEDIA_DISK_DIDAKTIK_B_WP_SET,
460     /* .is_available = */ &ui_drive_is_available,
461     /* .get_params = */ &ui_drive_get_params_b,
462   },
463 };
464 
465 static void
didaktik_enabled_snapshot(libspectrum_snap * snap)466 didaktik_enabled_snapshot( libspectrum_snap *snap )
467 {
468   settings_current.didaktik80 = libspectrum_snap_didaktik80_active( snap );
469 }
470 
471 static void
didaktik_from_snapshot(libspectrum_snap * snap)472 didaktik_from_snapshot( libspectrum_snap *snap )
473 {
474   int i;
475 
476   if( !libspectrum_snap_didaktik80_active( snap ) ) return;
477 
478   if( libspectrum_snap_didaktik80_custom_rom( snap ) &&
479       libspectrum_snap_didaktik80_rom( snap, 0 ) &&
480       machine_load_rom_bank_from_buffer(
481                              didaktik_memory_map_romcs_rom, 0,
482                              libspectrum_snap_didaktik80_rom( snap, 0 ),
483                              ROM_SIZE, 1 ) )
484     return;
485 
486   if( libspectrum_snap_didaktik80_ram( snap, 0 ) ) {
487     for( i = 0; i < MEMORY_PAGES_IN_2K; i++ )
488       memcpy( didaktik_memory_map_romcs_ram[ i ].page,
489               libspectrum_snap_didaktik80_ram( snap, 0 ) + i * MEMORY_PAGE_SIZE,
490               MEMORY_PAGE_SIZE );
491   }
492 
493   /* ignore drive count for now, there will be an issue with loading snaps where
494      drives have been disabled
495   libspectrum_snap_didaktik80_drive_count( snap )
496    */
497 
498   didaktik_fdc->direction = libspectrum_snap_plusd_direction( snap );
499 
500   didaktik_cr_write ( 0x0081, libspectrum_snap_didaktik80_status ( snap ) );
501   didaktik_tr_write ( 0x0083, libspectrum_snap_didaktik80_track  ( snap ) );
502   didaktik_sec_write( 0x0085, libspectrum_snap_didaktik80_sector ( snap ) );
503   didaktik_dr_write ( 0x0087, libspectrum_snap_didaktik80_data   ( snap ) );
504   didaktik_aux_write( 0x0089, libspectrum_snap_didaktik80_aux    ( snap ) );
505 
506   if( libspectrum_snap_didaktik80_paged( snap ) ) {
507     didaktik80_page();
508   } else {
509     didaktik80_unpage();
510   }
511 }
512 
513 static void
didaktik_to_snapshot(libspectrum_snap * snap)514 didaktik_to_snapshot( libspectrum_snap *snap )
515 {
516   libspectrum_byte *buffer;
517   int drive_count = 0;
518   int i;
519   size_t memory_length;
520 
521   if( !periph_is_active( PERIPH_TYPE_DIDAKTIK80 ) ) return;
522 
523   libspectrum_snap_set_didaktik80_active( snap, 1 );
524 
525   memory_length = ROM_SIZE;
526 
527   libspectrum_snap_set_didaktik80_custom_rom( snap, 1 );
528   libspectrum_snap_set_didaktik80_rom_length( snap, 0, memory_length );
529 
530   buffer = libspectrum_new( libspectrum_byte, memory_length );
531 
532   for( i = 0; i < MEMORY_PAGES_IN_14K; i++ )
533     memcpy( buffer + i * MEMORY_PAGE_SIZE,
534             didaktik_memory_map_romcs_rom[ i ].page, MEMORY_PAGE_SIZE );
535 
536   libspectrum_snap_set_didaktik80_rom( snap, 0, buffer );
537 
538   memory_length = RAM_SIZE;
539   buffer = libspectrum_new( libspectrum_byte, memory_length );
540 
541   for( i = 0; i < MEMORY_PAGES_IN_2K; i++ )
542     memcpy( buffer + i * MEMORY_PAGE_SIZE,
543             didaktik_memory_map_romcs_ram[ i ].page, MEMORY_PAGE_SIZE );
544   libspectrum_snap_set_didaktik80_ram( snap, 0, buffer );
545 
546   drive_count++; /* Drive 1 is not removable */
547   if( option_enumerate_diskoptions_drive_didaktik80b_type() > 0 ) drive_count++;
548   libspectrum_snap_set_didaktik80_drive_count( snap, drive_count );
549 
550   libspectrum_snap_set_didaktik80_paged ( snap, didaktik80_active );
551   libspectrum_snap_set_didaktik80_direction( snap, didaktik_fdc->direction );
552   libspectrum_snap_set_didaktik80_status( snap, didaktik_fdc->status_register );
553   libspectrum_snap_set_didaktik80_track ( snap, didaktik_fdc->track_register );
554   libspectrum_snap_set_didaktik80_sector( snap, didaktik_fdc->sector_register );
555   libspectrum_snap_set_didaktik80_data  ( snap, didaktik_fdc->data_register );
556   libspectrum_snap_set_didaktik80_aux   ( snap, aux_register );
557 }
558