This is a brief code walkthrough for the fuel cut off situations. The overview is here and I highly recommend reading that first.
This is where we jump to after calculating the new timing value in r5.
X0bfd:
jb 23h.2,X0c54
mov r2,#44h ;Map 68, load by rpm
lcall X051d
mov r3,a
jb 21h.1,X0c38 ;21h.1 means we have overload already
cjne a,49h,X0c0c
X0c0c:
jc X0c12 ; c means 49h>=max
clr 21h.0
sjmp X0c54 ; clear flag and bail to coasting
;
X0c12: ; we have overload, start counting
mov a,#52h ; 11B2, contains 1Ah/26dec
jb 21h.0,X0c21 ;we're already counting
setb 21h.0 ;
movc a,@a+dptr
mov 58h,a ; 26
mov a,#54h ; 11B4 contains 10 dec.
movc a,@a+dptr
mov 59h,a ; 10 (26*10*11.5ms = ~3s)
X0c21:
mov a,58h
jnz X0c54 ; bail out if not zero
setb 21h.1 ;set overload flag
mov a,#53h
movc a,@a+dptr
mov 58h,a ;11B3, contains 29
mov a,#55h
movc a,@a+dptr
mov 59h,a ;11B5, contains 180 (29*180*0.0115=~60s)
setb 23h.5 ;cut fuel
mov 32h,r5 ;new timing target=latest calculation
mov 31h,r5 ;current timing = latest calculation
ret
;
X0c38: ;we already have overload
mov a,58h
jnz X0c42
clr 21h.0 ;release from overload jail
clr 21h.1
sjmp X0c54
;
X0c42: ;we have overload and haven't served the sentence
mov a,#51h ;11B1, contains 50
movc a,@a+dptr
cpl a
inc a
add a,r3 ;Map 68 value - 50
clr c
subb a,49h
jnc X0c54 ;bail if current load <= Map 68 - 50
setb 23h.5 ;stay in fuel-cut jail
mov 32h,r5
mov 31h,r5
ret
;
X0c54:
ljmp X1059
In pseudo code,
if cranking:
return
r3 = map_68[current_rpm]
if 21h.1 (we have overload for > 3 sec already):
if 58h=0 (30 sec timer expired):
clear 21h.0 (3 sec timer flag)
clear 21h.1 (30 sec flag)
return
else:
if current load >= r3 - 50:
set 23h.5 (cut fuel)
31h = 32h = r5 (set timing to latest calculation)
return
else: (we didn't already have overload for > 3 sec):
if current load <= r3:
clear 21h.0 (cancel 3 sec timer flag)
return
else:
if 21h.0 (we had already started 3 sec count):
if 58h=0 (timer expired):
set 21h.1 (overload flag)
58h:59h = 30s timer value
set 23h.5 (cut fuel)
else:
# start counting 3 second timer now
set 21h.0 (3 second timer flag)
58h:59h = load 3 second timer value
The timer value 58h:59h is decremented in a short routine that’s called via 103E at 0434 (end of post-load routine 040D):
;
X0c57:
dec 59h
mov a,59h
jnz X0c6c
mov a,#54h
jnb 21h.1,X0c63
inc a
X0c63:
movc a,@a+dptr
mov 59h,a
mov a,58h
jz X0c6c
dec 58h
X0c6c:
ljmp X1056
After the overload routine, we jump to 1059 which just jumps to 0708, which is the routine that handles coasting fuel cut off, fuel reactivation (for both coasting and overload) and various ignition timing rules.
This is a tricky routine and I don’t think it makes a lot of sense to break it down, so I’ll leave the whole thing as once snippet, but then we’ll see a very simple pseudo code version:
X0708:
jb 23h.2,X0770
jnb 23h.0,X0732
mov r2,#19h
acall X051d
clr c
subb a,37h
jnc X073e
mov r3,a
mov a,#32h ;1192, contains 9
jb 21h.6,X071f
mov a,#31h ;1191, also contains 9
X071f:
movc a,@a+dptr
add a,r3
jc X0770
setb 22h.5
mov a,r5
cjne a,31h,X0770
setb 23h.5
clr 22h.5
mov 32h,a
mov 31h,a
ret
;
X0732:
clr 21h.6
clr 22h.5
jnb 23h.5,X0770
mov a,#2fh ;118F, contains 249, or -6 timing
movc a,@a+dptr
ajmp X0748
;
X073e:
clr 22h.5
jnb 23h.5,X0770
setb 21h.6
mov a,#30h ;1190, contins ff/255, i.e. -1 timing
movc a,@a+dptr
X0748:
add a,31h
mov 31h,a
mov 32h,r5
clr c
mov a,r5
subb a,31h
jnb acc.7,X0761 ;31h > r5, timing is decreasing
mov 34h,#1
mov 4dh,#0
setb 21h.5
clr 23h.5
ajmp X0770
;
X0761:
mov a,#2dh
movc a,@a+dptr ;118D, contains 1
mov 34h,a
setb 22h.6
mov 4dh,#0
setb 21h.5
clr 23h.5
ret
;
The following section has some tricky boolean logic:
X0770:
clr c
mov a,#25h ;1185, contains 3Ch/60
movc a,@a+dptr
subb a,49h
jc X077e ;jump if load > 60
mov a,#26h ;1186, contains 14h/20
movc a,@a+dptr
subb a,37h
cpl c ;now c=1 if rpm<800
X077e:
jnb 22h.4,X0782
cpl c
X0782:
jnc X078f
cpl 22h.4
Working out the effect on 22h.4, we get this
if (49h > 60 or 37h < 800rpm) XOR 22h.4
cpl 22h.4
But that’s still kind of unclear, since it doesn’t explicitly set 22h.4. But if you work through it, you’ll see that this is actually equivalent to
22h.4 = bool(load>60 or rpm<800)
The rest of the routine is much easier to understand:
jb 22h.6,X078f
jb 22h.5,X078f
mov 34h,#1
X078f:
mov a,r5
jnb 23h.4,X0798
mov 31h,a
mov 34h,#1
X0798:
mov a,r5
jnb 22h.6,X07a7
clr c
subb a,31h
jnb acc.7,X07a7
clr 22h.6
mov 34h,#1
X07a7:
mov 32h,r5
ret
In very simple, high-level pseudo code, it’s this:
if at idle and rpm is at least 360 above threshold:
if timing has reached target:
cut fuel
else:
return
else if at idle but rpm is below threshold:
clear 8x timing change speed
if fuel is currently cut:
trigger the return-to-idle fuel correction (Map 1140)
reduce current timing by 1 (half tooth)
if the new timing target > new current timing:
set 8x timing change speed
re-activate fuel
else:
re-activate fuel
jump to 0770
else if not idle:
clear 16x timing change speed
if fuel is currently cut:
reduce current timing by 6 (half teeth)
trigger return-to-throttle fuel correction (Map 1150)
if new timing target > new current timing:
set 8x timing change speed
re-activate fuel
else:
reactivate fuel
jump to 0770
0770:
if load > 60 OR rpm < 800 and neither 8x nor 16x timing flags are set:
set 64x timing flag
if startup mode:
set current timing to the new calculation immediatley
if 16x timing speed is set and timing is decreasing:
clear 16x timing speed
update timing target (32h) with new calculation
That skips over a lot of details, so here’s a more detailed version but still in pseudo code:
if 23h.0 (idle):
if rpm > threshold from Map 25:
r3 = rpm diff (negative)
if |r3| < 360rpm:
bail to 0770
set 22h.5 (timing change flag #2, medium speed)
if 31h != r5 (current timing != new target):
bail to 0770
else:
set 23h.5 (cut fuel)
31h = 32h = r5 (current and target timing updated)
return
else: (rpm <= fuel cut threshold):
clear 22h.5 (timing change flag)
if not 23h.5 (fuel is not cut):
bail out to 0770
set 21h.6 (fuel reactivation correction flag)
31h = 31h - 1 (immediately reduce timing)
32h = r5 (set new target timing)
if 31h > r5 (timing is decreasing):
34h = 1 (trigger timing update)
4dh = 0 (reset injection event counter)
set 21h.5 (trigger fuel reactivation correction)
set 23h.5 (re-activate fuel)
bail out to 0770
else:
(timing is the same or increasing):
34h = 1 (via 118D)
set 22h.6 (top timing change flag)
4dh = 0 (reset injection event counter)
set 21h.5 (trigger fuel reactivation correction)
clear 23h.5 (re-activate fuel)
return
else (not at idle):
clear 21h.6 (fuel reactivation correction flag)
clear 22h.5 (second timing change flag)
if not 23h.5 (fuel is not cut):
bail out to 0770
31h = 31h - 6 (immediately reduce timing)
32h = r5 (set new target timing)
if 31h > r5 (timing is decreasing):
34h = 1 (trigger timing update)
4dh = 0 (reset injection event counter)
set 21h.5 (trigger fuel reactivation correction)
set 23h.5 (re-activate fuel)
bail out to 0770
else:
(timing is the same or increasing):
34h = 1 (via 118D)
set 22h.6 (top timing change flag)
4dh = 0 (reset injection event counter)
set 21h.5 (trigger fuel reactivation correction)
clear 23h.5 (re-activate fuel)
return
0770:
if (49h > 60 or 37h < 800rpm):
set 22h.4 (fastest possible timing change)
if not 22h.6 and not 22h.5:
34h = 1 (trigger the timing update)
if 23h.4 (startup flag, usually not set):
31h = r5
34h = 1
if 22h.6:
if 31 > r5: (timing is decreasing)
clear 22h.6
34h = 1
32h = r5
Everything the overload routine (0BFD), the timer decrement routine (0C57) and the coasting routine (0708) touch. See the memory map for the master list.
| Location | Purpose |
|---|---|
| 31h | current ignition advance, reduced directly on fuel reactivation |
| 32h | target ignition advance |
| 34h | countdown to the next permitted timing step; forced to 1 to act immediately |
| 37h | engine speed (rpm/40) |
| 49h | load, compared against the Map 68 overload threshold |
| 4Dh | injection event counter, reset to zero when fuel is reactivated |
| 58h | overload timer, counted down by the 0C57 routine |
| 59h | prescale counter for 58h |
| Flag | Purpose |
|---|---|
| 21h.0 | the ~3 second overload pre-timer is running |
| 21h.1 | overload has been confirmed; the ~60 second lockout is running |
| 21h.5 | triggers the transient fuel correction after reactivation |
| 21h.6 | selects the return-to-idle correction rather than return-to-throttle |
| 22h.4 | fastest timing change rate |
| 22h.5 | medium timing change rate |
| 22h.6 | top priority timing change rate |
| 23h.0 | TPS at idle |
| 23h.2 | cranking — the overload routine returns immediately |
| 23h.4 | startup — applies the new timing calculation immediately |
| 23h.5 | fuel is cut (for coasting or overload) |
| Reference | Address | Purpose |
|---|---|---|
| Map 25 (19h) | 144Fh | coasting fuel cut rpm threshold, by engine temperature |
| Map 68 (44h) | 16E0h | overload load threshold, by rpm |
| 1160+25h | 1185h | load threshold for the fastest timing change rate (3Ch, i.e. 60) |
| 1160+26h | 1186h | rpm threshold for the fastest timing change rate (14h, i.e. 800rpm) |
| 1160+2Dh | 118Dh | value written to 34h (1) |
| 1160+2Fh | 118Fh | timing step on return-to-throttle reactivation (249, i.e. -6) |
| 1160+30h | 1190h | timing step on return-to-idle reactivation (FFh, i.e. -1) |
| 1160+31h | 1191h | coasting rpm offset, 21h.6 clear (9) |
| 1160+32h | 1192h | coasting rpm offset, 21h.6 set (9) |
| 1160+51h | 11B1h | hysteresis below the Map 68 threshold for staying in overload (50) |
| 1160+52h | 11B2h | 58h reload for the ~3 second pre-timer (1Ah, i.e. 26) |
| 1160+53h | 11B3h | 58h reload for the ~60 second lockout (29) |
| 1160+54h | 11B4h | 59h prescale, 21h.1 clear (10) |
| 1160+55h | 11B5h | 59h prescale, 21h.1 set (180) |
| Map 1140 | 1140h | return-to-idle transient fuel correction |
| Map 1150 | 1150h | return-to-throttle transient fuel correction |