123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854 |
- #include <string.h>
- #include <stdio.h>
- #include "common.h"
- #include "config.h"
- #include "io.h"
- #include "abcio.h"
- #include "console.h"
- #include "sdcard.h"
- #include "ff.h"
- #define NOTTHERE 0
- #define READONLY 0
- #define INTERLEAVE 0
- #define FORMAT_SUPPORT 0
- enum drive_flags {
- DF_MOUNTED = 1,
- DF_READONLY = 2,
- DF_DISABLED = 4,
- DF_DIRTY = 8
- };
- enum pending {
- PEND_IO = 1,
- PEND_STARTCMD = 2,
- PEND_RESET = 4
- };
- enum abc_status {
- AS_CMD = 0x80,
- AS_WRITE = 0x40,
- AS_ERROR = 0x08,
- AS_READING = 0x04,
- AS_READY = 0x01
- };
- #define MAX_FAST_FRAGMENTS 16
- #define CLTBL_SIZE ((MAX_FAST_FRAGMENTS+1)*2)
- struct drive_state {
- FIL file;
- char name[4];
- uint16_t sectors;
- #if INTERLEAVE
- uint8_t ilmsk, ilfac;
- #endif
- enum drive_flags flags;
- enum drive_flags force;
- DWORD cltbl[CLTBL_SIZE];
- };
- struct ctl_params {
- enum sysvar_enum enable;
- enum sysvar_enum devsel;
- uint8_t clustshift;
- uint16_t maxsectors;
- uint8_t c, h, s;
- bool newaddr;
- const char name[4];
- #if INTERLEAVE
- uint8_t ilmsk, ilfac;
- #endif
- #if FORMAT_SUPPORT
- bool fmtdata_i_buf;
- #endif
- } __attribute__((aligned(4)));
- struct ctl_state {
- struct abc_dev iodev;
- const struct ctl_params *params;
- uint8_t k[4];
- uint8_t drives;
- uint8_t error;
- bool initialized;
- volatile enum pending pending;
- struct drive_state drv[8];
- uint8_t buf[4][256];
- };
- #define OUT_OF_RANGE 0x21
- #define DISK_NOT_READY 0x80
- #define WRITE_PROTECT 0x40
- #define WRITE_FAULT 0x20
- #define CRC_ERROR 0x08
- enum controller_types {
- MOx,
- MFx,
- SFx,
- HDx,
- XDx,
- CONTROLLER_TYPES
- };
- #if INTERLEAVE
- # define IL(mask, fac) .ilmsk = (mask), .ilfac = (fac),
- #else
- # define IL(mask, fac)
- #endif
- static const struct ctl_params parameters[CONTROLLER_TYPES] = {
-
- [MOx] = {
- .enable = config_abc_io_mo_enable,
- .devsel = config_abc_io_mo_devsel,
- .clustshift = 0,
- .maxsectors = 40 * 2 * 16,
- .c = 40, .h = 2, .s = 16,
- .name = "mo",
- #if FORMAT_SUPPORT
- .fmtdata_in_buf = true,
- #endif
- IL(15, 7)
- },
-
- [MFx] = {
- .enable = config_abc_io_mf_enable,
- .devsel = config_abc_io_mf_devsel,
- .clustshift = 2,
- .maxsectors = 80 * 2 * 16,
- .c = 80, .h = 2, .s = 16,
- .name = "mf"
- },
-
- [SFx] = {
- .enable = config_abc_io_sf_enable,
- .devsel = config_abc_io_sf_devsel,
- .clustshift = 2,
- .maxsectors = (77 * 2 - 1) * 26,
- .c = 77, .h = 2, .s = 26,
- .name = "sf"
- },
- [HDx] = {
- .enable = config_abc_io_hd_enable,
- .devsel = config_abc_io_hd_devsel,
- .clustshift = 5,
- .newaddr = true,
- .maxsectors = (239 * 8 - 1) * 32,
- .c = 238, .h = 16, .s = 64,
- .name = "hd"
- },
-
- [XDx] = {
- .enable = config_abc_io_xd_enable,
- .devsel = config_abc_io_xd_devsel,
- .clustshift = 5,
- .newaddr = true,
- .maxsectors = (239 * 8 - 1) * 32,
- .c = 238, .h = 16, .s = 64,
- .name = "xd"
- },
- };
- static struct ctl_state __dram_bss controllers[CONTROLLER_TYPES];
- static inline bool mounted(const struct drive_state *drv)
- {
- return !!(drv->flags & DF_MOUNTED);
- }
- static inline struct drive_state *cur_drv_mutable(struct ctl_state *state)
- {
- return &state->drv[state->k[1] & 7];
- }
- static inline const struct drive_state *cur_drv(const struct ctl_state *state)
- {
- return &state->drv[state->k[1] & 7];
- }
- static inline unsigned int cur_sector(const struct ctl_state *state)
- {
- uint8_t k2 = state->k[2], k3 = state->k[3];
- if (state->params->newaddr)
- return (k2 << 8) + k3;
- else
- return (((k2 << 3) + (k3 >> 5)) << state->params->clustshift)
- + (k3 & 31);
- }
- static inline unsigned int
- virt2phys(const struct drive_state *drv, unsigned int sector)
- {
- #if INTERLEAVE
- unsigned int ilmsk = drv->ilmsk;
- unsigned int ilfac = drv->ilfac;
- sector = (sector & ~ilmsk) | ((sector * ilfac) & ilmsk);
- #endif
- return sector;
- }
- static inline unsigned int phys_sector(const struct ctl_state *state)
- {
- return virt2phys(cur_drv(state), cur_sector(state));
- }
- static inline unsigned int file_pos(const struct ctl_state *state)
- {
- return phys_sector(state) << 8;
- }
- static inline bool file_pos_valid(const struct ctl_state *state)
- {
- return phys_sector(state) < cur_drv(state)->sectors;
- }
- static inline bool cur_sector_valid(const struct ctl_state *state)
- {
- uint8_t k3 = state->k[3];
- if (!state->params->newaddr && ((k3 & 31) >> state->params->clustshift))
- return false;
- return phys_sector(state) < state->params->maxsectors;
- }
- static inline uint8_t *cur_buf(struct ctl_state *state)
- {
- return state->buf[state->k[1] >> 6];
- }
- static void disk_start_command(struct ctl_state *state)
- {
- #if 0
- con_printf("%-2s: start command\n", state->params->name);
- #endif
- memset(&state->k, 0xee, sizeof state->k);
- state->iodev.callback_mask |= 1 << 0;
- abc_setup_out_queue(&state->iodev, state->k, 4,
- AS_CMD|AS_READY|AS_WRITE|
- (state->error ? AS_ERROR : 0));
- }
- static void sync_drives(struct ctl_state *state)
- {
- for (int i = 0; i < 8; i++) {
- struct drive_state *drv = &state->drv[i];
- if (drv->flags & DF_DIRTY) {
- f_sync(&state->drv[i].file);
- drv->flags &= ~DF_DIRTY;
- }
- }
- }
- static void disk_set_error(struct ctl_state *state, unsigned int error)
- {
- abc_set_inp_default(&state->iodev, state->error = error);
- state->k[0] = 0;
- }
- static void disk_reset_state(struct ctl_state *state)
- {
- abc_set_inp_status(&state->iodev, 0);
- disk_set_error(state, 0);
- disk_start_command(state);
- }
- static struct drive_state *
- name_to_drive(const char *drive)
- {
- unsigned int ndrive;
-
- if (strlen(drive) != 3)
- return NULL;
- ndrive = drive[2] - '0';
- if (ndrive > 7)
- return NULL;
- if (!memcmp("dr", drive, 2)) {
-
- return &controllers[MOx].drv[ndrive];
- }
- for (int i = 0; i < CONTROLLER_TYPES; i++) {
- struct ctl_state * const state = &controllers[i];
- if (!memcmp(state->params->name, drive, 2))
- return &state->drv[ndrive];
- }
- return NULL;
- }
- bool valid_drive_name(const char *drive)
- {
- return name_to_drive(drive) != NULL;
- }
- static int mount_drive(struct drive_state *drv, struct ctl_state *state,
- const char *filename)
- {
- FRESULT rv;
- if (mounted(drv)) {
- if (!(sdc.fsstatus & STA_NOINIT))
- f_close(&drv->file);
- drv->flags &= ~DF_MOUNTED;
- state->drives--;
- }
- if (drv->force & DF_DISABLED)
- return -1;
- drv->flags = drv->force & ~DF_MOUNTED;
- if (!filename) {
- return 0;
- } else {
- while (1) {
- BYTE mode = FA_OPEN_EXISTING | FA_READ;
- if (!(drv->flags & DF_READONLY))
- mode |= FA_WRITE;
- rv = f_open(&drv->file, filename, mode);
- if (rv == FR_WRITE_PROTECTED && (mode & FA_WRITE)) {
- drv->flags |= DF_READONLY;
- continue;
- }
- drv->flags |= (rv == FR_OK) ? DF_MOUNTED : DF_DISABLED;
- break;
- }
- if (!(drv->flags & DF_MOUNTED))
- return -1;
- }
- con_printf("abcdisk: %-3s = %s\n", drv->name, filename);
-
- drv->cltbl[0] = CLTBL_SIZE;
- drv->file.cltbl = drv->cltbl;
- rv = f_lseek(&drv->file, CREATE_LINKMAP);
- if (rv != FR_OK) {
- con_printf("abcdisk: %-3s ! file too fragmented, will be slow\n",
- drv->name);
- }
-
- unsigned int filesec = f_size(&drv->file) >> 8;
- drv->sectors = min(filesec, state->params->maxsectors);
-
- #if INTERLEAVE
- drv->ilfac = state->params->ilfac;
- drv->ilmsk = state->params->ilmsk;
- #endif
- state->drives++;
- return 0;
- }
- static void unmount_drives(struct ctl_state *state)
- {
- int i;
- for (int i = 0; i < 8; i++) {
- struct drive_state *drv = &state->drv[i];
- if (drv->flags & DF_MOUNTED)
- mount_drive(drv, state, NULL);
- }
- }
- #define IDLE_CALLBACK_MASK ((1 << 7)|(1 << 4)|(1 << 2))
- static ABC_CALLBACK(abcdisk_callback_out_inp)
- {
- struct ctl_state * const state = container_of(dev, struct ctl_state, iodev);
- dev->callback_mask = IDLE_CALLBACK_MASK;
- __abc_set_inp_status(dev, 0);
- state->error = 0;
- state->pending |= PEND_IO;
- }
- static ABC_CALLBACK(abcdisk_callback_restart)
- {
- struct ctl_state * const state = container_of(dev, struct ctl_state, iodev);
- state->pending |= PEND_STARTCMD;
- }
- static ABC_CALLBACK(abcdisk_callback_rst)
- {
- struct ctl_state * const state = container_of(dev, struct ctl_state, iodev);
- state->pending |= PEND_RESET;
- }
- static char abcdisk_80_800[] = "/abcdisk.800/";
- static const char * const disk_pfx[] = {
- abcdisk_80_800, "/abcdisk/", "/abcdisk.", "/", NULL
- };
- static void init_drives(struct ctl_state *state)
- {
- char *p80;
- int i;
-
- p80 = abcdisk_80_800 + 10 + is_abc800();
- p80[0] = '0';
- p80[1] = '/';
- p80[2] = '\0';
- for (i = 0; i < 8; i++) {
- struct drive_state *drv = &state->drv[i];
- unsigned int filesec;
- const char * const *pfx;
- snprintf(drv->name, sizeof drv->name, "%-.2s%c",
- state->params->name, i + '0');
- for (pfx = disk_pfx; *pfx; pfx++) {
- char filename_buf[64];
- snprintf(filename_buf, sizeof filename_buf,
- "%s%s", *pfx, drv->name);
- if (!mount_drive(drv, state, filename_buf))
- break;
- }
- }
- state->initialized = true;
- }
- static void do_next_command(struct ctl_state *state)
- {
- struct drive_state * const drv = cur_drv_mutable(state);
- uint8_t *buf = cur_buf(state);
- #if 0
- con_printf("%-3s: cmd %02x %02x %02x %02x\n",
- drv->name, state->k[0], state->k[1],
- state->k[2], state->k[3]);
- #endif
- if (state->k[0] & 0x01) {
-
- if (!(drv->flags & DF_MOUNTED)) {
- disk_set_error(state, DISK_NOT_READY);
- } else if (!cur_sector_valid(state)) {
- disk_set_error(state, OUT_OF_RANGE);
- } else {
- UINT rlen = 0;
- FRESULT rv;
- set_led(LED_DISKIO, true);
- abc_set_inp_status(&state->iodev, AS_READING|AS_READY);
- rv = f_lseek(&drv->file, file_pos(state));
- if (rv == FR_OK)
- rv = f_read(&drv->file, buf, 256, &rlen);
- if (rv != FR_OK || rlen != 256) {
- disk_set_error(state, CRC_ERROR);
- }
- }
- state->k[0] &= ~0x01;
- }
- if (state->k[0] & 0x02) {
-
- state->k[0] &= ~0x02;
- state->iodev.callback_mask |= 1 << 8;
- abc_setup_inp_queue(&state->iodev, buf, 256, AS_READY);
- return;
- }
- if (state->k[0] & 0x04) {
-
- state->k[0] &= ~0x04;
- state->iodev.callback_mask |= 1 << 0;
- abc_setup_out_queue(&state->iodev, buf, 256, AS_WRITE|AS_READY);
- return;
- }
- if (state->k[0] & 0x08) {
-
- if (!(drv->flags & DF_MOUNTED)) {
- disk_set_error(state, DISK_NOT_READY);
- } else if (drv->flags & DF_READONLY) {
- disk_set_error(state, WRITE_PROTECT);
- } else if (!cur_sector_valid(state)) {
- disk_set_error(state, OUT_OF_RANGE);
- } else {
- UINT wlen = 0;
- FRESULT rv;
- set_led(LED_DISKIO, true);
- rv = f_lseek(&drv->file, file_pos(state));
- if (rv == FR_OK) {
- drv->flags |= DF_DIRTY;
- rv = f_write(&drv->file, buf, 256, &wlen);
- }
- if (rv != FR_OK || wlen != 256)
- disk_set_error(state, WRITE_FAULT);
- }
- state->k[0] &= ~0x08;
- }
- #if FORMAT_SUPPORT
-
- if (state->k[0] & 0x10 && state->k[1] & 0x08) {
- state->out_ptr = 0;
-
- if (!drv->hf) {
- state->error = 0x80;
- } else if (!file_wrok(hf)) {
- state->error = 0x40;
- } else {
- unsigned int s, c0, c1, s0, s1;
- unsigned int cylsec = state->s * state->h;
- uint8_t data[256];
- unsigned int fmtsec, filesec;
-
- fmtsec = state->params->maxsectors;
-
- memset(data, 0x40, 256);
- if (state->fmtdata_in_buf) {
-
- bool single = false;
- const uint8_t *p, *ep;
- ep = state->buf[1];
- for (p = state->buf[0]+1; p < ep; p++) {
- if (*p == 0xf7)
- single = (p[-1] == 0);
- if (*p == 0xfb)
- break;
- }
- fmtsec >>= single;
- if (*p++ == 0xfb) {
- if (single) {
-
- memcpy(data, p, 128);
- memcpy(data+128, p, 128);
- } else {
- memcpy(data, p, 256);
- }
- }
- }
-
- filesec = drv->hf->filesize >> 8;
- drv->sectors = (filesec && filesec < fmtsec) ? filesec : fmtsec;
-
- c0 = state->k[2];
- s0 = c0 * cylsec;
- c1 = state->k[3] + 1;
- s1 = c1 * cylsec;
- if (tracing(TRACE_DISK)) {
- fprintf(tracef, "%s: formatting cyl %u..%u, sectors %u..%u\n",
- drv->name, c0, c1-1, s0, s1-1);
- }
- clearerr(hf->f);
- state->error = 0;
- for (s = s0; s < s1; s++) {
- unsigned int ps = virt2phys(drv, s);
- if (ps >= drv->sectors) {
- state->error |= 0x02;
- break;
- } else if (hf->map) {
- memcpy(hf->map + (ps << 8), data, 256);
- } else {
- fseek(hf->f, ps << 8, SEEK_SET);
- fwrite(data, 1, 256, hf->f);
- }
- }
- if (ferror(hf->f))
- state->error |= 0x20;
- }
- state->k[1] &= ~0x08;
- }
- if (!(state->k[1] & 0x38))
- state->k[0] &= ~0x10;
- #else
-
- state->k[0] &= ~0x10;
- #endif
- state->k[0] &= ~0xe0;
- disk_start_command(state);
- }
- static FATFS sd_fs;
- static bool sd_mounted;
- static int mount_disk(void)
- {
- FRESULT rv;
- char label[128];
- uint32_t volid, freeclust;
- FATFS *fs;
- set_led(LED_DISKIO, true);
- rv = f_mount(&sd_fs, "", 1);
- if (rv != FR_OK) {
- con_printf("sdcard: no volume found\n");
- set_led(LED_DISKIO, false);
- return -1;
- }
- sd_mounted = true;
- label[0] = '\0';
- volid = 0;
- f_getlabel("", label, &volid);
- con_printf("sdcard: volume found, label \"%s\", volid %08x\n", label, volid);
- freeclust = 0;
- f_getfree("", &freeclust, &fs);
- con_printf("sdcard: %u/%u clusters free, clusters = %u bytes\n",
- freeclust, fs->n_fatent - 2, fs->csize << 9);
-
- rom_flash_from_sdcard();
- return 0;
- }
- #define SYNC_TIME (1*TIMER_HZ)
- void __hot abcdisk_io_poll(void)
- {
- static uint32_t last_sync;
- static uint32_t last_timer = -1U;
- static uint32_t prev_abc_status = -1U;
- uint32_t abc_status_change;
- uint32_t now = timer_count();
- bool need_sync = false;
- uint32_t abc_status = ABC_STATUS & ABC_STATUS_LIVE;
- bool unmount_all = false;
- bool reset_all = false;
- if (now != last_timer) {
-
- if (sdc.status & STA_NOINIT) {
- if (!(sdcard_init() & STA_NOINIT))
- mount_disk();
- unmount_all = true;
- } else if (sdcard_present_poll() & STA_NOINIT) {
- unmount_all = true;
- } else {
- if ((now - last_sync) >= SYNC_TIME) {
- need_sync = true;
- last_sync = now;
- }
- }
- last_timer = now;
- }
-
- if (is_abc800())
- abc_status |= ABC_STATUS_800;
- abc_status_change = abc_status ^ prev_abc_status;
- if (unlikely(abc_status_change)) {
- const char *host;
- prev_abc_status = abc_status;
- set_led(LED_ABCBUS, !!(abc_status & ABC_STATUS_LIVE));
- con_puts("ABC-bus host: ");
- con_puts(abc_status & ABC_STATUS_800 ? "ABC800" : "ABC80");
- con_puts(abc_status & ABC_STATUS_LIVE ? " (online)\n" : " (offline)\n");
- unmount_all = !!(abc_status_change & ABC_STATUS_800);
- reset_all = true;
- need_sync = true;
- }
- for (int i = 0; i < CONTROLLER_TYPES; i++) {
- struct ctl_state * const state = &controllers[i];
- enum pending pending = 0;
- if (unmount_all && state->initialized) {
- unmount_drives(state);
- state->initialized = false;
- } else if (!state->initialized && !(sdc.status & STA_NOINIT)) {
- init_drives(state);
- }
- if (reset_all)
- disk_reset_state(state);
- if (abc_status & ABC_STATUS_LIVE) {
- mask_irq(ABC_IRQ);
- pending = state->pending;
- state->pending = 0;
- unmask_irq(ABC_IRQ);
- if (pending & (PEND_RESET|PEND_STARTCMD))
- disk_reset_state(state);
- else if (pending & PEND_IO)
- do_next_command(state);
- }
- if (state->initialized && (need_sync || (pending & PEND_RESET)))
- sync_drives(state);
- }
- if (need_sync) {
-
- set_led(LED_DISKIO, false);
- }
- }
- void abcdisk_init(void)
- {
- static const struct abc_dev iodev_template = {
- .callback_mask = IDLE_CALLBACK_MASK,
- .inp_en = 3,
- .status_first_out_mask = (uint8_t)~0x80,
- .status_first_inp_mask = (uint8_t)~0x80,
- .callback_out[0] = abcdisk_callback_out_inp,
- .callback_inp[0] = abcdisk_callback_out_inp,
- .callback_out[2] = abcdisk_callback_restart,
- .callback_out[4] = abcdisk_callback_rst,
- .callback_rst = abcdisk_callback_rst
- };
- for (size_t i = 0; i < CONTROLLER_TYPES; i++) {
- struct ctl_state * const state = &controllers[i];
- state->params = ¶meters[i];
- state->iodev = iodev_template;
- state->iodev.name = state->params->name;
- disk_reset_state(state);
- }
- abcdisk_config();
- }
- void abcdisk_config(void)
- {
- for (size_t i = 0; i < CONTROLLER_TYPES; i++) {
- struct ctl_state * const state = &controllers[i];
- unsigned int devsel = getvar_uint(state->params->devsel);
- if (!getvar_bool(state->params->enable))
- devsel = DEVSEL_NONE;
- abc_register(&state->iodev, devsel);
- }
- }
- void abcdisk_shutdown(void)
- {
- if (!sd_mounted)
- return;
- for (int i = 0; i < CONTROLLER_TYPES; i++) {
- struct ctl_state * const state = &controllers[i];
- if (state->initialized)
- unmount_drives(state);
- }
-
- f_unmount("");
-
- disk_ioctl(0, CTRL_SYNC, NULL);
- sd_mounted = false;
- }
|