
*
*   c2p4.s - chunky to planar routine for nybbles
*   Copyright (C) 1997 Aki Laukkanen
*
*   This program is free software; you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation; either version 2 of the License, or
*   (at your option) any later version.
*
*   This program is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License
*   along with this program; if not, write to the Free Software Foundation,
*   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*

	include "exec/types.i"
	include "exec/memory.i"
	include "lvo/exec_lib.i"
	include "mmu.i"
	include "evd_context.i"


	XDEF    _c2p4
	XDEF    @c2p4
	XDEF    _c2p4_reloc
	XDEF    @c2p4_reloc
	XDEF    _c2p4_deinit
	XDEF    @c2p4_deinit

	cnop    0,16

_c2p4_reloc
@c2p4_reloc
	movem.l a2/a6,-(sp)
	move.l  a0,a2
	move.l  (ct_SysBase,a0),a6
	move.l  #_c2p4_end-_c2p4,d0
	move.l  #MEMF_FAST,d1
	jsr     (_LVOAllocVec,a6)
	tst.l   d0
	beq     .fail
	move.l  d0,a0
	lea     _c2p4,a1
	move.w  #_c2p4_end-_c2p4-1,d1
.loop
	move.b  (a1)+,(a0)+
	dbf     d1,.loop

	move.l  d0,a0
	move.l  (ct_ChunkyBuffer,a2),d1
	add.l   (ct_Size,a2),d1
	move.l  d1,(c2p4_chunkyend1-_c2p4,a0)
	move.l  d1,(c2p4_chunkyend2-_c2p4,a0)
	move.l  d1,(c2p4_chunkyend3-_c2p4,a0)
	move.l  d1,(c2p4_chunkyend4-_c2p4,a0)
	move.l  d1,(c2p4_chunkyend5-_c2p4,a0)
	move.l  (ct_BitMap+bm_Planes+4,a2),d1
	sub.l   (ct_BitMap+bm_Planes,a2),d1
	move.l  d1,(c2p4_bpl1_1-_c2p4,a0)
	move.l  d1,(c2p4_bpl1_2-_c2p4,a0)
	move.l  (ct_BitMap+bm_Planes+8,a2),d1
	sub.l   (ct_BitMap+bm_Planes,a2),d1
	move.l  d1,(c2p4_bpl2_1-_c2p4,a0)
	move.l  d1,(c2p4_bpl2_2-_c2p4,a0)
	move.l  (ct_BitMap+bm_Planes+12,a2),d1
	sub.l   (ct_BitMap+bm_Planes,a2),d1
	move.l  d1,(c2p4_bpl3_1-_c2p4,a0)
	move.l  d1,(c2p4_bpl3_2-_c2p4,a0)

	move.l  d0,a2
	jsr     (_LVOCacheClearU,a6)
	move.l  a2,d0

.fail
	movem.l (sp)+,a2/a6
	rts

	cnop    0,16

_c2p4_deinit
@c2p4_deinit
	movem.l a2/a6,-(sp)
	move.l  a0,a2
	move.l  (ct_SysBase,a2),a6
	move.l  (ct_C2P,a2),a1
	jsr     (_LVOFreeVec,a6)
	clr.l   (ct_C2P,a2)
	movem.l (sp)+,a2/a6
	rts

_c2p4
@c2p4
	movem.l d2-d7/a2-a6,-(sp)

	move.l  (ct_ChunkyBuffer,a0),a1
	move.l  (ct_DeltaBuffer,a0),a3
	move.l  (ct_PageDesc,a0),a4
	move.l  (ct_BitMap+bm_Planes,a0),a2

	move.l  a1,a5                       ; a5 : end of the MMU page
c2p4_loop
	add.l   #$1000,a5

	cmp.l   #$DEADBEEF,a5               ; test with the end of the chunky buffer
c2p4_chunkyend1 EQU *-4                 ; self modify
	bls     c2p4_skip_move
	move.l  #$DEADBEEF,a5
c2p4_chunkyend2 EQU *-4
c2p4_skip_move
	move.l  (a4)+,a0                    ; fetch the page descriptor
	move.l  (a0),d0
	btst    #PDB_M,d0
	bne     c2p4_skip

	adda.l  #$1000,a1                   ; update chunky buffers
	add.l   #$400,a2                    ; update BitPlane pointers
	adda.l  #$1000,a3

	cmp.l   #$DEADBEEF,a1               ; check if more to c2p
c2p4_chunkyend3 EQU *-4
	bcs     c2p4_loop

	movem.l (sp)+,d2-d7/a2-a6

	rts

	cnop    0,16

c2p4_skip
	bclr    #PDB_M,d0                   ; modified bit was set
	move.l  d0,(a0)
c2p4_iloop

	move.l  a1,a0                       ; chunkybuffer -> a0
	move.l  a3,d5                       ; deltabuffer -> a0

	cmp.l   (a1)+,(a3)+                 ; compare chunky and delta buffers
	bne.w   c2p4_found_first
	cmp.l   (a1)+,(a3)+
	bne     c2p4_found_first
	cmp.l   (a1)+,(a3)+
	bne     c2p4_found_first
	cmp.l   (a1)+,(a3)+
	bne     c2p4_found_first

	addq.l  #4,a2                       ; update bitplane and chunky pointers

	cmp.l   a5,a1                       ; check if end of the current page
	bcs     c2p4_iloop

	cmp.l   #$DEADBEEF,a1               ; check if end of the chunky buffer
c2p4_chunkyend4 EQU *-4
	bcs     c2p4_loop

	movem.l (sp)+,d2-d7/a2-a6
	rts

	cnop    0,16

c2p4_found_first
	move.l  a0,a6                       ; address from where we should start c2ping
c2p4_found
	move.l  d5,a3                       ; backup these
	move.l  a0,a1

	move16  (a1)+,(a3)+                 ; use move16 to copy the data to
										; deltabuffer - fastest way
										; by far because it uses burst writes and no copyback

	move.l  a3,d5                       ; update backups
	move.l  a1,a0

	cmp.l   a5,a1                       ; this page
	bcc.s   c2p4_c2p                    ; end of so lets start c2ping

	cmp.l   (a3)+,(a1)+                 ; compare chunky and delta buffers
	bne.s   c2p4_found                      ; if difference was found back to loop
	cmp.l   (a3)+,(a1)+
	bne.s   c2p4_found
	cmp.l   (a3)+,(a1)+
	bne.s   c2p4_found
	cmp.l   (a3)+,(a1)+
	bne.s   c2p4_found

c2p4_c2p
	move.l  a0,a1
c2p4_start
; a6 : chunky
; a1 : end
; a2 : planes
; a3 : compare
; a4 : pagedesc
; a5 : end of 4 kB block

	move.l  (a6)+,d0
	move.l  (a6)+,d1
	move.l  (a6)+,d2
	move.l  (a6)+,d3

; 16x2 (d0,d2),(d1,d3)
; 4x2 (d0,d2),(d1,d3)
; 1x2 (d0,d2),(d1,d3)
; 8x1 (d0,d1)
; 2x1 (d0,d1)
; 8x1 (d2,d3)
; 2x1 (d3,d3)

; 16x2 (d0,d2),(d1,d3)
	swap    d2
	swap    d3
	eor.w   d0,d2
	eor.w   d1,d3
	eor.w   d2,d0
	eor.w   d3,d1
	eor.w   d0,d2
	eor.w   d1,d3
	swap    d2
	swap    d3

; 4x2 (d0,d2),(d1,d3)

	move.l  d2,d4
	move.l  d3,d6
	lsr.l   #4,d4
	lsr.l   #4,d6
	eor.l   d0,d4
	eor.l   d1,d6
	and.l   #$0f0f0f0f,d4
	and.l   #$0f0f0f0f,d6
	eor.l   d4,d0
	eor.l   d6,d1
	lsl.l   #4,d4
	lsl.l   #4,d6
	eor.l   d4,d2
	eor.l   d6,d3

; 1x2 (d0,d2),(d1,d3)

	move.l  d2,d4
	move.l  d3,d6
	lsr.l   #1,d4
	lsr.l   #1,d6
	eor.l   d0,d4
	eor.l   d1,d6
	and.l   #$55555555,d4
	and.l   #$55555555,d6
	eor.l   d4,d0
	eor.l   d6,d1
	add.l   d4,d4
	add.l   d6,d6
	eor.l   d4,d2
	eor.l   d6,d3

; 8x1 (d0,d1)

	move.l  d1,d4
	lsr.l   #8,d4
	eor.l   d0,d4
	and.l   #$00ff00ff,d4
	eor.l   d4,d0
	lsl.l   #8,d4
	eor.l   d4,d1

; 2x1 (d0,d1)

	move.l  d1,d4
	lsr.l   #2,d4
	eor.l   d0,d4
	and.l   #$33333333,d4
	eor.l   d4,d0
	move.l  d0,($12341234,a2)
c2p4_bpl3_1 EQU *-4
	lsl.l   #2,d4
	eor.l   d4,d1

; 8x1 (d2,d3)

	move.l  d3,d4
	lsr.l   #8,d4
	eor.l   d2,d4
	and.l   #$00ff00ff,d4
	eor.l   d4,d2
	lsl.l   #8,d4
	eor.l   d4,d3

; 2x1 (d2,d3)

	move.l  d3,d4
	lsr.l   #2,d4
	eor.l   d2,d4
	and.l   #$33333333,d4
	eor.l   d4,d2
	lsl.l   #2,d4
	eor.l   d4,d3

	move.l  d1,d4
	move.l  d2,d5
	move.l  d3,d7

	cmp.l   a6,a1
	beq     c2p4_end
c2p4_x1
	move.l  (a6)+,d0                        ; source data       pOEP (special case,
	move.l  (a6)+,d1                        ;                   sOEP see M68060UM/AD
	move.l  (a6)+,d2                        ;                   pOEP section 10 for
	move.l  (a6)+,d3                        ;                   sOEP reference)

	move.l  d4,($12341234,a2)
c2p4_bpl1_1 EQU *-4

; 16x2 (d0,d2),(d1,d3)

	swap    d2
	swap    d3
	eor.w   d0,d2
	eor.w   d1,d3
	eor.w   d2,d0
	eor.w   d3,d1
	eor.w   d0,d2
	eor.w   d1,d3
	swap    d2
	swap    d3

; 4x2 (d0,d2),(d1,d3)

	move.l  d2,d4
	move.l  d3,d6
	lsr.l   #4,d4
	lsr.l   #4,d6
	eor.l   d0,d4

	move.l  d5,($12341234,a2)
c2p4_bpl2_1 EQU *-4

	eor.l   d1,d6
	and.l   #$0f0f0f0f,d4
	and.l   #$0f0f0f0f,d6
	eor.l   d4,d0
	eor.l   d6,d1
	lsl.l   #4,d4
	lsl.l   #4,d6
	eor.l   d4,d2
	eor.l   d6,d3

; 1x2 (d0,d2),(d1,d3)

	move.l  d2,d4
	move.l  d3,d6
	lsr.l   #1,d4
	lsr.l   #1,d6
	eor.l   d0,d4
	eor.l   d1,d6
	and.l   #$55555555,d4
	and.l   #$55555555,d6
	eor.l   d4,d0

	move.l  d7,(a2)+

	eor.l   d6,d1
	add.l   d4,d4
	add.l   d6,d6
	eor.l   d4,d2
	eor.l   d6,d3

; 8x1 (d0,d1)

	move.l  d1,d4
	lsr.l   #8,d4
	eor.l   d0,d4
	and.l   #$00ff00ff,d4
	eor.l   d4,d0
	lsl.l   #8,d4
	eor.l   d4,d1

; 2x1 (d0,d1)

	move.l  d1,d4
	lsr.l   #2,d4
	eor.l   d0,d4
	and.l   #$33333333,d4
	eor.l   d4,d0

	move.l  d0,($12341234,a2)
c2p4_bpl3_2 EQU *-4

	lsl.l   #2,d4
	eor.l   d4,d1

; 8x1 (d2,d3)

	move.l  d3,d4
	lsr.l   #8,d4
	eor.l   d2,d4
	and.l   #$00ff00ff,d4
	eor.l   d4,d2
	lsl.l   #8,d4
	eor.l   d4,d3

; 2x1 (d2,d3)

	move.l  d3,d4
	lsr.l   #2,d4
	eor.l   d2,d4
	and.l   #$33333333,d4
	eor.l   d4,d2
	lsl.l   #2,d4
	eor.l   d4,d3

	move.l  d1,d4
	move.l  d2,d5
	move.l  d3,d7

	cmp.l   a6,a1
	bne     c2p4_x1
c2p4_end
	move.l  d4,($12341234,a2)
c2p4_bpl1_2 EQU *-4
	lea     (16,a6),a1
	move.l  d5,($12341234,a2)
c2p4_bpl2_2 EQU *-4
	move.l  d7,(a2)+
	addq.l  #4,a2

	cmp.l   a5,a1
	bcs     c2p4_iloop
	beq     c2p4_skipper

	subq.l  #4,a2
	lea     (-16,a1),a1
c2p4_skipper
	cmp.l   #$DEADBEEF,a1
c2p4_chunkyend5 EQU *-4
	bcs     c2p4_loop

	movem.l (sp)+,d2-d7/a2-a6
	rts
_c2p4_end
