Old Siemens ECU (MC68HC11)
-
Tobi_gNT
- Posts: 13
- Joined: Sat Aug 15, 2026 7:12 am
- cars: Golf 3 16V ABF Digifant3.2
BMW 335i N54 MSD80
Old Siemens ECU (MC68HC11)
Hello,
I have a Golf 3 2.0L ABF with a Siemens Digifant 3.2 ECU, part number 5WP4 304 037906024 BE.
MCU: Motorola MC68HC11G5FN1 (1C28M / ZQZOE9508)
EPROM: 27C256
While Digifant 1 (also HC11-based) is well documented and largely decrypted, Digifant 3.2 is still mostly unexplored.
I have read out the 27C256 EPROM and identified some tables:
0x117 – 16x16 Fuel MAP?
0x90E – 16x16 ??
0x362 – 4x16 ??
0x3A2 – 4x16 ??
0x5C2 – 16x16 Ignition MAP [(210-x)/4] – tested!
0x4C2 – 16x16 ??
0xD20 – 16-bit rev limiter – tested!
However, there is still a lot of code and many tables in the 27C256 that I don't understand or know the purpose of.
I have searched the entire internet, but I haven't been able to find a truly good .xdf file for this ECU. I have attached the only one I managed to find, but unfortunately, it isn't very informative.
Since I am still fairly new to reverse engineering, I wanted to ask if you could possibly help me with this.
I have attached the following files:
Pictures of the ECU
Original 27C256 EPROM dump
Any help or guidance would be greatly appreciated
Best regards,
Tobi
I have a Golf 3 2.0L ABF with a Siemens Digifant 3.2 ECU, part number 5WP4 304 037906024 BE.
MCU: Motorola MC68HC11G5FN1 (1C28M / ZQZOE9508)
EPROM: 27C256
While Digifant 1 (also HC11-based) is well documented and largely decrypted, Digifant 3.2 is still mostly unexplored.
I have read out the 27C256 EPROM and identified some tables:
0x117 – 16x16 Fuel MAP?
0x90E – 16x16 ??
0x362 – 4x16 ??
0x3A2 – 4x16 ??
0x5C2 – 16x16 Ignition MAP [(210-x)/4] – tested!
0x4C2 – 16x16 ??
0xD20 – 16-bit rev limiter – tested!
However, there is still a lot of code and many tables in the 27C256 that I don't understand or know the purpose of.
I have searched the entire internet, but I haven't been able to find a truly good .xdf file for this ECU. I have attached the only one I managed to find, but unfortunately, it isn't very informative.
Since I am still fairly new to reverse engineering, I wanted to ask if you could possibly help me with this.
I have attached the following files:
Pictures of the ECU
Original 27C256 EPROM dump
Any help or guidance would be greatly appreciated
Best regards,
Tobi
You do not have the required permissions to view the files attached to this post.
Last edited by Tobi_gNT on Sat Aug 15, 2026 4:47 pm, edited 1 time in total.
-
Tobi_gNT
- Posts: 13
- Joined: Sat Aug 15, 2026 7:12 am
- cars: Golf 3 16V ABF Digifant3.2
BMW 335i N54 MSD80
Re: Old Siemens ECU (HC11)
with Ghidra i dont found MC68HC11 processor
...i´m I on the wrong track?
...i´m I on the wrong track?
-
geep
- Posts: 47
- Joined: Sat Feb 02, 2019 3:43 pm
- cars: 60 ford falcon 07 grand prix 94 chevy swb ls swaped
Re: Old Siemens ECU (MC68HC11)
https://www.nxp.com/docs/en/data-sheet/M68HC11E.pdf
not sure if it will help but it has some code examples in it
not sure if it will help but it has some code examples in it
-
antus
- Site Admin
- Posts: 10076
- Joined: Sat Feb 28, 2009 10:34 am
- cars: TX Gemini 2L Twincam 8psi
TX Gemini SR20 18psi
Datsun 1200 Ute
Subaru Blitzen '06 EZ30 4th gen, 3.0R Spec B
Subaru WRX 2007
Re: Old Siemens ECU (MC68HC11)
Try hc11 or hcs11. Post a bin of the similar well defined ecm and well defined xdf and it might be possible with some help from AI to port most of it across if theyre that close.
Have you read the FAQ? For lots of information and links to significant threads see here: http://pcmhacking.net/forums/viewtopic.php?f=7&t=1396
-
Tobi_gNT
- Posts: 13
- Joined: Sat Aug 15, 2026 7:12 am
- cars: Golf 3 16V ABF Digifant3.2
BMW 335i N54 MSD80
Re: Old Siemens ECU (MC68HC11)
i have found a MC68HC11 for Ghidra:
https://github.com/GaryOderNichts/ghidra-hc11-lang
But it's not exactly the same: the Digifant 3.2 ECU uses the MC68HC11G5FN1 chip. i have loaded (M68HC11RM/D)
I added the HC11 dataset in Ghidra, but when opening the project, and analysed. I only get this far—see the image. I suspect it's the wrong processor definition?
@Antus
There is already a post about the Digifant 1 HC11 here in the forum.
viewtopic.php?p=54719&hilit=digifant#p54719
At the very bottom of the last post,it is the .xdf and original .bin files for the Digifant 1.
I manually compared the .xdf file for the Digifant 1 and examined the tables and conversion formulas, but I don't think much of it is applicable to the Digifant 3.2—except for the ignition table and RPM conversions.
https://github.com/GaryOderNichts/ghidra-hc11-lang
But it's not exactly the same: the Digifant 3.2 ECU uses the MC68HC11G5FN1 chip. i have loaded (M68HC11RM/D)
I added the HC11 dataset in Ghidra, but when opening the project, and analysed. I only get this far—see the image. I suspect it's the wrong processor definition?
@Antus
There is already a post about the Digifant 1 HC11 here in the forum.
viewtopic.php?p=54719&hilit=digifant#p54719
At the very bottom of the last post,it is the .xdf and original .bin files for the Digifant 1.
I manually compared the .xdf file for the Digifant 1 and examined the tables and conversion formulas, but I don't think much of it is applicable to the Digifant 3.2—except for the ignition table and RPM conversions.
You do not have the required permissions to view the files attached to this post.
-
antus
- Site Admin
- Posts: 10076
- Joined: Sat Feb 28, 2009 10:34 am
- cars: TX Gemini 2L Twincam 8psi
TX Gemini SR20 18psi
Datsun 1200 Ute
Subaru Blitzen '06 EZ30 4th gen, 3.0R Spec B
Subaru WRX 2007
Re: Old Siemens ECU (MC68HC11)
See if this gets you started. I used AI to look at the early bin and XDF and locate RPM in RAM. Then asked it to look at the shape of the functions in the new bin, being a later revision of the same platform, and attempt to identify fuel and spark tables. And gave it a direction of where we would be going. It identified some key routines and RAM, but then discarded the plan and went its own way, lol. This is a first cut from one session. I have not looked at checksums, and don't have any way to validate this. I would expect different HC11s still use the same bytecode, and should disassemble. Just onboard registers or eeprom or RAM sizes and things like that may be different. In your case, I think it may not have detected the reset vector and not started converting in to code. Perhaps the load address of the bin is wrong. For HC11 the reset vector is the last 2 bytes at FFFF so you may need to offset the whole file to load top justified ending at FFFF.
AI Warning, looks accurate but could have errors. See if this helps you get started:
VW Digifant 3.1 - 037 906 024 BE - full ROM teardown and a working XDF
This is a reverse engineering write-up of the Digifant 3.1 ECU 037 906 024 BE (software version 2121). No public XDF existed for this ECU, so it was built from the ROM itself rather than ported by address from the well-known Corrado G60 definition.
Short version of why that matters: the 3.1 image shares only 4 percent of its bytes with the G60 3-map ROM and is twice the size. It is a rewrite, not a recompile, so shifting the old XDF by a fixed offset does not work. What does carry across is the structure - the same engineers solving the same problem with the same arithmetic.
Everything below is derived from the code, not guessed from data shapes.
1. CPU and load geometry
CPU is a Motorola 68HC11. Confirmed by an exact 21-entry HC11 vector table at the top of the image, plus 0x18 (the Y prebyte) and 0xBD (JSR extended) being among the most frequent bytes in the file.
ROM occupies CPU 0x8000-0xFFFF, mapped 1:1 from file 0x0000-0x7FFF. Vectors sit at file 0x7FD6-0x7FFF (= CPU 0xFFD6-0xFFFF) and every vector target lands inside the ROM window, so there is no ambiguity.
Note this is different from the earlier G60 ECU, which aliases: on the G60 the ROM is only 16 KB and A15 is not decoded, so it appears at both 0x4000 and 0xC000, and the stored vector targets have bit 15 clear. The 3.1 does none of that.
IDA load parameters:
Memory map, confirmed from the reset code (it writes INIT = 0x01, and clears RAM up to 0x01FF):
Reset also does ldy #$1000, so most register access in this ROM is indexed as offset,y rather than extended. If you do not account for that, the register reads disassemble as meaningless absolute loads.
2. Identification block
At file 0x7FC0 (CPU 0xFFC0), immediately below the vector table:
So a filename like 037906024_BE_2121_8570 is fully accounted for except the trailing 8570, which is not in this block. That is almost certainly a checksum stored elsewhere. See the warning at the end.
3. Interrupt vectors
Standard HC11 layout. These are the best seed entry points - every one should end in RTI.
The OC handlers sit at evenly spaced addresses (E743, E802, E8C1, E980, EA3F - spacing 0xBF each). Near-identical handler sizes strongly suggest four injector drivers plus one ignition channel.
OC = pulse output (injector open time, coil dwell/fire). IC = pulse input (crank/cam sensing). Start any RPM work at IC1/IC3.
Open question: five more pointer-shaped words sit below 0xFFD6, at 0xFFCC-0xFFD4: E690, E60C, ED83, E6DC, E735. They all land in ROM and look like code pointers, which would make this an extended-vector HC11 derivative rather than a plain A/E series. The G60 ECU has plain filler in that space, so this is a real difference, not a mis-read. If anyone knows which HC11 variant Siemens used here, that would settle it.
4. The lookup primitives - this is the key
Every calibration on this platform is read through a tiny library of lookup routines. Find those, cross-reference every caller, and the entire table inventory enumerates itself. You do not have to hunt for tables by eye.
In the 3.1 that library sits at 0xF150-0xF3C2:
lookup_T16_interp is literally:
which is exactly (t*(16-p) + t[i+1]*p + 8) / 16, where i is the high nibble of the index and p the low nibble. That is the same formula documented years ago in convertParams.py for the G60. The platform convention survived the rewrite intact.
search_breakpoints16_u16 (0xF292) is instruction-for-instruction identical to the G60's sub_520B.
Table width - do not assume 17. Because the kernel reads t[i+1], an interpolated table can be 17 bytes. But many bases here are packed exactly 16 apart, and in that case the overrun simply lands on the next table's first byte, which is harmless because at index 0xF0 the fraction is zero. The reliable method is to take each table's width from the gap to the next known table base. Tables read by lookup_T16_noninterp never touch t[i+1] and are always 16.
5. The engine speed anchor
This is the single most useful thing to find in any of these ROMs. Anchor on the RAM variable, not on code layout - a RAM address survives a rewrite far better than any byte signature.
calc_engine_speed_index (sub_985A) is the direct analogue of the G60's sub_51D5:
RAM map that falls out of it:
RAM 0xA2 has 2 writers and 58 readers, and cross-referencing it turns up around 30 distinct calibration tables. Every single one of the six 16x16 maps takes it as an axis. That is exactly what you would expect, and it is strong independent confirmation that the identification is right.
6. The rpm axis tables, decoded
Both are 16 ascending 16-bit big-endian crank periods. RPM = 15000000 / value.
0x8EA7 - main RPM axis
Raw: 085E 0955 0A78 0BD2 0D72 0F6C 11DB 14E5 18BE 1DB2 2431 2CE6 38B8 4926 600E 7F60
0x8EC7 - idle RPM axis (read by idle_speed_control, sub_CDAF)
Period ascending means rpm descending, so index 0 is the highest rpm. An XDF axis needs the reversed stride that the G60 definition already uses.
This also settles an old inconsistency in the published G60 XDF. That definition uses 15000000/X on its map axes (correct) but 30000000/X on its standalone "RPM Scalar" table (wrong - it would double every number). 15000000/period produces physically sane ladders on both ECUs; 30000000 would put this engine's redline at 14000 rpm. convertParams.py had it right.
7. Map roles
0x84C2 is the ignition map because ignition_advance_from_map (sub_DB16) wraps the lookup in angular arithmetic - it clamps at 0x77 and wraps modulo 0x78, i.e. 120 counts per angular segment - and its caller sub_D964 also invokes the routine that writes TCNT/TCTL1 to schedule the output compare. Nothing else in the ROM has that shape.
It also behaves correctly as a spark map: values fall left-to-right as rpm falls, and fall again with increasing load. Both are what advance should do.
0x8A3E and 0x85C2 share an identical but quite different signature - bilinear lookup, addd #$80 (round to nearest), store one byte. That is a fuelling quantity, not an angle.
0x82E2 turned out to be 8 rows, not 16: another table base sits only 128 bytes in. That is exactly why its data looked banded rather than smooth.
8. The XDF
92 tables, no overlapping regions, confidence marked per table:
Notes on using it:
9. Warnings and open items
AI Warning, looks accurate but could have errors. See if this helps you get started:
VW Digifant 3.1 - 037 906 024 BE - full ROM teardown and a working XDF
This is a reverse engineering write-up of the Digifant 3.1 ECU 037 906 024 BE (software version 2121). No public XDF existed for this ECU, so it was built from the ROM itself rather than ported by address from the well-known Corrado G60 definition.
Short version of why that matters: the 3.1 image shares only 4 percent of its bytes with the G60 3-map ROM and is twice the size. It is a rewrite, not a recompile, so shifting the old XDF by a fixed offset does not work. What does carry across is the structure - the same engineers solving the same problem with the same arithmetic.
Everything below is derived from the code, not guessed from data shapes.
1. CPU and load geometry
CPU is a Motorola 68HC11. Confirmed by an exact 21-entry HC11 vector table at the top of the image, plus 0x18 (the Y prebyte) and 0xBD (JSR extended) being among the most frequent bytes in the file.
Code: Select all
CPU address = file offset + 0x8000Note this is different from the earlier G60 ECU, which aliases: on the G60 the ROM is only 16 KB and A15 is not decoded, so it appears at both 0x4000 and 0xC000, and the stored vector targets have bit 15 clear. The 3.1 does none of that.
IDA load parameters:
Code: Select all
Processor 6811 (Motorola 68HC11)
Loading offset / ROM base 0x8000
File offset 0x0
Size 0x8000
Entry point 0x9200Code: Select all
RAM 0x0000-0x01FF internal RAM, 512 bytes
REGS 0x1000-0x105F HC11 register block
ROM 0x8000-0xFFFF the image2. Identification block
At file 0x7FC0 (CPU 0xFFC0), immediately below the vector table:
Code: Select all
7FC0: 21 21 00 37 90 60 24 42 45 00 00 41
^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^
2121 0037906024 (BCD) "BE"
21 21 BCD 2121 - software / calibration version
00 37 90 60 24 BCD 0037906024 - VW part number 037 906 024
42 45 ASCII "BE" - variant suffix
00 00 41 unresolved3. Interrupt vectors
Standard HC11 layout. These are the best seed entry points - every one should end in RTI.
Code: Select all
CPU vec Target File Interrupt
FFD6 B562 0x3562 SCI (serial - diagnostics / K-line)
FFD8 EE4C 0x6E4C SPI
FFDA EE4D 0x6E4D Pulse Accumulator Input Edge
FFDC EE19 0x6E19 Pulse Accumulator Overflow
FFDE ED7D 0x6D7D Timer Overflow
FFE0 E743 0x6743 Output Compare 5
FFE2 E802 0x6802 Output Compare 4
FFE4 E8C1 0x68C1 Output Compare 3
FFE6 E980 0x6980 Output Compare 2
FFE8 EA3F 0x6A3F Output Compare 1
FFEA E6AF 0x66AF Input Capture 3
FFEC EE33 0x6E33 Input Capture 2
FFEE EE1B 0x6E1B Input Capture 1
FFF0 ED00 0x6D00 Real Time Interrupt
FFF2 EE10 0x6E10 IRQ
FFF4 EE4E 0x6E4E XIRQ
FFF6 EE1A 0x6E1A SWI
FFF8 9200 0x1200 Illegal Opcode -> reset
FFFA 9200 0x1200 COP failure -> reset
FFFC 9200 0x1200 Clock Monitor -> reset
FFFE 9200 0x1200 RESETOC = pulse output (injector open time, coil dwell/fire). IC = pulse input (crank/cam sensing). Start any RPM work at IC1/IC3.
Open question: five more pointer-shaped words sit below 0xFFD6, at 0xFFCC-0xFFD4: E690, E60C, ED83, E6DC, E735. They all land in ROM and look like code pointers, which would make this an extended-vector HC11 derivative rather than a plain A/E series. The G60 ECU has plain filler in that space, so this is a real difference, not a mis-read. If anyone knows which HC11 variant Siemens used here, that would settle it.
4. The lookup primitives - this is the key
Every calibration on this platform is read through a tiny library of lookup routines. Find those, cross-reference every caller, and the entire table inventory enumerates itself. You do not have to hunt for tables by eye.
In the 3.1 that library sits at 0xF150-0xF3C2:
Code: Select all
Addr Name G60 equivalent Reads
0xF1A7 interp_kernel_T16 0x53FC core interpolation
0xF19C lookup_T16_interp 0x5759 55 tables, 35 callers
0xF1F4 lookup_T16_noninterp - 14 tables, no interpolation
0xF150 lookup_map16x16_bilinear 0x5187 6 maps, row stride 16
0xF292 search_breakpoints16_u16 0x520B 2 rpm axis tables
0xF280 interp_blend - 2-D blend helperCode: Select all
bsr interp_kernel_T16
addd #8
lsrd
lsrd
lsrd
lsrdsearch_breakpoints16_u16 (0xF292) is instruction-for-instruction identical to the G60's sub_520B.
Table width - do not assume 17. Because the kernel reads t[i+1], an interpolated table can be 17 bytes. But many bases here are packed exactly 16 apart, and in that case the overrun simply lands on the next table's first byte, which is harmless because at index 0xF0 the fraction is zero. The reliable method is to take each table's width from the gap to the next known table base. Tables read by lookup_T16_noninterp never touch t[i+1] and are always 16.
5. The engine speed anchor
This is the single most useful thing to find in any of these ROMs. Anchor on the RAM variable, not on code layout - a RAM address survives a rewrite far better than any byte signature.
calc_engine_speed_index (sub_985A) is the direct analogue of the G60's sub_51D5:
Code: Select all
ldd <ram_crank_period ; RAM 0xBF
tst ram_crank_period_hi ; RAM 0xBE
ldab #$F0 ; clamp - same as the G60
ldx #$8EA7 ; the RPM breakpoint table
jsr search_breakpoints16_u16
stab <ram_rpm_index_raw ; RAM 0xA1
addb <ram_rpm_index / rorb ; (new + old) / 2
stab <ram_rpm_index ; RAM 0xA2Code: Select all
0x80 ram_load_index load (MAP) axis
0xA2 ram_rpm_index ENGINE SPEED INDEX 0x00-0xF0 <-- the big one
0xA1 / 0xA3 raw / previous pre-filter and previous sample
0xBE-0xC0 ram_crank_period RPM = 15000000 / period
0xC5 ram_ignition_angle ignition advance output
0xA0, 0xAE fuel outputs results of the two fuel maps6. The rpm axis tables, decoded
Both are 16 ascending 16-bit big-endian crank periods. RPM = 15000000 / value.
0x8EA7 - main RPM axis
Raw: 085E 0955 0A78 0BD2 0D72 0F6C 11DB 14E5 18BE 1DB2 2431 2CE6 38B8 4926 600E 7F60
Code: Select all
7003 6279 5597 4957 4358 3799 3282 2804
2368 1973 1619 1305 1033 801 610 460 rpmCode: Select all
1600 1527 1453 1380 1307 1233 1160 1087
1013 940 867 793 720 647 573 500 rpmThis also settles an old inconsistency in the published G60 XDF. That definition uses 15000000/X on its map axes (correct) but 30000000/X on its standalone "RPM Scalar" table (wrong - it would double every number). 15000000/period produces physically sane ladders on both ECUs; 30000000 would put this engine's redline at 14000 rpm. convertParams.py had it right.
7. Map roles
Code: Select all
Addr Role Confidence
0x84C2 Ignition / spark advance HIGH
0x8A3E Fuel (-> RAM 0xA0) medium-high
0x85C2 Fuel (-> RAM 0xAE) medium-high
0x8117 unclassified low
0x890E unclassified low
0x82E2 unclassified, 8 rows not 16 lowIt also behaves correctly as a spark map: values fall left-to-right as rpm falls, and fall again with increasing load. Both are what advance should do.
0x8A3E and 0x85C2 share an identical but quite different signature - bilinear lookup, addd #$80 (round to nearest), store one byte. That is a fuelling quantity, not an angle.
0x82E2 turned out to be 8 rows, not 16: another table base sits only 128 bytes in. That is exactly why its data looked banded rather than smooth.
8. The XDF
92 tables, no overlapping regions, confidence marked per table:
Code: Select all
1 x Ignition
2 x Fuel
2 x Axes and Breakpoints (real rpm, verified)
45 x 1-D Tables (interpolated)
11 x 1-D Tables (stepped)
3 x Unclassified Maps
28 x Unverified - inspection only- Map columns are rpm descending left to right (7003 down to 460), because index 0 is the shortest crank period. Rows are the load index 0-240.
- Everything except the two rpm axes is shown as raw counts. I deliberately did not bake in an unverified degrees-per-bit for ignition. 0.75 deg/bit would give a very plausible 18-36 deg, but it is not derived yet, and a wrong ignition scale is the worst kind to publish.
- Anything in Unclassified or Unverified is inspection only. The addresses and shapes are solid; the meanings are not.
9. Warnings and open items
Still open:The checksum algorithm for this ECU is not yet known. The 8570 in the filename is not in the ID block, so it is stored somewhere else or computed. Until that is solved, treat writing a modified bin as untested - it may be rejected or run incorrectly. Read and inspect freely.
- Checksum algorithm and location. This blocks any actual flashing.
- Degrees per bit for the ignition map. Needs the code that converts ram_ignition_angle into an output compare count.
- Which physical output each of the four OC handlers drives. That would pin the fuel maps down properly.
- Whether this is an extended-vector HC11 variant (the 0xFFCC question above).
- I only have one calibration of this ECU. A second or third 037 906 024 variant would allow differential analysis - regions that differ between calibrations of the same code base are, by definition, the calibration tables. This is by far the highest-value thing anyone could contribute.
You do not have the required permissions to view the files attached to this post.
Have you read the FAQ? For lots of information and links to significant threads see here: http://pcmhacking.net/forums/viewtopic.php?f=7&t=1396
-
Tobi_gNT
- Posts: 13
- Joined: Sat Aug 15, 2026 7:12 am
- cars: Golf 3 16V ABF Digifant3.2
BMW 335i N54 MSD80
Re: Old Siemens ECU (MC68HC11)
Wow, at first glance, what the AI is producing looks very impressive. Unfortunately, though, I can’t really do anything with the tables. On top of that, they’re also incorrect — not all of them, but around 90%. The only thing that seems to be correct are the RMP ranges.
If Digifant 1 and Digifant 3.2 were identical, things would certainly be much easier. Unfortunately, they aren’t.
I’ve also played around a bit more with Ghidra and used the base address 0x8000. Now I’m getting functions displayed, but at this point I’m completely lost... I also have no idea whether this is even correct.
Maybe someone here can point me in the right direction?
If Digifant 1 and Digifant 3.2 were identical, things would certainly be much easier. Unfortunately, they aren’t.
I’ve also played around a bit more with Ghidra and used the base address 0x8000. Now I’m getting functions displayed, but at this point I’m completely lost... I also have no idea whether this is even correct.
Maybe someone here can point me in the right direction?
You do not have the required permissions to view the files attached to this post.
-
antus
- Site Admin
- Posts: 10076
- Joined: Sat Feb 28, 2009 10:34 am
- cars: TX Gemini 2L Twincam 8psi
TX Gemini SR20 18psi
Datsun 1200 Ute
Subaru Blitzen '06 EZ30 4th gen, 3.0R Spec B
Subaru WRX 2007
Re: Old Siemens ECU (MC68HC11)
it looks correct from what we can see. the opcodes look valid and the code structure viable.
Have you read the FAQ? For lots of information and links to significant threads see here: http://pcmhacking.net/forums/viewtopic.php?f=7&t=1396
-
pman92
- Posts: 672
- Joined: Thu May 03, 2012 12:50 pm
- Location: Castlemaine, Vic
Re: Old Siemens ECU (MC68HC11)
Looks like real code to me. You'll know pretty quickly when it's not correct.Tobi_gNT wrote: Sun Aug 16, 2026 5:52 pm Now I’m getting functions displayed, but at this point I’m completely lost... I also have no idea whether this is even correct.
If you have a valid XDF or any known tables etc for this file that you've already found, start labelling them in ghidra. From there you will be able to find what references them and they should lead elsewhere
-
antus
- Site Admin
- Posts: 10076
- Joined: Sat Feb 28, 2009 10:34 am
- cars: TX Gemini 2L Twincam 8psi
TX Gemini SR20 18psi
Datsun 1200 Ute
Subaru Blitzen '06 EZ30 4th gen, 3.0R Spec B
Subaru WRX 2007
Re: Old Siemens ECU (MC68HC11)
I still have the code open and asked it to find load and it progressed this far. Removed first XDF and added update here. Still experimental and not usable.
Code: Select all
Load measurement: it's MAP (speed-density)
RAM 0x80 is the load axis. Signal path: external converter channel 0x1040 → sub_9758 → 4-deep shift register 0x95–0x98 → averaged → 0x99 → second register 0x9A–0x9C → averaged → 0x80. Sampled synchronously with engine events and double-averaged, which is what you do to a pulsating manifold-pressure signal.
The decisive evidence is an absence: nothing in the ROM ever combines the load value with a time base. Any flow meter measures quantity per unit time, so it must be multiplied by cycle time to give charge per cycle. The set of functions reading the load variable and the set reading a period variable are disjoint. The only use of crank period in the injector path is sub_A88F, which is a duty-cycle limiter. That's speed-density.
Supporting: it's analogue via an external converter (not a frequency input, so not a digital MAF); the plausibility ceiling 0x8C1F is flat at 48 from 1033–7003 rpm, which is meaningless for a flow meter but natural for pressure; and the G60 sibling is unambiguously MAP. High confidence, not proven — the kPa-per-bit scaling is still underived, so the axis ships as the raw 0–240 index rather than a fake pressure scale.
The error the feedback was pointing at
My index attribution was wrong in method. I was looking forward from any read of a candidate RAM byte to the next table lookup — which mis-assigns whenever a function touches several variables before the lookup. The correct method walks backward from each lookup call to the last ldab, since B holds the index.
Redoing it properly:
Table Was Now
0x8A3E "Fuel Map A" Substitute load model — its output replaces the MAP signal when the sensor is flagged faulty
0x85C2 "Fuel Map B" Unclassified — not in the main fuel chain; label was unsupported
0x8117 "Unclassified" Fuel trim map, signed around 0x80
0x82E2 "Unclassified" Fuel chain, 8 rows
So both tables I'd called fuel maps were wrong, and one I'd dismissed is a real fuel table. The actual fuel routine is sub_A2EA. RPM being right is consistent — it's the one axis I'd derived end-to-end and validated numerically.
Bonus finds along the way
RAM 0x91 is coolant temperature — sub_D61F is a textbook thermistor handler (open-circuit above 0xE5, short below 0x10, slew filter, substitute value on fault). It indexes 16 tables, the second most common axis after rpm.
The whole external converter bank at 0x1040–0x104F is mapped: load, battery, coolant, intake air, and a 16-bit channel that's probably throttle.
0x8106 is the injector dead-time vs battery table — curve 255 255 255 255 255 199 114 68 35 13 0…, near-identical in shape to the G60's 0x462E. That's the third POC target now located in the target ECU.
Updated
XDF regenerated — 48 of 92 tables now carry an identified physical axis (19 rpm, 14 coolant, 9 MAP load, 3 intake air, 2 battery, 1 throttle) instead of a generic index. The other 44 are honestly labelled as unidentified. The .i64 has all the new names and comments, and there's a new _index_map.txt with the per-table axis derivation.
If the OP can say which tables looked wrong rather than just "many", I can check them directly — but the axis relabelling above should account for a lot of it on its own.
You do not have the required permissions to view the files attached to this post.
Have you read the FAQ? For lots of information and links to significant threads see here: http://pcmhacking.net/forums/viewtopic.php?f=7&t=1396