;This is code for the EEConomizer engine control module.
;It is intended for carburetor conversion of a Ford EEC-IV fuel injection system.
;
;The EEConomizer controls ignition advance, egr flow, evap purge, and exhaust heat riser.
;It also has an output for a shift light that simulates the factory upshift light at 
;low throttle settings, then reverts to a conventional shift light at WOT.
;In addition to the shift light, there is also an economizer light that is set to come on
;at the same point that the power valve opens.
;
;It utilizes the Ford PIP, ECT, and MAP sensors. The TPS function is replaced with a 
;vacuum switch hooked to the "ported" source on the carburetor. The switch should be
;set to apply power to the Idle_In pin when vacuum drops below the power valve opening point.
;The EEConomizer can tell whether it's closed throttle or WOT by reading the MAP sensor.
;
;The code was written to use a PFE sensor to monitor EGR flow instead of an EVP sensor.
; 
;The SPOUT signal is CCD so a "black" TFI module can be used.
;
;The EEConomizer can interface with a separate hand-held programmer so that ignition
;timing and EGR flow can be adjusted while driving.
;
;Written by Brett Riggs (mrriggs), www.gofastforless.com




		DEVICE	SX28L,oschs2,TURBO
		DEVICE  stackx_optionx;,watchdog
		RESET	Start_Jump
		FREQ 	64_000_000

;### CALIBRATION CONSTANTS ###
ECT_EHC		EQU	136		;~86F
ECT_Cold	EQU	76		;~130F
ECT_Hot		EQU	20		;~220F
Shft_Cru_OnH	EQU	$1D
Shft_Cru_OnL	EQU	$4C		;2000rpm
Shft_Cru_OffH	EQU	$20
Shft_Cru_OffL	EQU	$8D		;1800rpm
Shft_Pow_OnH	EQU	$0D
Shft_Pow_OnL	EQU	$05		;4500rpm
Shft_Pow_OffH	EQU	$0D
Shft_Pow_OffL	EQU	$A0		;4300rpm
Rev_LimitH	EQU	$0B
Rev_LimitL	EQU	$B8		;5000rpm
Dwell_Time	EQU	12		;12 / 4 = 3mS
Fire_Time	EQU	4		;4 / 4 = 1mS
;#############################

Global		EQU	$08
CALC		EQU	$10
MATH		EQU	$30
InOut		EQU	$50
PowCurve	EQU	$70
CruCurve	EQU	$90
CALIBRATE	EQU	$B0
;Mem_7		EQU	$D0
;Mem_8		EQU	$F0

	org 	Global
flags		ds	1
Clock		ds	2
Variable	ds	2	
Turn_Coil_On	ds	1
Turn_Coil_Off	ds	2
	org	CALC	
Next_Period	ds	2
Last_Period	ds	2
Advance		ds	1
Pow_Adv		ds	1
Cru_Adv		ds	1
Hold_Bank	ds	1
No_Bounce	ds	1
Hold_Accel	ds	1
	org	MATH
X_var		ds	3
Y_var		ds	3
Z_var		ds	3
counter		ds	1
Int_X1		ds	2
Int_X2		ds	2
Int_Y1		ds	1
Int_Y2		ds	1
	org	InOut
MAP_Delay	ds	1
MAP_Hold	ds	1
MAP_Value	ds	1
PFE_Delay	ds	1
PFE_Count	ds	1
PFE_Hold	ds	1
PFE_Value	ds	1
EGR_Delay	ds	1
EGR_Count   	ds	1
EGR_Value	ds	1
ECT_Delay	ds	1
ECT_Count	ds	1
ECT_Hold	ds	1
ECT_Value	ds	1
	org	PowCurve
Adv_1k		ds	1
Adv_1k5		ds	1
Adv_2k		ds	1
Adv_2k5		ds	1
Adv_3k		ds	1
Adv_4k		ds	1
	org	CALIBRATE
Idle_Adv	ds	1
PFE_Target	ds	1
Fine_Tune	ds	1
Pow_Vac		ds	1
Cru_Vac		ds	1
Econ_Light	ds	1

ECT_Cal		EQU	ra.0 		;ADC calibration output
ECT_In		EQU	ra.1 		;ADC input, engine coolant temp sensor voltage
PFE_Cal 	EQU	ra.2 		;ADC calibration output
PFE_In		EQU	ra.3 		;ADC input, EGR pressure feedback sensor voltage
Spark_In	EQU	rb.0		;high = dwell, low = fire
Bypass		EQU	rb.1		;high = ECU control, low = ECU bypassed
Spark_Out	EQU	rb.2		;PIP is inverted, low = fire, high = reset
Shift_Out	EQU	rb.3 		;high = shift light on
Eco_Out		EQU	rb.4 		;high = economizer light on
EGR_Out		EQU	rb.5 		;PWM signal out, high = EGR open
Purge_Out	EQU	rb.6 		;high = purge valve open
EHC_Out		EQU	rb.7 		;high = exhaust heat valve closed
Idle_In		EQU	rc.0		;high = closed or WOT, low = part throttle 
MAP_In		EQU	rc.1 		;MAP sensor frequency input 
HHP		EQU	rc.2		;input from HHP
ECU		EQU	rc.3		;output to HHP
Data		EQU	rc.4		;input from HHP
DL		EQU	rc.5		;output to HHP
;unused		EQU	rc.6 
;unused		EQU	rc.7

Rise_Flag	EQU	flags.0		;set on Spark_In rising edge, cleared on falling edge 
Fall_Flag	EQU	flags.1		;set on Spark_In falling edge, cleared on rising edge
Memory_Flag	EQU	flags.2		;set when error found in memeory
MAP_Flag	EQU	flags.3		;set on MAP_In falling edge, cleared on rising edge
Accel_Flag	EQU	flags.4		;set when accelerating, cleared when decelerating
Stalled_Flag	EQU	flags.5		;set when clock exceeds two bytes

MAP_Vac_00	EQU	105
MAP_Vac_01	EQU	107
MAP_Vac_02	EQU	108
MAP_Vac_03	EQU	110
MAP_Vac_04	EQU	112
MAP_Vac_05	EQU	114
MAP_Vac_06	EQU	116
MAP_Vac_07	EQU	119
MAP_Vac_08	EQU	121
MAP_Vac_09	EQU	123
MAP_Vac_10	EQU	126
MAP_Vac_11	EQU	128
MAP_Vac_12	EQU	131
MAP_Vac_13	EQU	134
MAP_Vac_14	EQU	136
MAP_Vac_15	EQU	139
MAP_Vac_16	EQU	143
MAP_Vac_17	EQU	146
MAP_Vac_18	EQU	149
MAP_Vac_19	EQU	153
MAP_Vac_20	EQU	157
MAP_Vac_21	EQU	161
MAP_Vac_22	EQU	165
MAP_Vac_23	EQU	169
MAP_Vac_24	EQU	174
MAP_Vac_25	EQU	179
MAP_Vac_26	EQU	184
MAP_Vac_27	EQU	190
MAP_Vac_28	EQU	195
MAP_Vac_29	EQU	202
MAP_Vac_30	EQU	208


watch		MAP_Value,8,udec
watch		ECT_Value,8,udec
watch		EGR_Value,8,udec
watch		PFE_Value,8,udec
		
		org	0

;___________Interupt Routine_______________
isr		bank	INOUT
:map		djnz	MAP_Delay,:pfe	
		mov	MAP_Delay,#60	
		snb	MAP_IN
		clrb	MAP_Flag
		inc	MAP_Hold
		cjb	MAP_Hold,#100,:pfe	;false trigger bug fix
		jb	MAP_Flag,:pfe
		jb	MAP_IN,:pfe
		mov	MAP_Value,MAP_Hold
		clr	MAP_Hold
		setb	MAP_Flag
		
:pfe		djnz	PFE_Delay,:ect	
		mov	PFE_Delay,#20	;47k res, 0.01uF cap
		mov	w,ra		
		and	w,#%00001000
		snz
		setb	PFE_Cal
		sz	
		clrb	PFE_Cal
		sz	
		inc	PFE_Hold
		ijnz	PFE_Count,:ect
		mov	PFE_Value,PFE_Hold
		clr	PFE_Hold
		
:ect		djnz	ECT_Delay,:egr	
		mov	ECT_Delay,#20	;47k res, 0.01uF cap
		mov	w,ra		
		and	w,#%00000010
		snz
		setb	ECT_Cal
		sz	
		clrb	ECT_Cal
		sz	
		inc	ECT_Hold
		ijnz	ECT_Count,:egr
		mov	ECT_Value,ECT_Hold
		clr	ECT_Hold
		
:egr		djnz	EGR_Delay,:ignition
		mov	EGR_Delay,#20	
		inc	EGR_Count
		csb	EGR_Count,EGR_Value
		clrb	EGR_Out
		sc
		setb	EGR_Out
		
:ignition	cjne	clock,turn_coil_off,:clock		
		csne	clock+1,turn_coil_on
		setb	spark_out
		csne	clock+1,turn_coil_off+1
		clrb	spark_out

:clock		ijnz	clock,:end
		inc	clock+1
		snz
		setb	Stalled_Flag
		
:end		mov	w,#-64
		retiw

;___________Jump Table______________________
Start_Jump	jmp	@start_point
Fire		jmp	@_Fire
Extras		jmp	@_Extras
Check_HHP	jmp	@_Check_HHP
Lookup_Advance	jmp	@_Lookup_Advance
Interpolate	jmp	@_Interpolate


;___________Trigger Routine_________________
	;bank must be set to CALC before calling trigger
Trigger		jnb	Spark_In,:trig_low
		jnb	Rise_Flag,:yes_rising
		jnb	Stalled_Flag,Trigger	;terminate infinite loop_
		jmp	:bypass_ECU		;if stalled low

:yes_rising	djnz	No_Bounce,Trigger
		setb	Rise_Flag
		clrb	Fall_Flag
		clrb	Stalled_Flag
		jmp	Trigger

:trig_low	sb	Rise_Flag
		ret		
		jb	Fall_Flag,:not_falling
		mov	!option,#$cF		;disable interrupt
		mov	Next_Period,clock
		mov	Next_Period+1,clock+1
		mov	!option,#$8F		;enable interrupt
		setb	Fall_Flag
		mov	No_Bounce,#10

		csb	Turn_Coil_Off+1,Next_Period+1	;fire coil if missed
		clrb	Spark_Out

		inc	Next_Period+1
		snz
		setb	Stalled_Flag

:not_falling	cjb	clock+1,Next_Period+1,Trigger
		cjb	clock,Next_Period,Trigger

		clrb	Rise_Flag

		mov	!option,#$cF		;disable interrupt
		clr	clock
		mov	clock+1,#1
		mov	!option,#$8F		;enable interrupt

		jb	Stalled_Flag,:bypass_ECU
		
		csa	Turn_Coil_On,#1		;start dwell to prevent misfire
		setb	Spark_Out
	;	csa	Next_Period+1,turn_coil_on
	;	setb	Spark_Out		;start dwell if trig came early
		
		dec	Next_Period+1
		cjb	Next_Period+1,#$93,:not_start

:bypass_ECU	mov	turn_coil_on,turn_coil_off+1
		clrb	bypass
		clrb	EHC_Out
		clrb	Purge_Out
		clrb	Shift_Out
		clrb	Eco_Out
		bank	InOut
		clr	EGR_Value
		ret

:not_Start	setb	bypass

		mov	w,Next_Period+1		;find diff between last and current
		mov	w,Last_Period+1-w
		snc	
		setb	Accel_Flag		;set flag if accelerating or cruising
		sc	
		clrb	Accel_Flag		;clear flag if decelerating
		mov	Variable+1,w		;cont. find diff between last and current
		mov	w,Next_Period
		mov	w,Last_Period-w
		mov	Variable,w
		jc	:no_dec
		sub	Variable+1,#1
		sc
		clrb	Accel_Flag			;clr flag if underflow
:no_dec		mov	Hold_Accel,Variable+1
		jnb	Accel_Flag,:less_antic
		clc	
		rr	Variable+1
		rr	Variable
:less_antic	mov	Last_Period+1,Next_Period+1	;store current period
		mov	Last_Period,Next_Period
		sub	Next_Period+1,Variable+1	;sub diff from current_
		sub	Next_Period,Variable		;to guess next
		sc	
		dec	Next_Period+1

		call	@Fire
		
		csb	Clock+1,Turn_Coil_On		;start dwell to prevent misfire
		setb	Spark_Out
		
		call	EGR	
		call	@Extras

		ret
		
;___________EGR Routine______________________
EGR		bank	CALC
		mov	Variable+1,Hold_Accel
		cja	Last_Period+1,#$3B,:egr_off	;below 1k rpm
		cjb	Last_Period+1,#$14,:egr_off	;above 3k rpm
		jb	Idle_In,:egr_off		;throttle closed or WOT
		bank	InOut
		cja	ECT_Value,#ECT_Cold,:egr_off	;engine cold
		
		inc	Variable+1			;inc so FF=00, 00=01
		sub	Variable+1,#2			;test if <2
		snc
		clrb	Purge_Out			;close purge if not cruising
		sc
		setb	Purge_Out			;open purge valve if cruising
		
		bank	CALIBRATE
		mov	w,/PFE_Target			;find diff between value_
		bank	InOut				;and NOT target
		mov	w,PFE_Value-w			
		mov	Variable,w
		jc	:egr_up				;jump if pressure > target
		not	Variable			;if less than target_
		inc	Variable			;find absolute value_
		clc
		rr	Variable
		clc
		rr	Variable			;divide by 4
		sub	EGR_Value,Variable		;then subtract from EGR
		sc
		clr	EGR_Value			;clear if underflow
		ret

:egr_up		clc
		rr	Variable
		clc
		rr	Variable			;divide by 4
		add	EGR_Value,Variable		;add to EGR
		sc					
		ret					;return if no overflow
		mov	EGR_Value,#$FF			;set to max if overflow
		ret

:egr_off	bank	InOut
		clrb	Purge_Out			;shut off purge and EGR_
		clr	EGR_Value			;if not warm cruise
		ret		

;___________Main Loop____________________
Main		bank	CALC

		call	Trigger
		
		call	@Check_HHP 
		clr	!wdt
		jb	Stalled_Flag,Main	;skip lookup if stalled
		
		bank	CALC
	
		call	Trigger
		jb	Stalled_Flag,Main	;skip lookup if stalled
		
		bank 	CALC			;lookup power advance
		mov	Hold_Bank,#PowCurve
		call	@Lookup_Advance
		bank	CALC
		mov	Pow_Adv,Variable
		
		call	Trigger
		jb	Stalled_Flag,Main	;skip lookup if stalled
		
		bank	CALIBRATE		
		mov	Variable,Pow_Vac
		bank	InOut
		cja	MAP_Value,Variable,:not_pow	;jump if vac > pow_vac
		bank	CALC
		mov	Advance,Pow_Adv		;skip cru lookup if low vac
		jmp	Main

:not_pow	bank	CALC			;lookup cruise advance
		mov	Hold_Bank,#CruCurve
		call	@Lookup_Advance
		bank	CALC
		mov	Cru_Adv,Variable
		
		call	Trigger
		jb	Stalled_Flag,Main	;skip lookup if stalled
		
		jb	Idle_In,:not_cru	;jump if not part throttle
		bank	CALIBRATE		
		mov	Variable,Cru_Vac
		bank	InOut
		cjb	MAP_Value,Variable,:not_cru  	;jump if vac < cru_vac
		bank	CALC
		mov	Advance,Cru_Adv		;skip adv calc if high vac
		jmp	Main

:not_cru	jnb	Idle_In,:not_idle	;skip idle lookup if part throttle
		bank	InOut
		cja	ECT_Value,#ECT_Cold,:not_warm	;jump if below operating temp
		cjb	ECT_Value,#ECT_Hot,:not_warm	;jump if overheating
		bank	CALIBRATE
		mov	Variable,Idle_Adv	;lookup idle advance
		bank	InOut
		csbe	MAP_Value,#MAP_Vac_22
		clr	Variable		;run base timing if decelerating
		bank	CALC
		mov	Advance,Variable	
		jmp	Main			;skip adv calc if throttle closed

:not_warm	bank	CALC			;run high advance if cold or overheating
		mov	Advance,Cru_Adv		
		jmp	Main			;skip adv calc if throttle closed

:not_idle	bank	CALIBRATE		;interpolate adv between pow & cru
		mov	Variable,Cru_Vac
		mov	Variable+1,Pow_Vac
		bank	MATH
		mov	Int_X1,Variable
		clr	Int_X1+1
		mov	Int_X2,Variable+1
		clr	Int_X2+1
		bank	CALC
		mov	Variable,Cru_Adv
		mov	Variable+1,Pow_Adv
		bank	MATH
		mov	Int_Y1,Variable
		mov	Int_Y2,Variable+1
		bank	InOut
		mov	Variable,MAP_Value
		clr	Variable+1
		bank	MATH
		call	@Interpolate
		mov	w,Int_Y2
		bank	CALC
		mov	Advance,w
		jmp	Main


		org	$200
;__________Multiply________________________ 	
	;X * Y = Z: xx_xx_xx * yy = zz_zz_zz 
Multiply	clr	Z_var
		clr	Z_var+1
		clr	Z_var+2
		mov	counter,#8
:mloop		rr	Y_var
		jnc	:no_add
		add	Z_var,X_var
		jnc	:no_carry
		inc	Z_var+1
		snz
		inc	Z_var+2
:no_carry	add	Z_var+1,X_var+1
		snc
		inc	Z_var+2
		add	Z_var+2,X_var+2
:no_add		clc
		rl	X_var
		rl	X_var+1
		rl	X_var+2
		djnz	counter,:mloop
		ret
 		
;__________Divide__________________________
	;Z_var/X_var=Y_var; zz_zz_zz / xx_xx_xx = yy_yy_yy
Divide		clr	counter
		clc
:dloop		rl	X_var
		rl	X_var+1
		rl	X_var+2
		inc	counter
		jnc	:dloop
		rr	X_var+2
		rr	X_var+1
		rr	X_var
		clr	Y_var
		clr	Y_var+1
		clr	Y_var+2

:ddloop		test	counter
		jz	:ddone
		clc
		rl	Y_var
		rl	Y_var+1
		rl	Y_var+2
		cjb	Z_var+2,X_var+2,:ddloop1
		cje	Z_var+2,X_var+2,:dequal
		jmp	:dfinish
:dequal		cjb	Z_var+1,X_var+1,:ddloop1
		cje	Z_var+1,X_var+1,:equalx
		jmp	:dfinish
:equalx		cjb	Z_var,X_var,:ddloop1
:dfinish	sub	Z_var+2,X_var+2
		sub	Z_var+1,X_var+1
		sc
		dec	Z_var+2
		sub	Z_var,X_var
		sc
		dec	Z_var+1
		inc	Y_var
		snz
		inc	Y_var+1
		snz
		inc	Y_var+2

:ddloop1	dec	counter
		clc
		rr	X_var+2
		rr	X_var+1
		rr	X_var
		jmp	:ddloop

:ddone		ret


;___________Interpolate___________________
	;Int_X1 must be > Int_X2, calcs based on period, not frequency
	;low X = Int_X1 and Int_X1+1
	;low Y = Int_Y1
	;hi  X = Int_X2 and Int_X2+1
	;hi  Y = Int_Y2
	;int X = Variable and Variable+1
	;int Y = Int_Y2 <<<This is the answer>>>

_Interpolate	mov	X_var,Variable
		mov	X_var+1,Variable+1
		clr	X_var+2
		sub	X_var+1,Int_X2+1
		sub	X_var,Int_X2
		sc
		dec	X_var+1
		mov	Y_var,Int_Y2
		sub	Y_var,Int_Y1
		jc	:yes_up1		;use this value if Y2 is greater
		mov	Y_var,Int_Y1		
		sub	Y_var,Int_Y2		;use this value if Y1 is greater
:yes_up1	call	Multiply
		mov	X_var,Int_X1
		mov	X_var+1,Int_X1+1
		clr	X_var+2
		sub	X_var+1,Int_X2+1
		sub	X_var,Int_X2
		sc
		dec	X_var+1
		call	Divide
		cja	Int_Y2,Int_Y1,:yes_up2
		add	Int_Y2,Y_var		;add if Y1 is greater
		retp
:yes_up2	sub	Int_Y2,Y_var		;sub if Y2 is greater
		retp		

;___________Find Fire Time___________________
_Fire		bank	CALC
		mov	Variable,Next_Period
		mov	Variable+1,Next_Period+1
		mov	w,Advance			;advance is in 1/4 deg incriments
		bank	MATH
		mov	Y_var,w				;period * advance = Z
		mov	X_var,Variable
		mov	X_var+1,Variable+1
		clr	X_var+2
		call	Multiply			
		mov	X_var,#$68			;z / 360 = Y
		mov	X_var+1,#$1		;there are 360 quarter deg incriments per period
		clr	X_var+2
		call	Divide
		bank	CALC
		mov	Variable,Next_Period
		mov	Variable+1,Next_Period+1
		bank	MATH
		sub	Variable+1,Y_var+1		;period - Y = fire time
		sub	Variable,Y_var
		sc
		dec	Variable+1
		bank	CALIBRATE
		mov	w,Fine_Tune
		sub	Variable,w
		sc
		dec	Variable+1
		mov	turn_coil_off,Variable
		mov	turn_coil_off+1,Variable+1

:rev_limit	bank	CALC
		cjb	Last_Period+1,#Rev_LimitH,:yes_rev_lim
		jnz	:no_rev_lim
		cjae	Last_Period,#Rev_LimitL,:no_rev_lim
:yes_rev_lim	mov	turn_coil_on,turn_coil_off+1
		retp

:no_rev_lim	;do not retp, continue with dwell

;___________Find Dwell Time___________________
_Dwell		bank	MATH
		mov	counter,Turn_Coil_Off+1
		bank	CALC
		mov	Variable+1,Hold_Accel
		mov	w,Next_Period+1
		bank	MATH
		mov	X_var,w
		mov	X_var+1,w
		mov	Variable,#Fire_Time
		mov	X_var+2,#Dwell_Time  

		jnb	Accel_Flag,:not_accel
		add	X_var+2,Variable+1		;add accel to dwell
		jc	:less_dwell			;set to max if overflow

:not_accel	sub	X_var,X_var+2			;Next_Period+1 - Dwell_Time
		jnc	:less_dwell			;jump if period shorter than dwell
		cjae	X_var,Variable,:no_less_dwell  	;jump if greater than Fire_Time

:less_dwell	mov	w,Variable
		mov	w,X_var+1-w
		mov	X_var+2,w			;dwell = period - Fire_Time

:no_less_dwell	sub	counter,X_var+2			;turn_coil_off+1 - Dwell_Time
		jnc	:next_dwell			;jump if before trigger

		jz 	:trig_buff  			;jump if during trigger buffer
		
		mov	turn_coil_on,counter		;move to turn_coil_on if after trigger
		retp

:trig_buff	mov	w,X_var+1 			;Next_Period
		mov	turn_coil_on,w			;move to turn_coil_on
		retp

:next_dwell	mov	X_var,turn_coil_off+1
		sub	X_var+2,X_var			;Dwell_Time - turn_coil_off = X_var+2
		mov	w,X_var+2
		mov	w,X_var+1-w			
		mov	turn_coil_on,w			;move period - X_var+2 to turn_coil_on
		retp

;___________Extras__________________________
_Extras		bank 	CALIBRATE
:eco_light	mov	Variable,Econ_Light
		bank 	InOut
		csa	Map_Value,Variable
		setb	Eco_Out
		add	Variable,#3
		csbe	Map_Value,Variable
		clrb	Eco_Out

;-------------------------------------------
:shift_light	bank	CALC
		mov	Variable,Last_Period
		mov	Variable+1,Last_Period+1
		bank	MATH
		mov	X_var,#Shft_Pow_OnL		;default to power rpm
		mov	X_var+1,#Shft_Pow_OnH
		mov	Y_var,#Shft_Pow_OffL
		mov	Y_var+1,#Shft_Pow_OffH
		bank	InOut
		cja	ECT_Value,#ECT_Cold,:not_cru	;use power rpm if engine cold
		cjb	MAP_Value,#MAP_Vac_05,:not_cru	;use power rpm if low man. vacuum
		bank	MATH
		mov	X_var,#Shft_Cru_OnL		;switch to cruise rpm
		mov	X_var+1,#Shft_Cru_OnH
		mov	Y_var,#Shft_Cru_OffL
		mov	Y_var+1,#Shft_Cru_OffH
:not_cru	bank	MATH
		cja	Variable+1,X_var+1,:not_on
		jnz	:yes_on
		csa	Variable,X_var
:yes_on		setb	Shift_Out			;turn on shift light
:not_on		cjb	Variable+1,Y_var+1,:exh_heat
		jnz	:yes_off
		csbe	Variable,Y_var
:yes_off	clrb	Shift_Out			;turn off shift light

;--------------------------------------------
:exh_heat	bank	InOut
		cjb	ECT_Value,#ECT_EHC,:no_EHC	;open EHC if engine warm
		cjb	MAP_Value,#MAP_Vac_11,:no_EHC	;open EHC if accelerating
		setb	EHC_Out				;otherwise close EHC
		skip
:no_EHC		clrb	EHC_Out
		retp

;___________Lookup_Advance_____________________
_Lookup_Advance	mov	Variable,Last_Period
		mov	Variable+1,Last_Period+1
		mov	FSR,Hold_Bank

		cjb	Variable+1,#$3A,:not_1k
		jnz	:yes_1k
		cjb	Variable,#$98,:not_1k
:yes_1k		mov	Variable,Adv_1k
		retp

:not_1k		cjb	Variable+1,#$27,:not_1k5
		jnz	:yes_1k5
		cjb	Variable,#$10,:not_1k5
:yes_1k5	mov	w,Adv_1k
		bank	MATH
		mov	Int_Y1,w
		bank	CALC
		mov	FSR,Hold_Bank
		mov	w,Adv_1k5
		bank	MATH
		mov	Int_Y2,w
		mov	Int_X1,#$98
		mov	Int_X1+1,#$3A
		mov	Int_X2,#$10
		mov	Int_X2+1,#$27
		call	@_Interpolate
		mov	Variable,Int_Y2
		retp

:not_1k5	cjb	Variable+1,#$1D,:not_2k
		jnz	:yes_2k
		cjb	Variable,#$4C,:not_2k
:yes_2k		mov	w,Adv_1k5
		bank	MATH
		mov	Int_Y1,w
		bank	CALC
		mov	FSR,Hold_Bank
		mov	w,Adv_2k
		bank	MATH
		mov	Int_Y2,w
		mov	Int_X1,#$10
		mov	Int_X1+1,#$27
		mov	Int_X2,#$4C
		mov	Int_X2+1,#$1D
		call	@_Interpolate
		mov	Variable,Int_Y2
		retp

:not_2k		cjb	Variable+1,#$17,:not_2k5
		jnz	:yes_2k5
		cjb	Variable,#$70,:not_2k5
:yes_2k5	mov	w,Adv_2k
		bank	MATH
		mov	Int_Y1,w
		bank	CALC
		mov	FSR,Hold_Bank
		mov	w,Adv_2k5
		bank	MATH
		mov	Int_Y2,w
		mov	Int_X1,#$4C
		mov	Int_X1+1,#$1D
		mov	Int_X2,#$70
		mov	Int_X2+1,#$17
		call	@_Interpolate
		mov	Variable,Int_Y2
		retp

:not_2k5	cjb	Variable+1,#$13,:not_3k
		jnz	:yes_3k
		cjb	Variable,#$88,:not_3k
:yes_3k		mov	w,Adv_2k5
		bank	MATH
		mov	Int_Y1,w
		bank	CALC
		mov	FSR,Hold_Bank
		mov	w,Adv_3k
		bank	MATH
		mov	Int_Y2,w
		mov	Int_X1,#$70
		mov	Int_X1+1,#$17
		mov	Int_X2,#$88
		mov	Int_X2+1,#$13
		call	@_Interpolate
		mov	Variable,Int_Y2
		retp

:not_3k		cjb	Variable+1,#$0E,:not_4k
		jnz	:yes_4k
		cjb	Variable,#$A6,:not_4k
:yes_4k		mov	w,Adv_3k
		bank	MATH
		mov	Int_Y1,w
		bank	CALC
		mov	FSR,Hold_Bank
		mov	w,Adv_4k
		bank	MATH
		mov	Int_Y2,w
		mov	Int_X1,#$88
		mov	Int_X1+1,#$13
		mov	Int_X2,#$A6
		mov	Int_X2+1,#$0E
		call	@_Interpolate
		mov	Variable,Int_Y2
		retp

:not_4k		mov	Variable,Adv_4k
		retp


		org	$400
;___________Memory Check_________________
Memory_Check	bank	PowCurve
		call	Check_Twice	;check values
		snb	Memory_Flag
		call	Check_Twice	;check again if error found
		snb	Memory_Flag
		ret
		bank	CruCurve
		call	Check_Twice	;check values
		snb	Memory_Flag
		call	Check_Twice	;check again if error found
		snb	Memory_Flag
		ret
		bank	CALIBRATE
		call	Check_Twice2	;check values
		snb	Memory_Flag
		call	Check_Twice2	;check again if error found
		ret

;_________Memory Check Sub Routines_______
Check_Twice	csbe	Adv_1k,#200
		setb	Memory_Flag
		csbe	Adv_1k5,#200
		setb	Memory_Flag
		csbe	Adv_2k,#200
		setb	Memory_Flag
		csbe	Adv_2k5,#200
		setb	Memory_Flag
		csbe	Adv_3k,#200
		setb	Memory_Flag
		csbe	Adv_4k,#200
		setb	Memory_Flag
		ret

Check_Twice2	csbe	Idle_Adv,#200
		setb	Memory_Flag
		csbe	Pow_Vac,#208
		setb	Memory_Flag
		csae	Pow_Vac,#105
		setb	Memory_Flag
		csbe	Cru_Vac,#208
		setb	Memory_Flag
		csae	Cru_Vac,#105
		setb	Memory_Flag
		csbe	Econ_Light,#208
		setb	Memory_Flag
		csae	Econ_Light,#105
		setb	Memory_Flag
		ret
		
;___________Memory RESET_________________
Memory_Reset	bank	PowCurve
		mov	Adv_1k,#4
		mov	Adv_1k5,#32
		mov	Adv_2k,#56
		mov	Adv_2k5,#68
		mov	Adv_3k,#68
		mov	Adv_4k,#68
		bank	CruCurve
		mov	Adv_1k,#120
		mov	Adv_1k5,#132
		mov	Adv_2k,#136
		mov	Adv_2k5,#136
		mov	Adv_3k,#88
		mov	Adv_4k,#88
		bank	CALIBRATE
		mov	Idle_Adv,#20
		mov	PFE_Target,#0
		mov	Fine_Tune,#0
		mov	Pow_Vac,#Map_Vac_05
		mov	Cru_Vac,#Map_Vac_20
		mov	Econ_Light,#Map_Vac_11
		ret

;___________What Value___________________
What_Value	mov	w,Variable
		jmp	pc+w
		retw	$70 ;0  Pow Adv_1k
		retw	$71 ;1  Pow Adv_1k5
		retw	$72 ;2  Pow Adv_2k
		retw	$73 ;3  Pow Adv_2k5
		retw	$74 ;4  Pow Adv_3k
		retw	$75 ;5  Pow Adv_4k
		retw	$B1 ;6  PFE_Target
		retw	$90 ;7  Cru Adv_1k
		retw	$91 ;8  Cru Adv_1k5
		retw	$92 ;9  Cru Adv_2k
		retw	$93 ;10 Cru Adv_2k5
		retw	$94 ;11 Cru Adv_3k
		retw	$95 ;12 Cru Adv_4k
		retw	$B0 ;13 Idle_Adv
		retw	$B2 ;14 Fine_Tune
		retw	$B3 ;15 Pow_Vac
		retw	$B4 ;16 Cru_Vac
		retw	$B5 ;17 Econ_Light
		
;___________Get Byte_____________________
Get_Byte	jnb	HHP,Get_Byte
		setb	ECU
:gwait_1	jb	HHP,:gwait_1
		clc
		snb	DATA
		stc
		rr	Variable
		clrb	ECU
		djnz	Variable+1,Get_Byte
		ret

;___________Send Byte____________________
Send_Byte	sb	ind.0
		clrb	DL
		snb	ind.0
		setb	DL
		nop
		nop
		nop
		setb	ECU
:dlwait_1	jnb	HHP,:dlwait_1
		sb	ind.1
		clrb	DL
		snb	ind.1
		setb	DL
		nop
		nop
		nop
		clrb	ECU
:dlwait_2	jb	HHP,:dlwait_2
		sb	ind.2
		clrb	DL
		snb	ind.2
		setb	DL
		nop
		nop
		nop
		setb	ECU
:dlwait_3	jnb	HHP,:dlwait_3
		sb	ind.3
		clrb	DL
		snb	ind.3
		setb	DL
		nop
		nop
		nop
		clrb	ECU
:dlwait_4	jb	HHP,:dlwait_4
		sb	ind.4
		clrb	DL
		snb	ind.4
		setb	DL
		nop
		nop
		nop
		setb	ECU
:dlwait_5	jnb	HHP,:dlwait_5
		sb	ind.5
		clrb	DL
		snb	ind.5
		setb	DL
		nop
		nop
		nop
		clrb	ECU
:dlwait_6	jb	HHP,:dlwait_6
		sb	ind.6
		clrb	DL
		snb	ind.6
		setb	DL
		nop
		nop
		nop
		setb	ECU
:dlwait_7	jnb	HHP,:dlwait_7
		sb	ind.7
		clrb	DL
		snb	ind.7
		setb	DL
		nop
		nop
		nop
		clrb	ECU
:dlwait_8	jb	HHP,:dlwait_8		
		clrb	DL
		inc	fsr
		djnz	Variable,Send_Byte
		ret

;___________Check HHP___________________
_Check_HHP	jnb	DATA,:its_done		;skip if no signal from HHP
		jnb	HHP,:its_done		;skip if no signal from HHP
		setb	DL			;tell HHP signal was received

:now_DL		jb	HHP,:now_UL		;jump if not download

		clrb	DL			;tell HHP signal was received

		clrb	ECU
		mov	fsr,#$70
		mov	Variable,#6
		call	Send_Byte
		mov	fsr,#$90
		mov	Variable,#6
		call	Send_Byte
		mov	fsr,#$B0
		mov	Variable,#6
		call	Send_Byte
		
		retp

:now_UL		jb	DATA,:now_DL		;jump if not upload

		clrb	DL			;tell HHP signal was received
		clrb	ECU			;start upload
		
		mov	Variable+1,#6		;set bit count to 6
		clr	Variable
		
		call	Get_Byte		;get 6-bit command
		
		clc				;convert to 8-bit number
		rr	Variable
		rr	Variable		

		cjb	Variable,#60,:reg_op	;jump if not reset command
		call	Memory_Reset 

		retp

:reg_op		call	What_Value		;get memory address
		mov	fsr,w			;point to memory address
		mov	Variable+1,#8		;set bit count to 8
		call	Get_Byte		;get value
		mov	ind,Variable		;move value to address

:its_done	clrb	DL
		retp
		

;___________Program Start_________________
start_point 	bank	MATH
		clr	X_var
		clr	X_var+1
		clr	X_var+2;,#19
:fix_die	djnz	X_var,:fix_die
		djnz	X_var+1,:fix_die
		djnz	X_var+2,:fix_die

		mode	Level
		mov	!ra,#%0000
		mov	!rb,#%00000000
		mov	!rc,#%00000000
		mode	Schmitt
		mov	!rc,#%11101011
		mode	Direction
		mov	!ra,#%1010
		mov	!rb,#%00000001
		mov	!rc,#%00010111
		clr	ra
		clr	rb
		clr	rc
		clr	turn_coil_on
		clr	turn_coil_off
		clr	turn_coil_off+1
		mov	flags,#00100000
		bank	INOUT
		mov	MAP_Delay,#5
		mov	PFE_Delay,#10
		mov	ECT_Delay,#15
		mov	EGR_Delay,#20
		mov	MAP_Value,#$D0
		mov	ECT_Value,#$FF
		clr	EGR_Value
		bank	CALC
		clr	Advance
		mov	!option,#$cf	;disable interrupt

		call	Memory_Check	;check memory for erroneous values
		snb	Memory_Flag		
		call	Memory_Reset	;reset memory if errors found
		clrb	Memory_Flag
		mov	!option,#$8f	;initialize interrupt
				
		jmp	@Main



