Annotation of previous_trunk/src/floppy.c, revision 1.1

1.1     ! root        1: /* Floppy drive emulation */
        !             2: 
        !             3: 
        !             4: #include "ioMem.h"
        !             5: #include "ioMemTables.h"
        !             6: #include "m68000.h"
        !             7: #include "configuration.h"
        !             8: #include "sysReg.h"
        !             9: #include "dma.h"
        !            10: #include "floppy.h"
        !            11: #include "cycInt.h"
        !            12: #include "file.h"
        !            13: #include "statusbar.h"
        !            14: 
        !            15: 
        !            16: #define LOG_FLP_REG_LEVEL   LOG_DEBUG
        !            17: #define LOG_FLP_CMD_LEVEL   LOG_DEBUG
        !            18: 
        !            19: #define IO_SEG_MASK    0x1FFFF
        !            20: 
        !            21: 
        !            22: /* Controller */
        !            23: struct {
        !            24:     Uint8 sra;      /* Status Register A (ro) */
        !            25:     Uint8 srb;      /* Status Register B (ro) */
        !            26:     Uint8 dor;      /* Digital Output Register (rw) */
        !            27:     Uint8 msr;      /* Main Status Register (ro) */
        !            28:     Uint8 dsr;      /* Data Rate Select Register (wo) */
        !            29:     Uint8 fifo[16]; /* Data FIFO (rw) */
        !            30:     Uint8 din;      /* Digital Input Register (wo) */
        !            31:     Uint8 ccr;      /* Configuration Control Register (ro) */
        !            32:     Uint8 ctrl;     /* External Control (rw) */
        !            33:     
        !            34:     Uint8 st[4];    /* Internal Status Registers */
        !            35:     Uint8 pcn;      /* Cylinder Number */
        !            36:     
        !            37:     Uint8 sel;
        !            38:     Uint8 eis;
        !            39: } flp;
        !            40: 
        !            41: Uint8 floppy_select = 0;
        !            42: 
        !            43: /* Drives */
        !            44: struct {
        !            45:     Uint8 cyl;
        !            46:     Uint8 head;
        !            47:     Uint8 sector;
        !            48:     Uint8 blocksize;
        !            49:     
        !            50:     FILE* dsk;
        !            51:     Uint32 floppysize;
        !            52:     
        !            53:     Uint32 seekoffset;
        !            54:     
        !            55:     bool spinning;
        !            56:     
        !            57:     bool protected;
        !            58:     bool inserted;
        !            59:     bool connected;
        !            60: } flpdrv[FLP_MAX_DRIVES];
        !            61: 
        !            62: 
        !            63: /* Register bits */
        !            64: 
        !            65: #define SRA_INT         0x80
        !            66: #define SRA_DRV1_N      0x40
        !            67: #define SRA_STEP        0x20
        !            68: #define SRA_TRK0_N      0x10
        !            69: #define SRA_HDSEL       0x08
        !            70: #define SRA_INDEX_N     0x04
        !            71: #define SRA_WP_N        0x02
        !            72: #define SRA_DIR         0x01
        !            73: 
        !            74: #define SRB_ALL1        0xC0
        !            75: #define SRB_DRVSEL0_N   0x20
        !            76: #define SRB_W_TOGGLE    0x10
        !            77: #define SRB_R_TOGGLE    0x08
        !            78: #define SRB_W_ENABLE    0x04
        !            79: #define SRB_MOTEN_MASK  0x03
        !            80: 
        !            81: #define DOR_MOT3EN      0x80
        !            82: #define DOR_MOT2EN      0x40
        !            83: #define DOR_MOT1EN      0x20
        !            84: #define DOR_MOT0EN      0x10
        !            85: #define DOR_MOTEN_MASK  0xF0
        !            86: #define DOR_DMA_N       0x08
        !            87: #define DOR_RESET_N     0x04
        !            88: #define DOR_SEL_MSK     0x03
        !            89: 
        !            90: #define STAT_RQM        0x80
        !            91: #define STAT_DIO        0x40    /* read = 1 */
        !            92: #define STAT_NONDMA     0x20
        !            93: #define STAT_CMDBSY     0x10
        !            94: #define STAT_DRV3BSY    0x08
        !            95: #define STAT_DRV2BSY    0x04
        !            96: #define STAT_DRV1BSY    0x02
        !            97: #define STAT_DRV0BSY    0x01
        !            98: #define STAT_BSY_MASK   0x0F
        !            99: 
        !           100: #define DSR_RESET       0x80
        !           101: #define DSR_PDOWN       0x40
        !           102: #define DSR_0           0x20
        !           103: #define DSR_PRE_MASK    0x1C
        !           104: #define DSR_RATE_MASK   0x03
        !           105: 
        !           106: #define DIR_DSKCHG      0x80
        !           107: #define DIR_HIDENS_N    0x01
        !           108: 
        !           109: #define CCR_RATE_MASK   0x03
        !           110: 
        !           111: #define CTRL_EJECT      0x80
        !           112: #define CTRL_82077      0x40
        !           113: #define CTRL_DRV_ID     0x04
        !           114: #define CTRL_MEDIA_ID1  0x02
        !           115: #define CTRL_MEDIA_ID0  0x01
        !           116: 
        !           117: 
        !           118: /* Functions */
        !           119: void floppy_reset(bool hard);
        !           120: Uint8 floppy_fifo_read(void);
        !           121: void floppy_fifo_write(Uint8 val);
        !           122: Uint8 floppy_dor_read(void);
        !           123: void floppy_dor_write(Uint8 val);
        !           124: Uint8 floppy_sra_read(void);
        !           125: 
        !           126: 
        !           127: void FLP_StatA_Read(void) { // 0x02014100
        !           128:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = floppy_sra_read();
        !           129:     Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Status A read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           130: }
        !           131: 
        !           132: void FLP_StatB_Read(void) { // 0x02014101
        !           133:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = flp.srb|SRB_ALL1;
        !           134:     Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Status B read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           135: }
        !           136: 
        !           137: void FLP_DataOut_Read(void) { // 0x02014102
        !           138:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = floppy_dor_read();
        !           139:     Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Data out read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           140: }
        !           141: 
        !           142: void FLP_DataOut_Write(void) {
        !           143:     floppy_dor_write(IoMem[IoAccessCurrentAddress & IO_SEG_MASK]);
        !           144:     Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Data out write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           145: }
        !           146: 
        !           147: void FLP_Status_Read(void) { // 0x02014104
        !           148:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = flp.msr;
        !           149:     Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Main status read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           150: }
        !           151: 
        !           152: void FLP_DataRate_Write(void) {
        !           153:     flp.dsr = IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
        !           154:     Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Data rate write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           155:     
        !           156:     if (flp.dsr&DSR_RESET) {
        !           157:         floppy_reset(false);
        !           158:         flp.dsr&=~DSR_RESET;
        !           159:     }
        !           160: }
        !           161: 
        !           162: void FLP_FIFO_Read(void) { // 0x02014105
        !           163:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = floppy_fifo_read();
        !           164:     Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] FIFO read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           165: }
        !           166: 
        !           167: void FLP_FIFO_Write(void) {
        !           168:     Uint8 val = IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
        !           169:     Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] FIFO write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           170:     
        !           171:     floppy_fifo_write(val);
        !           172: }
        !           173: 
        !           174: void FLP_DataIn_Read(void) { // 0x02014107
        !           175:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = flp.din;
        !           176:     Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Data in read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           177: }
        !           178: 
        !           179: void FLP_Configuration_Write(void) {
        !           180:     flp.ccr = IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
        !           181:     Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Configuration write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           182: }
        !           183: 
        !           184: void FLP_Control_Read(void) { // 0x02014108
        !           185:     Uint8 val;
        !           186:     if (ConfigureParams.System.nMachineType==NEXT_CUBE030)
        !           187:         val=flp.ctrl&~CTRL_DRV_ID;
        !           188:     else
        !           189:         val=flp.ctrl;
        !           190:     
        !           191:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = val;
        !           192:     Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Control read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           193: }
        !           194: 
        !           195: void FLP_Select_Write(void) {
        !           196:     Uint8 val;
        !           197:     val = IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
        !           198:     Log_Printf(LOG_DEBUG,"[Floppy] Select write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
        !           199: 
        !           200:     if (ConfigureParams.System.nMachineType!=NEXT_CUBE030) {
        !           201:         set_floppy_select(val&CTRL_82077,false);
        !           202:     }
        !           203:     
        !           204:     if (val&CTRL_EJECT) {
        !           205:         Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Ejecting floppy disk");
        !           206:         Floppy_Eject(-1);
        !           207:     }
        !           208: }
        !           209: 
        !           210: void set_floppy_select(Uint8 sel, bool osp) {
        !           211:     if (sel) {
        !           212:         Log_Printf(LOG_DEBUG,"[%s] Selecting floppy controller",osp?"OSP":"Floppy");
        !           213:         floppy_select = 1;
        !           214:     } else {
        !           215:         Log_Printf(LOG_FLP_REG_LEVEL,"[%s] Selecting SCSI controller",osp?"OSP":"Floppy");
        !           216:         floppy_select = 0;
        !           217:     }
        !           218: }
        !           219: 
        !           220: enum {
        !           221:     FLP_STATE_WRITE,
        !           222:     FLP_STATE_READ,
        !           223:     FLP_STATE_FORMAT,
        !           224:     FLP_STATE_INTERRUPT,
        !           225:     FLP_STATE_DONE
        !           226: } flp_io_state;
        !           227: 
        !           228: int flp_sector_counter = 0;
        !           229: int flp_io_drv = 0;
        !           230: 
        !           231: 
        !           232: /* Internal registers */
        !           233: 
        !           234: #define ST0_IC      0xC0    /* Interrupt Code (0 = normal termination) */
        !           235: #define ST0_SE      0x20    /* Seek End */
        !           236: #define ST0_EC      0x10    /* Equipment Check */
        !           237: #define ST0_H       0x04    /* Head Address */
        !           238: #define ST0_DS      0x03    /* Drive Select */
        !           239: 
        !           240: #define ST1_EN      0x80    /* End of Cylinder */
        !           241: #define ST1_DE      0x20    /* Data Error */
        !           242: #define ST1_OR      0x10    /* Overrun/Underrun */
        !           243: #define ST1_ND      0x04    /* No Data */
        !           244: #define ST1_NW      0x02    /* Not writable */
        !           245: #define ST1_MA      0x01    /* Missing Address Mark */
        !           246: 
        !           247: #define ST2_CM      0x40    /* Control Mark */
        !           248: #define ST2_DD      0x20    /* Data Error in Data Field */
        !           249: #define ST2_WC      0x10    /* Wrong Cylinder */
        !           250: #define ST2_BC      0x02    /* Bad Cylinder */
        !           251: #define ST2_MD      0x01    /* Missing Data Address Mark */
        !           252: 
        !           253: #define ST3_WP      0x40    /* Write Protected */
        !           254: #define ST3_T0      0x10    /* Track 0 */
        !           255: #define ST3_HD      0x04    /* Head Address */
        !           256: #define ST3_DS      0x03    /* Drive Select */
        !           257: 
        !           258: 
        !           259: #define IC_NORMAL   0x00
        !           260: #define IC_ABNORMAL 0x40
        !           261: #define IC_INV_CMD  0x80
        !           262: 
        !           263: 
        !           264: 
        !           265: void floppy_reset(bool hard) {
        !           266:     Log_Printf(LOG_WARN,"[Floppy] Reset.");
        !           267:     
        !           268:     flp.sra &= ~(SRA_INT|SRA_STEP|SRA_HDSEL|SRA_DIR);
        !           269:     flp.srb &= ~(SRB_R_TOGGLE|SRB_W_TOGGLE);
        !           270:     flp.msr |= STAT_RQM;
        !           271:     flp.msr &= ~STAT_DIO;
        !           272:        
        !           273:     if (hard) {
        !           274:         flp_io_state = FLP_STATE_DONE;
        !           275:         flp.dor &= ~DOR_RESET_N;
        !           276:         flp.srb &= ~(SRB_MOTEN_MASK|SRB_DRVSEL0_N);
        !           277:         flp.din &= ~DIR_HIDENS_N;
        !           278:         flp.st[0]=flp.st[1]=flp.st[2]=flp.st[3]=0;
        !           279:         flp.pcn=0;
        !           280:     } else {
        !           281:         /* Single poll interrupt after reset (delay = 250 ms) */
        !           282:         flp_io_state = FLP_STATE_INTERRUPT;
        !           283:         CycInt_AddRelativeInterruptUs(250*1000, 0, INTERRUPT_FLP_IO);
        !           284:     }
        !           285: }
        !           286: 
        !           287: /* Floppy commands */
        !           288: 
        !           289: #define CMD_MT_MSK      0x80
        !           290: #define CMD_MFM_MSK     0x40
        !           291: #define CMD_SK_MSK      0x20
        !           292: #define CMD_OPCODE_MSK  0x1F
        !           293: 
        !           294: #define CMD_READ        0x06
        !           295: #define CMD_READ_DEL    0x0C
        !           296: #define CMD_WRITE       0x05
        !           297: #define CMD_WRITE_DEL   0x09
        !           298: #define CMD_READ_TRK    0x02
        !           299: #define CMD_VERIFY      0x16
        !           300: #define CMD_VERSION     0x10
        !           301: #define CMD_FORMAT      0x0D
        !           302: #define CMD_SCAN_E      0x11
        !           303: #define CMD_SCAN_LE     0x19
        !           304: #define CMD_SCAN_HE     0x1D
        !           305: #define CMD_RECAL       0x07
        !           306: #define CMD_INTSTAT     0x08
        !           307: #define CMD_SPECIFY     0x03
        !           308: #define CMD_DRV_STATUS  0x04
        !           309: #define CMD_SEEK        0x0F
        !           310: #define CMD_CONFIGURE   0x13
        !           311: #define CMD_DUMPREG     0x0E
        !           312: #define CMD_READ_ID     0x0A
        !           313: #define CMD_PERPEND     0x12
        !           314: #define CMD_LOCK        0x14
        !           315: 
        !           316: Uint8 cmd_data_size[] = {
        !           317:     0,0,8,2,1,8,8,1,
        !           318:     0,8,1,0,8,5,0,2,
        !           319:     0,8,1,3,0,0,8,0,
        !           320:     0,8,0,0,0,8,0,0
        !           321: };
        !           322: 
        !           323: bool cmd_phase = false;
        !           324: int cmd_size = 0;
        !           325: int cmd_limit = 0;
        !           326: Uint8 command;
        !           327: Uint8 cmd_data[8];
        !           328: 
        !           329: int result_size = 0;
        !           330: 
        !           331: static void floppy_interrupt(void) {
        !           332:     Log_Printf(LOG_FLP_CMD_LEVEL,"[Floppy] Interrupt.");
        !           333:     
        !           334:     if (result_size>0) {
        !           335:         /* Go to result phase */
        !           336:         flp.msr |= (STAT_RQM|STAT_DIO);
        !           337:     } else {
        !           338:         flp.msr |= STAT_RQM;
        !           339:     }
        !           340:     
        !           341:     flp.msr &= ~(STAT_BSY_MASK);
        !           342:     flp.sra |= SRA_INT;
        !           343:     set_interrupt(INT_PHONE, SET_INT);
        !           344: }
        !           345: 
        !           346: /* -- Helpers -- */
        !           347: 
        !           348: /* Geometry */
        !           349: #define SIZE_720K    737280
        !           350: #define SIZE_1440K  1474560
        !           351: #define SIZE_2880K  2949120
        !           352: 
        !           353: #define NUM_CYLINDERS   80
        !           354: #define TRACKS_PER_CYL  2
        !           355: 
        !           356: static Uint32 physical_to_logical_sector(Uint8 c, Uint8 h, Uint8 s, int drive) {
        !           357:     Uint32 disksize = flpdrv[drive].floppysize;
        !           358:     Uint32 blocksize = 0x80<<flpdrv[drive].blocksize;
        !           359:     Uint32 spt = disksize/blocksize/TRACKS_PER_CYL/NUM_CYLINDERS;
        !           360:     
        !           361:     Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Geometry: Cylinders: %i, Tracks per cylinder: %i, Sectors per track: %i, Blocksize: %i",
        !           362:                NUM_CYLINDERS,TRACKS_PER_CYL,spt,blocksize);
        !           363:     
        !           364:     if (s>spt) {
        !           365:         Log_Printf(LOG_WARN, "[Floppy] Geometry error: sector (%i) beyond limit (%i)!",s,spt);
        !           366:         flp.st[0] |= IC_ABNORMAL;
        !           367:         flp.st[1] |= ST1_EN;
        !           368:     }
        !           369:     
        !           370:     return (((c*TRACKS_PER_CYL)+h)*spt)+s-1;
        !           371: }
        !           372: 
        !           373: static void check_blocksize(int drive, Uint8 blocksize) {
        !           374:     if (blocksize!=flpdrv[drive].blocksize) {
        !           375:         Log_Printf(LOG_WARN, "[Floppy] Geometry error: Blocksize not supported (%i)!",blocksize);
        !           376:         flp.st[0] |= IC_ABNORMAL;
        !           377:         flp.st[1] |= ST1_ND;
        !           378:     }
        !           379: }
        !           380: 
        !           381: static void check_protection(int drive) {
        !           382:     if (flpdrv[drive].protected) {
        !           383:         Log_Printf(LOG_WARN, "[Floppy] Protection error: Disk is read-only!");
        !           384:         flp.st[0] |= IC_ABNORMAL;
        !           385:         flp.st[1] |= ST1_NW;
        !           386:     }
        !           387: }
        !           388: 
        !           389: static void floppy_seek_track(Uint8 c, Uint8 h, int drive) {
        !           390:     if (c>(NUM_CYLINDERS-1)) /* CHECK: does this cause an error? */
        !           391:         c=(NUM_CYLINDERS-1);
        !           392:     
        !           393:     flp.st[0] |= ST0_SE;
        !           394:     
        !           395:     flpdrv[drive].seekoffset = (flpdrv[drive].cyl < c) ? (c - flpdrv[drive].cyl) : (flpdrv[drive].cyl - c);
        !           396:     flpdrv[drive].cyl = c;
        !           397:     flpdrv[drive].head = h;
        !           398: }
        !           399: 
        !           400: /* Timings */
        !           401: #define FLP_SEEK_TIME 200000 /* 200 ms */
        !           402: 
        !           403: static int get_sector_time(int drive) {
        !           404:     switch (flpdrv[drive].floppysize) {
        !           405:         case SIZE_720K: return 22000;
        !           406:         case SIZE_1440K: return 11000;
        !           407:         case SIZE_2880K: return 5500;
        !           408:         default: return 1000;
        !           409:     }
        !           410: }
        !           411: 
        !           412: static int get_seek_time(int drive) {
        !           413:     if (flpdrv[drive].seekoffset > NUM_CYLINDERS) {
        !           414:         return FLP_SEEK_TIME;
        !           415:     }
        !           416:     
        !           417:     return (flpdrv[drive].seekoffset * FLP_SEEK_TIME / NUM_CYLINDERS);
        !           418: }
        !           419: 
        !           420: /* Media IDs for control register */
        !           421: #define MEDIA_ID_NONE   0
        !           422: #define MEDIA_ID_720K   3
        !           423: #define MEDIA_ID_1440K  2
        !           424: #define MEDIA_ID_2880K  1
        !           425: #define MEDIA_ID_MSK    3
        !           426: 
        !           427: static Uint8 get_media_id(int drive) {
        !           428:     if (!flpdrv[drive].inserted) {
        !           429:         return MEDIA_ID_NONE;
        !           430:     } else {
        !           431:         switch (flpdrv[drive].floppysize) {
        !           432:             case SIZE_720K: return MEDIA_ID_720K;
        !           433:             case SIZE_1440K: return MEDIA_ID_1440K;
        !           434:             case SIZE_2880K: return MEDIA_ID_2880K;
        !           435:             default: return MEDIA_ID_NONE;
        !           436:         }
        !           437:     }
        !           438: }
        !           439: 
        !           440: /* Validate data rate */
        !           441: #define CCR_RATE250     0x02
        !           442: #define CCR_RATE500     0x00
        !           443: #define CCR_RATE1000    0x03
        !           444: 
        !           445: static void check_data_rate(int drive) {
        !           446:     switch (flpdrv[drive].floppysize) {
        !           447:         case SIZE_720K:
        !           448:             if ((flp.ccr&CCR_RATE_MASK)==CCR_RATE250) {
        !           449:                 return;
        !           450:             }
        !           451:             break;
        !           452:         case SIZE_1440K:
        !           453:             if ((flp.ccr&CCR_RATE_MASK)==CCR_RATE500) {
        !           454:                 return;
        !           455:             }
        !           456:             break;
        !           457:         case SIZE_2880K:
        !           458:             if ((flp.ccr&CCR_RATE_MASK)==CCR_RATE1000) {
        !           459:                 return;
        !           460:             }
        !           461:             break;
        !           462: 
        !           463:         default:
        !           464:             break;
        !           465:     }
        !           466:     Log_Printf(LOG_WARN, "[Floppy] Invalid data rate %02X",flp.ccr&CCR_RATE_MASK);
        !           467:     flp.st[0] |= IC_ABNORMAL;
        !           468:     flp.st[1] |= ST1_ND;
        !           469: }
        !           470: 
        !           471: static void send_rw_status(int drive) {
        !           472:     flp.st[0] |= drive|(flpdrv[drive].head<<2);
        !           473:     flp.fifo[0] = flp.st[0];
        !           474:     flp.fifo[1] = flp.st[1];
        !           475:     flp.fifo[2] = flp.st[2];
        !           476:     flp.fifo[3] = flpdrv[drive].cyl;
        !           477:     flp.fifo[4] = flpdrv[drive].head;
        !           478:     flp.fifo[5] = flpdrv[drive].sector;
        !           479:     flp.fifo[6] = flpdrv[drive].blocksize;
        !           480:     result_size = 7;
        !           481: }
        !           482: 
        !           483: /* -- Floppy commands -- */
        !           484: 
        !           485: static void floppy_read(void) {
        !           486:     int drive = cmd_data[0]&0x03;
        !           487:     int head = (cmd_data[0]&0x04)>>2;
        !           488:     Uint8 c = cmd_data[1];
        !           489:     Uint8 h = cmd_data[2];
        !           490:     Uint8 s = cmd_data[3];
        !           491:     Uint8 bs = cmd_data[4];
        !           492:     
        !           493:     Uint32 sector_size, num_sectors, logical_sec;
        !           494:     
        !           495:     flp.st[0] = flp.st[1] = flp.st[2] = 0;
        !           496:     
        !           497:     /* If implied seek is enabled, seek track */
        !           498:     if (flp.eis) {
        !           499:         floppy_seek_track(c, h, drive);
        !           500:     }
        !           501:     /* Set start sector */
        !           502:     flpdrv[drive].sector = s;
        !           503:     
        !           504:     /* Match actual track with specified track */
        !           505:     if (flpdrv[drive].cyl!=c || flpdrv[drive].head!=h || flpdrv[drive].head!=head) {
        !           506:         Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Read: track mismatch!");
        !           507:         flp.st[0]|=IC_ABNORMAL;
        !           508:         flp.st[2]|=ST2_WC;
        !           509:     }
        !           510:     /* Validate blocksize */
        !           511:     check_blocksize(drive,bs);
        !           512:     sector_size = 0x80<<bs;
        !           513:     
        !           514:     /* Validate data rate */
        !           515:     check_data_rate(drive);
        !           516: 
        !           517:     Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Read: Cylinder=%i, Head=%i, Sector=%i, Blocksize=%i",
        !           518:                flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,sector_size);
        !           519:     
        !           520:     /* Get sector transfer count and logical sector offset */
        !           521:     num_sectors = cmd_data[5]-cmd_data[3]+1;
        !           522:     logical_sec = physical_to_logical_sector(flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,drive);
        !           523:     
        !           524:     Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Read %i sectors at offset %i",num_sectors,logical_sec);
        !           525:     
        !           526:     if (flp.st[0]&IC_ABNORMAL) {
        !           527:         send_rw_status(drive);
        !           528:         flp_io_state = FLP_STATE_INTERRUPT;
        !           529:     } else {
        !           530:         flp_buffer.size = 0;
        !           531:         flp_buffer.limit = sector_size;
        !           532:         flp_sector_counter = num_sectors;
        !           533:         flp_io_drv = drive;
        !           534:         flp_io_state = FLP_STATE_READ;
        !           535:     }
        !           536:     CycInt_AddRelativeInterruptUs(get_seek_time(drive) + get_sector_time(drive), 100, INTERRUPT_FLP_IO);
        !           537: }
        !           538: 
        !           539: static void floppy_write(void) {
        !           540:     int drive = cmd_data[0]&0x03;
        !           541:     int head = (cmd_data[0]&0x04)>>2;
        !           542:     Uint8 c = cmd_data[1];
        !           543:     Uint8 h = cmd_data[2];
        !           544:     Uint8 s = cmd_data[3];
        !           545:     Uint8 bs = cmd_data[4];
        !           546:     
        !           547:     Uint32 sector_size, num_sectors, logical_sec;
        !           548:     
        !           549:     flp.st[0] = flp.st[1] = flp.st[2] = 0;
        !           550:     
        !           551:     /* If implied seek is enabled, seek track */
        !           552:     if (flp.eis) {
        !           553:         floppy_seek_track(c, h, drive);
        !           554:     }
        !           555:     /* Set start sector */
        !           556:     flpdrv[drive].sector = s;
        !           557:     
        !           558:     /* Match actual track with specified track */
        !           559:     if (flpdrv[drive].cyl!=c || flpdrv[drive].head!=h || flpdrv[drive].head!=head) {
        !           560:         Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Write: track mismatch!");
        !           561:         flp.st[0]|=IC_ABNORMAL;
        !           562:         flp.st[2]|=ST2_WC;
        !           563:     }
        !           564:     /* Validate blocksize */
        !           565:     check_blocksize(drive,bs);
        !           566:     sector_size = 0x80<<bs;
        !           567:     
        !           568:     /* Validate data rate */
        !           569:     check_data_rate(drive);
        !           570:     
        !           571:     /* Check protection */
        !           572:     check_protection(drive);
        !           573:     
        !           574:     Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Write: Cylinder=%i, Head=%i, Sector=%i, Blocksize=%i",
        !           575:                flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,sector_size);
        !           576:     
        !           577:     /* Get sector transfer count and logical sector offset */
        !           578:     num_sectors = cmd_data[5]-cmd_data[3]+1;
        !           579:     logical_sec = physical_to_logical_sector(flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,drive);
        !           580:     
        !           581:     Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Write %i sectors at offset %i",num_sectors,logical_sec);
        !           582:     
        !           583:     if (flp.st[0]&IC_ABNORMAL) {
        !           584:         send_rw_status(drive);
        !           585:         flp_io_state = FLP_STATE_INTERRUPT;
        !           586:     } else {
        !           587:         flp_buffer.size = 0;
        !           588:         flp_buffer.limit = sector_size;
        !           589:         flp_sector_counter = num_sectors;
        !           590:         flp_io_drv = drive;
        !           591:         flp_io_state = FLP_STATE_WRITE;
        !           592:     }
        !           593:     CycInt_AddRelativeInterruptUs(get_seek_time(drive) + get_sector_time(drive), 100, INTERRUPT_FLP_IO);
        !           594: }
        !           595: 
        !           596: static void floppy_format(void) {
        !           597:     int drive = cmd_data[0]&0x03;
        !           598:     int head = (cmd_data[0]&0x04)>>2;
        !           599:     
        !           600:     flp.st[0] = flp.st[1] = flp.st[2] = 0;
        !           601:     
        !           602:     Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Format: Cylinder=%i, Head=%i",flpdrv[drive].cyl,head);
        !           603:     
        !           604:     /* Validate data rate */
        !           605:     check_data_rate(drive);
        !           606:     
        !           607:     /* Check protection */
        !           608:     check_protection(drive);
        !           609:     
        !           610:     if (flp.st[0]&IC_ABNORMAL) {
        !           611:         send_rw_status(drive);
        !           612:         flp_io_state = FLP_STATE_INTERRUPT;
        !           613:     } else {
        !           614:         flp_buffer.size = 0;
        !           615:         flp_buffer.limit = 4;
        !           616:         flp_io_drv = drive;
        !           617:         flp_io_state = FLP_STATE_FORMAT;
        !           618:         CycInt_AddRelativeInterruptUs(get_seek_time(drive) + get_sector_time(drive), 100, INTERRUPT_FLP_IO);
        !           619:     }
        !           620: }
        !           621: 
        !           622: static void floppy_read_id(void) {
        !           623:     int drive = cmd_data[0]&0x03;
        !           624:     int head = (cmd_data[0]&0x04)>>2;
        !           625:     
        !           626:     Uint32 sec_size = 0x80<<flpdrv[drive].blocksize;
        !           627:     
        !           628:     if (flpdrv[drive].head!=head)
        !           629:         abort();
        !           630:     
        !           631:     Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Read ID: Cylinder=%i, Head=%i, Sector=%i, Blocksize=%i",
        !           632:                flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,sec_size);
        !           633:     
        !           634:     flp.st[0] = flp.st[1] = flp.st[2] = 0;
        !           635:     
        !           636:     check_data_rate(drive); /* check data rate */
        !           637:     send_rw_status(drive);
        !           638:     
        !           639:     flp_io_state = FLP_STATE_INTERRUPT;
        !           640:     CycInt_AddRelativeInterruptUs(get_seek_time(drive), 100, INTERRUPT_FLP_IO);
        !           641: }
        !           642: 
        !           643: static void floppy_recalibrate(void) {
        !           644:     int drive = cmd_data[0]&0x03;
        !           645:     Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Drive = %i",drive);
        !           646: 
        !           647:     if (flpdrv[drive].connected) {
        !           648:         flp.msr |= (1<<drive); /* drive busy */
        !           649:         flp.dor &= 0xFC; /* CHECK: really needed? */
        !           650:         flp.dor |= drive;
        !           651:         flpdrv[drive].cyl = flp.pcn = 0;
        !           652: 
        !           653:         flp.st[0] = flp.st[1] = flp.st[2] = 0;
        !           654:         floppy_seek_track(0, 0, drive);
        !           655: 
        !           656:         /* Done */
        !           657:         flp.st[0] = IC_NORMAL|ST0_SE;
        !           658:         flp.sra &= ~SRA_TRK0_N;
        !           659:         
        !           660:         flp_io_state = FLP_STATE_INTERRUPT;
        !           661:         CycInt_AddRelativeInterruptUs(get_seek_time(drive), 100, INTERRUPT_FLP_IO);
        !           662:     }
        !           663: }
        !           664: 
        !           665: static void floppy_seek(Uint8 relative) {
        !           666:     int drive = cmd_data[0]&0x03;
        !           667:     int head = (cmd_data[0]&0x04)>>2;
        !           668:     flp.st[0] = flp.st[1] = flp.st[2] = 0;
        !           669:     
        !           670:     if (relative) {
        !           671:         Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Relative seek: Head %i: %i cylinders",head,0);
        !           672:         abort();
        !           673:     } else {
        !           674:         Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Seek: Head %i to cylinder %i",head,flpdrv[drive].cyl);
        !           675:         flp.st[0] = IC_NORMAL;
        !           676: 
        !           677:         floppy_seek_track(cmd_data[1], head, drive);
        !           678:         if (!(flp.st[0]&IC_ABNORMAL)) {
        !           679:             flp.pcn = flpdrv[drive].cyl;
        !           680:         }
        !           681:     }
        !           682:         
        !           683:     flp_io_state = FLP_STATE_INTERRUPT;
        !           684:     CycInt_AddRelativeInterruptUs(get_seek_time(drive), 100, INTERRUPT_FLP_IO);
        !           685: }
        !           686: 
        !           687: static void floppy_interrupt_status(void) {
        !           688:     /* Release interrupt */
        !           689:     set_interrupt(INT_PHONE, RELEASE_INT);
        !           690:     flp.sra &= ~SRA_INT;
        !           691:     /* Go to result phase */
        !           692:     flp.msr |= (STAT_RQM|STAT_DIO);
        !           693:     /* Return data */
        !           694:     flp.fifo[0] = flp.st[0];
        !           695:     flp.fifo[1] = flp.pcn;
        !           696:     result_size = 2;
        !           697: }
        !           698: 
        !           699: static void floppy_specify(void) {
        !           700:     Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Specify: %02X %02X",cmd_data[0],cmd_data[1]);
        !           701: 
        !           702:     if (cmd_data[1]&0x01) {
        !           703:         Log_Printf(LOG_WARN, "[Floppy] Specify: Non-DMA mode");
        !           704:     } else {
        !           705:         Log_Printf(LOG_WARN, "[Floppy] Specify: DMA mode");
        !           706:     }
        !           707:     flp.msr |= STAT_RQM;
        !           708: }
        !           709: 
        !           710: static void floppy_configure(void) {
        !           711:     Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Configure: %02X %02X %02X",cmd_data[0],cmd_data[1],cmd_data[2]);
        !           712:     
        !           713:     flp.eis = cmd_data[1]&0x40; /* Enable or disable implied seek */
        !           714: 
        !           715:     if (cmd_data[1]&0x10) {
        !           716:         Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Configure: disable polling");
        !           717:         if (CycInt_InterruptActive(INTERRUPT_FLP_IO)) {
        !           718:             Log_Printf(LOG_WARN, "[Floppy] Disable pending reset poll interrupt");
        !           719:             CycInt_RemovePendingInterrupt(INTERRUPT_FLP_IO);
        !           720:         }
        !           721:     }
        !           722:     if (cmd_data[2]) {
        !           723:         abort();
        !           724:     }
        !           725:     flp.msr |= STAT_RQM;
        !           726: }
        !           727: 
        !           728: static void floppy_perpendicular(void) {
        !           729:     Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Perpendicular: %02X",cmd_data[0]);
        !           730:     flp.msr |= STAT_RQM;
        !           731: }
        !           732: 
        !           733: static void floppy_unimplemented(void) {
        !           734:     flp.st[0] = IC_INV_CMD;
        !           735:     
        !           736:     flp.fifo[0] = flp.st[0];
        !           737:     result_size = 1;
        !           738:     
        !           739:     flp_io_state = FLP_STATE_INTERRUPT;
        !           740:     CycInt_AddRelativeInterruptUs(1000, 100, INTERRUPT_FLP_IO);
        !           741: }
        !           742: 
        !           743: static void floppy_execute_cmd(void) {
        !           744:     Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Executing %02X",command);
        !           745:     
        !           746:     switch (command&CMD_OPCODE_MSK) {
        !           747:         case CMD_READ:
        !           748:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Read");
        !           749:             floppy_read();
        !           750:             break;
        !           751:         case CMD_READ_DEL:
        !           752:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Read and delete");
        !           753:             abort();
        !           754:             break;
        !           755:         case CMD_WRITE:
        !           756:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Write");
        !           757:             floppy_write();
        !           758:             break;
        !           759:         case CMD_WRITE_DEL:
        !           760:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Write and delete");
        !           761:             abort();
        !           762:             break;
        !           763:         case CMD_READ_TRK:
        !           764:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Read track");
        !           765:             abort();
        !           766:             break;
        !           767:         case CMD_VERIFY:
        !           768:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Verify");
        !           769:             abort();
        !           770:             break;
        !           771:         case CMD_VERSION:
        !           772:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Version");
        !           773:             abort();
        !           774:             break;
        !           775:         case CMD_FORMAT:
        !           776:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Format");
        !           777:             floppy_format();
        !           778:             break;
        !           779:         case CMD_SCAN_E:
        !           780:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Scan equal");
        !           781:             abort();
        !           782:             break;
        !           783:         case CMD_SCAN_LE:
        !           784:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Scan lower or equal");
        !           785:             abort();
        !           786:             break;
        !           787:         case CMD_SCAN_HE:
        !           788:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Scan higher or equal");
        !           789:             abort();
        !           790:             break;
        !           791:         case CMD_RECAL:
        !           792:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Recalibrate");
        !           793:             floppy_recalibrate();
        !           794:             break;
        !           795:         case CMD_INTSTAT:
        !           796:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Interrupt status");
        !           797:             floppy_interrupt_status();
        !           798:             break;
        !           799:         case CMD_SPECIFY:
        !           800:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Specify");
        !           801:             floppy_specify();
        !           802:             break;
        !           803:         case CMD_DRV_STATUS:
        !           804:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Drive status");
        !           805:             abort();
        !           806:             break;
        !           807:         case CMD_SEEK:
        !           808:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Seek");
        !           809:             floppy_seek(command&0x80);
        !           810:             break;
        !           811:         case CMD_CONFIGURE:
        !           812:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Configure");
        !           813:             floppy_configure();
        !           814:             break;
        !           815:         case CMD_DUMPREG:
        !           816:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Dump register");
        !           817:             abort();
        !           818:             break;
        !           819:         case CMD_READ_ID:
        !           820:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Read ID");
        !           821:             floppy_read_id();
        !           822:             break;
        !           823:         case CMD_PERPEND:
        !           824:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Perpendicular");
        !           825:             floppy_perpendicular();
        !           826:             break;
        !           827:         case CMD_LOCK:
        !           828:             Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Command: Lock");
        !           829:             abort();
        !           830:             break;
        !           831: 
        !           832:         default:
        !           833:             Log_Printf(LOG_WARN, "[Floppy] Command: Unknown");
        !           834:             floppy_unimplemented();
        !           835:             break;
        !           836:     }
        !           837:     Statusbar_BlinkLed(DEVICE_LED_FD);
        !           838: }
        !           839: 
        !           840: void floppy_fifo_write(Uint8 val) {
        !           841:     
        !           842:     flp.msr &= ~STAT_RQM;
        !           843:     
        !           844:     if (!cmd_phase) {
        !           845:         cmd_phase = true;
        !           846:         command = val;
        !           847:         cmd_limit = cmd_size = cmd_data_size[val&CMD_OPCODE_MSK];
        !           848:         flp.msr |= STAT_RQM;
        !           849:     } else if (cmd_size>0) {
        !           850:         cmd_data[cmd_limit-cmd_size]=val;
        !           851:         cmd_size--;
        !           852:         flp.msr |= STAT_RQM;
        !           853:     }
        !           854:     
        !           855:     if (cmd_size==0) {
        !           856:         cmd_phase = false;
        !           857:         floppy_execute_cmd();
        !           858:     }
        !           859: }
        !           860: 
        !           861: Uint8 floppy_fifo_read(void) {
        !           862:     int i;
        !           863:     Uint8 val;
        !           864:     if (result_size>0) {
        !           865:         val = flp.fifo[0];
        !           866:         for (i=0; i<(16-1); i++)
        !           867:             flp.fifo[i]=flp.fifo[i+1];
        !           868:         flp.fifo[16-1] = 0x00;
        !           869:         result_size--;
        !           870:         Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] FIFO reading byte, val=%02x", val);
        !           871:     } else {
        !           872:         Log_Printf(LOG_WARN,"[Floppy] FIFO is emtpy!");
        !           873:         val = 0;
        !           874:     }
        !           875:     
        !           876:     if (result_size==0) {
        !           877:         flp.msr |= STAT_RQM;
        !           878:         flp.msr &= ~STAT_DIO;
        !           879:         /* FIXME: does this really belong here? */
        !           880:         set_interrupt(INT_PHONE, RELEASE_INT);
        !           881:         flp.sra &= ~SRA_INT;
        !           882:     }
        !           883:     
        !           884:     return val;
        !           885: }
        !           886: 
        !           887: void floppy_dor_write(Uint8 val) {
        !           888:     if ((val&DOR_SEL_MSK)!=flp.sel) {
        !           889:         Log_Printf(LOG_FLP_CMD_LEVEL,"[Floppy] Selecting drive %i.",val&DOR_SEL_MSK);
        !           890:     }
        !           891:     flp.sel = val&DOR_SEL_MSK;
        !           892:     
        !           893:     flp.dor &= ~DOR_SEL_MSK;
        !           894:     flp.dor |= flp.sel;
        !           895:     
        !           896:     
        !           897:     if (!(val&DOR_RESET_N)) {
        !           898:         flp.dor &= ~DOR_RESET_N;
        !           899:         floppy_reset(false);
        !           900:     } else {
        !           901:         flp.dor |= DOR_RESET_N;
        !           902:         Log_Printf(LOG_FLP_REG_LEVEL,"[Floppy] Clear reset state.");
        !           903:     }
        !           904:     if (flpdrv[flp.sel].connected) {
        !           905:         flp.ctrl &= ~CTRL_DRV_ID;
        !           906: 
        !           907:         if (val&(0x10<<flp.sel)) { /* motor enable */
        !           908:             Log_Printf(LOG_FLP_CMD_LEVEL,"[Floppy] Starting motor of drive %i.",flp.sel);
        !           909:             flp.ctrl &= ~MEDIA_ID_MSK;
        !           910:             flp.ctrl |= get_media_id(flp.sel);
        !           911:             flpdrv[flp.sel].spinning = true;
        !           912:         } else {
        !           913:             Log_Printf(LOG_FLP_CMD_LEVEL,"[Floppy] Stopping motor of drive %i.",flp.sel);
        !           914:             flp.ctrl &= ~MEDIA_ID_MSK;          /* CHECK: really delete ID? */
        !           915:             flpdrv[flp.sel].spinning = false;
        !           916:         }
        !           917:     } else {
        !           918:         flp.ctrl |= CTRL_DRV_ID;
        !           919:     }
        !           920: }
        !           921: 
        !           922: Uint8 floppy_dor_read(void) {
        !           923:     int i;
        !           924:     Uint8 val = flp.dor&~DOR_MOTEN_MASK;  /* clear motor bits */
        !           925:     for (i=0; i<FLP_MAX_DRIVES; i++) {
        !           926:         if (flpdrv[i].spinning) {           /* set motor bit if motor is on */
        !           927:             val |= 0x10<<i;
        !           928:         }
        !           929:     }
        !           930:     return val;
        !           931: }
        !           932: 
        !           933: Uint8 floppy_sra_read(void) {
        !           934:     Uint8 val = flp.sra;
        !           935:     if (!flpdrv[flp.sel].protected) {
        !           936:         val|=SRA_WP_N;
        !           937:     }
        !           938:     return val;
        !           939: }
        !           940: 
        !           941: 
        !           942: /* -- Floppy I/O functions -- */
        !           943: 
        !           944: static void floppy_rw_nodata(void) {
        !           945:     Log_Printf(LOG_WARN, "[Floppy] Write: No more data from DMA. Stopping.");
        !           946:     /* Stop transfer */
        !           947:     flp_sector_counter=0;
        !           948:     flp.st[0] |= IC_ABNORMAL;
        !           949:     flp.st[1] |= ST1_OR;
        !           950:     send_rw_status(flp_io_drv);
        !           951: }
        !           952: 
        !           953: static void floppy_format_done(void) {
        !           954:     int drive = flp_io_drv;
        !           955:     
        !           956:     Log_Printf(LOG_WARN, "[Floppy] Format: No more data from DMA. Done.");
        !           957:     
        !           958:     flp.st[0] = IC_NORMAL;
        !           959:     send_rw_status(drive);
        !           960: }
        !           961: 
        !           962: static void floppy_read_sector(void) {
        !           963:     int drive = flp_io_drv;
        !           964:     
        !           965:     /* Read from image */
        !           966:     Uint32 sec_size = 0x80<<flpdrv[drive].blocksize;
        !           967:     Uint32 logical_sec = physical_to_logical_sector(flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,drive);
        !           968:     
        !           969:     if (flp.st[0]&IC_ABNORMAL) {
        !           970:         Log_Printf(LOG_WARN, "[Floppy] Read error. Bad sector offset (%i).",logical_sec);
        !           971:         flp_sector_counter=0; /* stop the transfer */
        !           972:         flp_io_state = FLP_STATE_INTERRUPT;
        !           973:         send_rw_status(drive);
        !           974:         return;
        !           975:     } else {
        !           976:         Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Read sector at offset %i",logical_sec);
        !           977: 
        !           978:         flp_buffer.size = flp_buffer.limit = sec_size;
        !           979:         File_Read(flp_buffer.data, flp_buffer.size, logical_sec*sec_size, flpdrv[drive].dsk);
        !           980:         flpdrv[drive].sector++;
        !           981:         flp_sector_counter--;
        !           982:     }
        !           983:     
        !           984:     if (flp_sector_counter==0) {
        !           985:         flp.st[0] = IC_ABNORMAL; /* Strange behavior of NeXT hardware */
        !           986:         flp.st[1] |= ST1_EN;
        !           987:         send_rw_status(drive);
        !           988:     }
        !           989: }
        !           990: 
        !           991: static void floppy_write_sector(void) {
        !           992:     int drive = flp_io_drv;
        !           993:     
        !           994:     /* Write to image */
        !           995:     Uint32 sec_size = 0x80<<flpdrv[drive].blocksize;
        !           996:     Uint32 logical_sec = physical_to_logical_sector(flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,drive);
        !           997:     
        !           998:     if (flp.st[0]&IC_ABNORMAL) {
        !           999:         Log_Printf(LOG_WARN, "[Floppy] Write error. Bad sector offset (%i).",logical_sec);
        !          1000:         flp_sector_counter=0; /* stop the transfer */
        !          1001:         flp_io_state = FLP_STATE_INTERRUPT;
        !          1002:         send_rw_status(drive);
        !          1003:         return;
        !          1004:     } else {
        !          1005:         Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Write sector at offset %i",logical_sec);
        !          1006:         
        !          1007:         File_Write(flp_buffer.data, flp_buffer.size, logical_sec*sec_size, flpdrv[drive].dsk);
        !          1008:         flp_buffer.size = 0;
        !          1009:         flp_buffer.limit = sec_size;
        !          1010:         flpdrv[drive].sector++;
        !          1011:         flp_sector_counter--;
        !          1012:     }
        !          1013:     
        !          1014:     if (flp_sector_counter==0) {
        !          1015:         flp.st[0] = IC_ABNORMAL; /* Strange behavior of NeXT hardware */
        !          1016:         flp.st[1] |= ST1_EN;
        !          1017:         send_rw_status(drive);
        !          1018:     }
        !          1019: }
        !          1020: 
        !          1021: static void floppy_format_sector(void) {
        !          1022:     int drive = flp_io_drv;
        !          1023:     Uint8 c = flp_buffer.data[0];
        !          1024:     Uint8 h = flp_buffer.data[1];
        !          1025:     Uint8 s = flp_buffer.data[2];
        !          1026:     Uint8 bs = flp_buffer.data[3];
        !          1027:     
        !          1028:     if (c!=flpdrv[drive].cyl || h!=flpdrv[drive].head || bs!=flpdrv[drive].blocksize) {
        !          1029:         Log_Printf(LOG_WARN, "[Floppy] Format error. Bad sector data. Stopping.");
        !          1030:         flp_io_state = FLP_STATE_INTERRUPT; /* This is a hack */
        !          1031:         floppy_format_done();
        !          1032:         flp_buffer.size = 0;
        !          1033:         return;
        !          1034:     }
        !          1035:     flpdrv[drive].sector = s;
        !          1036:     
        !          1037:     /* Erase data */
        !          1038:     Uint32 sec_size = 0x80<<bs;
        !          1039:     Uint32 logical_sec = physical_to_logical_sector(flpdrv[drive].cyl,flpdrv[drive].head,flpdrv[drive].sector,drive);
        !          1040:     flp_buffer.size = sec_size;
        !          1041:     memset(flp_buffer.data, 0, flp_buffer.size);
        !          1042: 
        !          1043:     if (flp.st[0]&IC_ABNORMAL) {
        !          1044:         Log_Printf(LOG_WARN, "[Floppy] Format error. Bad sector offset (%i).",logical_sec);
        !          1045:         flp_buffer.size = flp_buffer.limit = 0;
        !          1046:         send_rw_status(drive);
        !          1047:     } else {
        !          1048:         Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Format sector at offset %i (%i/%i/%i), blocksize: %i",
        !          1049:                    logical_sec,c,h,s,sec_size);
        !          1050:         File_Write(flp_buffer.data, flp_buffer.size, logical_sec*sec_size, flpdrv[drive].dsk);
        !          1051:         flp_buffer.size = 0;
        !          1052:         flp_buffer.limit = 4;
        !          1053:     }
        !          1054: }
        !          1055: 
        !          1056: 
        !          1057: static Uint32 old_size;
        !          1058: 
        !          1059: void FLP_IO_Handler(void) {
        !          1060:     CycInt_AcknowledgeInterrupt();
        !          1061:     
        !          1062:     switch (flp_io_state) {
        !          1063:         case FLP_STATE_WRITE:
        !          1064:             if (flp_buffer.size==flp_buffer.limit) {
        !          1065:                 floppy_write_sector();
        !          1066:                 if (flp_sector_counter==0) { /* done */
        !          1067:                     floppy_interrupt();
        !          1068:                     flp_io_state = FLP_STATE_DONE;
        !          1069:                     return;
        !          1070:                 }
        !          1071:             } else if (flp_buffer.size<flp_buffer.limit) { /* loop in filling mode */
        !          1072:                 old_size = flp_buffer.size;
        !          1073:                 dma_esp_read_memory();
        !          1074:                 if (flp_buffer.size==old_size) {
        !          1075:                     floppy_rw_nodata();
        !          1076:                     floppy_interrupt();
        !          1077:                     flp_io_state = FLP_STATE_DONE;
        !          1078:                     return;
        !          1079:                 }
        !          1080:             }
        !          1081:             break;
        !          1082:             
        !          1083:         case FLP_STATE_READ:
        !          1084:             if (flp_buffer.size==0 && flp_sector_counter>0) {
        !          1085:                 floppy_read_sector();
        !          1086:             }
        !          1087:             if (flp_buffer.size>0) { /* loop in draining mode */
        !          1088:                 old_size = flp_buffer.size;
        !          1089:                 dma_esp_write_memory();
        !          1090:                 if (flp_buffer.size==old_size) {
        !          1091:                     floppy_rw_nodata();
        !          1092:                     floppy_interrupt();
        !          1093:                     flp_io_state = FLP_STATE_DONE;
        !          1094:                     return;
        !          1095:                 }
        !          1096:             }
        !          1097:             if (flp_buffer.size==0 && flp_sector_counter==0) { /* done */
        !          1098:                 floppy_interrupt();
        !          1099:                 flp_io_state = FLP_STATE_DONE;
        !          1100:                 return;
        !          1101:             }
        !          1102:             break;
        !          1103:             
        !          1104:         case FLP_STATE_FORMAT:
        !          1105:             if (flp_buffer.size<flp_buffer.limit) {
        !          1106:                 old_size = flp_buffer.size;
        !          1107:                 dma_esp_read_memory();
        !          1108:                 if (flp_buffer.size==old_size) {
        !          1109:                     floppy_format_done();
        !          1110:                     floppy_interrupt();
        !          1111:                     flp_io_state = FLP_STATE_DONE;
        !          1112:                     return;
        !          1113:                 }
        !          1114:             } else if (flp_buffer.size==flp_buffer.limit) {
        !          1115:                 floppy_format_sector();
        !          1116:             }
        !          1117:             break;
        !          1118:             
        !          1119:         case FLP_STATE_INTERRUPT:
        !          1120:             floppy_interrupt();
        !          1121:             flp_io_state = FLP_STATE_DONE;
        !          1122:             /* fall through */
        !          1123:             
        !          1124:         case FLP_STATE_DONE:
        !          1125:             return;
        !          1126:             
        !          1127:         default:
        !          1128:             return;
        !          1129:     }
        !          1130:     
        !          1131:     CycInt_AddRelativeInterruptUs(get_sector_time(flp_io_drv), 250, INTERRUPT_FLP_IO);
        !          1132: }
        !          1133: 
        !          1134: 
        !          1135: /* Initialize/Uninitialize floppy disks */
        !          1136: 
        !          1137: static void Floppy_Init(void) {
        !          1138:     Log_Printf(LOG_WARN, "Loading floppy disks:");
        !          1139:     int i;
        !          1140:     
        !          1141:     for (i=0; i<FLP_MAX_DRIVES; i++) {
        !          1142:         flpdrv[i].spinning=false;
        !          1143:         /* Check if files exist. */
        !          1144:         if (ConfigureParams.Floppy.drive[i].bDriveConnected) {
        !          1145:             flpdrv[i].connected=true;
        !          1146:             if (ConfigureParams.Floppy.drive[i].bDiskInserted &&
        !          1147:                 File_Exists(ConfigureParams.Floppy.drive[i].szImageName)) {
        !          1148:                 Floppy_Insert(i);
        !          1149:             } else {
        !          1150:                 flpdrv[i].dsk = NULL;
        !          1151:                 flpdrv[i].inserted=false;
        !          1152:             }
        !          1153:         } else {
        !          1154:             flpdrv[i].connected=false;
        !          1155:         }
        !          1156:     }
        !          1157:     
        !          1158:     floppy_reset(true);
        !          1159: }
        !          1160: 
        !          1161: static void Floppy_Uninit(void) {
        !          1162:     if (flpdrv[0].dsk)
        !          1163:         File_Close(flpdrv[0].dsk);
        !          1164:     if (flpdrv[1].dsk) {
        !          1165:         File_Close(flpdrv[1].dsk);
        !          1166:     }
        !          1167:     flpdrv[0].dsk = flpdrv[1].dsk = NULL;
        !          1168:     flpdrv[0].inserted = flpdrv[1].inserted = false;
        !          1169: }
        !          1170: 
        !          1171: static Uint32 Floppy_CheckSize(int drive) {
        !          1172:     Uint32 size = File_Length(ConfigureParams.Floppy.drive[drive].szImageName);
        !          1173:     
        !          1174:     switch (size) {
        !          1175:         case SIZE_720K:
        !          1176:         case SIZE_1440K:
        !          1177:         case SIZE_2880K:
        !          1178:             return size;
        !          1179:             
        !          1180:         default:
        !          1181:             Log_Printf(LOG_WARN, "Floppy Disk%i: Invalid size (%i byte)\n",drive,size);
        !          1182:             return 0;
        !          1183:     }
        !          1184: }
        !          1185: 
        !          1186: int Floppy_Insert(int drive) {
        !          1187:     Uint32 size;
        !          1188:     
        !          1189:     /* Check floppy size. */
        !          1190:     size = Floppy_CheckSize(drive);
        !          1191:     if (size) {
        !          1192:         flpdrv[drive].floppysize = size;
        !          1193:         flpdrv[drive].blocksize = 2; /* 512 byte */
        !          1194:         flpdrv[drive].cyl = flpdrv[drive].head = flpdrv[drive].sector = 0;
        !          1195:         flpdrv[drive].seekoffset = 0;
        !          1196:     } else {
        !          1197:         flpdrv[drive].dsk = NULL;
        !          1198:         flpdrv[drive].inserted=false;
        !          1199:         flpdrv[drive].floppysize = 0;
        !          1200:         return 1; /* bad size, do not insert */
        !          1201:     }
        !          1202:     
        !          1203:     if (ConfigureParams.Floppy.drive[drive].bWriteProtected) {
        !          1204:         flpdrv[drive].dsk = File_Open(ConfigureParams.Floppy.drive[drive].szImageName, "rb");
        !          1205:         if (flpdrv[drive].dsk == NULL) {
        !          1206:             Log_Printf(LOG_WARN, "Floppy Disk%i: Cannot open image file %s\n",
        !          1207:                        drive, ConfigureParams.Floppy.drive[drive].szImageName);
        !          1208:             flpdrv[drive].inserted=false;
        !          1209:             flpdrv[drive].spinning=false;
        !          1210:             Statusbar_AddMessage("Cannot insert floppy disk", 0);
        !          1211:             return 1;
        !          1212:         }
        !          1213:         flpdrv[drive].protected=true;
        !          1214:     } else {
        !          1215:         flpdrv[drive].dsk = File_Open(ConfigureParams.Floppy.drive[drive].szImageName, "rb+");
        !          1216:         flpdrv[drive].protected=false;
        !          1217:         if (flpdrv[drive].dsk == NULL) {
        !          1218:             flpdrv[drive].dsk = File_Open(ConfigureParams.Floppy.drive[drive].szImageName, "rb");
        !          1219:             if (flpdrv[drive].dsk == NULL) {
        !          1220:                 Log_Printf(LOG_WARN, "Floppy Disk%i: Cannot open image file %s\n",
        !          1221:                            drive, ConfigureParams.Floppy.drive[drive].szImageName);
        !          1222:                 flpdrv[drive].inserted=false;
        !          1223:                 flpdrv[drive].spinning=false;
        !          1224:                 Statusbar_AddMessage("Cannot insert floppy disk", 0);
        !          1225:                 return 1;
        !          1226:             }
        !          1227:             flpdrv[drive].protected=true;
        !          1228:             Log_Printf(LOG_WARN, "Floppy Disk%i: Image file is not writable. Enabling write protection.\n",
        !          1229:                        drive);
        !          1230:         }
        !          1231:     }
        !          1232:     
        !          1233:     flpdrv[drive].inserted=true;
        !          1234:     flpdrv[drive].spinning=false;
        !          1235: 
        !          1236:     Log_Printf(LOG_WARN, "Floppy Disk%i: %s, %iK\n",drive,
        !          1237:                ConfigureParams.Floppy.drive[drive].szImageName,flpdrv[drive].floppysize/1024);
        !          1238:     
        !          1239:     Statusbar_AddMessage("Inserting floppy disk.", 0);
        !          1240:     
        !          1241:     return 0;
        !          1242: }
        !          1243: 
        !          1244: void Floppy_Eject(int drive) {
        !          1245:     if (drive<0) { /* Called from emulator, else called from GUI */
        !          1246:         drive=flp.sel;
        !          1247:         
        !          1248:         Statusbar_AddMessage("Ejecting floppy disk.", 0);
        !          1249:     }
        !          1250:     
        !          1251:     Log_Printf(LOG_WARN, "Unloading floppy disk %i",drive);
        !          1252:     Log_Printf(LOG_WARN, "Floppy disk %i: Eject",drive);
        !          1253:     
        !          1254:     File_Close(flpdrv[drive].dsk);
        !          1255:     flpdrv[drive].floppysize = 0;
        !          1256:     flpdrv[drive].blocksize = 0;
        !          1257:     flpdrv[drive].dsk=NULL;
        !          1258:     flpdrv[drive].inserted=false;
        !          1259:     flpdrv[drive].spinning=false;
        !          1260:     
        !          1261:     ConfigureParams.Floppy.drive[drive].bDiskInserted=false;
        !          1262:     ConfigureParams.Floppy.drive[drive].szImageName[0]='\0';
        !          1263: }
        !          1264: 
        !          1265: void Floppy_Reset(void) {
        !          1266:     Floppy_Uninit();
        !          1267:     Floppy_Init();
        !          1268: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.