This is an example of how to hook code into an existing routine. Not 100% elegant, but there is plenty of free space to work with in our ECUs so I haven't optimized it for space.
Be careful when using the delayed slot instructions (jsr, rts, bra...) if you have any delayed instructions that reference addresses, the results can be quite screwy. The 32 bit instructions instructions in a delayed slot also are not reliable. Use of jsr/n, rts/n makes code more reliable, even though it takes up an extra clock cycle.
Example:
In the A01G ROM, the routine at 2B0E8 in the stock ROM scales sensor voltage data in fr4 according to multiplier and offset (Throttle angle, Accelerator angle, Batt Voltage, MAP sensor, Evap Pressure sensor)
Evap pressure sensor data is read when r6 = 06 and r13 = 0B.
At the end of this block of code, the program then branches to 2B100 with the scaled value stored in fr9.
Code:
ROM:0002B0E8 loc_2B0E8: ; CODE XREF: Scale_16_bit_sensor_data_in_table
ROM:0002B0E8 46 08 shll2 r6 ; Shift Logical Left 2
ROM:0002B0EA 46 00 shll r6 ; Shift Logical Left
ROM:0002B0EC D2 21 mov.l #off_10E0C, r2 ; Move Immediate Long Data
ROM:0002B0EE 60 63 mov r6, r0 ; Move Data
ROM:0002B0F0 06 2E mov.l @(r0,r2), r6 ; Move Long Data
ROM:0002B0F2 F0 68 fmov.s @r6, fr0 ; Floating-point move single precision: Multiplier value
ROM:0002B0F4 72 04 add #4, r2 ; Add binary
ROM:0002B0F6 06 2E mov.l @(r0,r2), r6 ; Move Long Data
ROM:0002B0F8 F9 68 fmov.s @r6, fr9 ; Floating-point move single precision: Offset value
ROM:0002B0FA A0 01 bra loc_2B100 ; Branch
ROM:0002B0FC F9 4E fmac fr0, fr4, fr9 ; Floating-point multiply and accumulate: fr9 = fr0(multiplier)*fr4(sensor voltage)+fr9(offset)
This substitute code loads a ROM address for a new subroutine in a patch of empty ROM in place of the old sensor scaling, returning with a sensor value in fr9 before branching to 2B100:
Code:
ROM:0002B0E8 loc_2B0E8: ; CODE XREF: sub_2B0A2
ROM:0002B0E8 D2 03 mov.l #sub_B97C0, r2 ; Move Immediate Long Data
ROM:0002B0EA 42 4B jsr/n @R2 ; sub_B97C0 ; Jump to Subroutine with No delay slot
ROM:0002B0EC A0 08 bra loc_2B100 ; Branch
ROM:0002B0EE 00 09 nop ; No Operation
ROM:0002B0EE ; ---------------------------------------------------------------------------
ROM:0002B0F0 FF FF FF FF+ .datab.l 2, h'FFFFFFFF
ROM:0002B0F8 00 0B 97 C0 off_2B0F8: .data.l sub_B97C0 ; DATA XREF: sub_2B0A2:loc_2B0E8
ROM:0002B0FC FF FF .datab.b 2, h'FF
The new subroutine at B97C0 replicates the original routine, checks if the Evap sensor is being evaluated; returns immediately if not, and runs on to new code otherwise before returning.
Code:
ROM:000B97C0 sub_B97C0: ; CODE XREF: sub_2B0A2
ROM:000B97C0 ; DATA XREF: sub_2B0A2:loc_2B0E8
ROM:000B97C0 4F 22 sts.l pr, @-r15 ; Store System Register Long
ROM:000B97C2 46 08 shll2 r6 ; Shift Logical Left 2
ROM:000B97C4 46 00 shll r6 ; Shift Logical Left
ROM:000B97C6 02 10 0E 0C movi20 #off_10E0C, r2 ; 20-bit immediate data transfer
ROM:000B97CA 60 63 mov r6, r0 ; Move Data
ROM:000B97CC 06 2E mov.l @(r0,r2), r6 ; Move Long Data
ROM:000B97CE F0 68 fmov.s @r6, fr0 ; Floating-point move single precision: Multiplier value
ROM:000B97D0 72 04 add #4, r2 ; Add binary
ROM:000B97D2 06 2E mov.l @(r0,r2), r6 ; Move Long Data
ROM:000B97D4 F9 68 fmov.s @r6, fr9 ; Floating-point move single precision: Offset value
ROM:000B97D6 F9 4E fmac fr0, fr4, fr9 ; Floating-point multiply and accumulate: fr9 = fr0(multiplier)*fr4(sensor voltage)+fr9(offset)
ROM:000B97D8 60 D3 mov r13, r0 ; Move Data
ROM:000B97DA 88 0B cmp/eq #h'B, r0 ; Compare: Equal: if sensor value being returned is Evap (r13 = 0B), the T bit is set
ROM:000B97DC 8B 2F bf loc_B983E ; Branch if False: Branch to return to stack after restoring pr
ROM:000B97DE Write new routines in here... then return to stack after restoring pr (at B983E in this case)
............
ROM:000B983E loc_B983E: ; CODE XREF: sub_B97C0
ROM:000B983E 4F 26 lds.l @r15+, pr ; Load to System Register Long
ROM:000B9840 00 6B rts/n ; Return from Subroutine with No delay slot