# Chunky2Planar algorithm, originally by James McCoull
# Modified by Peter McGavin for variable size and depth
# and "compare buffer" (hope I didn't slow it down too much)
#
# Ported by Frank Wille (phx) <frank@phoenix.owl.de> to PowerPC (04-Jan-98).
# Using optimized merge-macro by Tim Boescke (phx,26-Jan-98)
# AGA-bug and EHB-palette-change-bug fixed (phx,31-Jan-98)
#
# Modified for interleaved and system friendly by Álmos Rajnai (04-Jul-99)
#
# Included to the Flamingo project on 13-Jun-99
# Now it is being set to 8 bitplanes (for Flamingo)
#
# 	Cpu only solution VERSION 2
#	Not optimized - directly ported from 040-source... (phx)
#	bitplanes are assumed interleaved
#	analyse instruction offsets to check performance

#void c2p_8_ppc (__reg("r3") UBYTE *chunky_data,
#                __reg("r4") PLANEPTR raster,
#                __reg("r5") UBYTE *compare_buffer,
#                __reg("r22") ULONG bytesperrow,
#                __reg("r23") ULONG rowlength
#                __reg("r24") ULONG chunkysize)

# r3 -> width*height chunky pixels
# r4 -> contiguous bitplanes
# r5 -> compare buffer
# r22 = bytes per row
# r23 = rowlength in pixels

.macro	merge		# in1,in2,tmp3,tmp4,mask,shift
# \1 = abqr
# \2 = ijyz
	srwi	\3,\2,\6
	lis	\4,(\5&0xffff0000)>>16
	ori	\4,\4,\5&0xffff
	xor	\3,\3,\1
	and	\3,\3,\4
	xor	\1,\1,\3
	slwi	\3,\3,\6
	xor	\2,\2,\3
.endm

	.text

	.global	c2p_8_ppc

c2p_8_ppc:
	stwu	r1,-80(r1)
	stmw	r14,4(r1)		# save all non-volatile registers

# r3 = chunky buffer
# r4 = output area
# r5 = compare buffer
# r22 = bytesperrow
# r23 = rowlength
# r24 = chunkysize

	mr	r12,r22			# r12 = length of a plane-row
	srwi	r31,r23,3		# r31 = a rowlength in bytes
	slwi	r27,r22,3		# r27 = skip at the end of a row
	sub	r27,r27,r31		#       minus a row
	srwi	r28,r23,5		# 32 pixel a cycle
					# r28 = rowlength in cycles
	add	r30,r3,r24		# calc end of screen address

	mr	r29,r28

first_loop:

	lwz	r6,0(r3)
	lwz	r7,0(r5)
	cmpw	r6,r7
	bne	first_case
	lwz	r6,4(r3)
	lwz	r7,4(r5)
	cmpw	r6,r7
	bne	first_case
	lwz	r6,8(r3)
	lwz	r7,8(r5)
	cmpw	r6,r7
	bne	first_case
	lwz	r6,12(r3)
	lwz	r7,12(r5)
	cmpw	r6,r7
	bne	first_case
	lwz	r6,16(r3)
	lwz	r7,16(r5)
	cmpw	r6,r7
	bne	first_case
	lwz	r6,20(r3)
	lwz	r7,20(r5)
	cmpw	r6,r7
	bne	first_case
	lwz	r6,24(r3)
	lwz	r7,24(r5)
	cmpw	r6,r7
	bne	first_case
	lwz	r6,28(r3)
	lwz	r7,28(r5)
	cmpw	r6,r7
	bne	first_case

	addi	r4,r4,4			# skip 32 pixels on output
	addi	r3,r3,32
	addi	r5,r5,32

	subi	r29,r29,1
	cmpwi	r29,0
	bne+	.next

	add	r4,r4,r27		# skip extra bytes at rowend
	mr	r29,r28
.next:
	cmplw	r3,r30
	blt	first_loop
	b	exit			# exit if no changes found

first_case:
# hint from M68k: d0-d3 -> r8-r11,  d4-d7 -> r14-r17
	lwz	r9,0(r3)
	lwz	r11,4(r3)
	lwz	r8,8(r3)
	lwz	r10,12(r3)
	lwz	r14,2(r3)
	lwz	r15,10(r3)
	lwz	r16,6(r3)
	lwz	r17,14(r3)

	stw	r9,0(r5)
	stw	r11,4(r5)
	stw	r8,8(r5)
	stw	r10,12(r5)

	lwz	r6,16(r3)
	rlwimi	r9,r6,16,16,31
	rlwimi	r14,r6,0,16,31
	lwz	r6,20(r3)
	rlwimi	r11,r6,16,16,31
	rlwimi	r16,r6,0,16,31
	lwz	r6,24(r3)
	rlwimi	r8,r6,16,16,31
	rlwimi	r15,r6,0,16,31
	lwz	r6,28(r3)
	rlwimi	r10,r6,16,16,31
	rlwimi	r17,r6,0,16,31

	sth	r9,16(r5)
	sth	r8,24(r5)
	sth	r11,20(r5)
	sth	r10,28(r5)
	sth	r14,18(r5)
	sth	r15,26(r5)
	sth	r16,22(r5)
	sth	r17,30(r5)

	merge	r9,r8,r6,r7,0x00ff00ff,8
	merge	r11,r10,r6,r7,0x00ff00ff,8
	merge	r9,r11,r6,r7,0x0f0f0f0f,4
	merge	r8,r10,r6,r7,0x0f0f0f0f,4

	merge	r14,r15,r6,r7,0x00ff00ff,8
	merge	r16,r17,r6,r7,0x00ff00ff,8
	merge	r14,r16,r6,r7,0x0f0f0f0f,4
	merge	r15,r17,r6,r7,0x0f0f0f0f,4

	merge	r11,r16,r6,r7,0x33333333,2
	merge	r10,r17,r6,r7,0x33333333,2
	merge	r11,r10,r6,r7,0x55555555,1
	merge	r16,r17,r6,r7,0x55555555,1

	mr	r18,r17			# plane0
	mr	r19,r16			# plane1
	mr	r20,r10			# plane2
	mr	r21,r11			# plane3

	merge	r9,r14,r6,r7,0x33333333,2
	merge	r8,r15,r6,r7,0x33333333,2
	merge	r9,r8,r6,r7,0x55555555,1
	merge	r14,r15,r6,r7,0x55555555,1

	mr	r22,r15			# plane4
	mr	r23,r14			# plane5
	mr	r24,r8			# plane6
	mr	r25,r9			# plane7


	addi	r3,r3,32
	addi	r5,r5,32
	mr	r26,r4			# save output address
	addi	r4,r4,4			# skip 32 pixels on output

	subi	r29,r29,1
	cmpwi	r29,0
	bne+	.next2

	add	r4,r4,r27		# skip extra bytes at rowend
	mr	r29,r28
.next2:

	cmplw	r3,r30
	bge	final_case


main_loop:
	lwz	r6,0(r3)		# compare next 32 pixels
	lwz	r7,0(r5)
	cmpw	r6,r7
	bne	main_case
	lwz	r6,4(r3)
	lwz	r7,4(r5)
	cmpw	r6,r7
	bne	main_case
	lwz	r6,8(r3)
	lwz	r7,8(r5)
	cmpw	r6,r7
	bne	main_case
	lwz	r6,12(r3)
	lwz	r7,12(r5)
	cmpw	r6,r7
	bne	main_case
	lwz	r6,16(r3)
	lwz	r7,16(r5)
	cmpw	r6,r7
	bne	main_case
	lwz	r6,20(r3)
	lwz	r7,20(r5)
	cmpw	r6,r7
	bne	main_case
	lwz	r6,24(r3)
	lwz	r7,24(r5)
	cmpw	r6,r7
	bne	main_case
	lwz	r6,28(r3)
	lwz	r7,28(r5)
	cmpw	r6,r7
	bne	main_case

	addi	r4,r4,4			# skip 32 pixels on output
	addi	r3,r3,32
	addi	r5,r5,32

	subi	r29,r29,1
	cmpwi	r29,0
	bne+	.next3

	add	r4,r4,r27		# skip extra bytes at rowend
	mr	r29,r28
.next3:

	cmplw	r3,r30
	blt	main_loop
	b	final_case		# exit if no more changes found


main_case:

	lwz	r9,0(r3)
	lwz	r11,4(r3)
	lwz	r8,8(r3)
	lwz	r10,12(r3)
	lwz	r14,2(r3)
	lwz	r15,10(r3)
	lwz	r16,6(r3)
	lwz	r17,14(r3)

	stw	r9,0(r5)
	stw	r11,4(r5)
	stw	r8,8(r5)
	stw	r10,12(r5)

	lwz	r6,16(r3)
	rlwimi	r9,r6,16,16,31
	rlwimi	r14,r6,0,16,31
	lwz	r6,20(r3)
	rlwimi	r11,r6,16,16,31
	rlwimi	r16,r6,0,16,31
	lwz	r6,24(r3)
	rlwimi	r8,r6,16,16,31
	rlwimi	r15,r6,0,16,31
	lwz	r6,28(r3)
	rlwimi	r10,r6,16,16,31
	rlwimi	r17,r6,0,16,31

	sth	r9,16(r5)
	sth	r8,24(r5)
	sth	r11,20(r5)
	sth	r10,28(r5)
	sth	r14,18(r5)
	sth	r15,26(r5)
	sth	r16,22(r5)
	sth	r17,30(r5)

	sub	r26,r26,r12
	stwux	r18,r26,r12		# store plane0 (r26 += plsiz)
	merge	r9,r8,r6,r7,0x00ff00ff,8
	merge	r11,r10,r6,r7,0x00ff00ff,8

	stwux	r19,r26,r12		# store plane1 (r26 += plsiz)
	merge	r9,r11,r6,r7,0x0f0f0f0f,4
	merge	r8,r10,r6,r7,0x0f0f0f0f,4

	stwux	r20,r26,r12		# store plane2 (r26 += plsiz)
	merge	r14,r15,r6,r7,0x00ff00ff,8
	merge	r16,r17,r6,r7,0x00ff00ff,8

	stwux	r21,r26,r12		# store plane3 (r26 += plsiz)
	merge	r14,r16,r6,r7,0x0f0f0f0f,4
	merge	r15,r17,r6,r7,0x0f0f0f0f,4

	stwux	r22,r26,r12		# store plane4 (r26 += plsiz)
	merge	r11,r16,r6,r7,0x33333333,2
	merge	r10,r17,r6,r7,0x33333333,2

	stwux	r23,r26,r12		# store plane5 (r26 += plsiz)
	merge	r11,r10,r6,r7,0x55555555,1
	merge	r16,r17,r6,r7,0x55555555,1

	mr	r18,r17			# plane0
	mr	r19,r16			# plane1
	mr	r20,r10			# plane2
	mr	r21,r11			# plane3

	stwux	r24,r26,r12		# store plane6 (r26 += plsiz)
	merge	r9,r14,r6,r7,0x33333333,2
	merge	r8,r15,r6,r7,0x33333333,2

	stwux	r25,r26,r12		# store plane7 (r26 += plsiz)
	merge	r9,r8,r6,r7,0x55555555,1
	merge	r14,r15,r6,r7,0x55555555,1

	mr	r22,r15			# plane4
	mr	r23,r14			# plane5
	mr	r24,r8			# plane6
	mr	r25,r9			# plane7

	addi	r3,r3,32
	addi	r5,r5,32

	mr	r26,r4			# save output address
	addi	r4,r4,4			# skip 32 pixels on output

	subi	r29,r29,1
	cmpwi	r29,0
	bne+	.next4

	add	r4,r4,r27		# skip extra bytes at rowend
	mr	r29,r28
.next4:
	cmplw	r3,r30
	blt	main_loop



final_case:
	sub	r26,r26,r12
	stwux	r18,r26,r12		# store plane0 (r26 += plsiz)
	stwux	r19,r26,r12		# store plane1 (r26 += plsiz)
	stwux	r20,r26,r12		# store plane2 (r26 += plsiz)
	stwux	r21,r26,r12		# store plane3 (r26 += plsiz)
	stwux	r22,r26,r12		# store plane4 (r26 += plsiz)
	stwux	r23,r26,r12		# store plane5 (r26 += plsiz)
	stwux	r24,r26,r12		# store plane6 (r26 += plsiz)
	stwux	r25,r26,r12		# store plane7 (r26 += plsiz)

exit:
	lmw	r14,4(r1)		# restore non-volatile registers
	addi	r1,r1,80
	blr
