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
30 //==========================================================================
34 //==========================================================================
35 Floppy
*flpCreate (int id
) {
36 Floppy
*flp
= malloc(sizeof(Floppy
));
37 memset(flp
, 0, sizeof(Floppy
));
47 //==========================================================================
51 //==========================================================================
52 void flpDestroy (Floppy
*flp
) {
59 //==========================================================================
63 //==========================================================================
64 void flpEject (Floppy
*flp
) {
72 //==========================================================================
76 //==========================================================================
77 int flpWr (Floppy
*flp
, int hd
, uint8_t val
) {
78 if (!flp
) return FLPERR_SHIT
;
81 if (hd
&& !flp
->doubleSide
) return FLPERR_SHIT
; // saving on HD1 for SS Floppy
82 if (!flp
->insert
) return FLPERR_SHIT
;
84 flp
->data
[(flp
->trk
<<1)|hd
].byte
[flp
->pos
] = val
;
89 //==========================================================================
93 //==========================================================================
94 uint8_t flpRd (Floppy
*flp
, int hd
) {
95 if (!flp
) return 0xffU
;
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 //==========================================================================
108 //==========================================================================
109 void flpStep (Floppy
*flp
, int dir
) {
113 if (flp
->trk
< (flp
->trk80
? 86 : 43)) ++flp
->trk
;
116 if (flp
->trk
> 0) --flp
->trk
;
122 //==========================================================================
126 //==========================================================================
127 int flpNext (Floppy
*flp
, int fdcSide
) {
130 int rtrk
= (flp
->trk
<<1);
131 if (flp
->doubleSide
&& fdcSide
) ++rtrk
;
134 if (flp
->pos
>= FLP_MAX_TRACK_SIZE
) {
138 flp
->index
= (flp
->pos
< 4 ? 1 : 0); // ~90ms index pulse
139 flp
->field
= flp
->data
[rtrk
].field
[flp
->pos
]&0x0f;
147 //==========================================================================
151 //==========================================================================
152 void flpPrev (Floppy
*flp
, int fdcSide
) {
154 int rtrk
= (flp
->trk
<<1);
155 if (flp
->doubleSide
&& fdcSide
) ++rtrk
;
160 flp
->pos
= FLP_MAX_TRACK_SIZE
-1;
162 flp
->field
= flp
->data
[rtrk
].field
[flp
->pos
]&0x0f;
169 //==========================================================================
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
;
178 int bcnt
= 0; // number of bytes in the current field
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
) {
197 if (*bpos
== 0xf5) *bpos
= 0xa1;
198 if (*bpos
== 0xf6) *bpos
= 0xc2;
201 // process field data
203 // we are in field yet
207 // fld should not be 0 here
208 // other field types needs CRC, so calculate it
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
222 fld
= 0; // "gap field" type
226 // out of the field, check type and setup new field
227 const uint8_t bt
= *bpos
;
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
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;
269 //==========================================================================
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
));
287 //==========================================================================
291 //==========================================================================
292 int flpClearDisk (Floppy
*flp
) {
293 if (!flp
) return FLPERR_SHIT
;
294 for (int i
= 0; i
< 256; ++i
) flpClearTrack(flp
, i
);
299 //==========================================================================
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
);
312 //==========================================================================
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
);
325 //==========================================================================
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 //==========================================================================
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
;
350 for (unsigned i
= 0; i
< 8; ++i
) {
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; \
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_)); \
377 memset(ppos, (bt_), cc); \
381 //==========================================================================
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;
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
;
402 FFMT_FILL_BYTES(0x00u
, 12);
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));
413 FFMT_FILL_BYTES(0x4eu
, 10);
416 FFMT_FILL_BYTES(0x00u
, 12);
419 FFMT_PUT_BYTE(0xa1u
);
420 FFMT_PUT_BYTE(0xa1u
);
421 FFMT_PUT_BYTE(0xa1u
);
422 FFMT_PUT_BYTE(0xfeu
);
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
);
432 FFMT_FILL_BYTES(0x4eu
, 22);
435 FFMT_FILL_BYTES(0x00u
, 12);
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)
443 //fprintf(stderr, "tbleft=%u\n", (unsigned)tbleft);
444 const size_t ln
= 128u<<(sdata
[sc
].sz
&0x03u
);
446 if (tbleft
) memcpy(ppos
, sdata
[sc
].data
, tbleft
);
450 memcpy(ppos
, sdata
[sc
].data
, ln
);
454 if (tbleft
< 2) return FLPERR_SHIT
;
459 FFMT_FILL_BYTES(0x4eu
, dsz
);
463 while (ppos
-flp
->data
[tr
].byte
< FLP_MAX_TRACK_SIZE
) {
466 flpFillFields(flp
, tr
, (calccrc
? FLP_FILL_FIELDS_ALL
: FLP_FILL_FIELDS_NONE
));
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 //==========================================================================
488 //==========================================================================
489 uint16_t flpGetSectorSize (Floppy
*flp
, uint8_t tr
, uint8_t sc
) {
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
) {
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
518 //==========================================================================
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 //==========================================================================
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 //==========================================================================
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 //==========================================================================
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;
581 if (sinf
) *sinf
= (FDCSectorInfo
*)(flp
->data
[tr
].byte
+addrpos
);
585 const uint8_t ssz
= flp
->data
[tr
].byte
[addrpos
+3];
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
;
654 const uint16_t crc
= flpCalcWDCRC(ptr
-4, secsize
+4);
656 ptr
[0] = (crc
>>8)&0xffu
;
657 ptr
[1] = (crc
&0xffu
);
662 //==========================================================================
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
;
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 //==========================================================================
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
;
695 res
= FLPERR_NOSPACE
;
698 uint8_t *ptr
= flpGetSectorDataPtr(flp
, tr
, sc
);
699 if (ptr
== NULL
) return FLPERR_SHIT
;
700 if (len
) memcpy(buf
, ptr
, len
);