;***************************************
;***    U6223B u_pll - micro PLL     ***
;***   Assembler AS (public domain)  ***
;***************************************
		CPU	16C54

ident		macro	
		DATA	"u_PLL 1.1 08.03.96 DF1OG"
		endm

;***************************************
;allocation special registers:
;***************************************
Indirect	SFR	$00		;virtual indirect register
RTCC		SFR	$01		;realtime clock/counter
PClo		SFR	$02		;program counter low
Status		SFR	$03		;status register
FSR		SFR	$04		;file select register
Port_A		SFR	$05		;port A
Port_B		SFR	$06		;port B

;---------------------------------------
;allocation status register flags:
;---------------------------------------
Flag_C		EQU	0		;carry flag
Flag_DC		EQU	1		;digit carry flag
Flag_Z		EQU	2		;zero flag

;---------------------------------------
;destination register:
;---------------------------------------
w		EQU	0		;destination w register
f		EQU	1		;destination f register

		LISTING OFF
;---------------------------------------
;some flag operations...
;---------------------------------------
clrc		macro			;clear carry flag
		bcf	Status,Flag_C
		endm

setc		macro			;set carry flag
		bsf	Status,Flag_C
		endm

clrdc		macro			;clear digit carry flag
		bcf	Status,Flag_DC
		endm

setdc		macro			;set digit carry flag
		bsf	Status,Flag_DC
		endm

clrz		macro			;clear zero flag
		bcf	Status,Flag_Z
		endm

setz		macro			;set zero flag
		bcf	Status,Flag_Z
		endm

;---------------------------------------
;simple program skips... 
;---------------------------------------
skpc		macro			;skip on carry=1
		btfss	Status,Flag_C
		endm

skpnc		macro			;skip on carry=0
		btfsc	Status,Flag_C
		endm

skpdc		macro			;skip on digit carry=1
		btfss	Status,Flag_DC
		endm

skpndc		macro			;skip on digit carry=0
		btfsc	Status,Flag_DC
		endm

skpz		macro			;skip on zero=1
		btfss	Status,Flag_Z
		endm

skpnz		macro			;skip on zero=0
		btfsc	Status,Flag_Z
		endm

;---------------------------------------
;conditional branches...
;be careful! multiple byte code, not skipable!
;---------------------------------------
b		macro	target		;branch always
		goto	target
		endm

bc		macro	target		;branch on carry=1
		btfsc	Status,Flag_C
		goto	target
		endm

bnc		macro	target		;branch on carry=0
		btfss	Status,Flag_C
		goto	target
		endm

bdc		macro	target		;branch on digit carry=1
		btfsc	Status,Flag_DC
		goto	target
		endm

bndc		macro	target		;branch on digit carry=0
		btfss	Status,Flag_DC
		goto	target
		endm

bz		macro	target		;branch on zero=1
		btfsc	Status,Flag_Z
		goto	target
		endm

bnz		macro	target		;branch on zero=0
		btfss	Status,Flag_Z
		goto	target
		endm

bbs		macro	source,bit,target	;branch on bit set
		btfsc	source,bit
		goto	target
		endm

bbns		macro	source,bit,target	;branch on bit not set
		btfss	source,bit
		goto	target
		endm

;--------------------------------------- 
;loops...
;be careful again!
;---------------------------------------
dfbnz		macro	source,target	;decrement and branch if not zero
		decfsz	source,f
		goto	target
		endm

;--------------------------------------- 
;carry arithmetic...
;be careful again!
;---------------------------------------
addcf		macro	reg,dest	;add carry to register
		btfsc	Status,Flag_C
		incf	reg,dest
		endm

subcf		macro	reg,dest	;subtract carry from register
		btfsc	Status,Flag_C
		decf	reg,dest
		endm

adddcf		macro	reg,dest	;add digit carry to register
		btfsc	Status,Flag_DC
		incf	reg,dest
		endm

subdcf		macro	reg,dest	;subtract digit carry from register
		btfsc	Status,Flag_DC
		decf	reg,dest
		endm

;---------------------------------------
;misancelous...
;---------------------------------------
movfw		macro	reg		;transfer register --> w
		movf	reg,w
		endm

negf		macro	reg,dest	;two's complement
		comf	reg,f
		incf	reg,dest
		endm

tstf		macro	reg		;set flags due to register
		movf	reg,f
		endm

		LISTING ON

;***************************************
;constant and storage definitions
;***************************************
kc100_10l	EQU	$0a		;100 kc binary conversion
kc100_10h	EQU	$00
kc100_100l	EQU	$64
kc100_100h	EQU	$00
kc100_1000l	EQU	$e8
kc100_1000h	EQU	$03
kc100_10000l	EQU	$10
kc100_10000h	EQU	$27

kc125_10l	EQU	$08		;125 kc binary conversion
kc125_10h	EQU	$00
kc125_100l	EQU	$50
kc125_100h	EQU	$00
kc125_1000l	EQU	$20
kc125_1000h	EQU	$03
kc125_10000l	EQU	$40
kc125_10000h	EQU	$1F

AdrByte		EQU	$c2		;pll address byte: device address open
CtrlByte1	EQU	$c6		;control byte 1: hi current, scale 512
CtrlByte2	EQU	$00		;control byte 2: hi impedance outputs

;---------------------------------------
		SEGMENT	DATA
		ORG	$08

R0		RES	1		;general purpose register 0
R1		RES	1		;general purpose register 1
R2		RES	1		;general purpose register 2

Kc100		RES	1		;frequency bcd values 100/125 kc
Mc1		RES	1		;		 	    1 mc
Mc10		RES	1		;			   10 mc
Mc100		RES	1		;			  100 mc
Mc1000		RES	1		;			 1000 mc

Control		RES	1		;bit 2 off 100 kc steps
					;       on 125 kc steps

SwChange	RES	1		;switch change check
					
DevAdr		RES	1		;device address
PDB1		RES	1		;program divider byte 1
PDB2		RES	1		;program divider byte 2
CB1		RES	1		;control byte 1
CB2		RES	1		;control byte 2

;***************************************
		SEGMENT	CODE
		ORG	$000

Start:		b	Init		;subroutines in first 256 code bytes

;***************************************
;scan switches
;***************************************
ScanSw:		movlw	Kc100		;set pointer to freq. registers
		movwf	FSR
		
		movlw	5		;five switches to scan
		movwf	R0

		movlw	%11111110	;start with low significant switch
		movwf	R1

ScanSw10:	movfw	R1		;put scan information onto port
		movwf	Port_B
		tris	Port_B

		movfw	Port_B		;read scan information bits 0-2
		andlw	%11100000
		movwf	Indirect
		swapf	Indirect,f
		clrc
		rrf	Indirect,f

		movfw	Port_A		;read scan information bit 3
		movwf	R2
		rlf	R2,w
		andlw	%00001000

		iorwf	Indirect,f	;combine bits to negative logic
		movlw	%00001111
		xorwf	Indirect,f

		setc			;prepare next scan
		rlf	R1,f

		incf	FSR,f

		dfbnz	R0,ScanSw10	;all switches scaned?
		
ScanSw99:	retlw	0

;***************************************
;set pll data using i2c protocol
;***************************************
SetPLL:		movlw	DevAdr		;set pointer to pll data
		movwf	FSR
		movlw	5		;5 bytes have to be transfered
		movwf	R0

		movlw	%11111101	;start condition
		tris	Port_A
		nop
		nop
		nop
		movlw	%11111100
		tris	Port_A

SetPLL10:	movlw	8		;set bit counter
		movwf	R1

SetPLL20:	rlf	Indirect,f	;carry flag stores the bit
		bc	SetPLL30

		movlw	%11111100	;set data low
		tris	Port_A
		call	ClkOut			
		b	SetPLL40

SetPLL30:	movlw	%11111110	;set data high
		tris	Port_A
		call	ClkOut		

SetPLL40:	dfbnz	R1,SetPLL20	;one byte transfered?

		movlw	%11111110	;handle acknowledge
		tris	Port_A
		call	ClkOut			

		rlf	Indirect,f	;now all has left correctly again
        	incf	FSR,f		;set pointer to next byte  
	
		dfbnz	R0,SetPLL10	;all bytes transfered?

		movlw	%11111100	;stop condition
		tris	Port_A
		movlw	%11111101
		tris	Port_A
		nop
		nop
		nop
		movlw	%11111111
		tris	Port_A

SetPLL99:	retlw	0			

;***************************************
ClkOut:		iorlw	%00000001	;set clock high
		tris	Port_A
		nop
		nop
		nop
		andlw	%11111110	;set clock low
		tris	Port_A

		retlw	0

;***************************************
SwChk:		movlw	-10		;check for greater than nine
		addwf	Indirect,w
		bnc	SwChk99
		
		movlw	9		;if greater set to nine
		movwf	Indirect

SwChk99:	retlw	0

;***************************************
AddPDB:		movfw	R0		;do while not zero...
		bz	AddPDB99

		movfw	R2		;add LSBs
		addwf	PDB2,f
		addcf	PDB1,f		;add carry to MSB
		movfw	R1		;add MSBs
		addwf	PDB1,f

		decf	R0,f		;decrement loop count		
		b	AddPDB		;loop...

AddPDB99:	retlw	0

;***************************************
		ident			;include identification

;***************************************
;start of main program...
;***************************************
		ORG	$100

Init:		movlw	%11111100	;prepare SDA and SCL ports
		movwf	Port_A

		clrf	Kc100		;clear freq. registers		
		clrf	Mc1
		clrf	Mc10
		clrf	Mc100
		clrf	Mc1000
		clrf	Control
		clrf	SwChange	;initiate freq. setting
		decf	SwChange,f

;---------------------------------------
;main program loop
;---------------------------------------
Main:		call	ScanSw		;scan switches

;.......................................
		movlw	Mc1000		;mask out 1000 mc
		movwf	FSR
		movfw	Indirect
		movwf	Control
		andlw	%00000011	;bit 0-1 frequency
		movwf	Indirect
		movlw	%00000100	;bit 2 control
		andwf	Control,f
		
		decf	FSR,f		;check for valid BCD
		call	SwChk		;100 mc

		decf	FSR,f
		call	SwChk		;10 mc

		decf	FSR,f
		call	SwChk		;1 mc
					
		decf	FSR,f		  ;Kc100 mustn't exceed 9 at 100 kc
		bbs	Control,2,Main10  ;and mustn't exceed 7 at 125 kc steps

		call	SwChk		;100 kc steps
		b	Main20

Main10:		movlw	-8		;125 kc steps
		addwf	Indirect,w
		bnc	Main20
		
		movlw	7		;if greater than seven set to seven
		movwf	Indirect

;.......................................
Main20:		movlw	Kc100		;check for switch change
		movwf	FSR

		clrw			;add frequency and control values
		addwf	Indirect,w	;100 kc

		incf	FSR,f
		addwf	Indirect,w	;1 mc

		incf	FSR,f
		addwf	Indirect,w	;10 mc

		incf	FSR,f
		addwf	Indirect,w	;100 mc

		incf	FSR,f
		addwf	Indirect,w	;1000 mc

		incf	FSR,f
		addwf	Indirect,w	;control

		incf	FSR,f
		xorwf	Indirect,f	;compare to old switch change check
		movwf	Indirect	;store new change check
		bz	Main		;no change, back to main loop...

;.......................................
		clrf	PDB1		;convert 100/125 kc into binary format
			
		movfw	Kc100		;100/125 kc		
		movwf	PDB2

		bbs	Control,2,Main30 ;100/125 kc steps?

		movfw	Mc1		;100 kc steps 1 mc 
		movwf	R0
		movlw	kc100_10h
		movwf	R1
		movlw	kc100_10l
		movwf	R2
		call	AddPDB

		movfw	Mc10		;10 mc
		movwf	R0
		movlw	kc100_100h
		movwf	R1
		movlw	kc100_100l
		movwf	R2
		call	AddPDB

		movfw	Mc100		;100 mc
		movwf	R0
		movlw	kc100_1000h
		movwf	R1
		movlw	kc100_1000l
		movwf	R2
		call	AddPDB

		movfw	Mc1000		;1000 mc
		movwf	R0
		movlw	kc100_10000h
		movwf	R1
		movlw	kc100_10000l
		movwf	R2
		call	AddPDB
	
		b	Main40

Main30:		movfw	Mc1		;125 kc steps 1 mc
		movwf	R0
		movlw	kc125_10h
		movwf	R1
		movlw	kc125_10l
		movwf	R2
		call	AddPDB

		movfw	Mc10		;10 mc
		movwf	R0
		movlw	kc125_100h
		movwf	R1
		movlw	kc125_100l
		movwf	R2
		call	AddPDB

		movfw	Mc100		;100 mc
		movwf	R0
		movlw	kc125_1000h
		movwf	R1
		movlw	kc125_1000l
		movwf	R2
		call	AddPDB

		movfw	Mc1000		;1000 mc
		movwf	R0
		movlw	kc125_10000h
		movwf	R1
		movlw	kc125_10000l
		movwf	R2
		call	AddPDB

;.......................................
Main40:		movlw	AdrByte		;load pll parameter
		movwf	DevAdr
		movlw	CtrlByte1	
		movwf	CB1
		movlw	CtrlByte2
		movwf	CB2
		call	SetPLL		;transfer pll data

		b	Main		;main loop...

;***************************************
		ORG	$1ff

		b	Start		;program start on reset

;***************************************
		END
