;Interrupt based clock, v1, (C) George Chirtoaca, August 2007.

	DEVICE ZXSPECTRUM48

;253 * 256 = 64768 => interrupt handler is at 64768 + 253 = 65021.
;vector table is at 252 * 256 = 64512 to 64769
INT_VEC			equ 253				;interrupt vector value
SCR_OFF			equ 16384 + 32 - 8	;screen offset address for display

FNT_TBL_ADDR	equ 23606			;font table pointer system variable
ROM_INT_HANDLER	equ 056
TICS_PER_SEC	equ 50				;number of tics per second


;The setup part
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	org INT_VEC*256 + INT_VEC - (EndLdr - Start)

Start:
	;create vector table
	;257 values are required, cos the interrupt handler address is read
	;from 2 consecutive values from interval (INT_VEC-1)*256 to (INT_VEC-1)*256 + 255.
	ld	hl, (INT_VEC-1) << 8
	ld	a, INT_VEC
	ld	b, 0
FillIntTbl:
	ld	(hl), a
	inc hl
	djnz FillIntTbl
	ld	(hl), a

	;move int routine to proper address (INT_VEC*256) + INT_VEC
	call $52
OverHead:
	dec sp
	dec sp
	pop hl
	ld bc, StartIntRoutine - OverHead
	add hl, bc

	ld de, INT_VEC*256 + INT_VEC
	ld bc, EndIntRoutine - IntRoutine
	ldir

	;set interrupt
	di
	ld a, INT_VEC - 1
	ld i, a
	im	2
	ei

Return:
	ret
EndLdr:



;The interrupt handler part
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

StartIntRoutine:

	org INT_VEC*256 + INT_VEC
IntRoutine:

	di
	push af
	push hl
	push bc
	push de
	push ix

	ld a, (TickCount)
	inc a
	cp TICS_PER_SEC
	jr nz, Clean
	
	call 	Payload

	xor a
Clean:
	ld (TickCount), a
	pop ix
	pop de
	pop bc
	pop hl
	pop af
	jp ROM_INT_HANDLER		;this will re-enable interupts

Payload:
	ld a, (SecCount)
	inc a
	ld (SecCount), a
	cp 60
	jr nz, Print
	xor a
	ld (SecCount), a

	ld a, (MinCount)
	inc a
	ld (MinCount), a
	cp 60
	jr nz, Print
	xor a
	ld (MinCount), a

	ld a, (HourCount)
	inc a
	ld (HourCount), a
	cp 24
	jr nz, Print
	xor a
	ld (HourCount), a

Print:
	ld a, (HourCount)
	ld ix, SCR_OFF
	call N2DEC
	ld a, ':'
	ld ix, SCR_OFF + 2
	call PrintChar
	ld a, (MinCount)
	ld ix, SCR_OFF + 3
	call N2DEC
	ld a, ':'
	ld ix, SCR_OFF + 5
	call PrintChar
	ld a, (SecCount)
	ld ix, SCR_OFF + 6
	call N2DEC
	ret

;IN: IX = address, A = char
PrintChar:
	;find font address
	ld de, (FNT_TBL_ADDR)
	inc d
	sub ' '
	ld h, 0
	ld l, a
	add hl, hl
	add hl, hl
	add hl, hl
	add hl, de
	ld  de, 256
	ld  b, 8

PrintLine:
	ld a, (hl)
	ld (ix), a
	add ix, de
	inc hl
	djnz PrintLine

	ret


;IN : A = number
;OUT: DE = 2 digit representation of A
N2DEC:
	ld l, a
	ld h, 0
	ld bc, -10
	call DigitLoop
	ld e, a
	ld bc, -1
	call DigitLoop
	ld d, a

PrintNo:
	ld a, e
	push de
	call PrintChar
	pop de
	ld a, d
	ld  bc, -256*8 + 1
	add ix, bc
	call PrintChar
	ret


DigitLoop:
	ld	a, '0' - 1
DivNrLoop:
	inc	a			;increase reminder
	add	hl, bc		;substract divizor
	jr	c, DivNrLoop	;still dividing?
	sbc	hl, bc		;nope, restore
	ret

TickCount	defb 0
SecCount	defb 0
MinCount	defb 0
HourCount	defb 0
EndIntRoutine:

	savebin "clock.bin", Start, EndIntRoutine - Start