Previous 199869 Revisions Next

r32413 Friday 26th September, 2014 at 18:35:07 UTC by Michael Zapf
(MESS) hdc9234 still WIP, HFDC fixes, disk formats re-implemented for
modernized floppy system. (nw)
[src/emu/bus/ti99_peb]hfdc.c hfdc.h
[src/emu/machine]hdc9234.c hdc9234.h
[src/lib/formats]ti99_dsk.c ti99_dsk.h

trunk/src/emu/bus/ti99_peb/hfdc.c
r32412r32413
452452         break;
453453
454454      case 2:
455         m_CD = (data != 0)? (m_CD | 1) : (m_CD & 0xfe);
455         m_hdc9234->set_clock_divider(0, data);
456456
457457         // Activate motor
458458         // When 1, let motor run continuously. When 0, a simple monoflop circuit keeps the line active for another 4 sec
r32412r32413
469469         break;
470470
471471      case 3:
472         m_CD = (data != 0)? (m_CD | 2) : (m_CD & 0xfd);
472         m_hdc9234->set_clock_divider(1, data);
473473         m_rom_page = (data != 0)? (m_rom_page | 2) : (m_rom_page & 0xfd);
474         if (TRACE_CRU) logerror("%s: ROM page = %d, CD = %d\n", tag(), m_rom_page, m_CD);
474         if (TRACE_CRU) logerror("%s: ROM page = %d\n", tag(), m_rom_page);
475475         break;
476476
477477      case 4:
r32412r32413
828828
829829   m_dip = m_irq = CLEAR_LINE;
830830   m_see_switches = false;
831   m_CD = 0;
832831   m_motor_running = false;
833832   m_selected = false;
834833   m_lastval = 0;
r32412r32413
916915   SLOT_INTERFACE( "525dd", FLOPPY_525_DD )        // 40 tracks
917916   SLOT_INTERFACE( "525qd", FLOPPY_525_QD )        // 80 tracks
918917   SLOT_INTERFACE( "35dd", FLOPPY_35_DD )          // 80 tracks
918   SLOT_INTERFACE( "35hd", FLOPPY_35_HD )          // 80 tracks 1.4 MiB
919919SLOT_INTERFACE_END
920920
921921MACHINE_CONFIG_FRAGMENT( ti99_hfdc )
trunk/src/emu/bus/ti99_peb/hfdc.h
r32412r32413
153153   // Output 2 latch (STB3)
154154   UINT8   m_output2_latch;
155155
156   // Clock divider bits 0 and 1. Unused in this emulation. */
157   int     m_CD;
158
159156   // Needed for triggering the motor monoflop
160157   UINT8 m_lastval;
161158
trunk/src/emu/machine/hdc9234.c
r32412r32413
226226   TYPE_AT = 0x00,
227227   TYPE_HD = 0x01,
228228   TYPE_FLOPPY8 = 0x02,
229   TYPE_FLOPPY5 = 0x03,
230   DRIVE_TYPE = 0x03
229   TYPE_FLOPPY5 = 0x03
231230};
232231
233232/*
r32412r32413
12431242      if (TRACE_READ) logerror("%s: READ SECTORS %s command %02x, CHS=(%d,%d,%d)\n", tag(), logical? "LOGICAL": "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector());
12441243      m_retry_save = m_register_w[RETRY_COUNT];
12451244      m_multi_sector = (m_register_w[SECTOR_COUNT] != 1);
1246
1245      m_write = false;
12471246      m_substate = READ_ID;
12481247   }
12491248
r32412r32413
12621261         verify(cont, logical);  // for physical, only verify the first sector
12631262         break;
12641263      case DATA_TRANSFER:
1265         m_write = false;
12661264         data_transfer(cont);
12671265         break;
12681266      default:
r32412r32413
13441342      m_deleted = (current_command() & 0x10)==0;
13451343      m_reduced_write_current = (current_command() & 0x08)!=0;
13461344      m_precompensation = (current_command() & 0x07);
1345      m_write = true;
13471346
13481347      m_gap0_size = -m_register_w[DMA7_0] & 0xff;
13491348      m_gap1_size = -m_register_w[DMA15_8] & 0xff;
r32412r32413
14391438      m_precompensation = (current_command() & 0x07);
14401439      // Important for DATA TRANSFER
14411440      m_transfer_enabled = true;
1442      m_write = true;
14431441      m_sync_size = fm_mode()? 6 : 12;
14441442      m_gap2_size = fm_mode()? 11 : 22;
1443      m_write = false; // until we're writing
14451444   }
14461445
14471446   int cont = NEXT;
r32412r32413
14591458         verify(cont, logical);
14601459         break;
14611460      case DATA_TRANSFER:
1461         m_write = true;
14621462         data_transfer(cont);
14631463         break;
14641464      default:
r32412r32413
15181518   int time = 0;
15191519   int index = m_register_w[MODE] & MO_STEPRATE;
15201520   // Get seek time.
1521   if ((m_selected_drive_type & DRIVE_TYPE) == TYPE_FLOPPY8)
1521   if (m_selected_drive_type == TYPE_FLOPPY8)
15221522      time = step_flop8[index] - pulse_flop8;
15231523
1524   else if ((m_selected_drive_type & DRIVE_TYPE) == TYPE_FLOPPY5)
1524   else if (m_selected_drive_type == TYPE_FLOPPY5)
15251525      time = step_flop5[index] - pulse_flop5;
15261526   else
15271527      time = step_hd[index] - pulse_hd;
r32412r32413
15371537{
15381538   int time = 0;
15391539   // Get seek time.
1540   if ((m_selected_drive_type & DRIVE_TYPE) == TYPE_FLOPPY8)
1540   if (m_selected_drive_type == TYPE_FLOPPY8)
15411541      time = pulse_flop8;
15421542
1543   else if ((m_selected_drive_type & DRIVE_TYPE) == TYPE_FLOPPY5)
1543   else if (m_selected_drive_type == TYPE_FLOPPY5)
15441544      time = pulse_flop5;
15451545   else
15461546      time = pulse_hd;
r32412r32413
16061606   m_live_state.data_reg = 0;
16071607   m_live_state.last_data_bit = false;
16081608
1609   pll_reset(m_live_state.time);
1609   pll_reset(m_live_state.time, m_write);
16101610   m_checkpoint_state = m_live_state;
16111611
16121612   // Save checkpoint
r32412r32413
21162116            write_on_track(encode((m_live_state.crc >> 8) & 0xff), 1, WRITE_DATA_CRC);
21172117         }
21182118         else
2119            m_live_state.state = WRITE_DONE;
2119            // Write a filler byte so that the last CRC bit is saved correctly
2120            write_on_track(encode(0xff), 1, WRITE_DONE);
21202121
21212122         break;
21222123
21232124      case WRITE_DONE:
21242125         if (m_substate == DATA_TRANSFER_WRITE)
21252126         {
2126            if (TRACE_WRITE) logerror("%s: Write sector complete\n", tag());
2127            if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write sector complete\n", tag());
21272128            m_pll.stop_writing(m_floppy, m_live_state.time);
21282129            m_live_state.state = IDLE;
21292130            return;
r32412r32413
26052606   checkpoint();
26062607}
26072608
2608void hdc9234_device::pll_reset(const attotime &when)
2609/*
2610    Reset the PLL. For reading, data must pass through a dedicated data
2611    separator. The clock rate is delivered from
2612    m_clock_divider with values 1-3, where 1 is FM (4000), 2 is MFM (2000),
2613    and 3 is MFM (1000).
2614    When writing, the controller generates the proper output bitstream, so we
2615    have to set it from its own state (fm/mfm and device type).
2616*/
2617void hdc9234_device::pll_reset(const attotime &when, bool output)
26092618{
26102619   m_pll.reset(when);
2611   // In FM mode, cells are 4 usec long; in MFM they are 2 usec long.
2612   m_pll.set_clock(attotime::from_usec(fm_mode()? 4 : 2));
2620
2621   if (output)
2622   {
2623      if (fm_mode())
2624         m_pll.set_clock(attotime::from_nsec(4000));
2625      else
2626         m_pll.set_clock(attotime::from_nsec((m_selected_drive_type==TYPE_FLOPPY5)? 2000 : 1000));
2627   }
2628   else
2629      m_pll.set_clock(attotime::from_nsec(8000 >> (~m_clock_divider & 0x03)));
26132630}
26142631
26152632void hdc9234_device::checkpoint()
r32412r32413
29993016}
30003017
30013018/*
3019    Clock divider. This input line actually belongs to the data separator which
3020    is a separate circuit. Maybe we will take it out of this implementation
3021    at some time and make it a device of its own.
3022    line: CD0 (0) and CD1(1), value 0 or 1
3023*/
3024void hdc9234_device::set_clock_divider(int line, int value)
3025{
3026   set_bits(m_clock_divider, (line==0)? 1 : 2, value&1);
3027}
3028
3029/*
30023030    Reset the controller. Negative logic, but we use ASSERT_LINE.
30033031*/
30043032WRITE_LINE_MEMBER( hdc9234_device::reset )
r32412r32413
30293057
30303058void hdc9234_device::device_reset()
30313059{
3060   m_clock_divider = 0;
30323061   m_deleted = false;
30333062   m_executing = false;
30343063   m_event_line = UNDEF;
trunk/src/emu/machine/hdc9234.h
r32412r32413
9898   // we implement it as a push call
9999   void auxbus_in( UINT8 data );
100100
101   // We pretend that the data separator is part of this controller. It is
102   // in fact a separate circuit. The clock divider must be properly set
103   // for MFM (CD0=1, CD1=0) or FM (CD0=0, CD1=1).
104   // This is not set by the controller itself!
105   void set_clock_divider(int pin, int value);
106
101107   // Used to reconfigure the drive connections. Floppy drive selection is done
102108   // using the user-programmable outputs. Hence, the connection
103109   // is changed outside of the controller, and by this way we let it know.
r32412r32413
235241   // Phase-locked loops
236242   fdc_pll_t m_pll, m_checkpoint_pll;
237243
244   // Clock divider value
245   UINT8 m_clock_divider;
246
238247   // Resets the PLL to the given time
239   void pll_reset(const attotime &when);
248   void pll_reset(const attotime &when, bool write);
240249
241250   // Encodes the byte using FM or MFM. Changes the m_live_state members
242251   // shift_reg, data_reg, and last_data_bit
trunk/src/lib/formats/ti99_dsk.c
r32412r32413
2424 * controllers and ROMs allow for up to 36 sectors per track and 80 tracks on
2525 * both sides, which is 1,44 MiB (DSHD80).
2626 *
27 * Double stepping
28 * --------------
29 * When using a 40-track disk in an 80-track drive, it seems as if each
30 * track appears twice in sequence (0,0,1,1,2,2,...,39,39).
31 * The system will write to each second track and leave the others untouched.
32 * When we write back that image, there is no simple way to know that
33 * the 80 tracks are in fact doubled 40 tracks. We will actually write
34 * all 80 tracks, doubling the size of the image file. This disk image will
35 * now become unusable in a 40-track drive - which is exactly what happens in reality.
36 *
37 * -------------------------------------------------------------------
2738 * The second half of this file contains the legacy implementation.
2839 *
29 * Michael Zapf, Feb 2014
40 * Michael Zapf, Sep 2014
3041 *
3142 ********************************************************************/
3243
r32412r32413
4354// Debugging
4455#define TRACE 0
4556
57// ====================================================
58//  Common methods for both formats.
59// ====================================================
60
4661/*
47    Sector Dump Format
48    ------------------
49    The Sector Dump Format is also known as v9t9 format (named after the first
50    TI emulator to use this format). It is a contiguous sequence of sector
51    contents without track data. The first sector of the disk is located at
52    the start of the image, while the last sector is at its end. The sectors
53    are ordered by their logical number as used in the TI file system.
54
55    In this implementation, the sector dump format is just a kind of
56    wd177x_format with minor customizations, which allows us to keep the code
57    small. The difference is the logical ordering of tracks and sectors.
58
59    The TI file system orders all tracks on side 0 as going inwards,
60    and then all tracks on side 1 going outwards.
61
62        00 01 02 03 ... 38 39     side 0
63        79 78 77 76 ... 41 40     side 1
64
65    The SDF format stores the tracks and their sectors in logical order
66        00 01 02 03 ... 38 39 [40 41 ... 79]
67
68    There is also a variant of the SDF which adds three sectors at the end
69    containing a map of bad sectors. This was introduced by a tool to read
70    real TI floppy disks on a PC. As other emulators tolerate this additional
71    bad sector map, we just check whether there are 3 more sectors and ignore
72    them.
62    Find out whether there are IDAMs and DAMs (without having clock bits).
63    As said above, let's not spend too much effort allowing format deviations.
64    If the image does not exactly adhere to the format, give up.
7365*/
74const char *ti99_sdf_format::name() const
66bool ti99_floppy_format::check_for_address_marks(UINT8* trackdata, int encoding)
7567{
76   return "sdf";
77}
68   int i=0;
7869
79const char *ti99_sdf_format::description() const
80{
81   return "TI99 sector dump floppy disk image";
70   if (encoding==floppy_image::FM)
71   {
72      // Check 5 sectors of track 0
73      while (i < 5)
74      {
75         if (trackdata[16 + 6 + i*334] != 0xfe) break;
76         if (trackdata[16 + 30 + i*334] != 0xfb && trackdata[16 + 30 + i*334] != 0xf8) break;
77         i++;
78      }
79   }
80   else
81   {
82      // Try MFM
83      i = 0;
84      while (i < 5)
85      {
86         if (trackdata[40 + 13 + i*340] != 0xfe) break;
87         if (trackdata[40 + 57 + i*340] != 0xfb && trackdata[40 + 57 + i*334] != 0xf8) break;
88         i++;
89      }
90   }
91   return (i==5);
8292}
8393
84const char *ti99_sdf_format::extensions() const
94int ti99_floppy_format::get_encoding(int cell_size)
8595{
86   return "dsk";
96   return (cell_size==4000)? floppy_image::FM : floppy_image::MFM;
8797}
8898
89bool ti99_sdf_format::supports_save() const
99/*
100    Load the image from disk and convert it into a sequence of flux levels.
101*/
102bool ti99_floppy_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
90103{
91   return true;
92}
104   int cell_size = 0;
105   int sector_count = 0;
106   int heads = 0;
107   determine_sizes(io, cell_size, sector_count, heads);
93108
94int ti99_sdf_format::identify(io_generic *io, UINT32 form_factor)
95{
96   UINT64 file_size = io_generic_size(io);
97   int vote = 0;
109   if (cell_size == 0) return false;
98110
99   vib_t vib;
111   // Be ready to hold a track of up to 36 sectors (with gaps and marks)
112   UINT8 trackdata[13000];
100113
101   // Adding support for another sector image format which adds 768 bytes
102   // as a bad sector map
103   if ((file_size / SECTOR_SIZE) % 10 == 3)
104   {
105      if (TRACE) logerror("ti99_dsk: Stripping map of bad sectors at image end\n");
106      file_size -= SECTOR_SIZE*3;
107   }
114   int maxtrack, maxheads;
115   image->get_maximal_geometry(maxtrack, maxheads);
108116
109   // Formats with 9 or 18 sectors per track
110   if (((file_size % 92160)==0)
111      && (   (file_size/92160==1)
112         || (file_size/92160==2)
113         || (file_size/92160==4)
114         || (file_size/92160==8)
115         || ((file_size/92160==16)&& (form_factor==floppy_image::FF_35)))) vote = 50;
117   int file_size = io_generic_size(io);
118   int track_size = get_track_size(cell_size, sector_count);
119   int track_count = file_size / (track_size*heads);
116120
117   // Formats with 16 sectors per track (rare)
118   if (((file_size % 163840)==0)
119      && (   (file_size/163840==1)
120         || (file_size/163840==2))) vote = 50;
121   if (TRACE) logerror("ti99_dsk: track count = %d\n", track_count);
121122
122   if (vote > 0)
123   if (track_count > maxtrack)
123124   {
124      // Read first sector (Volume Information Block)
125      io_generic_read(io, &vib, 0, sizeof(vib_t));
126
127      // Check from contents
128      if ((vib.id[0]=='D')&&(vib.id[1]=='S')&&(vib.id[2]=='K'))
129      {
130         if (TRACE) logerror("ti99_dsk: Found formatted SDF disk medium\n");
131         vote = 100;
132      }
133      else
134      {
135         if (TRACE) logerror("ti99_dsk: No valid VIB found; disk may be unformatted\n");
136      }
125      logerror("ti99_dsk: Floppy disk has too many tracks for this drive.\n");
126      return false;
137127   }
138   else if (TRACE) logerror("ti99_dsk: Disk image obviously not a SDF image\n");
139   return vote;
140}
141128
142int ti99_sdf_format::find_size(io_generic *io, UINT32 form_factor)
143{
144   UINT64 file_size = io_generic_size(io);
145   vib_t vib;
129   bool doubletracks = (track_count * 2 <= maxtrack);
146130
147   int vib_enc = 0;
131   if (doubletracks) logerror("ti99_dsk: 40-track image in an 80-track drive. On save, image size will double.\n");
148132
149   // See above
150   if ((file_size / SECTOR_SIZE) % 10 == 3) file_size -= SECTOR_SIZE*3;
151
152   // Read first sector
153   io_generic_read(io, &vib, 0, sizeof(vib_t));
154
155   // Check from contents
156   if ((vib.id[0]=='D')&&(vib.id[1]=='S')&&(vib.id[2]=='K'))
133   // Read the image
134   for(int head=0; head < heads; head++)
157135   {
158      // Find out more about the density. SSDD happens to be the same size
159      // as DSSD in the sector dump format, so we need to ask the
160      // VIB if available. Oherwise, we assume that we have a DSSD medium.
161      vib_enc = (vib.density < 2)? floppy_image::FM : floppy_image::MFM;
162      if (TRACE) logerror("ti99_dsk: VIB says that disk is %s density\n", (vib_enc==floppy_image::FM)? "single":"double");
163   }
164
165   for (int i=0; formats[i].form_factor != 0; i++)
166   {
167      if (formats[i].form_factor != form_factor)
136      for(int track=0; track < track_count; track++)
168137      {
169         if (TRACE) logerror("ti99_dsk: format %d has different form factor\n", i);
170         continue;
171      }
172      if (TRACE) logerror("ti99_dsk: trying sec=%d, tr=%d, head=%d, ss=%d for file size %d\n", formats[i].sector_count, formats[i].track_count, formats[i].head_count, formats[i].sector_base_size, (int)file_size);
138         load_track(io, trackdata, head, track, sector_count, track_count, cell_size);
173139
174      if (formats[i].sector_count * formats[i].track_count * formats[i].head_count * formats[i].sector_base_size == (int)file_size)
175      {
176         if (vib_enc == formats[i].encoding || vib_enc==0)
140         if (doubletracks)
177141         {
178            if (TRACE) logerror("ti99_dsk: format %d matches\n", i);
179            return i;
142            // Create two tracks from each medium track. This reflects the
143            // fact that the drive head will find the same data after
144            // a single step
145            if (get_encoding(cell_size)==floppy_image::FM)
146            {
147               generate_track_fm(track*2, head, cell_size, trackdata, image);
148               generate_track_fm(track*2+1, head, cell_size, trackdata, image);
149            }
150            else
151            {
152               generate_track_mfm(track*2, head, cell_size, trackdata, image);
153               generate_track_mfm(track*2+1, head, cell_size, trackdata, image);
154            }
180155         }
181156         else
182157         {
183            if (TRACE) logerror("ti99_dsk: format %d matches by size, but encoding does not match\n", i);
158            // Normal tracks
159            if (get_encoding(cell_size)==floppy_image::FM)
160               generate_track_fm(track, head, cell_size, trackdata, image);
161            else
162               generate_track_mfm(track, head, cell_size, trackdata, image);
184163         }
185164      }
186165   }
187   return -1;
166   return true;
188167}
189168
190int ti99_sdf_format::get_image_offset(const format &f, int head, int track)
169bool ti99_floppy_format::save(io_generic *io, floppy_image *image)
191170{
192   int logicaltrack = head * f.track_count;
193   logicaltrack += ((head&1)==0)?  track : (f.track_count - 1 - track);
194   if (TRACE) logerror("ti99_dsk: track %d, head %d -> logical track %d\n", track, head, logicaltrack);
195   return logicaltrack * compute_track_size(f);
196}
171   int act_track_size = 0;
197172
198// Format: form_factor, variant, encoding, cell_size, sector_count, track_count,
199//         head_count, sector_base_size, per_sector_size, sector_base_id,
200//         per_sector_id, gap1, gap2, gap3
173   UINT8 bitstream[500000/8];
174   UINT8 trackdata[9216];   // max size
201175
202const ti99_sdf_format::format ti99_sdf_format::formats[] =
203{
204   {   //  90K 5.25" single sided single density
205      floppy_image::FF_525, floppy_image::SSSD, floppy_image::FM,
206      4000, 9, 40, 1, SECTOR_SIZE, {}, 0, {}, 16, 11, 45
207   },
208   {   //  180K 5.25" double sided single density
209      floppy_image::FF_525, floppy_image::DSSD, floppy_image::FM,
210      4000, 9, 40, 2, SECTOR_SIZE, {}, 0, {}, 16, 11, 45
211   },
212   {   //  160K 5.25" single sided double density 16 sectors (rare)
213      floppy_image::FF_525, floppy_image::DSSD, floppy_image::MFM,
214      2000, 16, 40, 1, SECTOR_SIZE, {}, 0, {}, 40, 22, 24
215   },
216   {   //  180K 5.25" single sided double density
217      floppy_image::FF_525, floppy_image::SSDD, floppy_image::MFM,
218      2000, 18, 40, 1, SECTOR_SIZE, {}, 0, {}, 40, 22, 24
219   },
220   {   //  320K 5.25" double sided double density 16 sectors (rare)
221      floppy_image::FF_525, floppy_image::DSDD, floppy_image::MFM,
222      2000, 16, 40, 2, SECTOR_SIZE, {}, 0, {}, 40, 22, 24
223   },
224   {   //  360K 5.25" double sided double density
225      floppy_image::FF_525, floppy_image::DSDD, floppy_image::MFM,
226      2000, 18, 40, 2, SECTOR_SIZE, {}, 0, {}, 40, 22, 24
227   },
228   {   //  720K 5.25" double sided quad density (80 tracks)
229      floppy_image::FF_525, floppy_image::DSQD, floppy_image::MFM,
230      2000, 18, 80, 2, SECTOR_SIZE, {}, 0, {}, 40, 22, 24
231   },
232   {   //  720K 3.5" double sided double density (80 tracks)
233      floppy_image::FF_35, floppy_image::DSDD, floppy_image::MFM,
234      2000, 18, 80, 2, SECTOR_SIZE, {}, 0, {}, 40, 22, 24
235   },
236   {   //  1440K 3.5" double sided high density (80 tracks)
237      floppy_image::FF_35, floppy_image::DSHD, floppy_image::MFM,
238      1000, 36, 80, 2, SECTOR_SIZE, {}, 0, {}, 40, 22, 24
239   },
240   { 0 }
241};
176   int cellsizes[] = { 2000, 4000, 1000, 2000 };
242177
243/*
244    FM track image for sector dump format
245*/
246floppy_image_format_t::desc_e* ti99_sdf_format::get_desc_fm(const format &f, int &current_size, int &end_gap_index)
247{
248   static floppy_image_format_t::desc_e desc_fm[] =
249   {
250      { SECTOR_INTERLEAVE_SKEW, 3, 3 },       // skew/2 because of track*2+head
251      { FM, 0x00, f.gap_1 },                  // Gap 1 (note that we have 00 instead of ff)
252      { SECTOR_LOOP_START, 0, 8 },            // 9 sectors
253         { FM, 0x00, 6 },                    // pre-id gap
254         { CRC_CCITT_FM_START, 1 },
255         {   RAW, 0xf57e, 1 },               // IDAM (fe, clock=c7; 11110101 01111110)
256         {   TRACK_ID_FM },
257         {   HEAD_ID_FM },
258         {   SECTOR_ID_FM },
259         {   SIZE_ID_FM },
260         { CRC_END, 1 },
261         { CRC, 1 },
262         { FM, 0xff, f.gap_2 },               // Gap 2
263         { FM, 0x00, 6 },
264         { CRC_CCITT_FM_START, 2 },
265         {   RAW, 0xf56f, 1 },                // DAM (fb, clock=c7; 11110101 01101111)
266         {   SECTOR_DATA_FM, -1 },            // Sector data
267         { CRC_END, 2 },
268         { CRC, 2 },
269         { FM, 0xff, f.gap_3 },               // Gap 3
270      { SECTOR_LOOP_END },
271      { FM, 0xff, 0 },                         // track lead-out (end gap, 231)
272      { END }
273   };
274   current_size = (f.gap_1 + 9 * (6 + 1 + 4 + 2 + f.gap_2 + 6 + 1 + SECTOR_SIZE + 2 + f.gap_3) + 0) * 16;
275   end_gap_index = 21;
178   // Do we use double-stepping?
179   // If our image was loaded into a 80-track drive, we will always write 80 tracks.
180   int maxtrack, maxheads;
181   image->get_maximal_geometry(maxtrack, maxheads);
276182
277   return desc_fm;
278}
279
280/*
281    MFM track image for sector dump format
282*/
283floppy_image_format_t::desc_e* ti99_sdf_format::get_desc_mfm(const format &f, int &current_size, int &end_gap_index)
284{
285   static floppy_image_format_t::desc_e desc_mfm[] =
183   if (maxtrack > 80) maxtrack = 80;
184   else
286185   {
287      { SECTOR_INTERLEAVE_SKEW, 4, 0 },         // Possible ilv: 0, 4, 6, 10, 12, 16.
288      { MFM, 0x4e, f.gap_1 },                  // track lead-in
289      { SECTOR_LOOP_START, 0, 17 },            // 18 sectors
290         { CRC_CCITT_START, 1 },
291         {   RAW, 0x4489, 3 },                 // A1 sync mark
292         {   MFM, 0xfe, 1 },                  // IDAM
293         {   TRACK_ID },
294         {   HEAD_ID },
295         {   SECTOR_ID },
296         {   SIZE_ID },
297         { CRC_END, 1 },
298         { CRC, 1 },
299         { MFM, 0x4e, f.gap_2 },                   // Gap 2
300         { MFM, 0x00, 12 },
301         { CRC_CCITT_START, 2 },
302         {   RAW, 0x4489, 3 },                // A1
303         {   MFM, 0xfb, 1 },                  // DAM
304         {   SECTOR_DATA, -1 },               // Sector data
305         { CRC_END, 2 },
306         { CRC, 2 },
307         { MFM, 0x4e, f.gap_3 },                   // Gap 3
308      { SECTOR_LOOP_END },
309      { MFM, 0x4e, 0 },                      // track lead-out (712)
310      { END }
311   };
312   current_size = (f.gap_1 + 18 * (3 + 1 + 4 + 2 + f.gap_2 + 12 + 3 + 1 + SECTOR_SIZE + 2 + f.gap_3) + 0) * 16;
313   end_gap_index = 22;
186      if (maxtrack > 35 && maxtrack < 80) maxtrack = 40;
187      else maxtrack = 35;
188   }
314189
315   return desc_mfm;
316}
190   int attempt = 0;
191   int sector[36];
192   int maxsect = 18;
193   bool write = true;
317194
318const floppy_format_type FLOPPY_TI99_SDF_FORMAT = &floppy_image_format_creator<ti99_sdf_format>;
319
320/*
321    Track Dump Format
322    -----------------
323    The Track Dump Format is also known as pc99 (again, named after the first
324    TI emulator to use this format). It is a contiguous sequence of track
325    contents, containing all information including address marks and CRC, but it
326    does not contain clock signals. Therefore, the format requires that the
327    address marks be at the same positions within each track.
328
329    For FM recording, each track is exactly 3253 bytes long in this format.
330    For MFM recording, track length is 6872 bytes.
331
332    Accordingly, we get a multiple of these values as the image length.
333    There are no single-sided images (when single-sided, the upper half of
334    the image is empty).
335
336    DSSD: 260240 bytes
337    DSDD: 549760 bytes
338
339    We do not support other geometries in this format.
340
341    Tracks are stored from outside to inside of head 0, then outside to inside of head 1:
342
343    [Head0/track0] [Head0/track1] ... [Head0/track39] [Head1/track0] [Head1/track1] ... [Head1/track39]
344
345    Known Issues:
346    - When formatting a disk in MFM encoding, BwG with Disk Manager 2 creates
347      a format that is not compatible with TDF.
348      It differs not only with respect to the Gap_1 size but also wrt the
349      pre-id gap length and therefore causes a different track layout
350      (sectors are apart by 346 instead of 340 bytes).
351*/
352
353const char *ti99_tdf_format::name() const
354{
355   return "tdf";
356}
357
358const char *ti99_tdf_format::description() const
359{
360   return "TI99 track dump floppy disk image";
361}
362
363const char *ti99_tdf_format::extensions() const
364{
365   return "dsk,dtk";
366}
367
368bool ti99_tdf_format::supports_save() const
369{
370   return true;
371}
372
373/*
374    Determine whether the image file can be interpreted as a track dump
375*/
376int ti99_tdf_format::identify(io_generic *io, UINT32 form_factor)
377{
378   UINT64 file_size = io_generic_size(io);
379   int vote = 0;
380   UINT8 trackdata[500];
381
382   // Formats with 9 or 18 sectors per track
383   if ((file_size == 260240) || (file_size == 549760))
384      vote = 50;
385
386   if (vote > 0)
195   // We expect a bitstream of length 50000 for FM and 100000 for MFM
196   for(int head=0; head < 2; head++)
387197   {
388      if (TRACE) logerror("ti99_dsk: Image looks like a TDF image\n");
389
390      // Get some bytes from track 0
391      io_generic_read(io, trackdata, 0, 500);
392
393      int start = find_start(trackdata, 500, (file_size < 500000)? floppy_image::FM : floppy_image::MFM);
394      if (start != -1)
198      int track = 0;
199      while (track < maxtrack)
395200      {
396         if (TRACE) logerror("ti99_dsk: Start of image complies with TDF\n");
397         vote = 100;
398      }
399      else
400      {
401         logerror("ti99_dsk: Image does not comply with TDF; may be broken or unformatted\n");
402      }
403   }
404   else logerror("ti99_dsk: Disk image obviously not a TDF image\n");
405   return vote;
406}
201         int cell_size = cellsizes[attempt];
202         int encoding = get_encoding(cell_size);
203         int track_size = get_track_size(cell_size, 36); // max number of sectors
407204
408/*
409    Find the proper format for this image.
410*/
411int ti99_tdf_format::find_size(io_generic *io, UINT32 form_factor)
412{
413   UINT64 file_size = io_generic_size(io);
205         // Retrieve the cells from the flux sequence
206         generate_bitstream_from_track(track, head, cell_size, bitstream, act_track_size, image);
414207
415   for (int i=0; formats[i].form_factor != 0; i++)
416   {
417      if (formats[i].form_factor != form_factor)
418      {
419         if (TRACE) logerror("ti99_dsk: format %d has different form factor\n", i);
420         continue;
421      }
422      if (TRACE) logerror("ti99_dsk: trying format %d with encoding=%s, tr=%d, head=%d for file size %d\n", i, (formats[i].encoding==floppy_image::FM)? "FM" : "MFM", formats[i].track_count, formats[i].head_count, (int)file_size);
423      if (formats[i].track_size * formats[i].track_count * formats[i].head_count == (int)file_size)
424      {
425         if (TRACE) logerror("ti99_dsk: format %d matches\n", i);
426         return i;
427      }
428   }
429   return -1;
430}
208         // Maybe the track has become longer due to moving splices
209         if (act_track_size > 200000000/cell_size) act_track_size = 200000000/cell_size;
431210
432/*
433    Find out where the address marks are. Unfortunately, the TDF offers no
434    clock signals. So we are looking for this pattern:
211         int marks = decode_bitstream(bitstream, trackdata, sector, act_track_size, encoding, (encoding==floppy_image::FM)? 0xff:0x4e, track_size);
435212
436    FM: (00)*6, FE, (xx)*6, (FF)*11, (00)*6, FB
437    MFM: (00)*10, (a1)*3, fe, (xx)*6, (4e)*22, (00)*12
213         if (track==0)
214         {
215            if (head==0)
216            {
217               // Find the highest sector in the track
218               // This is only needed for the SDF format
219               int i=35;
220               while (i>=0 && sector[i]==-1) i--;
438221
439    Returns the position of the start of the pre-IDAM gap.
440*/
441int ti99_tdf_format::find_start(UINT8* trackdata, int track_size, int encoding)
442{
443   int pos = 0;
444   int pos1 = 0;
222               if (i>18) maxsect = 36;
223               else
224               {
225                  if (i>16) maxsect = 18;
226                  else
227                  {
228                     if (i>9) maxsect = 16;
229                     else maxsect = 9;
230                  }
231               }
232               if (TRACE) logerror("ti99_dsk: Sectors/track: %d\n", maxsect);
445233
446   // Does not make sense to look any further but the first 400 bytes.
447   while (pos < 400)
448   {
449      if (encoding==floppy_image::FM)
450      {
451         // FM
452         if (!has_byteseq(trackdata, track_size, 0x00, pos, 6))
453         {
454            pos++;
455            continue;
234               // We try different cell sizes until we find a fitting size.
235               // If this fails, we fall back to a size of 2000 ns
236               // The criterion for a successful decoding is that we find at least
237               // 6 ID or data address marks on the track. It is highly unlikely
238               // to find so many marks with a wrong cell size.
239               if (marks < 6 && attempt < 4)
240               {
241                  if (TRACE) logerror("ti99_dsk: Decoding with cell size %d failed.\n", cell_size);
242                  attempt++;
243                  write = false;
244               }
245               else write = true;
246            }
247            else
248            {
249               if (marks < 6)
250               {
251                  if (min_heads()==1)
252                  {
253                     if (TRACE) logerror("ti99_dsk: We don't have a second side and the format allows for single-sided recording.\n");
254                     return true;
255                  }
256                  else
257                  {
258                     logerror("ti99_dsk: No second side, but this format requires two-sided recording. Saving empty tracks.\n");
259                  }
260               }
261            }
456262         }
457         pos1 = pos + 6;
458         if (trackdata[pos1]!=0xfe)
263
264         if (write)
459265         {
460            pos++;
461            continue;
266            if (TRACE)
267            {
268               if (head == 0 && track == 0)
269               {
270                  if (marks >=6) { if (TRACE) logerror("ti99_dsk: Decoding with cell size %d successful.\n", cell_size); }
271                  else logerror("ti99_dsk: No address marks found on track 0. Assuming MFM format.\n");
272               }
273            }
274            // Save to the file
275            write_track(io, trackdata, sector, track, head, maxsect, maxtrack, track_size);
276            track++;
462277         }
463         pos1 += 7;
464         if (!has_byteseq(trackdata, track_size, 0xff, pos1, 11))
465         {
466            pos++;
467            continue;
468         }
469         pos1 += 11;
470         if (!has_byteseq(trackdata, track_size, 0x00, pos1, 6))
471         {
472            pos++;
473            continue;
474         }
475         pos1 += 6;
476         if (trackdata[pos1]!=0xfb)
477         {
478            pos++;
479            continue;
480         }
481278      }
482      else
483      {
484         // MFM
485         if (!has_byteseq(trackdata, track_size, 0x00, pos, 10))
486         {
487            pos++;
488            continue;
489         }
490         pos1 = pos + 10;
491         if (!has_byteseq(trackdata, track_size, 0xa1, pos1, 3))
492         {
493            pos++;
494            continue;
495         }
496         pos1 += 3;
497         if (trackdata[pos1]!=0xfe)
498         {
499            pos++;
500            continue;
501         }
502         pos1 += 7;
503         if (!has_byteseq(trackdata, track_size, 0x4e, pos1, 22))
504         {
505            pos++;
506            continue;
507         }
508         pos1 += 22;
509         if (!has_byteseq(trackdata, track_size, 0x00, pos1, 12))
510         {
511            pos++;
512            continue;
513         }
514      }
515      return pos;
516279   }
517   return -1;
518}
519280
520/*
521    Determine the offset from the start of the image, given the head and track.
522    At this location the track will be saved to the file.
523*/
524int ti99_tdf_format::get_image_offset(const format &f, int head, int track)
525{
526   return ((f.track_count * head) + track) * f.track_size;
527}
528
529/*
530    Load the TDF image from disk and convert it into a sequence of flux levels.
531*/
532bool ti99_tdf_format::load(io_generic *io, UINT32 form_factor, floppy_image *image)
533{
534   int type = find_size(io, form_factor);
535   if(type == -1)
536      return false;
537
538   UINT8 trackdata[6872];
539   const format &f = formats[type];
540
541   // Read the image
542   for(int head=0; head < f.head_count; head++)
543   {
544      for(int track=0; track < f.track_count; track++)
545      {
546         io_generic_read(io, trackdata, get_image_offset(f, head, track), f.track_size);
547         if (f.encoding==floppy_image::FM)
548            generate_track_fm(track, head, f.cell_size, trackdata, image);
549         else
550            generate_track_mfm(track, head, f.cell_size, trackdata, image);
551      }
552   }
553281   return true;
554282}
555283
556/*
557    Check whether a sequence of bytes is at the given position.
558*/
559bool ti99_tdf_format::has_byteseq(UINT8* trackdata, int track_size, UINT8 byte, int pos, int count)
284void ti99_floppy_format::generate_track_fm(int track, int head, int cell_size, UINT8* trackdata, floppy_image *image)
560285{
561   while ((pos < track_size) && (count > 0))
562   {
563      if (trackdata[pos] != byte) return false;
564      pos++;
565      count--;
566   }
567   return true;
568}
569
570void ti99_tdf_format::generate_track_fm(int track, int head, int cell_size, UINT8* trackdata, floppy_image *image)
571{
572286   int track_size_cells = 200000000/cell_size;
573287   UINT32 *buffer = global_alloc_array_clear(UINT32, 200000000/cell_size);
574288
r32412r32413
587301
588302   int offset = 0;
589303   short crc1, crc2, found_crc;
304   int start = 16;
590305
591   int start = find_start(trackdata, track_size, floppy_image::FM);
592   bool broken = false;
593
594   if (start == -1)
306   if (check_for_address_marks(trackdata, floppy_image::FM)==false)
595307   {
596      logerror("ti99_dsk: TDF: Start of track %d, head %d not found. Assuming broken format, starting at offset 16.\n", track, head);
597      start = 16;
598      broken = true;
308      if (head==0 && track==0) logerror("ti99_dsk: Cannot find FM address marks on track %d, head %d; likely broken or unformatted.\n", track, head);
309      global_free_array(buffer);
310      return;
599311   }
600312
601313   // Found a track; we now know where the address marks are:
r32412r32413
630342               if ((found_crc & 0xffff) == 0xf7f7)
631343               {
632344                  // PC99 format: no real CRC; replace it
345                  // Also, when converting from SDF we let this method create the proper CRC.
633346                  // logerror("Warning: PC99 format using pseudo CRC1; replace by %04x\n", crc1);
634347                  trackdata[i] = (crc1 >> 8) & 0xff;
635348                  trackdata[i+1] = crc1 & 0xff;
636349                  found_crc = crc1;
637350               }
638               if ((crc1 != found_crc) && !broken)
351               if (crc1 != found_crc)
639352               {
640353                  logerror("ti99_dsk: Warning: CRC1 does not match (track=%d, head=%d). Found = %04x, calc = %04x\n", track, head, found_crc& 0xffff, crc1& 0xffff);
641354               }
r32412r32413
655368                     trackdata[i+1] = crc2 & 0xff;
656369                     found_crc = crc2;
657370                  }
658                  if ((crc2 != found_crc) && !broken)
371                  if (crc2 != found_crc)
659372                  {
660373                     logerror("ti99_dsk: Warning: CRC2 does not match (track=%d, head=%d). Found = %04x, calc = %04x\n", track, head, found_crc& 0xffff, crc2& 0xffff);
661374                  }
r32412r32413
671384   global_free_array(buffer);
672385}
673386
674void ti99_tdf_format::generate_track_mfm(int track, int head, int cell_size, UINT8* trackdata, floppy_image *image)
387void ti99_floppy_format::generate_track_mfm(int track, int head, int cell_size, UINT8* trackdata, floppy_image *image)
675388{
676389   int track_size_cells = 200000000/cell_size;
677390   UINT32 *buffer = global_alloc_array_clear(UINT32, 200000000/cell_size);
r32412r32413
681394   // Here, Gap 4 is actually only 90 bytes long
682395   // (not 712 as specified in the TDF format)
683396   int track_size = track_size_cells / 16;
684   int start = find_start(trackdata, track_size, floppy_image::MFM);
685   bool broken = false;
686397
687398   int offset = 0;
688399   short crc1, crc2, found_crc;
400   int start = 40;
689401
690   if (start == -1)
402   if (check_for_address_marks(trackdata, floppy_image::MFM)==false)
691403   {
692      logerror("ti99_dsk: TDF: Start of track %d, head %d not found. Assuming broken format, starting at offset 40.\n", track, head);
693      start = 40;
694      broken = true;
404      if (track==0 && head==0) logerror("ti99_dsk: Cannot find MFM address marks on track %d, head %d; likely broken or unformatted.\n", track, head);
405      global_free_array(buffer);
406      return;
695407   }
696408
697409   // Found a track; we now know where the address marks are:
r32412r32413
738450                  trackdata[i+1] = crc1 & 0xff;
739451                  found_crc = crc1;
740452               }
741               if (crc1 != found_crc && !broken)
453               if (crc1 != found_crc)
742454               {
743455                  logerror("ti99_dsk: Warning: CRC1 does not match (track=%d, head=%d). Found = %04x, calc = %04x\n", track, head, found_crc & 0xffff, crc1& 0xffff);
744456               }
r32412r32413
758470                     trackdata[i+1] = crc2 & 0xff;
759471                     found_crc = crc2;
760472                  }
761                  if (crc2 != found_crc && !broken)
473                  if (crc2 != found_crc)
762474                  {
763475                     logerror("ti99_dsk: Warning: CRC2 does not match (track=%d, head=%d). Found = %04x, calc = %04x\n", track, head, found_crc& 0xffff,  crc2& 0xffff);
764476                  }
r32412r32413
774486   global_free_array(buffer);
775487}
776488
489// States for decoding the bitstream
490enum
491{
492   FMIDAM,
493   MFMIDAM,
494   HEADER,
495   FMDAM,
496   MFMDAM,
497   DATA
498};
499
777500/*
778    Get the track bytes from the bitstream. We store this sequence as the
779    contents of the TDF.
780
781    Note that this is risky to some extend. Since write splices may shift
782    in theory, we must be aware that dumping the bits may not be guaranteed
783    to deliver the sector contents properly. On the other hand, the floppy
784    implementation currently works very precisely, so it is not likely that
785    we get shifted splices.
786
787    To make this more stable we should better retrieve all sectors
788    separately (by extract_sectors_from_bitstream), then paste the sectors
789    back into the respective positions of the track image, then save this
790    rebuilt track image. Hence, as the track data outside of the sectors remain
791    unchanged after formatting, we can ensure a proper positioning of the
792    sectors for the TDF.
501    Decodes the bitstream into a TDF track image.
502    Returns the number of detected marks.
793503*/
794void ti99_tdf_format::extract_track_from_bitstream(const UINT8 *bitstream, int track_size, UINT8 *trackdata)
504int ti99_floppy_format::decode_bitstream(const UINT8 *bitstream, UINT8 *trackdata, int* sector, int cell_count, int encoding, UINT8 gapbytes, int track_size)
795505{
506   int databytes = 0;
507   int a1count = 0;
508   int lastpos = 0;
509   int headerbytes = 0;
510   int curpos = 0;
511   UINT8 curbyte = 0;
512   UINT16 shift_reg = 0;
513   int tpos = 0;
796514   int pos = 0;
797   int tpos = 0;
798   int lastpos = -1;
799   while ((pos < track_size) && (pos > lastpos)) {
800      // When pos < lastpos, we wrapped around the track end
801      lastpos = pos;
802      UINT8 byte = sbyte_mfm_r(bitstream, pos, track_size);
803      trackdata[tpos++] = byte;
804   }
805}
515   int state;
516   bool good = false;
517   int marks = 0;
518   int current_sector = 0;
806519
807bool ti99_tdf_format::save(io_generic *io, floppy_image *image)
808{
809   int act_track_size = 0;
520   // Init track
521   memset(trackdata, 0x00, track_size);
810522
811   UINT8 bitstream[500000/8];
812   UINT8 trackdata[6872];
523   for (int i=0; i < 36; i++) sector[i] = -1;
813524
814   // From the track_size alone we cannot tell whether this is FM or MFM
815   // We will have to try both ways; start with the size of the existing file
525   state = (encoding==floppy_image::MFM)? MFMIDAM : FMIDAM;
816526
817   int type = (io_generic_size(io) > 500000)? 1 : 0;
818
819   // If this choice fails we must try the other way
820   // If this fails again, we go for the first option again and save a possibly
821   // broken format
822
823   bool goodformat = true;
824   for (int option=0; option < 3; option++)
527   while (pos < cell_count && tpos < track_size)
825528   {
826      const format &f = formats[type];
827      if (TRACE) logerror("ti99_dsk: Trying format %d (TDF) for saving\n", type);
828      goodformat = true;
529      shift_reg = (shift_reg << 1) & 0xffff;
530      if ((pos & 0x07)==0) curbyte = bitstream[curpos++];
531      if ((curbyte & 0x80) != 0) shift_reg |= 1;
532      curbyte <<= 1;
829533
830      // We expect a bitstream of length 50000 for FM and 100000 for MFM
831      for(int head=0; (head < 2) && goodformat; head++)
534      switch (state)
832535      {
833         for(int track=0; (track < 40) && goodformat; track++)
536      case FMIDAM:
537         if (shift_reg == 0xf57e)
834538         {
835            // Retrieve the cells from the flux sequence
836            generate_bitstream_from_track(track, head, f.cell_size, bitstream, act_track_size, image);
539            marks++;
540            // Found a header
541            headerbytes = 5;
542            // Create GAP0 at the beginning or GAP3 later
543            if (tpos==0)
544               tpos += 16;
545            else
546               for (int i=0; i < 45; i++) trackdata[tpos++] = gapbytes;
837547
838            // Maybe the track has become longer due to moving splices
839            if (act_track_size > 200000000/f.cell_size)
548            // IDAM sync bytes
549            tpos += 6;
550            trackdata[tpos++] = 0xfe;
551            state = HEADER;
552            lastpos = pos;
553         }
554         break;
555
556      case MFMIDAM:
557         // Count three subsequent A1
558         if (shift_reg == 0x4489)
559         {
560            if (lastpos > 0)
840561            {
841               // Truncate the track
842               act_track_size = 200000000/f.cell_size;
562               if (pos - lastpos == 16) a1count++;
563               else a1count = 1;
843564            }
565            else a1count = 1;
844566
845            // Get the bytes from the cells
846            extract_track_from_bitstream(bitstream, act_track_size, trackdata);
567            lastpos = pos;
568         }
569         if (a1count == 3)
570         {
571            marks++;
572            // Found a header
573            headerbytes = 6;
574            // Create GAP0 at the beginning or GAP3 later
575            if (tpos==0)
576               for (int i=0; i < 40; i++) trackdata[tpos++] = gapbytes;
577            else
578               for (int i=0; i < 24; i++) trackdata[tpos++] = gapbytes;
847579
848            // Do we get a reasonable track format?
849            // Test this for track 0 only (we won't be able to change that
850            // for each single track, anyway)
580            // IDAM sync bytes
581            tpos += 10;
582            state = HEADER;
583            trackdata[tpos++] = 0xa1;
584            trackdata[tpos++] = 0xa1;
585            trackdata[tpos++] = 0xa1;
586         }
587         break;
851588
852            if ((track == 0) && (head == 0) && (option < 2))
589      case HEADER:
590         if (pos - lastpos == 16)
591         {
592            // Transfer header bytes
593            trackdata[tpos] = get_data_from_encoding(shift_reg);
594
595            if (headerbytes == 3) current_sector = trackdata[tpos];
596            tpos++;
597
598            if (headerbytes == 0)
853599            {
854            //  for (int i=0; i < 256; i++)
855            //      logerror("%02x%c", trackdata[i], (i%16==15)? '\n' : ' ');
600               state = (encoding==floppy_image::MFM)? MFMDAM : FMDAM;
601               a1count = 0;
602            }
603            else headerbytes--;
604            lastpos = pos;
605         }
606         break;
856607
857               goodformat = (find_start(trackdata, act_track_size, f.encoding) != -1);
858               if (!goodformat) logerror("ti99_dsk: Format %d (TDF) not suitable for saving\n", type);
608      case FMDAM:
609         if (shift_reg == 0xf56a || shift_reg == 0xf56f)
610         {
611            if (pos - lastpos > 400)
612            {
613               // Too far apart
614               state = FMIDAM;
615               // Abort this sector, skip to the next
616               tpos += 321;
617               a1count = 1;
618               break;
859619            }
620            marks++;
621            // Add GAP2 and DAM sync
622            for (int i=0; i < 11; i++) trackdata[tpos++] = 0xff;
623            tpos += 6;
624            state = DATA;
625            databytes = 257;
626            trackdata[tpos++] = (shift_reg==0xf56a)? 0xf8 : 0xfb;
627            lastpos = pos;
628            sector[current_sector] = tpos;
629         }
630         break;
860631
861            if (goodformat)
632      case MFMDAM:
633         // Count three subsequent A1
634         if (shift_reg == 0x4489)
635         {
636            if (pos - lastpos > 560)
862637            {
863               // Pad the trackdata according to the TDF spec
864               for (int i = act_track_size; i <  f.track_size; i++)
865                  trackdata[i] = f.gapbytes;
638               // Too far apart
639               state = MFMIDAM;
640               // Abort this sector, skip to the next
641               tpos += 320;
642               a1count = 1;
643               break;
644            }
866645
867               // Save to the file
868               io_generic_write(io, trackdata, get_image_offset(f, head, track), f.track_size);
646            if (lastpos > 0)
647            {
648               if (pos - lastpos == 16) a1count++;
649               else a1count = 1;
869650            }
651            else a1count = 1;
652
653            lastpos = pos;
870654         }
655         if (a1count == 3)
656         {
657            marks++;
658            // Add GAP2 and DAM sync
659            for (int i=0; i < 22; i++) trackdata[tpos++] = gapbytes;
660            tpos += 12;
661            trackdata[tpos++] = 0xa1;
662            trackdata[tpos++] = 0xa1;
663            trackdata[tpos++] = 0xa1;
664            state = DATA;
665            databytes = 258;
666            sector[current_sector] = tpos+1;
667         }
668         break;
669
670      case DATA:
671         if (pos - lastpos == 16)
672         {
673            // Ident byte
674            trackdata[tpos++] = get_data_from_encoding(shift_reg);
675            if (databytes > 0) databytes--;
676            else
677            {
678               state = (encoding==floppy_image::MFM)? MFMIDAM : FMIDAM;
679               a1count = 0;
680            }
681            lastpos = pos;
682         }
683         break;
871684      }
872      if (!goodformat)
685      pos++;
686   }
687   return marks;
688}
689
690UINT8 ti99_floppy_format::get_data_from_encoding(UINT16 raw)
691{
692   return (raw & 0x4000 ? 0x80 : 0x00) |
693         (raw & 0x1000 ? 0x40 : 0x00) |
694         (raw & 0x0400 ? 0x20 : 0x00) |
695         (raw & 0x0100 ? 0x10 : 0x00) |
696         (raw & 0x0040 ? 0x08 : 0x00) |
697         (raw & 0x0010 ? 0x04 : 0x00) |
698         (raw & 0x0004 ? 0x02 : 0x00) |
699         (raw & 0x0001 ? 0x01 : 0x00);
700}
701
702/*
703    Sector Dump Format
704    ------------------
705    The Sector Dump Format is also known as v9t9 format (named after the first
706    TI emulator to use this format). It is a contiguous sequence of sector
707    contents without track data. The first sector of the disk is located at
708    the start of the image, while the last sector is at its end. The sectors
709    are ordered by their logical number as used in the TI file system.
710
711    In this implementation, the sector dump format is just a kind of
712    wd177x_format with minor customizations, which allows us to keep the code
713    small. The difference is the logical ordering of tracks and sectors.
714
715    The TI file system orders all tracks on side 0 as going inwards,
716    and then all tracks on side 1 going outwards.
717
718        00 01 02 03 ... 38 39     side 0
719        79 78 77 76 ... 41 40     side 1
720
721    The SDF format stores the tracks and their sectors in logical order
722        00 01 02 03 ... 38 39 [40 41 ... 79]
723
724    There is also a variant of the SDF which adds three sectors at the end
725    containing a map of bad sectors. This was introduced by a tool to read
726    real TI floppy disks on a PC. As other emulators tolerate this additional
727    bad sector map, we just check whether there are 3 more sectors and ignore
728    them.
729*/
730const char *ti99_sdf_format::name() const
731{
732   return "sdf";
733}
734
735const char *ti99_sdf_format::description() const
736{
737   return "TI99 sector dump floppy disk image";
738}
739
740const char *ti99_sdf_format::extensions() const
741{
742   return "dsk";
743}
744
745int ti99_sdf_format::identify(io_generic *io, UINT32 form_factor)
746{
747   UINT64 file_size = io_generic_size(io);
748   int vote = 0;
749
750   // Adding support for another sector image format which adds 768 bytes
751   // as a bad sector map
752   if ((file_size / SECTOR_SIZE) % 10 == 3)
753   {
754      if (TRACE) logerror("ti99_dsk: Stripping map of bad sectors at image end\n");
755      file_size -= SECTOR_SIZE*3;
756   }
757
758   // Formats with 9 or 18 sectors per track (multiples of SSSD)
759   // 40-track formats: SSSD/9/40 (1), DSSD/9/40 (2), SSDD/18/40 (2), DSDD/18/40 (4)
760   // 80-track formats: SSSD/9/80 (2), DSSD/9/80 (4), SSDD/18/80 (4), DSDD/18/80,(8)
761   // High density: DSQD/36/80 (16) (experimental)
762
763   // All formats apply for 5.25" and 3.5" form factors
764
765   // Default formats (when the geometry cannot be determined from the VIB)
766   // (1)  -> SSSD
767   // (2)  -> DSSD
768   // (4)  -> DSDD
769   // (8)  -> DSDD80
770   // (16) -> DSQD
771
772   if ((file_size % 92160)==0)
773   {
774      int multiple = file_size/92160;
775      if ((multiple == 1) || (multiple == 2) || (multiple == 4) || (multiple == 8) || (multiple == 16)) vote = 50;
776   }
777
778   // Formats with 16 sectors per track (rare, SSDD/16/40, DSDD/16/40).
779   if (file_size == 163840) vote = 50;
780   if (file_size == 327680) vote = 50;
781
782   if (vote > 0)
783   {
784      // Read first sector (Volume Information Block)
785      ti99vib vib;
786      io_generic_read(io, &vib, 0, sizeof(ti99vib));
787
788      // Check from contents
789      if ((vib.id[0]=='D')&&(vib.id[1]=='S')&&(vib.id[2]=='K'))
873790      {
874         // If 0 then next is 1 and fallback is 0.
875         // If 1 then next is 0 and fallback is 1.
876         type = (type+1) % 2;
791         if (TRACE) logerror("ti99_dsk: Found formatted SDF disk medium\n");
792         vote = 100;
877793      }
878794      else
879         return true;
795      {
796         if (TRACE) logerror("ti99_dsk: No valid VIB found; disk may be unformatted\n");
797      }
880798   }
799   else if (TRACE) logerror("ti99_dsk: Disk image is not a SDF image\n");
800   return vote;
801}
881802
882   // We won't reach this line
883   return true;
803void ti99_sdf_format::determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads)
804{
805   UINT64 file_size = io_generic_size(io);
806   ti99vib vib;
807
808   cell_size = 0;
809   sector_count = 0;
810   heads = 2;
811
812   bool have_vib = false;
813
814   // See above
815   if ((file_size / SECTOR_SIZE) % 10 == 3) file_size -= SECTOR_SIZE*3;
816
817   // Read first sector
818   io_generic_read(io, &vib, 0, sizeof(ti99vib));
819
820   // Check from contents
821   if ((vib.id[0]=='D')&&(vib.id[1]=='S')&&(vib.id[2]=='K'))
822   {
823      sector_count = vib.secspertrack;
824      heads = vib.sides;
825
826      // Find out more about the density. SSDD happens to be the same size
827      // as DSSD in the sector dump format, so we need to ask the
828      // VIB if available. Otherwise, we assume that we have a DSSD medium.
829      if (vib.density < 2) cell_size = 4000;
830      else
831      {
832         if (vib.density < 4) cell_size = 2000;
833         else cell_size = 1000;
834      }
835      if (TRACE) logerror("ti99_dsk: VIB says that this disk is %s density with %d sectors per track, %d tracks, and %d heads\n", (cell_size==4000)? "single": ((cell_size==2000)? "double" : "high"), sector_count, vib.tracksperside, heads);
836      have_vib = true;
837   }
838
839   // We're also checking the size of the image
840   int cell_size1 = 0;
841   int sector_count1 = 0;
842
843   // 90 KiB -> SSSD, 9 sect, FM
844   // 160 KiB -> SSDD, 16 sect, MFM
845   // 180 KiB -> DSSD, 9 sect, FM
846   // 320 KiB -> DSDD, 16 sect, MFM
847   // 360 KiB -> DSDD, 18 sect, MFM
848   // 720 KiB -> DSDD, 18 sect, MFM, 80 tracks
849   // 1440 KiB-> DSQD, 36 sect, MFM, 80 tracks
850
851   if ((file_size == 163840) || (file_size == 327680))
852   {
853      cell_size1 = 2000;
854      sector_count1 = 16;
855   }
856   else
857   {
858      if (file_size < 300000) cell_size1 = 4000;
859      else
860      {
861         if (file_size < 1000000) cell_size1 = 2000;
862         else cell_size1 = 1000;
863      }
864      sector_count1 = 36000 / cell_size1;
865   }
866
867   if (have_vib)
868   {
869      if (sector_count == 16 && sector_count1 == 18)
870      {
871         logerror("ti99_dsk: Warning: Invalid 16-sector format. Assuming 18 sectors.\n");
872         sector_count = 18;
873      }
874      else
875      {
876         if (heads == 2 && ((cell_size1 != cell_size) || (sector_count1 != sector_count)))
877            logerror("ti99_dsk: Warning: Disk image size does not correspond with format information in VIB.\n");
878      }
879   }
880   else
881   {
882      heads = (file_size < 100000)? 1 : 2;    // for SSSD
883      cell_size = cell_size1;
884      sector_count = sector_count1;
885   }
884886}
885887
888int ti99_sdf_format::get_track_size(int cell_size, int sector_count)
889{
890   return sector_count * SECTOR_SIZE;
891}
892
886893/*
887    Supported formats for the track dump format.
888    There are only two formats: FM double-sided and MFM double-sided.
894    Load a SDF image track. Essentially, we want to end up in the same
895    kind of track image as with the TDF, so the easiest thing is to produce
896    a TDF image track from the sectors and process them as if it came from TDF.
889897*/
890const ti99_tdf_format::format ti99_tdf_format::formats[] =
898void ti99_sdf_format::load_track(io_generic *io, UINT8 *trackdata, int head, int track, int sectorcount, int trackcount, int cellsize)
891899{
892   {   //  180K 5.25" double sided single density
893      floppy_image::FF_525, floppy_image::DSSD, floppy_image::FM,
894      4000, 9, 40, 2, 3253, 0xff
895   },
896   {   //  360K 5.25" double sided double density
897      floppy_image::FF_525, floppy_image::DSDD, floppy_image::MFM,
898      2000, 18, 40, 2, 6872, 0x4e
899   },
900   { 0 }
901};
900   bool fm = (cellsize==4000);
901   int tracksize = sectorcount * SECTOR_SIZE;
902902
903   // Calculate the track offset from the beginning of the image file
904   int logicaltrack = head * trackcount;
905   logicaltrack += ((head&1)==0)?  track : (trackcount - 1 - track);
906
907   // Interleave and skew
908   int interleave = fm? 4 : 5;
909   int skew = fm? 6 : 0;
910
911   int secsize = fm? 334 : 340;
912   int secoff = fm? 33 : 58;
913   int position = 0;
914   int count = 0;
915
916   memset(trackdata, 0x00, 9216);
917
918   int secno = 0;
919   secno = (track * skew) % sectorcount;
920
921   // Gap 1
922   int gap1 = fm? 16 : 40;
923   for (int i=0; i < gap1; i++) trackdata[position+i] = fm? 0x00 : 0x4e;
924
925   for (int i=0; i < sectorcount; i++)
926   {
927      position = secno * secsize + gap1;
928      // Sync
929      count = fm? 6 : 10;
930      while (count-- > 0) trackdata[position++] = 0x00;
931
932      if (!fm)
933      {
934         trackdata[position++] = 0xa1;
935         trackdata[position++] = 0xa1;
936         trackdata[position++] = 0xa1;
937      }
938      trackdata[position++] = 0xfe;   // IDAM / ident
939
940      // Header
941      trackdata[position++] = track;
942      trackdata[position++] = head;
943      trackdata[position++] = i;
944      trackdata[position++] = 1;
945
946      trackdata[position++] = 0xf7;
947      trackdata[position++] = 0xf7;
948
949      // Gap 2
950      count = fm? 11 : 22;
951      while (count-- > 0) trackdata[position++] = fm? 0xff : 0x4e;
952
953      // Sync
954      count = fm? 6 : 12;
955      while (count-- > 0) trackdata[position++] = 0x00;
956
957      if (!fm)
958      {
959         trackdata[position++] = 0xa1;
960         trackdata[position++] = 0xa1;
961         trackdata[position++] = 0xa1;
962      }
963      trackdata[position++] = 0xfb;
964
965      io_generic_read(io, trackdata + position, logicaltrack * tracksize + i*SECTOR_SIZE, SECTOR_SIZE);
966
967      position += SECTOR_SIZE;
968      trackdata[position++] = 0xf7;
969      trackdata[position++] = 0xf7;
970
971      // Gap 3
972      count = fm? 45 : 24;
973      while (count-- > 0) trackdata[position++] = fm? 0xff : 0x4e;
974      secno = (secno + interleave) % sectorcount;
975   }
976
977   // Gap 4
978   count = fm? 231 : 712;
979   position = sectorcount * secsize + gap1;
980   while (count-- > 0) trackdata[position++] = fm? 0xff : 0x4e;
981
982   // if (head==0 && track==0) showtrack(trackdata, 9216);
983}
984
985/*
986    For debugging. Outputs the byte array in a xxd-like way.
987*/
988void ti99_floppy_format::showtrack(UINT8* trackdata, int length)
989{
990   for (int i=0; i < length; i+=16)
991   {
992      logerror("%07x: ", i);
993      for (int j=0; j < 16; j++)
994      {
995         logerror("%02x", trackdata[i+j]);
996         if ((j&1)==1) logerror(" ");
997      }
998      logerror(" ");
999      for (int j=0; j < 16; j++)
1000      {
1001         if (trackdata[i+j] >= 32 && trackdata[i+j]<128) logerror("%c", trackdata[i+j]);
1002         else logerror(".");
1003      }
1004      logerror("\n");
1005   }
1006}
1007
1008/*
1009    Write the data to the disk. We have a list of sector positions, so we
1010    just need to go through that list and save each sector in the track data.
1011*/
1012void ti99_sdf_format::write_track(io_generic *io, UINT8 *trackdata, int *sector, int track, int head, int maxsect, int maxtrack, int numbytes)
1013{
1014   int logicaltrack = head * maxtrack;
1015   logicaltrack += ((head&1)==0)?  track : (maxtrack - 1 - track);
1016   int trackoffset = logicaltrack * maxsect * SECTOR_SIZE;
1017
1018//  if (head==0 && track==0) showtrack(trackdata, 9216);
1019
1020   for (int i=0; i < maxsect; i++)
1021      io_generic_write(io, trackdata + sector[i], trackoffset + i * SECTOR_SIZE, SECTOR_SIZE);
1022}
1023
1024const floppy_format_type FLOPPY_TI99_SDF_FORMAT = &floppy_image_format_creator<ti99_sdf_format>;
1025
1026/*
1027    Track Dump Format
1028    -----------------
1029    The Track Dump Format is also known as pc99 (again, named after the first
1030    TI emulator to use this format). It is a contiguous sequence of track
1031    contents, containing all information including the data values of the
1032    address marks and CRC, but it does not contain clock signals.
1033    Therefore, the format requires that the address marks be at the same
1034    positions within each track.
1035
1036    Different to earlier implementations of the TDF format, we stay much
1037    closer to the specification. Deviations (like different gap sizes) are
1038    automatically rectified. It does not make sense to have a format that
1039    pretends to be an almost precise track image and then fail to load in
1040    other emulations because of small deviations.
1041    For precise track images there are better suited formats.
1042
1043    For FM recording, each track is exactly 3253 bytes long in this format.
1044    For MFM recording, track length is 6872 bytes.
1045
1046    Accordingly, we get a multiple of these values as the image length.
1047    There are no single-sided images (when single-sided, the upper half of
1048    the image is empty).
1049
1050    DSSD: 260240 bytes
1051    DSDD: 549760 bytes
1052
1053    We do not support other geometries in this format. One exception: We accept
1054    images of double size which may be generated when a 40-track disk is
1055    modified in an 80-track drive. This will automatically cause the creation
1056    of an 80-track image.
1057
1058    Tracks are stored from outside to inside of head 0, then outside to inside of head 1:
1059
1060    (Head,Track): (0,0) (0,1) (0,2) ... (0,38) (0,39) (1,0) (1,1) ... (1,39)
1061*/
1062const char *ti99_tdf_format::name() const
1063{
1064   return "tdf";
1065}
1066
1067const char *ti99_tdf_format::description() const
1068{
1069   return "TI99 track dump floppy disk image";
1070}
1071
1072const char *ti99_tdf_format::extensions() const
1073{
1074   return "dsk,dtk";
1075}
1076
1077/*
1078    Determine whether the image file can be interpreted as a track dump
1079*/
1080int ti99_tdf_format::identify(io_generic *io, UINT32 form_factor)
1081{
1082   UINT64 file_size = io_generic_size(io);
1083   int vote = 0;
1084   UINT8 trackdata[2000];
1085
1086   // Do we have a plausible image size? From the size alone we only give a 50 percent vote.
1087   if ((file_size == 260240) || (file_size == 549760) || (file_size == 1099520))
1088      vote = 50;
1089
1090   if (vote > 0)
1091   {
1092      if (TRACE) logerror("ti99_dsk: Image looks like a TDF image\n");
1093
1094      // Get some bytes from track 0
1095      io_generic_read(io, trackdata, 0, 2000);
1096
1097      if (check_for_address_marks(trackdata, floppy_image::FM)==true || check_for_address_marks(trackdata, floppy_image::MFM)==true) vote=100;
1098      else
1099      {
1100         if (TRACE) logerror("ti99_dsk: Image does not comply with TDF; may be broken or unformatted\n");
1101      }
1102   }
1103   else if (TRACE) logerror("ti99_dsk: Disk image is not a TDF image\n");
1104   return vote;
1105}
1106
1107/*
1108    Find the proper format for a given image file. We determine the cell size,
1109    but we do not care about the sector size (only needed by the SDF converter).
1110*/
1111void ti99_tdf_format::determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads)
1112{
1113   UINT64 file_size = io_generic_size(io);
1114   heads = 2;  // TDF only supports two-sided recordings
1115
1116   if (file_size % get_track_size(2000, 0)==0) cell_size = 2000;
1117   else if (file_size % get_track_size(4000, 0)==0) cell_size = 4000;
1118
1119   // We could check for the content, but if we find that the content is
1120   // FM and the size implies MFM, the calculated track count will be wrong.
1121}
1122
1123/*
1124    For TDF this just amounts to loading the track from the image file.
1125*/
1126void ti99_tdf_format::load_track(io_generic *io, UINT8 *trackdata, int head, int track, int sectorcount, int trackcount, int cellsize)
1127{
1128   int offset = ((trackcount * head) + track) * get_track_size(cellsize, 0);
1129   io_generic_read(io, trackdata, offset, get_track_size(cellsize, 0));
1130}
1131
1132/*
1133    Also here, we just need to write the complete track on the image file.
1134*/
1135void ti99_tdf_format::write_track(io_generic *io, UINT8 *trackdata, int *sector, int track, int head, int maxsect, int maxtrack, int numbytes)
1136{
1137   int offset = ((maxtrack * head) + track) * numbytes;
1138   io_generic_write(io, trackdata, offset, numbytes);
1139}
1140
1141int ti99_tdf_format::get_track_size(int cell_size, int sector_count)
1142{
1143   if (cell_size == 4000) return 3253;
1144   if (cell_size == 2000) return 6872;
1145   return 0;
1146}
1147
9031148const floppy_format_type FLOPPY_TI99_TDF_FORMAT = &floppy_image_format_creator<ti99_tdf_format>;
9041149
9051150
trunk/src/lib/formats/ti99_dsk.h
r32412r32413
44
55    TI99 and Geneve disk images
66
7    Michael Zapf, Feb 2014
7    Michael Zapf, Sept 2014
88
99*********************************************************************/
1010
r32412r32413
1414#include "flopimg.h"
1515#include "wd177x_dsk.h"
1616
17class ti99_floppy_format : public floppy_image_format_t
18{
19public:
20   bool supports_save() const { return true; }
21   bool load(io_generic *io, UINT32 form_factor, floppy_image *image);
22   bool save(io_generic *io, floppy_image *image);
23
24protected:
25   int decode_bitstream(const UINT8 *bitstream, UINT8 *trackdata, int *sector, int cell_count, int encoding, UINT8 gapbytes, int track_size);
26   UINT8 get_data_from_encoding(UINT16 raw);
27
28   virtual int min_heads() =0;
29
30   virtual void determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads) =0;
31   virtual int get_track_size(int cell_size, int sector_count) =0;
32   virtual void load_track(io_generic *io, UINT8 *trackdata, int head, int track, int sectorcount, int trackcount, int cellsize) =0;
33   virtual void write_track(io_generic *io, UINT8 *trackdata, int *sector, int track, int head, int maxsect, int maxtrack, int numbytes) =0;
34
35   int get_encoding(int cell_size);
36   int get_track_size(int cell_size);
37
38   void generate_track_fm(int track, int head, int cell_size, UINT8* trackdata, floppy_image *image);
39   void generate_track_mfm(int track, int head, int cell_size, UINT8* trackdata, floppy_image *image);
40
41   bool check_for_address_marks(UINT8* trackdata, int encoding);
42
43   // Debugging
44   void showtrack(UINT8* trackdata, int length);
45};
46
1747/*
1848    Modern implementation of the sector dump format.
1949*/
20class ti99_sdf_format : public wd177x_format
50class ti99_sdf_format : public ti99_floppy_format
2151{
2252public:
23   ti99_sdf_format(): wd177x_format(formats) { }
24
2553   int identify(io_generic *io, UINT32 form_factor);
26
2754   const char *name() const;
2855   const char *description() const;
2956   const char *extensions() const;
30   bool supports_save() const;
3157
3258private:
33   static const format formats[];
34   floppy_image_format_t::desc_e* get_desc_fm(const format &f, int &current_size, int &end_gap_index);
35   floppy_image_format_t::desc_e* get_desc_mfm(const format &f, int &current_size, int &end_gap_index);
59   void determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads);
60   int get_track_size(int cell_size, int sector_count);
61   void write_track(io_generic *io, UINT8 *trackdata, int *sector, int track, int head, int maxsect, int maxtrack, int numbytes);
62   void load_track(io_generic *io, UINT8 *trackdata, int head, int track, int sectorcount, int trackcount, int cellsize);
3663
37   int get_format_param(io_generic *io);
38   int get_image_offset(const format &f, int head, int track);
39   int find_size(io_generic *io, UINT32 form_factor);
64   // This format supports single-sided images
65   int min_heads() { return 1; }
4066
41   typedef struct ti99_vib
67   struct ti99vib
4268   {
4369      char    name[10];       // volume name (10 characters, pad with spaces)
4470      UINT8   totsecsMSB;     // disk length in sectors (big-endian) (usually 360, 720 or 1440)
r32412r32413
5278      UINT8   res[36];        // Empty for traditional disks, or up to 3 directory pointers
5379      UINT8   abm[200];       // allocation bitmap: a 1 for each sector in use (sector 0 is LSBit of byte 0,
5480                        // sector 7 is MSBit of byte 0, sector 8 is LSBit of byte 1, etc.)
55   } vib_t;
81   };
5682};
5783
5884extern const floppy_format_type FLOPPY_TI99_SDF_FORMAT;
r32412r32413
6086/*
6187    Modern implementation of the track dump format.
6288*/
63class ti99_tdf_format : public floppy_image_format_t
89class ti99_tdf_format : public ti99_floppy_format
6490{
6591public:
66
6792   int identify(io_generic *io, UINT32 form_factor);
68
69   bool load(io_generic *io, UINT32 form_factor, floppy_image *image);
70   bool save(io_generic *io, floppy_image *image);
71
7293   const char *name() const;
7394   const char *description() const;
7495   const char *extensions() const;
75   bool supports_save() const;
7696
7797private:
98   void determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads);
99   void load_track(io_generic *io, UINT8 *trackdata, int head, int track, int sectorcount, int trackcount, int cellsize);
100   void write_track(io_generic *io, UINT8 *trackdata, int *sector, int track, int head, int maxsect, int maxtrack, int numbytes);
101   int get_track_size(int cell_size, int sector_count);
78102
79   struct format {
80      UINT32 form_factor;      // See floppy_image for possible values
81      UINT32 variant;          // See floppy_image for possible values
82      UINT32 encoding;         // See floppy_image for possible values
83      int cell_size;           // See floppy_image_format_t for details
84      int sector_count;
85      int track_count;
86      int head_count;
87      int track_size;
88      UINT8 gapbytes;
89   };
90
91   static const format formats[];
92
93   int get_format_param(io_generic *io);
94   int get_image_offset(const format &f, int head, int track);
95   int find_size(io_generic *io, UINT32 form_factor);
96
97   void generate_track_fm(int track, int head, int cell_size, UINT8* trackdata, floppy_image *image);
98   void generate_track_mfm(int track, int head, int cell_size, UINT8* trackdata, floppy_image *image);
99
100   int find_start(UINT8* trackdata, int track_size, int encoding);
101   bool has_byteseq(UINT8* trackdata, int track_size, UINT8 byte, int pos, int count);
102
103   void extract_track_from_bitstream(const UINT8 *bitstream, int track_size, UINT8 *trackdata);
103   // This format only supports double-sided images
104   int min_heads() { return 2; }
104105};
105106
106107extern const floppy_format_type FLOPPY_TI99_TDF_FORMAT;

Previous 199869 Revisions Next


© 1997-2024 The MAME Team