This project started as a simple attempt to improve air-fuel ratio (AFR) monitoring in my 2004 Monte Carlo SS. The stock GM P04 PCM reads from a narrowband oxygen sensor, which only reports whether the exhaust gas is rich or lean relative to stoichiometric AFR (14.7:1) by outputting a voltage between 0 and 1 volts. In this system, 0.01 to 0.44V indicates lean, while 0.46 to 1V indicates rich, but it provides no actual AFR reading. Stoichiometric, or stoich, refers to the ideal AFR where fuel and air are present in perfect proportion for complete combustion, 14.7 parts air to 1 part fuel for gasoline. Targeting this ratio ensures the engine is neither too rich nor too lean under normal conditions, making it a key reference point for efficiency and emissions. In contrast, a wideband oxygen sensor gives a true AFR measurement over a 0 to 5V range. I wanted to install the wideband so I could log AFR over a drive and correct my Mass Airflow (MAF) table, since it had been reading lean throughout the entire range after installing the larger intake and 1.9:1 rockers, both of which allow more airflow.
Very quickly, I learned this would not be as simple as wiring in a new sensor. The PCM was not designed to interpret a 0 to 5V wideband signal, only the narrowband’s binary rich or lean indication. As I dug deeper, I started to realize that if I could get the PCM to read the wideband input properly, I could potentially modify the firmware itself to process and act on that more precise data. That realization shifted the entire scope of the project. I was not just looking to install a sensor anymore, I was working toward rewriting the AFR control logic inside the PCM.
Early on I found that this OS was both more complex and simpler than I expected. It is a fast loop based system where all logic is executed and updated in milliseconds, making real time responsiveness possible if I could understand its workings. As I continued researching and mapping available sensor inputs, I realized I could go far beyond simply reading from a wideband. The PCM architecture and available inputs made it feasible to create a fully custom AFR control system inside the PCM itself.
That idea opened up the possibility of building a mode switch to select different AFR targets on the fly. I envisioned mounting a discreet 3 way switch in the cigarette lighter hole, right in front of the shifter, so I could toggle between a normal mode, an eco mode targeting leaner AFRs (around 16.5:1) to improve fuel economy, and a performance mode running richer (around 11.5:1) to lower combustion temperatures and help avoid knock during high boost conditions.
For this switch, I plan to feed a 1V reference signal into the switch and have it return either 0V, 0.5V, or 1V to the PCM depending on position. The PCM will interpret this analog voltage as the selected mode. Because of the PCM’s rapid loop time (around 10 to 15ms), this system should be hot swappable, updating AFR targets essentially in real time as I drive.
Before I could even begin reversing the OS, I needed a reliable way to read the PCM’s flash memory and eventually write changes back for testing. The only easy commercial solution for the GM P04 PCM is HP Tuners, but their approach is expensive. It requires around $400 for the hardware and then $50 for every flash, and even then the files it saves are in a proprietary format that would not be as clean to work with in Ghidra. I found an open source alternative in PCM Hammer, which has an experimental build that supports the P04 PCM. However, I quickly ran into issues. Every read I performed failed its CRC check at the end. After digging into the tool itself, I modified the PCM Hammer source code to eliminate the CRC verification step after dumping, allowing me to retrieve clean binary reads even though the tool reported failures. To ensure the integrity of the dump, I read the PCM six times and verified that all six reads were identical. This read workflow is what allowed me to get the full firmware dumped from my PCM so I could analyze it in Ghidra.
In parallel, I began documenting the entire wiring harness, determining which PCM pins could be safely reused without interfering with essential functions. My handwritten notebooks include detailed evaluations of candidates like C1P28 (EGR solenoid low control) and C2P75 (potential on or off output). Some pins require additional research, for example checking if a pin might trip a warning light due to a BCM dependency before repurposing it.
The CRC check logic in PCM Hammer, which I modified to allow clean reads from the P04 PCM despite reported failures.
Ghidra's XREF window shows where variables are referenced, and how (read vs write).
On the software side, my process involved working off the known calibration data from my tuning software. I converted known tables to hex, then searched for those values in Ghidra to locate and label them correctly. Once found, I ensured that Ghidra was interpreting them as complete, contiguous tables, sometimes correcting cases where tables would read only partially due to embedded null bytes splitting them. Through this I learned a lot about 3D tables and how GM used simple multiplier scaling techniques to store them compactly.
This effort required me to develop skills I did not have when I started. I had zero understanding of M68K instructions before this project, the closest I had come was working in SIC Assembly as part of coursework. From there I had to learn Motorola 68k (M68K) assembly instructions, master Ghidra’s workflow, and understand the interplay between calibration data and control routines. M68K is an older processor architecture that competed with x86 back in the day but lost out, and it has been obsolete for decades now. It still found use in embedded systems like this PCM, which means I had to work through old architecture quirks and limitations. Few resources specific to this OS and PCM exist, so I had to figure much of it out myself, relying on a combination of careful documentation, educated guesses, and intuition.
At this point, I feel I have developed a solid understanding of the PCM’s internal structure and am ready to begin wiring the wideband sensor, validating inputs, and eventually writing my own AFR control routines. The most rewarding part has been the clarity that comes with identifying what an undocumented function actually does. The most frustrating has been the hardware setbacks outside of the software itself, which have delayed validation and testing.
The deeper impact of this project has been realizing that my skill set allows me to tackle any kind of challenge. I am taking a decades old platform, doing something nobody has documented before, and building the confidence that I can bridge mechanical, electrical, and software domains to accomplish whatever I set out to do. Just as important, this project made me realize how much of the knowledge I gained during my time at UNF has been directly applicable. The classes I previously thought were useless, like Systems Software, actually gave me the in-depth understanding of low level computing that made this possible. That foundation gave me the ability to navigate an obsolete processor architecture and an undocumented OS and figure things out on my own.