**
**	asm.a
**
**	Various stuff coded in (Devpac 3) assembler

** -------------------------------------------------------------------------


** Dummy function. Useful for placing breakpoints in C code.
** (FIXME: remove the dummy function when the rest is working.)

	SECTION CODE

	XDEF	_dummy
_dummy	rts


** -------------------------------------------------------------------------


** Raw keycode message handling

	SECTION CODE

	;C stub:

	XDEF _rawKey

_rawKey 	;void rawKey(struct IntuiMessage *)

		move.l	a1,-(a7)
		move.l	8(a7),a1
		bsr	rawKey
		move.l	(a7)+,a1
		rts


	INCLUDE "keys.a"


** -------------------------------------------------------------------------


** Screen updating routines

	SECTION CODE

	;C stubs:

	XDEF	_softScr_Recalc

_softScr_Recalc ;void softScr_Recalc(void)

		movem.l d0-d7/a0-a6,-(a7)
		bsr	softScr_Recalc
		movem.l (a7)+,d0-d7/a0-a6
		rts


	XDEF	_softScr_Redraw

_softScr_Redraw ;void softScr_Redraw(void)

		movem.l d0-d7/a0-a6,-(a7)
		bsr	softScr_Redraw
		movem.l (a7)+,d0-d7/a0-a6
		rts


	XDEF	_softScr_Update

_softScr_Update ;void softScr_Update(void)

		movem.l d0-d7/a0-a6,-(a7)
		bsr	softScr_Update
		movem.l (a7)+,d0-d7/a0-a6
		rts


	INCLUDE "screen.a"


** -------------------------------------------------------------------------


** Interrupt server routines:


** Interrupt control structure offsets
**
** Make sure they match the C struct 'intControl' defined in init.c !

	RSRESET
INTC_Z80_Ctrl		rs.l 1	;Pointer to Z80 control structure
INTC_frozen		rs.w 1	;Nonzero if emulation is frozen
INTC_INTperiod		rs.w 1	;INT period, in VERTB:s. 0 = off.
INTC_INTcount		rs.w 1	;Internal counter
INTC_UPDtype		rs.w 1	;Type of update to perform
INTC_UPDperiod		rs.w 1	;Screen update period. 0 = off.
INTC_UPDcount		rs.w 1	;Internal counter
INTC_FLASHstate 	rs.w 1	;Flash state, nonzero for inverted.
INTC_FLASHperiod	rs.w 1	;Flash period, 25 for 50 Hz VERTB.
INTC_FLASHcount 	rs.w 1	;Internal counter

	;Update types are:
	;	-1	No update (actually, any negative value).
	;	0	Update only changed portions of the screen.
	;	1	Complete recalculation and redrawing of bitplanes
	;	2	Bitplanes redrawn using cached attribute masks
	;	3	Switch to type -1 and signal the control process.
	;Types 1 and 2 reset the INTC_UPDtype field to 0 after completing
	;the update. Type -1 stays off until changed from the outside.
	;Type 3 is for verifying that no update is currently in progress.



** Vertical Blanking Server
**
** D0,D1 scratch.
** See note on A0 if you set priority >= 10, otherwise A0 scratch.
** A1 pointer to data area (specified by is_Data).
** A5 pointer to interrupt code (scratch). A6 scratch.

	SECTION CODE

	XDEF _VBServer

	XREF Z80_INTreq
	XREF _updateSig
	XREF _ctrlTaskPtr

_VBServer
	;Proceed only if emulation is not frozen:

		tst.w	INTC_frozen(a1)
		bne	.vertb_end

	;Handle the maskable interrupt:

		move.w	INTC_INTcount(a1),d0
		subq.w	#1,d0
		bne.s	.no_signal

		move.w	INTC_INTperiod(a1),d0	;set count = period
		beq.s	.INT_off	;pretend nothing happened if INT off

		move.l	INTC_Z80_Ctrl(a1),a0	;get control struct address
		jsr	Z80_INTreq		;No registers are affected.

.no_signal	move.w	d0,INTC_INTcount(a1)
.INT_off

	;Then the state of the flash attributes:

		move.w	INTC_FLASHcount(a1),d0
		subq.w	#1,d0
		bne.s	.no_flash

		move.w	INTC_FLASHperiod(a1),d0 ;set count = period
		beq.s	.flash_off	;flash is off if period is zero

		move.w	INTC_FLASHstate(a1),d1	;get old state
		seq	d1	;$FFFF if zero, $0000 if nonzero.
		ext.w	d1
		move.w	d1,INTC_FLASHstate(a1)	;store new state

.no_flash	move.w	d0,INTC_FLASHcount(a1)
.flash_off

	;Then the screen updating:

		move.w	INTC_UPDcount(a1),d0
		subq.w	#1,d0
		bne.s	.no_update

		move.w	INTC_UPDperiod(a1),d0	;set count = period
		beq.s	.update_off	;skip the rest if period is zero

		movem.l d0/d2-d7/a0-a5,-(SP)
		move.w	INTC_FLASHstate(a1),d0	;wanted flash state in d0
		move.w	INTC_UPDtype(a1),d1
		bmi.s	.upd_skip	;no update if type < 0
		beq.s	.upd_normal	;normal update if type = 0
		cmpi.w	#1,d1
		beq.s	.upd_recalc	;recalc if type = 1
		cmpi.w	#2,d1
		beq.s	.upd_redraw	;redraw if type = 2
		cmpi.w	#3,d1
		bne.s	.upd_skip	;skip if type > 3

		;type 3, switch off and signal:
		move.w	#-1,INTC_UPDtype(a1)	;set type to -1
		move.l	_updateSig,d0
		move.l	_ctrlTaskPtr,a1
		move.l	4.w,a6
		jsr	_LVOSignal(a6)	;signal that updating is off
		bra.s	.upd_skip

.upd_redraw	clr.w	INTC_UPDtype(a1)	;reset type
		bsr	softScr_Redraw
		bra.s	.upd_skip

.upd_recalc	clr.w	INTC_UPDtype(a1)	;reset type
		bsr	softScr_Recalc
		bra.s	.upd_skip

.upd_normal	bsr	softScr_Update
.upd_skip
		movem.l (SP)+,d0/d2-d7/a0-a5

.no_update	move.w	d0,INTC_UPDcount(a1)
.update_off

	;Return from server:

.vertb_end	moveq.l #0,d0	;Set Z - server chain continue
		rts


** -------------------------------------------------------------------------


** The code for the separate task running the Z80 emulator:
**
** Can also simply be called as a subroutine, from assembler or C,
** in which case the returned value (in d0) is nonzero upon error and
** zero otherwise. The C prototype is 'int z80task(void)'.
**   The control structure pointed to by _Zctrl must be initialised
** before activating this code.
**

	SECTION DATA

_warmStart	dc.w	0	;nonzero to skip Z80_Coldstart call
_taskLoop	dc.w	0	;while nonzero, the task will loop

	XDEF	_warmStart
	XDEF	_taskLoop

	SECTION CODE

	XDEF	z80task
	XDEF	_z80task

	XREF	_resumeSig
	XREF	_Zctrl
	XREF	_ackSig
	XREF	_ctrlTaskPtr
	XREF	_z80TaskPtr

	INCLUDE "exec/exec.i"
	INCLUDE "exec/exec_lib.i"


	INCLUDE "Z80_struct.i"

_z80task
z80task 	movem.l a0/a1/a6/d1,-(a7)
		move.l	4.w,a6

	;Get the 'resume' signal

		moveq	#-1,d0
		jsr	_LVOAllocSignal(a6)
		moveq	#-1,d1
		cmp.l	d1,d0
		bne	.sig_ok
		bsr	z80task_err	;wait until allowed to exit
		moveq	#-1,d0
		bra	.exit

.sig_ok 	moveq	#1,d1
		asl.l	d0,d1
		move.l	d1,_resumeSig	;create signal mask


	;The initial call can do warm- or coldstart

		move.l	_Zctrl,a0
		tst.w	_warmStart	;nonzero for warmstart
		beq.s	.cold
		jsr	Z80_Continue
		bra.s	.loop
.cold		jsr	Z80_Coldstart


	;The exit/resume loop

.loop		;acknowledge the exit and synchronize
		bsr	z80task_sync

		;exit if break
		tst.l	d0
		bne.s	.exit_ok

		;else resume emulation
		move.l	_Zctrl,a0
		jsr	Z80_Continue

		bra.s	.loop

.exit_ok	moveq	#0,d0

.exit		clr.l	_z80TaskPtr	;clear pointer on self-termination
		movem.l (a7)+,a0/a1/a6/d1
		rts



	;This subroutine behaves as if the emulation was running,
	;but actually only sends ackSig and waits for signals,
	;looping until a break is received.

z80task_err
.loop		bsr	z80task_sync
		tst.l	d0
		beq.s	.loop
		rts



	;This subroutine sends an ackSig, waits for a resume or break
	;and then returns, with d0 nonzero if a break was received.
	;It assumes that a6 points to ExecBase, and d0/d1,a0/a1 are
	;free as scratch registers.

z80task_sync
		;Send acknowledge signal
		move.l	_ctrlTaskPtr,a1
		move.l	_ackSig,d0
		jsr	_LVOSignal(a6)

		;Wait for resume or break signal
		move.l	_resumeSig,d0
		ori.l	#SIGBREAKF_CTRL_C,d0
		jsr	_LVOWait(a6)

		;Make d0 nonzero if break, zero otherwise
		andi.l	#SIGBREAKF_CTRL_C,d0

		rts


** -------------------------------------------------------------------------


** User memory exception handler
**
** A test version: Flashes border and stores passed information.
** Returns <value = same, write = true> if the exception number was 17,
** and otherwise <value = same, write = false>.

	SECTION DATA

	;Storage accessible from C:

	XDEF _UsrMemH_ExNum
	XDEF _UsrMemH_Addr
	XDEF _UsrMemH_Value

_UsrMemH_ExNum	dc.l	0
_UsrMemH_Addr	dc.w	0
_UsrMemH_Value	dc.b	0



	EVEN

	SECTION CODE

	;d0 contains the exception number (longword, range -128 to 127).
	;d1 contains the value (longword, range -128 to 127).
	;d2 contains the Z80 address (longword, range -32768 to 32767).
	;a0 is scratch (address of user handler).
	;All other registers must be protected before used.

	;Handler return values:
	; d0 (longword) nonzero if value should be written, zero if not.
	; d1 (low byte) contains the value.
	; d2 and a0 are ignored.


	XDEF _UsrMemHandler

_UsrMemHandler
		move.l	d0,_UsrMemH_ExNum
		move.b	d1,_UsrMemH_Value
		move.w	d2,_UsrMemH_Addr

		move.w	#$F0F,$dff180.l ;set background colour to magenta

		moveq	#17,d2	;d2 can be used as scratch
		cmp.w	d2,d0
		bne.s	.ROM	;all attributes but 17 are ROM

		moveq	#1,d0	;signal 'write'
		rts

.ROM		moveq	#0,d0	;signal 'do not write'
		rts


** -------------------------------------------------------------------------

