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 "dskfs_all.h"
28 #include "dskfs_trdos.h"
32 //**************************************************************************
34 // TR-DOS low level API
36 //**************************************************************************
38 //==========================================================================
42 //==========================================================================
43 int flpIsDiskTRDOS (Floppy
*flp
) {
44 if (!flp
|| !flp
->insert
) return 0;
47 if (flpGetSectorData(flp
, 0, 15, fbuf
, 0x100) != 0) return 0;
48 // at least 16 sectors
49 if (flpGetSectorData(flp
, 0, 9, fbuf
, 0x100) != 0) return 0;
50 return (fbuf
[0xe7] == 0x10u
);
54 //==========================================================================
58 // build a single track 16x256 (TRDOS), sector data @bpos (4K)
60 //==========================================================================
61 int flpFormatTRDTrack (Floppy
*flp
, int tr
, const void *bpos
, size_t bpossize
) {
62 if (!flp
|| bpossize
< 0 || tr
< 0 || tr
> 255) return FLPERR_SHIT
;
63 FDCSector lst
[FLP_TRDOS_SECTORS_PER_TRACK
];
64 memset(lst
, 0, sizeof(lst
));
65 const uint8_t *ppos
= (const uint8_t *)bpos
;
66 if (!ppos
) bpossize
= 0;
67 for (unsigned f
= 0; f
< FLP_TRDOS_SECTORS_PER_TRACK
; ++f
) {
68 FDCSector
*sc
= &lst
[f
];
69 sc
->sec
= (uint8_t)(f
+1u);
72 sc
->trk
= ((tr
&0xfe)>>1);
73 sc
->head
= (tr
&0x01 ? 1 : 0);
74 sc
->sz
= 1; // 256 bytes
76 if (bpossize
>= 256) {
77 memcpy(sc
->data
, ppos
, 256);
81 memcpy(sc
->data
, ppos
, bpossize
);
82 memset(sc
->data
, 0, 256-bpossize
);
86 memset(sc
->data
, 0, 256);
89 return flpFormatTracks(flp
, tr
, lst
, FLP_TRDOS_SECTORS_PER_TRACK
, FLP_FORMAT_TRACK_CALC_CRC
);
93 //==========================================================================
97 // format whole disk as 2x84x16x256 and init as TRDOS
99 //==========================================================================
100 int flpFormatTRD (Floppy
*flp
) {
101 if (!flp
) return FLPERR_SHIT
;
107 for (int i
= 1; i
< 168; ++i
) {
108 int res
= flpFormatTRDTrack(flp
, i
, NULL
, 0);
109 if (res
!= 0) return res
;
112 const uint8_t trd_8e0
[32] = {
113 0x00,0x00,0x01,0x16,0x00,0xf0,0x09,0x10,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,
114 0x20,0x20,0x20,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,
117 memset(buf
, 0, 0x1000);
118 memcpy(buf
+0x8e0, trd_8e0
, 0x20);
119 int res
= flpFormatTRDTrack(flp
, 0, buf
, sizeof(buf
));
120 if (res
== FLPERR_OK
) flp
->insert
= 1;
126 //**************************************************************************
130 //**************************************************************************
132 //==========================================================================
136 //==========================================================================
137 int flpCreateFile (Floppy
*flp
, TRFile
*dsc
) {
138 if (flpDetectDiskType(flp
) != FLP_DISK_TYPE_TRDOS
) return FLPERR_SHIT
;
142 if (flpGetSectorData(flp
, 0, 9, fbuf
, 256) != FLPERR_OK
) return FLPERR_SHIT
;
143 dsc
->sec
= fbuf
[0xe1];
144 dsc
->trk
= fbuf
[0xe2];
146 if (files
> 127) return FLPERR_MANYFILES
;
149 freesec
= fbuf
[0xe5]+(fbuf
[0xe6]<<8);
150 if (freesec
< dsc
->slen
) return FLPERR_NOSPACE
;
151 freesec
-= dsc
->slen
;
152 fbuf
[0xe5] = (freesec
&0xff);
153 fbuf
[0xe6] = ((freesec
&0xff00)>>8);
154 fbuf
[0xe1] += (dsc
->slen
&0x0f);
155 fbuf
[0xe2] += ((dsc
->slen
&0xf0)>>4);
156 if (fbuf
[0xe1] > 0x0f) {
160 if (flpPutSectorData(flp
, 0, 9, fbuf
, 256) != FLPERR_OK
) return FLPERR_SHIT
;
161 freesec
= ((files
&0xf0)>>4)+1;
162 if (flpGetSectorData(flp
, 0, freesec
, fbuf
, 256) != FLPERR_OK
) return FLPERR_SHIT
;
163 memmove(fbuf
+(((files
-1)&0x0f)<<4), dsc
, 16);
164 flpPutSectorData(flp
, 0, freesec
, fbuf
, 256);
170 //==========================================================================
172 // flpGetCatalogEntry
174 //==========================================================================
175 int flpGetCatalogEntry (Floppy
*flp
, TRFile
*dst
, int num
) {
178 if (flpDetectDiskType(flp
) != FLP_DISK_TYPE_TRDOS
) return FLPERR_SHIT
;
179 if (num
< 0 || num
> 127) return FLPERR_MANYFILES
;
180 sec
= ((num
&0xf0)>>4); // sector
181 pos
= ((num
&0x0f)<<4); // file number inside sector
182 if (flpGetSectorData(flp
, 0, sec
+1, fbuf
, 256) != FLPERR_OK
) return FLPERR_NOSPACE
;
183 if (dst
!= NULL
) memmove(dst
, fbuf
+pos
, 16);
188 //==========================================================================
192 //==========================================================================
193 int flpGetTRCatalog (Floppy
*flp
, TRFile
*dst
) {
195 if (flpDetectDiskType(flp
) == FLP_DISK_TYPE_TRDOS
) {
196 uint8_t *dpt
= (uint8_t *)dst
;
198 for (int sc
= 1; sc
< 9; ++sc
) {
199 if (flpGetSectorData(flp
, 0, sc
, fbuf
, 256) != FLPERR_OK
) break;
200 const uint8_t *ptr
= fbuf
;
202 for (fc
= 0; fc
< 16; ++fc
) {
203 if (*ptr
== 0) break;
205 memmove(dpt
, ptr
, 16);
219 //**************************************************************************
223 //**************************************************************************
225 //==========================================================================
229 //==========================================================================
230 int flpHasBoot (Floppy
*flp
) {
231 if (flp
!= NULL
&& flpDetectDiskType(flp
) == FLP_DISK_TYPE_TRDOS
) {
233 int catSize
= flpGetTRCatalog(flp
, cat
);
234 for (int i
= 0; i
< catSize
; ++i
) {
235 if (memcmp(cat
[i
].name
, "boot B", 9) == 0) return i
;
242 //==========================================================================
246 //==========================================================================
247 int flpSetBoot (Floppy
*flp
, FILE *fl
, int replace
) {
248 if (flp
!= NULL
&& flpDetectDiskType(flp
) == FLP_DISK_TYPE_TRDOS
) {
249 int idx
= flpHasBoot(flp
);
251 if (replace
) return FLPERR_SHIT
; //TODO
254 return dskLoadHoBeta(flp
, fl
);
260 //==========================================================================
264 //==========================================================================
265 int flpFindFirstBasic (Floppy
*flp
, TRFile
*dst
, int ffirst
) {
266 if (flp
== NULL
|| flpDetectDiskType(flp
) != FLP_DISK_TYPE_TRDOS
) return FLPERR_SHIT
;
267 if (!flp
->insert
) return FLPERR_SHIT
;
268 if (ffirst
< 0) ffirst
= 0;
270 for (; ffirst
< FLP_TRDOS_CATALOG_MAX
; ++ffirst
) {
271 if (flpGetCatalogEntry(flp
, &fcb
, ffirst
) != 0) break;
272 if (fcb
.name
[0] == 0) break; // end of directory
273 if (fcb
.name
[0] == 1) continue; // deleted
274 if (fcb
.ext
!= 'B') continue;
277 for (unsigned f
= 0; f
< 8; ++f
) {
278 const uint8_t ch
= (unsigned)(fcb
.name
[f
]&0xffU
);
279 if (ch
< 32 || ch
== '"') { nameok
= 0; break; }
280 if (ch
!= 32) seennspc
= 1;
282 if (!nameok
|| !seennspc
) continue;
283 if (dst
) memcpy(dst
, &fcb
, sizeof(TRFile
));
290 //==========================================================================
292 // flpHasAnyNonBootBasic
294 //==========================================================================
295 int flpHasAnyNonBootBasic (Floppy
*flp
, TRFile
*dst
) {
296 if (flp
== NULL
|| flpDetectDiskType(flp
) != FLP_DISK_TYPE_TRDOS
) return 0;
297 if (!flp
->insert
) return 0;
298 // check if we have any non-boot basic file
302 fidx
= flpFindFirstBasic(flp
, &fcb
, fidx
);
304 if (memcmp(fcb
.name
, "boot ", 8) == 0) { ++fidx
; continue; }
305 if (dst
) memcpy(dst
, &fcb
, sizeof(TRFile
));
312 //==========================================================================
316 //==========================================================================
317 int flpSetBootSimple (Floppy
*flp
) {
318 if (flp
== NULL
|| flpDetectDiskType(flp
) != FLP_DISK_TYPE_TRDOS
) return FLPERR_SHIT
;
319 if (!flp
->insert
) return FLPERR_SHIT
;
320 // check if we have any non-boot basic file
325 fidx
= flpFindFirstBasic(flp
, &fcb
, fidx
);
327 if (memcmp(fcb
.name
, "boot ", 8) == 0) return FLPERR_SHIT
; // nothing to do
328 if (seenBasic
) return FLPERR_SHIT
; // too many basic files
332 if (!seenBasic
) return FLPERR_SHIT
;
334 // create simple autorun boot:
335 // 10 RANDOMIZE USR VAL "15619":REM LOAD "file"
338 memset(secBuf
, 0, sizeof(secBuf
));
342 secBuf
[scpos
++] = 10;
343 // line size (will be fixed later)
347 secBuf
[scpos
++] = 0xf9U
; // RANDOMIZE
348 secBuf
[scpos
++] = 0xc0U
; // USR
349 secBuf
[scpos
++] = 0xb0U
; // VAL
350 secBuf
[scpos
++] = '"';
351 secBuf
[scpos
++] = '1';
352 secBuf
[scpos
++] = '5';
353 secBuf
[scpos
++] = '6';
354 secBuf
[scpos
++] = '1';
355 secBuf
[scpos
++] = '9';
356 secBuf
[scpos
++] = '"';
357 secBuf
[scpos
++] = ':';
358 secBuf
[scpos
++] = 0xeaU
; // REM
359 secBuf
[scpos
++] = ':';
360 secBuf
[scpos
++] = 0xefU
; // LOAD
361 secBuf
[scpos
++] = '"';
364 while (nlen
> 0 && fcb
.name
[nlen
-1] == ' ') --nlen
;
365 if (nlen
== 0) return FLPERR_SHIT
; // just in case
366 memcpy(secBuf
+scpos
, fcb
.name
, nlen
); scpos
+= nlen
;
367 secBuf
[scpos
++] = '"';
369 secBuf
[scpos
++] = 13;
371 secBuf
[2] = (scpos
-4)&0xffU
;
372 secBuf
[3] = ((scpos
-4)>>8)&0xffU
;
374 secBuf
[scpos
++] = 0x80;
375 secBuf
[scpos
++] = 0xaa;
377 secBuf
[scpos
++] = 10;
380 memcpy(fcb
.name
, "boot ", 8);
382 // last 4 bytes are not in length
383 fcb
.lst
= (scpos
-4)&0xff;
384 fcb
.hst
= ((scpos
-4)>>8)&0xff;
385 fcb
.llen
= (scpos
-4)&0xff;
386 fcb
.hlen
= ((scpos
-4)>>8)&0xff;
387 fcb
.slen
= 1; // one sector
388 fcb
.sec
= fcb
.trk
= 0; // will be set in `flpCreateFile()`
390 if (flpCreateFile(flp
, &fcb
) != FLPERR_OK
) return FLPERR_SHIT
;
391 if (flpPutSectorData(flp
, fcb
.trk
, fcb
.sec
+1, secBuf
, 256) != FLPERR_OK
) return FLPERR_SHIT
;
398 //==========================================================================
404 //==========================================================================
405 int flpRemoveBoot (Floppy
*flp
) {
406 return FLPERR_SHIT
; //TODO