Annotation of previous/src/floppy.c, revision 1.1.1.2

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:     
1.1.1.2 ! root       53:     Uint32 seekoffset;
        !            54:     
1.1       root       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) {
1.1.1.2 ! root      212:         Log_Printf(LOG_DEBUG,"[%s] Selecting floppy controller",osp?"OSP":"Floppy");
1.1       root      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 {
1.1.1.2 ! root      281:         /* Single poll interrupt after reset (delay = 250 ms) */
1.1       root      282:         flp_io_state = FLP_STATE_INTERRUPT;
1.1.1.2 ! root      283:         CycInt_AddRelativeInterruptUs(250*1000, 0, INTERRUPT_FLP_IO);
1.1       root      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: 
1.1.1.2 ! root      331: static void floppy_interrupt(void) {
1.1       root      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: 
1.1.1.2 ! root      356: static Uint32 physical_to_logical_sector(Uint8 c, Uint8 h, Uint8 s, int drive) {
1.1       root      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: 
1.1.1.2 ! root      373: static void check_blocksize(int drive, Uint8 blocksize) {
1.1       root      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: 
1.1.1.2 ! root      381: static void check_protection(int drive) {
1.1       root      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: 
1.1.1.2 ! root      389: static void floppy_seek_track(Uint8 c, Uint8 h, int drive) {
1.1       root      390:     if (c>(NUM_CYLINDERS-1)) /* CHECK: does this cause an error? */
                    391:         c=(NUM_CYLINDERS-1);
                    392:     
                    393:     flp.st[0] |= ST0_SE;
1.1.1.2 ! root      394:     
        !           395:     flpdrv[drive].seekoffset = (flpdrv[drive].cyl < c) ? (c - flpdrv[drive].cyl) : (flpdrv[drive].cyl - c);
1.1       root      396:     flpdrv[drive].cyl = c;
                    397:     flpdrv[drive].head = h;
                    398: }
                    399: 
1.1.1.2 ! root      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: 
1.1       root      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: 
1.1.1.2 ! root      427: static Uint8 get_media_id(int drive) {
1.1       root      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: 
1.1.1.2 ! root      445: static void check_data_rate(int drive) {
1.1       root      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: 
1.1.1.2 ! root      471: static void send_rw_status(int drive) {
1.1       root      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: 
1.1.1.2 ! root      485: static void floppy_read(void) {
1.1       root      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:     }
1.1.1.2 ! root      536:     CycInt_AddRelativeInterruptUs(get_seek_time(drive) + get_sector_time(drive), 100, INTERRUPT_FLP_IO);
1.1       root      537: }
                    538: 
1.1.1.2 ! root      539: static void floppy_write(void) {
1.1       root      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:     }
1.1.1.2 ! root      593:     CycInt_AddRelativeInterruptUs(get_seek_time(drive) + get_sector_time(drive), 100, INTERRUPT_FLP_IO);
1.1       root      594: }
                    595: 
1.1.1.2 ! root      596: static void floppy_format(void) {
1.1       root      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;
1.1.1.2 ! root      618:         CycInt_AddRelativeInterruptUs(get_seek_time(drive) + get_sector_time(drive), 100, INTERRUPT_FLP_IO);
1.1       root      619:     }
                    620: }
                    621: 
1.1.1.2 ! root      622: static void floppy_read_id(void) {
1.1       root      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;
1.1.1.2 ! root      640:     CycInt_AddRelativeInterruptUs(get_seek_time(drive), 100, INTERRUPT_FLP_IO);
1.1       root      641: }
                    642: 
1.1.1.2 ! root      643: static void floppy_recalibrate(void) {
1.1       root      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;
1.1.1.2 ! root      654:         floppy_seek_track(0, 0, drive);
1.1       root      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;
1.1.1.2 ! root      661:         CycInt_AddRelativeInterruptUs(get_seek_time(drive), 100, INTERRUPT_FLP_IO);
1.1       root      662:     }
                    663: }
                    664: 
1.1.1.2 ! root      665: static void floppy_seek(Uint8 relative) {
1.1       root      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;
1.1.1.2 ! root      684:     CycInt_AddRelativeInterruptUs(get_seek_time(drive), 100, INTERRUPT_FLP_IO);
1.1       root      685: }
                    686: 
1.1.1.2 ! root      687: static void floppy_interrupt_status(void) {
1.1       root      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: 
1.1.1.2 ! root      699: static void floppy_specify(void) {
1.1       root      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: 
1.1.1.2 ! root      710: static void floppy_configure(void) {
1.1       root      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: 
1.1.1.2 ! root      728: static void floppy_perpendicular(void) {
1.1       root      729:     Log_Printf(LOG_FLP_CMD_LEVEL, "[Floppy] Perpendicular: %02X",cmd_data[0]);
                    730:     flp.msr |= STAT_RQM;
                    731: }
                    732: 
1.1.1.2 ! root      733: static void floppy_unimplemented(void) {
1.1       root      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;
1.1.1.2 ! root      740:     CycInt_AddRelativeInterruptUs(1000, 100, INTERRUPT_FLP_IO);
1.1       root      741: }
                    742: 
1.1.1.2 ! root      743: static void floppy_execute_cmd(void) {
1.1       root      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: 
1.1.1.2 ! root      944: static void floppy_rw_nodata(void) {
1.1       root      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: 
1.1.1.2 ! root      953: static void floppy_format_done(void) {
1.1       root      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: 
1.1.1.2 ! root      962: static void floppy_read_sector(void) {
1.1       root      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;
1.1.1.2 ! root      979:         File_Read(flp_buffer.data, flp_buffer.size, logical_sec*sec_size, flpdrv[drive].dsk);
1.1       root      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: 
1.1.1.2 ! root      991: static void floppy_write_sector(void) {
1.1       root      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:         
1.1.1.2 ! root     1007:         File_Write(flp_buffer.data, flp_buffer.size, logical_sec*sec_size, flpdrv[drive].dsk);
1.1       root     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: 
1.1.1.2 ! root     1021: static void floppy_format_sector(void) {
1.1       root     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);
1.1.1.2 ! root     1050:         File_Write(flp_buffer.data, flp_buffer.size, logical_sec*sec_size, flpdrv[drive].dsk);
1.1       root     1051:         flp_buffer.size = 0;
                   1052:         flp_buffer.limit = 4;
                   1053:     }
                   1054: }
                   1055: 
                   1056: 
1.1.1.2 ! root     1057: static Uint32 old_size;
1.1       root     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 */
1.1.1.2 ! root     1067:                     floppy_interrupt();
        !          1068:                     flp_io_state = FLP_STATE_DONE;
        !          1069:                     return;
1.1       root     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();
1.1.1.2 ! root     1076:                     floppy_interrupt();
        !          1077:                     flp_io_state = FLP_STATE_DONE;
        !          1078:                     return;
1.1       root     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();
1.1.1.2 ! root     1092:                     floppy_interrupt();
        !          1093:                     flp_io_state = FLP_STATE_DONE;
        !          1094:                     return;
1.1       root     1095:                 }
                   1096:             }
                   1097:             if (flp_buffer.size==0 && flp_sector_counter==0) { /* done */
1.1.1.2 ! root     1098:                 floppy_interrupt();
        !          1099:                 flp_io_state = FLP_STATE_DONE;
        !          1100:                 return;
1.1       root     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();
1.1.1.2 ! root     1110:                     floppy_interrupt();
        !          1111:                     flp_io_state = FLP_STATE_DONE;
        !          1112:                     return;
1.1       root     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();
1.1.1.2 ! root     1121:             flp_io_state = FLP_STATE_DONE;
1.1       root     1122:             /* fall through */
                   1123:             
                   1124:         case FLP_STATE_DONE:
                   1125:             return;
                   1126:             
                   1127:         default:
                   1128:             return;
                   1129:     }
                   1130:     
1.1.1.2 ! root     1131:     CycInt_AddRelativeInterruptUs(get_sector_time(flp_io_drv), 250, INTERRUPT_FLP_IO);
1.1       root     1132: }
                   1133: 
                   1134: 
                   1135: /* Initialize/Uninitialize floppy disks */
                   1136: 
1.1.1.2 ! root     1137: static void Floppy_Init(void) {
1.1       root     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: 
1.1.1.2 ! root     1161: static void Floppy_Uninit(void) {
1.1       root     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: 
1.1.1.2 ! root     1171: static Uint32 Floppy_CheckSize(int drive) {
1.1       root     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 */
1.1.1.2 ! root     1194:         flpdrv[drive].cyl = flpdrv[drive].head = flpdrv[drive].sector = 0;
        !          1195:         flpdrv[drive].seekoffset = 0;
1.1       root     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");
1.1.1.2 ! root     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:         }
1.1       root     1213:         flpdrv[drive].protected=true;
                   1214:     } else {
                   1215:         flpdrv[drive].dsk = File_Open(ConfigureParams.Floppy.drive[drive].szImageName, "rb+");
                   1216:         flpdrv[drive].protected=false;
1.1.1.2 ! root     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:         }
1.1       root     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.