void UPD765A::process_cmd(int cmd) { switch(cmd & 0x1f) { case 0x02: cmd_read_diagnostic(); break; case 0x03: cmd_specify(); break; case 0x04: cmd_sence_devstat(); break; case 0x05: case 0x09: cmd_write_data(); break; case 0x06: case 0x0c: cmd_read_data(); break; case 0x07: cmd_recalib(); break; case 0x08: cmd_sence_intstat(); break; case 0x0a: cmd_read_id(); break; case 0x0d: cmd_write_id(); break; case 0x0f: cmd_seek(); break; case 0x11: case 0x19: case 0x1d: cmd_scan(); break; default: cmd_invalid(); break; } }
static int main_cmd(int argc, char *argv[]) { if (argc < 1) { return help(); } char *cmd = *argv++; argc--; if (contains(cmd, "key")) { if (argc < 2) { return help(); } uint32_t lockkey = strtoul(argv[0], NULL, 0); hdhomerun_device_tuner_lockkey_use_value(hd, lockkey); cmd = argv[1]; argv+=2; argc-=2; } if (contains(cmd, "get")) { if (argc < 1) { return help(); } return cmd_get(argv[0]); } if (contains(cmd, "set")) { if (argc < 2) { return help(); } return cmd_set(argv[0], argv[1]); } if (contains(cmd, "scan")) { if (argc < 1) { return help(); } if (argc < 2) { return cmd_scan(argv[0], NULL); } else { return cmd_scan(argv[0], argv[1]); } } if (contains(cmd, "save")) { if (argc < 2) { return help(); } return cmd_save(argv[0], argv[1]); } if (contains(cmd, "upgrade")) { if (argc < 1) { return help(); } return cmd_upgrade(argv[0]); } if (contains(cmd, "execute")) { return cmd_execute(); } return help(); }
void fdc_write_data(byte val) { int idx; #ifdef DEBUG_FDC if (FDC.phase == CMD_PHASE) { if (FDC.byte_count) { fprintf(pfoDebug, "%02x ", val); } else { fprintf(pfoDebug, "\n%02x: ", val); } } #endif switch (FDC.phase) { case CMD_PHASE: // in command phase? if (FDC.byte_count) { // receiving command parameters? FDC.command[FDC.byte_count++] = val; // copy to buffer if (FDC.byte_count == FDC.cmd_length) { // received all command bytes? FDC.byte_count = 0; // clear byte counter FDC.phase = EXEC_PHASE; // switch to execution phase FDC.cmd_handler(); } } else { // first command byte received if (val & 0x20) { // skip DAM or DDAM? FDC.flags |= SKIP_flag; // DAM/DDAM will be skipped val &= ~0x20; // reset skip bit in command byte } else { FDC.flags &= ~SKIP_flag; // make sure skip inidicator is off } for (idx = 0; idx < MAX_CMD_COUNT; idx++) { // loop through all known FDC commands if (fdc_cmd_table[idx].cmd == val) { // do we have a match? break; } } if (idx != MAX_CMD_COUNT) { // valid command received FDC.cmd_length = fdc_cmd_table[idx].cmd_length; // command length in bytes FDC.res_length = fdc_cmd_table[idx].res_length; // result length in bytes FDC.cmd_direction = fdc_cmd_table[idx].cmd_direction; // direction is CPU to FDC, or FDC to CPU FDC.cmd_handler = fdc_cmd_table[idx].cmd_handler; // pointer to command handler FDC.command[FDC.byte_count++] = val; // copy command code to buffer if (FDC.byte_count == FDC.cmd_length) { // already received all command bytes? FDC.byte_count = 0; // clear byte counter FDC.phase = EXEC_PHASE; // switch to execution phase FDC.cmd_handler(); } } else { // unknown command received FDC.result[0] = 0x80; // indicate invalid command FDC.res_length = 1; FDC.phase = RESULT_PHASE; // switch to result phase } } break; case EXEC_PHASE: // in execution phase? if (FDC.cmd_direction == CPU_TO_FDC) { // proper direction? FDC.timeout = OVERRUN_TIMEOUT; if ((FDC.flags & SCAN_flag)) { // processing any of the scan commands? if (val != 0xff) { // no comparison on CPU byte = 0xff switch((FDC.command[CMD_CODE] & 0x1f)) { case 0x51: // scan equal if (val != *FDC.buffer_ptr) { FDC.result[RES_ST2] &= 0xf7; // reset Scan Equal Hit FDC.flags |= SCANFAILED_flag; } break; case 0x59: // scan low or equal if (val != *FDC.buffer_ptr) { FDC.result[RES_ST2] &= 0xf7; // reset Scan Equal Hit } if (val > *FDC.buffer_ptr) { FDC.flags |= SCANFAILED_flag; } break; case 0x5d: // scan high or equal if (val != *FDC.buffer_ptr) { FDC.result[RES_ST2] &= 0xf7; // reset Scan Equal Hit } if (val < *FDC.buffer_ptr) { FDC.flags |= SCANFAILED_flag; } break; } } FDC.buffer_ptr++; // advance sector data pointer } else { *FDC.buffer_ptr++ = val; // write byte to sector } if (FDC.buffer_ptr > FDC.buffer_endptr) { FDC.buffer_ptr = active_track->data; // wrap around } if (--FDC.buffer_count == 0) { // processed all data? if ((FDC.flags & SCAN_flag)) { // processing any of the scan commands? if ((FDC.flags & SCANFAILED_flag) && (FDC.command[CMD_R] != FDC.command[CMD_EOT])) { FDC.command[CMD_R] += FDC.command[CMD_STP]; // advance to next sector cmd_scan(); } else { if ((FDC.flags & SCANFAILED_flag)) { FDC.result[RES_ST2] |= 0x04; // Scan Not Satisfied } LOAD_RESULT_WITH_CHRN FDC.phase = RESULT_PHASE; // switch to result phase } } else if (FDC.command[CMD_CODE] == 0x4d) { // write ID command? dword sector_size, track_size; byte *pbPtr, *pbDataPtr; if (active_track->sectors != 0) { // track is formatted? free(active_track->data); // dealloc memory for old track data } sector_size = 128 << FDC.command[CMD_C]; // determine number of bytes from N value if (((sector_size + 62 + FDC.command[CMD_R]) * FDC.command[CMD_H]) > CPC.max_tracksize) { // track size exceeds maximum? active_track->sectors = 0; // 'unformat' track } else { int sector; track_size = sector_size * FDC.command[CMD_H]; active_track->sectors = FDC.command[CMD_H]; active_track->data = (byte *)malloc(track_size); // attempt to allocate the required memory pbDataPtr = active_track->data; pbPtr = pbGPBuffer; for (sector = 0; sector < FDC.command[CMD_H]; sector++) { memcpy(active_track->sector[sector].CHRN, pbPtr, 4); // copy CHRN memset(active_track->sector[sector].flags, 0, 2); // clear ST1 & ST2 active_track->sector[sector].data = pbDataPtr; // store pointer to sector data pbDataPtr += sector_size; pbPtr += 4; } memset(active_track->data, FDC.command[CMD_N], track_size); // fill track data with specified byte value } pbPtr = pbGPBuffer + ((FDC.command[CMD_H]-1) * 4); // pointer to the last CHRN passed to writeID memcpy(&FDC.result[RES_C], pbPtr, 4); // copy sector's CHRN to result buffer FDC.result[RES_N] = FDC.command[CMD_C]; // overwrite with the N value from the writeID command active_drive->altered = 1; // indicate that the image has been modified FDC.phase = RESULT_PHASE; // switch to result phase } else if (FDC.command[CMD_R] != FDC.command[CMD_EOT]) { // haven't reached End of Track? FDC.command[CMD_R]++; // advance to next sector cmd_write(); } else { active_drive->altered = 1; // indicate that the image has been modified FDC.result[RES_ST0] |= 0x40; // AT FDC.result[RES_ST1] |= 0x80; // End of Cylinder LOAD_RESULT_WITH_CHRN FDC.phase = RESULT_PHASE; // switch to result phase } } } break; } }
void UPD765A::write_io8(uint32 addr, uint32 data) { if(addr & 1) { // fdc data if((status & (S_RQM | S_DIO)) == S_RQM) { status &= ~S_RQM; switch(phase) { case PHASE_IDLE: #ifdef _FDC_DEBUG_LOG switch(data & 0x1f) { case 0x02: emu->out_debug_log("FDC: CMD=%2x READ DIAGNOSTIC\n", data); break; case 0x03: emu->out_debug_log("FDC: CMD=%2x SPECIFY\n", data); break; case 0x04: emu->out_debug_log("FDC: CMD=%2x SENCE DEVSTAT\n", data); break; case 0x05: case 0x09: emu->out_debug_log("FDC: CMD=%2x WRITE DATA\n", data); break; case 0x06: case 0x0c: emu->out_debug_log("FDC: CMD=%2x READ DATA\n", data); break; case 0x07: emu->out_debug_log("FDC: CMD=%2x RECALIB\n", data); break; case 0x08: emu->out_debug_log("FDC: CMD=%2x SENCE INTSTAT\n", data); break; case 0x0a: emu->out_debug_log("FDC: CMD=%2x READ ID\n", data); break; case 0x0d: emu->out_debug_log("FDC: CMD=%2x WRITE ID\n", data); break; case 0x0f: emu->out_debug_log("FDC: CMD=%2x SEEK\n", data); break; case 0x11: case 0x19: case 0x1d: emu->out_debug_log("FDC: CMD=%2x SCAN\n", data); break; default: emu->out_debug_log("FDC: CMD=%2x INVALID\n", data); break; } #endif command = data; process_cmd(command & 0x1f); break; case PHASE_CMD: #ifdef _FDC_DEBUG_LOG emu->out_debug_log("FDC: PARAM=%2x\n", data); #endif *bufptr++ = data; if(--count) { status |= S_RQM; } else { process_cmd(command & 0x1f); } break; case PHASE_WRITE: #ifdef _FDC_DEBUG_LOG emu->out_debug_log("FDC: WRITE=%2x\n", data); #endif *bufptr++ = data; set_drq(false); if(--count) { REGISTER_DRQ_EVENT(); } else { process_cmd(command & 0x1f); } fdc[hdu & DRIVE_MASK].access = true; break; case PHASE_SCAN: if(data != 0xff) { if(((command & 0x1f) == 0x11 && *bufptr != data) || ((command & 0x1f) == 0x19 && *bufptr > data) || ((command & 0x1f) == 0x1d && *bufptr < data)) { result &= ~ST2_SH; } } bufptr++; set_drq(false); if(--count) { REGISTER_DRQ_EVENT(); } else { cmd_scan(); } fdc[hdu & DRIVE_MASK].access = true; break; } } } }