#ifndef COMPILE_H
#include "COMPILE.H"
#endif
#ifdef MEDIA153_S10EA_S10EB_S11E_S12E_S12G_S13FA_S13FB_S20E_S21E_A20ED_A20E_A20F_A20G_A21E_A22E_A22G_A31E_A31M_A33M_A35E_A35M
#ifndef NOCOPYPROTECTION
#ifdef MEDIA007_S10EA_S10EB_S11E_S12E_S12G_S13FA_S13FB_S20E_S21E
BOOLEAN G0624_B_FloppyDriveTurnedOn_CPSDF = C0_FALSE;
int16_t G0625_i_FloppyDriveDMATimeout_CPSDF = 0;
void (*G0626_pfv_S0080_CPSDF_CheckDMATransferCompletion)();
void (*G0627_pfv_S0081_CPSDF_TurnOffFloppyDrive)();


overlay "main"

asm {
        S0080_CPSDF_CheckDMATransferCompletion:
                lea     G0625_i_FloppyDriveDMATimeout_CPSDF(A4),A1
                cmpi.w  #259,(A1)
                beq.s   T0080001
                btst    #5,0xFA01                                               /* Test bit 5 of the MFP GPIP (the chip managing DMA transfers) */
                beq.s   T0080002                                                /* If this bit is 1, a DMA transfer from the floppy disk controller is still ongoing. If this bit is 0, then the DMA transfer is complete */
                moveq   #-2,D0                                                  /* Return value -2 means 'DMA transfer is not complete yet' */
        T0080001:
                subq.w  #1,(A1)                                                 /* Decrement timeout value */
                beq.s   T0080005                                                /* If 0 then this means the DMA transfer has timed out */
                rts
        T0080002:
                movea.w #0x8606,A0                                              /* Address of the DMA mode/status register */
                move.w  #0x0090,(A0)                                            /* Write mode $90 to the DMA mode/status register. Set read mode (from DMA to memory) from the FDC. Subsequent write to -2(A0) = 0xFFFF8604 will be directed to the DMA internal sector count register */
                moveq   #1,D0
                and.w   (A0),D0                                                 /* If bit 0 of register 0xFFFF8606 is 0 then there is a DMA error otherwise there is no DMA error */
                beq.s   T0080004                                                /* Branch if bit 0 = 0 (DMA error) */
                move.w  #0x0080,(A0)                                            /* Write mode $80 to the DMA mode/status register. Subsequent read/write from/to -2(A0) = 0xFFFF8604 will be directed to the FDC STATUS/CONTROL register */
                moveq   #44,D0                                                  /* Delay */
        T0080003_Loop:
                subq.w  #1,D0
                bne.s   T0080003_Loop                                           /* This loop introduces the necessary delay for programming the FDC */
                moveq   #0x10,D0                                                /* This is a mask with only bit 4 set */
                and.w   -2(A0),D0                                               /* Read the STATUS register of the FDC and apply the mask in D0 to keep only bit 4 */
                beq.s   T0080005                                                /* Branch if bit 4 = 0. The FDC sets this bit to indicate 'RECORD NOT FOUND (RNF)' (track, sector or side not found) */
                moveq   #-7,D0
        T0080004:
                subq.w  #1,D0
        T0080005:
                move.w  D0,(A1)                                                 /* Floppy Drive DMA Timeout = D0:
                                                                                        -8 if the FDC returned error 'Record not found'
                                                                                        -2 if the read operation timed out
                                                                                        -1 if the DMA reported a transfer error
                                                                                         0 if the read operation succeeded */
                bne.s   T0080006                                                /* If an error occured during the transfer */
                clr.w   G0314_i_SectorsReadRequested_CPSDF(A4)
        T0080006:
                clr.w   C0x043E_ADDRESS_SYSTEM_VARIABLE_flock                   /* Clear flock to indicate that DMA is not busy anymore */
                rts
        S0081_CPSDF_TurnOffFloppyDrive:
                tst.w   C0x043E_ADDRESS_SYSTEM_VARIABLE_flock                   /* Test flock. This value is not 0 if the floppy disk is being accessed. This is a system semaphore to avoid DMA conflicts */
                bne.s   T0081001                                                /* Branch if flock != 0 */
                move.w  0x8604,D0                                               /* Address of DMA data register */
                btst    #7,D0                                                   /* Status byte from the DMA data register (MOTOR ON). This bit is 0 if the floppy drive motor is on, 1 if it is off */
                bne.s   T0081001                                                /* Branch if bit7 != 0 (if motor is already stopped) */
                movea.w #0x8800,A0                                              /* This is the address of the Programmable Sound Generator (PSG, YM2149 sound chip) Read data/Register select */
                moveq   #7,D0                                                   /* This is used as a bit mask 00000111 */
                move    SR,D1                                                   /* Backup Status Register in D1 */
                ori     #0x0700,SR                                              /* Set interrupt priority mask = 7. All interrupts <= 7 are now ignored. This includes Horizontal Blank interrupts (level 2), Vertical Blank interrupts (level 4) and MFP interrupts (level 6) */
                move.b  #14,(A0)                                                /* Write $0E to the PSG register select. This selects I/O port A */
                or.b    (A0),D0                                                 /* Read data from chip and apply binary mask in D0 to set bits 0 to 2 and not change bits 3 to 7, in order to turn off floppy drive 0 and its light (this will also stop the motor) */
                move.b  D0,2(A0)                                                /* Write D0 to the write address of the PSG */
                move    D1,SR                                                   /* Restore Status Register from D1 */
                clr.w   G0624_B_FloppyDriveTurnedOn_CPSDF(A4)
        T0081001:
                rts
}
#endif
#ifdef MEDIA423_A20ED_A20E_A20F_A20G_A21E_A22E_A22G_A31E_A31M_A33M_A35E_A35M
int16_t G1079_i_DriveTimeout_CPSDF = 0; /* May have to swap this with G0625_i_FloppyDriveDMATimeout_CPSDF ! */

int16_t S0080_CPSDF_CheckDMATransferCompletion(
)
{
        REGISTER int16_t L1579_i_Unreferenced;
        REGISTER int16_t L1580_i_Unreferenced;
        REGISTER int16_t L1581_i_Unreferenced;
        REGISTER int16_t L1582_i_Unreferenced;
        REGISTER char* L1583_pc_Unreferenced;
        REGISTER char* L1584_pc_Unreferenced;
        int16_t L1585_i_Unreferenced;


        switch (G0625_i_FloppyDriveDMATimeout_CPSDF) {
                case 1:
                        if (!(ciaa.ciapra & CIAF_DSKRDY)) { /* If disk drive is ready */
                                if (ciaa.ciapra & CIAF_DSKTRACK0) { /* If drive head is not over track 0 */
                                        ciab.ciaprb = CIAF_DSKSEL3 | CIAF_DSKSEL2 | CIAF_DSKSEL1 | CIAF_DSKDIREC; /* Drive 0 is selected */
#ifdef MEDIA413_A20ED_A20E_A20F_A20G_A21E_A22E_A22G
                                        #asm
                                                nop
                                                nop
                                        #endasm
#endif
#ifdef MEDIA626_A31E_A31M_A33M_A35E_A35M
                                        asm {
                                                nop
                                                nop
                                        }
#endif
                                        ciab.ciaprb = CIAF_DSKSEL3 | CIAF_DSKSEL2 | CIAF_DSKSEL1 | CIAF_DSKDIREC | CIAF_DSKSTEP; /* Drive 0 is selected. Pulse to step toward track 0 */
                                } else {
                                        G0625_i_FloppyDriveDMATimeout_CPSDF = 2;
                                        G1079_i_DriveTimeout_CPSDF = 0;
                                }
                        } else {
                                if (G1079_i_DriveTimeout_CPSDF++ > 259) {
                                        G0625_i_FloppyDriveDMATimeout_CPSDF = -1;
                                        G0624_B_FloppyDriveTurnedOn_CPSDF = C1_TRUE;
                                        G1079_i_DriveTimeout_CPSDF = 0;
                                }
                        }
                        break;
                case 2:
                        if (!(ciaa.ciapra & CIAF_DSKRDY)) { /* 0x20 */
                                custom.intreq = INTF_DSKBLK; /* 0x0002. 0x8000: Clear specified bits without changing other bits. 0x0002: Clear 'Disk block finished' interrupt bit */
                                custom.dmacon = 0x8010; /* 0x8000: set other specified bits without affecting other bits. 0x0010: Disk DMA enable */
                                custom.dsklen = 0x4000; /* Force the DMA for the disk to be turned off */
                                custom.adkcon = ADKF_SETCLR | ADKF_WORDSYNC; /* 0x8400. Enable sync with sync mark (set this bit without affecting other bits) */
                                custom.dsksync = 0x5545; /* MFM sync mark */
                                G0625_i_FloppyDriveDMATimeout_CPSDF = 3;
                                G1079_i_DriveTimeout_CPSDF = 0;
                                custom.intreq = 0x2000; /* 0x8000: Clear specified bits without changing other bits. 0x2000: Disable external interrupt request 6 (generated by CIAB) */
                                custom.intena = 0xA000; /* 0x8000: Set specified bits without changing other bits. 0x2000: Enable external interrupt 6 (generated by CIAB) */
                                ciab.ciaicr = CIAICRF_SETCLR | CIAICRF_FLG; /* 0x90. CIAB interrupt control register. Sets bit 4 CIAICRF_FLG and preserve other bits in the MASK register */
#ifdef MEDIA413_A20ED_A20E_A20F_A20G_A21E_A22E_A22G
                                AddIntServer(INTB_EXTER, G1080_ps_Interrupt_CPSX); /* Add custom handler for external interrupt */
#endif
#ifdef MEDIA626_A31E_A31M_A33M_A35E_A35M
                                AddIntServer(INTB_EXTER, &G3224_s_Interrupt_CPSX); /* Add custom handler for external interrupt */
#endif
                        } else {
                                if (G1079_i_DriveTimeout_CPSDF++ > 259) {
                                        G0624_B_FloppyDriveTurnedOn_CPSDF = C1_TRUE;
                                        G0625_i_FloppyDriveDMATimeout_CPSDF = -1;
                                        G1079_i_DriveTimeout_CPSDF = 0;
                                }
                        }
                        break;
                case 4:
                        if (custom.intreqr & INTF_DSKBLK) { /* Wait until 'Disk block finished' interrupt request bit is set, indicating the end of the read operation */
                                custom.intreq = INTF_DSKBLK; /* 0x0002.  0x8000: Clear specified bits without changing other bits. 0x0002: Clear 'Disk block finished' interrupt bit */
                                custom.dsklen = 0x4000; /* Force the DMA for the disk to be turned off */
                                ciab.ciaprb = (unsigned char)(CIAF_DSKMOTOR | CIAF_DSKSEL3 | CIAF_DSKSEL2 | CIAF_DSKSEL1 | CIAF_DSKSEL0 | CIAF_DSKSIDE | CIAF_DSKDIREC | CIAF_DSKSTEP); /* 0xFF */
                                ciab.ciaprb = (unsigned char)(CIAF_DSKMOTOR | CIAF_DSKSEL3 | CIAF_DSKSEL2 | CIAF_DSKSEL1 | CIAF_DSKSIDE | CIAF_DSKDIREC | CIAF_DSKSTEP); /* 0xF7 */
#ifdef MEDIA413_A20ED_A20E_A20F_A20G_A21E_A22E_A22G
                                RemIntServer(INTB_EXTER, G1080_ps_Interrupt_CPSX); /* Remove custom handler for external interrupt */
#endif
#ifdef MEDIA626_A31E_A31M_A33M_A35E_A35M
                                RemIntServer(INTB_EXTER, &G3224_s_Interrupt_CPSX); /* Remove custom handler for external interrupt */
#endif
                                G1079_i_DriveTimeout_CPSDF = 0;
                                G0624_B_FloppyDriveTurnedOn_CPSDF = C1_TRUE;
                                G0625_i_FloppyDriveDMATimeout_CPSDF = 0;
                        } else {
                                if (G1079_i_DriveTimeout_CPSDF++ > 259) {
                                        custom.intreq = INTF_DSKBLK; /* 0x0002.  0x8000: Clear specified bits without changing other bits. 0x0002: Clear 'Disk block finished' interrupt bit */
                                        custom.dsklen = 0x4000; /* Force the DMA for the disk to be turned off */
                                        ciab.ciaprb = (unsigned char)(CIAF_DSKMOTOR | CIAF_DSKSEL3 | CIAF_DSKSEL2 | CIAF_DSKSEL1 | CIAF_DSKSEL0 | CIAF_DSKSIDE | CIAF_DSKDIREC | CIAF_DSKSTEP); /* 0xFF */
                                        ciab.ciaprb = (unsigned char)(CIAF_DSKMOTOR | CIAF_DSKSEL3 | CIAF_DSKSEL2 | CIAF_DSKSEL1 | CIAF_DSKSIDE | CIAF_DSKDIREC | CIAF_DSKSTEP); /* 0xF7 */
#ifdef MEDIA413_A20ED_A20E_A20F_A20G_A21E_A22E_A22G
                                        RemIntServer(INTB_EXTER, G1080_ps_Interrupt_CPSX);
#endif
#ifdef MEDIA626_A31E_A31M_A33M_A35E_A35M
                                        RemIntServer(INTB_EXTER, &G3224_s_Interrupt_CPSX);
#endif
                                        ciab.ciaicr = CIAICRF_FLG; /* CIAB interrupt control register */
                                        custom.intreq = 0x2000; /* 0x8000: Clear specified bits without changing other bits. 0x2000: Disable external interrupt request 6 (generated by CIAB) */
                                        custom.intena = 0x2000; /* 0x8000: Set specified bits without changing other bits. 0x2000: Enable external interrupt 6 (generated by CIAB) */
                                        G0624_B_FloppyDriveTurnedOn_CPSDF = C1_TRUE;
                                        G0625_i_FloppyDriveDMATimeout_CPSDF = -1;
                                        G1079_i_DriveTimeout_CPSDF = 0;
                                }
                        }
                        break;
                default:
                        break;
        }
}

int16_t S0081_CPSDF_TurnOffFloppyDrive(
)
{
        if ((G0625_i_FloppyDriveDMATimeout_CPSDF > 0) || (!G0624_B_FloppyDriveTurnedOn_CPSDF)) { /* If there is a ongoing read operation or if the drive is already turned off */
                return;
        }
        G0624_B_FloppyDriveTurnedOn_CPSDF = C0_FALSE;
#ifdef MEDIA413_A20ED_A20E_A20F_A20G_A21E_A22E_A22G
        #asm
                        move.l  a6,-(sp)
                        movea.l _G1054_ps_DiskResource_CPSX,a6
                        jsr     -$18(a6)                        ; disk.resource/GiveUnit (see DR_GIVEUNIT in disk.h)
                        movea.l (sp)+,a6
                public _G1054_ps_DiskResource_CPSX
        #endasm
#endif
#ifdef MEDIA626_A31E_A31M_A33M_A35E_A35M
        if (G3171_c_ReadingCopyProtectionSector_CPSX) {
                Signal(G3165_ps_CurrentTask, 0x10000); /* Trigger signal 16 */
        }
#endif
}
#endif
#endif
#endif
