#ifndef COMPILE_H
#include "COMPILE.H"
#endif
#ifdef MEDIA207_S10EA_S20E_G20E_A20E_A31E
#ifdef MEDIA206_S10EA_S20E
/* This routine checks the 489 bytes of the fuzzy sector that contain a fuzzy bit. If there is not at least one fuzzy bit detected (a bit with a value different than the value it had in a previous sector reading) or if any of the normal bits does not have the expected value then the routine detects a copy instead of an original disk.
Before this routine is called, two parameters are pushed to the stack by R0138_CPSEF_HiddenCodeLauncher. The return address is also pushed to the stack by the jsr instruction used to call this routine (there is an rts at the end of this routine). The first parameter is the address of a buffer containing a fuzzy sector reading to analyze. The second parameter is the address of an array of 3 (DM) or 4 (CSB) addresses to store the results. This routine is called either with:
G0643_puc_FloppyDiskReadBuffer_CPSDF and G0083_api_Graphic21Result_CPSF containing pointers to:
     G0081_ai_FuzzyBits_CPSF
     G0070_B_FuzzySectorAnalyzed_CPSF
     G0078_B_FuzzyBitFound_CPSF
     G0073_i_StopFreeingMemory_CPSF (CSB only, only the first 3 pointers are used in DM)
G0295_ac_FuzzySectorReadingBuffer_CPSE and G0429_api_Graphic21Result_CPSE containing pointers to:
     G0293_ai_FuzzyBits_CPSE
     G0031_i_Graphic562_FuzzySectorAnalyzed_CPSE
     G0418_l_LastEvent22Time_CPSE
     G0068_i_CheckLastEvent22Time_CPSE (CSB only, only the first 3 pointers are used in DM) */
asm {
                movem.l D6-D7/A3,-(A7)                  /* Backup registers to the stack */
                movea.l 16(A7),A0                       /* First parameter: Address of the 512 bytes buffer containing a sector 7 reading (G0643_puc_FloppyDiskReadBuffer_CPSDF or G0295_ac_FuzzySectorReadingBuffer_CPSE) */
                lea     20(A0),A0                       /* Address of the first byte in the sector that contains a fuzzy bit at offset 20 in buffer */
                movea.l 20(A7),A3                       /* Second routine parameter: Address of array of 4 pointers (G0083_api_Graphic21Result_CPSF or G0429_api_Graphic21Result_CPSE) */
                movea.l (A3)+,A1                        /* Address of (G0081_ai_FuzzyBits_CPSF or G0293_ai_FuzzyBits_CPSE): a 64 bytes buffer containing the fuzzy bits extracted from a previous sector 7 reading */
                move.w  #489,D6                         /* Counter for InspectionLoop. 489 = number of bytes in sector 7 that contain a fuzzy bit */
                moveq   #16,D7                          /* Data will be read and analysed in blocks of 16 bytes (16 fuzzy bits, one from each byte, will form a word in D2) */
                moveq   #0,D0                           /* D0 will store the number of D2 words (fuzzy bits) that are different between two readings of sector 7. If D0 stays at 0 (no difference), then the disk is identified as a copy */
        T0914000_InspectionLoop:
                moveq   #0,D1                           /* Index of a bit in D2 in the InspectionLoop. Incremented until it reaches value 16 */
                moveq   #0,D2                           /* D2 stores the values of 16 fuzzy bits (bit 7 extracted from 16 bytes) and is then compared with a previous value from the specified buffer */
        T0914001_AnalysisLoop:
                move.b  (A0)+,D3                        /* Get next byte to inspect from read buffer in D3 then increment A0 */
                bpl.s   T0914002_FuzzyBitClear          /* Branch if bit 7 of D3 is 0 (in each byte, Bit 7 is the fuzzy bit) */
                bset    D1,D2                           /* Set in D2 the bit whose index is in D1 */
                andi.b  #0x7F,D3                        /* Clear bit 7 (the fuzzy bit) in D3 */
        T0914002_FuzzyBitClear:
                cmpi.b  #0x68,D3
                beq.s   T0914003_ValidByte              /* Branch if D3 = 0x68 (if the normal bits in the byte have the expected value 0x68) */
                moveq   #0,D0                           /* D0 = 0 means that the sector is not original */
                bra.s   T0914006_ExitInspectionLoop
        T0914003_ValidByte:
                addq.w  #1,D1
                subq.w  #1,D6
                beq.s   T0914004_ExitAnalysisLoop       /* Branch if D6 = 0 (if all bytes in the sector that contain a fuzzy bit have been analyzed) */
                cmp.w   D7,D1
                bne.s   T0914001_AnalysisLoop           /* Branch if D1 <> 16 (if 16 fuzzy bits have not yet been extracted into D2) */
        T0914004_ExitAnalysisLoop:
                cmp.w   (A1),D2                         /* Compare word of 16 fuzzy bits previously read with the one just collected */
                beq.s   T0914005_NoDifferenceFound      /* Branch if no difference was found between the two readings */
                addq.w  #1,D0                           /* Increment the count of differences between readings of sector 7 */
        T0914005_NoDifferenceFound:
                move.w  D2,(A1)+                        /* Overwrite the previously read word of fuzzy bits with the newly collected one. A total of (489/8) = 62 bytes are written in the 64 bytes buffer */
                tst.w   D6
                bne.s   T0914000_InspectionLoop         /* Branch if D6 <> 0 (if there are still bytes to inspect) */
        T0914006_ExitInspectionLoop:
                movea.l (A3)+,A0                        /* Address of (G0070_B_FuzzySectorAnalyzed_CPSF or G0031_i_Graphic562_FuzzySectorAnalyzed_CPSE): a variable used as a boolean to indicate if sector was analyzed */
                move.w  #136,(A0)                       /* Set value to C00136_TRUE. This indicates that the fuzzy bits sector analysis has been completed */
                tst.w   D0
                bne.s   T0914007_DiskIsOriginal         /* Branch if D0 <> 0 (if differences have been found between two sector readings which means the disk is original) */
#ifdef MEDIA000_S10EA
                movea.l (A3),A3
                clr.l   (A3)
#endif
#ifdef MEDIA264_S20E
                movea.l (A3),A0                         /* Address of (G0078_B_FuzzyBitFound_CPSF or G0418_l_LastEvent22Time_CPSE) */
                clr.l   (A0)                            /* If no differences were found with the previous reading, the value is set to 0 otherwise it is not modified */
#endif
                                                        /* BUG0_01 Coding error without consequence. If graphic #21 is called with G0643_puc_FloppyDiskReadBuffer_CPSDF as second parameter and it does not detect any fuzzy bit then it writes 0 as a long (4 bytes) to G0078_B_FuzzyBitFound_CPSF but this variable is an int16_t (2 bytes) which causes G0077_B_DoNotDrawFluxcagesDuringEndgame (not related to the copy protection) to be overwritten too as a side effect as it is the next variable in memory. No consequence because the value of this variable is always 0 until the very end of the game */
        T0914007_DiskIsOriginal:
#ifdef MEDIA264_S20E
                movea.l 4(A3),A3                        /* CSB only. Address of (G0073_i_StopFreeingMemory_CPSF or G0068_i_CheckLastEvent22Time_CPSE) */
                move.w  #512,(A3)                       /* CSB only. The value is set to C00512_FALSE */
#endif
                movem.l (A7)+,D6-D7/A3                  /* Restore registers from the stack */
                rts                                     /* Return from subroutine */
                dc.l    0x00000000                      /* Unused padding */
}
#endif
#ifdef MEDIA387_G20E
asm(F0914_Graphic21) {
                PHD             /* Push current Direct Page register */
                LDA     0x6,S   /* Load A from stack (function call parameter) */
                TCD             /* Transfer C accumulator to Direct Register */
                PLA             /* Pull current Direct Page register from stack into A (16 bit) */
                STA     0x0     /* Store A (16 bit) at offset 0 in Direct page */
                PLA             /* Pull A (16 bit) */
                STA     0xa     /* Store A (16 bit) at offset 0xA in Direct page */
                SEP     #0x20   /* LONGA OFF */
                PLA             /* Pull A (8 bit) */
                STA     0xc     /* Store A (8 bit) at offset 0xC in Direct page */
                REP     #0x20   /* LONGA ON */
                PLA             /* Pull A (16 bit), value ignored */
                PLA             /* Pull A (16 bit) */
                STA     0x2     /* Store A (16 bit) at offset 0x2 in Direct page M517_FuzzySectorReadingBuffer_CPSE */
                PLA             /* Pull A (16 bit) */
                STA     0x4     /* Store A (16 bit) at offset 0x4 in Direct page M517_FuzzySectorReadingBuffer_CPSE+2 */
                PLA             /* Pull A (16 bit) */
                STA     0x6     /* Store A (16 bit) at offset 0x6 in Direct page G0429_api_Graphic21Result_CPSE */
                PLA             /* Pull A (16 bit) */
                STA     0x8     /* Store A (16 bit) at offset 0x8 in Direct page G0429_api_Graphic21Result_CPSE+2 */
/* Copy function parameter P1007_api_Graphic21Result = G0429_api_Graphic21Result_CPSE (array of 4 pointers = 16 bytes) into Direct Page at offset 0xf */
                LDX     #0x0e   /* X = 14 */
                TXY             /* Y = X */
        T914_1:
                LDA     [0x6],Y /* Address of G0429_api_Graphic21Result_CPSE */
                STA     0xf,X
                DEX             /* Decrement X */
                DEX             /* Decrement X */
                DEY             /* Decrement Y */
                DEY             /* Decrement Y */
                BPL     T914_1  /* Branch if Y >= 0. Loop to copy 8 words = 16 bytes */
/* Check all fuzzy bits in the sector reading buffer from offset 13 to 692 */
                STZ     0xd     /* L0784_i_DifferingWordCount = 0. Store 0 at offset 0xd in Direct page */
                LDY     #0x0d   /* Y = 13 */
        T914_2:
                SEP     #0x20   /* LONGA OFF */
                LDA     [0x2],Y /* Address of M517_FuzzySectorReadingBuffer_CPSE */
                TAX             /* X = Accumulator */
                EOR     [0xf]   /* A = A exclusive or value at offset 0xf P1007_api_Graphic21Result[0] = G0293_ai_FuzzyBits_CPSE in Direct page to proceed to the next byte in the buffer */
                PHA             /* Push A */
                TXA             /* A = X */
                AND     #0x1b   /* A = A & 0x1b */
                STA     [0xf]   /* P1007_api_Graphic21Result[0] = G0293_ai_FuzzyBits_CPSE */
                REP     #0x20   /* LONGA ON */
                INC     0xf     /* Increment value (16 bit) at offset 0xf P1007_api_Graphic21Result[0] = G0293_ai_FuzzyBits_CPSE in Direct page to proceed to the next byte in the buffer */
                BNE     T914_3
                INC     0x11    /* Increment value (16 bit) at offset 0x11 in Direct page */
        T914_3:
                SEP     #0x20   /* LONGA OFF */
                PLA             /* Pull A */
                REP     #0x20   /* LONGA ON */
                AND     #0x1b   /* A = A & 0x1b */
                BEQ     T914_4
                INC     0xd     /* L0784_i_DifferingWordCount++. Increment value (16 bit) at offset 0xd in Direct page */
        T914_4:
                INY             /* Increment Y */
                INY             /* Increment Y */
                CPY     #0x2bf  /* Compare 692 to Y */
                BCC     T914_2
/* Update Graphic 21 result data */
                LDA     0xd     /* L0784_i_DifferingWordCount */
                BNE     T914_5
                LDA     #0x00   /* A = 0 */
                STA     [0x17]  /* *((long*)(P1007_api_Graphic21Result[2])) = 0;        G0418_l_LastEvent22Time_CPSE = 0 */
        T914_5:
                LDA     #0x88   /* A = C00136_TRUE */
                STA     [0x13]  /* *(P1007_api_Graphic21Result[1]) = C00136_TRUE;       G0031_i_Graphic562_FuzzySectorAnalyzed_CPSE = C00136_TRUE */
                LDA     #0x200  /* A = C00512_FALSE */
                STA     [0x1b]  /* *(P1007_api_Graphic21Result[3]) = C00512_FALSE;      G0068_i_CheckLastEvent22Time_CPSE = C00512_FALSE */
/* Restore stack and registers to their status before the call */
                TSC             /* Transfer Stack register to Accumulator */
                SEC
                SBC     #0x0a   /* Substract 10 */
                TCS             /* Transfer Accumulator to Stack register */
                SEP     #0x20   /* LONGA OFF */
                LDA     0xc
                PHA             /* Push A */
                REP     #0x20   /* LONGA ON */
                LDA     0xa
                PHA             /* Push A */
                LDA     0xd
                PHA             /* Push A */
                LDA     0x0     /* Restore Direct page register */
                TCD             /* Restore Direct page register */
                PLA             /* Pull A */
                RTL
                DCL      0      /* Probably padding added by graphic compressor not present in original code */
}
#endif
#ifdef MEDIA432_A20E
int16_t F0914_Graphic21(P1006_pui_SectorBuffer, P1007_api_Graphic21Result) /* Similar to F0277_CPSE_IsFuzzySectorValid_FuzzyBits */
REGISTER unsigned int16_t* P1006_pui_SectorBuffer;
int16_t* P1007_api_Graphic21Result[];
{
        REGISTER int16_t L0780_i_ByteIndex;
        REGISTER int16_t L0781_i_Counter;
        REGISTER int16_t L0782_i_FuzzyBitCount;
        REGISTER int16_t L0783_i_FuzzyBits;
        int16_t L0784_i_DifferingWordCount;
        int16_t* L1786_pi_FuzzyBits;


        L1786_pi_FuzzyBits = P1007_api_Graphic21Result[0];
        L0782_i_FuzzyBitCount = 0;
        L0784_i_DifferingWordCount = 0;
        L0781_i_Counter = 0;
        L0783_i_FuzzyBits = 0;
        for (L0780_i_ByteIndex = 20; L0780_i_ByteIndex <= 508; L0780_i_ByteIndex++) {
                L0783_i_FuzzyBits = (L0783_i_FuzzyBits << 1) | ((P1006_pui_SectorBuffer[L0780_i_ByteIndex] >> 14) & 0x0001);
                if (((L0782_i_FuzzyBitCount++) == 16) || (L0780_i_ByteIndex == 508)) {
                        L0782_i_FuzzyBitCount = 0;
                        if (L0783_i_FuzzyBits != L1786_pi_FuzzyBits[L0781_i_Counter]) {
                                L0784_i_DifferingWordCount++;
                        }
                        L1786_pi_FuzzyBits[L0781_i_Counter++] = L0783_i_FuzzyBits;
                        L0783_i_FuzzyBits = 0;
                }
        }
        if (!L0784_i_DifferingWordCount) {
                *((long*)(P1007_api_Graphic21Result[2])) = 0;
        }
        *(P1007_api_Graphic21Result[3]) = C00512_FALSE;
        *(P1007_api_Graphic21Result[1]) = C00136_TRUE;
        return L0784_i_DifferingWordCount;
}
#endif
#ifdef MEDIA618_A31E
int16_t F0914_Graphic21(P1006_pui_SectorBuffer, P1007_api_Graphic21Result) /* Similar to F0277_CPSE_IsFuzzySectorValid_FuzzyBits */
register unsigned int16_t* P1006_pui_SectorBuffer;
int16_t* P1007_api_Graphic21Result[];
{
        register int16_t L0780_i_ByteIndex;
        register int16_t L0781_i_Counter;
        register int16_t L0782_i_FuzzyBitCount;
        register int16_t L0783_i_FuzzyBits;
        register int16_t L0784_i_DifferingWordCount;
        register int16_t* L1786_pi_FuzzyBits;


        L1786_pi_FuzzyBits = P1007_api_Graphic21Result[0];
        L0782_i_FuzzyBitCount = 0;
        L0784_i_DifferingWordCount = 0;
        L0781_i_Counter = 0;
        L0783_i_FuzzyBits = 0;
        for (L0780_i_ByteIndex = 635; L0780_i_ByteIndex <= 1123; L0780_i_ByteIndex++) {
                L0783_i_FuzzyBits = (L0783_i_FuzzyBits << 1) | ((P1006_pui_SectorBuffer[L0780_i_ByteIndex] >> 14) & 0x0001);
                if (((L0782_i_FuzzyBitCount++) == 16) || (L0780_i_ByteIndex == 1123)) {
                        L0782_i_FuzzyBitCount = 0;
                        if (L0783_i_FuzzyBits != L1786_pi_FuzzyBits[L0781_i_Counter]) {
                                L0784_i_DifferingWordCount++;
                        }
                        L1786_pi_FuzzyBits[L0781_i_Counter++] = L0783_i_FuzzyBits;
                        L0783_i_FuzzyBits = 0;
                }
        }
        if (!L0784_i_DifferingWordCount) {
                *((long*)(P1007_api_Graphic21Result[2])) = 0;
        }
        *(P1007_api_Graphic21Result[3]) = C00512_FALSE;
        *(P1007_api_Graphic21Result[1]) = C00136_TRUE;
        return L0784_i_DifferingWordCount;
}
#endif
#endif
