; -----------------------------------
; scopeclock.asm
;
; Scopeclock controller based on PIC16F690
;
; Dual 8-bit x/y output with blanking
; DCF77 interface
; DS1307 I2C RTC
; 50Hz mains synchronization to reduce flicker
; burn-in reduction
;
; (c) Stephan Asmus 11/2023
; info@sasmus.de
;
; the software or parts of it may be used for private, non-commercial use
; the original author has to be named in such a case, however
;
; Das Programm oder Teile davon dŸrfen fŸr private, nicht-kommerzielle
; Anwendungen weiterverwendet werden.
; Der ursprŸngliche Autor ist dabei zu erwaehnen
; -----------------------------------
; PIC 16F690
; -----------------------------------
; Log:
; 24.11.2023 Start
; 27.11.2023 Watchface working, Chars (Numbers only) working
; 01.12.2023 DCF77 working, Date & signal indication are on screen
; 12.01.2024 blanking, delays for xy amp adaption
; 09.02.2024 50Hz synchronization, scale factors, new chars, mode selection, key check
; 12.02.2024 I2C + RTC working + synchronized, preset load + save
; 15.02.2024 housekeeping & optimization :-)
; 22.02.2024 burn-in reduction, 1st release
; 15.09.2024 add delay to some modes to prevent unwanted additional trigger at zero-crossing of sync signal
; 16.09.2014 correct positioning of beam during blanking
;
; Used Controller: PIC 16F690
; 
; Pins & Ports:
;   Port C:
;   0..7: Data to DAC
;   Port B:
;   4: /DACA_DACB
;   5: /WR & /CS
;	6: I2C - SCL
;	7: I2C - SDA
;	Port A:
;	0: 50Hz sync input
;	1: key
;	2: blanking output
;	3: DCF77 input
;
; see schematic for more details
;
; Fosc=20MHz quartz oscillator

	LIST   P=PIC16F690

	#include <p16f690.inc>

    errorlevel  -1302		;No bank select warnings
    errorlevel  -306		;No page select warnings

	__config (_HS_OSC & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOD_OFF & _IESO_OFF & _FCMEN_OFF)
;----------------------------------------------------------------
;variables
	cblock 0x20
	w_tmp			; used for context saving Register "W"
	status_tmp		; used for context saving Register "Status"
	pclath_tmp		; used for context saving Register "PCLATH"
	pclath_save		; used to save pclath within computed gotos

	d1				;Delay-Variable 1
	d2				;Delay-Variable 2
	d3				;Delay-Variable 3
	
	tmp				;general temp variables
	tmp1
	tmp2
    tmpGIE          ;temp GIE
	tmpi2c			;tmp for i2c routines
    count           ;used in I2C routines

    f0              ;used by conversion routines
	
	sec				;holds current time
	min
	hour			;in 24h format
	hour12			;in 12h format - used within normal watchface routine
	tag_e, tag_z	;day, month, year separated by tens and ones
	mon_e, mon_z
	jahr_e, jahr_z

	dcf0			;holds dcf77 stream from receiver
	dcf1
	dcf2
	dcf3
	dcf4
	dcf5
	bittime			;used to check pulsewith dcf77
	bitcount		;which bit is current (DCF77)
	tmp77, tmp77_1	;tmp variables for DCF77 routines

	dataa			;output to DAC port A=x
	datab			;output to DAC port B=y

	;bresenham line drawing variables
	xstart, ystart	;start and endpoints
	xend, yend
	adx, ady		;absolute deltas
	sdx, sdy		;signum: 2 if negative, 1 if positive, 0 if 0
	pdx, pdy		;parallel step 
	ddx, ddy		;diagonal step
	dslow, dfast	;delta in slow & fast direction
	berror			;bresenham eror variable
	bloop			;loop variable
	btmpx, btmpy	;temp variables for x and y
	btmpx1, btmpy1

	charp, chard	;charpointer, chardata
	offsx, offsy	;offset for chardrawing & watchface
	scx,scy			;scale x & y - scale x times in x & y direction (used for chars)

	nbix, nbitmp	;no burn in - additional delta in x direction
	
	dttmp			;tmp variables for draw_time routine
	dctmp			;tmp variables for draw_char routine

	vmode			;which watch do we want to display (0..4)

	flags, flags1
	tickcounter		;counter to count 50Hz interrupts (used to calculate time)

	eprom_adr		;eeprom Adress tmp
	eprom_dat		;eeprom data tmp
	
	endc
;----------------------------------------------------------------
;constants & definitions
#define dacdat	PORTC	;output port to DAC, 8 bit
#define dacab	PORTB,4	;low=A(x), high=B(y)
#define wrcs	PORTB,5 ;pulse low to take the data
#define SDA		PORTB,7	;I2C Interface
#define SCL		PORTB,6
#define DCF77in	PORTA,3
#define blank	PORTA,2	;blanking output
#define	key1	PORTA,1	;key
#define	sync	PORTA,0	;50Hz sync input
#define SDA_T	TRISB,7	;Tris-Bit for SDA used in I2C routines
#define SCL_T	TRISB,6	;Tris-Bit for SCL

#define signal		flags,0 ;signal dcf77 available
#define sec59		flags,1	;sec59 recognized
#define newtime 	flags,2 ;indicates that new time value was loaded
#define dcf77sync	flags,3	;dcf77 signal valid and synced
#define dcflevel	flags,4	;level of last dcf read (1=high)
#define biterror	flags,5	;set if received bit/signal was wrong
#define divx		flags,6	;set if divide by 2 in x-direction
#define divy		flags,7	;set if divide by 2 in y-direction
#define noblankatstart	flags1,0 	;set if we do not want to blank and delay at 1st point of line drawing
#define keyispressed	flags1,1	;set if key is currently pressed
#define keywaspressed	flags1,2	;set if key was pressed at last check
#define	rtcinitial		flags1,3	;set if RTC ch bit is set or not in 24h mode (typically at 1st start)

;----------------------------------------------------------------
;macro definitions
;----------------------------------------------------------------
;set to Register Bank 0
SET_BANK0 MACRO
	bcf STATUS, RP0
	bcf STATUS, RP1
	ENDM
;set to Register Bank 1
SET_BANK1 MACRO
	bsf	STATUS, RP0
	bcf	STATUS, RP1
	ENDM
;set to Register Bank 2
SET_BANK2 MACRO
	bcf	STATUS, RP0
	bsf	STATUS, RP1
	ENDM
; **********************************************************************
;Program Start
; **********************************************************************
	org 0
	goto    INIT
	
	ORG		0x004           ; interrupt vector location
	movwf	w_tmp          ; save off current W register contents
	swapf	STATUS,W        ; move status register into W register
	clrf	STATUS          ; select Bank 0
	movwf	status_tmp     ; save off contents of STATUS register
	movf	PCLATH,w
	movwf	pclath_tmp
	clrf	PCLATH

	btfss	INTCON,RABIF	;Interrupt on change on port A (RA0)
	goto	ISR_0			;if other then leave
	btfss	sync			;state-change was caused by falling edge of pulse (so port is 1 now)
	goto	IOC_ISR			;hard coded (no call) to save stackspace
ISR_reentry
	bcf		keyispressed	;clear flag
	btfss	key1			;check status of key	(key pressed: port =0=clear)
	bsf		keyispressed	;and set flag if needed
	bcf		INTCON,RABIF	;clear interrupt flag
ISR_0
	movf	pclath_tmp,w
	movwf	PCLATH
	swapf   status_tmp,w     ; retrieve copy of STATUS register
	movwf   STATUS            ; restore pre-isr STATUS register contents
	swapf   w_tmp,f
	swapf   w_tmp,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt

; *********************************************
; Interrupt on change Interrupt handler.
; Port A changed state due to 50Hz sync
; *********************************************
IOC_ISR
	;first check which mode and display corresponding watch
	movf	vmode,w
	xorlw	0x00		;mode 0?
	btfss	STATUS,Z
	goto	modecheck_1
	call	mode_0
	goto	modecheck_end
modecheck_1
	xorlw	0x01^0x00		;mode 1?
	btfss	STATUS,Z
	goto	modecheck_2
	call	mode_1
	goto	modecheck_end
modecheck_2
	xorlw	0x02^0x01		;mode 2?
	btfss	STATUS,Z
	goto	modecheck_3
	call	mode_2
	goto	modecheck_end
modecheck_3
	xorlw	0x03^0x02		;mode 3?
	btfss	STATUS,Z
	goto	modecheck_4
	call	mode_3
	goto	modecheck_end
modecheck_4
	xorlw	0x04^0x03		;mode 4?
	btfss	STATUS,Z
	goto	modecheck_end
	call	mode_4
	goto	modecheck_end
modecheck_end

	;we count seconds and measure time if dcf77 is not available and between full minutes
	incf	tickcounter,f	;counts 50Hz interrupts (every 20ms)
	movlw	d'50'		;1sec over (50 ticks are 1sec)
	xorwf	tickcounter,w
	btfss	STATUS,Z	;if=50 then go on, else end
	goto	IOC_1
	clrf	tickcounter
	incf	sec,f			;inc 1 second
	movlw	d'60'		;already 60sec?
	xorwf	sec,w
	btfss	STATUS,Z
	goto	IOC_1		;no, then nothing else to do
	clrf	sec			;yes, start new minute...
	incf	min,f
	bsf		newtime		;indicate to synchronize with RTC and/or DCF77
	movlw	d'60'		;already 60 mins?
	xorwf	min,w
	btfss	STATUS,Z	
	goto	IOC_1		;no, then nothing else to do
	clrf	min
	incf	hour,f
	movlw	d'24'		;already 24h? 
	xorwf	hour,w
	btfss	STATUS,Z	
	goto	IOC_1		;no, then nothing else to do
	clrf	hour
IOC_1
	;now up to handle dcf77...
	incf	bittime,f		;count time from last leading dcf pulse
	movlw	d'90'
	xorwf	bittime,w
	btfss	STATUS,Z
	goto	check_rise
	clrf	bittime		;count from beginning (have to check this!!!)
	bsf		sec59		;set sec59 indicator if time since last pulse >1,8sec (90*20ms)
	bcf		dcf77sync	;clear flag - if next pulse is dcf pulse 0 then flag is set again
	bcf		signal		;clear flag - if next pulse is dcf pulse 0 then flag is set again
	movf	bitcount,w	;check if 58 bits received - otherwise set errorflag
	xorlw	d'58'
	btfss	STATUS,Z
	bsf		biterror
	
check_rise				;check for rising pulse
	btfsc	dcflevel	;last level=low?	
	goto	check_fall	;no, then check falling pulse
	btfss	DCF77in		;current signal=high?
	goto	check_fall	;no, then check falling pulse
	clrf	bittime		;yes, this is a new pulse
	incf	bitcount,f	;new bit detected...
	bsf		signal		;and we have a signal from dcf receiver
	btfss	sec59		;if last sec was 59...
	goto	check_fall
	bcf		sec59		;clear flag
	clrf	bitcount	;this is bit 0
	call	process_time
	goto	IOC_2		;leave

check_fall
	movf	bitcount,w
	sublw	d'15'		;k-w=w C=0 if W>k; C=1 if W<=k
	btfsc	STATUS,C
	goto	IOC_2		;if <16 then do nothing with this bit
	;do this for bitcount >15....
	btfss	dcflevel	;lastlevel =1?
	goto	IOC_2		;no, then fin
	btfsc	DCF77in		;check current signal
	goto	IOC_2		;if still 1 then end check
	;bittime values
	;new with 50Hz Interrup
	;8=160ms (target 150ms)
	;3=60ms (target 72ms)			*****possibly to be reduced to improve reception of signal (reichelt receiver is on the very low side of DCF77 spec)
	;13=260ms (target 250ms)
	movf	bittime,w
	sublw	d'3'		;k-w=w C=0 if W>k; C=1 if W<=k ***was 11, see comment above***
	btfss	STATUS,C
	goto	check_fall_1
	bsf		biterror		;time <75ms
	goto	IOC_2
check_fall_1
	movf	bittime,w
	sublw	d'13'		;k-w=w C=0 if W>k; C=1 if W<=k
	btfsc	STATUS,C
	goto	check_fall_2
	bsf		biterror		;time>250ms
	goto	IOC_2
check_fall_2
	movlw	d'8'		;<150ms=0; >150ms=1
	subwf	bittime,w	;f-w=w C=0 if W>f; C=1 if W<=f
						;now C contains the current received bit
	; shift C-bit which represents DCF bit into memory for further processing
	; start with dcf bit 16, end with bit 58
	rrf		dcf5,f
	rrf		dcf4,f
	rrf		dcf3,f
	rrf		dcf2,f
	rrf		dcf1,f
	rrf		dcf0,f
IOC_2
	bcf		dcflevel		;remember current level
	btfsc	DCF77in
	bsf		dcflevel

    goto	ISR_reentry		;hard coded to save stackspace
;------------------------------------------------------------------
;initializes Processor
;------------------------------------------------------------------
INIT
	SET_BANK1	 			;select Register Page 1
	bcf		TRISA,2			;Port A bit 2 output (blanking)
	bsf		TRISA,3			;except bit 3 (DCF input)
	bsf		TRISA,0			;except bit 0 & 1 (sync & Key input)
	bsf		TRISA,1
	clrf	TRISB			;port B all output
	bsf		SDA_T			;except I2C ports
	bsf		SCL_T
	clrf    TRISC			;Port C all output
	movlw	b'00000011'		;weak pullup enabled for bit 0 & 1
	movwf	WPUA
	movlw	b'00000001'
	movwf	IOCA			;IOC on RA0 (sync input)
	movlw	b'00000111'		;Pullup enable, Rest irrelevant for this project
	movwf   OPTION_REG
    SET_BANK2
    ;configure analog I/O
	clrf 	ANSEL			;all digital I/O
	clrf	ANSELH
	clrf	IOCB			;no IOC on Port B
	SET_BANK0
	;----now set reasonable values to variables
	bsf		SDA
	bsf		SCL			;SCL and SDA high
    clrf	tickcounter
	clrf	bitcount
	clrf	bittime
    clrf    flags
	clrf	flags1
	clrf	hour
	clrf	min
	clrf	sec
	clrf	tag_z
	clrf	tag_e
	clrf	mon_z
	clrf	mon_e
	clrf	jahr_z
	clrf	jahr_e
	clrf	dataa
	clrf	datab
	bcf		dacab
	bsf		wrcs
	bcf		blank
	clrf	nbix

    call    load_prefs
	call	Delay100ms	;make sure all Input-level are settled

	;--now get current time from RTC
	bcf		rtcinitial		;assume that rtc is already initialized
	call	i2c_stop
	call	rtc_brst_rd		;get time
	btfsc	rtcinitial
	call	rtc_brst_wr		;save to make sure 24 mode & OSC is running only if rtc not initialized correctly
	call	rtc_init		;to set control reg

	clrf	INTCON			;initialize Interrupts & clear interrupt flags
	bsf		INTCON,RABIE	;enable port on change Interrupt
	bsf		INTCON,GIE		;enable global interrupts

;#############################################################################
;here to start main routine###################################################
;#############################################################################
main		
	btfss	keyispressed	;key pressed (from ISR)
	goto	nokey			;none, so go on
	;key was pressed
	btfsc	keywaspressed	;if key was already pressed last time
	goto	nonewkey		;then do nothing until release
	bsf		keywaspressed	;yes, remember that
	incf	vmode,f			;yes, then next mode
	movf	vmode,w
	xorlw	0x05			;already mode 5 (which doesnt exist)?
	btfsc	STATUS,Z
	clrf	vmode			;yes, then back to mode 0
	call	save_prefs
	goto	nonewkey
nokey
	bcf		keywaspressed	;clear flag, currently no key pressed
nonewkey
	;now time handling
	btfss	newtime			;only if newtime indicator set
	goto	main_end
	btfss	dcf77sync		;dcf77 in sync?
	goto	no_dcf77sync
	movf	sec,w
	btfsc	STATUS,Z		;if sec=0 (1 minute over) then save current time to RTC
	call	rtc_brst_wr
	bcf		newtime
	goto	calc_nbi

no_dcf77sync				;fetch time from RTC if dcf77 not synced
	movf	sec,w
	btfsc	STATUS,Z		;if sec=0 (1 minute over) then get current time from RTC
    call	rtc_brst_rd		;get time
	bcf		newtime

calc_nbi					;calculate delta in x for no-burn-in-protection
							;+2 pixel every 10 mins for 10,20,30min and -2 pixel for 40 & 50min
	movlw	0x03
	movwf	nbitmp		;max delta for no burn in=3
	movf	min,w
	call	bin2bcd
	andlw	0xf0		;only 10mins are of interest
	xorlw	0x10		;10min
	btfsc	STATUS,Z
	bcf		nbitmp,1	;nbitmp=1
	xorlw	0x20^0x10	;20min
	btfsc	STATUS,Z
	bcf		nbitmp,0	;nbitmp=2
	xorlw	0x40^0x20	;40min
	btfsc	STATUS,Z
	bcf		nbitmp,0	;nbitmp=2
	xorlw	0x50^0x40	;50min
	btfsc	STATUS,Z
	bcf		nbitmp,1	;nbitmp=1
	xorlw	0x00^0x50	;0min
	btfsc	STATUS,Z
	clrf	nbitmp		;nbitmp=0
	;no change for 30sec.... nbix remains 3
	bcf		STATUS,C
	rlf		nbitmp,w	;2*
	movwf	nbix		;and save
main_end
	goto	main
;------------------------------------------------
; draw mode 0 (only watchface in the middle of the screen)
;------------------------------------------------
mode_0
	movlw	0x40
	addwf	nbix,w
	movwf	offsx
	movlw	0x00
	movwf	offsy	
	bsf		divx	;divide by 2 in x because our screen is 2times larger in x
	bcf		divy
	call	draw_watch

	bsf		blank
	movlw	0xed		;goto beginning of Dcf markings to reduce artifacts
	movwf	dataa
	movlw	0x08
	movwf	datab
	call	pushdata
	bcf		noblankatstart

	movlw	0xe9
	addwf	nbix,w
	movwf	offsx
	movlw	0x08
	movwf	offsy
	movlw	0x01		;load scale-Factors (1=no scale, 2=2, 3=3,...)
	movwf	scx
	movlw	0x02
	movwf	scy
	btfss	signal		;DCF77 signal?
	goto 	mode_0_0	;no, then do nothing
	movlw	0x0d		;yes, show symbol
	call 	draw_char
	btfss	dcf77sync	;DCF77 in sync?
	goto 	mode_0_0	;no, then do nothing
	movlw	0x0a		;offset
	addwf	offsx,f		;yes, show symbol
	movlw	0x0e
	call draw_char
mode_0_0
	bsf		blank
	movlw	0x80		;goto beginning of next cycle to reduce artifacts
	addwf	nbix,w		;add no burn-in delta
	movwf	dataa
	movlw	0xff
	movwf	datab
	call	pushdata
	call	Delay4ms	;delay to prolong routine >10ms and <20ms - prevents additional trigger at zero-crossing of sync signal
	bcf		blank
	bsf		blank
	return
;------------------------------------------------
; draw mode 1	(Watchface left, Date right)
;------------------------------------------------
mode_1
	movlw	0x00
	addwf	nbix,w
	movwf	offsx
	movlw	0x00
	movwf	offsy	
	bsf		divx
	bcf		divy
	call	draw_watch
	
	bsf		blank
	movlw	0x80		;goto near the beginning of Date to reduce artifacts
	movwf	dataa
	movlw	0x80
	movwf	datab
	call	pushdata
	bcf		noblankatstart

	movlw	0x8e
	addwf	nbix,w
	movwf	offsx
	movlw	0x78
	movwf	offsy	
	movlw	0x01	;load scale-Factors (1=no scale, 2=2, 3=3,...)
	movwf	scx
	movlw	0x02
	movwf	scy
	call	draw_date

	movlw	0xe9
	addwf	nbix,w
	movwf	offsx
	movlw	0x08
	movwf	offsy
	movlw	0x01	;load scale-Factors (1=no scale, 2=2, 3=3,...)
	movwf	scx
	movlw	0x02
	movwf	scy
	btfss	signal		;DCF77 signal?
	goto 	mode_1_0	;no, then do nothing
	movlw	0x0d		;yes, show symbol
	call 	draw_char
	btfss	dcf77sync	;DCF77 in sync?
	goto 	mode_1_0	;no, then do nothing
	movlw	0x0a		;offset
	addwf	offsx,f		;yes, show symbol
	movlw	0x0e
	call draw_char
mode_1_0
	bsf		blank
	movlw	0x40		;goto beginning of next cycle to reduce artifacts
	addwf	nbix,w		;add no burn-in delta
	movwf	dataa
	movlw	0xff
	movwf	datab
	call	pushdata
	return
;------------------------------------------------
; draw mode 2 (big letter time on top, small letter date at the bottom of the screen)
;------------------------------------------------
mode_2
	movlw	d'16'
	addwf	nbix,w
	movwf	offsx
	movlw	0x80
	movwf	offsy
	movlw	0x03	;load scale-Factors (1=no scale, 2=2, 3=3,...)
	movwf	scx
	movlw	0x07
	movwf	scy
	call	draw_time

	bsf		blank
	movlw	0x48		;goto near the beginning of Date to reduce artifacts
	movwf	dataa
	movlw	0x20
	movwf	datab
	call	pushdata
	bcf		noblankatstart

	movlw	0x48
	addwf	nbix,w
	movwf	offsx
	movlw	0x20
	movwf	offsy
	movlw	0x01	;load scale-Factors (1=no scale, 2=2, 3=3,...)
	movwf	scx
	movlw	0x02
	movwf	scy
	call	draw_date

	movlw	0xe9
	addwf	nbix,w
	movwf	offsx
	movlw	0x08
	movwf	offsy
	movlw	0x01	;load scale-Factors (1=no scale, 2=2, 3=3,...)
	movwf	scx
	movlw	0x02
	movwf	scy
	btfss	signal		;DCF77 signal?
	goto 	mode_2_0	;no, then do nothing
	movlw	0x0d		;yes, show symbol
	call 	draw_char
	btfss	dcf77sync	;DCF77 in sync?
	goto 	mode_2_0	;no, then do nothing
	movlw	0x0a		;offset
	addwf	offsx,f		;yes, show symbol
	movlw	0x0e
	call 	draw_char
mode_2_0
	bsf		blank
	movlw	d'22'		;goto beginning of next cycle to reduce artifacts
	addwf	nbix,w		;add no burn-in delta
	movwf	dataa
	movlw	0x80
	movwf	datab
	call	pushdata
	return
;------------------------------------------------
; draw mode 3 (big letter time only)
;------------------------------------------------
mode_3
	movlw	d'16'
	addwf	nbix,w
	movwf	offsx
	movlw	0x50
	movwf	offsy
	movlw	0x03	;load scale-Factors (1=no scale, 2=2, 3=3,...)
	movwf	scx
	movlw	0x07
	movwf	scy
	call	draw_time

	movlw	0xe9
	addwf	nbix,w
	movwf	offsx
	movlw	0x08
	movwf	offsy
	movlw	0x01	;load scale-Factors (1=no scale, 2=2, 3=3,...)
	movwf	scx
	movlw	0x02
	movwf	scy
	btfss	signal		;DCF77 signal?
	goto 	mode_3_0	;no, then do nothing
	movlw	0x0d		;yes, show symbol
	call 	draw_char
	btfss	dcf77sync	;DCF77 in sync?
	goto 	mode_3_0	;no, then do nothing
	movlw	0x0a		;offset
	addwf	offsx,f		;yes, show symbol
	movlw	0x0e
	call 	draw_char
mode_3_0
	bsf		blank
	movlw	d'22'		;goto beginning of next cycle to reduce artifacts
	addwf	nbix,w		;add no burn-in delta
	movwf	dataa
	movlw	0x50
	movwf	datab
	call	pushdata
	call	Delay4ms	;delay to prolong routine >10ms and <20ms - prevents additional trigger at zero-crossing of sync signal
	return
;------------------------------------------------
; draw mode 4 (only test pattern)
;------------------------------------------------
mode_4
	;draw cross
	clrf	xstart
	clrf	ystart
	movlw	0xff
	movwf	xend
	movwf	yend
	call	bresenham
	movlw	0xff
	movwf	xstart
	clrf	ystart
	clrf	xend
	movlw	0xff
	movwf	yend
	call	bresenham

	;draw circle
	movlw	0x40
	movwf	offsx
	;get startpiont
	movlw	d'59'			;start at 59 to close the circle
	movwf	tmp
	movlw	high circletable	;prepare computed goto
	movwf	PCLATH
	movf	tmp,w			;get curr. pos
	call	circletable		;get value x
	movwf	xstart			;save it
	bcf		STATUS,C
	rrf		xstart,f		;scale/2 to become a circle
	movf	offsx,w
	addwf	xstart,f
	;do it for y
	movf	tmp,w			;get curr. pos
	addlw	d'64'			;add offset for y-values
	call	circletable		;get value y
	movwf	ystart			;save it
	movlw	high $			;reset pclath to current Page (0)
	movwf	PCLATH
	clrf	tmp					;define start=0
mode_41
	movlw	high circletable	;prepare computed goto
	movwf	PCLATH
	movf	tmp,w			;get curr. pos
	call	circletable		;get value x
	movwf	xend			;save it
	bcf		STATUS,C
	rrf		xend,f		;scale/2 to become a circle
	movf	offsx,w
	addwf	xend,f
	;do it for y
	movf	tmp,w			;get curr. pos
	addlw	d'64'			;add offset for y-values
	call	circletable		;get value y
	movwf	yend			;save it
	movlw	high $			;reset pclath to current Page (0)
	movwf	PCLATH

	call	bresenham
	bsf		noblankatstart	;other than 1st line: no blanking required
	movf	xend,w			;make endpoints the new start
	movwf	xstart
	movf	yend,w
	movwf	ystart
	incf	tmp,f			;next value
	movf	tmp,w
	xorlw	d'60'			;test if last entry
	btfss	STATUS,Z		;if Z then last entry, end this loop
	goto	mode_41
	bcf		noblankatstart
	bsf		blank
	call	Delay4ms	;delay to prolong routine >10ms and <20ms - prevents additional trigger at zero-crossing of sync signal

	return
;------------------------------------------------
;draws the time (char-based)
;------------------------------------------------
draw_time
	;hour
	movf	hour,w
	call	bin2bcd
	movwf	dttmp		;holds hours in bcd format
	swapf	dttmp,w
	andlw	0x0F
	call	draw_char	;hour 10s
	movlw	d'28'
	addwf	offsx,f
	movf	dttmp,w
	andlw	0x0F
	call	draw_char	;hour 1s
	;points
	movlw	d'28'
	addwf	offsx,f
	movlw	0x0B
	call	draw_char
	movlw	0x0C		;no distance!
	call	draw_char
	;mins
	movlw	d'28'
	addwf	offsx,f
	movf	min,w
	call	bin2bcd
	movwf	dttmp		;holds mins in bcd format
	swapf	dttmp,w
	andlw	0x0F
	call	draw_char	;min 10s
	movlw	d'28'
	addwf	offsx,f
	movf	dttmp,w
	andlw	0x0F
	call	draw_char	;min 1s
	;points
	movlw	d'28'
	addwf	offsx,f
	movlw	0x0B
	call	draw_char
	movlw	0x0C		;no distance!
	call	draw_char
	;secs
	movlw	d'28'
	addwf	offsx,f
	movf	sec,w
	call	bin2bcd
	movwf	dttmp		;holds secs in bcd format
	swapf	dttmp,w
	andlw	0x0F
	call	draw_char	;sec 10s
	movlw	d'28'
	addwf	offsx,f
	movf	dttmp,w
	andlw	0x0F
	call	draw_char	;sec 1s
	return
;------------------------------------------------
;draws the date 
;------------------------------------------------
draw_date
	;day
	movf	tag_z,w
	call 	draw_char
	movlw	0x0b
	addwf	offsx,f
	movf	tag_e,w
	call 	draw_char
	movlw	0x0b
	addwf	offsx,f
	movlw	0x0a		;.
	call 	draw_char
	;month
	movlw	0x0b
	addwf	offsx,f
	movf	mon_z,w
	call 	draw_char
	movlw	0x0b
	addwf	offsx,f
	movf	mon_e,w
	call 	draw_char
	movlw	0x0b
	addwf	offsx,f
	movlw	0x0a		;.
	call 	draw_char
	;year (20xx)
	movlw	0x0b
	addwf	offsx,f
	movlw	0x02		;"2"
	call 	draw_char
	movlw	0x0b
	addwf	offsx,f
	movlw	0x00		;"0"
	call 	draw_char
	movlw	0x0b
	addwf	offsx,f
	movf	jahr_z,w
	call 	draw_char
	movlw	0x0b
	addwf	offsx,f
	movf	jahr_e,w
	call 	draw_char
draw_date_end
	return
;------------------------------------------------
;draws one char in w at pos offsx, offsy, scaled by scx, scy
;------------------------------------------------
draw_char
	clrf	tmp				;used to count bytes of indexed char (max 16)

	andlw	0x0F			;char in w: mask lower 4 bits
	movwf	charp			;save to charpointer
	swapf	charp,f			;swap - which is a multiply by 16 (16 entrys for each char in our chartable)

	movlw	high zifftable	;prepare computed goto
	movwf	PCLATH
	movf	charp,w
	call	zifftable		;get first value as starting-point
	movwf	chard			;save for a moment
	movlw	high $			;reset pclath to current Page (0)
	movwf	PCLATH
	;first y-value
	clrf	ystart
	movf	scy,w
	movwf	tmp1
	movf	chard,w
	andlw	0x0F
	movwf	dctmp
	addwf	ystart,f		;multiply by scy
	decfsz	tmp1,f
	goto	$-2
	movf	offsy,w
	addwf	ystart,f
	;then x-value
	clrf	xstart
	movf	scx,w
	movwf	tmp1
	swapf	chard,w
	andlw	0x0F
	movwf	dctmp
	addwf	xstart,f		;multiply by scx
	decfsz	tmp1,f
	goto	$-2
	movf	offsx,w
	addwf	xstart,f
	bcf		noblankatstart	;first point: we want to blank and delay

char1
	incf	charp,f			;next points
	incf	tmp,f
	movlw	high zifftable	;prepare computed goto
	movwf	PCLATH
	movf	charp,w
	call	zifftable		;get value x
	movwf	chard			;save for a moment
	movlw	high $			;reset pclath to current Page (0)
	movwf	PCLATH
	movf	chard,w			;end of table?
	xorlw	0xff
	btfsc	STATUS,Z		;then end
	goto	charfin
	clrf	yend
	movf	scy,w
	movwf	tmp1
	movf	chard,w
	andlw	0x0F
	movwf	dctmp
	addwf	yend,f			;multiply by scy
	decfsz	tmp1,f
	goto	$-2
	movf	offsy,w
	addwf	yend,f
	;now next x
	clrf	xend
	movf	scx,w
	movwf	tmp1
	swapf	chard,w
	andlw	0x0F
	movwf	dctmp
	addwf	xend,f		;else multiply by scx
	decfsz	tmp1,f
	goto	$-2
	movf	offsx,w
	addwf	xend,f

	call	bresenham
	bsf		noblankatstart	;further points: we want no blank and delay
	movf	tmp,w			;max 16 ?
	xorlw	d'15'
	btfsc	STATUS,Z	
	goto	charfin			;then end also
	movf	xend,w			;swap start/end coordinates
	movwf	xstart
	movf	yend,w
	movwf	ystart
	goto	char1
charfin
	bcf		noblankatstart	
	return
;------------------------------------------------
;draws the watchface including hands
;------------------------------------------------
draw_watch
	;first draw the minute-ticks as points at the outer rim
	clrf	tmp					;define start=0
circloop1
	movlw	high circletable	;prepare computed goto
	movwf	PCLATH
	movf	tmp,w			;get curr. pos
	call	circletable		;get value x
	movwf	dataa			;save it
	;do it for y
	movf	tmp,w			;get curr. pos
	addlw	d'64'			;add offset for y-values
	call	circletable		;get value y
	movwf	datab			;save it
	movlw	high $			;reset pclath to current Page (0)
	movwf	PCLATH
	
	movf	dataa,w
	call	scale_x
	movwf	dataa
	movf	datab,w
	call	scale_y
	movwf	datab

	bsf		blank
	call	pushdata		;and output x & y
	movf	tmp,w			;test if 0 (1st value)
	btfsc	STATUS,Z
	call	Delay25us		;if so delay (additional time for xy amps only at first point)
	call	Delay10us		;time for amps between each point
	bcf		blank
	call	Delay10us		;here we have enough time to let things settle (more stable watchface...)
	incf	tmp,f			;next value
	movf	tmp,w
	xorlw	d'60'			;test if last entry
	btfss	STATUS,Z		;if Z then last entry, end this loop
	goto	circloop1

	;now show 5-minutes markings
	clrf	tmp					;define start=0
circloop2
	movlw	high circletable	;prepare computed goto
	movwf	PCLATH
	movf	tmp,w			;get curr. pos
	call	circletable		;get value x
	movwf	xend			;save it
	;do it for y
	movf	tmp,w			;get curr. pos
	addlw	d'64'			;add offset for y-values
	call	circletable		;get value y
	movwf	yend			;save it

	movf	tmp,w			;get curr. pos
	addlw	d'128'
	call	circletable		;get value x
	movwf	xstart			;save it
	;do it for y
	movf	tmp,w			;get curr. pos
	addlw	d'192'			;add offset for y-values
	call	circletable		;get value y
	movwf	ystart			;save it

	movlw	high $			;reset pclath to current Page (0)
	movwf	PCLATH

	movf	xstart,w
	call	scale_x
	movwf	xstart
	movf	xend,w
	call	scale_x
	movwf	xend	
	movf	ystart,w
	call	scale_y
	movwf	ystart
	movf	yend,w
	call	scale_y
	movwf	yend

	bcf		noblankatstart
	call	bresenham		;and output line
	movf	tmp,w			;next value
	addlw	d'05'
	movwf	tmp
	xorlw	d'60'			;test if last entry
	btfss	STATUS,Z		;if Z then last entry, end this loop
	goto	circloop2

	;show seconds - - - - - - - - - - - - - - - - - - -
	movlw	d'128'
	call	scale_x
	movwf	xstart
	movlw	d'128'
	call	scale_y	
	movwf	ystart

	movlw	high circletable	;prepare computed goto
	movwf	PCLATH
	movf	sec,w			;get curr. pos
	call	circletable		;get value x
	movwf	xend			;save it
	;do it for y
	movf	sec,w			;get curr. pos
	addlw	d'64'			;add offset for y-values
	call	circletable		;get value y
	movwf	yend			;save it
	movlw	high $			;reset pclath to current Page (0)
	movwf	PCLATH

	movf	xend,w
	call	scale_x
	movwf	xend	
	movf	yend,w
	call	scale_y
	movwf	yend
	
	call	bresenham
	;show minutes - - - - - - - - - - - - - - - - - - -
	;bigger clock hand composed of more than one line
	;calc startpoint of watchhand small end
	movf	min,w
	sublw	d'30'	
	btfss	STATUS,C	;C=1 if w <= k; 0 if w >k
	goto	sm0			;min >30
	movf	min,w		;min <=30
	addlw	d'30'
	movwf	tmp
	xorlw	d'60'		;special case 60: set to zero
	btfsc	STATUS,Z
	clrf	tmp
	goto	sm01
sm0
	movlw	d'30'
	subwf	min,w
	movwf	tmp
sm01
	movlw	high circletable1	;prepare computed goto
	movwf	PCLATH
	movf	tmp,w
	addlw	d'128'
	call	circletable1	;get value x
	movwf	btmpx			;save it
	movf	tmp,w
	addlw	d'192'
	call	circletable1	;get value y
	movwf	btmpy			;save it
	movlw	high $			;reset pclath to current Page (0)
	movwf	PCLATH

	movf	btmpx,w
	call	scale_x
	movwf	btmpx	
	movf	btmpy,w
	call	scale_y
	movwf	btmpy

	;first line...
	movf	min,w
	sublw	d'15'	
	btfss	STATUS,C	;C=1 if w <= k; 0 if w >k
	goto	sm1			;min >15
	movf	min,w		;min <=15
	addlw	d'45'
	movwf	tmp
	xorlw	d'60'		;special case 60: set to zero
	btfsc	STATUS,Z
	clrf	tmp
	goto	sm2
sm1
	movlw	d'15'
	subwf	min,w
	movwf	tmp
sm2
	movlw	high circletable1	;prepare computed goto
	movwf	PCLATH
	movf	tmp,w
	addlw	d'128'
	call	circletable1	;get value x
	movwf	xstart			;save it
	movf	tmp,w
	addlw	d'192'
	call	circletable1	;get value y
	movwf	ystart			;save it

	movlw	high circletable	;prepare computed goto	
	movwf	PCLATH
	movf	min,w			;get curr. pos
	call	circletable		;get value x
	movwf	xend			;save it
	;do it for y
	movf	min,w			;get curr. pos
	addlw	d'64'			;add offset for y-values
	call	circletable		;get value y
	movwf	yend			;save it
	movlw	high $			;reset pclath to current Page (0)
	movwf	PCLATH

	movf	xstart,w
	call	scale_x
	movwf	xstart
	movf	xend,w
	call	scale_x
	movwf	xend	
	movwf	btmpx1			;prepare to draw small end
	movf	ystart,w
	call	scale_y
	movwf	ystart
	movf	yend,w
	call	scale_y
	movwf	yend
	movwf	btmpy1			;prepare to draw small end

	call	bresenham		;draw first line (left if 12 — clock)
	
	;small end first part
	movf	btmpx,w
	movwf	xend
	movf	btmpy,w
	movwf	yend
	call	bresenham
	movf	btmpx1,w		;and restore endpoints to draw 2nd line in the following code
	movwf	xend
	movf	btmpy1,w
	movwf	yend

	;now second line...
	movf	min,w
	sublw	d'45'			;45-min
	btfss	STATUS,C		;C=1 if w <= k; 0 if w >k
	goto	sm3				;min >45
	movlw	d'15'			;min <=45
	addwf	min,w
	movwf	tmp
	xorlw	d'60'		;special case 60: set to zero
	btfsc	STATUS,Z
	clrf	tmp
	goto	sm4
sm3
	movlw	d'45'
	subwf	min,w
	movwf	tmp
sm4
	movlw	high circletable1	;prepare computed goto
	movwf	PCLATH
	movf	tmp,w
	addlw	d'128'
	call	circletable1	;get value x
	movwf	xstart			;save it
	movf	tmp,w
	addlw	d'192'
	call	circletable1	;get value y
	movwf	ystart			;save it
	;xend & yend are already in place from 1st line
	movlw	high $			;reset pclath to current Page (0)
	movwf	PCLATH

	movf	xstart,w
	call	scale_x
	movwf	xstart
	movf	ystart,w
	call	scale_y
	movwf	ystart

	call	bresenham		;draw second line (right if 12 — clock)

	;small end second part
	movf	btmpx,w
	movwf	xend
	movf	btmpy,w
	movwf	yend
	call	bresenham

	;show hours - - - - - - - - - - - - - - - - - - -
	movf	hour,w		;make a copy of 24h-hour to work with
	movwf	hour12
	xorlw	d'12'		;check if exactly 12h
	btfsc	STATUS,Z
	clrf	hour12		;then set to 0
	movf	hour12,w
	sublw	d'12'		;check if>12h k-w
	btfsc	STATUS,C	;C=1 if w <= k; 0 if w >k
	goto	shour00		;no, then go on
	movlw	d'12'		;yes, then subtract 12
	subwf	hour12,f
shour00
	movf	hour12,w			;get curr. pos	(x5 because 1h= 5min-position on watchface)
	addwf	hour12,w
	addwf	hour12,w
	addwf	hour12,w
	addwf	hour12,w
	movwf	tmp1
	movf	min,w
	movwf	tmp
shour0	
	movlw	d'12'	
	subwf	tmp,f
	btfss	STATUS,C	;C=1 if w <= f; 0 if w >f
	goto	shour1
	incf	tmp1,f		;add one for each 12 minutes
	goto	shour0
shour1
	;first line...
	movf	tmp1,w
	sublw	d'15'	
	btfss	STATUS,C	;C=1 if w <= k; 0 if w >k
	goto	sh1			;hour >15
	movf	tmp1,w		;hour <=15
	addlw	d'45'
	movwf	tmp
	xorlw	d'60'		;special case 60: set to zero
	btfsc	STATUS,Z
	clrf	tmp
	goto	sh2
sh1
	movlw	d'15'
	subwf	tmp1,w
	movwf	tmp
sh2
	movlw	high circletable1	;prepare computed goto
	movwf	PCLATH
	movf	tmp,w
	addlw	d'128'
	call	circletable1	;get value x
	movwf	xstart			;save it
	movf	tmp,w
	addlw	d'192'
	call	circletable1	;get value y
	movwf	ystart			;save it

	;movlw	high circletable1	;prepare computed goto (not necessary caus we already loaded PCLATH above)
	;movwf	PCLATH
	movf	tmp1,w
	call	circletable1	;get value x
	movwf	xend			;save it
	;do it for y
	movf	tmp1,w			;get curr. pos 
	addlw	d'64'			;add offset for y-values
	call	circletable1	;get value y
	movwf	yend			;save it
	movlw	high $			;reset pclath to current Page (0)
	movwf	PCLATH

	movf	xstart,w
	call	scale_x
	movwf	xstart
	movf	xend,w
	call	scale_x
	movwf	xend	
	movf	ystart,w
	call	scale_y
	movwf	ystart
	movf	yend,w
	call	scale_y
	movwf	yend

	call	bresenham

	;now second line...
	movf	tmp1,w
	sublw	d'45'			;45-min
	btfss	STATUS,C		;C=1 if w <= k; 0 if w >k
	goto	sh3				;hour >45
	movlw	d'15'			;hour <=45
	addwf	tmp1,w
	movwf	tmp
	xorlw	d'60'		;special case 60: set to zero
	btfsc	STATUS,Z
	clrf	tmp
	goto	sh4
sh3
	movlw	d'45'
	subwf	tmp1,w
	movwf	tmp
sh4
	movlw	high circletable1	;prepare computed goto
	movwf	PCLATH
	movf	tmp,w
	addlw	d'128'
	call	circletable1	;get value x
	movwf	xstart			;save it
	movf	tmp,w
	addlw	d'192'
	call	circletable1	;get value y
	movwf	ystart			;save it
	;xend & yend are already in place from 1st line
	movlw	high $			;reset pclath to current Page (0)
	movwf	PCLATH

	movf	xstart,w
	call	scale_x
	movwf	xstart
	movf	ystart,w
	call	scale_y
	movwf	ystart

	call	bresenham		;draw second line (right if 12 — clock)

	return					;draw_watch
;------------------------------------------------
;scale value in w by 2 if flag set and adds offset in x & y direction
;------------------------------------------------
scale_x
	movwf	tmp2
	bcf		STATUS,C		;clear carry
	btfsc	divx			;and divide by 2 if flag set
	rrf		tmp2,f
	movf	offsx,w
	addwf	tmp2,w
	return
scale_y
	movwf	tmp2
	bcf		STATUS,C		;clear carry
	btfsc	divy			;and divide by 2 if flag set
	rrf		tmp2,f
	movf	offsy,w
	addwf	tmp2,w
	return
;------------------------------------------------
;pushes the current data to the DAC, both channel
;------------------------------------------------
pushdata
	bcf		dacab	;A
	movf	dataa,w
	movwf	dacdat
	bcf		wrcs	;pulse in
	bsf		wrcs
	bsf		dacab	;B
	movf	datab,w
	movwf	dacdat
	bcf		wrcs	;pulse in
	bsf		wrcs
	return
;------------------------------------------------
;bresenham line drawing algorithm
;input with xstart, ystart, xend, yend
;------------------------------------------------
bresenham
	;calculate absolute deltas and signum for x and y
	movf	xstart,w
	subwf	xend,w		;xend-xstart
	btfsc	STATUS,C	;C=1 if w <= f; 0 if w >f
	goto b1				;positive
	movlw	0x02		;indicator negative
	movwf	sdx
	movf	xend,w
	subwf	xstart,w
	movwf	adx
	goto	b2
b1
	movwf	adx			;save absolut delta x
	movlw	0x01
	movwf	sdx			;signum positive
	btfsc	STATUS,Z	;set zero if delta is zero
	clrf	sdx			
b2
	movf	ystart,w
	subwf	yend,w		;yend-ystart
	btfsc	STATUS,C	;C=1 if w <= f; 0 if w >f
	goto b3				;positive
	movlw	0x02		;indicator negative
	movwf	sdy
	movf	yend,w
	subwf	ystart,w
	movwf	ady
	goto	b4
b3
	movwf	ady			;save absolut delta y
	movlw	0x01
	movwf	sdy			;signum positive
	btfsc	STATUS,Z	;set zero if delta is zero
	clrf	sdy			
b4
	;test for fast direction
	movf	adx,w
	subwf	ady,w		;ady-adx
	btfsc	STATUS,C	;C=1 if w <= f; 0 if w >f
	goto	yisfast
	;x is fast dircetion
	movf	sdx,w
	movwf	pdx
	movwf	ddx
	clrf	pdy
	movf	sdy,w
	movwf	ddy
	movf	ady,w
	movwf	dslow
	movf	adx,w
	movwf	dfast
	goto	bresloop
yisfast
	;y is fast direction
	clrf	pdx
	movf	sdy,w
	movwf	pdy
	movwf	ddy
	movf	sdx,w
	movwf	ddx
	movf	ady,w
	movwf	dfast
	movf	adx,w
	movwf	dslow

bresloop
	movf	xstart,w
	movwf	dataa
	movf	ystart,w
	movwf	datab
	bcf		STATUS,C		;delta fast / 2 to error
	rrf		dfast,w			;error=0 if delta was 1!!
	movwf	berror
	
	movlw	0x01
	movwf	bloop


	btfsc	noblankatstart	;1st pixel?
	goto	bres_noblank	;yes, then we need no blanking and no delay
	bsf		blank			;otherwise....blanking
	call	pushdata		;start-pixel
	call 	Delay25us		;wait for xy amps to settle...
	bcf		blank			;beam on again
	goto	bloop_start
bres_noblank
	bcf		blank			;beam on....to be sure
	call	pushdata		;start-pixel

bloop_start
	movf	dslow,w
	subwf	berror,f	;berror-dslow
	btfsc	STATUS,C	;C=1 if w <= f; 0 if w >f
	goto	dofast
doslow
	;go in slow direction
	movf	dfast,w		;make error positive again
	addwf	berror,f
	btfsc	ddx,0		; ddx=1?
	incf	dataa,f		;yes, then add 1
	btfsc	ddx,1		; ddx=2?
	decf	dataa,f		;yes, then subtract 1

	btfsc	ddy,0		; ddy=1?
	incf	datab,f		;yes, then add 1
	btfsc	ddy,1		; ddx=2?
	decf	datab,f		;yes, then subtract 1

	goto	dopush
dofast
	btfsc	pdx,0		;pdx=1?
	incf	dataa,f		;yes, then add 1
	btfsc	pdx,1		;pdx=2?
	decf	dataa,f		;yes, then subtract 1
	btfsc	pdy,0		;pdy=1?
	incf	datab,f		;yes, then add 1
	btfsc	pdy,1		;pdx=2?
	decf	datab,f		;yes, then subtract 1
dopush
	;call	pushdata	;draw new pixel
	;same as pushdata, implemented here to save time (no need to call & return)
	bcf		dacab	;A
	movf	dataa,w
	movwf	dacdat
	bcf		wrcs	;pulse in
	bsf		wrcs
	bsf		dacab	;B
	movf	datab,w
	movwf	dacdat
	bcf		wrcs	;pulse in
	bsf		wrcs
	;--------------
	movf	dfast,w
	xorwf	bloop,w		;end of loop?
	btfsc	STATUS,Z	;not Z--> not ready, next loop
	goto	bres_end	;Z=1 --> end of loop
	incf	bloop,f
	goto	bloop_start
bres_end
	call	Delay4us	;to clearly show the last point
	bsf		blank		;beam off
	return
;---------------------------------------------------------------
; process received dcf bits into processable time (hour, minutes)
; error check & parity check
;---------------------------------------------------------------
process_time
	;here to check errors, and get shifted bits into the real variables
	;5       4       3       2       1       0
	;765432107654321076543210765432107654321076543210
	;PJJJJJJJJMMMMMTTTTTTTTTPhhhhhhPmmmmmmm1SSSS
	;
	;1st check parity and set errorflag if necessary
	;mins
	movf	dcf1,w
	movwf	tmp77
	movf	dcf2,w
	movwf	tmp77_1
	rrf		tmp77_1,f
	rrf		tmp77,f
	rrf		tmp77_1,f
	rrf		tmp77,f
	movf	tmp77,w
	call	calc_parity
	btfss	STATUS,Z		;0=even parity
	bsf		biterror
	;hours
	movf	dcf2,w
	movwf	tmp77
	movf	dcf3,w
	movwf	tmp77_1
	rrf		tmp77_1,f
	rrf		tmp77,f
	movf	tmp77,w
	andlw	b'11111110'
	call	calc_parity
	btfss	STATUS,Z		;0=even parity
	bsf		biterror
	
	btfsc	biterror
	goto	process_time_1
	clrf	sec
	clrf	tickcounter
	bsf		dcf77sync
	bsf		newtime
	;minutes
	movlw	0x00
	btfsc	dcf1,6
	addlw	d'10'
	btfsc	dcf1,7
	addlw	d'20'
	btfsc	dcf2,0
	addlw	d'40'
	movwf	tmp77
	rrf		dcf1,f
	rrf		dcf1,f
	movf	dcf1,w
	andlw	0x0F
	addwf	tmp77,w
	movwf	min
	;hours
	movlw	0x00
	btfsc	dcf2,6
	addlw	d'10'
	btfsc	dcf2,7
	addlw	d'20'
	movwf	tmp77
	rrf		dcf2,f
	rrf		dcf2,f
	movf	dcf2,w
	andlw	0x0F
	addwf	tmp77,w
	movwf	hour
day
	movlw	0x00
	btfsc	dcf3,6
	addlw	d'2'
	btfsc	dcf3,5
	addlw	d'1'
	movwf	tag_z
	rrf		dcf3,w
	andlw	0xf
	movwf	tag_e
	;month
	movlw	0x00
	btfsc	dcf4,6
	addlw	d'1'
	movwf	mon_z
	movf	dcf4,w
	movwf	tmp77
	rrf		tmp77,f
	rrf		tmp77,w
	andlw	0xf
	movwf	mon_e
	;year
	movlw	0x00
	btfsc	dcf5,6
	addlw	d'8'
	btfsc	dcf5,5
	addlw	d'4'
	btfsc	dcf5,4
	addlw	d'2'
	btfsc	dcf5,3
	addlw	d'1'
	movwf	jahr_z
	rlf		dcf4,w
	rlf		dcf5,w
	andlw	0xf
	movwf	jahr_e
	goto	process_time_end
process_time_1
	bcf		dcf77sync
process_time_end
	bcf		biterror
	return
;---------------------------------------------------------------
; CALC_PARITY - Calculates parity of one byte, content is trashed,
; result in lowest bit
; There '1' means ODD and '0' means EVEN
; argument in W, result in W
;---------------------------------------------------------------
calc_parity
		movwf	tmp77
        SWAPF	tmp77, W 
        XORWF	tmp77, F 
        RRF		tmp77, W 
        XORWF	tmp77, F 
        BTFSC	tmp77, 2 
        INCF	tmp77, F 
		movf	tmp77,w
		andlw	b'00000001'
        return
;--------------------------------------------------------------------
;Conversion routines
;--------------------------------------------------------------------
;--------------------------------------------------------------------
; BCD to Binary
; input:f0
; output:w
; From: Scott Dattalo
;--------------------------------------------------------------------
bcd2bin
        swapf   f0, W
        andlw   0x0F            ; W=tens
        movwf   tmp
        addwf   tmp, W         ; W=2*tens
        addwf   tmp, F         ; tmp=3*tens (note carry is cleared)
        rlf     tmp, W         ; W=6*tens
        subwf   f0, W          ; W = 16*tens+ones - 6*tens

        return
;--------------------------------------------------------------------
; bin to BCD conversion - limited to 0-99 decimal (0x00-0x63 hex)
; Call with: number to be converted in W
; Returns with: converted BCD number in W
; Registers: tmp, tmp1 used during conversion
;--------------------------------------------------------------------
bin2bcd
		movwf	tmp		;original hex, save to tmp
		clrw
		btfsc	tmp, 4		;if 16 then bcd+16
		addlw	0x16
		btfsc	tmp, 5		;if 32 then bcd+32
		addlw	0x32
		addlw	0x06		;add 6 to correct bcd
		btfss	STATUS,DC	;overflow? then skip
		addlw	-0x06		;else subtract 6 again
		btfsc	tmp, 6		;if 64 then bcd+64
		addlw	0x64
		addlw	0x06		;bcd correction
		btfss	STATUS,DC
		addlw	-0x06
		movwf	tmp1		;save w to tmp1
		movf	tmp, 0		;load original hex to w
		andlw	0x0F		;mask ones
		addwf	tmp1, 0	;add ones to tmp1
		btfsc	STATUS,DC
		addlw	0x06		;bcd correction
		addlw	0x06		;bcd correction again
		btfss	STATUS,DC
		addlw	-0x06
		return
;--------------------------------------------------------------------
;RTC Subroutines
;DS1307 (Real time clock chip with I2C interface)
;--------------------------------------------------------------------
rtc_init
	bcf		tmpGIE,0
	btfss	INTCON,GIE
	goto	rtc_init_1
	bsf		tmpGIE,0		;remember State of GIE
	bcf		INTCON,GIE		;we don't want interrupts now
	btfsc	INTCON,GIE		;make sure it is really cleared
	goto	$-2
rtc_init_1
	call	i2c_start
	movlw	0xD0			; slave address + write
	call	i2c_write
	movlw	0x07			; set word address to control register
	call	i2c_write
	movlw	0x00				;write 0 to control reg
	call	i2c_write
	call	i2c_stop
	btfsc	tmpGIE,0			;restore GIE
	bsf		INTCON,GIE
	return

rtc_brst_rd
	bcf     tmpGIE,0
	btfss	INTCON,GIE
	goto	rtc_brst_rd_1
	bsf     tmpGIE,0		;remember State of GIE
	bcf		INTCON,GIE		;we don't want interrupts now
	btfsc	INTCON,GIE		;make sure it is really cleared
	goto	$-2
rtc_brst_rd_1
	call	i2c_start
	movlw	0xD0			; slave address + write
	call	i2c_write
	movlw	0x00			; set word address to seconds register
	call	i2c_write
	call	i2c_start
	movlw	0xD1			; slave address + read
	call	i2c_write
	call	i2c_read		; read the seconds data
	movwf	f0
	btfsc	f0,7		;if bit 7 (CH) is set
	bsf		rtcinitial	;flag this (will be processed at startup-routine)
	andlw	0x7f		;set bit 7 to 0
	movwf	f0
	call	bcd2bin		;we need it in binary format
	movwf	sec			; save it
	call	i2c_ack
	call	i2c_read		; and so on
	movwf	f0
	call	bcd2bin		;we need it in binary format
	movwf	min
	call	i2c_ack
	call	i2c_read
	movwf	f0
	btfsc	f0,6		;if bit 6 (12h mode) is set
	bsf		rtcinitial	;flag this (will be processed at startup-routine)
	andlw	0x3f		;set bit 7 and 6 to 0
	movwf	f0
	call	bcd2bin		;we need it in binary format
	movwf	hour
	call	i2c_ack
	call	i2c_read		;day, which we don't need
	call	i2c_ack			;so just send ack
	call	i2c_read		;date/day
	movwf	f0
	andlw	0x0f
	movwf	tag_e
	swapf	f0,w
	andlw	0x03
	movwf	tag_z
	call	i2c_ack
	call	i2c_read		; month
	movwf	f0
	andlw	0x0f
	movwf	mon_e
	swapf	f0,w
	andlw	0x01
	movwf	mon_z
	call	i2c_ack
	call	i2c_read		; year
	movwf	f0
	andlw	0x0f
	movwf	jahr_e
	swapf	f0,w
	andlw	0x0f
	movwf	jahr_z
	call	i2c_nack
	call	i2c_stop
	btfsc	tmpGIE,0			;restore GIE
	bsf     INTCON,GIE
	return

rtc_brst_wr
	bcf		tmpGIE,0
	btfss	INTCON,GIE
	goto	rtc_brst_wr_1
	bsf		tmpGIE,0		;remember State of GIE
	bcf		INTCON,GIE		;we don't want interrupts now
	btfsc	INTCON,GIE		;make sure it is really cleared
	goto	$-2
rtc_brst_wr_1
	call	i2c_start
	movlw	0xD0			; slave address + write
	call	i2c_write
	movlw	0x00			; set word address to seconds register
	call	i2c_write
	movf	sec, W
	call	bin2bcd			;the RTC needs it in bcd format & Bit 7 must be 0 to enble the clock
	call	i2c_write
	movf	min, W
	call	bin2bcd			;the RTC needs it in bcd format
	call	i2c_write
	movf	hour, W
	call	bin2bcd			;the RTC needs it in bcd format
	andlw	0x3f			;make sure bit 6 is clear (24h mode)
	call	i2c_write
	movlw	0x00			;day - doesn't matter because we dont need it
	call	i2c_write
	swapf	tag_z,w			;date
	addwf	tag_e,w
	call	i2c_write
	swapf	mon_z,w			;date
	addwf	mon_e,w
	call	i2c_write
	swapf	jahr_z,w			;date
	addwf	jahr_e,w
	call	i2c_write
	call	i2c_stop
	btfsc	tmpGIE,0			;restore GIE
	bsf	INTCON,GIE
	return
;--------------------------------------------------------------------
;I2C Subroutines
;--------------------------------------------------------------------
i2c_start
	bsf		SDA			; SDA high
	;fixme: next two lines necessary?
    ;SET_BANK1
	;bcf		SDA_T		; set SDA for output
	nop
	SET_BANK1
	bsf		SCL_T		; SCL high (input)
	SET_BANK0
	bcf		SDA			; SDA low (start)
	call Delay4us
	return
;-------------
i2c_stop; assumes SCL is high on entry
	bcf		SDA			; SDA low
	nop
	nop
	SET_BANK1
	bsf		SCL_T		; SCL high (input)
	SET_BANK0
	bsf		SDA			; SDA high
	call Delay4us
	return
;-------------
;i2c_read
;returns read byte in w
;-------------
i2c_read
	SET_BANK1
	bsf		SDA_T		; set SDA for input
	SET_BANK0

	movlw	08h			; send 8 bits
	movwf	count

	bcf		SCL			; clock data out
	SET_BANK1
	bcf		SCL_T		; SCL low (output)
	SET_BANK0

	clrf	tmpi2c			; clear var
	rlf		tmpi2c,1		; rotate carry in
	clrf	tmpi2c			; clear var again

i2c_read_loop
	rlf		tmpi2c, 1

	call 	Delay4us
	SET_BANK1
	bsf		SCL_T		; SCL high (input)
	SET_BANK0

	btfsc	SDA
	bsf		tmpi2c, 0			; if data out = 1, set bit

	bcf		SCL
	call 	Delay4us
	SET_BANK1
	bcf		SCL_T		; SCL low (output)
	SET_BANK0
	decfsz	count, 1
	goto	i2c_read_loop

	movf	tmpi2c, W

	return
;---- ACK read (assumes SCL=0 on entry) ----
i2c_ack
	bcf		SDA

	SET_BANK1
	bcf		SDA_T		; set SDA for output
	SET_BANK0

	SET_BANK1
	bsf		SCL_T		; SCL high (input)
	SET_BANK0
	nop
	bcf		SCL
	call 	Delay4us
	SET_BANK1
	bcf		SCL_T		; SCL low (output)
	SET_BANK0

	return
;---- NACK read (assumes SCL = 0 on entry) ----
i2c_nack
	bsf		SDA

	SET_BANK1
	bcf		SDA_T		; set SDA for output
	SET_BANK0

	SET_BANK1
	bsf		SCL_T		; SCL high (input)
	SET_BANK0

	bcf	SCL
	call 	Delay4us
	SET_BANK1	
	bcf		SCL_T		; SCL low (output)
	SET_BANK0

	return
;--- Do a I2C bus write of byte in 'tmp' ---
i2c_write
	movwf	tmpi2c		;save tmp

	SET_BANK1
	bcf		SDA_T		; set SDA for output
	SET_BANK0

	movlw	08h			; send 8 bits
	movwf	count

	bcf		SCL
	SET_BANK1
	bcf		SCL_T		; SCL low (output)
	SET_BANK0

i2c_w_loop
	bcf		SDA			; assume data out is low
	btfsc	tmpi2c, 7
	bsf		SDA			; if data out = 1, set bit
	; nop
	call 	Delay4us
	SET_BANK1
	bsf		SCL_T		; SCL high (input)
	SET_BANK0
	rlf		tmpi2c, 1
	bcf		SCL			; clock it in
	call 	Delay4us
	SET_BANK1
	bcf		SCL_T		; SCL low (output)
	SET_BANK0
	decfsz	count, 1
	goto	i2c_w_loop

	SET_BANK1
	bsf		SDA_T	; set SDA for input
	SET_BANK0

	bcf		SCL
	SET_BANK1
	bcf		SCL_T		; SCL low (output)
	SET_BANK0
	; nop
	call 	Delay4us
	SET_BANK1
	bsf		SCL_T		; SCL high (input)
	SET_BANK0
	; if(sda) printf("Ack bit missing  %02X\n",(unsigned int)d);
	bcf		SCL
	call 	Delay4us
	SET_BANK1
	bcf		SCL_T		; SCL low (output)
	SET_BANK0

	return
;---------------------------------------------------------------
;load Prefs
;loads Preferences from internal eeprom if valid config is saved
;in eeprom. Set to default values otherwise
;---------------------------------------------------------------
load_prefs
	clrf	eprom_adr		;read pos 0 =valid-check
	call	eprom_read
	xorlw	0x55
	skpz					;go on if config is valid
	goto	load_prefs_def	;set to defaults otherwise
	;config is valid, now load them
	incf	eprom_adr,f		;next
	call	eprom_read
	movwf	vmode
	goto	load_prefs_end
load_prefs_def			;set default to prefs
	;bsf		configerr	;if we got here, config in eeprom is not valid
    movlw   0x00
    movwf   vmode
load_prefs_end
	return
;---------------------------------------------------------------
;save_Prefs
; save Preferences to internal eeprom
;---------------------------------------------------------------
save_prefs
	clrf	eprom_adr		;begin saving at pos 0
	movlw	0x55			;valid config marker
	movwf	eprom_dat
	call	eprom_write
	;only mode to be saved
	movf	vmode,w
	movwf	eprom_dat
	incf	eprom_adr,f
	call	eprom_write
	return
;---------------------------------------------------------------
;EEPROM handling routines
;---------------------------------------------------------------
;eprom read: Address in eprom_adr, return value in w
;---------------------------------------------------------------
eprom_read
	bcf		PIR2, EEIF		;clear interrupt flag (necessary?)
	movf	eprom_adr,w		;Set adress of read
	banksel	EEADR
	movwf	EEADR

	banksel	EECON1
	bcf		EECON1,EEPGD	;we want to read data mem
	bsf		EECON1,RD		;init read
	banksel	EEDAT
	movf	EEDAT,w
	bcf		STATUS,RP0		;back to bank 0 (our standard)
	bcf		STATUS,RP1
	return
;-------------------------------------------------------------------------
;eprom write Address in eprom_adr, data in eprom_dat returns when finished
;-------------------------------------------------------------------------
eprom_write
	bcf		PIR2, EEIF		;clear interrupt (to be sure)
	movf	eprom_adr,w		;load Adress
	banksel	EEADR
	movwf	EEADR
	banksel	0x00
	movf	eprom_dat,w	;load value
	banksel	EEDAT
	movwf	EEDAT
	banksel	EECON1
	bcf		EECON1,EEPGD	;we want to write data mem
	bsf		EECON1,WREN		;enable write

	bcf		INTCON,GIE		;we don't want interrupts now
	;btfsc	INTCON,GIE		;make sure it is really cleared
	;goto	$-2
	movlw	0x55			;see datasheet, required sequence
	movwf	EECON2
	movlw	0xaa
	movwf	EECON2
	bsf		EECON1,WR		;set write bit to begin write
	bsf		INTCON,GIE		;re-enable global interrupts

	banksel	0x00			;back to Bank0 (our default)
	btfss	PIR2,EEIF		;wait for flag to be set (polling)
	goto	$-1
	bcf		PIR2,EEIF		;clear it, write complete

	banksel	EECON1
	bcf		EECON1,WREN		;clear write enable
	banksel	0x00
	
	return
;--------------------------------------------------------------------
;Delay-Subroutines (for fosc 20MHz)
;--------------------------------------------------------------------
Delay4us		;used in I2C routines
	movlw	0x06
	movwf	d1
Delay4us_1
	decfsz	d1, f
	goto		Delay4us_1
	nop
	return
;-----
Delay10us					;Delays ca. 10us
	movlw	0x10
	movwf	d1
Delay10us_1
	decfsz	d1, f
	goto		Delay10us_1
	nop
	return
;-----
Delay25us					;Delays ca. 25us
	movlw	0x29
	movwf	d1
Delay25us_1
	decfsz	d1, f
	goto		Delay25us_1
	nop
	return
;-----
Delay100us					;Delays ca. 100us
	movlw	0xA5
	movwf	d1
Delay100us_1
	decfsz	d1, f
	goto		Delay100us_1
	return
;-----
Delay4ms					;Delays ca.4ms
			;19998 cycles
	movlw	0x9F
	movwf	d1
	movlw	0x10
	movwf	d2
Delay4ms_1
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	Delay4ms_1
	goto	$+1
	return
;-----
Delay10ms					;Delays ca.10ms
	movlw	0x0E
	movwf	d1
	movlw	0x28
	movwf	d2
Delay10ms_1
	decfsz	d1, f
	goto		$+2
	decfsz	d2, f
	goto		Delay10ms_1
	goto	$+1
	nop
	return
;-----
Delay100ms					;Delays ca.100ms
	movlw	0x03
	movwf	d1
	movlw	0x18
	movwf	d2
	movlw	0x02
	movwf	d3

Delay100ms_1
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	$+2
	decfsz	d3,f
	goto	Delay100ms_1
	goto		$+1
	goto		$+1
	goto		$+1	
	return
;#########################################################################
	org	0x800	;define next in memory Page 1 (so we have space in Page 0)
;#########################################################################
;---------------------------------------------------------
;Tables are short enough to ensure that no rollover from 0xff to 0x00 happens
;within these tables - otherwise the code above has to be modified
;
circletable		;part1: outer circle, part2: inner circle for 5-min-markings
	addwf	PCL,f
	;x outer circle
	dt 0x80,0x8D,0x9A,0xA7,0xB3,0xBF,0xCA,0xD5,0xDE,0xE7,0xEE,0xF4,0xF9,0xFC,0xFE,0xFF
	dt 0xFE,0xFC,0xF9,0xF4,0xEE,0xE7,0xDE,0xD5,0xCA,0xBF,0xB3,0xA7,0x9A,0x8D,0x80,0x72
	dt 0x65,0x58,0x4C,0x40,0x35,0x2A,0x21,0x18,0x11,0x0B,0x06,0x03,0x01,0x00,0x01,0x03
	dt 0x06,0x0B,0x11,0x18,0x21,0x2A,0x35,0x40,0x4C,0x58,0x65,0x72,0x00,0x00,0x00,0x00
	;y outer circle (+64)
	dt 0xFF,0xFE,0xFC,0xF9,0xF4,0xEE,0xE7,0xDE,0xD5,0xCA,0xBF,0xB3,0xA7,0x9A,0x8D,0x80
	dt 0x72,0x65,0x58,0x4C,0x40,0x35,0x2A,0x21,0x18,0x11,0x0B,0x06,0x03,0x01,0x00,0x01
	dt 0x03,0x06,0x0B,0x11,0x18,0x21,0x2A,0x35,0x40,0x4C,0x58,0x65,0x72,0x7F,0x8D,0x9A
	dt 0xA7,0xB3,0xBF,0xCA,0xD5,0xDE,0xE7,0xEE,0xF4,0xF9,0xFC,0xFE,0x00,0x00,0x00,0x00
	;x inner circle (+128)
	dt 0x80,0x8B,0x97,0xA3,0xAE,0xB9,0xC3,0xCC,0xD5,0xDC,0xE3,0xE8,0xED,0xF0,0xF2,0xF2
	dt 0xF2,0xF0,0xED,0xE8,0xE3,0xDC,0xD5,0xCC,0xC3,0xB9,0xAE,0xA3,0x97,0x8B,0x80,0x74
	dt 0x68,0x5C,0x51,0x46,0x3C,0x33,0x2A,0x23,0x1C,0x17,0x12,0x0F,0x0D,0x0D,0x0D,0x0F
	dt 0x12,0x17,0x1C,0x23,0x2A,0x33,0x3C,0x46,0x51,0x5C,0x68,0x74,0x00,0x00,0x00,0x00
	;y inner circle (+192)
	dt 0xF2,0xF2,0xF0,0xED,0xE8,0xE3,0xDC,0xD5,0xCC,0xC3,0xB9,0xAE,0xA3,0x97,0x8B,0x80
	dt 0x74,0x68,0x5C,0x51,0x46,0x3C,0x33,0x2A,0x23,0x1C,0x17,0x12,0x0F,0x0D,0x0D,0x0D
	dt 0x0F,0x12,0x17,0x1C,0x23,0x2A,0x33,0x3C,0x46,0x51,0x5C,0x68,0x74,0x7F,0x8B,0x97
	dt 0xA3,0xAE,0xB9,0xC3,0xCC,0xD5,0xDC,0xE3,0xE8,0xED,0xF0,0xF2,0x00,0x00,0x00

circletable1	;part1: inner circle for hour-clock hand, part2: inner circle for beginning of hands
	addwf	PCL,f
	;x
	dt 0x80,0x89,0x93,0x9D,0xA6,0xAF,0xB8,0xBF,0xC7,0xCD,0xD2,0xD7,0xDA,0xDD,0xDF,0xDF
	dt 0xDF,0xDD,0xDA,0xD7,0xD2,0xCD,0xC7,0xBF,0xB8,0xAF,0xA6,0x9D,0x93,0x89,0x80,0x76
	dt 0x6C,0x62,0x59,0x50,0x47,0x40,0x38,0x32,0x2D,0x28,0x25,0x22,0x20,0x20,0x20,0x22
	dt 0x25,0x28,0x2D,0x32,0x38,0x40,0x47,0x50,0x59,0x62,0x6C,0x76,0x00,0x00,0x00,0x00
	;y
	dt 0xDF,0xDF,0xDD,0xDA,0xD7,0xD2,0xCD,0xC7,0xBF,0xB8,0xAF,0xA6,0x9D,0x93,0x89,0x80
	dt 0x76,0x6C,0x62,0x59,0x50,0x47,0x40,0x38,0x32,0x2D,0x28,0x25,0x22,0x20,0x20,0x20
	dt 0x22,0x25,0x28,0x2D,0x32,0x38,0x40,0x47,0x50,0x59,0x62,0x6C,0x76,0x7F,0x89,0x93
	dt 0x9D,0xA6,0xAF,0xB8,0xBF,0xC7,0xCD,0xD2,0xD7,0xDA,0xDD,0xDF,0x00,0x00,0x00,0x00
	;x
	dt 0x80,0x80,0x81,0x81,0x82,0x83,0x83,0x84,0x84,0x85,0x85,0x85,0x86,0x86,0x86,0x86
	dt 0x86,0x86,0x86,0x85,0x85,0x85,0x84,0x84,0x83,0x83,0x82,0x81,0x81,0x80,0x80,0x7F
	dt 0x7E,0x7E,0x7D,0x7C,0x7C,0x7B,0x7B,0x7A,0x7A,0x7A,0x79,0x79,0x79,0x79,0x79,0x79
	dt 0x79,0x7A,0x7A,0x7A,0x7B,0x7B,0x7C,0x7C,0x7D,0x7E,0x7E,0x7F,0x00,0x00,0x00,0x00
	;y
	dt 0x86,0x86,0x86,0x86,0x85,0x85,0x85,0x84,0x84,0x83,0x83,0x82,0x81,0x81,0x80,0x80
	dt 0x7F,0x7E,0x7E,0x7D,0x7C,0x7C,0x7B,0x7B,0x7A,0x7A,0x7A,0x79,0x79,0x79,0x79,0x79
	dt 0x79,0x79,0x7A,0x7A,0x7A,0x7B,0x7B,0x7C,0x7C,0x7D,0x7E,0x7E,0x7F,0x80,0x80,0x81
	dt 0x81,0x82,0x83,0x83,0x84,0x84,0x85,0x85,0x85,0x86,0x86,0x86,0x00,0x00,0x00

zifftable	
;numbers - high nibble x, low nibble y, always 4 bits: xxxxyyyy
;charsize 8x16
;reads from...to; max 16 entries per char, endmarker 0xff if necessary
;chars: 0123456789.:[bottom]:[top][Ant][sync]
	addwf	PCL,f
	dt 0x20,0x02,0x0D,0x2F,0x5F,0x7D,0x72,0x50,0x20,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
	dt 0x1C,0x4F,0x40,0x10,0x70,0x40,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
	dt 0x0D,0x2F,0x5F,0x7D,0x7A,0x03,0x00,0x70,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
	dt 0x0D,0x2F,0x5F,0x7D,0x7A,0x58,0x38,0x58,0x76,0x72,0x50,0x20,0x02,0xFF,0xFF,0xFF

	dt 0x77,0x07,0x6F,0x60,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
	dt 0x02,0x20,0x50,0x72,0x76,0x58,0x08,0x0F,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
	dt 0x17,0x28,0x58,0x76,0x72,0x50,0x20,0x02,0x0D,0x2F,0x5F,0x6E,0xFF,0xFF,0xFF,0xFF
	dt 0x20,0x24,0x7D,0x7F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF

	dt 0x28,0x0A,0x0D,0x2F,0x5F,0x7D,0x7A,0x58,0x76,0x72,0x50,0x20,0x02,0x06,0x28,0x58
	dt 0x69,0x58,0x28,0x0A,0x0D,0x2F,0x5F,0x7D,0x72,0x50,0x20,0x11,0xFF,0xFF,0xFF,0xFF
	dt 0x30,0x32,0x52,0x50,0x30,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
	dt 0x33,0x35,0x55,0x53,0x33,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF

	dt 0x39,0x3B,0x5B,0x59,0x39,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
	dt 0x40,0x47,0x1C,0x47,0x7C,0x47,0x4D,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
	dt 0x20,0x50,0x53,0x23,0x26,0x56,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
	dt 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF

	end
