2
0

abcdisk.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. /*
  2. * abcdisk.c
  3. *
  4. * Emulate an ABC80/800 disk controller
  5. */
  6. #include "fw.h"
  7. #include "ff.h"
  8. /* Option flags, mostly for debugging */
  9. #define NOTTHERE 0
  10. #define READONLY 0
  11. #define INTERLEAVE 0
  12. /* Disk controller I/O state machine */
  13. enum controller_state {
  14. ctl_uninit, /* Disks not initialized */
  15. ctl_command, /* Expecting command */
  16. ctl_upload, /* Expecting data block upload */
  17. ctl_download /* Expecting data block download */
  18. };
  19. enum drive_flags {
  20. DF_MOUNTED, /* Host file open, drive exported */
  21. DF_READONLY, /* Drive is readonly */
  22. DF_DISABLED /* Drive is disabled */
  23. };
  24. /* Per-drive state */
  25. struct drive_state {
  26. FIL file; /* Host file */
  27. char name[4]; /* Drive name */
  28. uint16_t sectors; /* Total size in 256-byte sectors */
  29. uint8_t ilmsk, ilfac; /* Software interleaving parameters */
  30. enum drive_flags flags;
  31. enum drive_flags force; /* Option to force flags */
  32. };
  33. /* Per-controller state */
  34. struct ctl_state {
  35. enum controller_state state;
  36. uint8_t k[4]; /* Command bytes */
  37. uint8_t clustshift; /* log2(clustersize/256) */
  38. uint8_t devsel; /* I/O device select */
  39. uint16_t maxsectors; /* Maximum sectors for this controller */
  40. uint8_t c, h, s; /* Disk geometry */
  41. uint8_t drives; /* Total drives present */
  42. bool newaddr; /* "New addressing" */
  43. bool fmtdata_in_buf; /* Use user-provided formatting data */
  44. const char name[4]; /* Name of controller (disk type) */
  45. uint8_t ilmsk, ilfac; /* Software interleaving parea */
  46. uint8_t error; /* Error code status */
  47. struct drive_state drv[8]; /* Per-drive state */
  48. uint8_t buf[4][256]; /* 4 host buffers @ 256 bytes */
  49. };
  50. /*
  51. * DOSGEN depends on this value... and different DOSGEN
  52. * expect different values. If this value is wrong, DOSGEN
  53. * will spin forever on "testing sector..."
  54. */
  55. #define OUT_OF_RANGE 0x21 /* Status code for an invalid sector */
  56. enum controller_types {
  57. MOx,
  58. MFx,
  59. SFx,
  60. HDx,
  61. CONTROLLER_TYPES
  62. };
  63. static struct ctl_state controllers[CONTROLLER_TYPES] = {
  64. /*
  65. * MOx: covers all of these formats:
  66. * SSSD = 40×8×1 (80K, FD2/DD80),
  67. * SSDD = 40×16×1 (160K, FD2D/DD82/ABC830) and
  68. * DSDD = 40×16×2 (320K, FD4D/DD84/DD52)
  69. */
  70. [MOx] = {
  71. .devsel = 45,
  72. .clustshift = 0,
  73. .maxsectors = 40 * 2 * 16,
  74. .c = 40, .h = 2, .s = 16,
  75. .fmtdata_in_buf = true,
  76. .ilmsk = 15,
  77. .ilfac = 7,
  78. .name = "mo"
  79. },
  80. /* MFx: DSQD = 80×16x2 (640K, ABC832/834) */
  81. [MFx] = {
  82. .devsel = 44,
  83. .clustshift = 2,
  84. .maxsectors = 80 * 2 * 16,
  85. .c = 80, .h = 2, .s = 16,
  86. .name = "mf"
  87. },
  88. /* SFx: 8" floppy (DD88, ABC838) */
  89. [SFx] = {
  90. .devsel = 46,
  91. .clustshift = 2,
  92. .maxsectors = (77 * 2 - 1) * 26, /* Track 0, side 0 not used */
  93. .c = 77, .h = 2, .s = 26,
  94. .name = "sf"
  95. },
  96. [HDx] = {
  97. .devsel = 36,
  98. .clustshift = 5,
  99. .newaddr = true, /* Actually irrelevant for clustshift = 5 */
  100. .maxsectors = (239 * 32 - 1) * 32, /* Maximum supported by UFD-DOS */
  101. .c = 238, .h = 16, .s = 64,
  102. .name = "hd"
  103. }
  104. };
  105. static inline bool mounted(const struct drive_state *drv)
  106. {
  107. return !!(drv->flags & DF_MOUNTED);
  108. }
  109. static inline struct drive_state *cur_drv_mutable(struct ctl_state *state)
  110. {
  111. return &state->drv[state->k[1] & 7];
  112. }
  113. static inline const struct drive_state *cur_drv(const struct ctl_state *state)
  114. {
  115. return &state->drv[state->k[1] & 7];
  116. }
  117. static inline unsigned int cur_sector(const struct ctl_state *state)
  118. {
  119. uint8_t k2 = state->k[2], k3 = state->k[3];
  120. if (state->newaddr)
  121. return (k2 << 8) + k3;
  122. else
  123. return (((k2 << 3) + (k3 >> 5)) << state->clustshift) + (k3 & 31);
  124. }
  125. /* Get physical sector number, after interleaving */
  126. static inline unsigned int
  127. virt2phys(const struct drive_state *drv, unsigned int sector)
  128. {
  129. unsigned int ilmsk = drv->ilmsk;
  130. unsigned int ilfac = drv->ilfac;
  131. sector = (sector & ~ilmsk) | ((sector * ilfac) & ilmsk);
  132. return sector;
  133. }
  134. static inline unsigned int phys_sector(const struct ctl_state *state)
  135. {
  136. return virt2phys(cur_drv(state), cur_sector(state));
  137. }
  138. static inline off_t file_pos(const struct ctl_state *state)
  139. {
  140. return phys_sector(state) << 8;
  141. }
  142. static inline bool cur_sector_valid(const struct ctl_state *state)
  143. {
  144. uint8_t k3 = state->k[3];
  145. if (!state->newaddr && ((k3 & 31) >> state->clustshift))
  146. return false;
  147. return cur_sector(state) < cur_drv(state)->sectors;
  148. }
  149. static inline bool file_pos_valid(const struct ctl_state *state)
  150. {
  151. return file_pos(state) < cur_drv(state)->hf->filesize - 255;
  152. }
  153. static inline uint8_t *cur_buf(struct ctl_state *state)
  154. {
  155. return state->buf[state->k[1] >> 6];
  156. }
  157. static void disk_reset_state(struct ctl_state *state)
  158. {
  159. int i;
  160. state->state = disk_k0;
  161. state->error = 0;
  162. state->in_ptr = -1;
  163. state->out_ptr = 0;
  164. state->notready_ctr = NOT_READY;
  165. for (i = 0; i < 8; i++)
  166. f_sync(&state->drv[i].file);
  167. }
  168. static struct drive_state *
  169. name_to_drive(const char *drive)
  170. {
  171. int sel;
  172. struct ctl_state *state;
  173. unsigned int ndrive;
  174. /* All drive names are three letters long */
  175. if (strlen(drive) != 3)
  176. return NULL;
  177. ndrive = drive[2] - '0';
  178. if (ndrive > 7)
  179. return NULL;
  180. if (!memcmp("dr", drive, 2)) {
  181. /* DRx alias for MOx (matches "old DOS") */
  182. return &mo_state.drv[ndrive];
  183. }
  184. for (sel = 0; sel < 64; sel++) {
  185. state = sel_to_state[sel];
  186. if (!state)
  187. continue;
  188. if (!memcmp(state->name, drive, 2))
  189. return &state->drv[ndrive];
  190. }
  191. return NULL; /* No such disk */
  192. }
  193. bool valid_drive_name(const char *drive)
  194. {
  195. return name_to_drive(drive) != NULL;
  196. }
  197. static int mount_drive(struct drive_state *drv, const char *filename)
  198. {
  199. if (mounted(drv)) {
  200. f_close(&drv->file);
  201. drv->flags &= ~DF_MOUNTED;
  202. }
  203. if (drv->force & DF_DISABLED)
  204. return -1;
  205. drv->flags = drv->force & ~DF_MOUNTED;
  206. if (!filename) {
  207. return 0; /* Explicit unmount */
  208. } else {
  209. while (1) {
  210. BYTE mode = FA_OPEN_EXISTING | FA_READ;
  211. if (!(drv->flags & DF_READONLY))
  212. mode |= FA_WRITE;
  213. FRESULT rv = f_open(&drv->file, filename, mode);
  214. if (rv == FR_WRITE_PROTECTED && (mode & FA_WRITE)) {
  215. drv->flags |= DF_READONLY;
  216. continue;
  217. }
  218. if (rv != FR_OK)
  219. drv->flags |= DF_DISABLED;
  220. else
  221. drv->flags |= DF_MOUNTED;
  222. break;
  223. }
  224. if (!(drv->flags & DF_MOUNTED))
  225. return -1;
  226. }
  227. /*
  228. * Smaller than the standard disk size? Treat the sectors
  229. * beyond the end as bad.
  230. */
  231. unsigned int filesec = f_size(drv->file) >> 8;
  232. drv->sectors = (filesec && filesec < state->maxsectors)
  233. ? filesec : state->maxsectors;
  234. /* Interleaving parameters */
  235. #if INTERLEAVE
  236. drv->ilfac = state->ilfac;
  237. drv->ilmsk = state->ilmsk;
  238. #else
  239. drv->ilfac = drv->ilmsk = 0;
  240. #endif
  241. return 0;
  242. }
  243. static const char * const disk_pfx_abc80[] = { "/abcdisk.80/", "/abcdisk/", "/", NULL };
  244. static const char * const disk_pfx_abc800[] = { "/abcdisk.800/", "/abcdisk/", "/", NULL };
  245. static void disk_init(struct ctl_state *state)
  246. {
  247. uint32_t abc_status = ABC_STATUS;
  248. const char * const *pfx_list;
  249. int i;
  250. /* If no ABC, don't initialize disks; should in fact unmount them all */
  251. if (!(abc_status & ABC_STATUS_LIVE))
  252. return;
  253. pfx_list = (abc_status & ABC_STATUS_800) ? disk_pfx_abc800 : disk_pfx_abc80;
  254. /* If any of these don't exist we simply report device not ready */
  255. state->drives = 0;
  256. for (i = 0; i < 8; i++) {
  257. struct drive_state *drv = &state->drv[i];
  258. unsigned int filesec;
  259. const char **pfx;
  260. snprintf(drv->name, sizeof drv->name, "%-.2s%c", state->name, i + '0');
  261. for (pfx = pfx_list; *pfx; pfx++) {
  262. char filename_buf[64];
  263. snprintf(filename_buf, sizeof filename_buf, "%s%s", *pfx, drv->name);
  264. if (!mount_drive(drv, filename_buf)) {
  265. state->drives++;
  266. break;
  267. }
  268. }
  269. }
  270. disk_reset_state(state);
  271. }
  272. static void setup_dma(struct drive_state *drv, unsigned int len, uint8_t devsel, bool out_dir)
  273. {
  274. static void do_next_command(struct ctl_state *state)
  275. {
  276. struct drive_state *drv = cur_drv_mutable(state);
  277. uint8_t *buf = cur_buf(state);
  278. if (state->k[0] & 0x01) {
  279. /* READ SECTOR */
  280. if (!) {
  281. state->error = 0x80; /* Device not ready */
  282. } else if (!cur_sector_valid(state)) {
  283. state->error = OUT_OF_RANGE;
  284. } else if (!file_pos_valid(state)) {
  285. state->error = 0x08; /* CRC error(?) */
  286. } else {
  287. UINT rlen = 0;
  288. FRESULT rv;
  289. rv = f_lseek(&drv->file, file_pos(state));
  290. if (rv == FR_OK)
  291. rv = f_read(&drv->file, buf, 256, &rlen);
  292. if (rv != FR_OK || rlen != 256) {
  293. state->error = 0x08; /* CRC error */
  294. }
  295. }
  296. state->k[0] &= ~0x01; /* Command done */
  297. }
  298. if (state->k[0] & 0x02) {
  299. /* SECTOR TO HOST */
  300. state->in_ptr = 0;
  301. state->state = disk_download;
  302. state->k[0] &= ~0x02; /* Command done */
  303. return;
  304. }
  305. if (state->k[0] & 0x04) {
  306. /* SECTOR FROM HOST */
  307. state->state = disk_upload;
  308. state->out_ptr = 0;
  309. state->k[0] &= ~0x04; /* Command done */
  310. return;
  311. }
  312. if (state->k[0] & 0x08) {
  313. /* WRITE SECTOR */
  314. if (!hf) {
  315. state->error = 0x80; /* Not ready */
  316. } else if (!file_wrok(hf)) {
  317. state->error = 0x40; /* Write protect */
  318. } else if (!cur_sector_valid(state)) {
  319. state->error = OUT_OF_RANGE;
  320. if (tracing(TRACE_DISK)) {
  321. fprintf(tracef, "%s: write: disk sector out of range: %u/%u (cluster %u/%u)\n",
  322. drv->name, cur_sector(state), drv->sectors,
  323. cur_sector(state) >> state->clustshift,
  324. drv->sectors >> state->clustshift);
  325. }
  326. } else if (!file_pos_valid(state)) {
  327. state->error = 0x08; /* CRC error(?) */
  328. } else {
  329. if (hf->map) {
  330. memcpy(hf->map + file_pos(state), buf, 256);
  331. } else {
  332. clearerr(hf->f);
  333. fseek(hf->f, file_pos(state), SEEK_SET);
  334. fwrite(buf, 1, 256, hf->f);
  335. if (ferror(hf->f))
  336. state->error = 0x20; /* Write fault */
  337. }
  338. }
  339. state->k[0] &= ~0x08; /* Command done */
  340. }
  341. if (state->k[0] & 0x10 && state->k[1] & 0x08) {
  342. state->out_ptr = 0;
  343. /* FORMAT */
  344. if (!drv->hf) {
  345. state->error = 0x80; /* Not ready */
  346. } else if (!file_wrok(hf)) {
  347. state->error = 0x40; /* Write protect */
  348. } else {
  349. unsigned int s, c0, c1, s0, s1;
  350. unsigned int cylsec = state->s * state->h;
  351. uint8_t data[256];
  352. unsigned int fmtsec, filesec;
  353. /* Sector count produced by format */
  354. fmtsec = state->maxsectors;
  355. /* For non-MO-drives, this seems to be internally generated */
  356. memset(data, 0x40, 256);
  357. if (state->fmtdata_in_buf) {
  358. /*
  359. * MO drives put the sector image in the buffers, for
  360. * backwards compatibility and to support single density.
  361. *
  362. * Right before the F7 header CRC opcode is a density byte;
  363. * 00 for single, and 01 for double. The data begins after
  364. * a byte of FB.
  365. */
  366. bool single = false;
  367. const uint8_t *p, *ep;
  368. ep = state->buf[1];
  369. for (p = state->buf[0]+1; p < ep; p++) {
  370. if (*p == 0xf7)
  371. single = (p[-1] == 0);
  372. if (*p == 0xfb)
  373. break;
  374. }
  375. fmtsec >>= single;
  376. if (*p++ == 0xfb) { /* Data block found */
  377. if (single) {
  378. /* Really two 128-byte sectors! */
  379. memcpy(data, p, 128);
  380. memcpy(data+128, p, 128);
  381. } else {
  382. memcpy(data, p, 256);
  383. }
  384. }
  385. }
  386. /*
  387. * Adjust the size of the accessible device to the smallest
  388. * of the physical file and the formatted size
  389. */
  390. filesec = drv->hf->filesize >> 8;
  391. drv->sectors = (filesec && filesec < fmtsec) ? filesec : fmtsec;
  392. /*
  393. * k2 and k3 contain the first and last cylinder numbers to
  394. * format, inclusively. The last cylinder may be partial due
  395. * to virtual remapping, e.g. for sf floppies.
  396. */
  397. c0 = state->k[2];
  398. s0 = c0 * cylsec;
  399. c1 = state->k[3] + 1;
  400. s1 = c1 * cylsec;
  401. if (tracing(TRACE_DISK)) {
  402. fprintf(tracef, "%s: formatting cyl %u..%u, sectors %u..%u\n",
  403. drv->name, c0, c1-1, s0, s1-1);
  404. }
  405. clearerr(hf->f);
  406. state->error = 0;
  407. for (s = s0; s < s1; s++) {
  408. unsigned int ps = virt2phys(drv, s);
  409. if (ps >= drv->sectors) {
  410. state->error |= 0x02; /* Track 0/Lost data? */
  411. break;
  412. } else if (hf->map) {
  413. memcpy(hf->map + (ps << 8), data, 256);
  414. } else {
  415. fseek(hf->f, ps << 8, SEEK_SET);
  416. fwrite(data, 1, 256, hf->f);
  417. }
  418. }
  419. if (ferror(hf->f))
  420. state->error |= 0x20; /* Write fault */
  421. }
  422. state->k[1] &= ~0x08;
  423. }
  424. if (!(state->k[1] & 0x38))
  425. state->k[0] &= ~0x10;
  426. if (tracing(TRACE_DISK)) {
  427. if (state->trace_dump) {
  428. trace_dump(TRACE_DISK, drv->name, buf, 256);
  429. state->trace_dump = false;
  430. }
  431. }
  432. state->state = disk_k0;
  433. }
  434. static void disk_reset(uint8_t sel)
  435. {
  436. struct ctl_state *state = sel_to_state[sel];
  437. if (state && state->state != disk_need_init)
  438. disk_reset_state(state);
  439. }