UrForth: removed some unused code; oops! fixed bug in C kernel basic compiler (negati...
[urasm.git] / src / libfdc / dskldr_dsk.c
blob739b687cfbd4322f24bae8c31bf55f9f4935488e
1 /*
2 * disk images I/O
3 * based on the code by SAM style
4 * Understanding is not required. Only obedience.
6 * This program is free software. It comes without any warranty, to
7 * the extent permitted by applicable law. You can redistribute it
8 * and/or modify it under the terms of the Do What The Fuck You Want
9 * To Public License, Version 2, as published by Sam Hocevar. See
10 * http://sam.zoy.org/wtfpl/COPYING for more details.
12 #include "dskldr.h"
14 //#include "filetypes.h"
16 // +0x00 signature (23)
17 // +0x17 DiskInfo\r\n
18 // +0x22 disk info block
20 typedef struct LIBFDC_PACKED {
21 uint8_t byte0d0f[4]; // unused
22 uint8_t track;
23 uint8_t side;
24 uint8_t dataRate; // unknown, SD, HD, ED
25 uint8_t recMode; // unknown, FM, MFM
26 uint8_t secSize;
27 uint8_t secCount;
28 uint8_t gap3Size;
29 uint8_t filler;
30 uint8_t sectorInfo[0x100-0x18]; // max 29 (x 8 bytes)
31 } TrackInfBlock;
34 typedef struct LIBFDC_PACKED {
35 uint8_t track;
36 uint8_t side;
37 uint8_t sector;
38 uint8_t size;
39 uint8_t sr1;
40 uint8_t sr2;
41 uint8_t bslo;
42 uint8_t bshi;
43 } SectorInfBlock; // 8 bytes
46 static const char edsksgn[8] = "EXTENDED";
47 static const char dsksgn[8] = "MV - CPC";
50 int dskLoadDSK (Floppy *flp, FILE *fl) {
51 //fprintf(stderr, "*** loading DSK (000) (fpl=%p; ins=%d) ***\n", flp, (flp ? flp->insert : -1));
52 if (!flp) return FLPERR_SHIT;
53 if (fl == NULL) return FLPERR_SHIT;
55 FDCSector secs[256];
56 char sigBuf[256];
58 //fprintf(stderr, "*** loading DSK ***\n");
59 // disk info block
60 if (fread(sigBuf, 256, 1, fl) != 1) {
61 libfdcMsg(LIBFDC_MSG_ERROR, "cannot load DSK header");
62 return FLPERR_SHIT;
65 // check disk format
66 int ext = -1;
67 if (!strncmp(sigBuf, edsksgn, 8)) {
68 // extend dsk format
69 ext = 1;
70 } else if (!strncmp(sigBuf, dsksgn, 8)) {
71 // common dsk format
72 ext = 0;
74 if (ext < 0) {
75 libfdcMsg(LIBFDC_MSG_ERROR, "invalid DSK signature");
76 return FLPERR_SHIT;
79 // clear disk
80 for (int i = 0; i < 168; ++i) {
81 memset(flp->data[i].byte, 0, FLP_MAX_TRACK_SIZE);
82 flpFillFields(flp, i, 0);
85 int trkcnt = sigBuf[0x30]&0xff;
86 int sidcnt = sigBuf[0x31]&0xff;
88 if (sidcnt == 0 || sidcnt > 2) {
89 libfdcMsg(LIBFDC_MSG_ERROR, "invalid number of DSK sides (%d)", sidcnt);
90 return FLPERR_SHIT;
93 if (trkcnt == 0) {
94 libfdcMsg(LIBFDC_MSG_ERROR, "DSK contains no tracks");
95 return FLPERR_SHIT;
98 if (trkcnt > 86) {
99 libfdcMsg(LIBFDC_MSG_WARNING, "too many cylinders in DSK (%d), truncated to %d", trkcnt, 86);
100 trkcnt = 86;
103 libfdcMsg(LIBFDC_MSG_DEBUG, "DSK: %d head%s, %d cylinders", sidcnt, (sidcnt == 2 ? "s" :""), trkcnt);
104 int tlen = (sigBuf[0x32]&0xff)|((sigBuf[0x33]&0xff)<<8);
105 int tr = 0;
106 int pos = 0x100; // 1st track allways @ 0x100
107 int err = 0;
108 for (int i = 0; i < trkcnt*sidcnt && !err; ++i) {
109 int rtlen = (ext ? sigBuf[0x34+i]<<8 : tlen);
110 if (rtlen > 0) {
111 // move to track info block
112 if (fseek(fl, pos, SEEK_SET) < 0) {
113 libfdcMsg(LIBFDC_MSG_ERROR, "cannot seek to DSK track info block for track %d", i);
114 return FLPERR_SHIT;
116 if (fread(sigBuf, 12, 1, fl) != 1) {
117 libfdcMsg(LIBFDC_MSG_ERROR, "cannot read DSK track info block for track %d", i);
118 return FLPERR_SHIT;
120 // track-info?
121 if (strncmp(sigBuf, "Track-Info\r\n", 12) == 0) {
122 TrackInfBlock tib;
123 if (fread((char *)&tib, sizeof(TrackInfBlock), 1, fl) != 1) return FLPERR_SHIT;
124 SectorInfBlock *sib = (SectorInfBlock *)&tib.sectorInfo;
125 for (int sc = 0; sc < tib.secCount; ++sc) {
126 int slen;
127 if (!ext) {
128 if (sib[sc].size > 5) {
129 slen = 0x1800;
130 } else {
131 slen = (0x80<<sib[sc].size)&0xffff;
133 } else {
134 slen = sib[sc].bslo|(sib[sc].bshi<<8);
136 secs[sc].trk = sib[sc].track;
137 secs[sc].head = sib[sc].side;
138 secs[sc].sec = sib[sc].sector;
139 secs[sc].sz = sib[sc].size;
140 secs[sc].type = 0xfb;
141 //fprintf(stderr, " sector(tr=%d;sc=%d): C=%d; H=%d; R=%d; N=%d; slen=%d\n", tr, sc, sib[sc].track, sib[sc].side, sib[sc].sector, sib[sc].size, slen);
142 if (fread((char *)secs[sc].data, slen, 1, fl) != 1) return FLPERR_SHIT;
144 // calculate good CRCs
145 flpFormatTracks(flp, tr, secs, tib.secCount, FLP_FORMAT_TRACK_CALC_CRC);
146 ++tr;
147 if (sidcnt == 1) ++tr;
148 pos += rtlen;
149 } else {
150 libfdcMsg(LIBFDC_MSG_ERROR, "invalid DSK track info block signature for track %d", i);
151 err = 1; //ERR_DSK_SIGN;
153 } else {
154 //flpFormatTracks(flp, tr, secs, tib.secCount, FLP_FORMAT_TRACK_CALC_CRC);
155 // flp_format_trk(flp, tr, 10, 512, NULL);
156 ++tr;
157 if (sidcnt == 1) ++tr;
160 flp->protect = 0;
161 flp->doubleSide = (sidcnt > 1 ? 1 : 0);
162 flp->trk80 = (trkcnt > 42 ? 1 : 0);
163 flp->insert = 1;
164 flp->changed = 0;
165 return (err ? FLPERR_SHIT : FLPERR_OK);
169 static long saveTrackDSK (Floppy *flp, int trk, int side, FILE *fl) {
170 TrackInfBlock tinf;
171 FDCSector sdata[29];
172 long fpos = ftell(fl);
173 if (fpos < 0) return -1;
174 int sec = 0;
175 int pos = 0;
176 int dsz, dps;
177 int mdsz = 0;
178 int rtrk = (trk<<1)|side;
179 side &= 1;
180 memset(&tinf, 0, sizeof(TrackInfBlock));
181 // scan track & collect sectors info & data
182 for (pos = 0; pos < FLP_MAX_TRACK_SIZE && sec < 29; ++pos) {
183 if (flp->data[rtrk].field[pos] == 1) {
184 // sector info
185 sdata[sec].trk = flp->data[rtrk].byte[pos++]; // C
186 sdata[sec].head = flp->data[rtrk].byte[pos++];// H
187 sdata[sec].sec = flp->data[rtrk].byte[pos++]; // R
188 sdata[sec].sz = flp->data[rtrk].byte[pos++]&7;// N
189 pos += 2; // skip crc
190 if (sdata[sec].sz > mdsz) mdsz = sdata[sec].sz; // max N
191 dsz = 128<<sdata[sec].sz; // sector data size
192 if (dsz > 0x1800) dsz = 0x1800;
193 dps = flp->data[rtrk].map[sdata[sec].sec]; // position of sector data
194 if (dps > 0) sdata[sec].type = flp->data[rtrk].byte[dps-1]; // sector data type (FB | F8)
195 memcpy(sdata[sec].data, flp->data[rtrk].byte+dps, dsz); // copy sector data
196 ++sec;
199 if (sec < 1) return 0; // no sectors found, no data written, size = 0
200 // fill track info
201 tinf.track = trk&0xff;
202 tinf.side = side&1;
203 tinf.secSize = mdsz&7; // 0 @ extend dsk ?
204 tinf.secCount = sec&0xff;
205 tinf.gap3Size = 0x1a;
206 tinf.filler = 0xe5;
207 pos = 0;
208 for (int i = 0; i < sec; ++i) {
209 tinf.sectorInfo[pos] = sdata[i].trk;
210 tinf.sectorInfo[pos+1] = sdata[i].head;
211 tinf.sectorInfo[pos+2] = sdata[i].sec;
212 tinf.sectorInfo[pos+3] = sdata[i].sz;
213 dsz = 128<<sdata[i].sz;
214 if (i == sec-1) tinf.sectorInfo[pos+4] = 0x80; // end of cylinder
215 tinf.sectorInfo[pos+6] = dsz&0xff;
216 tinf.sectorInfo[pos+7] = (dsz>>8)&0xff;
217 pos += 8;
219 // save track info block
220 if (fwrite("Track-Info\r\n", 12, 1, fl) != 1) return -1;
221 if (fwrite(&tinf, sizeof(TrackInfBlock), 1, fl) != 1) return -1;
222 // save sectors data
223 for (int i = 0; i < sec; ++i) {
224 dsz = 128<<sdata[i].sz;
225 if (dsz > 0x1800) dsz = 0x1800;
226 if (fwrite(sdata[i].data, dsz, 1, fl) != 1) return -1;
228 long epos = ftell(fl);
229 if (epos < 0) return -1;
230 return epos-fpos;
234 static const char *sign = "EXTENDED CPC DSK File\r\nDisk-Info\r\nZXEmuT ";
236 int dskSaveDSK (Floppy *flp, FILE *fl) {
237 if (!flp || fl == NULL || !flp->insert) return FLPERR_SHIT;
238 uint8_t buf[256];
239 memset(buf, 0, 0x100);
240 memcpy(buf, sign, 0x22+0x0e);
241 // 30 = track count, will be updated later
242 // 31: 1 | 2 sides
243 // 32,33 = 0 @ extend format
244 // 34+N = size of track N (from Track-Info to Track-Info)
245 // fwrite(buf, 256, 1, fl); // signature + disk info : buf will be saved later
246 if (fseek(fl, 256, SEEK_SET) < 0) return FLPERR_SHIT;
247 int cpos = 0x34;
248 long isize;
249 int ds = 0;
250 int tcount = 0;
251 for (int i = 0; i < 86; ++i) {
252 isize = saveTrackDSK(flp, i, 0, fl);
253 buf[cpos] = (isize>>8)&0xff;
254 ++cpos;
255 if (isize > 0) tcount = i+1;
256 if (flp->doubleSide) {
257 isize = saveTrackDSK(flp, i, 1, fl);
258 if (isize < 0) return FLPERR_SHIT;
259 if (isize > 0) ds = 1;
260 buf[cpos] = (isize>>8)&0xff;
261 ++cpos;
262 if (isize > 0) tcount = i+1;
265 buf[0x30] = (tcount < 43 ? 42 : 84); // = tcount & 0xff;
266 buf[0x31] = (ds ? 2 : 1);
267 if (!ds) {
268 cpos = 0x36; // 0x34 doesn't changed
269 tcount = 0x35;
270 while (cpos < 256) {
271 buf[tcount] = buf[cpos];
272 buf[cpos] = 0;
273 ++tcount;
274 cpos += 2;
277 // save disk info block
278 if (fseek(fl, 0, SEEK_SET) < 0) return FLPERR_SHIT;
279 if (fwrite(buf, 256, 1, fl) != 1) return FLPERR_SHIT;
280 // update name
281 flp->changed = 0;
282 return FLPERR_OK;