Previous 15994 Revisions Next

r7367 Tuesday 16th February, 2010 at 08:34:50 UTC by Miodrag Milanović
- Adds track dump floppy image support (also known as pc99 format) to
TI-99/4(A), /8, /4P, Geneve
- Extends sector dump floppy image support to collaborate with track
operations (full support of low-level formatting)
- Enables track read/write functionality for WD17xx.
[Michael Zapf]
[src/mess]mess.mak
[src/mess/drivers]geneve.c ti99_4p.c ti99_4x.c ti99_8.c
[src/mess/formats]ti99_dsk.c* ti99_dsk.h*
[src/mess/machine]99_dsk.c 99_dsk.h wd17xx.c

src/mess/machine/99_dsk.c
r7366r7367
2121    but I think this computer supported the TI-99/4(a) disk controllers, too.
2222
2323    Raphael Nabet, 1999-2004.
24   
25    CHANGES
26   
27    * Removed format definition and put it in separate file (ti99_dsk)
28      Michael Zapf, Feb 2010
2429*/
2530
2631#include "emu.h"
27#include "machine/wd17xx.h"
32#include "wd17xx.h"
2833#include "smc92x4.h"
29#include "ti99_4x.h"
34#include "ti99_4x.h"  /* required for memory region offsets */
3035#include "99_peb.h"
3136#include "99_dsk.h"
3237#include "mm58274c.h"
33#include "formats/basicdsk.h"
3438#include "devices/flopdrv.h"
3539
3640
r7366r7367
6468static emu_timer *motor_on_timer;
6569
6670/*
71   Resets the drive geometry. This is required because the heuristic of
72   the default implementation sets the drive geometry to the geometry
73   of the medium.
74*/
75static void set_geometry(running_device *drive, floppy_type_t type)
76{
77   if (drive!=NULL)
78      floppy_drive_set_geometry(drive, type);
79   else
80      logerror("Drive not found\n");
81}
82
83static void set_all_geometries(running_machine *machine, floppy_type_t type)
84{
85   set_geometry(devtag_get_device(machine, FLOPPY_0), type);
86   set_geometry(devtag_get_device(machine, FLOPPY_1), type);
87   set_geometry(devtag_get_device(machine, FLOPPY_2), type);
88   set_geometry(devtag_get_device(machine, FLOPPY_3), type);
89}
90
91/*
92   Callback for the ti99_dsk format. Required for the image format handler
93   to find out whether we have a 40-track disk in an 80-track drive.
94*/
95int ti99_image_in_80_track_drive()
96{
97   return use_80_track_drives;
98}
99
100/*
67101    call this when the state of DSKhold or DRQ/IRQ or DVENA change
68102
69103    Emulation is faulty because the CPU is actually stopped in the midst of
r7366r7367
86120   fdc_handle_hold(machine);
87121}
88122
89typedef struct ti99_geometry
90{
91   UINT8 sides;
92   UINT8 tracksperside;
93   UINT8 secspertrack;
94   UINT8 density;
95} ti99_geometry;
96
97123static void hfdc_int_callback(int which, int state);
98124static int hfdc_select_callback(int which, select_mode_t select_mode, int select_line, int gpos);
99125static UINT8 hfdc_dma_read_callback(int which, offs_t offset);
r7366r7367
108134};
109135
110136/*
111    Convert physical sector address to sector offset in disk image
112*/
113static UINT64 ti99_translate_offset(floppy_image *floppy, const struct basicdsk_geometry *geom, int track, int head, int sector)
114{
115   UINT64 reply;
116
117#if 0
118   /* old MESS format */
119   reply = ((track*geom->heads) + head)*geom->sectors + sector;
120#else
121   /* V9T9 format */
122   if (head & 1)
123      /* on side 1, tracks are stored in the reverse order */
124      reply = ((head*geom->tracks) + (geom->tracks-1 - track))*geom->sectors + sector;
125   else
126      reply = ((head*geom->tracks) + track)*geom->sectors + sector;
127#endif
128
129   return reply;
130}
131
132/*
133    support for 48TPI disks in 96TPI drives
134*/
135static int ti99_tracktranslate(running_device *image, floppy_image *floppy, int physical_track)
136{
137   struct ti99_geometry *geometry;
138   geometry = (ti99_geometry *)floppy_tag(floppy);
139
140   if (use_80_track_drives && (geometry->tracksperside <= 40))
141      return physical_track/2;
142   else
143      return physical_track;
144}
145
146/*
147    Sniff the geometry of a v9t9 format disk image
148*/
149static void ti99_guess_geometry(floppy_image *floppy, ti99_geometry *geometry, int *vote, int *success)
150{
151   typedef struct ti99_vib
152   {
153      char   name[10];         /* volume name (10 characters, pad with spaces) */
154      UINT8   totsecsMSB;         /* disk length in sectors (big-endian) (usually 360, 720 or 1440) */
155      UINT8   totsecsLSB;
156      UINT8   secspertrack;      /* sectors per track (usually 9 (FM) or 18 (MFM)) */
157      UINT8   id[3];            /* 'DSK' */
158      UINT8   protection;         /* 'P' if disk is protected, ' ' otherwise. */
159      UINT8   tracksperside;      /* tracks per side (usually 40) */
160      UINT8   sides;            /* sides (1 or 2) */
161      UINT8   density;         /* 1 (FM) or 2 (MFM) */
162      UINT8   res[36];         /* reserved */
163      UINT8   abm[200];         /* allocation bitmap: a 1 for each sector in use (sector 0 is LSBit of byte 0, sector 7 is MSBit of byte 0, sector 8 is LSBit of byte 1, etc.) */
164   } ti99_vib;
165
166   ti99_vib vib;
167   int totsecs;
168
169
170   /* Read sector 0 to identify format */
171   /*if (floppy_image_read(floppy, & vib, 0, sizeof(vib)))*/
172   floppy_image_read(floppy, & vib, 0, sizeof(vib));
173   {
174      /* If we have read the sector successfully, let us parse it */
175      totsecs = (vib.totsecsMSB << 8) | vib.totsecsLSB;
176      geometry->secspertrack = vib.secspertrack;
177      if (geometry->secspertrack == 0)
178         /* Some images might be like this, because the original SSSD TI
179            controller always assumes 9. */
180         geometry->secspertrack = 9;
181      geometry->tracksperside = vib.tracksperside;
182      if (geometry->tracksperside == 0)
183         /* Some images are like this, because the original SSSD TI
184            controller always assumes 40. */
185         geometry->tracksperside = 40;
186      geometry->sides = vib.sides;
187      if (geometry->sides == 0)
188         /* Some images are like this, because the original SSSD TI
189            controller always assumes that tracks beyond 40 are on side 2. */
190         geometry->sides = totsecs / (geometry->secspertrack * geometry->tracksperside);
191      geometry->density = vib.density;
192      if (geometry->density == 0)
193         geometry->density = 1;
194      /* check that the format makes sense */
195      if (((geometry->secspertrack * geometry->tracksperside * geometry->sides) == totsecs)
196         && (geometry->density <= 3) && (totsecs >= 2) && (! memcmp(vib.id, "DSK", 3))
197         && (floppy_image_size(floppy) == totsecs*256))
198      {
199         /* validate geometry */
200         if (vote)
201            *vote = 100;
202         if (success)
203            *success = TRUE;
204         return;
205      }
206   }
207
208   /* If we have been unable to parse the format, let us guess according to
209    file lenght */
210   switch (floppy_image_size(floppy))
211   {
212   case 1*40*9*256:   /* 90kbytes: SSSD */
213   case 0:
214   /*default:*/
215      geometry->sides = 1;
216      geometry->tracksperside = 40;
217      geometry->secspertrack = 9;
218      geometry->density = 1;
219      if (vote)
220         *vote = 50;
221      if (success)
222         *success = TRUE;
223      return;
224
225   case 2*40*9*256:   /* 180kbytes: either DSSD or 18-sector-per-track
226                        SSDD.  We assume DSSD since DSSD is more common
227                        and is supported by the original TI SD disk
228                        controller. */
229      geometry->sides = 2;
230      geometry->tracksperside = 40;
231      geometry->secspertrack = 9;
232      geometry->density = 1;
233      if (vote)
234         *vote = 50;
235      if (success)
236         *success = TRUE;
237      return;
238
239   case 1*40*16*256:   /* 160kbytes: 16-sector-per-track SSDD (standard
240                        format for TI DD disk controller prototype, and
241                        the TI hexbus disk controller???) */
242      geometry->sides = 1;
243      geometry->tracksperside = 40;
244      geometry->secspertrack = 16;
245      geometry->density = 2;
246      if (vote)
247         *vote = 50;
248      if (success)
249         *success = TRUE;
250      return;
251
252   case 2*40*16*256:   /* 320kbytes: 16-sector-per-track DSDD (standard
253                        format for TI DD disk controller prototype, and
254                        TI hexbus disk controller???) */
255      geometry->sides = 2;
256      geometry->tracksperside = 40;
257      geometry->secspertrack = 16;
258      geometry->density = 2;
259      if (vote)
260         *vote = 50;
261      if (success)
262         *success = TRUE;
263      return;
264
265   case 2*40*18*256:   /* 360kbytes: 18-sector-per-track DSDD (standard
266                        format for most third-party DD disk controllers,
267                        but reportedly not supported by the original TI
268                        DD disk controller) */
269      geometry->sides = 2;
270      geometry->tracksperside = 40;
271      geometry->secspertrack = 18;
272      geometry->density = 2;
273      if (vote)
274         *vote = 50;
275      if (success)
276         *success = TRUE;
277      return;
278
279   case 2*80*18*256:   /* 720kbytes: 18-sector-per-track 80-track DSDD
280                        (Myarc only) */
281      geometry->sides = 2;
282      geometry->tracksperside = 80;
283      geometry->secspertrack = 18;
284      geometry->density = 2;
285      if (vote)
286         *vote = 50;
287      if (success)
288         *success = TRUE;
289      return;
290
291   case 2*80*36*256:   /* 1.44Mbytes: DSHD (Myarc only) */
292      geometry->sides = 2;
293      geometry->tracksperside = 80;
294      geometry->secspertrack = 36;
295      geometry->density = 3;
296      if (vote)
297         *vote = 50;
298      if (success)
299         *success = TRUE;
300      return;
301
302   default:
303      logerror("%s:%d: unrecognized disk image geometry\n", __FILE__, __LINE__);
304      break;
305   }
306   if (vote)
307      *vote = 0;
308   if (success)
309      *success = FALSE;
310}
311
312static FLOPPY_IDENTIFY(ti99_floppy_identify)
313{
314   ti99_geometry dummy_geom;
315
316   ti99_guess_geometry(floppy, &dummy_geom, vote, NULL);
317
318   return FLOPPY_ERROR_SUCCESS;
319}
320
321static FLOPPY_CONSTRUCT(ti99_floppy_construct)
322{
323   struct ti99_geometry *geometry1;
324   struct basicdsk_geometry geometry2;
325   int success;
326   floperr_t err;
327
328   geometry1 = (ti99_geometry *)floppy_create_tag(floppy, sizeof(*geometry1));
329
330   ti99_guess_geometry(floppy, geometry1, NULL, &success);
331   if (! success)
332      return FLOPPY_ERROR_INVALIDIMAGE;
333
334   memset(&geometry2, 0, sizeof(geometry2));
335   geometry2.heads = geometry1->sides;
336   geometry2.tracks = geometry1->tracksperside;
337   geometry2.sectors = geometry1->secspertrack;
338   geometry2.sector_length = 256;
339   geometry2.translate_sector = NULL;
340   geometry2.translate_offset = ti99_translate_offset;
341
342   err = basicdsk_construct(floppy, &geometry2);
343   if (err)
344      return err;
345
346   return FLOPPY_ERROR_SUCCESS;
347}
348
349FLOPPY_OPTIONS_START( ti99 )
350   FLOPPY_OPTION( ti99, "dsk",   "TI99 disk image",   ti99_floppy_identify,   ti99_floppy_construct, NULL)
351FLOPPY_OPTIONS_END
352
353static void ti99_install_tracktranslate_procs(running_machine *machine)
354{
355   int id;
356   running_device *image;
357
358   for (id=0; id<MAX_FLOPPIES; id++)
359   {
360      image = floppy_get_device(machine, id);
361      floppy_install_tracktranslate_proc(image, ti99_tracktranslate);
362   }
363}
364
365/*
366137    callback called whenever DRQ/IRQ state change
367138*/
368139static WRITE_LINE_DEVICE_HANDLER( ti99_fdc_intrq_w )
r7366r7367
410181   /* initialize the controller chip for HFDC */
411182   smc92x4_init(0, & hfdc_intf);
412183
413   ti99_install_tracktranslate_procs(machine);
414
415184   motor_on_timer = timer_alloc(machine, motor_on_timer_callback, NULL);
416185}
417186
r7366r7367
452221   DVENA = 0;
453222   motor_on = 0;
454223
224   set_all_geometries(machine, FLOPPY_DRIVE_DS_40);
455225   use_80_track_drives = FALSE;
456226
457227   ti99_peb_set_card_handlers(0x1100, & fdc_handlers);
r7366r7367
664434   DVENA = 0;
665435   motor_on = 0;
666436
437   set_all_geometries(machine, FLOPPY_DRIVE_DS_40);
667438   use_80_track_drives = FALSE;
668439
669440   ti99_peb_set_card_handlers(0x1100, & ccfdc_handlers);
r7366r7367
884655   DVENA = 0;
885656   motor_on = 0;
886657
658   set_all_geometries(machine, FLOPPY_DRIVE_DS_40);
887659        use_80_track_drives = FALSE;
888660
889661   ti99_peb_set_card_handlers(0x1100, & bwg_handlers);
r7366r7367
12641036
12651037   ti99_peb_set_card_handlers(0x1100, & hfdc_handlers);
12661038
1039   set_all_geometries(machine, FLOPPY_DRIVE_DS_80);
12671040   use_80_track_drives = TRUE;
12681041
12691042   smc92x4_reset(0);
src/mess/machine/99_dsk.h
r7366r7367
44#include "machine/wd17xx.h"
55#include "formats/flopimg.h"
66
7FLOPPY_OPTIONS_EXTERN(ti99);
7/* Note: this currently mirrors the flag in ti99_4x.h */
8#define HAS_99CCFDC 0
89
910void ti99_floppy_controllers_init_all(running_machine *machine);
1011void ti99_fdc_reset(running_machine *machine);
r7366r7367
1415void ti99_bwg_reset(running_machine *machine);
1516void ti99_hfdc_reset(running_machine *machine);
1617
18int ti99_image_in_80_track_drive(void);
19
1720extern const wd17xx_interface ti99_wd17xx_interface;
1821#endif /* TI99_DSK_H_ */
src/mess/machine/wd17xx.c
r7366r7367
134134#include "machine/wd17xx.h"
135135#include "devices/flopdrv.h"
136136
137#include "formats/flopimg.h"
137138
138139/***************************************************************************
139140    CONSTANTS
r7366r7367
298299
299300   int stepping_rate[4];  /* track stepping rate in ms */
300301
302        unsigned short  crc;    /* Holds the current CRC value for write_track CRC calculation */
303        int     crc_active;   /* Flag indicating that CRC calculation in write_track is active. */
304
301305   UINT8   track_reg;            /* value of track register */
302306   UINT8   command_type;         /* last command type */
303307   UINT8   head;               /* current head # */
r7366r7367
525529   wd17xx_set_busy(device, ATTOTIME_IN_USEC(100));
526530}
527531
532/*
533        Gets the size in bytes of the current track. For real hardware this
534   may vary per system in small degree, and there even for each track
535   and head, so we should not assume a fixed value here.
536   As we are using a buffered track writing, we have to find out how long
537   the track will become. The only object which can tell us is the
538   selected format.
539*/
540static int get_track_size(wd1770_state *w)
541{
542        int size = 0;
543        floppy_image *floppy = flopimg_get_image(w->drive);
544        if (floppy != NULL)
545        {
546                const struct FloppyCallbacks *fmt = floppy_callbacks(floppy);
547                if (fmt != NULL)
548                {
549                        size = fmt->get_track_size(floppy, w->hd, w->track);
550                }
551        }
552        return size;
553}
528554
529555/*
530    Write an entire track. Formats which do not define a write_track
531    function pointer will cause a silent return.
556   Write an entire track. Formats which do not define a write_track
557   function pointer will cause a silent return.
558   What is written to the image depends on the selected format. Sector
559   dumps have to extract the sectors in the track, while track dumps
560   may directly write the bytes.
561   (The if-part below may thus be removed.)
532562*/
533563static void write_track(running_device *device)
534564{
r7366r7367
555585   }
556586#endif
557587
558   if (device->type == WD1771)
559      w->data_count = TRKSIZE_SD;
560   else
561      w->data_count = wd17xx_dden(device) ? TRKSIZE_SD : TRKSIZE_DD;
588   /* Determine the track size. We cannot allow different sizes in this
589      design. */
590        w->data_count = get_track_size(w);
562591
592        if (w->data_count==0)
593        {
594                if (device->type == WD1771)
595                        w->data_count = TRKSIZE_SD;
596                else
597         w->data_count = wd17xx_dden(device) ? TRKSIZE_SD : TRKSIZE_DD;
598        }
599
563600   floppy_drive_write_track_data_info_buffer( w->drive, w->hd, (char *)w->buffer, &(w->data_count) );
564601
565602   w->data_offset = 0;
r7366r7367
569606   w->busy_count = 0;
570607}
571608
572
573/* read an entire track */
609/*
610   Read an entire track. It is up to the format to deliver the data. Sector
611   dumps may be required to fantasize the missing track bytes, while track
612   dumps can directly deliver them.
613   (The if-part below may thus be removed.)
614*/
574615static void read_track(running_device *device)
575616{
576617   wd1770_state *w = get_safe_token(device);
r7366r7367
692733      }
693734   }
694735#endif
736   /* Determine the track size. We cannot allow different sizes in this
737      design. */
738        w->data_count = get_track_size(w);
695739
696   if (device->type == WD1771)
697      w->data_count = TRKSIZE_SD;
698   else
699      w->data_count = wd17xx_dden(device) ? TRKSIZE_SD : TRKSIZE_DD;
740        if (w->data_count==0)
741        {
742                if (device->type == WD1771)
743                        w->data_count = TRKSIZE_SD;
744                else
745         w->data_count = wd17xx_dden(device) ? TRKSIZE_SD : TRKSIZE_DD;
746        }
700747
701748   floppy_drive_read_track_data_info_buffer( w->drive, w->hd, (char *)w->buffer, &(w->data_count) );
702749
r7366r7367
17251772WRITE8_DEVICE_HANDLER( wd17xx_data_w )
17261773{
17271774   wd1770_state *w = get_safe_token(device);
1728
1775   
17291776   if (w->data_count > 0)
17301777   {
17311778      wd17xx_clear_drq(device);
1732
1779     
17331780      /* put byte into buffer */
17341781      if (VERBOSE_DATA)
17351782         logerror("wd17xx_info buffered data: $%02X at offset %d.\n", data, w->data_offset);
1736
1783     
17371784      w->buffer[w->data_offset++] = data;
1738
1739      if (--w->data_count < 1)
1740      {
1741         if (w->command == FDC_WRITE_TRK)
1742            write_track(device);
1743         else
1744            wd17xx_write_sector(device);
1745
1746         w->data_offset = 0;
1747
1748
1749         /* Check we should handle the next sector for a multi record write */
1750         if ( w->command_type == TYPE_II && w->command == FDC_WRITE_SEC && ( w->write_cmd & 0x10 ) )
1751            {
1752            w->sector++;
1753            if (wd17xx_locate_sector(device))
1754            {
1755               w->data_count = w->sector_length;
1756
1757               w->status |= STA_2_BUSY;
1758               w->busy_count = 0;
1759
1760               wd17xx_timed_data_request(device);
1761            }
1762            }
1763            else
1764            {
1765                wd17xx_complete_command(device, DELAY_DATADONE);
1766                if (VERBOSE)
1767               logerror("wd17xx_data_w(): multi data write completed\n");
1768            }
1769        }
1770      else
1771      {
1772         /* yes... setup a timed data request */
1773         wd17xx_timed_data_request(device);
1774      }
1775
1776   }
1785     
1786                if (--w->data_count < 1)
1787                {
1788                        if (w->command == FDC_WRITE_TRK)
1789                                write_track(device);
1790                        else
1791                                wd17xx_write_sector(device);
1792         
1793                        w->data_offset = 0;
1794         
1795                        wd17xx_complete_command(device, DELAY_DATADONE);
1796                }
1797                else
1798                {
1799                        if (w->command == FDC_WRITE_TRK)
1800                        {
1801                                /* Process special data values according to WD17xx specification.
1802               Note that as CRC values take up two bytes which are written on
1803               every 0xf7 byte, this will cause the actual image to
1804               grow larger than what was written from the system. So we need
1805               to take the value of data_offset when writing the track.
1806                                */
1807                                if (!wd17xx_dden(device))
1808                                {
1809                                        switch (data)
1810                                        {
1811                                        case 0xf5:
1812                                        case 0xf6:
1813                                                /* not allowed in FM. */
1814                                                /* Take back the last write. */
1815                                                w->data_offset--;
1816                                                break;
1817                                        case 0xf7:
1818                                                /* Take back the last write. */
1819                                                w->data_offset--;
1820                                                /* write two crc bytes */
1821                                                w->buffer[w->data_offset++] = (w->crc>>8)&0xff;
1822                                                w->buffer[w->data_offset++] = (w->crc&0xff);
1823                                                w->crc_active = FALSE;
1824                                                break;
1825                                        case 0xf8:
1826                                        case 0xf9:
1827                                        case 0xfa:
1828                                        case 0xfb:
1829                                        case 0xfe:
1830                                                /* Preset crc */
1831                                                w->crc = 0xffff;
1832                  /* AM is included in the CRC */
1833                  w->crc = ccitt_crc16_one(w->crc, data);
1834                                                w->crc_active = TRUE;
1835                                                break;
1836                                        case 0xfc:
1837                                                /* Write index mark. No effect here as we do not store clock patterns.
1838                     Maybe later. */
1839                                                break;
1840                                        case 0xfd:
1841                                                /* Just write, don't use for CRC. */
1842                                                break;
1843                                        default:
1844                                                /* Byte already written. */
1845                                                if (w->crc_active)
1846                                                        w->crc = ccitt_crc16_one(w->crc, data);
1847                                        }
1848                                }
1849                                else  /* MFM */
1850                                {
1851                                        switch (data)
1852                                        {
1853                                        case 0xf5:
1854                                                /* Take back the last write. */
1855                                                w->data_offset--;
1856                                                /* Write a1 */
1857                                                w->buffer[w->data_offset++] = 0xa1;
1858                                                /* Preset CRC */
1859                                                w->crc = 0xffff;
1860                                                w->crc_active = TRUE;
1861                                                break;
1862                                        case 0xf6:
1863                                                /* Take back the last write. */
1864                                                w->data_offset--;
1865                                                /* Write c2 */
1866                                                w->buffer[w->data_offset++] = 0xc2;
1867                                                break;
1868                                        case 0xf7:
1869                                                /* Take back the last write. */
1870                                                w->data_offset--;
1871                                                /* write two crc bytes */
1872                                                w->buffer[w->data_offset++] = (w->crc>>8)&0xff;
1873                                                w->buffer[w->data_offset++] = (w->crc&0xff);
1874                                                w->crc_active = FALSE;
1875                                                break;
1876                                        case 0xf8:
1877                                        case 0xf9:
1878                                        case 0xfa:
1879                                        case 0xfb:
1880                                        case 0xfc:
1881                                        case 0xfd:
1882                                                /* Just write, don't use for CRC. */
1883                                                break;
1884                                        case 0xfe:
1885                  /* AM is included in the CRC */
1886                  if (w->crc_active)
1887                     w->crc = ccitt_crc16_one(w->crc, data);
1888                                                break;
1889                                        default:
1890                                                /* Byte already written. */
1891                                                if (w->crc_active)
1892                                                        w->crc = ccitt_crc16_one(w->crc, data);
1893                                        }
1894                                }
1895                        }
1896                        /* yes... setup a timed data request */
1897                        wd17xx_timed_data_request(device);
1898                }
1899   }     
17771900   else
17781901   {
17791902      if (VERBOSE)
src/mess/formats/ti99_dsk.c
r0r7367
1/*********************************************************************
2 *
3 * formats/ti99_dsk.c
4 *
5 * TI99 and Geneve disk images
6 * Sector Dump and Track Dump format
7 *
8 * used by TI-99/4, TI-99/4A, TI-99/8, TI-99/4P, and Geneve
9 *
10 * The Sector Dump Format is also known as v9t9 (named after the first TI
11 * emulator to use this format). It is a contiguous sequence of sector contents
12 * without track data. The first sector of the disk is located at the start of
13 * the image, while the last sector is at its end.
14 *
15 * The Track Dump Format is also known as pc99 (again, named after the first
16 * TI emulator to use this format). It is a contiguous sequence of track
17 * contents, containing all information including address marks and CRC, but it
18 * does not contain clock signals. Therefore, the format requires that the
19 * address marks be at the same positions within each track.
20 *
21 * Both formats allow for a broad range of medium sizes. All sectors are 256
22 * bytes long. The most common formats are 9 sectors per track, single-sided,
23 * 40 tracks, which yields 90 KiB of sector data (known as SSSD), and 18
24 * sectors per track, double-sided, and 40 tracks, which is 360 KiB (known as
25 * DSDD). There are rare occurances of 8/16 sectors/track
26 * (prototypical TI double-density controller) and 35 track media. Newer
27 * controllers and ROMs allow for up to 36 sectors per track and 80 tracks on
28 * both sides, which is 2,88 MiB (DSHD80).
29 *
30 * Different to earlier implementations, these format implementations provide
31 * full track read/write capabilities. For the SDF format, the missing track
32 * information is recreated, and a common interleave is assumed.   
33 *
34 * Note that in principle, writing tracks may change track sizes.
35 * As neither one of the formats contains meta-information about track lengths,
36 * and as the image consists of a contiguous sequence of the tracks, we
37 * cannot allow different track sizes currently. Accordingly, the track size
38 * cannot be changed after the image has been created by imgtool.
39 * Hence, also sector count per tracks and recording type (FM or MFM) cannot be
40 * changed without breaking the image.
41 * For example, MFM disks with 18 sectors per track can only be reformatted to
42 * MFM/18. Moreover, while this could be handled in a future revision,
43 * the number of tracks should also remain unchanged.
44 *
45 * You can use blank image files (filled with zeros or arbitrary data) and use
46 * the Disk Manager cartridge to properly format them. Also, this can be done
47 * by imgtool. The image file must match the format length (representing the
48 * space on the physical medium).
49 *
50 * 80 track drive handling
51 *
52 * For the TI system there may be a situation where 40 track disks are used
53 * in 80 track drives. In these cases, the disk driver applies double-stepping,
54 * that is, it advances the head twice in order to seek the next track. We
55 * emulate this by dividing the track number by 2, which means that two tracks
56 * are mapped to one (0,1 -> 0; 2,3 -> 1; 4,5 -> 2; ...; 78,79 -> 39)
57 *
58 * Technical detail: The size of the track must be given before actually
59 * starting write_track as the controller implementation uses buffered
60 * transfer.
61 *
62 * Michael Zapf, Feb 2010
63 *
64 * TODO: Link to imgtool. imgtool still uses its own format creation
65 *
66 * TODO: Test with diverse disks, inserted at the start and in the meantime
67 *       Check delay
68 *
69 ********************************************************************/
70
71#include <string.h>
72#include <assert.h>
73#include <time.h>
74
75#include "osdepend.h"
76#include "formats/ti99_dsk.h"
77#include "utils.h"
78
79/*
80   The flag for 80-track drives is set in the controller, so we need to
81   include it here.
82*/
83#include "machine/99_dsk.h"   
84
85#define SECTOR_SIZE 256
86#define TI99_IDAM_LENGTH 7
87
88struct ti99dsk_geometry
89{
90   UINT8 sides;
91   UINT8 tracksperside;
92   UINT8 secspertrack;
93   UINT8 density;
94};
95
96struct ti99dsk_tag
97{
98   int heads;
99   int tracks;
100   int sectors;
101   int track_size;  /* Complete track; to be calculated */
102   int format;
103   int first_idam;
104   int dam_offset;
105};
106
107#define TI99_DSK_TAG   "ti99dsktag"
108
109#if 0
110static void dump_contents(UINT8 *buffer, int length)
111{
112        for (int i=0; i < length; i+=16)
113        {
114                for (int j=0; j < 16; j+=2)
115                {
116                        printf("%02x%02x ", buffer[i+j], buffer[i+j+1]);
117                }
118                printf("\n");
119        }
120}
121#endif
122
123#define TI99DSK_BLOCKNOTFOUND -1
124
125/*
126   Searches a block containing number * byte, starting at the given
127   position. Returns the position of the first byte of the block.
128*/
129static int find_block(const UINT8 *buffer, int start, int stop, UINT8 byte, size_t number)
130{
131   int i = start;
132   size_t current = number;
133   while (i < stop && current > 0)
134   {
135      if (buffer[i++] != byte)
136      {
137         current = number;
138      }
139      else
140      {
141         current--;
142      }
143   }
144   if (current==0)
145   {
146      return i - number;
147   }
148   else
149      return TI99DSK_BLOCKNOTFOUND;
150}
151
152/*
153   Queried by flopdrv. Instead of the image tracks, we return the tracks
154   of the floppy drive. We assume we always have two heads.
155*/
156static int ti99_get_heads_per_disk(floppy_image *floppy)
157{
158/*   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
159   return tag->heads; */
160   return 2;
161}
162
163/*
164   Queried by flopdrv. Instead of the image tracks, we return the tracks
165   of the floppy drive.
166*/
167static int ti99_get_tracks_per_disk(floppy_image *floppy)
168{
169   int drivetracks = 42;
170   
171   /* This may fail on startup; therefore we use a special function in
172      99_dsk to explicitly set the geometry. */
173   if (ti99_image_in_80_track_drive())
174   {
175      drivetracks = 83;
176   }
177   return drivetracks;
178}
179
180static floperr_t ti99_get_sector_length(floppy_image *floppy, int head, int track, int sector, UINT32 *sector_length)
181{
182   *sector_length=SECTOR_SIZE;
183   return FLOPPY_ERROR_SUCCESS;
184}
185
186/*
187   Return the track size. We do not allow different track
188   sizes, so we store the track size in the tag.
189*/
190static UINT32 ti99_get_track_size(floppy_image *floppy, int head, int track)
191{
192   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
193   return tag->track_size;   
194}
195
196/*
197static void create_vib(UINT8 *sector0, option_resolution *params)
198{
199   const char *name = "UNNAMED   ";
200   int sides, tracksperside,secspertrack,totalsectors,ausize,allocbytes,i;
201   
202   enum { NAME=0, TOTALSECS=10, SECSPERTRACK=11, SIG=12, PROT=16, TRACKS=17, SIDES=18, DENSITY=19, EXT=20, ALLOC=56 };
203
204   sides      = option_resolution_lookup_int(params, PARAM_HEADS);
205   tracksperside   = option_resolution_lookup_int(params, PARAM_TRACKS);
206   secspertrack   = option_resolution_lookup_int(params, PARAM_SECTORS);
207   
208   totalsectors = sides * tracksperside * secspertrack;
209   
210   memcpy(&sector0[NAME], name, 10);
211   
212   sector0[TOTALSECS] = (totalsectors>>8)&0xff;
213   sector0[TOTALSECS+1] = (totalsectors&0xff);
214   
215   sector0[SECSPERTRACK] = secspertrack;
216   sector0[SIG] = 'D';
217   sector0[SIG+1] = 'S';
218   sector0[SIG+2] = 'K';
219   
220   sector0[PROT] = ' ';
221   sector0[TRACKS] = tracksperside;
222   sector0[SIDES] = sides;
223   sector0[DENSITY] = (secspertrack<10)? 0x01 : 0x02;
224   
225   for (i=EXT; i < ALLOC; i++)
226      sector0[i] = 0;
227   
228   ausize = (totalsectors / 1441) + 1;
229   
230   allocbytes = totalsectors / ausize / 8;
231   
232   for (i=ALLOC; i < ALLOC+allocbytes; i++)
233      sector0[i] = 0;
234   
235   while (i++ < SECTOR_SIZE)
236      sector0[i] = 0xff;
237}
238*/
239/* =========================================================================
240             Sector dump format
241   =========================================================================*/
242
243static floperr_t ti99_sdf_read_sector(floppy_image *floppy, int head, int track, int sector, void *buffer, size_t buflen);
244static floperr_t ti99_sdf_write_sector(floppy_image *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam);
245 
246/* -----------------------------------------------------------------------
247 * Guess the geometry of the sector dump disk.
248 *
249 * Sector size is always 256 bytes.
250 *
251 * Common formats:
252 * 90 KiB = 40 tracks / 1 side / 9 sectors = SSSD
253 * 180 KiB = 40 tracks / 2 side / 9 sectors = DSSD (most common)
254 *         = 40 tracks / 1 side / 18 sectors = SSDD (rare)
255 *         = 80 tracks / 1 side / 9 sectors = SSSD80 (rare)
256 * 360 KiB = 40 tracks / 2 side / 18 sectors = DSDD (most common)
257 *         = 80 tracks / 2 side / 9 sectors = DSSD80 (rare)
258 *         = 80 tracks / 1 side / 18 sectors = SSDD80 (rare)
259 *         = 40 tracks / 1 side / 36 sectors = SSHD (rare)
260 * 720 KiB = 80 tracks / 2 side / 18 sectors = DSDD80 (most common)
261 * 1440 KiB= 80 tracks / 2 side / 36 sectors = DSHD80 (most common)
262 *
263 * Moreover, there may be formats with 35 tracks (ancient) and 8 sectors/track.
264 * We only check for the 8 sector formats.
265 * 160 KiB = 40 tracks / 1 side / 16 sectors = SSDD8
266 * 320 KiB = 40 tracks / 2 side / 16 sectors = DSDD8
267 *
268 * The Volume Information Block may contain suitable information, but not
269 * before the disk is formatted and initialized.
270 *
271 * returns 100 if recognized, 0 if not recognized
272 * ----------------------------------------------------------------------- */
273
274static int ti99_sdf_guess_geometry(floppy_image *floppy, UINT64 size,
275   struct ti99dsk_geometry *geometry)
276{
277   int totsecs;
278   typedef struct ti99_vib
279   {
280      char   name[10];      /* volume name (10 characters, pad with spaces) */
281      UINT8   totsecsMSB;      /* disk length in sectors (big-endian) (usually 360, 720 or 1440) */
282      UINT8   totsecsLSB;
283      UINT8   secspertrack;      /* sectors per track (usually 9 (FM) or 18 (MFM)) */
284      UINT8   id[3];         /* String "DSK" */
285      UINT8   protection;      /* 'P' if disk is protected, ' ' otherwise. */
286      UINT8   tracksperside;      /* tracks per side (usually 40) */
287      UINT8   sides;         /* sides (1 or 2) */
288      UINT8   density;      /* 0,1 (FM) or 2,3,4 (MFM) */
289      UINT8   res[36];      /* Empty for traditional disks, or up to 3 directory pointers */
290      UINT8   abm[200];      /* allocation bitmap: a 1 for each sector in use (sector 0 is LSBit of byte 0, sector 7 is MSBit of byte 0, sector 8 is LSBit of byte 1, etc.) */
291   } ti99_vib;
292
293   ti99_vib vib;
294   UINT32 file_size;
295   struct ti99dsk_geometry dummy_geometry;
296   
297   if (geometry)
298      memset(geometry, 0, sizeof(*geometry));
299   else
300      geometry = &dummy_geometry;
301   
302   if (size > 0xFFFFFFFF)
303      return 0;
304
305   file_size = (UINT32) size;
306
307   /* Read the Volume Information Block */
308   floppy_image_read(floppy, &vib, 0, sizeof(vib));
309   
310   /* If we have read the sector successfully, let us parse it */
311   totsecs = (vib.totsecsMSB << 8) | vib.totsecsLSB;
312   geometry->secspertrack = vib.secspertrack;
313   if (geometry->secspertrack == 0)
314      /* Some images might be like this, because the original SSSD TI controller always assumes 9. */
315      geometry->secspertrack = 9;
316   geometry->tracksperside = vib.tracksperside;
317   if (geometry->tracksperside == 0)
318      /* Some images are like this, because the original SSSD TI controller always assumes 40. */
319      geometry->tracksperside = 40;
320   geometry->sides = vib.sides;
321   if (geometry->sides == 0)
322      /* Some images are like this, because the original SSSD TI controller always assumes that tracks beyond 40 are on side 2. */
323      geometry->sides = totsecs / (geometry->secspertrack * geometry->tracksperside);
324   geometry->density = vib.density;
325   /* check that the format makes sense */
326   if (((geometry->secspertrack * geometry->tracksperside * geometry->sides) == totsecs)
327      && (geometry->density <= 4) && (totsecs >= 2) && (! memcmp(vib.id, "DSK", 3))
328      && (file_size == totsecs*256))
329   {
330      logerror("SDF/VIB consistent; tracks = %d, heads = %d, sectors = %d\n", geometry->tracksperside, geometry->sides, geometry->secspertrack);
331      return 100;
332   }
333   logerror("SDF/VIB not consistent; guessing format\n");
334
335   /* So that was not consistent. We guess the size from the file size
336      and assume that the VIB did not contain reliable data. For the
337      ambiguous case we choose the most common format.
338   */
339   switch (file_size)
340   {
341   case 1*40*9*256:   
342      /* 90kbytes: SSSD */
343   case 0:
344   /*default:*/
345      geometry->sides = 1;
346      geometry->tracksperside = 40;
347      geometry->secspertrack = 9;
348      geometry->density = 1;
349      break;
350
351   case 2*40*9*256:
352      /* 180kbytes: either DSSD or 18-sector-per-track SSDD. 
353      We assume DSSD since DSSD is more common and is supported by
354      the original TI SD disk controller. */
355      geometry->sides = 2;
356      geometry->tracksperside = 40;
357      geometry->secspertrack = 9;
358      geometry->density = 1;
359      break;
360
361   case 1*40*16*256:
362      /* 160kbytes: 16-sector-per-track SSDD (standard format for TI
363      DD disk controller prototype, and the TI hexbus disk
364      controller?) */
365      geometry->sides = 1;
366      geometry->tracksperside = 40;
367      geometry->secspertrack = 16;
368      geometry->density = 2;
369      break;
370
371   case 2*40*16*256:
372      /* 320kbytes: 16-sector-per-track DSDD (standard format for TI
373      DD disk controller prototype, and TI hexbus disk
374      controller?) */
375      geometry->sides = 2;
376      geometry->tracksperside = 40;
377      geometry->secspertrack = 16;
378      geometry->density = 2;
379      break;
380
381   case 2*40*18*256:
382      /* 360kbytes: 18-sector-per-track DSDD (standard format for most
383      third-party DD disk controllers, but reportedly not supported by
384      the original TI DD disk controller prototype) */
385      geometry->sides = 2;
386      geometry->tracksperside = 40;
387      geometry->secspertrack = 18;
388      geometry->density = 2;
389      break;
390
391   case 2*80*18*256:
392      /* 720kbytes: 18-sector-per-track 80-track DSDD (Myarc only) */
393      geometry->sides = 2;
394      geometry->tracksperside = 80;
395      geometry->secspertrack = 18;
396      geometry->density = 2;
397      break;
398     
399   case 2*80*36*256:   
400      /* 1.44Mbytes: DSHD (Myarc only) */
401      geometry->sides = 2;
402      geometry->tracksperside = 80;
403      geometry->secspertrack = 36;
404      geometry->density = 3;
405      break;
406
407   default:
408      logerror("Unrecognized disk image geometry\n");
409      return 0;
410   }
411
412   logerror("SDF geometry guess: tracks = %d, heads = %d, sectors = %d\n", geometry->tracksperside, geometry->sides, geometry->secspertrack);
413   return 100;
414}
415
416/*
417   Figure out the interleave for the sector arrangement in the track. For
418   SDF format this is required for the read_track function.
419   
420   Interleave:
421       0 7 5 3 1 8 6 4 2;
422            start with 0, 3, 6, 0, 3, 6, ...
423            0 11 4 15 8 1 12 5 16 9 2 13 6 17 10 3 14 7
424            start with 0 for every track
425         
426   Rare formats: 8 sectors
427      0 3 6 1 4 7 2 5   (i*3)%8
428     
429      16 sectors
430      0 9 2 11 4 13 6 15 8 1 10 3 12 5 14 7  (i*9)%16
431     
432      36 sectors
433      0 11 22 ... 3 14 25 (i*11)%36
434*/
435static void guess_interleave(int sectors, int *step, int *initial)
436{
437   switch (sectors)
438   {
439   case 8:
440      *step = 3;
441      /* initial is the offset from track to track+1 of the starting sector number */
442      *initial = 0;
443      break;
444   case 9:
445      *step = 7;
446      *initial = 3;
447      break;
448   case 16:
449      *step = 9;
450      *initial = 0;
451      break;
452   case 18:
453      *step = 11;
454      *initial = 0;
455      break;
456   case 36:
457      *step = 11;
458      *initial = 0;
459      break;
460   default:
461      *step = 11;
462      *initial = 0;
463      break;
464   }   
465}
466
467/*
468   Delivers a whole track. As the image consists only of
469   sector data, we must reconstruct the track data and
470   then insert the sector data.
471   
472   The track layout is exactly the Track Dump Format, except that the
473   CRC values must be correctly calculated.   
474   
475   Total length (FM)  = 247 + sectors*334; (sectors=8 or 9)
476   Total length (MFM) = 752 + sectors*340; (sectors=16 or 18)
477*/
478static floperr_t ti99_sdf_read_track(floppy_image *floppy, int head, int track, UINT64 offset, void *buffer, size_t buflen)
479{
480   int sector;
481   int startstep;
482   int step;
483   int position=0;   
484   unsigned short crc;
485   int i;
486   floperr_t err;
487   int imgtrack = track;
488   
489   UINT8 *trackdata = (UINT8*)buffer;
490   
491   /* Determine from the image geometry whether we have FM or MFM */
492   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
493   
494   /* Do we have a 40 track disk in an 80 track drive? In that case we
495      double the "width" of the tracks. */
496   if (ti99_image_in_80_track_drive() && tag->tracks<=40)
497   {
498      imgtrack = track / 2;
499   }
500   
501   guess_interleave(tag->sectors, &step, &startstep);
502   
503   if (tag->sectors < 10)  /* must be FM */
504   {
505      /* Write lead-in. */
506      memset(trackdata, 0x00, 16);
507      position += 16;
508      for (i=0; i < tag->sectors; i++)
509      {
510         /* Create interleaving */
511         sector = (i*step + imgtrack*startstep) % tag->sectors;
512
513         memset(&trackdata[position], 0x00, 6);
514         position += 6;
515         /* Set IDAM */
516         trackdata[position++] = 0xfe;
517         trackdata[position++] = imgtrack;
518         trackdata[position++] = head;
519         trackdata[position++] = sector;
520         trackdata[position++] = 0x01;
521         /* Calculate CRC16. Preset to 0xffff (what is 0xcdb4?) */
522         crc = ccitt_crc16(0xffff, &trackdata[position-(TI99_IDAM_LENGTH-2)], TI99_IDAM_LENGTH - 2);
523         trackdata[position++] = (crc>>8)&0xff;
524         trackdata[position++] = crc & 0xff;
525
526         /* Write Gap2 */
527         memset(&trackdata[position], 0xff, 11);
528         position += 11;
529         memset(&trackdata[position], 0x00, 6);
530         position += 6;
531         /* Write DAM */
532         trackdata[position++] = 0xfb;
533         
534         /* Locate the sector content in the image and load it. */
535         err = ti99_sdf_read_sector(floppy, head, imgtrack, sector, &trackdata[position], SECTOR_SIZE);
536         if (err)
537            return err;
538
539         position += SECTOR_SIZE;
540
541         /* Set CRC16 */
542         crc = ccitt_crc16(0xffff, &trackdata[position-(SECTOR_SIZE+1)], SECTOR_SIZE+1);
543         trackdata[position++] = (crc>>8)&0xff;
544         trackdata[position++] = crc & 0xff;
545         
546         /* Write Gap3 */
547         memset(&trackdata[position], 0xff, 45);
548         position += 45;
549      }
550      /* Write lead-out */
551      memset(&trackdata[position], 0xff, 231);
552      position += 231;
553   }
554   else /* we have MFM */
555   {
556      /* Write lead-in. */
557      memset(trackdata, 0x4e, 40);
558      position += 40;
559      for (i=0; i < tag->sectors; i++)
560      {
561         sector = (i*step + imgtrack*startstep) % tag->sectors;
562
563         memset(&trackdata[position], 0x00, 10);
564         position += 10;
565         /* Write sync */
566         memset(&trackdata[position], 0xa1, 3);
567         position += 3;
568         /* Set IDAM */
569         trackdata[position++] = 0xfe;
570         trackdata[position++] = imgtrack;
571         trackdata[position++] = head;
572         trackdata[position++] = sector;
573         trackdata[position++] = 0x01;
574         /* Set CRC16 */
575         crc = ccitt_crc16(0xffff, &trackdata[position-TI99_IDAM_LENGTH+2], TI99_IDAM_LENGTH - 2);
576         trackdata[position++] = (crc>>8)&0xff;
577         trackdata[position++] = crc & 0xff;
578
579         /* Write Gap2 */
580         memset(&trackdata[position], 0x4e, 22);
581         position += 22;
582         memset(&trackdata[position], 0x00, 12);
583         position += 12;
584         /* Write sync */
585         memset(&trackdata[position], 0xa1, 3);
586         position += 3;
587         /* Write DAM */
588         trackdata[position++] = 0xfb;
589         
590         /* Locate the sector content in the image and load it. */
591         err = ti99_sdf_read_sector(floppy, head, track, sector, &trackdata[position], SECTOR_SIZE);
592         if (err)
593            return err;
594
595         position += SECTOR_SIZE;
596
597         /* Set CRC16 */
598         crc = ccitt_crc16(0xffff, &trackdata[position-SECTOR_SIZE-1], SECTOR_SIZE+1);
599         trackdata[position++] = (crc>>8)&0xff;
600         trackdata[position++] = crc & 0xff;
601         
602         /* Write Gap3 */
603         memset(&trackdata[position], 0x4e, 24);
604         position += 24;
605      }
606      /* Write lead-out */
607      memset(&trackdata[position], 0x4e, 712);
608      position += 712;
609   }
610   return FLOPPY_ERROR_SUCCESS;
611}
612
613/*
614   Writes a whole track. As the sector dump format does not include track
615   data, we have to extract the sector contents and to write them
616   in sequence into the image. All the rest (gaps, crc, sync bytes) are
617   dropped here.
618   Bytes written to locations beyond the image end will be droppped
619   silently (as if the medium is unwritable from that point).
620*/
621static floperr_t ti99_sdf_write_track(floppy_image *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buflen)
622{
623   int current_pos = 0;
624   UINT8 *track_image;
625   int leadin, gap1, gap2;
626   int is_fm;
627   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
628   int imgtrack = track;
629   
630   /* Find out if we are going to write an FM or MFM track. Caution: The
631      original TI controller is known to have a bug in the formatting
632      routine (using a MOVB instead of a MOV instruction when setting the
633      pointer to the track data), outputting false bytes at the
634      beginning of the track. So we don't rely on absolute positions
635      (neither does the controller).
636   */
637   track_image = (UINT8*)buffer;
638   
639   if (ti99_image_in_80_track_drive() && tag->tracks<=40)
640   {
641      imgtrack = track / 2;
642   }
643   
644   /* Only search in the first 100 bytes for the start. */
645   leadin = 40;
646   gap1 = 10;
647   gap2 = 12;
648   is_fm = FALSE;
649   
650   current_pos = find_block(track_image, 0, 100, 0x4e, leadin);
651
652   /* In case of defect formats, we continue as far as possible. This
653      may lead to sectors not being written. */
654   if (current_pos==TI99DSK_BLOCKNOTFOUND)
655   {
656      /* Not MFM, possibly FM image */
657      /* Again, find Lead-in */
658      leadin = 16;
659      current_pos = find_block(track_image, 0, 100, 0x00, leadin);
660      if (current_pos==TI99DSK_BLOCKNOTFOUND)
661      {
662         /* If neither, forget about this process completely. */
663         logerror("Cannot find lead-in for track %d, head %d.\n", track, head);
664         return FLOPPY_ERROR_INVALIDIMAGE;
665      }
666      gap1 = 6;
667      gap2 = 6;
668      is_fm = TRUE;
669   }
670
671   /* Get behind lead-in */
672   current_pos += leadin;
673   while (current_pos < buflen)
674   {
675      /* We must find the address block to determine the sector. */
676      int new_pos = find_block(track_image, current_pos, buflen, 0x00, gap1);
677      if (new_pos==TI99DSK_BLOCKNOTFOUND)
678      {
679         /* Forget about the rest. */
680         logerror("Cannot find any address block for track %d, head %d.\n", track, head);
681         return FLOPPY_ERROR_INVALIDIMAGE;
682      }
683      if (!is_fm)
684         new_pos += 3; /* skip sync bytes in MFM */
685         
686      if (track_image[new_pos + gap1]==0xfe)
687      {
688         current_pos = new_pos + gap2  + 1;
689         /* IDAM found. */
690         int wtrack = track_image[current_pos];
691         int whead = track_image[current_pos+1];
692         int sector = track_image[current_pos+2];
693         if (wtrack == imgtrack && whead == head)
694         {
695            /* We skip the first part of gap2. */
696            new_pos = find_block(track_image, current_pos, buflen, 0x00, gap2);
697            if (current_pos==TI99DSK_BLOCKNOTFOUND)
698            {
699               logerror("Cannot find gap2 for track %d, head %d.\n", imgtrack, head);
700               return FLOPPY_ERROR_INVALIDIMAGE;
701            }
702            else
703            {
704               new_pos += gap2;
705               if (!is_fm)
706                  new_pos += 3; /* skip sync */
707               current_pos = new_pos;
708               if (track_image[current_pos]==0xfb)
709               {
710                  /* DAM found. We now write the sector content to the image. */
711                  ti99_sdf_write_sector(floppy, head, track, sector, &track_image[current_pos+1], SECTOR_SIZE, 0);
712                  current_pos += SECTOR_SIZE;
713               }
714               else
715                  logerror("DAM not found. Don't write sector %d\n", sector);
716               /* else not found, ignore this sector. */
717            }
718         }
719         /* else the sector head data do not match the
720            current track and head. Ignore the sector. */
721      }
722      else
723      {
724         /* One step forward. Retry. */
725         current_pos++;
726      }
727   }
728   return FLOPPY_ERROR_SUCCESS;
729}
730
731/*
732   This method creates a properly formatted image.
733   
734   For a proper image, we need to format all tracks, and to create a
735   minimal filesystem:
736   
737   name = "UNNAMED   "
738   number of sectors
739   sectors/track
740   "DSK"
741   protection = 0x00
742   tracks/side
743   sides
744   density (0,1 = FM, 2 = MFM)
745   0x14 - 0x37 : 0x00
746   Allocation bitmap: 0xFF except for the first #sectors/AU size
747   
748   AU size = 1 (360 - 1440 sectors)
749           = 2 (1441 - 2880 sectors)
750      = 4 (2881 - 5760 sectors)
751      = 8 (5760 - 11520 sectors)
752   
753   sector 0 =
754   sector 1 = 256* 0x00   
755*/
756/* static floperr_t ti99_sdf_format_track(floppy_image *floppy, int head, int track, option_resolution *params)
757{
758   UINT8 *sector0 = (UINT8*)malloc(SECTOR_SIZE);
759   create_vib(sector0, params);
760   free(sector0);
761   if (true)
762   {
763      printf("not implemented\n");
764      return FLOPPY_ERROR_SEEKERROR;
765   }
766   return FLOPPY_ERROR_SUCCESS;
767}
768*/
769
770/*
771   Get the offset from the start of the image file. In this format, logical
772   tracks on two-sided disks are arranged as follows (example for 40
773   tracks; accordingly for 35 or 80)
774
775   head-track
776   0-0
777   0-1
778   0-2
779   0-3
780   ...
781   0-39
782   1-39
783   1-38
784   1-37
785   ...
786   1-0
787   Note that we take the imgtrack, which may be half of the drive track.
788*/
789static floperr_t ti99_sdf_get_offset(floppy_image *floppy, int head, int imgtrack, int sector, UINT64 *offset)
790{
791   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
792
793   if ((head < 0) || (head >= tag->heads)
794      || (imgtrack < 0) || (imgtrack >= tag->tracks)
795      || (sector < 0) || (sector > tag->sectors))
796      return FLOPPY_ERROR_SEEKERROR;
797
798   if (head == 0)  /* track numbers increasing towards inner track */
799   {
800      *offset = (imgtrack * tag->sectors + sector) * SECTOR_SIZE;
801   }
802   else      /* track numbers increasing towards outer track */
803   {
804      *offset = (((2*tag->tracks)-1-imgtrack) * tag->sectors + sector) * SECTOR_SIZE;
805   }
806   return FLOPPY_ERROR_SUCCESS;
807}
808
809/*
810   Read one sector at the specified position.
811*/
812static floperr_t ti99_sdf_read_sector(floppy_image *floppy, int head, int track, int sector, void *buffer, size_t buflen)
813{
814   floperr_t err;
815   UINT64 offset;
816   int imgtrack = track;
817   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
818
819   if (ti99_image_in_80_track_drive() && tag->tracks<=40)
820   {
821      imgtrack = track / 2;
822   }
823
824   err = ti99_sdf_get_offset(floppy, head, imgtrack, sector, &offset);
825   if (err)
826   {
827      return err;
828   }
829   floppy_image_read(floppy, buffer, offset, SECTOR_SIZE);
830   
831   return FLOPPY_ERROR_SUCCESS;
832}
833
834/*
835   For the SDF format, sectors are always numbered in ascending order,
836   starting with the lowest numbered sector in each track. In other words,
837   we have nothing to calculate here.
838*/
839static floperr_t ti99_sdf_read_indexed_sector(floppy_image *floppy, int head, int track, int sector, void *buffer, size_t buflen)
840{
841   return ti99_sdf_read_sector(floppy, head, track, sector, buffer, buflen);
842}
843
844/*
845   Write one sector at the specified position.
846*/
847static floperr_t ti99_sdf_write_sector(floppy_image *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam)
848{
849   UINT64 offset;
850   floperr_t err;
851   int imgtrack = track;
852   
853   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
854
855   if (ti99_image_in_80_track_drive() && tag->tracks<=40)
856   {
857      imgtrack = track / 2;
858   }
859
860   err = ti99_sdf_get_offset(floppy, head, imgtrack, sector, &offset);
861   if (err)
862   {
863      return err;
864   }
865   floppy_image_write(floppy, buffer, offset, SECTOR_SIZE);
866   
867   return FLOPPY_ERROR_SUCCESS;
868}
869
870/*
871   See above; indexing and numbering coincide.
872*/
873static floperr_t ti99_sdf_write_indexed_sector(floppy_image *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam)
874{
875   return ti99_sdf_write_sector(floppy, head, track, sector, buffer, buflen, ddam);
876}
877
878/*
879   Required for ReadAddress command
880*/
881static floperr_t ti99_sdf_get_indexed_sector_info(floppy_image *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags)
882{
883   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
884
885   if (ti99_image_in_80_track_drive() && tag->tracks<=40)
886   {
887      track = track / 2;
888   }
889
890   if (sector_length)
891      *sector_length=SECTOR_SIZE;
892   if (cylinder)
893      *cylinder = track;
894   if (side)
895      *side = head;
896   if (sector)
897      *sector = sector_index;
898   if (flags)
899      *flags = 0;
900   if (sector_index > tag->sectors)
901   {
902      return FLOPPY_ERROR_SEEKERROR;
903   }
904   
905   return FLOPPY_ERROR_SUCCESS;
906}
907
908/*
909   Try to identify the image as an SDF format image.
910*/
911static FLOPPY_IDENTIFY(ti99_sdf_identify)
912{
913   UINT64 size;
914   size = floppy_image_size(floppy);
915   *vote = ti99_sdf_guess_geometry(floppy, size, NULL);
916   logerror("SDF voting %d\n", *vote);
917   return FLOPPY_ERROR_SUCCESS;
918}
919
920/*
921   Create the SDF data structures and set the callbacks.
922*/
923static FLOPPY_CONSTRUCT(ti99_sdf_construct)
924{
925   struct ti99dsk_geometry geometry;
926   struct FloppyCallbacks *callbacks;
927   struct ti99dsk_tag *tag;
928   logerror("Reading image as SDF\n");
929   
930   if (params)
931   {
932      /* create */
933      memset(&geometry, 0, sizeof(geometry));
934      geometry.sides            = option_resolution_lookup_int(params, PARAM_HEADS);
935      geometry.tracksperside         = option_resolution_lookup_int(params, PARAM_TRACKS);
936      geometry.secspertrack         = option_resolution_lookup_int(params, PARAM_SECTORS);
937
938      /* We don't have headers for geometry */
939      /* check for usage in imgtool - we want to be able to create useful disks */
940   }
941   else
942   {
943      /* load */
944      if (ti99_sdf_guess_geometry(floppy, floppy_image_size(floppy), &geometry)<50)
945         return FLOPPY_ERROR_INVALIDIMAGE;
946   }
947
948   assert(geometry.sides);
949   assert(geometry.tracksperside);
950   assert(geometry.secspertrack);
951
952   tag = (struct ti99dsk_tag *) floppy_create_tag(floppy, sizeof(struct ti99dsk_tag));
953
954   if (!tag)
955      return FLOPPY_ERROR_OUTOFMEMORY;
956
957   tag->heads = geometry.sides;
958   tag->tracks = geometry.tracksperside;
959   tag->sectors = geometry.secspertrack;
960   if (tag->sectors < 10)
961      /* FM mode */
962      tag->track_size = 16 + tag->sectors*334 + 231;
963   else
964      tag->track_size = 40 + tag->sectors*340 + 712;
965     
966   /* set up format callbacks */
967   callbacks = floppy_callbacks(floppy);
968   callbacks->read_sector = ti99_sdf_read_sector;
969   callbacks->write_sector = ti99_sdf_write_sector;
970   callbacks->read_indexed_sector = ti99_sdf_read_indexed_sector;
971   callbacks->write_indexed_sector = ti99_sdf_write_indexed_sector;
972   callbacks->read_track = ti99_sdf_read_track;
973   callbacks->write_track = ti99_sdf_write_track;
974/*   callbacks->format_track = ti99_sdf_format_track; */
975   callbacks->get_track_size = ti99_get_track_size;
976   /* post format unset */
977   callbacks->get_heads_per_disk = ti99_get_heads_per_disk;
978   callbacks->get_tracks_per_disk = ti99_get_tracks_per_disk;
979   callbacks->get_sector_length = ti99_get_sector_length;   
980   callbacks->get_indexed_sector_info = ti99_sdf_get_indexed_sector_info;
981   
982   return FLOPPY_ERROR_SUCCESS;
983}
984
985/* -----------------------------------------------------------------------
986 * Track Dump Format, aka PC99 format
987 * This format includes all track data, including address marks and gaps.
988 * However, CRC is not stored; instead, a f7f7 is stored at that location.
989 * Two track images exist, one for FM and one for MFM format.
990 *
991 * In this implementation, however, we do calculate the CRC.
992 *
993 * All tracks have exactly the same size, so offsets are calculated easily.
994 *
995 * This format is a precise map of the data contents of the track;
996 * however, it does not store clock patterns.
997 *
998 * The TDF format does not have a special index part, so any sector on it
999 * must be searched (as done by the disk controller)
1000 *
1001 * Interesting detail: The original TI disk controller has a bug which has
1002 * just recently been discovered (using MESS!): The lead-in has another 9
1003 * bytes as a prefix; this is due to a wrongly set pointer in the format
1004 * routine. Strictly speaking, it produces invalid track images.
1005 * The original hardware does not care, however, so neither should we.
1006 * To keep the emulation realistic (and to allow for a
1007 * possible future extension with clock bits), we search for the
1008 * beginning of the track. From there on, however, we accept no further
1009 * deviations. This may make the resulting format unusable with the PC99
1010 * emulator, but it only appears when formatting with the TI disk
1011 * controller anyway. If the image is created with another disk controller or
1012 * using imgtool, the format is correctly created.
1013 *
1014 * FM track image
1015 *
1016 * Lead-in:           16*  00
1017 * Pre-ID gap:         6*  00    ---+
1018 *       IDAM:             fe       |
1019 *      Track:             tt       |
1020 *       Head:             hh       |
1021 *     Sector:             ss       |
1022 *       Size:             01       |
1023 *        CRC:         2*  f7       +--- repeat 9 times (8 rarely)
1024 *       Gap2:        11*  ff       |
1025 *                     6*  00       |
1026 *        DAM:             fb       |
1027 *    Content:       256*  xx       |
1028 *        CRC:         2*  f7       |
1029 *       Gap3:        45*  ff    ---+
1030 * Lead-out:         231*  ff
1031 *
1032 * --------------
1033 *
1034 * MFM track image
1035 *
1036 * Lead-in:           40*  4e
1037 * Pre-ID gap:        10*  00    ---+
1038 *       Sync:         3*  a1       |
1039 *       IDAM:             fe       |
1040 *      Track:             tt       |
1041 *       Head:             hh       |
1042 *     Sector:             ss       |
1043 *       Size:             01       |
1044 *        CRC:         2*  f7       +--- repeat 18 times (16 rarely)
1045 *       Gap2:        22*  4e       |
1046 *                    12*  00       |
1047 *       Sync:         3*  a1       |
1048 *        DAM:             fb       |
1049 *    Content:       256*  xx       |
1050 *        CRC:         2*  f7       |
1051 *       Gap3:        24*  4e    ---+
1052 * Lead-out:         712*  4e
1053 *
1054 * ------------------
1055 * The tracks are located on the image as follows (different to SDF!):
1056 *
1057 *   head-track
1058 *      0-0
1059 *      0-1
1060 *      0-2
1061 *      0-3
1062 *      ...
1063 *      0-39
1064 *      1-0
1065 *      1-1
1066 *      1-2
1067 *      ...
1068 *      1-39
1069 * ----------------------------------------------------------------------- */
1070
1071#define TI99_FM 1
1072#define TI99_MFM 2
1073
1074/* For the emulation of the clock pattern, we add a 9th bit. */
1075#define TI99_DAM 0x1fb
1076#define TI99_IDAM 0x1fe
1077
1078#define TI99_FM_DAM_OFFSET 24
1079#define TI99_MFM_DAM_OFFSET 44
1080
1081#define TI99_FM_TRACK_ADD 247
1082#define TI99_MFM_TRACK_ADD 752
1083
1084#define TI99_FM_TOTAL_SECTOR 334
1085#define TI99_MFM_TOTAL_SECTOR 340
1086
1087/*
1088   Determine offset of the first IDAM. This is the base of the simulation
1089   of the clock bytes. We use a heuristic to guess where the track begins
1090   and simply check whether we can locate the first IDAM and DAM. Return
1091   value is the offset to the first IDAM.
1092*/   
1093static floperr_t determine_offset(int format, UINT8 *track, int *offset)
1094{
1095   floperr_t retval;
1096   int current_pos;
1097
1098   if (format==TI99_FM)
1099   {
1100//      printf("Trying FM\n");
1101      /* We are seeking the lead-in and pre-id gap from
1102      position 0 to position 50. This is just to make sure that
1103      if there are bad bytes at the beginning (original TI controller)
1104      we will skip them.*/
1105      current_pos = find_block(track, 0, 50, 0x00, 22);
1106      if (current_pos==TI99DSK_BLOCKNOTFOUND)
1107      {
1108         logerror("Lead-in not found\n");         
1109         retval = FLOPPY_ERROR_SEEKERROR;
1110      }
1111      else
1112      {
1113         current_pos += 22;
1114         if (track[current_pos]==0xfe /* IDAM */ &&
1115             track[current_pos+4]==0x01 /* sector length, always 256 for TI */ &&
1116                 track[current_pos+24]==0xfb) /* DAM */
1117         {
1118            /* We're pretty sure this is the beginning. */
1119            *offset = current_pos;
1120            retval = FLOPPY_ERROR_SUCCESS;
1121         }
1122         else
1123         {
1124            logerror("IDAM or DAM not found\n");         
1125            retval = FLOPPY_ERROR_SEEKERROR;
1126         }
1127      }
1128   }
1129   else
1130   {
1131      /* MFM */
1132//      printf("Trying MFM\n");
1133      int track_start = find_block(track, 0, 100, 0x4e, 40);
1134      if (track_start==TI99DSK_BLOCKNOTFOUND)
1135      {
1136         logerror("Lead-in not found\n");         
1137         retval = FLOPPY_ERROR_SEEKERROR;
1138      }
1139      else
1140      {
1141         track_start += 40;
1142         current_pos = find_block(track, track_start, track_start+10, 0x00, 10);
1143         if (current_pos==TI99DSK_BLOCKNOTFOUND)
1144         {
1145            logerror("Pre-gap not found\n");         
1146            retval = FLOPPY_ERROR_SEEKERROR;
1147         }
1148         else
1149         {
1150            current_pos += 10;
1151            if (track[current_pos] == 0xa1 /* First sync */ &&
1152                track[current_pos+3] == 0xfe /* IDAM */ &&
1153                track[current_pos+44] == 0xa1 /* First sync */ &&
1154                track[current_pos+47] == 0xfb) /* DAM */
1155            {
1156            /* We're pretty sure this is the beginning. */
1157               *offset = current_pos + 3;
1158               retval = FLOPPY_ERROR_SUCCESS;
1159            }
1160            else
1161            {
1162               logerror("Sync/IDAM/DAM not found\n");         
1163               retval = FLOPPY_ERROR_SEEKERROR;
1164            }
1165         }
1166      }
1167   }
1168/*   printf("TDF offset = 0x%x\n", *offset); */
1169   return retval;         
1170}
1171
1172/*
1173   Gets a byte from the track. In this format we do not have a clock
1174   signal, so we will simulate it. Thus, this function returns a 9-bit
1175   value, with the first bit set as a marker for an address mark.
1176
1177   This may be a little more complicated than necessary, but it correctly
1178   emulates the behavior of the controller (and it allows for an
1179   alternative format which actually supports clock and data).
1180*/
1181static int read_byte(int format, int first_idam, UINT8 *track, int position)
1182{
1183   int totalseclen;
1184   int dam_offset;
1185   int byte;
1186   
1187   /* Check whether we are at any IDAM or DAM in this track. */
1188   if (format==TI99_FM)
1189   {
1190      totalseclen = TI99_FM_TOTAL_SECTOR;
1191      dam_offset = TI99_FM_DAM_OFFSET;
1192   }
1193   else
1194   {
1195      totalseclen = TI99_MFM_TOTAL_SECTOR;
1196      dam_offset = TI99_MFM_DAM_OFFSET;
1197   }
1198
1199   int curpos = (position - first_idam) % totalseclen;
1200   if (curpos==0 && track[position]==0xfe)
1201      byte = TI99_IDAM;
1202   else
1203   {
1204      if (curpos==dam_offset && track[position]==0xfb)
1205         byte = TI99_DAM;
1206      else
1207         byte = track[position] & 0xff;
1208   }
1209   return byte;     
1210}
1211
1212/*
1213   Determine the position of this track in the image.
1214*/
1215static floperr_t ti99_tdf_get_offset(floppy_image *floppy, int head, int imgtrack, UINT64 *offset)
1216{
1217   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
1218
1219   if ((head < 0) || (head >= tag->heads) || (imgtrack < 0) || (imgtrack >= tag->tracks))
1220      return FLOPPY_ERROR_SEEKERROR;
1221
1222   /* For head 0, tracks increase from 0 to tracks-1; then for head 1,
1223      tracks also increase from 0 to tracks-1. */
1224   *offset = head * (tag->tracks * tag->track_size) +  imgtrack * tag->track_size;
1225         
1226   return FLOPPY_ERROR_SUCCESS;
1227}
1228
1229/*
1230   Reads a track. We just copy the contents from the format and recreate
1231   the CRC if it is the "blank" CRC as F7F7.
1232   This method assumes that the track division be done already.
1233*/
1234static floperr_t ti99_tdf_read_track_internal(floppy_image *floppy, int head, int imgtrack, UINT64 offset, void *buffer, size_t buflen)
1235{
1236   floperr_t err;
1237   UINT64 track_offset;
1238   int first_idam = 0;
1239   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
1240   int i, byte, crc;
1241   
1242   UINT8 *track_data = (UINT8*)buffer;
1243   
1244   err = ti99_tdf_get_offset(floppy, head, imgtrack, &track_offset);
1245   if (err)
1246      return err;
1247
1248   floppy_image_read(floppy, buffer, track_offset, buflen);
1249   
1250   /* Rebuild the CRCs. PC99 did not store the CRC but put
1251      F7F7 in its place.
1252      The first CRC is at position IDAM + 5 
1253      The second CRC is at position IDAM + 0x119 (FM) or +0x12d (MFM)
1254      All this is repeated for each sector in the track
1255   */
1256   if (determine_offset(tag->format, track_data, &first_idam)==FLOPPY_ERROR_SEEKERROR)
1257      return FLOPPY_ERROR_SEEKERROR;
1258
1259   i = 0;
1260   while (i < buflen)
1261   {
1262      byte = read_byte(tag->format, first_idam, track_data, i);
1263      if (byte == TI99_IDAM)
1264      {
1265         /* Do we have a valid CRCs already? Then this image
1266            already contains proper CRCs handling. Do not
1267            recreate them. */
1268         if (track_data[i+5] != 0xf7 || track_data[i+5] != 0xf7)
1269            return FLOPPY_ERROR_SUCCESS;
1270
1271         crc = ccitt_crc16(0xffff, &track_data[i], 5);
1272         track_data[i+5] = (crc>>8) & 0xff;
1273         track_data[i+6] = (crc & 0xff);
1274      }
1275      else
1276      {
1277         if (byte == TI99_DAM)
1278         {
1279            crc = ccitt_crc16(0xffff, &track_data[i], SECTOR_SIZE+1);
1280            track_data[i+SECTOR_SIZE+1] = (crc>>8) & 0xff;
1281            track_data[i+SECTOR_SIZE+2] = (crc & 0xff);
1282         }
1283      }
1284      i++;
1285   }
1286//   dump_contents(track_data, buflen);
1287   return FLOPPY_ERROR_SUCCESS;
1288}
1289
1290/*
1291   Reads a track. We just copy the contents from the format, without
1292   changes.
1293*/
1294static floperr_t ti99_tdf_read_track(floppy_image *floppy, int head, int track, UINT64 offset, void *buffer, size_t buflen)
1295{
1296   int imgtrack = track;
1297   
1298   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
1299   if (ti99_image_in_80_track_drive() && tag->tracks<=40)
1300   {
1301      imgtrack = track / 2;
1302   }
1303   return ti99_tdf_read_track_internal(floppy, head, imgtrack, offset, buffer, buflen);
1304}
1305
1306/*
1307   Writes a track.
1308*/
1309static floperr_t ti99_tdf_write_track(floppy_image *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buflen)
1310{
1311   floperr_t err;
1312   UINT64 track_offset;
1313   int imgtrack = track;
1314   
1315   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
1316   if (ti99_image_in_80_track_drive() && tag->tracks<=40)
1317   {
1318      imgtrack = track / 2;
1319   }
1320
1321   err = ti99_tdf_get_offset(floppy, head, imgtrack, &track_offset);
1322   if (err)
1323      return err;
1324
1325   /* According to the TDF format, we don't need the CRC but replace it
1326      with F7F7. For now we keep it and see whether PC99 can cope with
1327      that. (Otherwise we would have to copy the const buffer). */
1328   floppy_image_write(floppy, buffer, offset + track_offset, buflen);
1329   return FLOPPY_ERROR_SUCCESS;
1330}
1331
1332/*
1333static floperr_t ti99_tdf_format_track(floppy_image *floppy, int head, int track, option_resolution *params)
1334{
1335   int sectors;
1336   int sector_length;
1337   int interleave;
1338   int first_sector_id;
1339   sectors         = option_resolution_lookup_int(params, PARAM_SECTORS);
1340   sector_length   = option_resolution_lookup_int(params, PARAM_SECTOR_LENGTH);
1341   interleave      = option_resolution_lookup_int(params, PARAM_INTERLEAVE);
1342   first_sector_id   = option_resolution_lookup_int(params, PARAM_FIRST_SECTOR_ID);
1343   return FLOPPY_ERROR_SUCCESS;
1344}
1345*/
1346
1347/*
1348   Get a sector from a track. This function takes a complete track,
1349   searches for the sector, and passes a pointer to the sector contents
1350   back.
1351   As the original TI controller creates bad bytes at the start of a track
1352   we do *not* assume a simple layout. The strategy is to search the
1353   lead-in of the track, and from this offset, step through the track
1354   in search for the sector. Since we do not have index marks (we cannot
1355   distinguish them from ordinary data, as we do not store the clock), we
1356   do not attempt to detect IDAM or DAM.
1357*/
1358static floperr_t ti99_tdf_seek_sector_in_track(floppy_image *floppy, int head, int track, int sector, UINT8 *track_data, UINT8 **sector_data)
1359{
1360   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
1361
1362   int byte;
1363   int state;
1364   enum { SEARCHIDAM, SEARCHDAM };
1365   
1366   state = SEARCHIDAM;
1367   if (tag->first_idam==0) /* should we check for every track? */
1368   {
1369      if (determine_offset(tag->format, track_data, &tag->first_idam)==FLOPPY_ERROR_SEEKERROR)
1370      {
1371         logerror("could not determine offset\n");
1372         return FLOPPY_ERROR_SEEKERROR;
1373      }
1374   }
1375
1376   for (int i=0; i < tag->track_size; i++)
1377   {
1378      byte = read_byte(tag->format, tag->first_idam, track_data, i);
1379
1380      switch (state)
1381      {
1382      case SEARCHIDAM:
1383         /* search for the IDAM */
1384         if (byte==TI99_IDAM)
1385         {
1386            if ((track_data[i+1]==track) && (track_data[i+2]==head) && (track_data[i+3]==sector))
1387               state = SEARCHDAM;
1388            else
1389               state = SEARCHIDAM;
1390         }
1391         break;
1392      case SEARCHDAM:
1393         if (byte==TI99_DAM)
1394         {
1395            *sector_data = &track_data[i+1];
1396            return FLOPPY_ERROR_SUCCESS;
1397         }
1398         break;
1399      }
1400   }
1401   logerror("Sector not found.\n");
1402   return FLOPPY_ERROR_SEEKERROR;
1403}
1404
1405static floperr_t ti99_tdf_read_sector(floppy_image *floppy, int head, int track, int sector, void *buffer, size_t buflen)
1406{
1407   floperr_t err;
1408   UINT8 *sector_data;
1409   UINT8 *track_data;
1410   int imgtrack = track;
1411   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
1412
1413   track_data = (UINT8*)malloc(tag->track_size);
1414
1415   if (ti99_image_in_80_track_drive() && tag->tracks<=40)
1416   {
1417      imgtrack = track / 2;
1418   }
1419
1420   err = ti99_tdf_read_track_internal(floppy, head, imgtrack, 0, track_data, tag->track_size);
1421   if (err)
1422      return err;
1423
1424   err = ti99_tdf_seek_sector_in_track(floppy, head, imgtrack, sector, track_data, &sector_data);
1425   if (err)
1426      return err;
1427   /* verify CRC? */
1428
1429   memcpy(buffer, sector_data, SECTOR_SIZE);
1430   free(track_data);
1431   return FLOPPY_ERROR_SUCCESS;
1432}
1433
1434/*
1435   Writes a sector into the track. Note that the indexed_write method
1436   may be used instead of this method, according to the implementation
1437   of flopimg/flopdrv.
1438*/
1439static floperr_t ti99_tdf_write_sector(floppy_image *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam)
1440{
1441   floperr_t err;
1442   UINT8 *sector_data;
1443   UINT8 *track_data;
1444   UINT64 track_offset;
1445   int imgtrack = track;
1446   UINT64 offset;
1447   UINT8 crc_field[2];
1448   int crc;
1449   
1450   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
1451
1452   track_data = (UINT8*)malloc(tag->track_size);
1453   if (ti99_image_in_80_track_drive() && tag->tracks<=40)
1454   {
1455      imgtrack = track / 2;
1456   }
1457
1458   err = ti99_tdf_read_track_internal(floppy, head, imgtrack, 0, track_data, tag->track_size);
1459   if (err)
1460      return err;
1461   err = ti99_tdf_seek_sector_in_track(floppy, head, imgtrack, sector, track_data, &sector_data);
1462   if (err)
1463      return err;
1464
1465   err = ti99_tdf_get_offset(floppy, head, imgtrack, &track_offset);
1466   if (err)
1467      return err;
1468
1469   offset = track_offset + (sector_data - track_data);
1470
1471   floppy_image_write(floppy, buffer, offset, SECTOR_SIZE);
1472
1473   /* Recalculate CRC */
1474   crc = ccitt_crc16(0xffff, (UINT8*)buffer, SECTOR_SIZE);
1475   crc_field[0] = (crc>>8) & 0xff;
1476   crc_field[1] = (crc & 0xff);
1477   floppy_image_write(floppy, crc_field, offset+SECTOR_SIZE, 2);
1478   
1479   return FLOPPY_ERROR_SUCCESS;
1480}
1481
1482static floperr_t ti99_tdf_write_indexed_sector(floppy_image *floppy, int head, int track, int sector_index, const void *buffer, size_t buflen, int ddam)
1483{
1484   /* Read track, head */
1485   int byte;
1486   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
1487   UINT8 *track_data;
1488   UINT8 *sector_data;
1489   UINT64 track_offset;
1490   UINT64 offset;
1491   UINT8 crc_field[2];
1492
1493   int crc;
1494   int imgtrack = track;
1495
1496   int i;
1497   floperr_t err;
1498
1499   track_data = (UINT8*)malloc(tag->track_size);
1500
1501   if (ti99_image_in_80_track_drive() && tag->tracks<=40)
1502   {
1503      imgtrack = track / 2;
1504   }
1505
1506   err = ti99_tdf_read_track_internal(floppy, head, imgtrack, 0, track_data, tag->track_size);
1507   if (err)
1508   {
1509      free(track_data);
1510      return err;
1511   }
1512
1513   /* Search for the sector_index-th sector. */
1514   if (tag->first_idam==0) /* should we check for every track? */
1515   {
1516      if (determine_offset(tag->format, track_data, &tag->first_idam)==FLOPPY_ERROR_SEEKERROR)
1517      {
1518         free(track_data);
1519         return FLOPPY_ERROR_SEEKERROR;
1520      }
1521   }
1522
1523   /* Search for the IDAM of the n-th sector */
1524   i=0;
1525   while (i < tag->track_size && sector_index>=0)
1526   {
1527      byte = read_byte(tag->format, tag->first_idam, track_data, i);
1528      if (byte == TI99_IDAM)
1529      {
1530         sector_index--;
1531      }
1532      i++;
1533   }
1534   i--;
1535
1536   /* Not that many sectors in this track? */
1537   if (sector_index>0)
1538   {
1539      free(track_data);
1540      return FLOPPY_ERROR_SEEKERROR;
1541   }
1542   
1543   /* Find the DAM. */
1544   while (i < tag->track_size)
1545   {
1546      byte = read_byte(tag->format, tag->first_idam, track_data, i);
1547      if (byte == TI99_DAM)
1548         break;
1549      else
1550         i++;
1551   }
1552
1553   /* There was no DAM. Image seems to be broken. */
1554   if (i == tag->track_size)
1555   {
1556      free(track_data);
1557      return FLOPPY_ERROR_SEEKERROR;
1558   }
1559   
1560   /* Sector data is right after the DAM. */
1561   sector_data = &track_data[i+1];
1562
1563   /* Get the position of the track in the image. */
1564   err = ti99_tdf_get_offset(floppy, head, imgtrack, &track_offset);
1565   if (err)
1566      return err;
1567   
1568   offset = track_offset + (sector_data - track_data);
1569   
1570   /* Write the sector data at that position. */
1571   floppy_image_write(floppy, buffer, offset, SECTOR_SIZE);
1572   
1573   /* Recalculate CRC */
1574   crc = ccitt_crc16(0xffff, (UINT8*)buffer, SECTOR_SIZE);
1575   crc_field[0] = (crc>>8) & 0xff;
1576   crc_field[1] = (crc & 0xff);
1577   floppy_image_write(floppy, crc_field, offset+SECTOR_SIZE, 2);
1578
1579   /* Free the temporary buffer */
1580   free(track_data);
1581   
1582   return FLOPPY_ERROR_SUCCESS;
1583}
1584
1585
1586static floperr_t ti99_tdf_find_indexed_sector(floppy_image *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, void *buffer, unsigned long *flags)
1587{
1588   /* Read track, head */
1589   int byte;
1590   struct ti99dsk_tag *tag = (ti99dsk_tag*)floppy_tag(floppy);
1591   UINT8 *track_data;
1592   int imgtrack = track;
1593   int i;
1594   floperr_t err;
1595   floperr_t retval;
1596   track_data = (UINT8*)malloc(tag->track_size);
1597
1598   if (ti99_image_in_80_track_drive() && tag->tracks<=40)
1599   {
1600      imgtrack = track / 2;
1601   }
1602   
1603   err = ti99_tdf_read_track_internal(floppy, head, imgtrack, 0, track_data, tag->track_size);
1604   if (err)
1605   {
1606      free(track_data);
1607      return err;
1608   }
1609
1610   /* Search for the sector_index-th sector. */
1611
1612   if (tag->first_idam==0) /* should we check for every track? */
1613   {
1614      if (determine_offset(tag->format, track_data, &tag->first_idam)==FLOPPY_ERROR_SEEKERROR)
1615      {
1616         free(track_data);
1617         return FLOPPY_ERROR_SEEKERROR;
1618      }
1619   }
1620
1621   i=0;
1622   sector_index = sector_index+1;
1623   while (i++ < tag->track_size && sector_index>0)
1624   {
1625      byte = read_byte(tag->format, tag->first_idam, track_data, i);
1626      if (byte == TI99_IDAM)
1627      {
1628         sector_index--;
1629      }
1630   }
1631   
1632   retval = FLOPPY_ERROR_SEEKERROR;
1633   if (sector_index==0)
1634   {
1635      /* If desired, return the ID field */
1636      if (cylinder)
1637      {
1638         *cylinder = track_data[i];
1639         //      printf("cylinder=%d", *cylinder);
1640         
1641      }
1642      if (side)
1643      {
1644         *side = track_data[i+1];
1645         //      printf(", side=%d", *side);
1646      }
1647      if (sector)
1648      {
1649         *sector = track_data[i+2];
1650         //      printf(", sector=%d", *sector);
1651      }
1652      if (sector_length)
1653      {
1654         *sector_length = 128 << track_data[i+3];
1655         //      printf(", sector_length=%d\n", *sector_length);
1656      }
1657      if (flags)
1658      {
1659         *flags = 0;
1660      }
1661      retval = FLOPPY_ERROR_SUCCESS;
1662     
1663      /* If desired, return the sector contents. */
1664      if (buffer)
1665      {
1666         while (i++ < tag->track_size)
1667         {
1668            byte = read_byte(tag->format, tag->first_idam, track_data, i);
1669            if (byte == TI99_DAM)
1670               break;
1671         }
1672         if (byte == TI99_DAM)
1673         {
1674            memcpy(buffer, &track_data[i+1], SECTOR_SIZE);
1675         }
1676         else
1677         {
1678            retval = FLOPPY_ERROR_SEEKERROR;
1679         }
1680      }
1681   }
1682   free(track_data);
1683   return retval;
1684}
1685
1686/*
1687   Required for ReadAddress command. This function gets the 1st, 2nd, 3rd,
1688   sector (and so on) from the track, not sector 1, 2, 3. That is, the
1689   returned sector info depends on the interleave and the start sector.
1690*/
1691static floperr_t ti99_tdf_get_indexed_sector_info(floppy_image *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags)
1692{
1693   return ti99_tdf_find_indexed_sector(floppy, head, track, sector_index, cylinder, side, sector, sector_length, NULL, flags);
1694}
1695
1696static floperr_t ti99_tdf_read_indexed_sector(floppy_image *floppy, int head, int track, int sector, void *buffer, size_t buflen)
1697{
1698   return ti99_tdf_find_indexed_sector(floppy, head, track, sector, (int*)NULL, (int*)NULL, (int*)NULL, (UINT32*)NULL, buffer, (unsigned long*)NULL);
1699}
1700
1701
1702/*
1703   Guess the geometry of the disk.
1704   1. Check whether the disk is formatted, and if so, whether it is
1705      a FM or a MFM disk
1706   2. If this fails, guess from the file size which format it should have
1707   
1708   SDF formats have sizes which are multiples of 10KiB.
1709   TDF: full sector size FM (MFM) = 334 (340) bytes
1710             additional track data FM (MFM) = 247 (752) bytes
1711       
1712        => check whether size is dividable by 40 (or 35) and by 2
1713        => get track size
1714        => subtract track data
1715        => divide by 334 or 340
1716        => number of sectors should be 8, 9, 16, 18, 32, or 36
1717       
1718    SSDD is 274880, but DSSD is 260240, so they differ (unlike in the SDF format)
1719    Still, we cannot tell apart single-sided 80 track formats from double-sided
1720    40 tracks. We assume the latter. Moreover, we only attempt to detect
1721    9/18/36 sectors (no 8/16) and 40 tracks (no 35).   
1722
1723    SSSD40 =  130120
1724    DSSD   =  260240
1725    SSDD   =  274880
1726    DSDD   =  549760
1727    DSHD   = 1039360
1728    DSDD80 = 1099520
1729    DSHD80 = 2078720
1730*/
1731static int ti99_tdf_guess_geometry(floppy_image *floppy, UINT64 size,
1732   struct ti99dsk_geometry *geometry)
1733{
1734   int idamcnt, state, track, head, i, totalseclen, format, byte, tracklength, trackadd;
1735   int first_idam = 0;
1736   UINT8 *track_data;
1737   int offset;
1738   
1739   struct ti99dsk_geometry dummy_geometry;
1740   
1741   if (geometry)
1742      memset(geometry, 0, sizeof(*geometry));
1743   else
1744      geometry = &dummy_geometry;
1745   
1746   /* Allocate enough bytes to hold the longest supported track. */
1747   track_data = (UINT8*)malloc(13000);
1748   floppy_image_read(floppy, track_data, 0, 13000);
1749
1750   if (determine_offset(TI99_MFM, track_data, &first_idam)==FLOPPY_ERROR_SEEKERROR)
1751   {
1752      /* MFM failed. */
1753      if (determine_offset(TI99_FM, track_data, &first_idam)==FLOPPY_ERROR_SEEKERROR)
1754      {
1755         logerror("IDAM not found. Unformatted disk.\n");
1756         /* FM failed as well. Disk is not formatted. We assume
1757            a format that fits into the space provided by the
1758            file.
1759            We only give a moderate vote in this case, so SDF
1760            make take it.
1761         */
1762         free(track_data);
1763         if (size < 130120 || size > 2078720)
1764         {
1765            logerror("Unknown format size: %d\n", (int)size);
1766            return 0;
1767         }
1768         if (size >= 130120 && size < 260240)
1769         {
1770            /* SSSD */
1771            geometry->sides = 1;
1772            geometry->tracksperside = 40;
1773            geometry->secspertrack = 9;
1774            geometry->density = 1;
1775            return 50;
1776         }
1777         if (size >= 260240 && size < 274880)
1778         {
1779            /* DSSD */
1780            geometry->sides = 2;
1781            geometry->tracksperside = 40;
1782            geometry->secspertrack = 9;
1783            geometry->density = 1;
1784            return 50;
1785         }
1786         if (size >= 274880 && size < 549760)
1787         {
1788            /* SSDD */
1789            geometry->sides = 1;
1790            geometry->tracksperside = 40;
1791            geometry->secspertrack = 18;
1792            geometry->density = 2;
1793            return 50;
1794         }
1795         if (size >= 549760 && size < 1039360)
1796         {
1797            /* DSDD */
1798            geometry->sides = 2;
1799            geometry->tracksperside = 40;
1800            geometry->secspertrack = 18;
1801            geometry->density = 2;
1802            return 50;
1803         }
1804         if (size >= 1039360 && size < 1099520)
1805         {
1806            /* DSHD */
1807            geometry->sides = 2;
1808            geometry->tracksperside = 40;
1809            geometry->secspertrack = 36;
1810            geometry->density = 2;
1811            return 50;
1812         }
1813         if (size >= 1099520 && size < 2078720)
1814         {
1815            /* DSDD80 */
1816            geometry->sides = 2;
1817            geometry->tracksperside = 80;
1818            geometry->secspertrack = 18;
1819            geometry->density = 2;
1820            return 50;
1821         }
1822         if (size == 2078720)
1823         {
1824            /* DSHD80 */
1825            geometry->sides = 2;
1826            geometry->tracksperside = 80;
1827            geometry->secspertrack = 36;
1828            geometry->density = 2;
1829            return 50;
1830         }
1831      }
1832      else
1833      {
1834         /* FM format */
1835         totalseclen = TI99_FM_TOTAL_SECTOR;
1836         trackadd = TI99_FM_TRACK_ADD; /* additional track data (gaps etc.) */
1837         geometry->density = 1;
1838         format = TI99_FM;
1839      }         
1840   }
1841   else
1842   {
1843      /* MFM format */
1844      totalseclen = TI99_MFM_TOTAL_SECTOR;
1845      trackadd = TI99_MFM_TRACK_ADD;
1846      geometry->density = 2;
1847      format = TI99_MFM;
1848   }
1849
1850   /* Count the number of IDAMs on track 0, head 0 */
1851   idamcnt = 0;
1852   state = 0;
1853   track = 0;
1854   head = 0;
1855   i=0;
1856   
1857   while (i++ < 13000 && head == 0 && track == 0)
1858   {
1859      byte = read_byte(format, first_idam, track_data, i);
1860      switch (state)
1861      {
1862      case 0:
1863         if (byte==TI99_IDAM)
1864            state = 1;
1865         break;
1866      case 1:
1867         track = byte;
1868         state = 2;
1869         break;
1870      case 2:
1871         head = byte;
1872         state = 3;
1873         break;
1874      case 3:         
1875         idamcnt++;
1876         state = 0;
1877      }
1878   }
1879   logerror("Determined %d sectors\n", idamcnt);
1880
1881   /* Now calculate the geometry
1882      The track size, in theory, may change due to reformatting,
1883      and it may also vary between tracks, but the TDF does not support
1884      varying track lengths. So every track has the same length as track 0.
1885      Also, we don't yet know whether the drive and the disk have the
1886      same track count. For 80 track drives and 40 track disks, we need
1887      double-stepping; this will be known as soon as the controller is
1888      initialized; we need to check that in the access methods.
1889   */
1890
1891   tracklength = idamcnt * totalseclen + trackadd;
1892   offset = 0;
1893   
1894   /* Read the last track. We assume that all tracks are properly
1895      formatted; otherwise, the above calculations would already fail.
1896      That is, the last track in the image tells us whether it is for
1897      head 0 or for head 1.
1898   */
1899   
1900   geometry->sides = 1;
1901   floppy_image_read(floppy, track_data, size-tracklength, tracklength);
1902   if (determine_offset(format, track_data, &first_idam)==FLOPPY_ERROR_SEEKERROR)
1903   {
1904      /* error ... what now? */
1905      logerror("Error when reading last track. Image broken.\n");
1906      free(track_data);
1907      return 50;
1908   }
1909   else
1910   {
1911      if (track_data[first_idam+2]==0)
1912      {
1913         geometry->sides = 1;
1914      }
1915      else
1916      {
1917         if (track_data[first_idam+2]==1)
1918         {
1919            geometry->sides = 2;
1920         }
1921         else
1922         {
1923            logerror("Error: Last track has invalid first IDAM: head = %d.\n", track_data[first_idam+2]);
1924         }
1925         
1926      }
1927   }
1928         
1929   
1930   geometry->tracksperside = (size / tracklength) / geometry->sides;
1931   geometry->secspertrack = idamcnt;
1932
1933   if (geometry->tracksperside < 35 || geometry->tracksperside > 80)
1934   {
1935      logerror("Unsupported track count: %d\n", geometry->tracksperside);
1936      free(track_data);
1937      return 0;
1938   }
1939   
1940   free(track_data);
1941   return 100;
1942}
1943
1944FLOPPY_IDENTIFY(ti99_tdf_identify)
1945{
1946   UINT64 size;
1947   size = floppy_image_size(floppy);
1948   *vote = ti99_tdf_guess_geometry(floppy, size, NULL);
1949   logerror("TDF voting %d\n", *vote);
1950   return FLOPPY_ERROR_SUCCESS;
1951}
1952
1953FLOPPY_CONSTRUCT(ti99_tdf_construct)
1954{
1955   struct ti99dsk_geometry geometry;
1956   struct FloppyCallbacks *callbacks;
1957   struct ti99dsk_tag *tag;
1958   logerror("Reading image as TDF\n");
1959   if (params)
1960   {
1961      /* create */
1962/*
1963      memset(&geometry, 0, sizeof(geometry));
1964      geometry.sides            = option_resolution_lookup_int(params, PARAM_HEADS);
1965      geometry.tracksperside         = option_resolution_lookup_int(params, PARAM_TRACKS);
1966      geometry.secspertrack         = option_resolution_lookup_int(params, PARAM_SECTORS);
1967*/
1968   }
1969   else
1970   {
1971      /* load */
1972      if (ti99_tdf_guess_geometry(floppy, floppy_image_size(floppy), &geometry)<50)
1973         return FLOPPY_ERROR_INVALIDIMAGE;
1974   }
1975
1976   assert(geometry.sides);
1977   assert(geometry.tracksperside);
1978   assert(geometry.secspertrack);
1979
1980   tag = (struct ti99dsk_tag *) floppy_create_tag(floppy, sizeof(struct ti99dsk_tag));
1981   
1982   tag->heads = geometry.sides;
1983   tag->tracks = geometry.tracksperside;
1984   
1985   if (geometry.density==TI99_FM)
1986      tag->track_size = geometry.secspertrack * TI99_FM_TOTAL_SECTOR + TI99_FM_TRACK_ADD;
1987   else
1988      tag->track_size = geometry.secspertrack * TI99_MFM_TOTAL_SECTOR + TI99_MFM_TRACK_ADD;
1989   
1990   tag->format = geometry.density;
1991   tag->first_idam = 0; /* let's find out later */
1992   tag->dam_offset = 0;
1993   
1994   /* set up format callbacks */
1995   callbacks = floppy_callbacks(floppy);
1996   callbacks->read_sector = ti99_tdf_read_sector;
1997   callbacks->write_sector = ti99_tdf_write_sector;
1998   callbacks->read_indexed_sector = ti99_tdf_read_indexed_sector;
1999   callbacks->write_indexed_sector = ti99_tdf_write_indexed_sector;
2000   callbacks->read_track = ti99_tdf_read_track;
2001   callbacks->write_track = ti99_tdf_write_track;
2002/*   callbacks->format_track = ti99_tdf_format_track; */
2003   callbacks->get_track_size = ti99_get_track_size;
2004   /* post format unset */
2005   callbacks->get_heads_per_disk = ti99_get_heads_per_disk;
2006   callbacks->get_tracks_per_disk = ti99_get_tracks_per_disk;
2007   callbacks->get_sector_length = ti99_get_sector_length;
2008   callbacks->get_indexed_sector_info = ti99_tdf_get_indexed_sector_info;
2009
2010   return FLOPPY_ERROR_SUCCESS;
2011}
2012
2013/* ----------------------------------------------------------------------- */
2014
2015FLOPPY_OPTIONS_START( ti99 )
2016   FLOPPY_OPTION( ti99_sdf, "dsk",         "TI99 sector dump (v9t9)",   ti99_sdf_identify,   ti99_sdf_construct,
2017      HEADS([1]-2)
2018      TRACKS(35-[40]-80)
2019      SECTORS(8/9/16/[18]/36)
2020      SECTOR_LENGTH([256])
2021      FIRST_SECTOR_ID(0))
2022   FLOPPY_OPTION( ti99_tdf, "dsk,dtk",         "TI99 track dump (pc99)",   ti99_tdf_identify,   ti99_tdf_construct,
2023      TRACKS(35-[40]-80)
2024      SECTORS(8/9/16/[18]/36)
2025      SECTOR_LENGTH([256])
2026      FIRST_SECTOR_ID(0))
2027FLOPPY_OPTIONS_END
src/mess/formats/ti99_dsk.h
r0r7367
1/*********************************************************************
2
3    formats/ti99_dsk.c
4
5    TI99 and Geneve disk images
6
7    Header file to be included by drivers which use these floppy options
8*********************************************************************/
9
10#ifndef TI99_DSK_H
11#define TI99_DSK_H
12
13#include "formats/flopimg.h"
14
15FLOPPY_OPTIONS_EXTERN(ti99);
16
17#endif /* TI99_DSK_H */
src/mess/mess.mak
r7366r7367
514514   $(MESS_FORMATS)/ap2_dsk.o   \
515515   $(MESS_FORMATS)/ap_dsk35.o   \
516516   $(MESS_FORMATS)/hect_tap.o   \
517   $(MESS_FORMATS)/ti99_dsk.o   \
517518
518519
519520
src/mess/drivers/ti99_8.c
r7366r7367
182182#include "machine/mm58274c.h"
183183#include "devices/ti99cart.h"
184184#include "machine/rtc65271.h"
185#include "formats/ti99_dsk.h"
185186
187
186188/*
187189    Memory map - see description above
188190*/
src/mess/drivers/geneve.c
r7366r7367
219219#include "machine/smc92x4.h"
220220#include "machine/mm58274c.h"
221221#include "machine/rtc65271.h"
222#include "formats/ti99_dsk.h"
222223
223224/*
224225    memory map
r7366r7367
468469   DEVCB_NULL,
469470   FLOPPY_DRIVE_DS_80,
470471   FLOPPY_OPTIONS_NAME(ti99),
471   KEEP_GEOMETRY
472   DO_NOT_KEEP_GEOMETRY
472473};
473474
474475static MACHINE_DRIVER_START(geneve_60hz)
src/mess/drivers/ti99_4p.c
r7366r7367
5959#include "machine/idectrl.h"
6060#include "machine/smc92x4.h"
6161#include "machine/rtc65271.h"
62#include "formats/ti99_dsk.h"
6263
6364static ADDRESS_MAP_START(memmap, ADDRESS_SPACE_PROGRAM, 16)
6465   AM_RANGE(0x0000, 0x1fff) AM_ROMBANK("bank1")                        /*system ROM*/
src/mess/drivers/ti99_4x.c
r7366r7367
4343#include "machine/mm58274c.h"
4444#include "machine/rtc65271.h"
4545#include "devices/ti99cart.h"
46#include "formats/ti99_dsk.h"
4647
4748/*
4849    memory map
r7366r7367
609610   DEVCB_NULL,
610611   FLOPPY_DRIVE_DS_80,
611612   FLOPPY_OPTIONS_NAME(ti99),
612   KEEP_GEOMETRY
613   DO_NOT_KEEP_GEOMETRY
613614};
614615
615616static MACHINE_DRIVER_START(ti99_4_60hz)

Previous 15994 Revisions Next


© 1998-2018 The MESS Team