;===================================================================================;
;                                 CHUNKY8 EMULATOR
;===================================================================================;
;This c2p routine is also used in the rtgmaster library, it's not too bad for
;a CPU only routine.

CHUNKYMEM =	MEM_CLEAR	;<- Fast memory.

	INCDIR	"INCLUDES:"
	INCLUDE	"exec/libraries.i"
	INCLUDE	"exec/initializers.i"
	INCLUDE	"exec/resident.i"
	INCLUDE	"exec/exec_lib.i"
	INCLUDE	"hardware/custom.i"
	INCLUDE	"games/games.i"
	INCLUDE	"games/games_lib.i"
	INCLUDE	"games/debug.i"

CALL	MACRO
	jsr	_LVO\1(a6)
	ENDM

;===================================================================================;
;                                  MONITOR DRIVER
;===================================================================================;

    STRUCTURE	ChunkyBase,LIB_SIZE
	ULONG	CHK_SegList
	LABEL	CHKBase_SIZEOF

	SECTION	"Chunky8",CODE

LibPriority = 	0

CleanExit:		;If the user tries to run the library, we
	moveq	#$00,d0	;don't want to crash...
	rts

InitDescrip:
	dc.w	RTC_MATCHWORD	;UWORD rt_matchword
	dc.l	InitDescrip,EndCode	;APTR  rt_matchtag, rt_endskip
	dc.b	RTF_AUTOINIT,GMSVersion	;UBYTE rt_flags, rt_version
	dc.b	NT_LIBRARY,LibPriority	;UBYTE rt_type, rt_pri
	dc.l	LibName,IDString,Init	;APTR  rt_name, rt_idstring, rt_init

LibName:
	dc.b	"000.CPU1",0
	even
	dc.b	"$VER: "
IDString:
	dc.b	"Chunky 8 Emulator V0.6",10,0
	even

Init:	dc.l	CHKBase_SIZEOF,FunctionTable,DataTable,InitRoutine

FunctionTable:
FT:	dc.w	-1,Open-FT,Close-FT,Expunge-FT,Null-FT
	dc.w	LIB_emuRemapFunctions-FT
	dc.w	LIB_emuInitRefresh-FT
	dc.w	LIB_emuFreeRefresh-FT
	dc.w	LIB_emuRefreshScreen-FT
	dc.w	-1

DataTable:
	INITBYTE LN_TYPE,NT_LIBRARY
	INITLONG LN_NAME,LibName
	INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
	INITWORD LIB_VERSION,GMSVersion
	INITWORD LIB_REVISION,GMSRevision
	INITLONG LIB_IDSTRING,IDString
	dc.l	0
	even

;===================================================================================;
;                              INITIALISATION ROUTINE
;===================================================================================;
;Requires: a0 = SegList
;	   d0 = Library Base.

InitRoutine:
	MOVEM.L	D1-D7/A0-A6,-(SP)	;SP = Save registers.
	move.l	d0,a5	;a5 = Store pointer to our base.
	move.l	d0,CHKBase	;ma = Save pointer to our base.
	move.l	a0,CHK_SegList(a5)	;a5 = Save pointer to SegList.
	move.l	CHKBase(pc),d0	;d0 = Return library pointer.
.error	MOVEM.L	(SP)+,D1-D7/A0-A6	;SP = Return registers.
	rts

;===================================================================================;
;                                   OPEN LIBRARY
;===================================================================================;

Open:	addq.w	#1,LIB_OPENCNT(a6)	;Increment lib count.
	bclr	#LIBB_DELEXP,LIB_FLAGS(a6)
	move.l	a6,d0	;Return library base.
	rts

;===================================================================================;
;                                  CLOSE LIBRARY
;===================================================================================;

Close:	moveq	#$00,d0	;This is called whenever someone closes
	subq.w	#1,LIB_OPENCNT(a6)	;our library.
	bne.s	.Exit
	btst	#LIBB_DELEXP,LIB_FLAGS(a6)
	beq.s	.Exit
	bsr.s	Expunge
.Exit	rts

;===================================================================================;
;                               EXPUNGE THE LIBRARY
;===================================================================================;

Expunge:
	MOVEM.L	D1-D7/A0-A6,-(SP)	;SP = Save all registers.
	move.l	a6,a5	;a5 = Our library base.
	tst.w	LIB_OPENCNT(a5)	;a5 = Do any programs have us open?
	beq.s	.expunge	;>> = No, so it's safe to expunge ourselves.
	bset	#LIBB_DELEXP,LIB_FLAGS(a5)
	MOVEM.L	(SP)+,D1-D7/A0-A6	;SP = Return all registers.
	moveq	#$00,d0
	rts

.expunge
	move.l	($4).w,a6	;a6 = ExecBase.
	move.l	CHK_SegList(a5),d2	;d2 = Our segment list.
	move.l	a5,a1	;a1 = Our library base.
	CALL	Remove	;>> = Remove it.
	move.l	a5,a1	;a1 = Our library base.
	moveq	#$00,d0	;d0 = 00
	move.w	LIB_NEGSIZE(a5),d0	;d0 = LIB_NEGSIZE(base)
	sub.l	d0,a1	;a1 = (base)-LIB_NEGSIZE
	add.w	LIB_POSSIZE(a5),d0	;d0 = (LIB_NEGSIZE)+LIB_POSSIZE
	CALL	FreeMem	;>> = Free the memory.
	move.l	d2,d0	;d0 = Pointer to segment list.
	MOVEM.L	(SP)+,D1-D7/A0-A6	;SP = Return all registers, d0 = seglist.
	rts

;===================================================================================;
;                                    DO NOTHING
;===================================================================================;

Null:	moveq	#$00,d0
	rts

;===================================================================================;
;                                FUNCTION REMAPPING
;===================================================================================;
;Function: Ignore this function, we will only use it to grab the GMSBase.
;Requires: d0 = GamesBase.
;	   a6 = Chunky Base.
;Returns:  Nothing.

LIB_emuRemapFunctions:
	move.l	d0,GMSBase	;ma = Save the GMSBase.
	rts

;===================================================================================;
;                             INITIALISE C2P ALGORITHM
;===================================================================================;
;Function: Initialise the C2P algorithm for emuRefreshScreen().  Note how if the
;	   screen is double buffered, we do not allocate a second chunky buffer.
;	   The reason is because a second planar display buffer already exists, so
;	   having a second chunky buffer has no benefit.
;Requires: a0 = GameScreen
;	   a6 = Chunky Base.
;Returns:  d0 = ErrorCode.

LIB_emuInitRefresh:
	MOVEM.L	D1-D7/A0-A6,-(SP)	;SP = Return used registers.
	move.l	GMSBase(pc),a6	;a6 = GMSBase.

	;Move the planar screen displays (allocated in AddScreen()) to
	;GS_EMemPtrX.

	move.l	GS_MemPtr1(a0),GS_EMemPtr1(a0)
	move.l	GS_MemPtr2(a0),GS_EMemPtr2(a0)
	move.l	GS_MemPtr3(a0),GS_EMemPtr3(a0)

	;Allocate the chunky memory, place it in GS_MemPtrX fields and store
	;the pointers in GS_EFreeX fields to free it later.

	move.w	GS_PicWidth(a0),d0	;d0 = PicWidth
	mulu	GS_PicHeight(a0),d0	;d0 = (PicWidth)*PicHeight
	moveq	#CHUNKYMEM,d1	;d1 = Memory Type (see definition).
	CALL	AllocMemBlock	;>> = Go get the chunky memory.
	move.l	d0,GS_EFree1(a0)	;a4 = Store chunky buffer for freemem.
	move.l	d0,GS_MemPtr1(a0)	;a0 = Store chunky buffer #1.
	beq.s	.error	;>> = Memory allocation error.

	move.l	GS_Attrib(a0),d2	;d2 = Screen attributes.
	and.l	#DBLBUFFER,d2	;d2 = Double buffer?
	beq.s	.done	;>> = No, finished.
	move.l	d0,GS_MemPtr2(a0)	;a0 = Store chunky buffer #1.

.done	MOVEM.L	(SP)+,D1-D7/A0-A6	;SP = Return used registers.
	moveq	#ERR_SUCCESS,d0
	rts

.error	MOVEM.L	(SP)+,D1-D7/A0-A6	;SP = Return used registers.
	moveq	#ERR_FAILED,d0
	rts

;===================================================================================;
;                            DE-INITIALISE C2P ALGORITHM
;===================================================================================;
;Function: Free any allocations we made for the C2P routine.
;Requires: a0 = GameScreen
;	   a6 = Chunky Base.
;Returns:  Nothing.

LIB_emuFreeRefresh:
	MOVEM.L	D0/A6,-(SP)	;SP = Save used registers.
	move.l	GMSBase(pc),a6	;a6 = GMSBase.
	move.l	GS_EFree1(a0),d0	;d0 = Screen memory 1 (C2P)
	CALL	FreeMemBlock	;>> = Free screen memory.
	move.l	GS_EFree2(a0),d0	;d0 = Screen memory 2 (C2P)
	CALL	FreeMemBlock	;>> = Free screen memory.
	move.l	GS_EFree3(a0),d0	;d0 = Screen memory 3 (C2P)
	CALL	FreeMemBlock	;>> = Free screen memory.
	MOVEM.L	(SP)+,D0/A6	;SP = Return used registers.
	rts

;===================================================================================;
;                              C2P CONVERSION ROUTINE
;===================================================================================;
;Function: Do the C2P process.
;Requires: a0 = GameScreen
;	   a6 = Chunky Base.
;Returns:  Nothing.

LIB_emuRefreshScreen:
	MOVEM.L	D0-D7/A0-A6,-(SP)	;SP = Save used registers.
	moveq	#$00,d0	;d0 = 00.
	moveq	#$00,d1	;d1 = 00.
	move.w	GS_PicWidth(a0),d0	;d0 = Width.
	move.w	GS_PicHeight(a0),d1	;d1 = Height.
	move.l	d0,d2	;d2 = ByteWidth
	lsr.l	#3,d2	;d2 = (ByteWidth)/8 [planar]
	move.l	d2,d3	;d3 = Line modulo.
	mulu	GS_PicHeight(a0),d2	;d2 = (ByteWidth/8)*Height

	move.l	GS_Attrib(a0),d7	;d7 = GameScreen attributes
	and.l	#DBLBUFFER|TPLBUFFER,d7	;d7 = Double or triple buffered?
	bne.s	.doubleandtriple	:>> = Yes.
.single	move.l	GS_EMemPtr1(a0),a1	;a1 = Pointer to planar display.
	move.l	GS_MemPtr1(a0),a0	;a0 = Pointer to chunky buffer.
	bra.s	.process

.doubleandtriple
	move.l	GS_EMemPtr2(a0),a1	;a1 = Pointer to planar display.
	move.l	GS_MemPtr2(a0),a0	;a0 = Pointer to chunky buffer.

	;a0 = Chunky buffer.
	;a1 = First bitplane.
	;d0 = Width in pixels, multiple of 32.
	;d1 = Height in pixels (even).
	;d2 = Bitplane modulo.
	;d3 = Line modulo. Modulo from start of one line to start of next (linemod)

.process
	move.l	d2,a5	;a5 = Plane Size.
	lsl.l	#3,d2	;d2 = (PlaneSize)*8
	sub.l	a5,d2	;d2 = (PlaneSize*8)-PlaneSize
	subq.l	#2,d2	;d2 = --2
	move.l	d2,a6	;a6 = (PlaneSize*8-PlaneSize-2)
	lsr.w	#4,d0	;d0 = Width/32
	ext.l	d0	;d0 = Make long.
	move.l	d0,d4	;d4 = Width/32
	subq.l	#1,d4	;d4 = (Width/32)-1
	move.l	d4,-(SP)	;SP = Save it.
	add.l	d0,d0	;d0 = (Width/32)*2
	sub.l	d0,d3	;d3 = (LineMod)-Width/16
	sub.l	a6,d3	;d3 =
	move.l	d3,-(SP)	;SP =
	move.w	d1,d7	;d7 = Height
	subq.w	#1,d7	;d7 = (Height)-1 [for loop]
	movea.l	#$f0f0f0f0,a2	;a2 = $F0F0F0F0
	movea.l	#$cccccccc,a3	;a3 = $CCCCCCCC
	movea.l	#$aaaa5555,a4	;a4 = $AAAA5555
	move.l	a2,d6	;d6 = $F0F0F0F0
	swap	d7	;d7 = (loop)<<16
	move.w	(6,SP),d7
	move.l	(a0)+,d0
	move.l	(a0)+,d1
	move.l	(a0)+,d2
	move.l	(a0)+,d3
	move.l	d0,d4
	and.l	d6,d0
	eor.l	d0,d4
	lsl.l	#4,d4
	bra	.same

.outer	swap	d7
	move.w	(6,sp),d7
	move.w	d5,(a1)
	adda.l	a5,a1
	swap	d5
	move.w	d5,(a1)
	adda.l	(sp),a1
	movem.l	(a0)+,d0-d3
	move.l	d0,d5
	swap	d0
	rol.l	#8,d2
	move.w	d0,d4
	move.b	d2,d4
	swap	d4
	swap	d2
	move.w	d2,d4
	move.b	d0,d4
	ror.w	#8,d4
	move.b	d2,d5
	swap	d5
	swap	d2
	move.w	d2,d5
	swap	d0
	move.b	d0,d5
	ror.w	#8,d5
	move.l	d1,d2
	swap	d1
	rol.l	#8,d3
	move.w	d1,d0
	move.b	d3,d0
	swap	d0
	swap	d3
	move.w	d3,d0
	move.b	d1,d0
	ror.w	#8,d0
	move.b	d3,d2
	swap	d2
	swap	d3
	move.w	d3,d2
	swap	d1
	move.b	d1,d2
	ror.w	#8,d2
	move.l	d2,d3
	move.l	d0,d2
	move.l	d4,d0
	move.l	d5,d1
	move.l	d0,d4
	and.l	d6,d0
	eor.l	d0,d4
	lsl.l	#4,d4
	bra.s	.same

.inner	move.w	d5,(a1)
	adda.l	a5,a1
	swap	d5
	move.w	d5,(a1)
	suba.l	a6,a1
	move.l	(a0)+,d0
	move.l	d0,d5
	move.l	(a0)+,d1
	swap	d0
	move.l	(a0)+,d2
	rol.l	#8,d2
	move.w	d0,d4
	move.b	d2,d4
	swap	d4
	swap	d2
	move.w	d2,d4
	move.b	d0,d4
	ror.w	#8,d4
	move.b	d2,d5
	swap	d5
	swap	d2
	move.w	d2,d5
	swap	d0
	move.b	d0,d5
	ror.w	#8,d5
	move.l	d1,d2
	swap	d1
	move.l	(a0)+,d3
	rol.l	#8,d3
	move.w	d1,d0
	move.b	d3,d0
	swap	d0
	swap	d3
	move.w	d3,d0
	move.b	d1,d0
	ror.w	#8,d0
	move.b	d3,d2
	swap	d2
	swap	d3
	move.w	d3,d2
	swap	d1
	move.b	d1,d2
	ror.w	#8,d2
	move.l	d2,d3
	move.l	d0,d2
	move.l	d4,d0
	move.l	d5,d1
	and.l	d6,d0
	eor.l	d0,d4
	lsl.l	#4,d4

.same	move.l	d2,d5
	and.l	d6,d5
	eor.l	d5,d2
	lsr.l	#4,d5
	or.l	d5,d0
	or.l	d4,d2
	move.l	d1,d4
	and.l	d6,d1
	eor.l	d1,d4
	move.l	d3,d5
	and.l	d6,d5
	eor.l	d5,d3
	lsr.l	#4,d5
	lsl.l	#4,d4
	or.l	d5,d1
	or.l	d4,d3
	move.l	a3,d6
	move.l	d2,d4
	and.l	d6,d2
	eor.l	d2,d4
	move.l	d3,d5
	and.l	d6,d5
	eor.l	d5,d3
	lsl.l	#2,d4
	or.l	d4,d3
	move.l	a4,d6
	move.l	d3,d4
	and.l	d6,d3
	eor.l	d3,d4
	lsr.w	#1,d4
	swap	d4
	add.w	d4,d4
	or.l	d4,d3
	move.w	d3,(a1)
	adda.l	a5,a1
	lsr.l	#2,d5
	or.l	d5,d2
	move.l	d2,d4
	and.l	d6,d2
	eor.l	d2,d4
	lsr.w	#1,d4
	swap	d3
	move.w	d3,(a1)
	adda.l	a5,a1
	swap	d4
	add.w	d4,d4
	or.l	d4,d2
	move.l	a3,d6
	move.l	d0,d4
	and.l	d6,d0
	eor.l	d0,d4
	move.w	d2,(a1)
	adda.l	a5,a1
	move.l	d1,d5
	and.l	d6,d5
	eor.l	d5,d1
	lsl.l	#2,d4
	or.l	d4,d1
	move.l	a4,d6
	swap	d2
	move.w	d2,(a1)
	adda.l	a5,a1
	move.l	d1,d4
	and.l	d6,d1
	eor.l	d1,d4
	lsr.w	#1,d4
	swap	d4
	add.w	d4,d4
	or.l	d4,d1
	move.w	d1,(a1)
	adda.l	a5,a1
	lsr.l	#2,d5
	or.l	d5,d0
	move.l	d0,d5
	and.l	d6,d0
	eor.l	d0,d5
	swap	d1
	move.w	d1,(a1)
	adda.l	a5,a1
	lsr.w	#1,d5
	swap	d5
	add.w	d5,d5
	or.l	d0,d5
	move.l	a2,d6
	dbra	d7,.inner
	swap	d7
	dbra	d7,.outer
	move.w	d5,(a1)
	adda.l	a5,a1
	swap	d5
	move.w	d5,(a1)
	addq.l	#8,sp
	MOVEM.L	(SP)+,D0-D7/A0-A6	;SP = Return used registers.
	rts

;===================================================================================;
;                                       DATA
;===================================================================================;

GMSBase	dc.l	0
CHKBase dc.l	0

;-----------------------------------------------------------------------------------;
EndCode:
