1 // license:BSD-3-Clause
2 // copyright-holders:Wilbert Pol, tim lindner
3 /*********************************************************************
4 
5     formats/sdf_dsk.h
6 
7     SDF disk images. Format created by Darren Atkinson for use with
8     his CoCoSDC floppy disk emulator.
9 
10     http://cocosdc.blogspot.com/p/sd-card-socket-sd-card-socket-is-push.html
11 
12 *********************************************************************/
13 
14 #include "sdf_dsk.h"
15 #include <cassert>
16 
sdf_format()17 sdf_format::sdf_format()
18 {
19 }
20 
21 
name() const22 const char *sdf_format::name() const
23 {
24 	return "sdf";
25 }
26 
27 
description() const28 const char *sdf_format::description() const
29 {
30 	return "SDF disk image";
31 }
32 
33 
extensions() const34 const char *sdf_format::extensions() const
35 {
36 	return "sdf";
37 }
38 
39 
identify(io_generic * io,uint32_t form_factor)40 int sdf_format::identify(io_generic *io, uint32_t form_factor)
41 {
42 	uint8_t header[HEADER_SIZE];
43 
44 	uint64_t size = io_generic_size(io);
45 
46 	if (size < HEADER_SIZE)
47 	{
48 		return 0;
49 	}
50 
51 	io_generic_read(io, header, 0, HEADER_SIZE);
52 
53 	int tracks = header[4];
54 	int heads = header[5];
55 
56 	// Check magic bytes
57 	if (header[0] != 'S' || header[1] != 'D' || header[2] != 'F' || header[3] != '1')
58 	{
59 		return 0;
60 	}
61 
62 	// Check heads
63 	if (heads != 1 && heads != 2)
64 	{
65 		return 0;
66 	}
67 
68 	if (size == HEADER_SIZE + heads * tracks * TOTAL_TRACK_SIZE)
69 	{
70 		return 100;
71 	}
72 
73 	return 0;
74 }
75 
76 
load(io_generic * io,uint32_t form_factor,floppy_image * image)77 bool sdf_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
78 {
79 	uint8_t header[HEADER_SIZE];
80 	std::vector<uint8_t> track_data(TOTAL_TRACK_SIZE);
81 	std::vector<uint32_t> raw_track_data;
82 
83 	io_generic_read(io, header, 0, HEADER_SIZE);
84 
85 	const int tracks = header[4];
86 	const int heads = header[5];
87 
88 	if (heads == 2)
89 	{
90 		image->set_variant(floppy_image::DSDD);
91 	}
92 	else
93 	{
94 		image->set_variant(floppy_image::SSDD);
95 	}
96 
97 	for (int track = 0; track < tracks; track++)
98 	{
99 		for (int head = 0; head < heads; head++)
100 		{
101 			int iam_location = -1;
102 			int idam_location[SECTOR_SLOT_COUNT+1];
103 			int dam_location[SECTOR_SLOT_COUNT+1];
104 			raw_track_data.clear();
105 
106 			// Read track
107 			io_generic_read(io, &track_data[0], HEADER_SIZE + ( heads * track + head ) * TOTAL_TRACK_SIZE, TOTAL_TRACK_SIZE);
108 
109 			int sector_count = track_data[0];
110 
111 			if (sector_count > SECTOR_SLOT_COUNT) return false;
112 
113 			// Transfer IDAM and DAM locations to table
114 			for (int i = 0; i < SECTOR_SLOT_COUNT+1; i++)
115 			{
116 				if (i < sector_count )
117 				{
118 					idam_location[i] = ((track_data[ 8 * (i+1) + 1] << 8 | track_data[ 8 * (i+1)]) & 0x3FFF) - 4;
119 					dam_location[i] = ((track_data[ 8 * (i+1) + 1 + 2] << 8 | track_data[ 8 * (i+1) + 2]) & 0x3FFF) - 4;
120 
121 					if (idam_location[i] > TOTAL_TRACK_SIZE) return false;
122 					if (dam_location[i] > TOTAL_TRACK_SIZE) return false;
123 				}
124 				else
125 				{
126 					idam_location[i] = -1;
127 					dam_location[i] = -1;
128 				}
129 			}
130 
131 			// Find IAM location
132 			for (int i = idam_location[0] - 1; i >= TRACK_HEADER_SIZE + 3; i--)
133 			{
134 				// It's usually 3 bytes but several dumped tracks seem to contain only 2 bytes
135 				if (track_data[i] == 0xfc && track_data[i-1] == 0xc2 && track_data[i-2] == 0xc2)
136 				{
137 					iam_location = i - 3;
138 					break;
139 				}
140 			}
141 
142 			int idam_index = 0;
143 			int dam_index = 0;
144 			for (int offset = TRACK_HEADER_SIZE; offset < TRACK_HEADER_SIZE + TRACK_SIZE; offset++)
145 			{
146 				if (offset == iam_location)
147 				{
148 					// Write IAM
149 					raw_w(raw_track_data, 16, 0x5224);
150 					raw_w(raw_track_data, 16, 0x5224);
151 					raw_w(raw_track_data, 16, 0x5224);
152 					offset += 3;
153 				}
154 
155 				if (offset == idam_location[idam_index])
156 				{
157 					raw_w(raw_track_data, 16, 0x4489);
158 					raw_w(raw_track_data, 16, 0x4489);
159 					raw_w(raw_track_data, 16, 0x4489);
160 					idam_index += 1;
161 					offset += 3;
162 				}
163 
164 				if (offset == dam_location[dam_index])
165 				{
166 					raw_w(raw_track_data, 16, 0x4489);
167 					raw_w(raw_track_data, 16, 0x4489);
168 					raw_w(raw_track_data, 16, 0x4489);
169 					dam_index += 1;
170 					offset += 3;
171 				}
172 
173 				mfm_w(raw_track_data, 8, track_data[offset]);
174 			}
175 
176 			generate_track_from_levels(track, head, raw_track_data, 0, image);
177 		}
178 	}
179 
180 	return true;
181 }
182 
183 
save(io_generic * io,floppy_image * image)184 bool sdf_format::save(io_generic *io, floppy_image *image)
185 {
186 	return false;
187 }
188 
189 
supports_save() const190 bool sdf_format::supports_save() const
191 {
192 	return false;
193 }
194 
195 
196 const floppy_format_type FLOPPY_SDF_FORMAT = &floppy_image_format_creator<sdf_format>;
197