;
; Gestion du CRTC 6845
;
; Les adresses définies par AMSTRAD sont :
;
; BCXX : Sélection d'un registre                (Ecriture)
; BDXX : Positionne la valeur du registre       (Ecriture)
;
; inutilisés ici :
; BEXX : Lecture du status du CRTC
; BFXX : Lecture de la valeur d'un registre (regs 14 à 17 seulement )
;
; Les registres 16 et 17 déterminent la position du crayon optique, et sont
; inhibé dans AMI-CPC... (seulement 16 regs possibles pour le CRTC...)
;
;
            SECTION         text,CODE


            XREF            RedrawScreen
            XREF            ClrScreen


ADJADRCPC   MACRO
            MOVE.W          D6,D0
            ADD.W           D7,D0               ;D0 = adr + offset
            AND.W           #$7FF,D0
            MOVE.W          D6,\1
            AND.W           #$3800,\1           ;adrReel = adr & 0x3800
            ADD.W           D0,\1
            ADDQ.W          #1,D6
            ENDM


CalcAdrEcrCPC:
            MOVEM.L         D0-D1/D4-D7/A1-A5,-(A7)

            LEA             RegsCRTC,A1
;
; Precalcul de Reg1 * 2 - 1 dans A3
;
            CLR.W           D4
            MOVE.B          1(A1),D4
            BEQ.W           FinCalc
            ADD.B           D4,D4
            SUBQ.B          #1,D4
            MOVE.W          D4,A3
;
; Precalcul de 2047 - Reg6 * Reg1 * 2 dans A4
;
            ADDQ.B          #1,D4
            CLR.W           D0
            MOVE.B          6(A1),D0
            BEQ.W           FinCalc
            MULU.W          D4,D0
            MOVE.W          #2047,D4
            SUB.W           D0,D4
            MOVE.W          D4,A4
;
; Precalcul de 46 - Reg2 * 2 dans A5
;
            MOVE.W          #46,D6
            SUB.B           2(A1),D6
            ADD.B           D6,D6
            MOVE.W          D6,A5
;
; Offset dans D7
;
            MOVE.W          12(A1),D7
            ADD.W           D7,D7

            SUBA.L          A0,A0
            MOVEQ           #0,D6

BCLNbBlocks:
            MOVE.W          A0,D3               ; decal = NbBlocks
            MOVE.B          6(A1),D1
            SUBQ.B          #1,D1
            AND.W           #$1F,D1

BCLNbLignes:
            MOVE.W          A3,D4
            MOVE.W          D3,D2               ;AdrCPC = decal
            ADD.W           A5,D2

BCLAdrCPC:  ADJADRCPC       D5
            MOVE.W          D2,0(A2,D5.W*2)
            ADDQ.W          #1,D2
            DBF             D4,BCLAdrCPC

            ADD.W           #640,D3
            DBF             D1,BCLNbLignes

            MOVE.W          A4,D3
            MOVE.W          #-1,D2

BCLdecal:   ADJADRCPC       D5
            MOVE.W          D2,0(A2,D5.W*2)
            DBF             D3,BCLdecal

            LEA             80(A0),A0
            CMP.W           #640,A0
            BNE.S           BCLNbBlocks

FinCalc:    MOVEM.L         (A7)+,D0-D1/D4-D7/A1-A5
            MOVEQ           #0,D0
            RTS


_WriteCRTC:
            AND.W           #$BF00,D0
            CMP.W           #$BC00,D0
            BNE.S           WriteCRTC_1

            ;
            ; Ecriture adresse #$BC00
            ;
            AND.W           #$0F,D1
            MOVE.W          D1,lastReg
            RTS

            ;
            ; Ecriture Adresse #$BD00
            ;
WriteCRTC_1:
            CMP.W           #$BD00,D0
            BNE.S           WriteCRTC_F

            LEA             RegsCRTC,A0
            MOVE.W          lastReg,D0
            MOVE.B          0(A0,D0.W),D2       ; Lecture ancienne val. reg
            CMP.B           D1,D2               ; Valeur différente pour
            BEQ.S           WriteCRTC_F         ; le registre ?

            MOVE.B          D1,0(A0,D0.W)       ; Ecriture registre

            CMP.B           #12,D0              ; Registre 12 ?
            BNE.S           WriteCRTC_3

            ;
            ; Vérifie si offset est identique
            ;
            MOVE.B          D1,D0
            AND.W           #$F,D2
            AND.W           #$F,D0
            CMP.B           D0,D2
            BEQ.S           WriteCRTC_11        ; si oui, pas de recalcul
            BSR.W           CalcAdrEcrCPC
WriteCRTC_11:
            AND.W           #$30,D1
            LSR.W           #4,D1
            MOVE.W          D1,adrEcr           ; nouvelle adresse ecran
            AND.W           #$30,D2
            LSR.W           #4,D2
            CMP.W           D1,D2               ; page écran différent ?
            BEQ.S           WriteCRTC_2
            BRA.W           RedrawScreen
WriteCRTC_2:
            RTS

WriteCRTC_3:
            CMP.B           #13,D0
            BEQ.S           WriteCRTC_4
            CMP.B           #6,D0
            BEQ.S           WriteCRTC_4
            CMP.B           #2,D0
            BEQ.S           WriteCRTC_4
            CMP.B           #1,D0
            BEQ.S           WriteCRTC_4
WriteCRTC_F:
            RTS

WriteCRTC_4:
            ; Registre 1,2,6 ou 13
            CMP.B           #13,D0
            ;
            ; Inutile d'effacer l'écran quand changement du reg. 13
            ;
            BEQ.S           WriteCRTC_5
            ;
            ; Nouveau >= Ancien Reg ?
            ;
            CMP.B           D2,D1
            ;
            ; si oui, inutile d'effacer l'écran
            ;
            BGE.S           WriteCRTC_5
            BSR.W           ClrScreen

WriteCRTC_5:
            BSR.W           CalcAdrEcrCPC
            BRA.W           RedrawScreen


            SECTION         data,DATA


lastReg:    DC.W            0,0
adrEcr:     DC.W            $03,0


            SECTION         udata,BSS


tabAdrMemEcrCPC:
            DS.W            $4000

RegsCRTC:   
            DS.B            16


            XDEF            _WriteCRTC
            XDEF            adrEcr
            XDEF            tabAdrMemEcrCPC


            END
