;	Signal Generator / 9/01 Luhan Monat
;Mode	Sine	Square	Triang	H-Pulse	L-Pulse	Sweep	Burst
;--------------------------------------------------------------
;F1		freq	freq	freq	freq	freq	freq	freq	
;F2				sym		sym		width	width	cycles	cycles
;F3												delta	rate

;Mode	Sine	Triand	Square	Saw		H-Pulse	L-Pulse	Burst	Sweep	Noise
;----------------------------------------------------------------------------
;F1		freq	freq	freq	freq	freq	freq	freq	freq	freq
;F2				sym		sym		?		width	width	cycles	cycles	?
;F3														rate	delta

 TITLE  "Function Generator"   	  
 List P=PIC16F870, R=DEC	
 INCLUDE "p16f870.inc"

  __CONFIG _CP_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF  & _PWRTE_ON & _WDT_OFF & _HS_OSC

 CBLOCK 0x20
 temp:3
 count	
 lights						;front panel light image
 del1, del2, del3
 val1, val2
 accum:3					;24 bit accumulator
 step:2						;16 bit
 vstep:2
 looper:2
 select						;select type of operation
 vrate						;rate of adjustment 
 mode						;type of waveform
 f1:3						;24 bit f1
 f2:2
 f3
 flags
 input
 ENDC

#define ROT		input,7		;rotary encoder
#define	BUT		input,6		;button
#define	SPD		input,5		;adjust rate
;#define	DIR		input,3		;encoder direction
#define	DIR		input,4		;encoder direction

#define	RACT	flags,0		;encoder active
#define	BACT	flags,1		;button active
#define	ON		flags,2
#define	SACT	flags,3		;rate active
#define	GEN		flags,4		;generate sinewave
#define	MEM		flags,5		; auxilary bit

#define	FILT	PORTB,2		;bypass filter network

#define	SRDAT	PORTA,0		;shift register data
;#define	SRCLK	PORTA,1		;s/r clock
#define	SRCLK	PORTA,5		;s/r clock
#define	SYNCO	PORTA,3		;sync output
MAXMODE	EQU	9

 ORG 0
	goto	start
	nop
	nop
	nop

 ORG 4						; go here on interrupt of port 7
	nop
	btfss	INTCON, T0IF	;timeout?
	 retfie					;no - disallow interrupt process
		
	clrf	PCLATH
	bcf		STATUS, RP0		; select BANK 0
	bcf		STATUS, RP1

no	movlw	100				;must match 10 times
	movwf	count
	movf	PORTB, w		;clear the interrupt source
	xorlw	0xff			;invert bits
	movwf	input

chk	movf	PORTB, w
	xorlw	0xff
	xorwf	input, w
	btfss	STATUS, Z		;same?
	 goto	no				;start count over
	decfsz	count, f
	 goto	chk
	bcf		INTCON, RBIF	;clear the flag bit
	goto	contin			

lmask	
	movf	select, w
	btfsc	SPD
	 movf	vrate,w
	addwf	PCL, f
	retlw	4
	retlw	2
	retlw	1
	retlw	0

vrvals	
	addwf	PCL, f
	retlw	HIGH 33539 
	retlw	LOW 33539
	retlw	HIGH 500 
	retlw	LOW 500
	retlw	HIGH 1676
	retlw	LOW 1676 
	retlw	HIGH 25
	retlw	LOW 25
	retlw	HIGH 67
	retlw	LOW 67
	retlw	HIGH 1 
	retlw	LOW 1
	

selmsk	
	addwf	PCL, f
	retlw	4
	retlw	2
	retlw	1
	
vrmask	
	addwf	PCL, f
	retlw	0x20
	retlw	0x10
	retlw	8
		

start	
	bsf		STATUS, RP0
	movlw	b'000010'
	movwf	TRISA ^ 0x80
	movlw	b'11111000'
	movwf	TRISB ^ 0x80
	movlw	0
	movwf	TRISC ^ 0x80
	movlw	b'00000111'			; 256 count prescale to timer-0
	movwf	OPTION_REG ^ 0x80	; rb<4:7> pull ups
	movlw	6
	movwf	ADCON1 ^ 0x80		;all digital bits
	bcf		STATUS, RP0

	movlw	0xff
	movwf	PORTB
	movlw	0x88
	movwf	INTCON				;RB<4:7> interrupts enabled
	movlw	1
	movwf	f1
	clrf	f1+1
	clrf	f1+2
	clrf	step
	movlw	10
	movwf	step+1
	movlw	5
	movwf	f3
	movlw	50
	movwf	f2
	clrf	f2+1
	clrf	mode
	clrf	select
	clrf	vrate
	clrf	flags
	clrf	input
	call	lites
	call	dorate	

; continue here after controls are changed
contin	
;	bcf		MEM				; MEM = DIR
;	btfsc	DIR	
;	 bsf	MEM	
;	bcf		DIR				; DIR = ROT for my encoder
;	btfsc	ROT
;	 bsf	DIR
	btfsc	DIR				; ROT = ROT V DIR for my encoder
	 bsf	ROT

	btfss	SPD				;new rate?
	 goto	nr				; NO
	bsf		SACT			;speed active
	goto	done
nr	btfss	BUT				; SEL button down?
	 goto	adj				;no.
	bsf		BACT			;flag as active
	call	nolite
	btfss	ROT				;encoder active?
	 goto	done		
	bsf		RACT			;flag rotor active.
	btfsc	DIR				;which way?
	 goto	dec

inc	incf	mode, f
	movf	mode, w
	xorlw	MAXMODE			;too high?
	btfss	STATUS, Z		
	 goto	done			;no.
dec	decf	mode, f
	btfss	mode, 7			;underflow?
	 goto	done			;no.
	clrf	mode
	goto	done
adj	btfss	ROT				;encoder active?
	 goto	norot			;no.
	call	adjust
	goto	done

norot	
	btfss	SACT
	 goto	nos
	bcf		SACT
	call	newrate
	goto	lite	
nos	btfss	BACT			;previously hit?
	 goto	lite			;no.
	bcf		BACT
	btfsc	RACT			;was mode changed?
	 goto	lite			;no.
	incf	select, f
	movf	select, w
	xorlw	3				;too high
	btfsc	STATUS, Z
	 clrf	select			;wrap to zero
lite	
	bcf		RACT
	call	lites			;turn on light
	goto	done		

done	
	movlw	-250
	movwf	TMR0			; reset timer
	bcf		INTCON, T0IF	; clear TMR0 overflow flag
	bsf		INTCON, GIE		; enable interrupts
	nop

run	clrf	PCLATH
	movf	mode, w			;get the mode
	addwf	PCL, f			;compute the jump
	goto	sine
	goto	trian
	goto	square
	goto	saw
	goto	hpulse
	goto	lpulse
	goto	burst
	goto	sweep
	goto	noise
	goto	start			;just in case!

newrate	
	incf	vrate, f
dorate	
	movf	vrate, w
	xorlw	3
	btfsc	STATUS, Z
	 clrf	vrate			; taking vrate (mod 3)
	movf	vrate, w
	movwf	temp
	bcf		STATUS, C	
	rlf		temp, f
	bcf		STATUS, C
	rlf		temp, f			; vrate *= 4
	movf	temp, w			; setup step:2 from table
	call	vrvals
	movwf	step
	incf	temp, f
	movf	temp, w
	call	vrvals
	movwf	step+1
	incf	temp, f			; setup vstep:2 from table (500, 25, 0r 1)
	movf	temp, w
	call	vrvals
	movwf	vstep
	incf	temp, f
	movf	temp, w
	call	vrvals
	movwf	vstep+1
	return


sine	
	bsf		FILT
	movlw	3
	movwf	PCLATH
nxt1	
	movf	f1, w			; accum += f1 (3 bytes addition)	
	addwf	accum, f		; f1 = 1
	movf	f1+1, w
	btfsc	STATUS, C
	 incfsz	f1+1, w
	  addwf	accum+1, f
	movf	f1+2, w
	btfsc	STATUS, C
	 incfsz	f1+2,w
	  addwf	accum+2, f
	movf	accum+2, w	
	call	getsv			; get sine value
	movwf	PORTC			; output it
	goto	nxt1			; 
	

trian	
	bsf		FILT
nxt2	
	movf	f1, w
	addwf	accum, f
	movf	f1+1, w
	btfsc	STATUS, C
	 incfsz	f1+1, w
	  addwf	accum+1, f
	movf	f1+2, w
	btfsc	STATUS, C
	 incfsz	f1+2, w
	  addwf	accum+2, f
	movf	accum+2, w
	addwf	accum+2, w
	btfsc	STATUS, C
	 sublw	255
	movwf	PORTC
	nop
	nop
	nop
	goto	nxt2
	

square	
	bcf		FILT
;clr1	
	clrf	accum
	clrf	accum+1
	clrf	accum+2
nxt3	
	movf	f1, w
	addwf	accum, f
	movf	f1+1, w
	btfsc	STATUS, C
	 incfsz	f1+1, w
	  addwf	accum+1, f
	movf	f1+2, w
	btfsc	STATUS, C
	 incfsz	f1+2, w
	  addwf	accum+2, f
	nop
	nop
	nop
	nop
	clrw
	btfsc	accum+2, 7
	 movlw	255
	movwf	PORTC
	goto	nxt3

	
saw	bcf		FILT
nxt4	
	movf	f1, w
	addwf	accum, f
	movf	f1+1, w
	btfsc	STATUS, C
	 incfsz	f1+1, w
	  addwf	accum+1, f
	movf	f1+2, w
	btfsc	STATUS, C	
	 incfsz	f1+2, w
	  addwf	accum+2, f
	movf	accum+2, w
	nop
	nop
	nop
	nop
	nop
	nop
	movwf	PORTC
	goto	nxt4
	
hpulse	
	movlw	255
	movwf	val1
	clrf	val2
	goto	pulse
lpulse	
	movlw	255
	movwf	val2
	clrf	val1
pulse	
	bcf		FILT
lp	movf	val1, w
	movwf	PORTC				;start pulse
	movf	f2, w
	movwf	temp
	movf	f2+1, w
	movwf	temp+1
	call	time
	movf	val2, w
	movwf	PORTC				;end of pulse
	movf	f1, w
	movwf	temp
	movf	f1+1, w
	movwf	temp+1
	movf	f1+2, w
	movwf	temp+2
	call	xtime
	goto	lp

	
sweep	
	bsf		FILT
	movlw	3
	movwf	PCLATH
	clrf	accum
	clrf	accum+1
	clrf	accum+2	
	bsf		GEN
	movf	f1, w 
	movwf	temp
	movf	f1+1, w
	movwf	temp+1
	movf	f1+2, w
	movwf	temp+2
	bsf		GEN
	bsf		SYNCO
	call	brst1
	bcf		GEN
	bcf		SYNCO
	call	brst1
	goto	sweep
	
brst1	
	movf	f3, w
	movwf	count
br2	clrf	accum+2
	incf	accum+2, f
	call	cycle		;do some cycles
	movf	f2,w
	addwf	temp, f
	btfsc	STATUS, C
	 incf	temp+1, f
	btfsc	STATUS, Z
	 incf	temp+2, f
	movf	f2+1, w
	addwf	temp+1, f
	btfsc	STATUS, C
	 incf	temp+2, f
	decfsz	count, f
	 goto	br2
	return

burst	
	bsf		FILT
	movlw	3
	movwf	PCLATH
	clrf	accum
	clrf	accum+1
	clrf	accum+2	
	bsf		SYNCO			;start of sync
	movf	f3, w
	movwf	count
	bsf		GEN
	movf	f1, w
	movwf	temp
	movf	f1+1, w
	movwf	temp+1
	movf	f1+2, w
	movwf	temp+2
brst2	
	clrf	accum+2
	incf	accum+2, f
	call	cycle			;do some cycles
	decfsz	count, f
	 goto	brst2
	bcf		SYNCO			;end of sync
	movlw	127
	movwf	PORTC
	bcf		GEN
	movf	f2, w
	movwf	del1
	movf	f2+1, w
	movwf	del2
	incf	del2, f
wait	
	clrf	accum+2
	incf	accum+2, f
	call	cycle
	decfsz	del1, f
	 goto	wait
	decfsz	del2, f
	 goto	wait
	goto	burst


cycle	
	movf	temp, w			;get low byte
	addwf	accum, f		;add to low byte
	btfsc	STATUS, C		;possible carry bit
	 incf	accum+1, f
	btfsc	STATUS, Z
	 incf	accum+2, f
	movf	temp+1, w
	addwf	accum+1, f
	btfsc	STATUS, C
	 incf	accum+2, f
	movf	temp+2, w
	addwf	accum+2, f
	btfsc	STATUS, C
	 return
	movf	accum+2, w
	btfsc	STATUS, Z
	 return
	call	getsv
	btfsc	GEN
	 movwf	PORTC
	goto	cycle

	

noise	
	call	pseudo
	movwf	PORTC
	movf	f2, w
	movwf	temp
	movf	f2+1, w
	movwf	temp+1
	call	time
	goto	noise

pseudo	
	movf	del1, w
	addwf	del2, w
	movwf	del2
	addwf	del3, w
	movwf	del3
	bcf		STATUS, C
	rlf		del3, f
	btfsc	STATUS, C
	 incf	del3, f
	addwf	del1, f
	return

	
adjust	
	movf	select, w
	btfsc	STATUS, Z
	 goto	f1s
	addlw	-1
	btfsc	STATUS, Z
	 goto	f2s

f3s	btfsc	DIR
	 goto	f3dn
	incfsz	f3, f
	 return
	decf	f3, f
	return
f3dn	
	decfsz	f3, f
	 return
	incf	f3, f
	return
	

f2s	btfsc	DIR				;which way
	 goto	f2dn
	movf	vstep, w
	addwf	f2, f
	btfsc	STATUS, C	
	 incf	f2+1, f
	movf	vstep+1, w
	addwf	f2+1, f
	btfss	f2+1, 7
	 return

f2dn	
	movf	vstep, w
	bsf		SYNCO
	subwf	f2, f
	movf	vstep+1, w
	btfss	STATUS, C
	incf	vstep+1, w
	subwf	f2+1, f
	btfss	f2+1, 7
	 return
	clrf	f2
	incf	f2, f
	clrf	f2+1
	bcf		SYNCO
	return


f1s	btfsc	DIR				;which way
	 goto	f1dn
	movf	step, w
	addwf	f1,f
	btfsc	STATUS, C
	 incf	f1+1, f
	btfsc	STATUS, Z
	 incf	f1+2, f
	movf	step+1, w
	addwf	f1+1, f
	btfsc	STATUS, C
	 incf	f1+2, f
	btfss	f1+2, 6			; should it be 7 ???
	 return

f1dn	
	movf	step, w
	subwf	f1, f
	movf	step+1, w
	btfss	STATUS, C
	 incfsz	step+1, w
	  subwf	f1+1, f
	btfss	STATUS, C
	 decf	f1+2, f
	btfss	f1+2, 7
	 return

clr2	
	clrf	f1
	clrf	f1+1
	clrf	f1+2
	return


xtime	
	movf	temp, w
	iorwf	temp+1, w
	iorwf	temp+2, w
	btfsc	STATUS, Z
	 return
	movlw	-1
	addwf	temp, f
	btfss	STATUS, C
	 addwf	temp+1, f
	btfss	STATUS, C
	 addwf	temp+2, f
	goto	xtime
		

; linear time delay del2/del1

time	
	movf	temp, w
	iorwf	temp+1, w
	btfsc	STATUS, Z
	 return
	movlw	-1
	addwf	temp, f
	btfss	STATUS, C
	 decf	temp+1, f
	goto	time
	
	
; approx 5ms/count
delay	
	movwf	del1
	clrf	del2
dx	nop
	nop
	decfsz	del2, f
	 goto	dx
	decfsz	del1, f
	 goto	dx
	return

nolite	
	clrf	temp
	goto	nosel

lites	
	movf	select, w
	call	selmsk			; w in {4, 2, 1} for lower LEDs 
	movwf	temp
nosel	
	movf	vrate, w
	call	vrmask			; w in {32, 16, 8} for upper LEDs
	iorwf	temp, f
	movlw	6
	movwf	count
	bcf		SRCLK
nxt	
	btfss	temp, 0			; shift the value into 74HC164 (6 bits)
	 bcf	SRDAT
	btfsc	temp, 0
	 bsf	SRDAT
	bsf		SRCLK
	bcf		SRCLK
	rrf		temp, f
	decfsz	count, f
	 goto	nxt
	return
	

flash	
	bsf		PORTA, 2
	movlw	200
	call	delay
	bcf		PORTA, 2
	movlw	200
	call	delay
	bsf		PORTA, 2
	return

 ORG 0x2ff

getsv	
	addwf	PCL, f
	
sintab	
	dt	127,130,133,136,139,142,145,148		;127
	dt	151,154,157,160,163,166,169,172
	dt	175,178,181,184,186,189,192,194
	dt	197,200,202,205,207,209,212,214
	dt	216,218,221,223,225,227,228,230
	dt	232,234,235,237,238,240,241,243
	dt	244,245,246,247,248,249,250,250
	dt	251,252,252,253,253,253,253,253
	dt	253,253,253,253,253,253,252,252
	dt	251,250,250,249,248,247,246,245
	dt	244,243,241,240,239,237,236,234
	dt	232,230,229,227,225,223,221,219
	dt	216,214,212,210,207,205,202,200
	dt	197,195,192,189,187,184,181,178
	dt	175,172,169,167,164,161,158,155
	dt	151,148,145,142,139,136,133,130
	dt	127,124,120,117,114,111,108,105
	dt	102,99,96,93,90,87,84,81
	dt	78,75,72,70,67,64,61,59
	dt	56,54,51,49,46,44,41,39
	dt	37,35,33,31,28,27,25,23
	dt	21,19,18,16,15,13,12,11
	dt	 9, 8, 7, 6, 5, 4, 3, 3
	dt	 2, 1, 1, 0, 0, 0, 0, 0
	dt	 0, 0, 0, 0, 0, 0, 1, 1
	dt	 2, 3, 3, 4, 5, 6, 7, 8
	dt	 9,10,12,13,14,16,17,19
	dt	21,22,24,26,28,30,32,34
	dt	36,39,41,43,46,48,51,53
	dt	56,58,61,64,66,69,72,75
	dt	78,80,83,86,89,92,95,98
	dt	101,104,107,111,114,117,120,123		;123

 END