Previous 15994 Revisions Next

r9938 Thursday 6th January, 2011 at 09:41:46 UTC by Miodrag Milanović
Moved files to proper location
[src/mess]mess.mak
[src/mess/devices]thomflop.c thomflop.h ti99_hd.c ti99_hd.h
[src/mess/includes]thomson.h
[src/mess/machine]thomflop.c* thomflop.h* thomson.c
[src/mess/machine/ti99]hfdc.c peribox.c ti99_hd.c* ti99_hd.h*

src/mess/devices/ti99_hd.c
r9937r9938
1/*************************************************************************
2
3    Hard disk support
4
5    This device wraps the plain image device as that device does not allow
6    for internal states (like head position)
7    The plain device is a subdevice ("drive") of this device, so we
8    get names like "mfmhd0:drive"
9
10    Michael Zapf, April 2010
11
12**************************************************************************/
13
14#include "emu.h"
15#include "imageutl.h"
16#include "harddisk.h"
17#include "imagedev/harddriv.h"
18#include "machine/smc92x4.h"
19
20#include "ti99_hd.h"
21
22typedef struct _mfmhd
23{
24   int current_cylinder;
25   int current_head;
26   int seeking;
27   int status;
28   int id_index; /* position in track for seeking the sector; counts the sector number */
29} mfmhd_state, idehd_state;
30
31#if 0
32static void dump_contents(UINT8 *buffer, int length)
33{
34   for (int i=0; i < length; i+=16)
35   {
36      for (int j=0; j < 16; j+=2)
37      {
38         printf("%02x%02x ", buffer[i+j], buffer[i+j+1]);
39      }
40      printf("\n");
41   }
42}
43#endif
44
45/*
46    Returns the linear sector number, given the CHS data.
47*/
48static int harddisk_chs_to_lba(hard_disk_file *hdfile, int cylinder, int head, int sector, UINT32 *lba)
49{
50   const hard_disk_info *info;
51
52   if ( hdfile != NULL)
53   {
54      info = hard_disk_get_info(hdfile);
55
56      if (   (cylinder >= info->cylinders) ||
57            (head >= info->heads) ||
58            (sector >= info->sectors))
59      return FALSE;
60
61      *lba = (cylinder * info->heads + head)
62            * info->sectors
63            + sector;
64      return TRUE;
65   }
66   return FALSE;
67}
68
69/* Accessor functions */
70void ti99_mfm_harddisk_read_sector(device_t *harddisk, int cylinder, int head, int sector, UINT8 **buf, int *sector_length)
71{
72   UINT32 lba;
73   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
74   device_t *drive = harddisk->subdevice("drive");
75   hard_disk_file *file = hd_get_hard_disk_file(drive);
76
77   *sector_length = 256;
78   *buf = (UINT8 *)malloc(*sector_length);
79
80   if (cylinder != hd->current_cylinder)
81   {
82      return;
83   }
84
85   if (file==NULL)
86   {
87      hd->status &= ~MFMHD_READY;
88      return;
89   }
90
91   if (!harddisk_chs_to_lba(file, cylinder, head, sector, &lba))
92   {
93      hd->status &= ~MFMHD_READY;
94      return;
95   }
96
97   if (!hard_disk_read(file, lba, *buf))
98   {
99      hd->status &= ~MFMHD_READY;
100      return;
101   }
102   /* printf("ti99_hd read sector  c=%04d h=%02d s=%02d\n", cylinder, head, sector); */
103   hd->status |= MFMHD_READY;
104}
105
106void ti99_mfm_harddisk_write_sector(device_t *harddisk, int cylinder, int head, int sector, UINT8 *buf, int sector_length)
107{
108   UINT32 lba;
109   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
110   device_t *drive = harddisk->subdevice("drive");
111   hard_disk_file *file = hd_get_hard_disk_file(drive);
112
113   if (file==NULL)
114   {
115      hd->status &= ~MFMHD_READY;
116      return;
117   }
118
119   if (!harddisk_chs_to_lba(file, cylinder, head, sector, &lba))
120   {
121      hd->status &= ~MFMHD_READY;
122      hd->status |= MFMHD_WRFAULT;
123      return;
124   }
125
126   if (!hard_disk_write(file, lba, buf))
127   {
128      hd->status &= ~MFMHD_READY;
129      hd->status |= MFMHD_WRFAULT;
130      return;
131   }
132
133   hd->status |= MFMHD_READY;
134}
135
136#define TI99HD_BLOCKNOTFOUND -1
137
138/*
139    Searches a block containing number * byte, starting at the given
140    position. Returns the position of the first byte of the block.
141*/
142static int find_block(const UINT8 *buffer, int start, int stop, UINT8 byte, size_t number)
143{
144   int i = start;
145   size_t current = number;
146   while (i < stop && current > 0)
147   {
148      if (buffer[i++] != byte)
149      {
150         current = number;
151      }
152      else
153      {
154         current--;
155      }
156   }
157   if (current==0)
158   {
159      return i - number;
160   }
161   else
162      return TI99HD_BLOCKNOTFOUND;
163}
164
165/*
166    Reads a complete track. We have to rebuild the gaps. This is basically
167    done in the same way as in the SDF format in ti99_dsk.
168
169    WARNING: This function is untested! We need to create a suitable
170    application program for the TI which makes use of it.
171*/
172void ti99_mfm_harddisk_read_track(device_t *harddisk, int head, UINT8 **pbuffer, int *data_count)
173{
174   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
175   device_t *drive = harddisk->subdevice("drive");
176
177   /* We assume an interleave of 3 for 32 sectors. */
178   int step = 3;
179   UINT32 lba;
180   int i;
181
182   int gap1 = 16;
183   int gap2 = 8;
184   int gap3 = 15;
185   int gap4 = 340;
186   int sync = 13;
187   int count;
188   int size;
189   int position = 0;
190   int sector;
191   int crc;
192
193   const hard_disk_info *info;
194   hard_disk_file *file = hd_get_hard_disk_file(drive);
195
196   if (file==NULL)
197   {
198      hd->status &= ~MFMHD_READY;
199      return;
200   }
201
202   info = hard_disk_get_info(file);
203
204   count = info->sectors;
205   size = info->sectorbytes/128;
206
207   *data_count = gap1 + count*(sync+12+gap2+sync+size*128+gap3)+gap4;
208
209   UINT8 *trackdata = (UINT8*)malloc(*data_count);
210
211   /* Write lead-in. */
212   memset(trackdata, 0x4e, gap1);
213
214   position += gap1;
215   for (i=0; i < info->sectors; i++)
216   {
217      sector = (i*step) % info->sectors;
218      memset(&trackdata[position], 0x00, sync);
219      position += 10;
220
221      /* Write sync */
222      trackdata[position++] = 0xa1;
223
224      /* Write IDAM */
225      trackdata[position++] = cylinder_to_ident(hd->current_cylinder);
226      trackdata[position++] = hd->current_cylinder;
227      trackdata[position++] = head;
228      trackdata[position++] = sector;
229      trackdata[position++] = (size==1)? 0x00 : (0x01 << (size-1));
230
231      /* Set CRC16 */
232      crc = ccitt_crc16(0xffff, &trackdata[position-5], 5);
233      trackdata[position++] = (crc>>8)&0xff;
234      trackdata[position++] = crc & 0xff;
235
236      /* Write Gap2 */
237      memset(&trackdata[position], 0x4e, gap2);
238      position += gap2;
239
240      /* Write sync */
241      memset(&trackdata[position], 0x00, sync);
242      position += sync;
243      trackdata[position++] = 0xa1;
244
245      /* Write DAM */
246      trackdata[position++] = 0xfb;
247
248      /* Locate the sector content in the image and load it. */
249
250      if (!harddisk_chs_to_lba(file, hd->current_cylinder, head, sector, &lba))
251      {
252         hd->status &= ~MFMHD_READY;
253         free(trackdata);
254         return;
255      }
256
257      if (!hard_disk_read(file, lba, &trackdata[position]))
258      {
259         hd->status &= ~MFMHD_READY;
260         free(trackdata);
261         return;
262      }
263
264      position += size;
265
266      /* Set CRC16. Includes the address mark. */
267      crc = ccitt_crc16(0xffff, &trackdata[position-size-1], size+1);
268      trackdata[position++] = (crc>>8)&0xff;
269      trackdata[position++] = crc & 0xff;
270
271      /* Write remaining 3 bytes which would have been used for ECC. */
272      memset(&trackdata[position], 0x00, 3);
273      position += 3;
274
275      /* Write Gap3 */
276      memset(&trackdata[position], 0x4e, gap3);
277      position += gap3;
278   }
279   /* Write Gap 4 */
280   memset(&trackdata[position], 0x4e, gap4);
281   position += gap4;
282
283   hd->status |= MFMHD_READY;
284
285   *pbuffer = trackdata;
286
287   // Remember to free the buffer! Except when an error has occured,
288   // the function returns a newly allocated buffer.
289   // Errors are indicated by READY=FALSE.
290}
291
292/*
293    Writes a track to the image. We need to isolate the sector contents.
294    This is basically done in the same way as in the SDF format in ti99_dsk.
295*/
296void ti99_mfm_harddisk_write_track(device_t *harddisk, int head, UINT8 *track_image, int data_count)
297{
298   int current_pos = 0;
299   int found;
300   UINT8 wident, whead = 0, wsector = 0, wsize;
301   UINT16 wcyl = 0;
302   int state;
303
304   /* Only search in the first 100 bytes for the start. */
305   int gap1 = 16;
306   int sync = 13;
307
308   UINT32 lba;
309   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
310   device_t *drive = harddisk->subdevice("drive");
311   hard_disk_file *file = hd_get_hard_disk_file(drive);
312
313   /* printf("ti99_hd write track c=%d h=%d\n", hd->current_cylinder, head); */
314
315   if (file==NULL)
316   {
317      hd->status &= ~MFMHD_READY;
318      return;
319   }
320
321   current_pos = find_block(track_image, 0, 100, 0x4e, gap1);
322
323   // In case of defect formats, we continue as far as possible. This
324   // may lead to sectors not being written. */
325   if (current_pos==TI99HD_BLOCKNOTFOUND)
326   {
327      logerror("ti99_hd error: write track: Cannot find gap1 for cylinder %d, head %d.\n", hd->current_cylinder, head);
328      /* What now? The track data are illegal, so we refuse to continue. */
329      hd->status |= MFMHD_WRFAULT;
330      return;
331   }
332
333   /* Get behind GAP1 */
334   current_pos += gap1;
335   found = FALSE;
336
337   while (current_pos < data_count)
338   {
339      /* We must find the address block to determine the sector. */
340      int new_pos = find_block(track_image, current_pos, data_count, 0x00, sync);
341      if (new_pos==TI99HD_BLOCKNOTFOUND)
342      {
343         /* Forget about the rest; we're done. */
344         if (found) break;  /* we were already successful, so all ok */
345         logerror("ti99_hd error: write track: Cannot find sync for track %d, head %d.\n", hd->current_cylinder, head);
346         hd->status |= MFMHD_WRFAULT;
347         return;
348      }
349      found = TRUE;
350
351      new_pos = new_pos + sync; /* skip sync bytes */
352
353      if (track_image[new_pos]==0xa1)
354      {
355         /* IDAM found. */
356         current_pos = new_pos + 1;
357         wident = track_image[current_pos];
358         wcyl = track_image[current_pos+1] + ((track_image[current_pos+2]&0x70)<<4);
359         whead = track_image[current_pos+2]&0x0f;
360         wsector = track_image[current_pos+3];
361         wsize = track_image[current_pos+4];
362
363         if (wcyl == hd->current_cylinder && whead == head)
364         {
365            if (!harddisk_chs_to_lba(file, wcyl, whead, wsector, &lba))
366            {
367               hd->status |= MFMHD_WRFAULT;
368               return;
369            }
370
371            /* Skip to the sector content. */
372            new_pos = find_block(track_image, current_pos, data_count, 0x00, sync);
373            current_pos = new_pos + sync;
374            if (track_image[current_pos]==0xa1)
375            {
376               current_pos += 2;
377               state = hard_disk_write(file, lba, track_image+current_pos);
378               if (state==0)
379               {
380                  logerror("ti99_hd error: write track: Write error during formatting cylinder %d, head %d\n", wcyl, whead);
381                  hd->status |= MFMHD_WRFAULT;
382                  return;
383               }
384               current_pos = current_pos+256+2; /* Skip contents and CRC */
385            }
386            else
387            {
388               logerror("ti99_hd error: write track: Cannot find DAM for cylinder %d, head %d, sector %d.\n", wcyl, whead, wsector);
389               hd->status |= MFMHD_WRFAULT;
390               return;
391            }
392         }
393         else
394         {
395            logerror("ti99_hd error: write track: Cylinder/head mismatch. Drive is on cyl=%d, head=%d, track data say cyl=%d, head=%d\n", hd->current_cylinder, head, wcyl, whead);
396            hd->status |= MFMHD_WRFAULT;
397         }
398      }
399      else
400      {
401         logerror("ti99_hd error: write track: Invalid track image for cyl=%d, head=%d. Cannot find any IDAM in track data.\n",  hd->current_cylinder, head);
402         hd->status |= MFMHD_WRFAULT;
403         return;
404      }
405   }
406}
407
408UINT8 ti99_mfm_harddisk_status(device_t *harddisk)
409{
410   UINT8 status = 0;
411   device_t *drive;
412   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
413   drive = harddisk->subdevice("drive");
414   hard_disk_file *file = hd_get_hard_disk_file(drive);
415
416   if (file!=NULL)
417      status |= MFMHD_READY;
418
419   if (hd->current_cylinder==0)
420      status |= MFMHD_TRACK00;
421
422   if (!hd->seeking)
423      status |= MFMHD_SEEKCOMP;
424
425   if (hd->id_index == 0)
426      status |= MFMHD_INDEX;
427
428   hd->status = status;
429   return status;
430}
431
432void ti99_mfm_harddisk_seek(device_t *harddisk, int direction)
433{
434   device_t *drive = harddisk->subdevice("drive");
435   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
436   const hard_disk_info *info;
437   hard_disk_file *file = hd_get_hard_disk_file(drive);
438
439   if (file==NULL)   return;
440
441   info = hard_disk_get_info(file);
442
443   hd->seeking = TRUE;
444
445   if (direction<0)
446   {
447      if (hd->current_cylinder>0)
448         hd->current_cylinder--;
449   }
450   else
451   {
452      if (hd->current_cylinder < info->cylinders)
453         hd->current_cylinder++;
454   }
455
456   hd->seeking = FALSE;
457}
458
459void ti99_mfm_harddisk_get_next_id(device_t *harddisk, int head, chrn_id_hd *id)
460{
461   device_t *drive = harddisk->subdevice("drive");
462   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
463   const hard_disk_info *info;
464   hard_disk_file *file;
465   int interleave = 3;
466
467   file = hd_get_hard_disk_file(drive);
468   if (file==NULL)
469   {
470      hd->status &= ~MFMHD_READY;
471      return;
472   }
473
474   info = hard_disk_get_info(file);
475
476   hd->current_head = head;
477
478   /* TODO: implement an interleave suitable for the number of sectors in the track. */
479   hd->id_index = (hd->id_index + interleave) % info->sectors;
480
481   /* build a new info block. */
482   id->C = hd->current_cylinder;
483   id->H = hd->current_head;
484   id->R = hd->id_index;
485   id->N = 1;
486   id->data_id = hd->id_index;
487   id->flags = 0;
488}
489
490static DEVICE_START( mfmhd )
491{
492}
493
494static DEVICE_START( idehd )
495{
496}
497
498
499MACHINE_CONFIG_FRAGMENT( mfmhd )
500   MCFG_DEVICE_ADD( "drive", HARDDISK, 0 )
501MACHINE_CONFIG_END
502
503MACHINE_CONFIG_FRAGMENT( idehd )
504   MCFG_DEVICE_ADD( "drive", IDE_HARDDISK, 0 )
505MACHINE_CONFIG_END
506
507static const char DEVTEMPLATE_SOURCE[] = __FILE__;
508
509#define DEVTEMPLATE_ID(p,s)             p##mfmhd##s
510#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_MACHINE_CONFIG
511#define DEVTEMPLATE_NAME                "TI99 MFM Hard disk"
512#define DEVTEMPLATE_FAMILY              "Hard disks"
513#define DEVTEMPLATE_VERSION      "1.0"
514#define DEVTEMPLATE_CREDITS      "Copyright MESS Team"
515#include "devtempl.h"
516
517#undef DEVTEMPLATE_ID
518#undef DEVTEMPLATE_FEATURES
519#undef DEVTEMPLATE_NAME
520
521#define DEVTEMPLATE_ID(p,s)             p##idehd##s
522#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_MACHINE_CONFIG
523#define DEVTEMPLATE_NAME                "TI99 IDE Hard disk"
524#include "devtempl.h"
525
526DEFINE_LEGACY_DEVICE(MFMHD, mfmhd);
527DEFINE_LEGACY_DEVICE(IDEHD, idehd);
src/mess/devices/ti99_hd.h
r9937r9938
1#ifndef __TI99_HD__
2#define __TI99_HD__
3
4#include "emu.h"
5#include "machine/smc92x4.h"
6
7#define MFMHD_0 "mfmhd0"
8#define MFMHD_1 "mfmhd1"
9#define MFMHD_2 "mfmhd2"
10
11#define IDEHD_0 "idehd0"
12
13/* typedef struct _mfmhd_config mfmhd_config;
14struct _mfmhd_config
15{
16    device_start_func           device_start;
17    device_image_load_func          device_load;
18    device_image_unload_func        device_unload;
19}; */
20
21/* Accessor functions */
22void ti99_mfm_harddisk_read_sector(device_t *harddisk, int cylinder, int head, int sector, UINT8 **buf, int *sector_length);
23void ti99_mfm_harddisk_write_sector(device_t *harddisk, int cylinder, int head, int sector, UINT8 *buf, int sector_length);
24void ti99_mfm_harddisk_read_track(device_t *harddisk, int head, UINT8 **buffer, int *data_count);
25void ti99_mfm_harddisk_write_track(device_t *harddisk, int head, UINT8 *buffer, int data_count);
26UINT8 ti99_mfm_harddisk_status(device_t *harddisk);
27void ti99_mfm_harddisk_seek(device_t *harddisk, int direction);
28void ti99_mfm_harddisk_get_next_id(device_t *harddisk, int head, chrn_id_hd *id);
29
30DECLARE_LEGACY_DEVICE(MFMHD, mfmhd);
31
32DECLARE_LEGACY_DEVICE(IDEHD, idehd);
33
34#define MCFG_MFMHD_3_DRIVES_ADD()         \
35   MCFG_DEVICE_ADD(MFMHD_0, MFMHD, 0)      \
36   MCFG_DEVICE_ADD(MFMHD_1, MFMHD, 0)      \
37   MCFG_DEVICE_ADD(MFMHD_2, MFMHD, 0)      \
38   MCFG_DEVICE_ADD(IDEHD_0, IDEHD, 0)
39#endif
40
41
42/*
43    MCFG_MFMHD_START(mfmhd)             \
44    MCFG_MFMHD_LOAD(mfmhd)              \
45    MCFG_MFMHD_UNLOAD(mfmhd)
46*/
src/mess/devices/thomflop.c
r9937r9938
1/**********************************************************************
2
3  Copyright (C) Antoine Mine' 2006
4
5  Thomson 8-bit computers
6
7**********************************************************************/
8
9#include "includes/thomson.h"
10#include "machine/wd17xx.h"
11
12
13#define VERBOSE 0 /* 0, 1 or 2 */
14
15#define PRINT(x) mame_printf_info x
16
17#define LOG(x)   do { if (VERBOSE > 0) logerror x; } while (0)
18#define VLOG(x)   do { if (VERBOSE > 1) logerror x; } while (0)
19
20
21
22
23/******************* 3''1/2 & 5''1/4 disk format ********************/
24
25/*
26  single density sector format:
27
28  data   bytes
29
30  id field     00      6      byte synchro
31  FE      1      id field mark
32  1      track
33  1      side
34  1      sector
35  00      1      log sector size (0->128, 1->256, 2->512,...)
36  2      CRC (unemulated)
37  FF     12      spaces
38  data field   00      6      bytes synchro
39  FB      1      data field mark
40  E5    128      actual data (set to E5 when formatting)
41  2      CRC (unemulated)
42  FF     22 ?    spaces
43
44
45
46  double density sector format:
47
48  data   bytes
49
50  id field     00     12      bit synchro
51  A1      3      byte synchro
52  FE      1      id field mark
53  1      track
54  1      side
55  1      sector
56  01      1      log sector size (0->128, 1->256, 2->512,...)
57  2      CRC (unemulated)
58  4E/F7   22      spaces
59  data field   00     12      bit synchro
60  A1      3      bytes synchro
61  FB      1      data field mark
62  E5    256      actual data (set to E5 when formatting)
63  2      CRC (unemulated)
64  4E/F7   74 ?    spaces
65
66  => at most  392 bytes / sector
67  => at most 6272 bytes / track
68
69  Notes:
70  - the BIOS puts 4E bytes as spaces after id and data fields
71  - some protected games expect F7 bytes (instead of 4E) after id fields
72*/
73
74#define THOM_SIZE_ID          32
75#define THOM_SIZE_DATA_LO    (128+80)
76#define THOM_SIZE_DATA_HI    (256+80)
77#define THOM_SIZE_SYNCHRO     12
78
79static int motor_on;
80
81
82/* build an identifier, with header & space */
83static int thom_floppy_make_addr( chrn_id id, UINT8* dst, int sector_size )
84{
85   if ( sector_size == 128 )
86   {
87      /* single density */
88      memset( dst, 0x00, 6 ); /* synchro bytes */
89      dst[  7 ] = 0xfe; /* address field mark */
90      dst[  8 ] = id.C;
91      dst[  9 ] = id.H;
92      dst[ 10 ] = id.N;
93      dst[ 11 ] = id.R;
94      dst[ 12 ] = 0; /* TODO: CRC */
95      dst[ 13 ] = 0; /* TODO: CRC */
96      memset( dst + 14, 0xff, 12 ); /* end mark */
97      return 36;
98   }
99   else
100   {
101      /* double density */
102      memset( dst, 0xa1, 3 ); /* synchro bytes */
103      dst[ 3 ] = 0xfe; /* address field mark */
104      dst[ 4 ] = id.C;
105      dst[ 5 ] = id.H;
106      dst[ 6 ] = id.N;
107      dst[ 7 ] = id.R;
108      dst[ 8 ] = 0; /* TODO: CRC */
109      dst[ 9 ] = 0; /* TODO: CRC */
110      memset( dst + 10, 0xf7, 22 ); /* end mark */
111      return 32;
112   }
113}
114
115
116
117/* build a sector, with header & space */
118static int thom_floppy_make_sector( device_t* img, chrn_id id, UINT8* dst, int sector_size )
119{
120   if ( sector_size == 128 )
121   {
122      /* single density */
123      memset( dst, 0x00, 6 ); /* synchro bytes */
124      dst[ 6 ] = 0xfb; /* data field mark */
125      floppy_drive_read_sector_data
126         ( img, id.H, id.data_id, dst + 7, sector_size );
127      dst[ sector_size + 7 ] = 0; /* TODO: CRC */
128      dst[ sector_size + 8 ] = 0; /* TODO: CRC */
129      memset( dst + sector_size + 9, 0xff, 22 ); /* end mark */
130      return sector_size + 31;
131   }
132   else
133   {
134      /* double density */
135      memset( dst, 0xa1, 3 ); /* synchro bytes */
136      dst[ 3 ] = 0xfb; /* data field mark */
137      floppy_drive_read_sector_data
138         ( img, id.H, id.data_id, dst + 4, sector_size );
139      dst[ sector_size + 4 ] = 0; /* TODO: CRC */
140      dst[ sector_size + 5 ] = 0; /* TODO: CRC */
141      memset( dst + sector_size + 6, 0xF7, 74 ); /* end mark */
142      return sector_size + 80;
143   }
144}
145
146
147
148/* build a whole track */
149static int thom_floppy_make_track( device_t* img, UINT8* dst, int sector_size, int side )
150{
151   UINT8 space = ( sector_size == 128 ) ? 0xff : 0;
152   UINT8* org = dst;
153   chrn_id id;
154   int nb;
155
156   /* go to start of track */
157   while ( ! floppy_drive_get_flag_state( img, FLOPPY_DRIVE_INDEX ) )
158   {
159      if ( ! floppy_drive_get_next_id( img, side, &id ) )
160         return 0;
161   }
162
163   /* for each sector... */
164   for ( nb = 0; nb < 16; nb++ )
165   {
166      if ( ! floppy_drive_get_next_id( img, side, &id ) )
167         break;
168
169      memset( dst, space, THOM_SIZE_SYNCHRO ); dst += THOM_SIZE_SYNCHRO;
170      dst += thom_floppy_make_addr( id, dst, sector_size );
171      memset( dst, space, THOM_SIZE_SYNCHRO ); dst += THOM_SIZE_SYNCHRO;
172      dst += thom_floppy_make_sector( img, id, dst, sector_size );
173
174      if ( floppy_drive_get_flag_state( img, FLOPPY_DRIVE_INDEX ) )
175         break;
176   }
177   return dst - org;
178}
179
180
181
182/******************* QDD disk format ********************/
183
184/*
185  sector format:
186
187  data   bytes
188
189  id field     16     17      synchro
190  A5      1      id field mark
191  1      sector (1-400) hi byte
192  1      sector (1-400) low byte
193  1      check-sum (sum modulo 256 of 3 last bytes)
194
195  data field   16     10      synchro
196  5A      1      data field mark
197  FF    128      actual data (set to FF when formatting)
198  1      check-sum (sum modulo 256 of 129 last bytes)
199
200
201  there are 400 sectors numbered from 1
202*/
203
204#define THOM_QDD_SYNCH_DISK 100
205#define THOM_QDD_SYNCH_ADDR  17
206#define THOM_QDD_SYNCH_DATA  10
207
208#define THOM_QDD_SIZE_ID     (   4 + THOM_QDD_SYNCH_ADDR  )
209#define THOM_QDD_SIZE_DATA   ( 130 + THOM_QDD_SYNCH_DATA )
210
211
212/* build an identifier, with header */
213static int thom_qdd_make_addr( int sector, UINT8* dst )
214{
215   dst[  0 ] = 0xa5;
216   dst[  1 ] = sector >> 8;
217   dst[  2 ] = sector & 0xff;
218   dst[  3 ] = dst[ 0 ] + dst[ 1 ] + dst[ 2 ];
219   return 4;
220}
221
222
223
224/* build a sector, with header */
225static int thom_qdd_make_sector( device_t* img, int sector, UINT8* dst )
226{
227   int i;
228   dst[ 0 ] = 0x5a;
229   floppy_drive_read_sector_data ( img, 0, sector, dst + 1, 128 );
230   dst[ 129 ] = 0;
231   for ( i = 0; i < 129; i++ )
232      dst[ 129 ] += dst[ i ];
233   return 130;
234}
235
236
237
238/* build a whole disk */
239static int thom_qdd_make_disk ( device_t* img, UINT8* dst )
240{
241   UINT8* org = dst;
242   int i;
243
244   memset( dst, 0x16, THOM_QDD_SYNCH_DISK ); dst += THOM_QDD_SYNCH_DISK;
245
246   for ( i = 1; i <= 400; i++ )
247   {
248      memset( dst, 0x16, THOM_QDD_SYNCH_ADDR ); dst += THOM_QDD_SYNCH_ADDR;
249      dst += thom_qdd_make_addr( i, dst );
250      memset( dst, 0x16, THOM_QDD_SYNCH_DATA ); dst += THOM_QDD_SYNCH_DATA;
251      dst += thom_qdd_make_sector( img, i, dst );
252   }
253
254   memset( dst, 0x16, THOM_QDD_SYNCH_DISK ); dst += THOM_QDD_SYNCH_DISK;
255
256   return dst - org;
257}
258
259
260
261/*********************** CD 90-640 controller ************************/
262
263/* 5''1/4 two-sided double-density
264   used in TO7, TO7/70, MO5 computers
265   based on a WD2793 (or lower ?) chip
266*/
267
268
269
270static UINT8 to7_5p14_select;
271
272
273
274static READ8_HANDLER ( to7_5p14_r )
275{
276   device_t *fdc = space->machine->device("wd2793");
277
278   if ( offset < 4 )
279      return wd17xx_r( fdc, offset );
280   else if ( offset == 8 )
281      return to7_5p14_select;
282   else
283      logerror ( "%f $%04x to7_5p14_r: invalid read offset %i\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset );
284   return 0;
285}
286
287
288
289static WRITE8_HANDLER( to7_5p14_w )
290{
291   device_t *fdc = space->machine->device("wd2793");
292   if ( offset < 4 )
293      wd17xx_w( fdc, offset, data );
294   else if ( offset == 8 )
295   {
296      /* drive select */
297      int drive = -1, side = 0;
298
299      switch ( data & 7 )
300      {
301      case 0: break;
302      case 2: drive = 0; side = 0; break;
303      case 3: drive = 1; side = 1; break;
304      case 4: drive = 2; side = 0; break;
305      case 5: drive = 3; side = 1; break;
306      default:
307         logerror( "%f $%04x to7_5p14_w: invalid drive select pattern $%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data );
308      }
309
310      wd17xx_dden_w(fdc, BIT(data, 7));
311
312      to7_5p14_select = data;
313
314      if ( drive != -1 )
315      {
316         thom_floppy_active( space->machine, 0 );
317         wd17xx_set_drive( fdc, drive );
318         wd17xx_set_side( fdc, side );
319         LOG(( "%f $%04x to7_5p14_w: $%02X set drive=%i side=%i density=%s\n",
320               attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")),
321               data, drive, side, (BIT(data, 7) ? "FM" : "MFM")));
322      }
323   }
324   else
325      logerror ( "%f $%04x to7_5p14_w: invalid write offset %i (data=$%02X)\n",
326            attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset, data );
327}
328
329
330
331static void to7_5p14_reset( running_machine *machine )
332{
333   device_t *fdc = machine->device("wd2793");
334   LOG(( "to7_5p14_reset: CD 90-640 controller\n" ));
335   wd17xx_reset(fdc);
336}
337
338
339
340static void to7_5p14_init( running_machine *machine )
341{
342   LOG(( "to7_5p14_init: CD 90-640 controller\n" ));
343   state_save_register_global( machine, to7_5p14_select );
344}
345
346
347
348/*********************** CD 90-015 controller ************************/
349
350/* 5''1/4 one-sided single-density (up to 4 one-sided drives)
351   used in TO7, TO7/70, MO5 computers
352   based on HD 46503 S chip, but we actually use a MC 6843 instead
353   (seems they are clone)
354*/
355
356
357
358static UINT8 to7_5p14sd_select;
359
360
361
362static READ8_HANDLER ( to7_5p14sd_r )
363{
364   if ( offset < 8 )
365      return mc6843_r( space->machine->device("mc6843"), offset );
366   else if ( offset >= 8 && offset <= 9 )
367      return to7_5p14sd_select;
368   else
369      logerror ( "%f $%04x to7_5p14sd_r: invalid read offset %i\n",  attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset );
370   return 0;
371}
372
373
374
375static WRITE8_HANDLER( to7_5p14sd_w )
376{
377   if ( offset < 8 )
378      mc6843_w( space->machine->device("mc6843"), offset, data );
379   else if ( offset >= 8 && offset <= 9 )
380   {
381      /* drive select */
382      int drive = -1, side = 0;
383
384      if ( data & 1 )
385      {
386         drive = 0;
387         side = 0;
388      }
389      else if ( data & 2 )
390      {
391         drive = 1;
392         side = 1;
393      }
394      else if ( data & 4 )
395      {
396         drive = 2;
397         side = 0;
398      }
399      else if ( data & 8 )
400      {
401         drive = 3;
402         side = 1;
403      }
404
405      to7_5p14sd_select = data;
406
407      if ( drive != -1 )
408      {
409         thom_floppy_active( space->machine, 0 );
410         mc6843_set_drive( space->machine->device("mc6843"), drive );
411         mc6843_set_side( space->machine->device("mc6843"), side );
412         LOG(( "%f $%04x to7_5p14sd_w: $%02X set drive=%i side=%i\n",
413               attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data, drive, side ));
414      }
415   }
416   else
417      logerror ( "%f $%04x to7_5p14sd_w: invalid write offset %i (data=$%02X)\n",
418            attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset, data );
419}
420
421static void to7_5p14_index_pulse_callback( device_t *controller,device_t *image, int state )
422{
423   mc6843_set_index_pulse( image->machine->device("mc6843"), state );
424}
425
426static void to7_5p14sd_reset( running_machine *machine )
427{
428   int i;
429   LOG(( "to7_5p14sd_reset: CD 90-015 controller\n" ));
430   for ( i = 0; i < floppy_get_count( machine ); i++ )
431   {
432      device_t * img = floppy_get_device( machine, i );
433      if (img) {
434         floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 );
435         floppy_drive_set_rpm( img, 300. );
436         floppy_drive_seek( img, - floppy_drive_get_current_track( img ) );
437         floppy_drive_set_index_pulse_callback( img, to7_5p14_index_pulse_callback );
438      }
439   }
440}
441
442
443
444const mc6843_interface to7_6843_itf = { NULL };
445
446
447
448static void to7_5p14sd_init( running_machine *machine )
449{
450   LOG(( "to7_5p14sd_init: CD 90-015 controller\n" ));
451   state_save_register_global( machine, to7_5p14sd_select );
452}
453
454
455/*********************** CQ 90-028 controller ************************/
456
457/* QDD 2''8 controller
458   used in TO7, TO7/70, MO5 computers
459   it is based on a MC6852 SSDA
460
461   Note: the MC6852 is only partially emulated, most features are not used in
462   the controller and are ignored.
463*/
464
465
466
467/* MC6852 status */
468#define QDD_S_RDA  0x01 /* receiver data available */
469#define QDD_S_TDRA 0x02 /* transitter data register available */
470#define QDD_S_NDCD 0x04 /* data carrier detect, negated (unused) */
471#define QDD_S_NCTS 0x08 /* clear-to-send, negated write-protect */
472#define QDD_S_TUF  0x10 /* transmitter underflow (unused) */
473#define QDD_S_OVR  0x20 /* receiver overrun (unused) */
474#define QDD_S_PE   0x40 /* receiver parity error (unused) */
475#define QDD_S_IRQ  0x80 /* interrupt request */
476#define QDD_S_ERR  (QDD_S_TUF | QDD_S_OVR | QDD_S_PE | QDD_S_NDCD | QDD_S_NCTS)
477
478
479/* MC6852 control */
480#define QDD_C1_RIE       0x20 /* interrupt on reveive */
481#define QDD_C1_TIE       0x10 /* interrupt on transmit */
482#define QDD_C1_CLRSYNC   0x08 /* clear receiver sync char (unused) */
483#define QDD_C1_STRIPSYNC 0x04 /* strips sync from received (unused) */
484#define QDD_C1_TRESET    0x02 /* transmitter reset */
485#define QDD_C1_RRESET    0x01 /* receiver reset */
486#define QDD_C2_EIE       0x80 /* interrupt on error */
487#define QDD_C2_TSYNC     0x40 /* underflow = ff if 0 / sync if 1 (unused) */
488#define QDD_C2_BLEN      0x04 /* transfer byte length (unused) */
489#define QDD_C3_CLRTUF    0x08 /* clear underflow */
490#define QDD_C3_CLRCTS    0x04 /* clear CTS  */
491#define QDD_C3_SYNCLEN   0x02 /* sync byte length (unused) */
492#define QDD_C3_SYNCMODE  0x01 /* external / internal sync mode (unused) */
493
494
495/* a track is actually the whole disk = 400 128-byte sectors + headers */
496#define QDD_MAXBUF ( THOM_QDD_SIZE_ID + THOM_QDD_SIZE_DATA ) * 512
497
498
499static struct _to7qdd
500{
501   /* MC6852 registers */
502   UINT8 status;
503   UINT8 ctrl1;
504   UINT8 ctrl2;
505   UINT8 ctrl3;
506
507   /* extra registers */
508   UINT8 drive;
509
510   /* internal state */
511   UINT8  data[QDD_MAXBUF];  /* enough for a whole track */
512   UINT32 data_idx;          /* byte position in track */
513   UINT32 start_idx;         /* start of write position */
514   UINT32 data_size;         /* track length */
515   UINT8  data_crc;          /* checksum when writing */
516   UINT8  index_pulse;       /* one pulse per track */
517
518} * to7qdd;
519
520
521
522static void to7_qdd_index_pulse_cb ( device_t *controller,device_t *image, int state )
523{
524   to7qdd->index_pulse = state;
525
526   if ( state )
527   {
528      /* rewind to disk start */
529      to7qdd->data_idx = 0;
530      to7qdd->start_idx = 0;
531      to7qdd->data_size = 0;
532   }
533
534   VLOG(( "%f to7_qdd_pulse_cb: state=%i\n", attotime_to_double(timer_get_time(image->machine)), state ));
535}
536
537
538
539static device_t * to7_qdd_image ( running_machine *machine )
540{
541   return floppy_get_device( machine, 0 );
542}
543
544
545
546/* update MC6852 status register */
547static void to7_qdd_stat_update( running_machine *machine )
548{
549   /* byte-ready */
550   to7qdd->status |= QDD_S_RDA | QDD_S_TDRA;
551   if ( ! to7qdd->drive )
552      to7qdd->status |= QDD_S_PE;
553
554   /* write-protect */
555   if (floppy_wpt_r(to7_qdd_image(machine)) == CLEAR_LINE)
556      to7qdd->status |= QDD_S_NCTS;
557
558   /* sticky reset conditions */
559   if ( to7qdd->ctrl1 & QDD_C1_RRESET )
560      to7qdd->status &= ~(QDD_S_PE | QDD_S_RDA | QDD_S_OVR);
561   if ( to7qdd->ctrl1 & QDD_C1_TRESET )
562      to7qdd->status &= ~(QDD_S_TDRA | QDD_S_TUF);
563
564   /* irq update */
565
566   if ( ( (to7qdd->ctrl1 & QDD_C1_RIE) && !(to7qdd->status & QDD_S_RDA ) ) ||
567        ( (to7qdd->ctrl1 & QDD_C1_TIE) && !(to7qdd->status & QDD_S_TDRA) ) ||
568        ( (to7qdd->ctrl2 & QDD_C2_EIE) && !(to7qdd->status & QDD_S_ERR ) ) )
569      to7qdd->status &= ~QDD_S_IRQ;
570
571   if ( ( (to7qdd->ctrl1 & QDD_C1_RIE) && (to7qdd->status & QDD_S_RDA ) ) ||
572        ( (to7qdd->ctrl1 & QDD_C1_TIE) && (to7qdd->status & QDD_S_TDRA) ) ||
573        ( (to7qdd->ctrl2 & QDD_C2_EIE) && (to7qdd->status & QDD_S_ERR ) ) )
574      to7qdd->status |= QDD_S_IRQ;
575}
576
577
578
579static UINT8 to7_qdd_read_byte( running_machine *machine )
580{
581   UINT8 data;
582
583   /* rebuild disk if needed */
584   if ( !to7qdd->data_size )
585   {
586      to7qdd->data_size = thom_qdd_make_disk( to7_qdd_image(machine), to7qdd->data );
587      assert( to7qdd->data_idx < sizeof( to7qdd->data ) );
588   }
589
590   if ( to7qdd->data_idx >= to7qdd->data_size )
591      data = 0;
592   else
593      data = to7qdd->data[ to7qdd->data_idx ];
594
595   VLOG(( "%f $%04x to7_qdd_read_byte: RDATA off=%i/%i data=$%02X\n",
596          attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")),
597          to7qdd->data_idx, to7qdd->data_size, data ));
598
599   to7qdd->data_idx++;
600   to7qdd->start_idx = to7qdd->data_idx;
601
602   return data;
603}
604
605
606
607/* This is quite complex: bytes are written one at a time by the CPU and we
608   must detect the following patterns:
609   * CPU write id field and data field => format
610   * CPU write data field after it has read an id field => sector write
611   */
612static void to7_qdd_write_byte( running_machine *machine, UINT8 data )
613{
614   int i;
615
616   /* rebuild disk if needed */
617   if ( !to7qdd->data_size )
618   {
619      to7qdd->data_size = thom_qdd_make_disk( to7_qdd_image(machine), to7qdd->data );
620      assert( to7qdd->data_idx < sizeof( to7qdd->data ) );
621   }
622
623   if ( ( to7qdd->start_idx != to7qdd->data_idx || /* field in construction */
624          data==0xA5 || data==0x5A ) &&    /* first byte of tentative field */
625        to7qdd->data_idx <to7qdd->data_size )
626   {
627
628      /* this is the first byte of the field */
629      if ( to7qdd->start_idx == to7qdd->data_idx )
630         to7qdd->data_crc = 0;
631
632      /* accumulate bytes */
633      to7qdd->data[ to7qdd->data_idx ] = data;
634      to7qdd->data_idx++;
635
636      VLOG (( "%f $%04x to7_qdd_write_byte: got $%02X offs=%i-%i\n",
637         attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), data,
638         to7qdd->start_idx, to7qdd->data_idx ));
639
640      /* end of tentative id field */
641      if ( to7qdd->data_idx == to7qdd->start_idx + 4 &&
642           to7qdd->data[ to7qdd->start_idx ] == 0xA5 &&
643           to7qdd->data[ to7qdd->start_idx + 3 ] == to7qdd->data_crc )
644      {
645
646         /* got an id field => format */
647         int sector = (int) to7qdd->data[ to7qdd->start_idx + 1 ] * 256 + (int) to7qdd->data[ to7qdd->start_idx + 2 ];
648         UINT8 filler = 0xff;
649
650         LOG(( "%f $%04x to7_qdd_write_byte: got id field for sector=%i\n",
651               attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), sector ));
652
653         floppy_drive_format_sector( to7_qdd_image(machine),
654                      0, sector, 0, 0, sector, 128, filler );
655                        thom_floppy_active( machine, 1 );
656         to7qdd->start_idx = to7qdd->data_idx;
657      }
658
659      /* end of tentative data field */
660      else if ( to7qdd->data_idx == to7qdd->start_idx + 130 &&
661           to7qdd->data[ to7qdd->start_idx  ] == 0x5A &&
662           to7qdd->data[ to7qdd->start_idx + 129 ] == to7qdd->data_crc )
663      {
664
665         /* look backwards for previous id field */
666         for ( i = to7qdd->start_idx - 3; i >= 0; i-- )
667         {
668            if ( to7qdd->data[ i ] == 0xA5 &&
669                 ( ( to7qdd->data[ i ] + to7qdd->data[ i + 1 ] +
670                to7qdd->data[ i + 2 ] ) & 0xff
671                    ) == to7qdd->data[ i + 3 ] )
672               break;
673         }
674
675         if ( i >= 0 )
676         {
677            /* got an id & a data field => write */
678            int sector = (int) to7qdd->data[ i + 1 ] * 256 + (int) to7qdd->data[ i + 2 ];
679
680            LOG(( "%f $%04x to7_qdd_write_byte: goto data field for sector=%i\n",
681                  attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), sector ));
682
683            floppy_drive_write_sector_data( to7_qdd_image(machine), 0, sector, to7qdd->data + to7qdd->start_idx + 1, 128, 0 );
684                                thom_floppy_active( machine, 1 );
685         }
686
687         to7qdd->start_idx = to7qdd->data_idx;
688      }
689
690      else to7qdd->data_crc += data;
691   }
692}
693
694
695
696static READ8_HANDLER ( to7_qdd_r )
697{
698   switch ( offset )
699   {
700
701   case 0: /* MC6852 status */
702      to7_qdd_stat_update(space->machine);
703      VLOG(( "%f $%04x to7_qdd_r: STAT=$%02X irq=%i pe=%i ovr=%i und=%i tr=%i rd=%i ncts=%i\n",
704             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), to7qdd->status,
705             to7qdd->status & QDD_S_IRQ  ? 1 : 0,
706             to7qdd->status & QDD_S_PE   ? 1 : 0,
707             to7qdd->status & QDD_S_OVR  ? 1 : 0,
708             to7qdd->status & QDD_S_TUF  ? 1 : 0,
709             to7qdd->status & QDD_S_TDRA ? 1 : 0,
710             to7qdd->status & QDD_S_RDA  ? 1 : 0,
711             to7qdd->status & QDD_S_NCTS ? 1 : 0 ));
712      return to7qdd->status;
713
714   case 1: /* MC6852 data input => read byte from disk */
715      to7qdd->status &= ~(QDD_S_RDA | QDD_S_PE | QDD_S_OVR);
716      to7_qdd_stat_update(space->machine);
717      return to7_qdd_read_byte( space->machine );
718
719   case 8: /* floppy status */
720   {
721      UINT8 data = 0;
722      device_image_interface* img = dynamic_cast<device_image_interface *>(to7_qdd_image(space->machine));
723      if ( ! img->exists() )
724         data |= 0x40; /* disk present */
725      if ( to7qdd->index_pulse )
726         data |= 0x80; /* disk start */
727      VLOG(( "%f $%04x to7_qdd_r: STATUS8 $%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
728      return data;
729   }
730
731   default:
732      logerror ( "%f $%04x to7_qdd_r: invalid read offset %i\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset );
733      return 0;
734   }
735}
736
737
738
739static WRITE8_HANDLER( to7_qdd_w )
740{
741   switch ( offset )
742   {
743
744   case 0: /* MC6852 control 1 */
745      /* reset */
746      if ( data & QDD_C1_RRESET )
747         to7qdd->status &= ~(QDD_S_PE | QDD_S_RDA | QDD_S_OVR);
748      if ( data & QDD_C1_TRESET )
749         to7qdd->status &= ~(QDD_S_TDRA | QDD_S_TUF);
750
751      to7qdd->ctrl1 = ( data & ~(QDD_C1_RRESET | QDD_C1_TRESET) ) |( data &  (QDD_C1_RRESET | QDD_C1_TRESET) & to7qdd->ctrl1 );
752      to7_qdd_stat_update(space->machine);
753      VLOG(( "%f $%04x to7_qdd_w: CTRL1=$%02X reset=%c%c %s%sirq=%c%c\n",
754             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
755             data & QDD_C1_RRESET ? 'r' : '-', data & QDD_C1_TRESET ? 't' : '-',
756             data & QDD_C1_STRIPSYNC ? "strip-sync " : "",
757             data & QDD_C1_CLRSYNC ? "clear-sync " : "",
758             data & QDD_C1_RIE ? 'r' : '-',
759             data & QDD_C1_TIE ? 't' : '-' ));
760      break;
761
762   case 1:
763      switch ( to7qdd->ctrl1 >> 6 )
764      {
765
766      case 0: /* MC6852 control 2 */
767      {
768#if 0
769         /* most of these are unused now */
770         static const int bit[8] = { 6, 6, 7, 8, 7, 7, 8, 8 };
771         static const int par[8] = { 2, 1, 0, 0, 2, 1, 2, 1 };
772         static const char *const parname[3] = { "none", "odd", "even" };
773         int bits, parity;
774         bits   = bit[ (data >> 3) & 7 ];
775         parity = par[ (data >> 3) & 7 ];
776         to7_qdd_stat_update(space->machine);
777         VLOG(( "%f $%04x to7_qdd_w: CTRL2=$%02X bits=%i par=%s blen=%i under=%s%s\n",
778                attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
779                bits, parname[ parity ], data & QDD_C2_BLEN ? 1 : 2,
780                data & QDD_C2_TSYNC ? "sync" : "ff",
781                data & QDD_C2_EIE ? "irq-err" : "" ));
782#endif
783         to7qdd->ctrl2 = data;
784         break;
785      }
786
787      case 1: /* MC6852 control 3 */
788         to7qdd->ctrl3 = data;
789         /* reset just once each write, not sticky */
790         if ( data & QDD_C3_CLRTUF )
791            to7qdd->status &= ~QDD_S_TUF;
792         if ( data & QDD_C3_CLRCTS )
793            to7qdd->status &= ~QDD_S_NCTS;
794         to7_qdd_stat_update(space->machine);
795         VLOG(( "%f $%04x to7_qdd_w: CTRL3=$%02X %s%ssync-len=%i sync-mode=%s\n",
796                attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
797                data & QDD_C3_CLRTUF ? "clr-tuf " : "",
798                data & QDD_C3_CLRCTS ? "clr-cts " : "",
799                data & QDD_C3_SYNCLEN ? 1 : 2,
800                data & QDD_C3_SYNCMODE ? "ext" : "int" ));
801         break;
802
803      case 2: /* MC6852 sync code => write byte to disk */
804         to7_qdd_write_byte( space->machine, data );
805         break;
806
807      case 3: /* MC6852 data out => does not seem to be used */
808         VLOG(( "%f $%04x to7_qdd_w: ignored WDATA=$%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
809         break;
810
811      }
812      break;
813
814   case 8: /* set drive */
815      to7qdd->drive = data;
816      VLOG(( "%f $%04x to7_qdd_w: DRIVE=$%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
817      break;
818
819   case 12: /* motor pulse ? */
820      thom_floppy_active( space->machine, 0 );
821      VLOG(( "%f $%04x to7_qdd_w: MOTOR=$%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
822      break;
823
824   default:
825      logerror ( "%f $%04x to7_qdd_w: invalid write offset %i (data=$%02X)\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset, data );
826   }
827}
828
829
830
831static void to7_qdd_reset( running_machine *machine )
832{
833   int i;
834   LOG(( "to7_qdd_reset: CQ 90-028 controller\n" ));
835
836   for ( i = 0; i < floppy_get_count( machine ); i++ )
837   {
838      device_t * img = floppy_get_device( machine, i );
839      if (img) {
840         floppy_drive_set_index_pulse_callback( img, to7_qdd_index_pulse_cb );
841         floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 );
842
843         motor_on = CLEAR_LINE;
844         floppy_mon_w(img, motor_on);
845
846         /* pulse each time the whole-disk spiraling track ends */
847         /* at 90us per byte read, the disk can be read in 6s */
848         floppy_drive_set_rpm( img, 60. / 6. );
849      }
850   }
851
852   to7qdd->ctrl1 |= QDD_C1_TRESET | QDD_C1_RRESET; /* reset */
853   to7qdd->ctrl2 &= 0x7c; /* clear EIE, PC2-PC1 */
854   to7qdd->ctrl3 &= 0xfe; /* internal sync */
855   to7qdd->drive = 0;
856   to7_qdd_stat_update(machine);
857}
858
859
860
861static void to7_qdd_init( running_machine *machine )
862{
863   LOG(( "to7_qdd_init: CQ 90-028 controller\n" ));
864
865   to7qdd = auto_alloc(machine, struct _to7qdd);
866
867   state_save_register_global( machine, to7qdd->status );
868   state_save_register_global( machine, to7qdd->ctrl1 );
869   state_save_register_global( machine, to7qdd->ctrl2 );
870   state_save_register_global( machine, to7qdd->ctrl3 );
871   state_save_register_global( machine, to7qdd->drive );
872   state_save_register_global( machine, to7qdd->data_idx );
873   state_save_register_global( machine, to7qdd->start_idx );
874   state_save_register_global( machine, to7qdd->data_size );
875   state_save_register_global( machine, to7qdd->data_crc );
876   state_save_register_global( machine, to7qdd->index_pulse );
877   state_save_register_global_array( machine, to7qdd->data );
878}
879
880
881
882/********************** THMFC1 controller *************************/
883
884/* custom Thomson Gate-array for 3''1/2, 5''1/4 (double density only) & QDD
885 */
886
887
888
889/* types of high-level operations */
890#define THMFC1_OP_RESET         0
891#define THMFC1_OP_WRITE_SECT    1
892#define THMFC1_OP_READ_ADDR     2
893#define THMFC1_OP_READ_SECT     3
894
895
896/* STAT0 flags */
897#define THMFC1_STAT0_SYNCHRO        0x01 /* bit clock synchronized */
898#define THMFC1_STAT0_BYTE_READY_OP  0x02 /* byte ready (high-level operation) */
899#define THMFC1_STAT0_CRC_ERROR      0x04
900#define THMFC1_STAT0_FINISHED       0x08
901#define THMFC1_STAT0_FINISHING      0x10 /* (unemulated) */
902#define THMFC1_STAT0_BYTE_READY_POL 0x80 /* polling mode */
903
904
905/*#define THOM_MAXBUF (THOM_SIZE_ID+THOM_SIZE_DATA_HI+2*THOM_SIZE_SYNCHRO)*17*/
906#define THOM_MAXBUF ( THOM_QDD_SIZE_ID + THOM_QDD_SIZE_DATA ) * 512
907
908
909static struct _thmfc1
910{
911
912   UINT8   op;
913   UINT8   sector;            /* target sector, in [1,16] */
914        UINT32  sector_id;
915   UINT8   track;             /* current track, in [0,79] */
916   UINT8   side;              /* current side, 0 or 1 */
917   UINT8   drive;             /* 0 to 3 */
918   UINT16  sector_size;       /* 128 or 256 (512, 1024 not supported) */
919   UINT8   formatting;
920   UINT8   ipl;               /* index pulse / QDD start */
921   UINT8   wsync;             /* synchronization word */
922
923   UINT8   data[THOM_MAXBUF]; /* enough for a whole track */
924   UINT32  data_idx;          /* reading / writing / formatting pos */
925   UINT32  data_size;         /* bytes to read / write */
926   UINT32  data_finish;       /* when to raise the finished flag */
927   UINT32  data_raw_idx;      /* byte index for raw track reading */
928   UINT32  data_raw_size;     /* size of track already cached in data */
929   UINT8   data_crc;          /* check-sum of written data */
930
931   UINT8   stat0;             /* status register */
932
933} * thmfc1;
934
935
936static emu_timer* thmfc_floppy_cmd;
937
938
939
940static device_t * thmfc_floppy_image ( running_machine *machine )
941{
942   return floppy_get_device( machine, thmfc1->drive );
943}
944
945
946
947static int thmfc_floppy_is_qdd ( device_image_interface *image )
948{
949   if (image==NULL) return 0;
950   if (!image->exists()) return 0;
951   return image->length()==51200; // idf QDD
952}
953
954
955
956static void thmfc_floppy_index_pulse_cb ( device_t *controller,device_t *image, int state )
957{
958   if ( image != thmfc_floppy_image(image->machine) )
959      return;
960
961   if ( thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(image)))
962   {
963      /* pulse each time the whole-disk spiraling track ends */
964      floppy_drive_set_rpm( image, 16.92f /* 423/25 */ );
965      thmfc1->ipl = state;
966      if ( state )
967      {
968         thmfc1->data_raw_size = 0;
969         thmfc1->data_raw_idx = 0;
970         thmfc1->data_idx = 0;
971      }
972   }
973   else
974   {
975      floppy_drive_set_rpm( image, 300. );
976      thmfc1->ipl = state;
977      if ( state  )
978         thmfc1->data_raw_idx = 0;
979   }
980
981   VLOG(( "%f thmfc_floppy_index_pulse_cb: state=%i\n", attotime_to_double(timer_get_time(image->machine)), state ));
982}
983
984
985
986static int thmfc_floppy_find_sector ( running_machine *machine, chrn_id* dst )
987{
988   device_t* img = thmfc_floppy_image(machine);
989   chrn_id id;
990   int r = 0;
991
992   /* scan track, try 4 revolutions */
993   while ( r < 4 )
994   {
995
996      if ( floppy_drive_get_next_id( img, thmfc1->side, &id ) )
997      {
998         if ( id.C == thmfc1->track &&
999              id.R == thmfc1->sector &&
1000              (128 << id.N) == thmfc1->sector_size
1001              /* check side ?  id.H == thmfc1->side */ )
1002         {
1003            if ( dst )
1004               memcpy( dst, &id, sizeof( chrn_id ) );
1005            thmfc1->stat0 = THMFC1_STAT0_BYTE_READY_POL;
1006            LOG (( "thmfc_floppy_find_sector: sector found C=%i H=%i R=%i N=%i\n", id.C, id.H, id.R, id.N ));
1007            return 1;
1008         }
1009      }
1010
1011      if ( floppy_drive_get_flag_state( img, FLOPPY_DRIVE_INDEX ) )
1012         r++;
1013   }
1014
1015   thmfc1->stat0 = THMFC1_STAT0_CRC_ERROR | THMFC1_STAT0_FINISHED;
1016   LOG (( "thmfc_floppy_find_sector: sector not found drive=%i track=%i sector=%i\n", floppy_get_drive( img ), thmfc1->track, thmfc1->sector ));
1017   return 0;
1018}
1019
1020
1021
1022/* complete command (by read, write, or timeout) */
1023static void thmfc_floppy_cmd_complete( running_machine *machine )
1024{
1025   LOG (( "%f thmfc_floppy_cmd_complete_cb: cmd=%i off=%i/%i/%i\n",
1026          attotime_to_double(timer_get_time(machine)), thmfc1->op, thmfc1->data_idx,
1027          thmfc1->data_finish - 1, thmfc1->data_size - 1 ));
1028
1029   if ( thmfc1->op == THMFC1_OP_WRITE_SECT )
1030   {
1031      device_t * img = thmfc_floppy_image(machine);
1032      floppy_drive_write_sector_data( img, thmfc1->side, thmfc1->sector_id, thmfc1->data + 3, thmfc1->data_size - 3, 0 );
1033                thom_floppy_active( machine, 1 );
1034   }
1035   thmfc1->op = THMFC1_OP_RESET;
1036   thmfc1->stat0 |= THMFC1_STAT0_FINISHED;
1037   thmfc1->data_idx = 0;
1038   thmfc1->data_size = 0;
1039   timer_adjust_oneshot(thmfc_floppy_cmd, attotime_never, 0);
1040}
1041
1042
1043
1044static TIMER_CALLBACK( thmfc_floppy_cmd_complete_cb )
1045{
1046   thmfc_floppy_cmd_complete( machine );
1047}
1048
1049
1050
1051/* intelligent read: show just one field, skip header */
1052static UINT8 thmfc_floppy_read_byte ( running_machine *machine )
1053{
1054   UINT8 data = thmfc1->data[ thmfc1->data_idx ];
1055
1056   VLOG(( "%f $%04x thmfc_floppy_read_byte: off=%i/%i/%i data=$%02X\n",
1057          attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")),
1058          thmfc1->data_idx, thmfc1->data_finish - 1, thmfc1->data_size - 1,
1059          data ));
1060
1061   if ( thmfc1->data_idx >= thmfc1->data_size - 1 )
1062      thmfc_floppy_cmd_complete( machine );
1063   else
1064      thmfc1->data_idx++;
1065
1066   if ( thmfc1->data_idx >= thmfc1->data_finish )
1067      thmfc1->stat0 |= THMFC1_STAT0_FINISHED;
1068
1069   return data;
1070}
1071
1072
1073
1074/* dumb read: show whole track with field headers and gaps  */
1075static UINT8 thmfc_floppy_raw_read_byte ( running_machine *machine )
1076{
1077   UINT8 data;
1078
1079   /* rebuild track if needed */
1080   if ( ! thmfc1->data_raw_size )
1081   {
1082      if ( thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(thmfc_floppy_image(machine))))
1083         /* QDD: track = whole disk */
1084         thmfc1->data_raw_size = thom_qdd_make_disk ( thmfc_floppy_image(machine), thmfc1->data );
1085      else
1086      {
1087         thmfc1->data_raw_idx = 0;
1088         thmfc1->data_raw_size = thom_floppy_make_track( thmfc_floppy_image(machine), thmfc1->data,
1089                           thmfc1->sector_size, thmfc1->side );
1090      }
1091      assert( thmfc1->data_raw_size < sizeof( thmfc1->data ) );
1092   }
1093
1094   if ( thmfc1->data_raw_idx >= thmfc1->data_raw_size )
1095      data = 0;
1096   else
1097      data = thmfc1->data[ thmfc1->data_raw_idx ];
1098
1099   VLOG(( "%f $%04x thmfc_floppy_raw_read_byte: off=%i/%i data=$%02X\n",
1100          attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")),
1101          thmfc1->data_raw_idx, thmfc1->data_raw_size, data ));
1102
1103   thmfc1->data_raw_idx++;
1104
1105   return data;
1106}
1107
1108
1109
1110/* QDD writing / formating */
1111static void thmfc_floppy_qdd_write_byte ( running_machine *machine, UINT8 data )
1112{
1113   int i;
1114
1115   if ( thmfc1->formatting &&
1116        ( thmfc1->data_idx || data==0xA5 || data==0x5A ) &&
1117        thmfc1->data_raw_idx < THOM_MAXBUF )
1118   {
1119
1120      if ( ! thmfc1->data_raw_size )
1121      {
1122         thmfc1->data_raw_size = thom_qdd_make_disk ( thmfc_floppy_image(machine), thmfc1->data );
1123         assert( thmfc1->data_raw_size < sizeof( thmfc1->data ) );
1124      }
1125
1126      /* accumulate bytes to form a field */
1127      thmfc1->data[ thmfc1->data_raw_idx ] = data;
1128      thmfc1->data_raw_idx++;
1129
1130      if ( ! thmfc1->data_idx  )
1131      {
1132         /* start */
1133         thmfc1->data_crc = 0;
1134         thmfc1->data_idx = thmfc1->data_raw_idx;
1135      }
1136
1137      VLOG (( "%f $%04x thmfc_floppy_qdd_write_byte: $%02X offs=%i-%i\n",
1138         attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), data,
1139         thmfc1->data_idx,thmfc1->data_raw_idx ));
1140
1141      if ( thmfc1->data_raw_idx == thmfc1->data_idx + 3 &&
1142           thmfc1->data[ thmfc1->data_idx - 1 ] == 0xA5 &&
1143           thmfc1->data[ thmfc1->data_idx + 2 ] == thmfc1->data_crc )
1144      {
1145
1146         /* got an id field => format */
1147         int sector = (int) thmfc1->data[ thmfc1->data_idx ] * 256 + (int) thmfc1->data[ thmfc1->data_idx + 1 ];
1148         UINT8 filler = 0xff;
1149
1150         LOG(( "%f $%04x thmfc_floppy_qdd_write_byte: id field, sector=%i\n", attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), sector ));
1151
1152         floppy_drive_format_sector( thmfc_floppy_image(machine), 0, sector, 0, 0, sector, 128, filler );
1153                        thom_floppy_active( machine, 1 );
1154         thmfc1->data_idx = 0;
1155      }
1156
1157      else if ( thmfc1->data_raw_idx == thmfc1->data_idx + 129 &&
1158           thmfc1->data[ thmfc1->data_idx -   1 ] == 0x5A &&
1159           thmfc1->data[ thmfc1->data_idx + 128 ] == thmfc1->data_crc )
1160      {
1161
1162         /* look backwards for previous id field */
1163         for ( i = thmfc1->data_idx - 4; i >= 0; i-- )
1164         {
1165            if ( thmfc1->data[ i ] == 0xA5 &&
1166                 ( ( thmfc1->data[ i ] + thmfc1->data[ i + 1 ] +
1167                thmfc1->data[ i + 2 ] ) & 0xff
1168                    ) == thmfc1->data[ i + 3 ] )
1169               break;
1170         }
1171
1172         if ( i >= 0 )
1173         {
1174            /* got an id & a data field => write */
1175            device_t * img = thmfc_floppy_image(machine);
1176            int sector = (int) thmfc1->data[ i + 1 ] * 256 +
1177               (int) thmfc1->data[ i + 2 ];
1178
1179            LOG(( "%f $%04x thmfc_floppy_qdd_write_byte: data field, sector=%i\n",
1180                  attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), sector ));
1181
1182            floppy_drive_write_sector_data( img, 0, sector, thmfc1->data + thmfc1->data_idx, 128, 0 );
1183                                thom_floppy_active( machine, 1 );
1184         }
1185
1186         thmfc1->data_idx = 0;
1187
1188      }
1189      else
1190         thmfc1->data_crc += data;
1191   }
1192   else
1193   {
1194      thmfc1->data_raw_idx++;
1195      VLOG (( "%f $%04x thmfc_floppy_qdd_write_byte: ignored $%02X\n", attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), data ));
1196   }
1197
1198}
1199
1200
1201
1202/* intelligent writing */
1203static void thmfc_floppy_write_byte ( running_machine *machine, UINT8 data )
1204{
1205   VLOG (( "%f $%04x thmfc_floppy_write_byte: off=%i/%i data=$%02X\n",
1206      attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")),
1207      thmfc1->data_idx, thmfc1->data_size - 1, data ));
1208
1209   thmfc1->data_raw_size = 0;
1210   thmfc1->data[ thmfc1->data_idx ] = data;
1211   if ( thmfc1->data_idx >= thmfc1->data_size - 1 )
1212      thmfc_floppy_cmd_complete( machine );
1213   else
1214      thmfc1->data_idx++;
1215}
1216
1217/* intelligent formatting */
1218static void thmfc_floppy_format_byte ( running_machine *machine, UINT8 data )
1219{
1220   VLOG (( "%f $%04x thmfc_floppy_format_byte: $%02X\n", attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), data ));
1221
1222   thmfc1->data_raw_size = 0;
1223
1224   /* accumulate bytes to form an id field */
1225   if ( thmfc1->data_idx || data==0xA1 )
1226   {
1227      static const UINT8 header[] = { 0xa1, 0xa1, 0xa1, 0xfe };
1228      thmfc1->data[ thmfc1->data_idx ] = data;
1229      thmfc1->data_idx++;
1230      if ( thmfc1->data_idx > 11 )
1231      {
1232
1233         if ( !memcmp ( thmfc1->data, header, sizeof( header ) ) )
1234         {
1235            /* got id field => format */
1236            device_t * img = thmfc_floppy_image(machine);
1237            UINT8 track  = thmfc1->data[4];
1238            UINT8 side   = thmfc1->data[5];
1239            UINT8 sector = thmfc1->data[6];
1240            UINT8 length = thmfc1->data[7]; /* actually, log length */
1241            UINT8 filler = 0xe5;            /* standard Thomson filler */
1242                                chrn_id id;
1243                                if ( thmfc_floppy_find_sector( machine, &id ) )
1244                                {
1245                                        floppy_drive_format_sector( img, side, thmfc1->sector_id, track, thmfc1->side, sector, length, filler );
1246                                        thom_floppy_active( machine, 1 );
1247                                }
1248         }
1249
1250         thmfc1->data_idx = 0;
1251      }
1252
1253   }
1254}
1255
1256
1257
1258READ8_HANDLER ( thmfc_floppy_r )
1259{
1260   switch ( offset )
1261   {
1262
1263   case 0: /* STAT0 */
1264      thmfc1->stat0 ^= THMFC1_STAT0_SYNCHRO | THMFC1_STAT0_BYTE_READY_POL;
1265      VLOG(( "%f $%04x thmfc_floppy_r: STAT0=$%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), thmfc1->stat0 ));
1266      return thmfc1->stat0;
1267
1268   case 1: /* STAT1 */
1269   {
1270      UINT8 data = 0;
1271      device_image_interface * img = dynamic_cast<device_image_interface *>(thmfc_floppy_image(space->machine));
1272      int flags = floppy_drive_get_flag_state( &img->device(), -1 );
1273      if ( thmfc_floppy_is_qdd(img) )
1274      {
1275         if ( ! img->exists() )
1276            data |= 0x40; /* disk present */
1277         if ( ! thmfc1->ipl )
1278            data |= 0x02;       /* disk start */
1279         data |= 0x08; /* connected */
1280      }
1281      else
1282      {
1283         if ( thmfc1->ipl )
1284            data |= 0x40;
1285         if ( img->exists() )
1286            data |= 0x20; /* disk change (?) */
1287
1288         data |= !floppy_tk00_r(&img->device()) << 3;
1289
1290         if ( flags & FLOPPY_DRIVE_READY )
1291            data |= 0x02;
1292      }
1293      if (!motor_on)
1294         data |= 0x10;
1295      if (!floppy_wpt_r(&img->device()))
1296         data |= 0x04;
1297      VLOG(( "%f $%04x thmfc_floppy_r: STAT1=$%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
1298      return data;
1299   }
1300
1301   case 3: /* RDATA */
1302
1303      if ( thmfc1->op == THMFC1_OP_READ_SECT || thmfc1->op == THMFC1_OP_READ_ADDR )
1304         return thmfc_floppy_read_byte( space->machine );
1305      else
1306         return thmfc_floppy_raw_read_byte( space->machine );
1307
1308   case 6:
1309      return 0;
1310
1311   case 8:
1312   {
1313      /* undocumented => emulate TO7 QDD controller ? */
1314      UINT8 data = thmfc1->ipl << 7;
1315      VLOG(( "%f $%04x thmfc_floppy_r: STAT8=$%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
1316      return data;
1317   }
1318
1319   default:
1320      logerror ( "%f $%04x thmfc_floppy_r: invalid read offset %i\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset );
1321      return 0;
1322   }
1323}
1324
1325
1326
1327WRITE8_HANDLER ( thmfc_floppy_w )
1328{
1329   switch ( offset ) {
1330
1331   case 0: /* CMD0 */
1332   {
1333      int wsync = (data >> 4) & 1;
1334      int qdd = thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(thmfc_floppy_image(space->machine)));
1335      chrn_id id;
1336      thmfc1->formatting = (data >> 2) & 1;
1337      LOG (( "%f $%04x thmfc_floppy_w: CMD0=$%02X dens=%s wsync=%i dsync=%i fmt=%i op=%i\n",
1338             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
1339             (BIT(data, 5) ? "FM" : "MFM"),
1340             wsync, (data >> 3) & 1,
1341             thmfc1->formatting, data & 3 ));
1342
1343      /* abort previous command, if any */
1344      thmfc1->op = THMFC1_OP_RESET;
1345      timer_adjust_oneshot(thmfc_floppy_cmd, attotime_never, 0);
1346
1347      switch ( data & 3 )
1348      {
1349
1350      case THMFC1_OP_RESET:
1351         thmfc1->stat0 = THMFC1_STAT0_FINISHED;
1352         break;
1353
1354      case THMFC1_OP_WRITE_SECT:
1355         if ( qdd )
1356            logerror( "thmfc_floppy_w: smart operation 1 not supported for QDD\n" );
1357         else if ( thmfc_floppy_find_sector( space->machine, &id ) )
1358         {
1359                                thmfc1->sector_id = id.data_id;
1360            thmfc1->data_idx = 0;
1361            thmfc1->data_size = thmfc1->sector_size + 3; /* A1 A1 FB <data> */
1362            thmfc1->data_finish = thmfc1->sector_size + 3;
1363            thmfc1->stat0 |= THMFC1_STAT0_BYTE_READY_OP;
1364            thmfc1->op = THMFC1_OP_WRITE_SECT;
1365            timer_adjust_oneshot(thmfc_floppy_cmd, ATTOTIME_IN_MSEC( 10 ), 0);
1366         }
1367         break;
1368
1369      case THMFC1_OP_READ_ADDR:
1370         if ( qdd )
1371            logerror( "thmfc_floppy_w: smart operation 2 not supported for QDD\n" );
1372         else if ( thmfc_floppy_find_sector( space->machine, &id ) )
1373         {
1374            thmfc1->data_size =
1375               thom_floppy_make_addr( id, thmfc1->data, thmfc1->sector_size );
1376            assert( thmfc1->data_size < sizeof( thmfc1->data ) );
1377            thmfc1->data_finish = 10;
1378            thmfc1->data_idx = 1;
1379            thmfc1->stat0 |= THMFC1_STAT0_BYTE_READY_OP;
1380            thmfc1->op = THMFC1_OP_READ_ADDR;
1381            timer_adjust_oneshot(thmfc_floppy_cmd, ATTOTIME_IN_MSEC( 1 ), 0);
1382         }
1383         break;
1384
1385      case THMFC1_OP_READ_SECT:
1386         if ( qdd )
1387            logerror( "thmfc_floppy_w: smart operation 3 not supported for QDD\n" );
1388         else if ( thmfc_floppy_find_sector( space->machine, &id ) )
1389         {
1390            thmfc1->data_size = thom_floppy_make_sector
1391               ( thmfc_floppy_image(space->machine), id, thmfc1->data, thmfc1->sector_size );
1392            assert( thmfc1->data_size < sizeof( thmfc1->data ) );
1393            thmfc1->data_finish = thmfc1->sector_size + 4;
1394            thmfc1->data_idx = 1;
1395            thmfc1->stat0 |= THMFC1_STAT0_BYTE_READY_OP;
1396            thmfc1->op = THMFC1_OP_READ_SECT;
1397            timer_adjust_oneshot(thmfc_floppy_cmd, ATTOTIME_IN_MSEC( 10 ), 0);
1398         }
1399         break;
1400      }
1401
1402      /* synchronize to word, if needed (QDD only) */
1403      if ( wsync && qdd ) {
1404         if ( ! thmfc1->data_raw_size )
1405            thmfc1->data_raw_size = thom_qdd_make_disk ( thmfc_floppy_image(space->machine), thmfc1->data );
1406         while ( thmfc1->data_raw_idx < thmfc1->data_raw_size &&
1407            thmfc1->data[ thmfc1->data_raw_idx ] != thmfc1->wsync )
1408         {
1409            thmfc1->data_raw_idx++;
1410         }
1411      }
1412   }
1413
1414   break;
1415
1416
1417   case 1: /* CMD1 */
1418      thmfc1->data_raw_size = 0;
1419      thmfc1->sector_size = 128 << ( (data >> 5) & 3);
1420      thmfc1->side = (data >> 4) & 1;
1421      if ( thmfc1->sector_size > 256 )
1422      {
1423         logerror( "$%04x thmfc_floppy_w: sector size %i > 256 not handled\n",
1424              cpu_get_previouspc(space->machine->device("maincpu")), thmfc1->sector_size );
1425         thmfc1->sector_size = 256;
1426      }
1427
1428      LOG (( "%f $%04x thmfc_floppy_w: CMD1=$%02X sect-size=%i comp=%i head=%i\n",
1429             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
1430             thmfc1->sector_size, (data >> 1) & 7, thmfc1->side ));
1431      break;
1432
1433
1434   case 2: /* CMD2 */
1435   {
1436      device_t * img;
1437      int seek = 0, motor;
1438      thmfc1->drive = data & 2;
1439
1440      img = thmfc_floppy_image(space->machine);
1441      if ( thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(img)))
1442      {
1443         motor = !(data & 0x40);
1444         /* no side select & no seek for QDD */
1445      }
1446      else
1447      {
1448         if ( data & 0x10 )
1449            seek = (data & 0x20) ? 1 : -1;
1450         motor =  (data >> 2) & 1;
1451         thmfc1->drive |= 1 ^ ((data >> 6) & 1);
1452                        img = thmfc_floppy_image(space->machine);
1453      }
1454
1455      thom_floppy_active( space->machine, 0 );
1456
1457      LOG (( "%f $%04x thmfc_floppy_w: CMD2=$%02X drv=%i step=%i motor=%i\n",
1458             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
1459             thmfc1->drive, seek, motor ));
1460
1461      if ( seek )
1462      {
1463         thmfc1->data_raw_size = 0;
1464         floppy_drive_seek( img, seek );
1465      }
1466
1467      /* in real life, to keep the motor running, it is sufficient to
1468           set motor to 1 every few seconds.
1469           instead of counting, we assume the motor is always running...
1470        */
1471      motor_on = CLEAR_LINE /* motor */;
1472      floppy_mon_w(img, motor_on);
1473   }
1474   break;
1475
1476
1477   case 3: /* WDATA */
1478      thmfc1->wsync = data;
1479      if ( thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(thmfc_floppy_image(space->machine))))
1480         thmfc_floppy_qdd_write_byte( space->machine, data );
1481      else if ( thmfc1->op==THMFC1_OP_WRITE_SECT )
1482         thmfc_floppy_write_byte( space->machine, data );
1483      else if ( thmfc1->formatting )
1484         thmfc_floppy_format_byte( space->machine, data );
1485      else
1486      {
1487         /* TODO: implement other forms of raw track writing */
1488         LOG (( "%f $%04x thmfc_floppy_w: ignored raw WDATA $%02X\n",
1489                attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
1490      }
1491      break;
1492
1493
1494   case 4: /* WCLK (unemulated) */
1495      /* clock configuration: FF for data, 0A for synchro */
1496      LOG (( "%f $%04x thmfc_floppy_w: WCLK=$%02X (%s)\n",
1497             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
1498             (data == 0xff) ? "data" : (data == 0x0A) ? "synchro" : "?" ));
1499      break;
1500
1501   case 5: /* WSECT */
1502      thmfc1->sector = data;
1503      LOG (( "%f $%04x thmfc_floppy_w: WSECT=%i\n",
1504             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
1505      break;
1506
1507   case 6: /* WTRCK */
1508      thmfc1->track = data;
1509      LOG (( "%f $%04x thmfc_floppy_w: WTRCK=%i (real=%i)\n",
1510             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
1511             floppy_drive_get_current_track( thmfc_floppy_image(space->machine) ) ));
1512      break;
1513
1514   case 7: /* WCELL */
1515      /* precompensation (unemulated) */
1516      LOG (( "%f $%04x thmfc_floppy_w: WCELL=$%02X\n",
1517             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
1518      break;
1519
1520   default:
1521      logerror ( "%f $%04x thmfc_floppy_w: invalid write offset %i (data=$%02X)\n",
1522            attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset, data );
1523   }
1524}
1525
1526
1527
1528void thmfc_floppy_reset( running_machine *machine )
1529{
1530   int i;
1531   LOG(( "thmfc_floppy_reset: THMFC1 controller\n" ));
1532
1533   for ( i = 0; i < floppy_get_count( machine ); i++ )
1534   {
1535      device_t * img = floppy_get_device( machine, i );
1536      if (img) {
1537         floppy_drive_set_index_pulse_callback( img, thmfc_floppy_index_pulse_cb );
1538         floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 );
1539         floppy_drive_seek( img, - floppy_drive_get_current_track( img ) );
1540      }
1541   }
1542
1543   thmfc1->op = THMFC1_OP_RESET;
1544   thmfc1->track = 0;
1545   thmfc1->sector = 0;
1546   thmfc1->side = 0;
1547   thmfc1->drive = 0;
1548   thmfc1->sector_size = 256;
1549   thmfc1->formatting = 0;
1550   thmfc1->stat0 = 0;
1551   thmfc1->data_idx = 0;
1552   thmfc1->data_size = 0;
1553   thmfc1->data_raw_idx = 0;
1554   thmfc1->data_raw_size = 0;
1555   thmfc1->data_crc = 0;
1556   thmfc1->wsync = 0;
1557   timer_adjust_oneshot(thmfc_floppy_cmd, attotime_never, 0);
1558}
1559
1560
1561
1562void thmfc_floppy_init( running_machine *machine )
1563{
1564   LOG(( "thmfc_floppy_init: THMFC1 controller\n" ));
1565
1566   thmfc1 = auto_alloc(machine, struct _thmfc1);
1567
1568   thmfc_floppy_cmd = timer_alloc( machine, thmfc_floppy_cmd_complete_cb, NULL );
1569
1570   state_save_register_global( machine, thmfc1->op );
1571   state_save_register_global( machine, thmfc1->sector );
1572   state_save_register_global( machine, thmfc1->sector_id );
1573   state_save_register_global( machine, thmfc1->track );
1574   state_save_register_global( machine, thmfc1->side );
1575   state_save_register_global( machine, thmfc1->drive );
1576   state_save_register_global( machine, thmfc1->sector_size );
1577   state_save_register_global( machine, thmfc1->formatting );
1578   state_save_register_global( machine, thmfc1->ipl );
1579   state_save_register_global( machine, thmfc1->data_idx );
1580   state_save_register_global( machine, thmfc1->data_size );
1581   state_save_register_global( machine, thmfc1->data_finish );
1582   state_save_register_global( machine, thmfc1->stat0 );
1583   state_save_register_global( machine, thmfc1->data_raw_idx );
1584   state_save_register_global( machine, thmfc1->data_raw_size );
1585   state_save_register_global( machine, thmfc1->data_crc );
1586   state_save_register_global( machine, thmfc1->wsync );
1587   state_save_register_global_array( machine, thmfc1->data );
1588}
1589
1590
1591
1592/*********************** Network ************************/
1593
1594/* The network extension is built as an external floppy controller.
1595   It uses the same ROM and I/O space, and so, it is natural to have the
1596   toplevel network emulation here!
1597*/
1598
1599/* NOTE: This is work in progress!
1600   For the moment, only hand-checks works: the TO7 can take the line, then
1601   perform a DKBOOT request. We do not have the server emulated yet, so,
1602   no way to answer the request.
1603*/
1604
1605static TIMER_CALLBACK( ans4 )
1606{
1607   LOG(( "%f ans4\n", attotime_to_double(timer_get_time(machine)) ));
1608   mc6854_set_cts( machine->device("mc6854"), 0 );
1609}
1610
1611static TIMER_CALLBACK( ans3 )
1612{
1613   LOG(( "%f ans3\n", attotime_to_double(timer_get_time(machine)) ));
1614   mc6854_set_cts( machine->device("mc6854"), 1 );
1615   timer_set( machine, ATTOTIME_IN_USEC( 100 ), NULL, 0, ans4 );
1616}
1617
1618static TIMER_CALLBACK( ans2 )
1619{
1620   LOG(( "%f ans2\n", attotime_to_double(timer_get_time(machine)) ));
1621   mc6854_set_cts( machine->device("mc6854"), 0 );
1622   timer_set( machine, ATTOTIME_IN_USEC( 100 ), NULL, 0, ans3 );
1623}
1624
1625static TIMER_CALLBACK( ans )
1626{
1627   LOG(( "%f ans\n", attotime_to_double(timer_get_time(machine)) ));
1628   mc6854_set_cts( machine->device("mc6854"), 1 );
1629   timer_set( machine, ATTOTIME_IN_USEC( 100 ), NULL, 0, ans2 );
1630}
1631/* consigne DKBOOT
1632
1633   MO5 BASIC
1634   $00 $00 $01 $00 $00 $00 $00 $00 $00 $00 $01 $00<$41 $00 $FF $20
1635   $3D $4C $01 $60 $20 $3C $4F $01 $05 $20 $3F $9C $19 $25 $03 $11
1636   $93 $15 $10 $25 $32 $8A $7E $FF $E1 $FD $E9 $41>$00 $00 $00 $00
1637   $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00
1638
1639   TO7/70 BASIC
1640   $00 $00 $01 $00 $00 $00 $00 $00 $00 $00 $02 $00<$20 $42 $41 $53
1641   $49 $43 $20 $4D $49 $43 $52 $4F $53 $4F $46 $54 $20 $31 $2E $30
1642   $04 $00 $00 $00 $00 $00 $60 $FF $37 $9B $37 $9C>$00 $00 $00 $00
1643   $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00
1644
1645   TO7 BASIC
1646   $00 $00 $01 $00 $00 $00 $00 $00 $00 $00 $00 $00<$20 $42 $41 $53
1647   $49 $43 $20 $4D $49 $43 $52 $4F $53 $4F $46 $54 $20 $31 $2E $30
1648   $04 $00 $00 $00 $00 $00 $60 $FF $37 $9B $37 $9C>$00 $00 $00 $00
1649   $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00
1650
1651   TO7 LOGO
1652   $00 $00 $01 $00 $00 $00 $00 $00 $00 $00 $00 $00<$00 $00 $00 $00
1653   $00 $20 $4C $4F $47 $4F $04 $00 $00 $00 $00 $00 $00 $00 $00 $00
1654   $00 $00 $00 $00 $00 $00 $AA $FF $01 $16 $00 $C8>$00 $00 $00 $00
1655   $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00
1656
1657
1658*/
1659
1660static void to7_network_got_frame( device_t *device, UINT8* data, int length )
1661{
1662   int i;
1663   LOG(( "%f to7_network_got_frame:", attotime_to_double(timer_get_time(device->machine)) ));
1664   for ( i = 0; i < length; i++ )
1665      LOG(( " $%02X", data[i] ));
1666   LOG(( "\n" ));
1667
1668   if ( data[1] == 0xff )
1669   {
1670      LOG(( "to7_network_got_frame: %i phones %i\n", data[2], data[0] ));
1671      timer_set( device->machine, ATTOTIME_IN_USEC( 100 ), NULL, 0, ans  );
1672      mc6854_set_cts( device, 0 );
1673   }
1674   else if ( ! data[1] )
1675   {
1676      char name[33];
1677      memcpy( name, data + 12, 32 );
1678      name[32] = 0;
1679      for (i=0;i<32;i++)
1680      {
1681         if ( name[i]<32 || name[i]>=127 )
1682            name[i]=' ';
1683      }
1684      LOG(( "to7_network_got_frame: DKBOOT system=%s appli=\"%s\"\n",
1685            (data[10] == 0) ? "TO7" : (data[10] == 1) ? "MO5" :
1686            (data[10] == 2) ? "TO7/70" : "?", name ));
1687   }
1688
1689}
1690
1691
1692
1693const mc6854_interface to7_network_iface = { NULL, to7_network_got_frame, NULL, NULL };
1694
1695
1696
1697static void to7_network_init( running_machine *machine )
1698{
1699   LOG(( "to7_network_init: NR 07-005 network extension\n" ));
1700   logerror( "to7_network_init: network not handled!\n" );
1701}
1702
1703
1704
1705static void to7_network_reset( running_machine *machine )
1706{
1707   LOG(( "to7_network_reset: NR 07-005 network extension\n" ));
1708   mc6854_set_cts( machine->device("mc6854"), 0 );
1709   mc6854_set_cts( machine->device("mc6854"), 1 );
1710}
1711
1712
1713
1714static READ8_HANDLER ( to7_network_r )
1715{
1716   if ( offset >= 0 && offset < 4 )
1717      return mc6854_r( space->machine->device("mc6854"), offset );
1718
1719   if ( offset == 8 )
1720   {
1721      /* network ID of the computer */
1722      UINT8 id = input_port_read(space->machine, "fconfig") >> 3;
1723      VLOG(( "%f $%04x to7_network_r: read id $%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), id ));
1724      return id;
1725   }
1726
1727   logerror( "%f $%04x to7_network_r: invalid read offset %i\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset );
1728   return 0;
1729}
1730
1731
1732
1733static WRITE8_HANDLER ( to7_network_w )
1734{
1735   if ( offset >= 0 && offset < 4 )
1736      mc6854_w( space->machine->device("mc6854"), offset, data );
1737   else
1738   {
1739      logerror( "%f $%04x to7_network_w: invalid write offset %i (data=$%02X)\n",
1740           attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset, data );
1741   }
1742}
1743
1744
1745
1746/*********************** TO7 dispatch ************************/
1747
1748/* The TO7, TO7/70, MO5 and MO6 can use a variety of floppy controllers.
1749   We use a PORT_CONFSETTING to chose the current controller, and dispatch
1750   here.
1751
1752   NOTE: you need to reset the computer after changing the floppy controller!
1753
1754   The CD 90-351 controller seems similar to the THMFC1 gate-array
1755   => we reuse the THMFC code!
1756*/
1757
1758
1759
1760UINT8 to7_controller_type;
1761UINT8 to7_floppy_bank;
1762
1763
1764void to7_floppy_init ( running_machine *machine, void* base )
1765{
1766   memory_configure_bank( machine, THOM_FLOP_BANK, 0, TO7_NB_FLOP_BANK, base, 0x800 );
1767   state_save_register_global( machine, to7_controller_type );
1768   state_save_register_global( machine, to7_floppy_bank );
1769   to7_5p14sd_init(machine);
1770   to7_5p14_init(machine);
1771   to7_qdd_init(machine);
1772   thmfc_floppy_init(machine);
1773   to7_network_init(machine);
1774}
1775
1776
1777
1778void to7_floppy_reset ( running_machine *machine )
1779{
1780   to7_controller_type = (input_port_read(machine, "fconfig") ) & 7;
1781
1782   switch ( to7_controller_type )
1783   {
1784
1785   case 1:
1786      to7_floppy_bank = 1;
1787      to7_5p14sd_reset(machine);
1788      break;
1789
1790   case 2:
1791      to7_floppy_bank = 2;
1792      to7_5p14_reset(machine);
1793      break;
1794
1795   case 3:
1796      to7_floppy_bank = 3;
1797      thmfc_floppy_reset(machine);
1798      break;
1799
1800   case 4:
1801      to7_floppy_bank = 7;
1802      to7_qdd_reset(machine);
1803      break;
1804
1805   case 5:
1806      to7_floppy_bank = 8;
1807      to7_network_reset(machine);
1808      break;
1809
1810   default:
1811      to7_floppy_bank = 0;
1812      break;
1813   }
1814
1815   memory_set_bank( machine, THOM_FLOP_BANK, to7_floppy_bank );
1816}
1817
1818
1819
1820READ8_HANDLER ( to7_floppy_r )
1821{
1822   switch ( to7_controller_type )
1823   {
1824
1825   case 1:
1826      return to7_5p14sd_r( space, offset );
1827
1828   case 2:
1829      return to7_5p14_r( space, offset );
1830
1831   case 3:
1832      return thmfc_floppy_r( space, offset );
1833
1834   case 4:
1835      return to7_qdd_r( space, offset );
1836
1837   case 5:
1838      return to7_network_r( space, offset );
1839   }
1840
1841   return 0;
1842}
1843
1844
1845
1846WRITE8_HANDLER ( to7_floppy_w )
1847{
1848   switch ( to7_controller_type )
1849   {
1850
1851   case 1:
1852      to7_5p14sd_w( space, offset, data );
1853      return;
1854
1855   case 2:
1856      to7_5p14_w( space, offset, data );
1857      break;
1858
1859   case 3:
1860      if ( offset == 8 )
1861      {
1862         to7_floppy_bank = 3 + (data & 3);
1863         memory_set_bank( space->machine, THOM_FLOP_BANK,  to7_floppy_bank );
1864         VLOG (( "to7_floppy_w: set CD 90-351 ROM bank to %i\n", data & 3 ));
1865      }
1866      else
1867         thmfc_floppy_w( space, offset, data );
1868      break;
1869
1870   case 4:
1871      to7_qdd_w( space, offset, data );
1872      break;
1873
1874   case 5:
1875      to7_network_w( space, offset, data );
1876      break;
1877   }
1878}
1879
1880
1881
1882/*********************** TO9 ************************/
1883
1884/* the internal controller is WD2793-based (so, similar to to7_5p14)
1885   we also emulate external controllers
1886*/
1887
1888
1889
1890void to9_floppy_init( running_machine *machine, void* int_base, void* ext_base )
1891{
1892   to7_floppy_init( machine, ext_base );
1893   memory_configure_bank( machine, THOM_FLOP_BANK, TO7_NB_FLOP_BANK, 1, int_base, 0x800 );
1894}
1895
1896
1897
1898void to9_floppy_reset( running_machine *machine )
1899{
1900   to7_floppy_reset(machine);
1901   if ( THOM_FLOPPY_EXT )
1902   {
1903      LOG(( "to9_floppy_reset: external controller\n" ));
1904   }
1905   else
1906   {
1907      LOG(( "to9_floppy_reset: internal controller\n" ));
1908      to7_5p14_reset(machine);
1909      memory_set_bank( machine, THOM_FLOP_BANK, TO7_NB_FLOP_BANK );
1910   }
1911}
1912
1913
1914
1915READ8_HANDLER ( to9_floppy_r )
1916{
1917   if ( THOM_FLOPPY_EXT )
1918      return to7_floppy_r( space, offset );
1919   else
1920      return  to7_5p14_r( space, offset );
1921}
1922
1923WRITE8_HANDLER ( to9_floppy_w )
1924{
1925   if ( THOM_FLOPPY_EXT )
1926      to7_floppy_w( space, offset, data );
1927   else
1928      to7_5p14_w( space, offset, data );
1929}
src/mess/devices/thomflop.h
r9937r9938
1/**********************************************************************
2
3  Copyright (C) Antoine Mine' 2006
4
5  Thomson 8-bit computers
6
7**********************************************************************/
8
9#ifndef THOMFLOP_H_
10#define THOMFLOP_H_
11
12#include "image.h"
13#include "machine/mc6843.h"
14#include "machine/mc6854.h"
15
16extern const mc6843_interface to7_6843_itf;
17extern const mc6854_interface to7_network_iface;
18
19extern UINT8 to7_controller_type; /* set during init */
20extern UINT8 to7_floppy_bank;
21
22/* number of external floppy controller ROM banks */
23#define TO7_NB_FLOP_BANK 9
24
25/* external floppy / network controller active */
26#define THOM_FLOPPY_EXT (to7_controller_type >= 1)
27
28/* internal floppy controller active (no or network extension) */
29#define THOM_FLOPPY_INT (to7_controller_type == 0 || to7_controller_type > 4)
30
31
32/* external controllers */
33extern void to7_floppy_init  ( running_machine *machine, void* base );
34extern void to7_floppy_reset ( running_machine *machine );
35extern READ8_HANDLER  ( to7_floppy_r );
36extern WRITE8_HANDLER ( to7_floppy_w );
37
38/* TO9 internal (WD2793) & external controllers */
39extern void to9_floppy_init  ( running_machine *machine, void* int_base, void* ext_base );
40extern void to9_floppy_reset ( running_machine *machine );
41extern READ8_HANDLER  ( to9_floppy_r );
42extern WRITE8_HANDLER ( to9_floppy_w );
43
44/* TO8 internal (THMFC1) controller */
45extern void thmfc_floppy_init  ( running_machine *machine );
46extern void thmfc_floppy_reset ( running_machine *machine );
47extern READ8_HANDLER  ( thmfc_floppy_r );
48extern WRITE8_HANDLER ( thmfc_floppy_w );
49
50
51#endif /* THOMFLOP_H_ */
src/mess/machine/ti99/ti99_hd.c
r0r9938
1/*************************************************************************
2
3    Hard disk support
4
5    This device wraps the plain image device as that device does not allow
6    for internal states (like head position)
7    The plain device is a subdevice ("drive") of this device, so we
8    get names like "mfmhd0:drive"
9
10    Michael Zapf, April 2010
11
12**************************************************************************/
13
14#include "emu.h"
15#include "imageutl.h"
16#include "harddisk.h"
17#include "imagedev/harddriv.h"
18#include "machine/smc92x4.h"
19
20#include "ti99_hd.h"
21
22typedef struct _mfmhd
23{
24   int current_cylinder;
25   int current_head;
26   int seeking;
27   int status;
28   int id_index; /* position in track for seeking the sector; counts the sector number */
29} mfmhd_state, idehd_state;
30
31#if 0
32static void dump_contents(UINT8 *buffer, int length)
33{
34   for (int i=0; i < length; i+=16)
35   {
36      for (int j=0; j < 16; j+=2)
37      {
38         printf("%02x%02x ", buffer[i+j], buffer[i+j+1]);
39      }
40      printf("\n");
41   }
42}
43#endif
44
45/*
46    Returns the linear sector number, given the CHS data.
47*/
48static int harddisk_chs_to_lba(hard_disk_file *hdfile, int cylinder, int head, int sector, UINT32 *lba)
49{
50   const hard_disk_info *info;
51
52   if ( hdfile != NULL)
53   {
54      info = hard_disk_get_info(hdfile);
55
56      if (   (cylinder >= info->cylinders) ||
57            (head >= info->heads) ||
58            (sector >= info->sectors))
59      return FALSE;
60
61      *lba = (cylinder * info->heads + head)
62            * info->sectors
63            + sector;
64      return TRUE;
65   }
66   return FALSE;
67}
68
69/* Accessor functions */
70void ti99_mfm_harddisk_read_sector(device_t *harddisk, int cylinder, int head, int sector, UINT8 **buf, int *sector_length)
71{
72   UINT32 lba;
73   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
74   device_t *drive = harddisk->subdevice("drive");
75   hard_disk_file *file = hd_get_hard_disk_file(drive);
76
77   *sector_length = 256;
78   *buf = (UINT8 *)malloc(*sector_length);
79
80   if (cylinder != hd->current_cylinder)
81   {
82      return;
83   }
84
85   if (file==NULL)
86   {
87      hd->status &= ~MFMHD_READY;
88      return;
89   }
90
91   if (!harddisk_chs_to_lba(file, cylinder, head, sector, &lba))
92   {
93      hd->status &= ~MFMHD_READY;
94      return;
95   }
96
97   if (!hard_disk_read(file, lba, *buf))
98   {
99      hd->status &= ~MFMHD_READY;
100      return;
101   }
102   /* printf("ti99_hd read sector  c=%04d h=%02d s=%02d\n", cylinder, head, sector); */
103   hd->status |= MFMHD_READY;
104}
105
106void ti99_mfm_harddisk_write_sector(device_t *harddisk, int cylinder, int head, int sector, UINT8 *buf, int sector_length)
107{
108   UINT32 lba;
109   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
110   device_t *drive = harddisk->subdevice("drive");
111   hard_disk_file *file = hd_get_hard_disk_file(drive);
112
113   if (file==NULL)
114   {
115      hd->status &= ~MFMHD_READY;
116      return;
117   }
118
119   if (!harddisk_chs_to_lba(file, cylinder, head, sector, &lba))
120   {
121      hd->status &= ~MFMHD_READY;
122      hd->status |= MFMHD_WRFAULT;
123      return;
124   }
125
126   if (!hard_disk_write(file, lba, buf))
127   {
128      hd->status &= ~MFMHD_READY;
129      hd->status |= MFMHD_WRFAULT;
130      return;
131   }
132
133   hd->status |= MFMHD_READY;
134}
135
136#define TI99HD_BLOCKNOTFOUND -1
137
138/*
139    Searches a block containing number * byte, starting at the given
140    position. Returns the position of the first byte of the block.
141*/
142static int find_block(const UINT8 *buffer, int start, int stop, UINT8 byte, size_t number)
143{
144   int i = start;
145   size_t current = number;
146   while (i < stop && current > 0)
147   {
148      if (buffer[i++] != byte)
149      {
150         current = number;
151      }
152      else
153      {
154         current--;
155      }
156   }
157   if (current==0)
158   {
159      return i - number;
160   }
161   else
162      return TI99HD_BLOCKNOTFOUND;
163}
164
165/*
166    Reads a complete track. We have to rebuild the gaps. This is basically
167    done in the same way as in the SDF format in ti99_dsk.
168
169    WARNING: This function is untested! We need to create a suitable
170    application program for the TI which makes use of it.
171*/
172void ti99_mfm_harddisk_read_track(device_t *harddisk, int head, UINT8 **pbuffer, int *data_count)
173{
174   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
175   device_t *drive = harddisk->subdevice("drive");
176
177   /* We assume an interleave of 3 for 32 sectors. */
178   int step = 3;
179   UINT32 lba;
180   int i;
181
182   int gap1 = 16;
183   int gap2 = 8;
184   int gap3 = 15;
185   int gap4 = 340;
186   int sync = 13;
187   int count;
188   int size;
189   int position = 0;
190   int sector;
191   int crc;
192
193   const hard_disk_info *info;
194   hard_disk_file *file = hd_get_hard_disk_file(drive);
195
196   if (file==NULL)
197   {
198      hd->status &= ~MFMHD_READY;
199      return;
200   }
201
202   info = hard_disk_get_info(file);
203
204   count = info->sectors;
205   size = info->sectorbytes/128;
206
207   *data_count = gap1 + count*(sync+12+gap2+sync+size*128+gap3)+gap4;
208
209   UINT8 *trackdata = (UINT8*)malloc(*data_count);
210
211   /* Write lead-in. */
212   memset(trackdata, 0x4e, gap1);
213
214   position += gap1;
215   for (i=0; i < info->sectors; i++)
216   {
217      sector = (i*step) % info->sectors;
218      memset(&trackdata[position], 0x00, sync);
219      position += 10;
220
221      /* Write sync */
222      trackdata[position++] = 0xa1;
223
224      /* Write IDAM */
225      trackdata[position++] = cylinder_to_ident(hd->current_cylinder);
226      trackdata[position++] = hd->current_cylinder;
227      trackdata[position++] = head;
228      trackdata[position++] = sector;
229      trackdata[position++] = (size==1)? 0x00 : (0x01 << (size-1));
230
231      /* Set CRC16 */
232      crc = ccitt_crc16(0xffff, &trackdata[position-5], 5);
233      trackdata[position++] = (crc>>8)&0xff;
234      trackdata[position++] = crc & 0xff;
235
236      /* Write Gap2 */
237      memset(&trackdata[position], 0x4e, gap2);
238      position += gap2;
239
240      /* Write sync */
241      memset(&trackdata[position], 0x00, sync);
242      position += sync;
243      trackdata[position++] = 0xa1;
244
245      /* Write DAM */
246      trackdata[position++] = 0xfb;
247
248      /* Locate the sector content in the image and load it. */
249
250      if (!harddisk_chs_to_lba(file, hd->current_cylinder, head, sector, &lba))
251      {
252         hd->status &= ~MFMHD_READY;
253         free(trackdata);
254         return;
255      }
256
257      if (!hard_disk_read(file, lba, &trackdata[position]))
258      {
259         hd->status &= ~MFMHD_READY;
260         free(trackdata);
261         return;
262      }
263
264      position += size;
265
266      /* Set CRC16. Includes the address mark. */
267      crc = ccitt_crc16(0xffff, &trackdata[position-size-1], size+1);
268      trackdata[position++] = (crc>>8)&0xff;
269      trackdata[position++] = crc & 0xff;
270
271      /* Write remaining 3 bytes which would have been used for ECC. */
272      memset(&trackdata[position], 0x00, 3);
273      position += 3;
274
275      /* Write Gap3 */
276      memset(&trackdata[position], 0x4e, gap3);
277      position += gap3;
278   }
279   /* Write Gap 4 */
280   memset(&trackdata[position], 0x4e, gap4);
281   position += gap4;
282
283   hd->status |= MFMHD_READY;
284
285   *pbuffer = trackdata;
286
287   // Remember to free the buffer! Except when an error has occured,
288   // the function returns a newly allocated buffer.
289   // Errors are indicated by READY=FALSE.
290}
291
292/*
293    Writes a track to the image. We need to isolate the sector contents.
294    This is basically done in the same way as in the SDF format in ti99_dsk.
295*/
296void ti99_mfm_harddisk_write_track(device_t *harddisk, int head, UINT8 *track_image, int data_count)
297{
298   int current_pos = 0;
299   int found;
300   UINT8 wident, whead = 0, wsector = 0, wsize;
301   UINT16 wcyl = 0;
302   int state;
303
304   /* Only search in the first 100 bytes for the start. */
305   int gap1 = 16;
306   int sync = 13;
307
308   UINT32 lba;
309   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
310   device_t *drive = harddisk->subdevice("drive");
311   hard_disk_file *file = hd_get_hard_disk_file(drive);
312
313   /* printf("ti99_hd write track c=%d h=%d\n", hd->current_cylinder, head); */
314
315   if (file==NULL)
316   {
317      hd->status &= ~MFMHD_READY;
318      return;
319   }
320
321   current_pos = find_block(track_image, 0, 100, 0x4e, gap1);
322
323   // In case of defect formats, we continue as far as possible. This
324   // may lead to sectors not being written. */
325   if (current_pos==TI99HD_BLOCKNOTFOUND)
326   {
327      logerror("ti99_hd error: write track: Cannot find gap1 for cylinder %d, head %d.\n", hd->current_cylinder, head);
328      /* What now? The track data are illegal, so we refuse to continue. */
329      hd->status |= MFMHD_WRFAULT;
330      return;
331   }
332
333   /* Get behind GAP1 */
334   current_pos += gap1;
335   found = FALSE;
336
337   while (current_pos < data_count)
338   {
339      /* We must find the address block to determine the sector. */
340      int new_pos = find_block(track_image, current_pos, data_count, 0x00, sync);
341      if (new_pos==TI99HD_BLOCKNOTFOUND)
342      {
343         /* Forget about the rest; we're done. */
344         if (found) break;  /* we were already successful, so all ok */
345         logerror("ti99_hd error: write track: Cannot find sync for track %d, head %d.\n", hd->current_cylinder, head);
346         hd->status |= MFMHD_WRFAULT;
347         return;
348      }
349      found = TRUE;
350
351      new_pos = new_pos + sync; /* skip sync bytes */
352
353      if (track_image[new_pos]==0xa1)
354      {
355         /* IDAM found. */
356         current_pos = new_pos + 1;
357         wident = track_image[current_pos];
358         wcyl = track_image[current_pos+1] + ((track_image[current_pos+2]&0x70)<<4);
359         whead = track_image[current_pos+2]&0x0f;
360         wsector = track_image[current_pos+3];
361         wsize = track_image[current_pos+4];
362
363         if (wcyl == hd->current_cylinder && whead == head)
364         {
365            if (!harddisk_chs_to_lba(file, wcyl, whead, wsector, &lba))
366            {
367               hd->status |= MFMHD_WRFAULT;
368               return;
369            }
370
371            /* Skip to the sector content. */
372            new_pos = find_block(track_image, current_pos, data_count, 0x00, sync);
373            current_pos = new_pos + sync;
374            if (track_image[current_pos]==0xa1)
375            {
376               current_pos += 2;
377               state = hard_disk_write(file, lba, track_image+current_pos);
378               if (state==0)
379               {
380                  logerror("ti99_hd error: write track: Write error during formatting cylinder %d, head %d\n", wcyl, whead);
381                  hd->status |= MFMHD_WRFAULT;
382                  return;
383               }
384               current_pos = current_pos+256+2; /* Skip contents and CRC */
385            }
386            else
387            {
388               logerror("ti99_hd error: write track: Cannot find DAM for cylinder %d, head %d, sector %d.\n", wcyl, whead, wsector);
389               hd->status |= MFMHD_WRFAULT;
390               return;
391            }
392         }
393         else
394         {
395            logerror("ti99_hd error: write track: Cylinder/head mismatch. Drive is on cyl=%d, head=%d, track data say cyl=%d, head=%d\n", hd->current_cylinder, head, wcyl, whead);
396            hd->status |= MFMHD_WRFAULT;
397         }
398      }
399      else
400      {
401         logerror("ti99_hd error: write track: Invalid track image for cyl=%d, head=%d. Cannot find any IDAM in track data.\n",  hd->current_cylinder, head);
402         hd->status |= MFMHD_WRFAULT;
403         return;
404      }
405   }
406}
407
408UINT8 ti99_mfm_harddisk_status(device_t *harddisk)
409{
410   UINT8 status = 0;
411   device_t *drive;
412   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
413   drive = harddisk->subdevice("drive");
414   hard_disk_file *file = hd_get_hard_disk_file(drive);
415
416   if (file!=NULL)
417      status |= MFMHD_READY;
418
419   if (hd->current_cylinder==0)
420      status |= MFMHD_TRACK00;
421
422   if (!hd->seeking)
423      status |= MFMHD_SEEKCOMP;
424
425   if (hd->id_index == 0)
426      status |= MFMHD_INDEX;
427
428   hd->status = status;
429   return status;
430}
431
432void ti99_mfm_harddisk_seek(device_t *harddisk, int direction)
433{
434   device_t *drive = harddisk->subdevice("drive");
435   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
436   const hard_disk_info *info;
437   hard_disk_file *file = hd_get_hard_disk_file(drive);
438
439   if (file==NULL)   return;
440
441   info = hard_disk_get_info(file);
442
443   hd->seeking = TRUE;
444
445   if (direction<0)
446   {
447      if (hd->current_cylinder>0)
448         hd->current_cylinder--;
449   }
450   else
451   {
452      if (hd->current_cylinder < info->cylinders)
453         hd->current_cylinder++;
454   }
455
456   hd->seeking = FALSE;
457}
458
459void ti99_mfm_harddisk_get_next_id(device_t *harddisk, int head, chrn_id_hd *id)
460{
461   device_t *drive = harddisk->subdevice("drive");
462   mfmhd_state *hd = (mfmhd_state *)downcast<legacy_device_base *>(harddisk)->token();
463   const hard_disk_info *info;
464   hard_disk_file *file;
465   int interleave = 3;
466
467   file = hd_get_hard_disk_file(drive);
468   if (file==NULL)
469   {
470      hd->status &= ~MFMHD_READY;
471      return;
472   }
473
474   info = hard_disk_get_info(file);
475
476   hd->current_head = head;
477
478   /* TODO: implement an interleave suitable for the number of sectors in the track. */
479   hd->id_index = (hd->id_index + interleave) % info->sectors;
480
481   /* build a new info block. */
482   id->C = hd->current_cylinder;
483   id->H = hd->current_head;
484   id->R = hd->id_index;
485   id->N = 1;
486   id->data_id = hd->id_index;
487   id->flags = 0;
488}
489
490static DEVICE_START( mfmhd )
491{
492}
493
494static DEVICE_START( idehd )
495{
496}
497
498
499MACHINE_CONFIG_FRAGMENT( mfmhd )
500   MCFG_DEVICE_ADD( "drive", HARDDISK, 0 )
501MACHINE_CONFIG_END
502
503MACHINE_CONFIG_FRAGMENT( idehd )
504   MCFG_DEVICE_ADD( "drive", IDE_HARDDISK, 0 )
505MACHINE_CONFIG_END
506
507static const char DEVTEMPLATE_SOURCE[] = __FILE__;
508
509#define DEVTEMPLATE_ID(p,s)             p##mfmhd##s
510#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_MACHINE_CONFIG
511#define DEVTEMPLATE_NAME                "TI99 MFM Hard disk"
512#define DEVTEMPLATE_FAMILY              "Hard disks"
513#define DEVTEMPLATE_VERSION      "1.0"
514#define DEVTEMPLATE_CREDITS      "Copyright MESS Team"
515#include "devtempl.h"
516
517#undef DEVTEMPLATE_ID
518#undef DEVTEMPLATE_FEATURES
519#undef DEVTEMPLATE_NAME
520
521#define DEVTEMPLATE_ID(p,s)             p##idehd##s
522#define DEVTEMPLATE_FEATURES            DT_HAS_START | DT_HAS_MACHINE_CONFIG
523#define DEVTEMPLATE_NAME                "TI99 IDE Hard disk"
524#include "devtempl.h"
525
526DEFINE_LEGACY_DEVICE(MFMHD, mfmhd);
527DEFINE_LEGACY_DEVICE(IDEHD, idehd);
src/mess/machine/ti99/ti99_hd.h
r0r9938
1#ifndef __TI99_HD__
2#define __TI99_HD__
3
4#include "emu.h"
5#include "machine/smc92x4.h"
6
7#define MFMHD_0 "mfmhd0"
8#define MFMHD_1 "mfmhd1"
9#define MFMHD_2 "mfmhd2"
10
11#define IDEHD_0 "idehd0"
12
13/* typedef struct _mfmhd_config mfmhd_config;
14struct _mfmhd_config
15{
16    device_start_func           device_start;
17    device_image_load_func          device_load;
18    device_image_unload_func        device_unload;
19}; */
20
21/* Accessor functions */
22void ti99_mfm_harddisk_read_sector(device_t *harddisk, int cylinder, int head, int sector, UINT8 **buf, int *sector_length);
23void ti99_mfm_harddisk_write_sector(device_t *harddisk, int cylinder, int head, int sector, UINT8 *buf, int sector_length);
24void ti99_mfm_harddisk_read_track(device_t *harddisk, int head, UINT8 **buffer, int *data_count);
25void ti99_mfm_harddisk_write_track(device_t *harddisk, int head, UINT8 *buffer, int data_count);
26UINT8 ti99_mfm_harddisk_status(device_t *harddisk);
27void ti99_mfm_harddisk_seek(device_t *harddisk, int direction);
28void ti99_mfm_harddisk_get_next_id(device_t *harddisk, int head, chrn_id_hd *id);
29
30DECLARE_LEGACY_DEVICE(MFMHD, mfmhd);
31
32DECLARE_LEGACY_DEVICE(IDEHD, idehd);
33
34#define MCFG_MFMHD_3_DRIVES_ADD()         \
35   MCFG_DEVICE_ADD(MFMHD_0, MFMHD, 0)      \
36   MCFG_DEVICE_ADD(MFMHD_1, MFMHD, 0)      \
37   MCFG_DEVICE_ADD(MFMHD_2, MFMHD, 0)      \
38   MCFG_DEVICE_ADD(IDEHD_0, IDEHD, 0)
39#endif
40
41
42/*
43    MCFG_MFMHD_START(mfmhd)             \
44    MCFG_MFMHD_LOAD(mfmhd)              \
45    MCFG_MFMHD_UNLOAD(mfmhd)
46*/
src/mess/machine/ti99/hfdc.c
r9937r9938
88#include "machine/wd17xx.h"
99#include "formats/ti99_dsk.h"
1010#include "imagedev/flopdrv.h"
11#include "devices/ti99_hd.h"
11#include "ti99_hd.h"
1212#include "machine/mm58274c.h"
1313#include "hfdc.h"
1414
src/mess/machine/ti99/peribox.c
r9937r9938
134134#include "imagedev/flopdrv.h"
135135#include "imagedev/harddriv.h"
136136#include "formats/ti99_dsk.h"
137#include "devices/ti99_hd.h"
137#include "ti99_hd.h"
138138
139139static const floppy_config ti99_4_floppy_config =
140140{
src/mess/machine/thomson.c
r9937r9938
77**********************************************************************/
88
99#include "emu.h"
10#include "devices/thomflop.h"
10#include "machine/thomflop.h"
1111#include "formats/thom_dsk.h"
1212#include "includes/thomson.h"
1313#include "machine/6821pia.h"
src/mess/machine/thomflop.c
r0r9938
1/**********************************************************************
2
3  Copyright (C) Antoine Mine' 2006
4
5  Thomson 8-bit computers
6
7**********************************************************************/
8
9#include "includes/thomson.h"
10#include "machine/wd17xx.h"
11
12
13#define VERBOSE 0 /* 0, 1 or 2 */
14
15#define PRINT(x) mame_printf_info x
16
17#define LOG(x)   do { if (VERBOSE > 0) logerror x; } while (0)
18#define VLOG(x)   do { if (VERBOSE > 1) logerror x; } while (0)
19
20
21
22
23/******************* 3''1/2 & 5''1/4 disk format ********************/
24
25/*
26  single density sector format:
27
28  data   bytes
29
30  id field     00      6      byte synchro
31  FE      1      id field mark
32  1      track
33  1      side
34  1      sector
35  00      1      log sector size (0->128, 1->256, 2->512,...)
36  2      CRC (unemulated)
37  FF     12      spaces
38  data field   00      6      bytes synchro
39  FB      1      data field mark
40  E5    128      actual data (set to E5 when formatting)
41  2      CRC (unemulated)
42  FF     22 ?    spaces
43
44
45
46  double density sector format:
47
48  data   bytes
49
50  id field     00     12      bit synchro
51  A1      3      byte synchro
52  FE      1      id field mark
53  1      track
54  1      side
55  1      sector
56  01      1      log sector size (0->128, 1->256, 2->512,...)
57  2      CRC (unemulated)
58  4E/F7   22      spaces
59  data field   00     12      bit synchro
60  A1      3      bytes synchro
61  FB      1      data field mark
62  E5    256      actual data (set to E5 when formatting)
63  2      CRC (unemulated)
64  4E/F7   74 ?    spaces
65
66  => at most  392 bytes / sector
67  => at most 6272 bytes / track
68
69  Notes:
70  - the BIOS puts 4E bytes as spaces after id and data fields
71  - some protected games expect F7 bytes (instead of 4E) after id fields
72*/
73
74#define THOM_SIZE_ID          32
75#define THOM_SIZE_DATA_LO    (128+80)
76#define THOM_SIZE_DATA_HI    (256+80)
77#define THOM_SIZE_SYNCHRO     12
78
79static int motor_on;
80
81
82/* build an identifier, with header & space */
83static int thom_floppy_make_addr( chrn_id id, UINT8* dst, int sector_size )
84{
85   if ( sector_size == 128 )
86   {
87      /* single density */
88      memset( dst, 0x00, 6 ); /* synchro bytes */
89      dst[  7 ] = 0xfe; /* address field mark */
90      dst[  8 ] = id.C;
91      dst[  9 ] = id.H;
92      dst[ 10 ] = id.N;
93      dst[ 11 ] = id.R;
94      dst[ 12 ] = 0; /* TODO: CRC */
95      dst[ 13 ] = 0; /* TODO: CRC */
96      memset( dst + 14, 0xff, 12 ); /* end mark */
97      return 36;
98   }
99   else
100   {
101      /* double density */
102      memset( dst, 0xa1, 3 ); /* synchro bytes */
103      dst[ 3 ] = 0xfe; /* address field mark */
104      dst[ 4 ] = id.C;
105      dst[ 5 ] = id.H;
106      dst[ 6 ] = id.N;
107      dst[ 7 ] = id.R;
108      dst[ 8 ] = 0; /* TODO: CRC */
109      dst[ 9 ] = 0; /* TODO: CRC */
110      memset( dst + 10, 0xf7, 22 ); /* end mark */
111      return 32;
112   }
113}
114
115
116
117/* build a sector, with header & space */
118static int thom_floppy_make_sector( device_t* img, chrn_id id, UINT8* dst, int sector_size )
119{
120   if ( sector_size == 128 )
121   {
122      /* single density */
123      memset( dst, 0x00, 6 ); /* synchro bytes */
124      dst[ 6 ] = 0xfb; /* data field mark */
125      floppy_drive_read_sector_data
126         ( img, id.H, id.data_id, dst + 7, sector_size );
127      dst[ sector_size + 7 ] = 0; /* TODO: CRC */
128      dst[ sector_size + 8 ] = 0; /* TODO: CRC */
129      memset( dst + sector_size + 9, 0xff, 22 ); /* end mark */
130      return sector_size + 31;
131   }
132   else
133   {
134      /* double density */
135      memset( dst, 0xa1, 3 ); /* synchro bytes */
136      dst[ 3 ] = 0xfb; /* data field mark */
137      floppy_drive_read_sector_data
138         ( img, id.H, id.data_id, dst + 4, sector_size );
139      dst[ sector_size + 4 ] = 0; /* TODO: CRC */
140      dst[ sector_size + 5 ] = 0; /* TODO: CRC */
141      memset( dst + sector_size + 6, 0xF7, 74 ); /* end mark */
142      return sector_size + 80;
143   }
144}
145
146
147
148/* build a whole track */
149static int thom_floppy_make_track( device_t* img, UINT8* dst, int sector_size, int side )
150{
151   UINT8 space = ( sector_size == 128 ) ? 0xff : 0;
152   UINT8* org = dst;
153   chrn_id id;
154   int nb;
155
156   /* go to start of track */
157   while ( ! floppy_drive_get_flag_state( img, FLOPPY_DRIVE_INDEX ) )
158   {
159      if ( ! floppy_drive_get_next_id( img, side, &id ) )
160         return 0;
161   }
162
163   /* for each sector... */
164   for ( nb = 0; nb < 16; nb++ )
165   {
166      if ( ! floppy_drive_get_next_id( img, side, &id ) )
167         break;
168
169      memset( dst, space, THOM_SIZE_SYNCHRO ); dst += THOM_SIZE_SYNCHRO;
170      dst += thom_floppy_make_addr( id, dst, sector_size );
171      memset( dst, space, THOM_SIZE_SYNCHRO ); dst += THOM_SIZE_SYNCHRO;
172      dst += thom_floppy_make_sector( img, id, dst, sector_size );
173
174      if ( floppy_drive_get_flag_state( img, FLOPPY_DRIVE_INDEX ) )
175         break;
176   }
177   return dst - org;
178}
179
180
181
182/******************* QDD disk format ********************/
183
184/*
185  sector format:
186
187  data   bytes
188
189  id field     16     17      synchro
190  A5      1      id field mark
191  1      sector (1-400) hi byte
192  1      sector (1-400) low byte
193  1      check-sum (sum modulo 256 of 3 last bytes)
194
195  data field   16     10      synchro
196  5A      1      data field mark
197  FF    128      actual data (set to FF when formatting)
198  1      check-sum (sum modulo 256 of 129 last bytes)
199
200
201  there are 400 sectors numbered from 1
202*/
203
204#define THOM_QDD_SYNCH_DISK 100
205#define THOM_QDD_SYNCH_ADDR  17
206#define THOM_QDD_SYNCH_DATA  10
207
208#define THOM_QDD_SIZE_ID     (   4 + THOM_QDD_SYNCH_ADDR  )
209#define THOM_QDD_SIZE_DATA   ( 130 + THOM_QDD_SYNCH_DATA )
210
211
212/* build an identifier, with header */
213static int thom_qdd_make_addr( int sector, UINT8* dst )
214{
215   dst[  0 ] = 0xa5;
216   dst[  1 ] = sector >> 8;
217   dst[  2 ] = sector & 0xff;
218   dst[  3 ] = dst[ 0 ] + dst[ 1 ] + dst[ 2 ];
219   return 4;
220}
221
222
223
224/* build a sector, with header */
225static int thom_qdd_make_sector( device_t* img, int sector, UINT8* dst )
226{
227   int i;
228   dst[ 0 ] = 0x5a;
229   floppy_drive_read_sector_data ( img, 0, sector, dst + 1, 128 );
230   dst[ 129 ] = 0;
231   for ( i = 0; i < 129; i++ )
232      dst[ 129 ] += dst[ i ];
233   return 130;
234}
235
236
237
238/* build a whole disk */
239static int thom_qdd_make_disk ( device_t* img, UINT8* dst )
240{
241   UINT8* org = dst;
242   int i;
243
244   memset( dst, 0x16, THOM_QDD_SYNCH_DISK ); dst += THOM_QDD_SYNCH_DISK;
245
246   for ( i = 1; i <= 400; i++ )
247   {
248      memset( dst, 0x16, THOM_QDD_SYNCH_ADDR ); dst += THOM_QDD_SYNCH_ADDR;
249      dst += thom_qdd_make_addr( i, dst );
250      memset( dst, 0x16, THOM_QDD_SYNCH_DATA ); dst += THOM_QDD_SYNCH_DATA;
251      dst += thom_qdd_make_sector( img, i, dst );
252   }
253
254   memset( dst, 0x16, THOM_QDD_SYNCH_DISK ); dst += THOM_QDD_SYNCH_DISK;
255
256   return dst - org;
257}
258
259
260
261/*********************** CD 90-640 controller ************************/
262
263/* 5''1/4 two-sided double-density
264   used in TO7, TO7/70, MO5 computers
265   based on a WD2793 (or lower ?) chip
266*/
267
268
269
270static UINT8 to7_5p14_select;
271
272
273
274static READ8_HANDLER ( to7_5p14_r )
275{
276   device_t *fdc = space->machine->device("wd2793");
277
278   if ( offset < 4 )
279      return wd17xx_r( fdc, offset );
280   else if ( offset == 8 )
281      return to7_5p14_select;
282   else
283      logerror ( "%f $%04x to7_5p14_r: invalid read offset %i\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset );
284   return 0;
285}
286
287
288
289static WRITE8_HANDLER( to7_5p14_w )
290{
291   device_t *fdc = space->machine->device("wd2793");
292   if ( offset < 4 )
293      wd17xx_w( fdc, offset, data );
294   else if ( offset == 8 )
295   {
296      /* drive select */
297      int drive = -1, side = 0;
298
299      switch ( data & 7 )
300      {
301      case 0: break;
302      case 2: drive = 0; side = 0; break;
303      case 3: drive = 1; side = 1; break;
304      case 4: drive = 2; side = 0; break;
305      case 5: drive = 3; side = 1; break;
306      default:
307         logerror( "%f $%04x to7_5p14_w: invalid drive select pattern $%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data );
308      }
309
310      wd17xx_dden_w(fdc, BIT(data, 7));
311
312      to7_5p14_select = data;
313
314      if ( drive != -1 )
315      {
316         thom_floppy_active( space->machine, 0 );
317         wd17xx_set_drive( fdc, drive );
318         wd17xx_set_side( fdc, side );
319         LOG(( "%f $%04x to7_5p14_w: $%02X set drive=%i side=%i density=%s\n",
320               attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")),
321               data, drive, side, (BIT(data, 7) ? "FM" : "MFM")));
322      }
323   }
324   else
325      logerror ( "%f $%04x to7_5p14_w: invalid write offset %i (data=$%02X)\n",
326            attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset, data );
327}
328
329
330
331static void to7_5p14_reset( running_machine *machine )
332{
333   device_t *fdc = machine->device("wd2793");
334   LOG(( "to7_5p14_reset: CD 90-640 controller\n" ));
335   wd17xx_reset(fdc);
336}
337
338
339
340static void to7_5p14_init( running_machine *machine )
341{
342   LOG(( "to7_5p14_init: CD 90-640 controller\n" ));
343   state_save_register_global( machine, to7_5p14_select );
344}
345
346
347
348/*********************** CD 90-015 controller ************************/
349
350/* 5''1/4 one-sided single-density (up to 4 one-sided drives)
351   used in TO7, TO7/70, MO5 computers
352   based on HD 46503 S chip, but we actually use a MC 6843 instead
353   (seems they are clone)
354*/
355
356
357
358static UINT8 to7_5p14sd_select;
359
360
361
362static READ8_HANDLER ( to7_5p14sd_r )
363{
364   if ( offset < 8 )
365      return mc6843_r( space->machine->device("mc6843"), offset );
366   else if ( offset >= 8 && offset <= 9 )
367      return to7_5p14sd_select;
368   else
369      logerror ( "%f $%04x to7_5p14sd_r: invalid read offset %i\n",  attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset );
370   return 0;
371}
372
373
374
375static WRITE8_HANDLER( to7_5p14sd_w )
376{
377   if ( offset < 8 )
378      mc6843_w( space->machine->device("mc6843"), offset, data );
379   else if ( offset >= 8 && offset <= 9 )
380   {
381      /* drive select */
382      int drive = -1, side = 0;
383
384      if ( data & 1 )
385      {
386         drive = 0;
387         side = 0;
388      }
389      else if ( data & 2 )
390      {
391         drive = 1;
392         side = 1;
393      }
394      else if ( data & 4 )
395      {
396         drive = 2;
397         side = 0;
398      }
399      else if ( data & 8 )
400      {
401         drive = 3;
402         side = 1;
403      }
404
405      to7_5p14sd_select = data;
406
407      if ( drive != -1 )
408      {
409         thom_floppy_active( space->machine, 0 );
410         mc6843_set_drive( space->machine->device("mc6843"), drive );
411         mc6843_set_side( space->machine->device("mc6843"), side );
412         LOG(( "%f $%04x to7_5p14sd_w: $%02X set drive=%i side=%i\n",
413               attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data, drive, side ));
414      }
415   }
416   else
417      logerror ( "%f $%04x to7_5p14sd_w: invalid write offset %i (data=$%02X)\n",
418            attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset, data );
419}
420
421static void to7_5p14_index_pulse_callback( device_t *controller,device_t *image, int state )
422{
423   mc6843_set_index_pulse( image->machine->device("mc6843"), state );
424}
425
426static void to7_5p14sd_reset( running_machine *machine )
427{
428   int i;
429   LOG(( "to7_5p14sd_reset: CD 90-015 controller\n" ));
430   for ( i = 0; i < floppy_get_count( machine ); i++ )
431   {
432      device_t * img = floppy_get_device( machine, i );
433      if (img) {
434         floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 );
435         floppy_drive_set_rpm( img, 300. );
436         floppy_drive_seek( img, - floppy_drive_get_current_track( img ) );
437         floppy_drive_set_index_pulse_callback( img, to7_5p14_index_pulse_callback );
438      }
439   }
440}
441
442
443
444const mc6843_interface to7_6843_itf = { NULL };
445
446
447
448static void to7_5p14sd_init( running_machine *machine )
449{
450   LOG(( "to7_5p14sd_init: CD 90-015 controller\n" ));
451   state_save_register_global( machine, to7_5p14sd_select );
452}
453
454
455/*********************** CQ 90-028 controller ************************/
456
457/* QDD 2''8 controller
458   used in TO7, TO7/70, MO5 computers
459   it is based on a MC6852 SSDA
460
461   Note: the MC6852 is only partially emulated, most features are not used in
462   the controller and are ignored.
463*/
464
465
466
467/* MC6852 status */
468#define QDD_S_RDA  0x01 /* receiver data available */
469#define QDD_S_TDRA 0x02 /* transitter data register available */
470#define QDD_S_NDCD 0x04 /* data carrier detect, negated (unused) */
471#define QDD_S_NCTS 0x08 /* clear-to-send, negated write-protect */
472#define QDD_S_TUF  0x10 /* transmitter underflow (unused) */
473#define QDD_S_OVR  0x20 /* receiver overrun (unused) */
474#define QDD_S_PE   0x40 /* receiver parity error (unused) */
475#define QDD_S_IRQ  0x80 /* interrupt request */
476#define QDD_S_ERR  (QDD_S_TUF | QDD_S_OVR | QDD_S_PE | QDD_S_NDCD | QDD_S_NCTS)
477
478
479/* MC6852 control */
480#define QDD_C1_RIE       0x20 /* interrupt on reveive */
481#define QDD_C1_TIE       0x10 /* interrupt on transmit */
482#define QDD_C1_CLRSYNC   0x08 /* clear receiver sync char (unused) */
483#define QDD_C1_STRIPSYNC 0x04 /* strips sync from received (unused) */
484#define QDD_C1_TRESET    0x02 /* transmitter reset */
485#define QDD_C1_RRESET    0x01 /* receiver reset */
486#define QDD_C2_EIE       0x80 /* interrupt on error */
487#define QDD_C2_TSYNC     0x40 /* underflow = ff if 0 / sync if 1 (unused) */
488#define QDD_C2_BLEN      0x04 /* transfer byte length (unused) */
489#define QDD_C3_CLRTUF    0x08 /* clear underflow */
490#define QDD_C3_CLRCTS    0x04 /* clear CTS  */
491#define QDD_C3_SYNCLEN   0x02 /* sync byte length (unused) */
492#define QDD_C3_SYNCMODE  0x01 /* external / internal sync mode (unused) */
493
494
495/* a track is actually the whole disk = 400 128-byte sectors + headers */
496#define QDD_MAXBUF ( THOM_QDD_SIZE_ID + THOM_QDD_SIZE_DATA ) * 512
497
498
499static struct _to7qdd
500{
501   /* MC6852 registers */
502   UINT8 status;
503   UINT8 ctrl1;
504   UINT8 ctrl2;
505   UINT8 ctrl3;
506
507   /* extra registers */
508   UINT8 drive;
509
510   /* internal state */
511   UINT8  data[QDD_MAXBUF];  /* enough for a whole track */
512   UINT32 data_idx;          /* byte position in track */
513   UINT32 start_idx;         /* start of write position */
514   UINT32 data_size;         /* track length */
515   UINT8  data_crc;          /* checksum when writing */
516   UINT8  index_pulse;       /* one pulse per track */
517
518} * to7qdd;
519
520
521
522static void to7_qdd_index_pulse_cb ( device_t *controller,device_t *image, int state )
523{
524   to7qdd->index_pulse = state;
525
526   if ( state )
527   {
528      /* rewind to disk start */
529      to7qdd->data_idx = 0;
530      to7qdd->start_idx = 0;
531      to7qdd->data_size = 0;
532   }
533
534   VLOG(( "%f to7_qdd_pulse_cb: state=%i\n", attotime_to_double(timer_get_time(image->machine)), state ));
535}
536
537
538
539static device_t * to7_qdd_image ( running_machine *machine )
540{
541   return floppy_get_device( machine, 0 );
542}
543
544
545
546/* update MC6852 status register */
547static void to7_qdd_stat_update( running_machine *machine )
548{
549   /* byte-ready */
550   to7qdd->status |= QDD_S_RDA | QDD_S_TDRA;
551   if ( ! to7qdd->drive )
552      to7qdd->status |= QDD_S_PE;
553
554   /* write-protect */
555   if (floppy_wpt_r(to7_qdd_image(machine)) == CLEAR_LINE)
556      to7qdd->status |= QDD_S_NCTS;
557
558   /* sticky reset conditions */
559   if ( to7qdd->ctrl1 & QDD_C1_RRESET )
560      to7qdd->status &= ~(QDD_S_PE | QDD_S_RDA | QDD_S_OVR);
561   if ( to7qdd->ctrl1 & QDD_C1_TRESET )
562      to7qdd->status &= ~(QDD_S_TDRA | QDD_S_TUF);
563
564   /* irq update */
565
566   if ( ( (to7qdd->ctrl1 & QDD_C1_RIE) && !(to7qdd->status & QDD_S_RDA ) ) ||
567        ( (to7qdd->ctrl1 & QDD_C1_TIE) && !(to7qdd->status & QDD_S_TDRA) ) ||
568        ( (to7qdd->ctrl2 & QDD_C2_EIE) && !(to7qdd->status & QDD_S_ERR ) ) )
569      to7qdd->status &= ~QDD_S_IRQ;
570
571   if ( ( (to7qdd->ctrl1 & QDD_C1_RIE) && (to7qdd->status & QDD_S_RDA ) ) ||
572        ( (to7qdd->ctrl1 & QDD_C1_TIE) && (to7qdd->status & QDD_S_TDRA) ) ||
573        ( (to7qdd->ctrl2 & QDD_C2_EIE) && (to7qdd->status & QDD_S_ERR ) ) )
574      to7qdd->status |= QDD_S_IRQ;
575}
576
577
578
579static UINT8 to7_qdd_read_byte( running_machine *machine )
580{
581   UINT8 data;
582
583   /* rebuild disk if needed */
584   if ( !to7qdd->data_size )
585   {
586      to7qdd->data_size = thom_qdd_make_disk( to7_qdd_image(machine), to7qdd->data );
587      assert( to7qdd->data_idx < sizeof( to7qdd->data ) );
588   }
589
590   if ( to7qdd->data_idx >= to7qdd->data_size )
591      data = 0;
592   else
593      data = to7qdd->data[ to7qdd->data_idx ];
594
595   VLOG(( "%f $%04x to7_qdd_read_byte: RDATA off=%i/%i data=$%02X\n",
596          attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")),
597          to7qdd->data_idx, to7qdd->data_size, data ));
598
599   to7qdd->data_idx++;
600   to7qdd->start_idx = to7qdd->data_idx;
601
602   return data;
603}
604
605
606
607/* This is quite complex: bytes are written one at a time by the CPU and we
608   must detect the following patterns:
609   * CPU write id field and data field => format
610   * CPU write data field after it has read an id field => sector write
611   */
612static void to7_qdd_write_byte( running_machine *machine, UINT8 data )
613{
614   int i;
615
616   /* rebuild disk if needed */
617   if ( !to7qdd->data_size )
618   {
619      to7qdd->data_size = thom_qdd_make_disk( to7_qdd_image(machine), to7qdd->data );
620      assert( to7qdd->data_idx < sizeof( to7qdd->data ) );
621   }
622
623   if ( ( to7qdd->start_idx != to7qdd->data_idx || /* field in construction */
624          data==0xA5 || data==0x5A ) &&    /* first byte of tentative field */
625        to7qdd->data_idx <to7qdd->data_size )
626   {
627
628      /* this is the first byte of the field */
629      if ( to7qdd->start_idx == to7qdd->data_idx )
630         to7qdd->data_crc = 0;
631
632      /* accumulate bytes */
633      to7qdd->data[ to7qdd->data_idx ] = data;
634      to7qdd->data_idx++;
635
636      VLOG (( "%f $%04x to7_qdd_write_byte: got $%02X offs=%i-%i\n",
637         attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), data,
638         to7qdd->start_idx, to7qdd->data_idx ));
639
640      /* end of tentative id field */
641      if ( to7qdd->data_idx == to7qdd->start_idx + 4 &&
642           to7qdd->data[ to7qdd->start_idx ] == 0xA5 &&
643           to7qdd->data[ to7qdd->start_idx + 3 ] == to7qdd->data_crc )
644      {
645
646         /* got an id field => format */
647         int sector = (int) to7qdd->data[ to7qdd->start_idx + 1 ] * 256 + (int) to7qdd->data[ to7qdd->start_idx + 2 ];
648         UINT8 filler = 0xff;
649
650         LOG(( "%f $%04x to7_qdd_write_byte: got id field for sector=%i\n",
651               attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), sector ));
652
653         floppy_drive_format_sector( to7_qdd_image(machine),
654                      0, sector, 0, 0, sector, 128, filler );
655                        thom_floppy_active( machine, 1 );
656         to7qdd->start_idx = to7qdd->data_idx;
657      }
658
659      /* end of tentative data field */
660      else if ( to7qdd->data_idx == to7qdd->start_idx + 130 &&
661           to7qdd->data[ to7qdd->start_idx  ] == 0x5A &&
662           to7qdd->data[ to7qdd->start_idx + 129 ] == to7qdd->data_crc )
663      {
664
665         /* look backwards for previous id field */
666         for ( i = to7qdd->start_idx - 3; i >= 0; i-- )
667         {
668            if ( to7qdd->data[ i ] == 0xA5 &&
669                 ( ( to7qdd->data[ i ] + to7qdd->data[ i + 1 ] +
670                to7qdd->data[ i + 2 ] ) & 0xff
671                    ) == to7qdd->data[ i + 3 ] )
672               break;
673         }
674
675         if ( i >= 0 )
676         {
677            /* got an id & a data field => write */
678            int sector = (int) to7qdd->data[ i + 1 ] * 256 + (int) to7qdd->data[ i + 2 ];
679
680            LOG(( "%f $%04x to7_qdd_write_byte: goto data field for sector=%i\n",
681                  attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), sector ));
682
683            floppy_drive_write_sector_data( to7_qdd_image(machine), 0, sector, to7qdd->data + to7qdd->start_idx + 1, 128, 0 );
684                                thom_floppy_active( machine, 1 );
685         }
686
687         to7qdd->start_idx = to7qdd->data_idx;
688      }
689
690      else to7qdd->data_crc += data;
691   }
692}
693
694
695
696static READ8_HANDLER ( to7_qdd_r )
697{
698   switch ( offset )
699   {
700
701   case 0: /* MC6852 status */
702      to7_qdd_stat_update(space->machine);
703      VLOG(( "%f $%04x to7_qdd_r: STAT=$%02X irq=%i pe=%i ovr=%i und=%i tr=%i rd=%i ncts=%i\n",
704             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), to7qdd->status,
705             to7qdd->status & QDD_S_IRQ  ? 1 : 0,
706             to7qdd->status & QDD_S_PE   ? 1 : 0,
707             to7qdd->status & QDD_S_OVR  ? 1 : 0,
708             to7qdd->status & QDD_S_TUF  ? 1 : 0,
709             to7qdd->status & QDD_S_TDRA ? 1 : 0,
710             to7qdd->status & QDD_S_RDA  ? 1 : 0,
711             to7qdd->status & QDD_S_NCTS ? 1 : 0 ));
712      return to7qdd->status;
713
714   case 1: /* MC6852 data input => read byte from disk */
715      to7qdd->status &= ~(QDD_S_RDA | QDD_S_PE | QDD_S_OVR);
716      to7_qdd_stat_update(space->machine);
717      return to7_qdd_read_byte( space->machine );
718
719   case 8: /* floppy status */
720   {
721      UINT8 data = 0;
722      device_image_interface* img = dynamic_cast<device_image_interface *>(to7_qdd_image(space->machine));
723      if ( ! img->exists() )
724         data |= 0x40; /* disk present */
725      if ( to7qdd->index_pulse )
726         data |= 0x80; /* disk start */
727      VLOG(( "%f $%04x to7_qdd_r: STATUS8 $%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
728      return data;
729   }
730
731   default:
732      logerror ( "%f $%04x to7_qdd_r: invalid read offset %i\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset );
733      return 0;
734   }
735}
736
737
738
739static WRITE8_HANDLER( to7_qdd_w )
740{
741   switch ( offset )
742   {
743
744   case 0: /* MC6852 control 1 */
745      /* reset */
746      if ( data & QDD_C1_RRESET )
747         to7qdd->status &= ~(QDD_S_PE | QDD_S_RDA | QDD_S_OVR);
748      if ( data & QDD_C1_TRESET )
749         to7qdd->status &= ~(QDD_S_TDRA | QDD_S_TUF);
750
751      to7qdd->ctrl1 = ( data & ~(QDD_C1_RRESET | QDD_C1_TRESET) ) |( data &  (QDD_C1_RRESET | QDD_C1_TRESET) & to7qdd->ctrl1 );
752      to7_qdd_stat_update(space->machine);
753      VLOG(( "%f $%04x to7_qdd_w: CTRL1=$%02X reset=%c%c %s%sirq=%c%c\n",
754             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
755             data & QDD_C1_RRESET ? 'r' : '-', data & QDD_C1_TRESET ? 't' : '-',
756             data & QDD_C1_STRIPSYNC ? "strip-sync " : "",
757             data & QDD_C1_CLRSYNC ? "clear-sync " : "",
758             data & QDD_C1_RIE ? 'r' : '-',
759             data & QDD_C1_TIE ? 't' : '-' ));
760      break;
761
762   case 1:
763      switch ( to7qdd->ctrl1 >> 6 )
764      {
765
766      case 0: /* MC6852 control 2 */
767      {
768#if 0
769         /* most of these are unused now */
770         static const int bit[8] = { 6, 6, 7, 8, 7, 7, 8, 8 };
771         static const int par[8] = { 2, 1, 0, 0, 2, 1, 2, 1 };
772         static const char *const parname[3] = { "none", "odd", "even" };
773         int bits, parity;
774         bits   = bit[ (data >> 3) & 7 ];
775         parity = par[ (data >> 3) & 7 ];
776         to7_qdd_stat_update(space->machine);
777         VLOG(( "%f $%04x to7_qdd_w: CTRL2=$%02X bits=%i par=%s blen=%i under=%s%s\n",
778                attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
779                bits, parname[ parity ], data & QDD_C2_BLEN ? 1 : 2,
780                data & QDD_C2_TSYNC ? "sync" : "ff",
781                data & QDD_C2_EIE ? "irq-err" : "" ));
782#endif
783         to7qdd->ctrl2 = data;
784         break;
785      }
786
787      case 1: /* MC6852 control 3 */
788         to7qdd->ctrl3 = data;
789         /* reset just once each write, not sticky */
790         if ( data & QDD_C3_CLRTUF )
791            to7qdd->status &= ~QDD_S_TUF;
792         if ( data & QDD_C3_CLRCTS )
793            to7qdd->status &= ~QDD_S_NCTS;
794         to7_qdd_stat_update(space->machine);
795         VLOG(( "%f $%04x to7_qdd_w: CTRL3=$%02X %s%ssync-len=%i sync-mode=%s\n",
796                attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
797                data & QDD_C3_CLRTUF ? "clr-tuf " : "",
798                data & QDD_C3_CLRCTS ? "clr-cts " : "",
799                data & QDD_C3_SYNCLEN ? 1 : 2,
800                data & QDD_C3_SYNCMODE ? "ext" : "int" ));
801         break;
802
803      case 2: /* MC6852 sync code => write byte to disk */
804         to7_qdd_write_byte( space->machine, data );
805         break;
806
807      case 3: /* MC6852 data out => does not seem to be used */
808         VLOG(( "%f $%04x to7_qdd_w: ignored WDATA=$%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
809         break;
810
811      }
812      break;
813
814   case 8: /* set drive */
815      to7qdd->drive = data;
816      VLOG(( "%f $%04x to7_qdd_w: DRIVE=$%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
817      break;
818
819   case 12: /* motor pulse ? */
820      thom_floppy_active( space->machine, 0 );
821      VLOG(( "%f $%04x to7_qdd_w: MOTOR=$%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
822      break;
823
824   default:
825      logerror ( "%f $%04x to7_qdd_w: invalid write offset %i (data=$%02X)\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset, data );
826   }
827}
828
829
830
831static void to7_qdd_reset( running_machine *machine )
832{
833   int i;
834   LOG(( "to7_qdd_reset: CQ 90-028 controller\n" ));
835
836   for ( i = 0; i < floppy_get_count( machine ); i++ )
837   {
838      device_t * img = floppy_get_device( machine, i );
839      if (img) {
840         floppy_drive_set_index_pulse_callback( img, to7_qdd_index_pulse_cb );
841         floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 );
842
843         motor_on = CLEAR_LINE;
844         floppy_mon_w(img, motor_on);
845
846         /* pulse each time the whole-disk spiraling track ends */
847         /* at 90us per byte read, the disk can be read in 6s */
848         floppy_drive_set_rpm( img, 60. / 6. );
849      }
850   }
851
852   to7qdd->ctrl1 |= QDD_C1_TRESET | QDD_C1_RRESET; /* reset */
853   to7qdd->ctrl2 &= 0x7c; /* clear EIE, PC2-PC1 */
854   to7qdd->ctrl3 &= 0xfe; /* internal sync */
855   to7qdd->drive = 0;
856   to7_qdd_stat_update(machine);
857}
858
859
860
861static void to7_qdd_init( running_machine *machine )
862{
863   LOG(( "to7_qdd_init: CQ 90-028 controller\n" ));
864
865   to7qdd = auto_alloc(machine, struct _to7qdd);
866
867   state_save_register_global( machine, to7qdd->status );
868   state_save_register_global( machine, to7qdd->ctrl1 );
869   state_save_register_global( machine, to7qdd->ctrl2 );
870   state_save_register_global( machine, to7qdd->ctrl3 );
871   state_save_register_global( machine, to7qdd->drive );
872   state_save_register_global( machine, to7qdd->data_idx );
873   state_save_register_global( machine, to7qdd->start_idx );
874   state_save_register_global( machine, to7qdd->data_size );
875   state_save_register_global( machine, to7qdd->data_crc );
876   state_save_register_global( machine, to7qdd->index_pulse );
877   state_save_register_global_array( machine, to7qdd->data );
878}
879
880
881
882/********************** THMFC1 controller *************************/
883
884/* custom Thomson Gate-array for 3''1/2, 5''1/4 (double density only) & QDD
885 */
886
887
888
889/* types of high-level operations */
890#define THMFC1_OP_RESET         0
891#define THMFC1_OP_WRITE_SECT    1
892#define THMFC1_OP_READ_ADDR     2
893#define THMFC1_OP_READ_SECT     3
894
895
896/* STAT0 flags */
897#define THMFC1_STAT0_SYNCHRO        0x01 /* bit clock synchronized */
898#define THMFC1_STAT0_BYTE_READY_OP  0x02 /* byte ready (high-level operation) */
899#define THMFC1_STAT0_CRC_ERROR      0x04
900#define THMFC1_STAT0_FINISHED       0x08
901#define THMFC1_STAT0_FINISHING      0x10 /* (unemulated) */
902#define THMFC1_STAT0_BYTE_READY_POL 0x80 /* polling mode */
903
904
905/*#define THOM_MAXBUF (THOM_SIZE_ID+THOM_SIZE_DATA_HI+2*THOM_SIZE_SYNCHRO)*17*/
906#define THOM_MAXBUF ( THOM_QDD_SIZE_ID + THOM_QDD_SIZE_DATA ) * 512
907
908
909static struct _thmfc1
910{
911
912   UINT8   op;
913   UINT8   sector;            /* target sector, in [1,16] */
914        UINT32  sector_id;
915   UINT8   track;             /* current track, in [0,79] */
916   UINT8   side;              /* current side, 0 or 1 */
917   UINT8   drive;             /* 0 to 3 */
918   UINT16  sector_size;       /* 128 or 256 (512, 1024 not supported) */
919   UINT8   formatting;
920   UINT8   ipl;               /* index pulse / QDD start */
921   UINT8   wsync;             /* synchronization word */
922
923   UINT8   data[THOM_MAXBUF]; /* enough for a whole track */
924   UINT32  data_idx;          /* reading / writing / formatting pos */
925   UINT32  data_size;         /* bytes to read / write */
926   UINT32  data_finish;       /* when to raise the finished flag */
927   UINT32  data_raw_idx;      /* byte index for raw track reading */
928   UINT32  data_raw_size;     /* size of track already cached in data */
929   UINT8   data_crc;          /* check-sum of written data */
930
931   UINT8   stat0;             /* status register */
932
933} * thmfc1;
934
935
936static emu_timer* thmfc_floppy_cmd;
937
938
939
940static device_t * thmfc_floppy_image ( running_machine *machine )
941{
942   return floppy_get_device( machine, thmfc1->drive );
943}
944
945
946
947static int thmfc_floppy_is_qdd ( device_image_interface *image )
948{
949   if (image==NULL) return 0;
950   if (!image->exists()) return 0;
951   return image->length()==51200; // idf QDD
952}
953
954
955
956static void thmfc_floppy_index_pulse_cb ( device_t *controller,device_t *image, int state )
957{
958   if ( image != thmfc_floppy_image(image->machine) )
959      return;
960
961   if ( thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(image)))
962   {
963      /* pulse each time the whole-disk spiraling track ends */
964      floppy_drive_set_rpm( image, 16.92f /* 423/25 */ );
965      thmfc1->ipl = state;
966      if ( state )
967      {
968         thmfc1->data_raw_size = 0;
969         thmfc1->data_raw_idx = 0;
970         thmfc1->data_idx = 0;
971      }
972   }
973   else
974   {
975      floppy_drive_set_rpm( image, 300. );
976      thmfc1->ipl = state;
977      if ( state  )
978         thmfc1->data_raw_idx = 0;
979   }
980
981   VLOG(( "%f thmfc_floppy_index_pulse_cb: state=%i\n", attotime_to_double(timer_get_time(image->machine)), state ));
982}
983
984
985
986static int thmfc_floppy_find_sector ( running_machine *machine, chrn_id* dst )
987{
988   device_t* img = thmfc_floppy_image(machine);
989   chrn_id id;
990   int r = 0;
991
992   /* scan track, try 4 revolutions */
993   while ( r < 4 )
994   {
995
996      if ( floppy_drive_get_next_id( img, thmfc1->side, &id ) )
997      {
998         if ( id.C == thmfc1->track &&
999              id.R == thmfc1->sector &&
1000              (128 << id.N) == thmfc1->sector_size
1001              /* check side ?  id.H == thmfc1->side */ )
1002         {
1003            if ( dst )
1004               memcpy( dst, &id, sizeof( chrn_id ) );
1005            thmfc1->stat0 = THMFC1_STAT0_BYTE_READY_POL;
1006            LOG (( "thmfc_floppy_find_sector: sector found C=%i H=%i R=%i N=%i\n", id.C, id.H, id.R, id.N ));
1007            return 1;
1008         }
1009      }
1010
1011      if ( floppy_drive_get_flag_state( img, FLOPPY_DRIVE_INDEX ) )
1012         r++;
1013   }
1014
1015   thmfc1->stat0 = THMFC1_STAT0_CRC_ERROR | THMFC1_STAT0_FINISHED;
1016   LOG (( "thmfc_floppy_find_sector: sector not found drive=%i track=%i sector=%i\n", floppy_get_drive( img ), thmfc1->track, thmfc1->sector ));
1017   return 0;
1018}
1019
1020
1021
1022/* complete command (by read, write, or timeout) */
1023static void thmfc_floppy_cmd_complete( running_machine *machine )
1024{
1025   LOG (( "%f thmfc_floppy_cmd_complete_cb: cmd=%i off=%i/%i/%i\n",
1026          attotime_to_double(timer_get_time(machine)), thmfc1->op, thmfc1->data_idx,
1027          thmfc1->data_finish - 1, thmfc1->data_size - 1 ));
1028
1029   if ( thmfc1->op == THMFC1_OP_WRITE_SECT )
1030   {
1031      device_t * img = thmfc_floppy_image(machine);
1032      floppy_drive_write_sector_data( img, thmfc1->side, thmfc1->sector_id, thmfc1->data + 3, thmfc1->data_size - 3, 0 );
1033                thom_floppy_active( machine, 1 );
1034   }
1035   thmfc1->op = THMFC1_OP_RESET;
1036   thmfc1->stat0 |= THMFC1_STAT0_FINISHED;
1037   thmfc1->data_idx = 0;
1038   thmfc1->data_size = 0;
1039   timer_adjust_oneshot(thmfc_floppy_cmd, attotime_never, 0);
1040}
1041
1042
1043
1044static TIMER_CALLBACK( thmfc_floppy_cmd_complete_cb )
1045{
1046   thmfc_floppy_cmd_complete( machine );
1047}
1048
1049
1050
1051/* intelligent read: show just one field, skip header */
1052static UINT8 thmfc_floppy_read_byte ( running_machine *machine )
1053{
1054   UINT8 data = thmfc1->data[ thmfc1->data_idx ];
1055
1056   VLOG(( "%f $%04x thmfc_floppy_read_byte: off=%i/%i/%i data=$%02X\n",
1057          attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")),
1058          thmfc1->data_idx, thmfc1->data_finish - 1, thmfc1->data_size - 1,
1059          data ));
1060
1061   if ( thmfc1->data_idx >= thmfc1->data_size - 1 )
1062      thmfc_floppy_cmd_complete( machine );
1063   else
1064      thmfc1->data_idx++;
1065
1066   if ( thmfc1->data_idx >= thmfc1->data_finish )
1067      thmfc1->stat0 |= THMFC1_STAT0_FINISHED;
1068
1069   return data;
1070}
1071
1072
1073
1074/* dumb read: show whole track with field headers and gaps  */
1075static UINT8 thmfc_floppy_raw_read_byte ( running_machine *machine )
1076{
1077   UINT8 data;
1078
1079   /* rebuild track if needed */
1080   if ( ! thmfc1->data_raw_size )
1081   {
1082      if ( thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(thmfc_floppy_image(machine))))
1083         /* QDD: track = whole disk */
1084         thmfc1->data_raw_size = thom_qdd_make_disk ( thmfc_floppy_image(machine), thmfc1->data );
1085      else
1086      {
1087         thmfc1->data_raw_idx = 0;
1088         thmfc1->data_raw_size = thom_floppy_make_track( thmfc_floppy_image(machine), thmfc1->data,
1089                           thmfc1->sector_size, thmfc1->side );
1090      }
1091      assert( thmfc1->data_raw_size < sizeof( thmfc1->data ) );
1092   }
1093
1094   if ( thmfc1->data_raw_idx >= thmfc1->data_raw_size )
1095      data = 0;
1096   else
1097      data = thmfc1->data[ thmfc1->data_raw_idx ];
1098
1099   VLOG(( "%f $%04x thmfc_floppy_raw_read_byte: off=%i/%i data=$%02X\n",
1100          attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")),
1101          thmfc1->data_raw_idx, thmfc1->data_raw_size, data ));
1102
1103   thmfc1->data_raw_idx++;
1104
1105   return data;
1106}
1107
1108
1109
1110/* QDD writing / formating */
1111static void thmfc_floppy_qdd_write_byte ( running_machine *machine, UINT8 data )
1112{
1113   int i;
1114
1115   if ( thmfc1->formatting &&
1116        ( thmfc1->data_idx || data==0xA5 || data==0x5A ) &&
1117        thmfc1->data_raw_idx < THOM_MAXBUF )
1118   {
1119
1120      if ( ! thmfc1->data_raw_size )
1121      {
1122         thmfc1->data_raw_size = thom_qdd_make_disk ( thmfc_floppy_image(machine), thmfc1->data );
1123         assert( thmfc1->data_raw_size < sizeof( thmfc1->data ) );
1124      }
1125
1126      /* accumulate bytes to form a field */
1127      thmfc1->data[ thmfc1->data_raw_idx ] = data;
1128      thmfc1->data_raw_idx++;
1129
1130      if ( ! thmfc1->data_idx  )
1131      {
1132         /* start */
1133         thmfc1->data_crc = 0;
1134         thmfc1->data_idx = thmfc1->data_raw_idx;
1135      }
1136
1137      VLOG (( "%f $%04x thmfc_floppy_qdd_write_byte: $%02X offs=%i-%i\n",
1138         attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), data,
1139         thmfc1->data_idx,thmfc1->data_raw_idx ));
1140
1141      if ( thmfc1->data_raw_idx == thmfc1->data_idx + 3 &&
1142           thmfc1->data[ thmfc1->data_idx - 1 ] == 0xA5 &&
1143           thmfc1->data[ thmfc1->data_idx + 2 ] == thmfc1->data_crc )
1144      {
1145
1146         /* got an id field => format */
1147         int sector = (int) thmfc1->data[ thmfc1->data_idx ] * 256 + (int) thmfc1->data[ thmfc1->data_idx + 1 ];
1148         UINT8 filler = 0xff;
1149
1150         LOG(( "%f $%04x thmfc_floppy_qdd_write_byte: id field, sector=%i\n", attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), sector ));
1151
1152         floppy_drive_format_sector( thmfc_floppy_image(machine), 0, sector, 0, 0, sector, 128, filler );
1153                        thom_floppy_active( machine, 1 );
1154         thmfc1->data_idx = 0;
1155      }
1156
1157      else if ( thmfc1->data_raw_idx == thmfc1->data_idx + 129 &&
1158           thmfc1->data[ thmfc1->data_idx -   1 ] == 0x5A &&
1159           thmfc1->data[ thmfc1->data_idx + 128 ] == thmfc1->data_crc )
1160      {
1161
1162         /* look backwards for previous id field */
1163         for ( i = thmfc1->data_idx - 4; i >= 0; i-- )
1164         {
1165            if ( thmfc1->data[ i ] == 0xA5 &&
1166                 ( ( thmfc1->data[ i ] + thmfc1->data[ i + 1 ] +
1167                thmfc1->data[ i + 2 ] ) & 0xff
1168                    ) == thmfc1->data[ i + 3 ] )
1169               break;
1170         }
1171
1172         if ( i >= 0 )
1173         {
1174            /* got an id & a data field => write */
1175            device_t * img = thmfc_floppy_image(machine);
1176            int sector = (int) thmfc1->data[ i + 1 ] * 256 +
1177               (int) thmfc1->data[ i + 2 ];
1178
1179            LOG(( "%f $%04x thmfc_floppy_qdd_write_byte: data field, sector=%i\n",
1180                  attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), sector ));
1181
1182            floppy_drive_write_sector_data( img, 0, sector, thmfc1->data + thmfc1->data_idx, 128, 0 );
1183                                thom_floppy_active( machine, 1 );
1184         }
1185
1186         thmfc1->data_idx = 0;
1187
1188      }
1189      else
1190         thmfc1->data_crc += data;
1191   }
1192   else
1193   {
1194      thmfc1->data_raw_idx++;
1195      VLOG (( "%f $%04x thmfc_floppy_qdd_write_byte: ignored $%02X\n", attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), data ));
1196   }
1197
1198}
1199
1200
1201
1202/* intelligent writing */
1203static void thmfc_floppy_write_byte ( running_machine *machine, UINT8 data )
1204{
1205   VLOG (( "%f $%04x thmfc_floppy_write_byte: off=%i/%i data=$%02X\n",
1206      attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")),
1207      thmfc1->data_idx, thmfc1->data_size - 1, data ));
1208
1209   thmfc1->data_raw_size = 0;
1210   thmfc1->data[ thmfc1->data_idx ] = data;
1211   if ( thmfc1->data_idx >= thmfc1->data_size - 1 )
1212      thmfc_floppy_cmd_complete( machine );
1213   else
1214      thmfc1->data_idx++;
1215}
1216
1217/* intelligent formatting */
1218static void thmfc_floppy_format_byte ( running_machine *machine, UINT8 data )
1219{
1220   VLOG (( "%f $%04x thmfc_floppy_format_byte: $%02X\n", attotime_to_double(timer_get_time(machine)), cpu_get_previouspc(machine->device("maincpu")), data ));
1221
1222   thmfc1->data_raw_size = 0;
1223
1224   /* accumulate bytes to form an id field */
1225   if ( thmfc1->data_idx || data==0xA1 )
1226   {
1227      static const UINT8 header[] = { 0xa1, 0xa1, 0xa1, 0xfe };
1228      thmfc1->data[ thmfc1->data_idx ] = data;
1229      thmfc1->data_idx++;
1230      if ( thmfc1->data_idx > 11 )
1231      {
1232
1233         if ( !memcmp ( thmfc1->data, header, sizeof( header ) ) )
1234         {
1235            /* got id field => format */
1236            device_t * img = thmfc_floppy_image(machine);
1237            UINT8 track  = thmfc1->data[4];
1238            UINT8 side   = thmfc1->data[5];
1239            UINT8 sector = thmfc1->data[6];
1240            UINT8 length = thmfc1->data[7]; /* actually, log length */
1241            UINT8 filler = 0xe5;            /* standard Thomson filler */
1242                                chrn_id id;
1243                                if ( thmfc_floppy_find_sector( machine, &id ) )
1244                                {
1245                                        floppy_drive_format_sector( img, side, thmfc1->sector_id, track, thmfc1->side, sector, length, filler );
1246                                        thom_floppy_active( machine, 1 );
1247                                }
1248         }
1249
1250         thmfc1->data_idx = 0;
1251      }
1252
1253   }
1254}
1255
1256
1257
1258READ8_HANDLER ( thmfc_floppy_r )
1259{
1260   switch ( offset )
1261   {
1262
1263   case 0: /* STAT0 */
1264      thmfc1->stat0 ^= THMFC1_STAT0_SYNCHRO | THMFC1_STAT0_BYTE_READY_POL;
1265      VLOG(( "%f $%04x thmfc_floppy_r: STAT0=$%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), thmfc1->stat0 ));
1266      return thmfc1->stat0;
1267
1268   case 1: /* STAT1 */
1269   {
1270      UINT8 data = 0;
1271      device_image_interface * img = dynamic_cast<device_image_interface *>(thmfc_floppy_image(space->machine));
1272      int flags = floppy_drive_get_flag_state( &img->device(), -1 );
1273      if ( thmfc_floppy_is_qdd(img) )
1274      {
1275         if ( ! img->exists() )
1276            data |= 0x40; /* disk present */
1277         if ( ! thmfc1->ipl )
1278            data |= 0x02;       /* disk start */
1279         data |= 0x08; /* connected */
1280      }
1281      else
1282      {
1283         if ( thmfc1->ipl )
1284            data |= 0x40;
1285         if ( img->exists() )
1286            data |= 0x20; /* disk change (?) */
1287
1288         data |= !floppy_tk00_r(&img->device()) << 3;
1289
1290         if ( flags & FLOPPY_DRIVE_READY )
1291            data |= 0x02;
1292      }
1293      if (!motor_on)
1294         data |= 0x10;
1295      if (!floppy_wpt_r(&img->device()))
1296         data |= 0x04;
1297      VLOG(( "%f $%04x thmfc_floppy_r: STAT1=$%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
1298      return data;
1299   }
1300
1301   case 3: /* RDATA */
1302
1303      if ( thmfc1->op == THMFC1_OP_READ_SECT || thmfc1->op == THMFC1_OP_READ_ADDR )
1304         return thmfc_floppy_read_byte( space->machine );
1305      else
1306         return thmfc_floppy_raw_read_byte( space->machine );
1307
1308   case 6:
1309      return 0;
1310
1311   case 8:
1312   {
1313      /* undocumented => emulate TO7 QDD controller ? */
1314      UINT8 data = thmfc1->ipl << 7;
1315      VLOG(( "%f $%04x thmfc_floppy_r: STAT8=$%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
1316      return data;
1317   }
1318
1319   default:
1320      logerror ( "%f $%04x thmfc_floppy_r: invalid read offset %i\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset );
1321      return 0;
1322   }
1323}
1324
1325
1326
1327WRITE8_HANDLER ( thmfc_floppy_w )
1328{
1329   switch ( offset ) {
1330
1331   case 0: /* CMD0 */
1332   {
1333      int wsync = (data >> 4) & 1;
1334      int qdd = thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(thmfc_floppy_image(space->machine)));
1335      chrn_id id;
1336      thmfc1->formatting = (data >> 2) & 1;
1337      LOG (( "%f $%04x thmfc_floppy_w: CMD0=$%02X dens=%s wsync=%i dsync=%i fmt=%i op=%i\n",
1338             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
1339             (BIT(data, 5) ? "FM" : "MFM"),
1340             wsync, (data >> 3) & 1,
1341             thmfc1->formatting, data & 3 ));
1342
1343      /* abort previous command, if any */
1344      thmfc1->op = THMFC1_OP_RESET;
1345      timer_adjust_oneshot(thmfc_floppy_cmd, attotime_never, 0);
1346
1347      switch ( data & 3 )
1348      {
1349
1350      case THMFC1_OP_RESET:
1351         thmfc1->stat0 = THMFC1_STAT0_FINISHED;
1352         break;
1353
1354      case THMFC1_OP_WRITE_SECT:
1355         if ( qdd )
1356            logerror( "thmfc_floppy_w: smart operation 1 not supported for QDD\n" );
1357         else if ( thmfc_floppy_find_sector( space->machine, &id ) )
1358         {
1359                                thmfc1->sector_id = id.data_id;
1360            thmfc1->data_idx = 0;
1361            thmfc1->data_size = thmfc1->sector_size + 3; /* A1 A1 FB <data> */
1362            thmfc1->data_finish = thmfc1->sector_size + 3;
1363            thmfc1->stat0 |= THMFC1_STAT0_BYTE_READY_OP;
1364            thmfc1->op = THMFC1_OP_WRITE_SECT;
1365            timer_adjust_oneshot(thmfc_floppy_cmd, ATTOTIME_IN_MSEC( 10 ), 0);
1366         }
1367         break;
1368
1369      case THMFC1_OP_READ_ADDR:
1370         if ( qdd )
1371            logerror( "thmfc_floppy_w: smart operation 2 not supported for QDD\n" );
1372         else if ( thmfc_floppy_find_sector( space->machine, &id ) )
1373         {
1374            thmfc1->data_size =
1375               thom_floppy_make_addr( id, thmfc1->data, thmfc1->sector_size );
1376            assert( thmfc1->data_size < sizeof( thmfc1->data ) );
1377            thmfc1->data_finish = 10;
1378            thmfc1->data_idx = 1;
1379            thmfc1->stat0 |= THMFC1_STAT0_BYTE_READY_OP;
1380            thmfc1->op = THMFC1_OP_READ_ADDR;
1381            timer_adjust_oneshot(thmfc_floppy_cmd, ATTOTIME_IN_MSEC( 1 ), 0);
1382         }
1383         break;
1384
1385      case THMFC1_OP_READ_SECT:
1386         if ( qdd )
1387            logerror( "thmfc_floppy_w: smart operation 3 not supported for QDD\n" );
1388         else if ( thmfc_floppy_find_sector( space->machine, &id ) )
1389         {
1390            thmfc1->data_size = thom_floppy_make_sector
1391               ( thmfc_floppy_image(space->machine), id, thmfc1->data, thmfc1->sector_size );
1392            assert( thmfc1->data_size < sizeof( thmfc1->data ) );
1393            thmfc1->data_finish = thmfc1->sector_size + 4;
1394            thmfc1->data_idx = 1;
1395            thmfc1->stat0 |= THMFC1_STAT0_BYTE_READY_OP;
1396            thmfc1->op = THMFC1_OP_READ_SECT;
1397            timer_adjust_oneshot(thmfc_floppy_cmd, ATTOTIME_IN_MSEC( 10 ), 0);
1398         }
1399         break;
1400      }
1401
1402      /* synchronize to word, if needed (QDD only) */
1403      if ( wsync && qdd ) {
1404         if ( ! thmfc1->data_raw_size )
1405            thmfc1->data_raw_size = thom_qdd_make_disk ( thmfc_floppy_image(space->machine), thmfc1->data );
1406         while ( thmfc1->data_raw_idx < thmfc1->data_raw_size &&
1407            thmfc1->data[ thmfc1->data_raw_idx ] != thmfc1->wsync )
1408         {
1409            thmfc1->data_raw_idx++;
1410         }
1411      }
1412   }
1413
1414   break;
1415
1416
1417   case 1: /* CMD1 */
1418      thmfc1->data_raw_size = 0;
1419      thmfc1->sector_size = 128 << ( (data >> 5) & 3);
1420      thmfc1->side = (data >> 4) & 1;
1421      if ( thmfc1->sector_size > 256 )
1422      {
1423         logerror( "$%04x thmfc_floppy_w: sector size %i > 256 not handled\n",
1424              cpu_get_previouspc(space->machine->device("maincpu")), thmfc1->sector_size );
1425         thmfc1->sector_size = 256;
1426      }
1427
1428      LOG (( "%f $%04x thmfc_floppy_w: CMD1=$%02X sect-size=%i comp=%i head=%i\n",
1429             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
1430             thmfc1->sector_size, (data >> 1) & 7, thmfc1->side ));
1431      break;
1432
1433
1434   case 2: /* CMD2 */
1435   {
1436      device_t * img;
1437      int seek = 0, motor;
1438      thmfc1->drive = data & 2;
1439
1440      img = thmfc_floppy_image(space->machine);
1441      if ( thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(img)))
1442      {
1443         motor = !(data & 0x40);
1444         /* no side select & no seek for QDD */
1445      }
1446      else
1447      {
1448         if ( data & 0x10 )
1449            seek = (data & 0x20) ? 1 : -1;
1450         motor =  (data >> 2) & 1;
1451         thmfc1->drive |= 1 ^ ((data >> 6) & 1);
1452                        img = thmfc_floppy_image(space->machine);
1453      }
1454
1455      thom_floppy_active( space->machine, 0 );
1456
1457      LOG (( "%f $%04x thmfc_floppy_w: CMD2=$%02X drv=%i step=%i motor=%i\n",
1458             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
1459             thmfc1->drive, seek, motor ));
1460
1461      if ( seek )
1462      {
1463         thmfc1->data_raw_size = 0;
1464         floppy_drive_seek( img, seek );
1465      }
1466
1467      /* in real life, to keep the motor running, it is sufficient to
1468           set motor to 1 every few seconds.
1469           instead of counting, we assume the motor is always running...
1470        */
1471      motor_on = CLEAR_LINE /* motor */;
1472      floppy_mon_w(img, motor_on);
1473   }
1474   break;
1475
1476
1477   case 3: /* WDATA */
1478      thmfc1->wsync = data;
1479      if ( thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(thmfc_floppy_image(space->machine))))
1480         thmfc_floppy_qdd_write_byte( space->machine, data );
1481      else if ( thmfc1->op==THMFC1_OP_WRITE_SECT )
1482         thmfc_floppy_write_byte( space->machine, data );
1483      else if ( thmfc1->formatting )
1484         thmfc_floppy_format_byte( space->machine, data );
1485      else
1486      {
1487         /* TODO: implement other forms of raw track writing */
1488         LOG (( "%f $%04x thmfc_floppy_w: ignored raw WDATA $%02X\n",
1489                attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
1490      }
1491      break;
1492
1493
1494   case 4: /* WCLK (unemulated) */
1495      /* clock configuration: FF for data, 0A for synchro */
1496      LOG (( "%f $%04x thmfc_floppy_w: WCLK=$%02X (%s)\n",
1497             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
1498             (data == 0xff) ? "data" : (data == 0x0A) ? "synchro" : "?" ));
1499      break;
1500
1501   case 5: /* WSECT */
1502      thmfc1->sector = data;
1503      LOG (( "%f $%04x thmfc_floppy_w: WSECT=%i\n",
1504             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
1505      break;
1506
1507   case 6: /* WTRCK */
1508      thmfc1->track = data;
1509      LOG (( "%f $%04x thmfc_floppy_w: WTRCK=%i (real=%i)\n",
1510             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data,
1511             floppy_drive_get_current_track( thmfc_floppy_image(space->machine) ) ));
1512      break;
1513
1514   case 7: /* WCELL */
1515      /* precompensation (unemulated) */
1516      LOG (( "%f $%04x thmfc_floppy_w: WCELL=$%02X\n",
1517             attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), data ));
1518      break;
1519
1520   default:
1521      logerror ( "%f $%04x thmfc_floppy_w: invalid write offset %i (data=$%02X)\n",
1522            attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset, data );
1523   }
1524}
1525
1526
1527
1528void thmfc_floppy_reset( running_machine *machine )
1529{
1530   int i;
1531   LOG(( "thmfc_floppy_reset: THMFC1 controller\n" ));
1532
1533   for ( i = 0; i < floppy_get_count( machine ); i++ )
1534   {
1535      device_t * img = floppy_get_device( machine, i );
1536      if (img) {
1537         floppy_drive_set_index_pulse_callback( img, thmfc_floppy_index_pulse_cb );
1538         floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 );
1539         floppy_drive_seek( img, - floppy_drive_get_current_track( img ) );
1540      }
1541   }
1542
1543   thmfc1->op = THMFC1_OP_RESET;
1544   thmfc1->track = 0;
1545   thmfc1->sector = 0;
1546   thmfc1->side = 0;
1547   thmfc1->drive = 0;
1548   thmfc1->sector_size = 256;
1549   thmfc1->formatting = 0;
1550   thmfc1->stat0 = 0;
1551   thmfc1->data_idx = 0;
1552   thmfc1->data_size = 0;
1553   thmfc1->data_raw_idx = 0;
1554   thmfc1->data_raw_size = 0;
1555   thmfc1->data_crc = 0;
1556   thmfc1->wsync = 0;
1557   timer_adjust_oneshot(thmfc_floppy_cmd, attotime_never, 0);
1558}
1559
1560
1561
1562void thmfc_floppy_init( running_machine *machine )
1563{
1564   LOG(( "thmfc_floppy_init: THMFC1 controller\n" ));
1565
1566   thmfc1 = auto_alloc(machine, struct _thmfc1);
1567
1568   thmfc_floppy_cmd = timer_alloc( machine, thmfc_floppy_cmd_complete_cb, NULL );
1569
1570   state_save_register_global( machine, thmfc1->op );
1571   state_save_register_global( machine, thmfc1->sector );
1572   state_save_register_global( machine, thmfc1->sector_id );
1573   state_save_register_global( machine, thmfc1->track );
1574   state_save_register_global( machine, thmfc1->side );
1575   state_save_register_global( machine, thmfc1->drive );
1576   state_save_register_global( machine, thmfc1->sector_size );
1577   state_save_register_global( machine, thmfc1->formatting );
1578   state_save_register_global( machine, thmfc1->ipl );
1579   state_save_register_global( machine, thmfc1->data_idx );
1580   state_save_register_global( machine, thmfc1->data_size );
1581   state_save_register_global( machine, thmfc1->data_finish );
1582   state_save_register_global( machine, thmfc1->stat0 );
1583   state_save_register_global( machine, thmfc1->data_raw_idx );
1584   state_save_register_global( machine, thmfc1->data_raw_size );
1585   state_save_register_global( machine, thmfc1->data_crc );
1586   state_save_register_global( machine, thmfc1->wsync );
1587   state_save_register_global_array( machine, thmfc1->data );
1588}
1589
1590
1591
1592/*********************** Network ************************/
1593
1594/* The network extension is built as an external floppy controller.
1595   It uses the same ROM and I/O space, and so, it is natural to have the
1596   toplevel network emulation here!
1597*/
1598
1599/* NOTE: This is work in progress!
1600   For the moment, only hand-checks works: the TO7 can take the line, then
1601   perform a DKBOOT request. We do not have the server emulated yet, so,
1602   no way to answer the request.
1603*/
1604
1605static TIMER_CALLBACK( ans4 )
1606{
1607   LOG(( "%f ans4\n", attotime_to_double(timer_get_time(machine)) ));
1608   mc6854_set_cts( machine->device("mc6854"), 0 );
1609}
1610
1611static TIMER_CALLBACK( ans3 )
1612{
1613   LOG(( "%f ans3\n", attotime_to_double(timer_get_time(machine)) ));
1614   mc6854_set_cts( machine->device("mc6854"), 1 );
1615   timer_set( machine, ATTOTIME_IN_USEC( 100 ), NULL, 0, ans4 );
1616}
1617
1618static TIMER_CALLBACK( ans2 )
1619{
1620   LOG(( "%f ans2\n", attotime_to_double(timer_get_time(machine)) ));
1621   mc6854_set_cts( machine->device("mc6854"), 0 );
1622   timer_set( machine, ATTOTIME_IN_USEC( 100 ), NULL, 0, ans3 );
1623}
1624
1625static TIMER_CALLBACK( ans )
1626{
1627   LOG(( "%f ans\n", attotime_to_double(timer_get_time(machine)) ));
1628   mc6854_set_cts( machine->device("mc6854"), 1 );
1629   timer_set( machine, ATTOTIME_IN_USEC( 100 ), NULL, 0, ans2 );
1630}
1631/* consigne DKBOOT
1632
1633   MO5 BASIC
1634   $00 $00 $01 $00 $00 $00 $00 $00 $00 $00 $01 $00<$41 $00 $FF $20
1635   $3D $4C $01 $60 $20 $3C $4F $01 $05 $20 $3F $9C $19 $25 $03 $11
1636   $93 $15 $10 $25 $32 $8A $7E $FF $E1 $FD $E9 $41>$00 $00 $00 $00
1637   $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00
1638
1639   TO7/70 BASIC
1640   $00 $00 $01 $00 $00 $00 $00 $00 $00 $00 $02 $00<$20 $42 $41 $53
1641   $49 $43 $20 $4D $49 $43 $52 $4F $53 $4F $46 $54 $20 $31 $2E $30
1642   $04 $00 $00 $00 $00 $00 $60 $FF $37 $9B $37 $9C>$00 $00 $00 $00
1643   $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00
1644
1645   TO7 BASIC
1646   $00 $00 $01 $00 $00 $00 $00 $00 $00 $00 $00 $00<$20 $42 $41 $53
1647   $49 $43 $20 $4D $49 $43 $52 $4F $53 $4F $46 $54 $20 $31 $2E $30
1648   $04 $00 $00 $00 $00 $00 $60 $FF $37 $9B $37 $9C>$00 $00 $00 $00
1649   $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00
1650
1651   TO7 LOGO
1652   $00 $00 $01 $00 $00 $00 $00 $00 $00 $00 $00 $00<$00 $00 $00 $00
1653   $00 $20 $4C $4F $47 $4F $04 $00 $00 $00 $00 $00 $00 $00 $00 $00
1654   $00 $00 $00 $00 $00 $00 $AA $FF $01 $16 $00 $C8>$00 $00 $00 $00
1655   $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00
1656
1657
1658*/
1659
1660static void to7_network_got_frame( device_t *device, UINT8* data, int length )
1661{
1662   int i;
1663   LOG(( "%f to7_network_got_frame:", attotime_to_double(timer_get_time(device->machine)) ));
1664   for ( i = 0; i < length; i++ )
1665      LOG(( " $%02X", data[i] ));
1666   LOG(( "\n" ));
1667
1668   if ( data[1] == 0xff )
1669   {
1670      LOG(( "to7_network_got_frame: %i phones %i\n", data[2], data[0] ));
1671      timer_set( device->machine, ATTOTIME_IN_USEC( 100 ), NULL, 0, ans  );
1672      mc6854_set_cts( device, 0 );
1673   }
1674   else if ( ! data[1] )
1675   {
1676      char name[33];
1677      memcpy( name, data + 12, 32 );
1678      name[32] = 0;
1679      for (i=0;i<32;i++)
1680      {
1681         if ( name[i]<32 || name[i]>=127 )
1682            name[i]=' ';
1683      }
1684      LOG(( "to7_network_got_frame: DKBOOT system=%s appli=\"%s\"\n",
1685            (data[10] == 0) ? "TO7" : (data[10] == 1) ? "MO5" :
1686            (data[10] == 2) ? "TO7/70" : "?", name ));
1687   }
1688
1689}
1690
1691
1692
1693const mc6854_interface to7_network_iface = { NULL, to7_network_got_frame, NULL, NULL };
1694
1695
1696
1697static void to7_network_init( running_machine *machine )
1698{
1699   LOG(( "to7_network_init: NR 07-005 network extension\n" ));
1700   logerror( "to7_network_init: network not handled!\n" );
1701}
1702
1703
1704
1705static void to7_network_reset( running_machine *machine )
1706{
1707   LOG(( "to7_network_reset: NR 07-005 network extension\n" ));
1708   mc6854_set_cts( machine->device("mc6854"), 0 );
1709   mc6854_set_cts( machine->device("mc6854"), 1 );
1710}
1711
1712
1713
1714static READ8_HANDLER ( to7_network_r )
1715{
1716   if ( offset >= 0 && offset < 4 )
1717      return mc6854_r( space->machine->device("mc6854"), offset );
1718
1719   if ( offset == 8 )
1720   {
1721      /* network ID of the computer */
1722      UINT8 id = input_port_read(space->machine, "fconfig") >> 3;
1723      VLOG(( "%f $%04x to7_network_r: read id $%02X\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), id ));
1724      return id;
1725   }
1726
1727   logerror( "%f $%04x to7_network_r: invalid read offset %i\n", attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset );
1728   return 0;
1729}
1730
1731
1732
1733static WRITE8_HANDLER ( to7_network_w )
1734{
1735   if ( offset >= 0 && offset < 4 )
1736      mc6854_w( space->machine->device("mc6854"), offset, data );
1737   else
1738   {
1739      logerror( "%f $%04x to7_network_w: invalid write offset %i (data=$%02X)\n",
1740           attotime_to_double(timer_get_time(space->machine)), cpu_get_previouspc(space->machine->device("maincpu")), offset, data );
1741   }
1742}
1743
1744
1745
1746/*********************** TO7 dispatch ************************/
1747
1748/* The TO7, TO7/70, MO5 and MO6 can use a variety of floppy controllers.
1749   We use a PORT_CONFSETTING to chose the current controller, and dispatch
1750   here.
1751
1752   NOTE: you need to reset the computer after changing the floppy controller!
1753
1754   The CD 90-351 controller seems similar to the THMFC1 gate-array
1755   => we reuse the THMFC code!
1756*/
1757
1758
1759
1760UINT8 to7_controller_type;
1761UINT8 to7_floppy_bank;
1762
1763
1764void to7_floppy_init ( running_machine *machine, void* base )
1765{
1766   memory_configure_bank( machine, THOM_FLOP_BANK, 0, TO7_NB_FLOP_BANK, base, 0x800 );
1767   state_save_register_global( machine, to7_controller_type );
1768   state_save_register_global( machine, to7_floppy_bank );
1769   to7_5p14sd_init(machine);
1770   to7_5p14_init(machine);
1771   to7_qdd_init(machine);
1772   thmfc_floppy_init(machine);
1773   to7_network_init(machine);
1774}
1775
1776
1777
1778void to7_floppy_reset ( running_machine *machine )
1779{
1780   to7_controller_type = (input_port_read(machine, "fconfig") ) & 7;
1781
1782   switch ( to7_controller_type )
1783   {
1784
1785   case 1:
1786      to7_floppy_bank = 1;
1787      to7_5p14sd_reset(machine);
1788      break;
1789
1790   case 2:
1791      to7_floppy_bank = 2;
1792      to7_5p14_reset(machine);
1793      break;
1794
1795   case 3:
1796      to7_floppy_bank = 3;
1797      thmfc_floppy_reset(machine);
1798      break;
1799
1800   case 4:
1801      to7_floppy_bank = 7;
1802      to7_qdd_reset(machine);
1803      break;
1804
1805   case 5:
1806      to7_floppy_bank = 8;
1807      to7_network_reset(machine);
1808      break;
1809
1810   default:
1811      to7_floppy_bank = 0;
1812      break;
1813   }
1814
1815   memory_set_bank( machine, THOM_FLOP_BANK, to7_floppy_bank );
1816}
1817
1818
1819
1820READ8_HANDLER ( to7_floppy_r )
1821{
1822   switch ( to7_controller_type )
1823   {
1824
1825   case 1:
1826      return to7_5p14sd_r( space, offset );
1827
1828   case 2:
1829      return to7_5p14_r( space, offset );
1830
1831   case 3:
1832      return thmfc_floppy_r( space, offset );
1833
1834   case 4:
1835      return to7_qdd_r( space, offset );
1836
1837   case 5:
1838      return to7_network_r( space, offset );
1839   }
1840
1841   return 0;
1842}
1843
1844
1845
1846WRITE8_HANDLER ( to7_floppy_w )
1847{
1848   switch ( to7_controller_type )
1849   {
1850
1851   case 1:
1852      to7_5p14sd_w( space, offset, data );
1853      return;
1854
1855   case 2:
1856      to7_5p14_w( space, offset, data );
1857      break;
1858
1859   case 3:
1860      if ( offset == 8 )
1861      {
1862         to7_floppy_bank = 3 + (data & 3);
1863         memory_set_bank( space->machine, THOM_FLOP_BANK,  to7_floppy_bank );
1864         VLOG (( "to7_floppy_w: set CD 90-351 ROM bank to %i\n", data & 3 ));
1865      }
1866      else
1867         thmfc_floppy_w( space, offset, data );
1868      break;
1869
1870   case 4:
1871      to7_qdd_w( space, offset, data );
1872      break;
1873
1874   case 5:
1875      to7_network_w( space, offset, data );
1876      break;
1877   }
1878}
1879
1880
1881
1882/*********************** TO9 ************************/
1883
1884/* the internal controller is WD2793-based (so, similar to to7_5p14)
1885   we also emulate external controllers
1886*/
1887
1888
1889
1890void to9_floppy_init( running_machine *machine, void* int_base, void* ext_base )
1891{
1892   to7_floppy_init( machine, ext_base );
1893   memory_configure_bank( machine, THOM_FLOP_BANK, TO7_NB_FLOP_BANK, 1, int_base, 0x800 );
1894}
1895
1896
1897
1898void to9_floppy_reset( running_machine *machine )
1899{
1900   to7_floppy_reset(machine);
1901   if ( THOM_FLOPPY_EXT )
1902   {
1903      LOG(( "to9_floppy_reset: external controller\n" ));
1904   }
1905   else
1906   {
1907      LOG(( "to9_floppy_reset: internal controller\n" ));
1908      to7_5p14_reset(machine);
1909      memory_set_bank( machine, THOM_FLOP_BANK, TO7_NB_FLOP_BANK );
1910   }
1911}
1912
1913
1914
1915READ8_HANDLER ( to9_floppy_r )
1916{
1917   if ( THOM_FLOPPY_EXT )
1918      return to7_floppy_r( space, offset );
1919   else
1920      return  to7_5p14_r( space, offset );
1921}
1922
1923WRITE8_HANDLER ( to9_floppy_w )
1924{
1925   if ( THOM_FLOPPY_EXT )
1926      to7_floppy_w( space, offset, data );
1927   else
1928      to7_5p14_w( space, offset, data );
1929}
src/mess/machine/thomflop.h
r0r9938
1/**********************************************************************
2
3  Copyright (C) Antoine Mine' 2006
4
5  Thomson 8-bit computers
6
7**********************************************************************/
8
9#ifndef THOMFLOP_H_
10#define THOMFLOP_H_
11
12#include "image.h"
13#include "machine/mc6843.h"
14#include "machine/mc6854.h"
15
16extern const mc6843_interface to7_6843_itf;
17extern const mc6854_interface to7_network_iface;
18
19extern UINT8 to7_controller_type; /* set during init */
20extern UINT8 to7_floppy_bank;
21
22/* number of external floppy controller ROM banks */
23#define TO7_NB_FLOP_BANK 9
24
25/* external floppy / network controller active */
26#define THOM_FLOPPY_EXT (to7_controller_type >= 1)
27
28/* internal floppy controller active (no or network extension) */
29#define THOM_FLOPPY_INT (to7_controller_type == 0 || to7_controller_type > 4)
30
31
32/* external controllers */
33extern void to7_floppy_init  ( running_machine *machine, void* base );
34extern void to7_floppy_reset ( running_machine *machine );
35extern READ8_HANDLER  ( to7_floppy_r );
36extern WRITE8_HANDLER ( to7_floppy_w );
37
38/* TO9 internal (WD2793) & external controllers */
39extern void to9_floppy_init  ( running_machine *machine, void* int_base, void* ext_base );
40extern void to9_floppy_reset ( running_machine *machine );
41extern READ8_HANDLER  ( to9_floppy_r );
42extern WRITE8_HANDLER ( to9_floppy_w );
43
44/* TO8 internal (THMFC1) controller */
45extern void thmfc_floppy_init  ( running_machine *machine );
46extern void thmfc_floppy_reset ( running_machine *machine );
47extern READ8_HANDLER  ( thmfc_floppy_r );
48extern WRITE8_HANDLER ( thmfc_floppy_w );
49
50
51#endif /* THOMFLOP_H_ */
src/mess/includes/thomson.h
r9937r9938
2626#include "machine/mc6854.h"
2727#include "formats/thom_cas.h"
2828#include "formats/thom_dsk.h"
29#include "devices/thomflop.h"
29#include "machine/thomflop.h"
3030
3131
3232/*----------- defined in machine/thomson.c -----------*/
src/mess/mess.mak
r9937r9938
15301530   $(MESS_DRIVERS)/thomson.o   \
15311531   $(MESS_MACHINE)/thomson.o   \
15321532   $(MESS_VIDEO)/thomson.o      \
1533   $(MESS_DEVICES)/thomflop.o   \
1533   $(MESS_MACHINE)/thomflop.o   \
15341534   $(MESS_FORMATS)/thom_dsk.o   \
15351535   $(MESS_FORMATS)/thom_cas.o   \
15361536
r9937r9938
15721572   $(MESS_MACHINE)/ti99/sgcpu.o  \
15731573   $(MESS_MACHINE)/ti99/genboard.o  \
15741574   $(MESS_MACHINE)/ti99/tiboard.o  \
1575   $(MESS_MACHINE)/ti99/ti99_hd.o   \
15751576   $(MESS_MACHINE)/strata.o   \
15761577   $(MESS_MACHINE)/990_dk.o   \
15771578   $(MESS_DRIVERS)/ti990_4.o   \
r9937r9938
15801581   $(MESS_DRIVERS)/geneve.o   \
15811582   $(MESS_DRIVERS)/tm990189.o   \
15821583   $(MESS_DRIVERS)/ti99_8.o   \
1583   $(MESS_DEVICES)/ti99_hd.o   \
15841584   $(MESS_VIDEO)/911_vdt.o      \
15851585   $(MESS_VIDEO)/733_asr.o      \
15861586   $(MESS_DRIVERS)/ti990_10.o   \

Previous 15994 Revisions Next


© 1998-2018 The MESS Team