UrForth: some microoptimisations
[urasm.git] / src / libfdc / floppy.c
blob8758b6cd774c063f23659044db55eeb8c85428e9
1 /*
2 * WD1793/uPD765 emulator
3 * Copyright (c) 2009-..., SAM style
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is furnished
10 * to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
17 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
20 * THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * changes by Ketmar // Invisible Vector
24 * Understanding is not required. Only obedience.
25 * git commit: 84b4cb3f749ff3cb954a202b3c65d7b53ee08273
27 #include "floppy.h"
30 //==========================================================================
32 // flpCreate
34 //==========================================================================
35 Floppy *flpCreate (int id) {
36 Floppy *flp = malloc(sizeof(Floppy));
37 memset(flp, 0, sizeof(Floppy));
38 flp->id = id;
39 flp->trk80 = 1;
40 flp->doubleSide = 1;
41 flp->trk = 0;
42 flp->pos = 0;
43 return flp;
47 //==========================================================================
49 // flpDestroy
51 //==========================================================================
52 void flpDestroy (Floppy *flp) {
53 if (flp) {
54 free(flp);
59 //==========================================================================
61 // flpEject
63 //==========================================================================
64 void flpEject (Floppy *flp) {
65 if (flp) {
66 flp->insert = 0;
67 flp->changed = 0;
72 //==========================================================================
74 // flpWr
76 //==========================================================================
77 int flpWr (Floppy *flp, int hd, uint8_t val) {
78 if (!flp) return FLPERR_SHIT;
79 flp->wr = 1;
80 hd &= 1;
81 if (hd && !flp->doubleSide) return FLPERR_SHIT; // saving on HD1 for SS Floppy
82 if (!flp->insert) return FLPERR_SHIT;
83 flp->changed = 1;
84 flp->data[(flp->trk<<1)|hd].byte[flp->pos] = val;
85 return FLPERR_OK;
89 //==========================================================================
91 // flpRd
93 //==========================================================================
94 uint8_t flpRd (Floppy *flp, int hd) {
95 if (!flp) return 0xffU;
96 flp->rd = 1;
97 hd &= 1;
98 if (!flp->insert) return 0xffU;
99 if (hd && !flp->doubleSide) return 0xffU;
100 return flp->data[(flp->trk<<1)|hd].byte[flp->pos];
104 //==========================================================================
106 // flpStep
108 //==========================================================================
109 void flpStep (Floppy *flp, int dir) {
110 if (!flp) return;
111 switch (dir) {
112 case FLP_FORWARD:
113 if (flp->trk < (flp->trk80 ? 86 : 43)) ++flp->trk;
114 break;
115 case FLP_BACK:
116 if (flp->trk > 0) --flp->trk;
117 break;
122 //==========================================================================
124 // flpNext
126 //==========================================================================
127 int flpNext (Floppy *flp, int fdcSide) {
128 if (!flp) return 0;
129 int res = 0;
130 int rtrk = (flp->trk<<1);
131 if (flp->doubleSide && fdcSide) ++rtrk;
132 if (flp->insert) {
133 ++flp->pos;
134 if (flp->pos >= FLP_MAX_TRACK_SIZE) {
135 flp->pos = 0;
136 res = 1;
138 flp->index = (flp->pos < 4 ? 1 : 0); // ~90ms index pulse
139 flp->field = flp->data[rtrk].field[flp->pos]&0x0f;
140 } else {
141 flp->field = 0;
143 return res;
147 //==========================================================================
149 // flpPrev
151 //==========================================================================
152 void flpPrev (Floppy *flp, int fdcSide) {
153 if (!flp) return;
154 int rtrk = (flp->trk<<1);
155 if (flp->doubleSide && fdcSide) ++rtrk;
156 if (flp->insert) {
157 if (flp->pos > 0) {
158 --flp->pos;
159 } else {
160 flp->pos = FLP_MAX_TRACK_SIZE-1;
162 flp->field = flp->data[rtrk].field[flp->pos]&0x0f;
163 } else {
164 flp->field = 0;
169 //==========================================================================
171 // flpFillFields
173 //==========================================================================
174 int flpFillFields (Floppy *flp, int tr, uint32_t flag) {
175 if (!flp) return FLPERR_SHIT;
176 if (tr < 0 || tr > 255) return FLPERR_SHIT;
177 int res = FLPERR_OK;
178 int bcnt = 0; // number of bytes in the current field
179 uint8_t fld = 0;
180 uint8_t *cpos = flp->data[tr].byte; // first byte of the current field
181 uint8_t *bpos = cpos; // current byte
182 uint8_t scn = 0; // sector number (1+)
183 uint8_t sct = 1; // sector size code
184 for (unsigned i = 0; i < 256; ++i) {
185 flp->data[tr].map[i] = 0;
186 flp->data[tr].mapaddr[i] = 0;
187 flp->data[tr].mapraw[i] = 0;
188 flp->data[tr].mapaddrraw[i] = 0;
190 uint8_t scraw = 0; // current "raw" sector index for address map
191 int lastscraw = -1; // current "raw" sector index for data map
192 for (unsigned i = 0; i < FLP_MAX_TRACK_SIZE; ++i, ++bpos) {
193 flp->data[tr].field[i] = fld;
194 fld &= 0x0f; // reset flags
195 if (flag&FLP_FILL_FIELDS_SVF) {
196 if (fld == 0) {
197 if (*bpos == 0xf5) *bpos = 0xa1;
198 if (*bpos == 0xf6) *bpos = 0xc2;
201 // process field data
202 if (bcnt > 0) {
203 // we are in field yet
204 --bcnt;
205 if (bcnt == 0) {
206 // field ends
207 // fld should not be 0 here
208 // other field types needs CRC, so calculate it
209 if (fld < 4) {
210 // always calculate CRC for address field
211 if (fld == 1 || (flag&FLP_FILL_FIELDS_CRC)) {
212 cpos -= 3; // including a1,a1,a1
213 uint16_t crc = flpCalcWDCRC(cpos, bpos-cpos+1);
214 // make "bad CRC" for data field, if requested
215 if (fld != 1 && (flag&FLP_FILL_FIELDS_INV_CRC)) crc ^= 0xaa55u;
216 if (i+1 < FLP_MAX_TRACK_SIZE) *(bpos+1) = ((crc&0xff00u)>>8); else res = FLPERR_NOSPACE;
217 if (i+2 < FLP_MAX_TRACK_SIZE) *(bpos+2) = (crc&0xffu); else res = FLPERR_NOSPACE;
219 fld = 4; // "CRC field" type
220 bcnt = 2; // two bytes
221 } else {
222 fld = 0; // "gap field" type
225 } else {
226 // out of the field, check type and setup new field
227 const uint8_t bt = *bpos;
228 if (bt == 0xfe) {
229 // address mark last byte, CHRN follows
230 cpos = bpos; // save field start
231 fld = 1; // "address field" type
232 bcnt = 4; // 4 bytes (CHRN)
233 scn = (i+3 < FLP_MAX_TRACK_SIZE ? flp->data[tr].byte[i+3] : 0); // get logical sector number
234 sct = (i+4 < FLP_MAX_TRACK_SIZE ? flp->data[tr].byte[i+4] : 0); // get sector size
235 if (i+4 < FLP_MAX_TRACK_SIZE) {
236 // remember address area for this logical sector
237 // for sectors with the same logical number, assume that the first sector always wins
238 if (scn > 0 && flp->data[tr].mapaddr[scn] == 0) flp->data[tr].mapaddr[scn] = i+1;
239 // remember address area for this "raw" sector
240 lastscraw = scraw;
241 flp->data[tr].mapaddrraw[scraw++] = i+1;
243 } else if (bt == 0xfb || bt == 0xf8) {
244 // 0xfb -- normal data
245 // 0xf8 -- deleted data
246 cpos = bpos; // save field start
247 fld = (bt == 0xfb ? 2 : 3); // set field type
248 bcnt = 128<<(sct&3); // bytes in field (k8: why `&3`?)
249 if (i+1 < FLP_MAX_TRACK_SIZE) {
250 // remember data area for this logical sector
251 // for sectors with the same logical number, assume that the first sector always wins
252 if (scn > 0 && flp->data[tr].map[scn] == 0) {
253 flp->data[tr].map[scn] = i+1;
254 scn = 0; // reset logical sector number, we don't need it anymore
256 // remember data area for this "raw" sector
257 if (lastscraw >= 0) {
258 flp->data[tr].mapraw[lastscraw] = i+1;
259 lastscraw = -1;
265 return res;
269 //==========================================================================
271 // flpClearTrack
273 //==========================================================================
274 int flpClearTrack (Floppy *flp, int tr) {
275 if (!flp) return FLPERR_SHIT;
276 if (tr < 0 || tr > 255) return FLPERR_SHIT;
277 memset(flp->data[tr].byte, 0, FLP_MAX_TRACK_SIZE);
278 memset(flp->data[tr].field, 0, FLP_MAX_TRACK_SIZE);
279 memset(flp->data[tr].map, 0, sizeof(flp->data[tr].map));
280 memset(flp->data[tr].mapaddr, 0, sizeof(flp->data[tr].mapaddr));
281 memset(flp->data[tr].mapraw, 0, sizeof(flp->data[tr].mapraw));
282 memset(flp->data[tr].mapaddrraw, 0, sizeof(flp->data[tr].mapaddrraw));
283 return FLPERR_OK;
287 //==========================================================================
289 // flpClearDisk
291 //==========================================================================
292 int flpClearDisk (Floppy *flp) {
293 if (!flp) return FLPERR_SHIT;
294 for (int i = 0; i < 256; ++i) flpClearTrack(flp, i);
295 return FLPERR_OK;
299 //==========================================================================
301 // flpGetTrack
303 //==========================================================================
304 int flpGetTrack (Floppy *flp, int tr, uint8_t *dst) {
305 if (!flp || !dst) return FLPERR_SHIT;
306 if (tr < 0 || tr > 255) return FLPERR_SHIT;
307 memcpy(dst, flp->data[tr].byte, FLP_MAX_TRACK_SIZE);
308 return FLPERR_OK;
312 //==========================================================================
314 // flpGetTrackFields
316 //==========================================================================
317 int flpGetTrackFields (Floppy *flp, int tr, uint8_t *dst) {
318 if (!flp || !dst) return FLPERR_SHIT;
319 if (tr < 0 || tr > 255) return FLPERR_SHIT;
320 memcpy(dst, flp->data[tr].field, FLP_MAX_TRACK_SIZE);
321 return FLPERR_OK;
325 //==========================================================================
327 // flpPutTrack
329 //==========================================================================
330 int flpPutTrack (Floppy *flp, int tr, const void *src, int len) {
331 if (!flp || len < 0 || len > FLP_MAX_TRACK_SIZE) return FLPERR_SHIT;
332 if (tr < 0 || tr > 255) return FLPERR_SHIT;
333 if (len && !src) return FLPERR_SHIT;
334 if (flpClearTrack(flp, tr) < 0) return FLPERR_SHIT;
335 if (len > 0) memcpy(flp->data[tr].byte, src, len);
336 return flpFillFields(flp, tr, FLP_FILL_FIELDS_NONE);
340 //==========================================================================
342 // flpCalcWDCRC
344 //==========================================================================
345 uint16_t flpCalcWDCRC (const void *buf, size_t len) {
346 uint32_t crc = 0xffffU;
347 const uint8_t *ptr = (const uint8_t *)buf;
348 while (len--) {
349 crc ^= (*ptr++)<<8;
350 for (unsigned i = 0; i < 8; ++i) {
351 crc <<= 1;
352 if (crc&0x10000U) crc ^= 0x1021U;
355 return (crc&0xffffU);
360 //**************************************************************************
362 // some higher-level API
364 //**************************************************************************
367 #define FFMT_PUT_BYTE(bt_) do { \
368 if (tbleft == 0) return FLPERR_OK; \
369 --tbleft; \
370 *(ppos++) = (bt_); \
371 } while (0)
373 #define FFMT_FILL_BYTES(bt_,cnt_) do { \
374 if (tbleft == 0) return FLPERR_OK; \
375 const size_t cc = (tbleft < (cnt_) ? tbleft : (size_t)(cnt_)); \
376 tbleft -= cc; \
377 memset(ppos, (bt_), cc); \
378 } while (0)
381 //==========================================================================
383 // flpFormatTracks
385 // format a single track from sectors list
386 // <sdata> is list of <scount> sectors
387 // TODO: calculate GAP3 len !!!
389 //==========================================================================
390 int flpFormatTracks (Floppy *flp, int tr, const FDCSector *sdata, int scount, int calccrc) {
391 if (!flp || scount < 1 || scount > 255 || !sdata) return FLPERR_SHIT;
392 if (tr < 0 || tr > 255) return FLPERR_SHIT;
393 //fprintf(stderr, "flpFormatTracks:000: tr=%d; scount=%d; calccrc=%d\n", tr, scount, calccrc);
394 uint8_t *ppos = flp->data[tr].byte;
395 //const uint8_t *const stppos = ppos;
396 int dsz = 0;
397 for (int i = 0; i < scount; ++i) dsz += (128<<sdata[i].sz);
398 dsz = (FLP_MAX_TRACK_SIZE-dsz)/scount-72;
399 if (dsz < 10) return FLPERR_SHIT;
400 size_t tbleft = (size_t)FLP_MAX_TRACK_SIZE;
401 // 12 spaces
402 FFMT_FILL_BYTES(0x00u, 12);
403 ppos += 12;
404 // track mark
405 FFMT_PUT_BYTE(0xc2u);
406 FFMT_PUT_BYTE(0xc2u);
407 FFMT_PUT_BYTE(0xc2u);
408 FFMT_PUT_BYTE(0xfcu);
409 //FIXME: make this safer!
410 for (unsigned sc = 0; sc < (unsigned)scount; ++sc) {
411 //size_t tbleft = (ppos >= stppos+FLP_MAX_TRACK_SIZE ? (size_t)0u : (size_t)(ptrdiff_t)(stppos+FLP_MAX_TRACK_SIZE-ppos));
412 // 10 sync (GAP1)
413 FFMT_FILL_BYTES(0x4eu, 10);
414 ppos += 10;
415 // 12 spaces
416 FFMT_FILL_BYTES(0x00u, 12);
417 ppos += 12;
418 // address mark
419 FFMT_PUT_BYTE(0xa1u);
420 FFMT_PUT_BYTE(0xa1u);
421 FFMT_PUT_BYTE(0xa1u);
422 FFMT_PUT_BYTE(0xfeu);
423 // addr field
424 FFMT_PUT_BYTE(sdata[sc].trk);
425 FFMT_PUT_BYTE(sdata[sc].head);
426 FFMT_PUT_BYTE(sdata[sc].sec);
427 FFMT_PUT_BYTE(sdata[sc].sz);
428 // address crc (will be fixed later)
429 FFMT_PUT_BYTE(0xf7u);
430 FFMT_PUT_BYTE(0xf7u);
431 // 22 syncs (GAP2)
432 FFMT_FILL_BYTES(0x4eu, 22);
433 ppos += 22;
434 // 12 spaces
435 FFMT_FILL_BYTES(0x00u, 12);
436 ppos += 12;
437 // data mark
438 FFMT_PUT_BYTE(0xa1u);
439 FFMT_PUT_BYTE(0xa1u);
440 FFMT_PUT_BYTE(0xa1u);
441 FFMT_PUT_BYTE(sdata[sc].type); // 0xf8 (deleted) or 0xfb (normal)
442 // data
443 //fprintf(stderr, "tbleft=%u\n", (unsigned)tbleft);
444 const size_t ln = 128u<<(sdata[sc].sz&0x03u);
445 if (tbleft < ln) {
446 if (tbleft) memcpy(ppos, sdata[sc].data, tbleft);
447 tbleft = 0;
448 return FLPERR_OK;
449 } else {
450 memcpy(ppos, sdata[sc].data, ln);
451 tbleft -= ln;
453 ppos += ln;
454 if (tbleft < 2) return FLPERR_SHIT;
455 // data crc
456 FFMT_PUT_BYTE(0xf7);
457 FFMT_PUT_BYTE(0xf7);
458 // 60 sync (GAP3)
459 FFMT_FILL_BYTES(0x4eu, dsz);
460 ppos += dsz;
462 // last sync (GAP4)
463 while (ppos-flp->data[tr].byte < FLP_MAX_TRACK_SIZE) {
464 FFMT_PUT_BYTE(0x4e);
466 flpFillFields(flp, tr, (calccrc ? FLP_FILL_FIELDS_ALL : FLP_FILL_FIELDS_NONE));
467 return FLPERR_OK;
471 //==========================================================================
473 // flpGetSectorDataPtr
475 //==========================================================================
476 uint8_t *flpGetSectorDataPtr (Floppy *flp, uint8_t tr, uint8_t sc) {
477 if (!flp) return NULL;
478 const uint32_t datapos = flp->data[tr].map[sc]; // input nr 1+, tab nr 0+
479 if (datapos < 4 || datapos >= FLP_MAX_TRACK_SIZE) return NULL;
480 return flp->data[tr].byte+datapos;
484 //==========================================================================
486 // flpGetSectorSize
488 //==========================================================================
489 uint16_t flpGetSectorSize (Floppy *flp, uint8_t tr, uint8_t sc) {
490 if (!flp) return 0;
491 uint32_t addrpos = flp->data[tr].mapaddr[sc]; // input nr 1+, tab nr 0+
492 if (addrpos == 0 || addrpos+3 >= FLP_MAX_TRACK_SIZE) return 0;
493 return 128u<<flp->data[tr].byte[addrpos+3];
497 //==========================================================================
499 // flpGetSectorSizeSafe
501 //==========================================================================
502 uint16_t flpGetSectorSizeSafe (Floppy *flp, uint8_t tr, uint8_t sc) {
503 if (!flp) return 0;
504 uint32_t addrpos = flp->data[tr].mapaddr[sc]; // input nr 1+, tab nr 0+
505 if (addrpos == 0 || addrpos+4 > FLP_MAX_TRACK_SIZE) return 0;
506 uint32_t datapos = flp->data[tr].map[sc]; // input nr 1+, tab nr 0+
507 if (datapos < 4 || datapos >= FLP_MAX_TRACK_SIZE) return 0;
508 const uint8_t n = flp->data[tr].byte[addrpos+3];
509 if (n > 6) return 0; // >8192? wtf?! is it bigger than track size
510 const uint16_t secsize = 128u<<n;
511 // check if it fits the track
512 if (datapos+secsize > FLP_MAX_TRACK_SIZE) return 0;
513 // ok, it seems to be safe
514 return secsize;
518 //==========================================================================
520 // flpGetRawSectorC
522 //==========================================================================
523 int flpGetRawSectorC (Floppy *flp, uint8_t tr, uint8_t sc) {
524 if (!flp) return FLPERR_SHIT;
525 uint32_t addrpos = flp->data[tr].mapaddrraw[sc]; // input nr 1+, tab nr 0+
526 if (addrpos == 0 || addrpos+0 >= FLP_MAX_TRACK_SIZE) return FLPERR_SHIT;
527 return flp->data[tr].byte[addrpos+0];
531 //==========================================================================
533 // flpGetRawSectorH
535 //==========================================================================
536 int flpGetRawSectorH (Floppy *flp, uint8_t tr, uint8_t sc) {
537 if (!flp) return FLPERR_SHIT;
538 uint32_t addrpos = flp->data[tr].mapaddrraw[sc]; // input nr 1+, tab nr 0+
539 if (addrpos == 0 || addrpos+1 >= FLP_MAX_TRACK_SIZE) return FLPERR_SHIT;
540 return flp->data[tr].byte[addrpos+1];
544 //==========================================================================
546 // flpGetRawSectorR
548 //==========================================================================
549 int flpGetRawSectorR (Floppy *flp, uint8_t tr, uint8_t sc) {
550 if (!flp) return FLPERR_SHIT;
551 uint32_t addrpos = flp->data[tr].mapaddrraw[sc]; // input nr 1+, tab nr 0+
552 if (addrpos == 0 || addrpos+2 >= FLP_MAX_TRACK_SIZE) return FLPERR_SHIT;
553 return flp->data[tr].byte[addrpos+2];
557 //==========================================================================
559 // flpGetRawSectorN
561 //==========================================================================
562 int flpGetRawSectorN (Floppy *flp, uint8_t tr, uint8_t sc) {
563 if (!flp) return FLPERR_SHIT;
564 uint32_t addrpos = flp->data[tr].mapaddrraw[sc]; // input nr 1+, tab nr 0+
565 if (addrpos == 0 || addrpos+3 >= FLP_MAX_TRACK_SIZE) return FLPERR_SHIT;
566 return flp->data[tr].byte[addrpos+3];
570 //==========================================================================
572 // flp_get_sector_data_common
574 //==========================================================================
575 static void flp_get_sector_data_common (Floppy *flp, uint8_t tr, uint32_t datapos, uint32_t addrpos, FDCSectorInfo **sinf, int *crcok) {
576 if (datapos < 4 || datapos >= FLP_MAX_TRACK_SIZE || addrpos+3 >= FLP_MAX_TRACK_SIZE) {
577 if (sinf) *sinf = NULL;
578 if (crcok) *crcok = 0;
579 return;
581 if (sinf) *sinf = (FDCSectorInfo *)(flp->data[tr].byte+addrpos);
582 /* check data crc */
583 if (crcok) {
584 *crcok = 0;
585 const uint8_t ssz = flp->data[tr].byte[addrpos+3];
586 if (ssz <= 5) {
587 const uint32_t bytesz = (128u<<ssz);
588 if (datapos+bytesz <= FLP_MAX_TRACK_SIZE) {
589 const uint16_t crc = flpCalcWDCRC(flp->data[tr].byte+datapos-4, bytesz+4);
590 const uint16_t xcrc = (((uint16_t)flp->data[tr].byte[datapos+bytesz])<<8)|((uint16_t)flp->data[tr].byte[datapos+bytesz+1]);
591 *crcok = (crc == xcrc ? 1 : 0);
598 //==========================================================================
600 // flpGetSectorDataPtrEx
602 //==========================================================================
603 uint8_t *flpGetSectorDataPtrEx (Floppy *flp, uint8_t tr, uint8_t sc, FDCSectorInfo **sinf, int *crcok) {
604 if (crcok) *crcok = 0;
605 if (sinf) *sinf = NULL;
607 if (!flp) return NULL;
609 const uint32_t datapos = flp->data[tr].map[sc]; // input nr 1+, tab nr 0+
610 if (datapos < 4 || datapos >= FLP_MAX_TRACK_SIZE) return NULL;
612 const uint32_t addrpos = flp->data[tr].mapaddr[sc]; // input nr 1+, tab nr 0+
613 if (addrpos == 0 || addrpos+4 > FLP_MAX_TRACK_SIZE) return NULL;
615 flp_get_sector_data_common(flp, tr, datapos, addrpos, sinf, crcok);
616 return flp->data[tr].byte+datapos;
620 //==========================================================================
622 // flpGetRawSectorDataPtr
624 //==========================================================================
625 uint8_t *flpGetRawSectorDataPtr (Floppy *flp, uint8_t tr, int idx, FDCSectorInfo **sinf, int *crcok) {
626 if (crcok) *crcok = 0;
627 if (sinf) *sinf = NULL;
629 if (!flp || idx < 0 || idx > 255) return NULL;
631 uint32_t datapos = flp->data[tr].mapraw[idx]; // input nr 1+, tab nr 0+
632 if (datapos < 4) return NULL;
634 uint32_t addrpos = flp->data[tr].mapaddrraw[idx]; // input nr 1+, tab nr 0+
635 if (addrpos == 0 || addrpos+4 > FLP_MAX_TRACK_SIZE) return NULL;
637 flp_get_sector_data_common(flp, tr, datapos, addrpos, sinf, crcok);
638 return flp->data[tr].byte+datapos;
642 //==========================================================================
644 // flpFixSectorDataCRC
646 //==========================================================================
647 int flpFixSectorDataCRC (Floppy *flp, uint8_t tr, uint8_t sc) {
648 if (!flp) return FLPERR_SHIT;
649 uint8_t *ptr = flpGetSectorDataPtr(flp, tr, sc);
650 if (ptr == NULL) return FLPERR_SHIT;
651 const uint16_t secsize = flpGetSectorSizeSafe(flp, tr, sc);
652 if (secsize == 0) return FLPERR_SHIT;
653 // fix CRC
654 const uint16_t crc = flpCalcWDCRC(ptr-4, secsize+4);
655 ptr += secsize;
656 ptr[0] = (crc>>8)&0xffu;
657 ptr[1] = (crc&0xffu);
658 return FLPERR_OK;
662 //==========================================================================
664 // flpPutSectorData
666 //==========================================================================
667 int flpPutSectorData (Floppy *flp, uint8_t tr, uint8_t sc, const void *buf, size_t len) {
668 if (!flp) return FLPERR_SHIT;
669 if (len && !buf) return FLPERR_SHIT;
670 if (len > FLP_MAX_TRACK_SIZE) return FLPERR_SHIT;
671 if (len) {
672 const uint16_t secsize = flpGetSectorSizeSafe(flp, tr, sc);
673 if (secsize == 0) return FLPERR_SHIT;
674 if (len > secsize) return FLPERR_NOSPACE;
675 uint8_t *ptr = flpGetSectorDataPtr(flp, tr, sc);
676 if (ptr == NULL) return FLPERR_SHIT;
677 memcpy(ptr, buf, len);
679 return flpFixSectorDataCRC(flp, tr, sc);
683 //==========================================================================
685 // flpGetSectorData
687 //==========================================================================
688 int flpGetSectorData (Floppy *flp, uint8_t tr, uint8_t sc, void *buf, size_t len) {
689 if (!flp) return FLPERR_SHIT;
690 if (len && !buf) return FLPERR_SHIT;
691 const uint16_t secsize = flpGetSectorSizeSafe(flp, tr, sc);
692 if (secsize == 0) return FLPERR_SHIT;
693 int res = FLPERR_OK;
694 if (len > secsize) {
695 res = FLPERR_NOSPACE;
696 len = secsize;
698 uint8_t *ptr = flpGetSectorDataPtr(flp, tr, sc);
699 if (ptr == NULL) return FLPERR_SHIT;
700 if (len) memcpy(buf, ptr, len);
701 return res;