Skip to content

Instantly share code, notes, and snippets.

@VIRUXE
Created November 26, 2025 22:19
Show Gist options
  • Select an option

  • Save VIRUXE/eefa0443a9cd4a0e1a7cff45141c79b8 to your computer and use it in GitHub Desktop.

Select an option

Save VIRUXE/eefa0443a9cd4a0e1a7cff45141c79b8 to your computer and use it in GitHub Desktop.
/**
* ============================================================================
* HONDA P30 OBD1 ECU FIRMWARE - PSEUDO-C CONVERSION
* ============================================================================
*
* Original File: P30_203.asm
* Target MCU: OKI M66207 (OBD1)
* ECU Type: Honda P30 (USDM B16A3, B18C1, etc.)
*
* This is a PSEUDO-C representation of the OBD1 ECU firmware.
* NOT compilable code - documentation format for understanding assembly logic.
*
* Conversion includes:
* - All 2,394 labels renamed with meaningful context
* - RAM variables inferred from usage patterns
* - All 14 interrupt handlers
* - 8 VCAL helper functions
* - Complete main engine logic
* - Data tables documented
*
* ============================================================================
*/
#include <stdint.h>
#include <stdbool.h>
/*============================================================================
* SECTION 1: OKI M66207 HARDWARE REGISTER DEFINITIONS
*
* The M66207 is a 16-bit CMOS microcontroller with:
* - 16-bit data bus, 20-bit address bus
* - 8 channels of 10-bit ADC
* - 4 timers (16-bit)
* - 2 PWM channels
* - Serial communication (UART)
* - Watchdog timer
*============================================================================*/
/* ---- CPU Control Registers ---- */
#define REG_PSW (*(volatile uint16_t*)0x0004) // Processor Status Word
#define REG_PSWL (*(volatile uint8_t*)0x0004) // PSW Low (flags)
#define REG_PSWH (*(volatile uint8_t*)0x0005) // PSW High (bank select)
#define REG_ACC (*(volatile uint16_t*)0x0006) // 16-bit Accumulator
#define REG_ACCH (*(volatile uint8_t*)0x0007) // Accumulator High byte
#define REG_LRB (*(volatile uint8_t*)0x0008) // Local Register Bank pointer
#define REG_DP (*(volatile uint16_t*)0x000A) // Data Pointer
#define REG_USP (*(volatile uint16_t*)0x000C) // User Stack Pointer
#define REG_SSP (*(volatile uint16_t*)0x000E) // System Stack Pointer
#define REG_SBYCON (*(volatile uint8_t*)0x0010) // Standby Control
#define REG_WDT (*(volatile uint8_t*)0x0011) // Watchdog Timer
#define REG_STPACP (*(volatile uint8_t*)0x0013) // Stop/Accept control
/* ---- Interrupt Control ---- */
#define REG_IRQ (*(volatile uint8_t*)0x0018) // Interrupt Request flags
#define REG_IRQH (*(volatile uint8_t*)0x0019) // IRQ High byte
#define REG_IE (*(volatile uint16_t*)0x001A) // Interrupt Enable
/* ---- Port Registers ---- */
#define REG_P0 (*(volatile uint8_t*)0x0020) // Port 0 (CEL, AC clutch, purge)
#define REG_P0IO (*(volatile uint8_t*)0x0021) // Port 0 Direction
#define REG_P1 (*(volatile uint8_t*)0x0022) // Port 1 (VTEC, CEL LED)
#define REG_P1IO (*(volatile uint8_t*)0x0023) // Port 1 Direction
#define REG_P2 (*(volatile uint8_t*)0x0024) // Port 2 (Injectors 1-4)
#define REG_P2IO (*(volatile uint8_t*)0x0025) // Port 2 Direction
#define REG_P2SF (*(volatile uint8_t*)0x0026) // Port 2 Special Function
#define REG_P3 (*(volatile uint8_t*)0x0028) // Port 3 (Ignition output)
#define REG_P3IO (*(volatile uint8_t*)0x0029) // Port 3 Direction
#define REG_P3SF (*(volatile uint8_t*)0x002A) // Port 3 Special Function
#define REG_P4 (*(volatile uint8_t*)0x002C) // Port 4 (External inputs)
#define REG_P4IO (*(volatile uint8_t*)0x002D) // Port 4 Direction
#define REG_P4SF (*(volatile uint8_t*)0x002E) // Port 4 Special Function
#define REG_P5 (*(volatile uint8_t*)0x0030) // Port 5
#define REG_P5IO (*(volatile uint8_t*)0x0031) // Port 5 Direction
/* ---- Timer Registers ---- */
#define REG_TM0 (*(volatile uint16_t*)0x0030) // Timer 0 Counter (Injector timing)
#define REG_TMR0 (*(volatile uint16_t*)0x0032) // Timer 0 Reload/Compare
#define REG_TM1 (*(volatile uint16_t*)0x0034) // Timer 1 Counter (RPM/TDC)
#define REG_TMR1 (*(volatile uint16_t*)0x0036) // Timer 1 Reload/Compare
#define REG_TM2 (*(volatile uint16_t*)0x0038) // Timer 2 Counter (Ignition dwell)
#define REG_TMR2 (*(volatile uint16_t*)0x003A) // Timer 2 Reload/Compare
#define REG_TM3 (*(volatile uint16_t*)0x003C) // Timer 3 Counter
#define REG_TMR3 (*(volatile uint16_t*)0x003E) // Timer 3 Reload/Compare
#define REG_TCON0 (*(volatile uint8_t*)0x0040) // Timer 0 Control
#define REG_TCON1 (*(volatile uint8_t*)0x0041) // Timer 1 Control
#define REG_TCON2 (*(volatile uint8_t*)0x0042) // Timer 2 Control (Ignition)
#define REG_TCON3 (*(volatile uint8_t*)0x0043) // Timer 3 Control
#define REG_TRNSIT (*(volatile uint8_t*)0x0046) // Timer Transit register
/* ---- Serial Communication ---- */
#define REG_STTM (*(volatile uint8_t*)0x0048) // Serial TX Timer
#define REG_STTMR (*(volatile uint8_t*)0x0049) // Serial TX Timer Reload
#define REG_STTMC (*(volatile uint8_t*)0x004A) // Serial TX Control
#define REG_SRTM (*(volatile uint8_t*)0x004C) // Serial RX Timer
#define REG_SRTMR (*(volatile uint8_t*)0x004D) // Serial RX Timer Reload
#define REG_SRTMC (*(volatile uint8_t*)0x004E) // Serial RX Timer Control
#define REG_STCON (*(volatile uint8_t*)0x0050) // Serial TX Control
#define REG_STBUF (*(volatile uint8_t*)0x0051) // Serial TX Buffer
#define REG_SRCON (*(volatile uint8_t*)0x0054) // Serial RX Control
#define REG_SRBUF (*(volatile uint8_t*)0x0055) // Serial RX Buffer
#define REG_SRSTAT (*(volatile uint8_t*)0x0056) // Serial Status
/* ---- ADC Registers ---- */
#define REG_ADSCAN (*(volatile uint8_t*)0x0058) // ADC Scan Control
#define REG_ADSEL (*(volatile uint8_t*)0x0059) // ADC Channel Select
#define REG_ADCR0 (*(volatile uint16_t*)0x0060) // ADC Ch0 (MUX'd: ECT/IAT)
#define REG_ADCR0H (*(volatile uint8_t*)0x0061) // ADC Ch0 High byte
#define REG_ADCR1 (*(volatile uint16_t*)0x0062) // ADC Ch1 (Window demister)
#define REG_ADCR2 (*(volatile uint16_t*)0x0064) // ADC Ch2 (O2 Secondary)
#define REG_ADCR2H (*(volatile uint8_t*)0x0065) // ADC Ch2 High byte
#define REG_ADCR3 (*(volatile uint16_t*)0x0066) // ADC Ch3 (O2 Primary)
#define REG_ADCR4 (*(volatile uint16_t*)0x0068) // ADC Ch4 (TPS)
#define REG_ADCR5 (*(volatile uint16_t*)0x006A) // ADC Ch5 (MAP Sensor)
#define REG_ADCR6 (*(volatile uint16_t*)0x006C) // ADC Ch6 (Battery/ECT)
#define REG_ADCR6H (*(volatile uint8_t*)0x006D) // ADC Ch6 High byte
#define REG_ADCR7 (*(volatile uint16_t*)0x006E) // ADC Ch7 (IAT)
/* ---- PWM Registers ---- */
#define REG_PWMC0 (*(volatile uint16_t*)0x0070) // PWM 0 Counter (IACV)
#define REG_PWMR0 (*(volatile uint16_t*)0x0072) // PWM 0 Reload
#define REG_PWMC1 (*(volatile uint16_t*)0x0074) // PWM 1 Counter
#define REG_PWMR1 (*(volatile uint16_t*)0x0076) // PWM 1 Reload
#define REG_PWCON0 (*(volatile uint8_t*)0x0078) // PWM 0 Control
#define REG_PWCON1 (*(volatile uint8_t*)0x007A) // PWM 1 Control
/*============================================================================
* SECTION 2: RAM VARIABLE DEFINITIONS
*
* Memory map inferred from code analysis:
* 0x98-0xBF: Sensor readings (raw and processed)
* 0xC0-0xDF: Timing/counter values
* 0xE0-0xFF: State flags and cycle counters
* 0x100-0x1FF: Extended flags and calculations
* 0x200-0x3FF: Final values, buffers, IACV
*============================================================================*/
/* ---- Sensor Readings (0x98-0xBF) ---- */
uint8_t g_coolantTempRaw; // 0x98 - ECT sensor raw value
uint8_t g_intakeAirTempRaw; // 0x99 - IAT sensor raw value
uint8_t g_batteryVoltageRaw; // 0x9A - Battery voltage (12V scaled)
uint8_t g_ecuVoltageRaw; // 0x9B - ECU internal 5V reference
uint8_t g_groundReference; // 0x9C - Ground reference check
uint8_t g_timingAdjustInput; // 0x9D - Timing adjust connector (B20)
uint8_t g_brakeSwitch; // 0x9E - Brake switch input (B9)
uint8_t g_auxInput; // 0x9F - Auxiliary input (B18)
uint8_t g_sensorFlags; // 0xA0 - Sensor status flags
uint8_t g_o2PrimaryRaw; // 0xA1 - O2 primary sensor value (0-50 decimal)
uint8_t g_o2SecondaryRaw; // 0xA2 - O2 secondary sensor value
uint8_t g_tempCalculated; // 0xA3 - Temperature intermediate calculation
uint8_t g_iatProcessed; // 0xA4 - IAT processed value
uint8_t g_alternatorFeedback; // 0xA5 - Alternator feedback signal
uint8_t g_rpmByteNonVtec; // 0xA6 - RPM byte (non-VTEC scale)
uint8_t g_rpmByteVtec; // 0xA7 - RPM byte (VTEC scale)
uint8_t g_ambientPressure; // 0xA8 - Ambient pressure (internal sensor)
uint8_t g_baroSensorRaw; // 0xA9 - Barometric pressure sensor
uint8_t g_tpsSensorRaw; // 0xAA - TPS raw value (0-255)
uint8_t g_tpsSensorFiltered; // 0xAB - TPS filtered/averaged
uint8_t g_tpsDelta; // 0xAC - TPS delta (acceleration rate)
uint8_t g_tpsDeltaOld; // 0xAD - Previous TPS delta
uint8_t g_tpsSmoothed; // 0xAE - TPS smoothed value
uint8_t g_tpsRelated; // 0xAF - TPS related calculation
uint16_t g_mapSensorRaw; // 0xB0 - MAP sensor value (from ADCR5)
uint16_t g_mapSensorOld; // 0xB2 - Previous MAP value (for delta calc)
uint8_t g_mapImageBase; // 0xB4 - MAP image (0-DF, before delta)
uint8_t g_mapImageFinal; // 0xB5 - MAP image after delta adjustment
uint16_t g_mapInitialHigh; // 0xB6 - Initial MAP high byte (for Code 5)
uint8_t g_mapDeltaCalc; // 0xB7 - MAP delta calculation result
uint16_t g_rpmTimerDelta; // 0xB8 - Delta timer ticks (for RPM change)
uint16_t g_rpmTimerCurrent; // 0xBA - Current revs timer count (45° period)
uint8_t g_rpmChangeRate; // 0xBC - RPM acceleration/deceleration rate
uint8_t g_rpmChangeDir; // 0xBD - RPM change direction indicator
uint16_t g_rpmTimerAverage; // 0xBE - Average of last 4 rev counts
/* ---- Timing and Counter Values (0xC0-0xDF) ---- */
uint16_t g_rpmAsymptotic; // 0xC0 - Asymptotic RPM follower
uint16_t g_rpmTargetDiff; // 0xC2 - |current RPM - target idle|
uint16_t g_vehicleSpeedWord; // 0xC4 - Vehicle speed (processed)
uint16_t g_timer1OldCapture; // 0xC6 - Old Timer 1 capture value
uint16_t g_timer1CurrentCapture; // 0xC8 - Current Timer 1 capture (INT0)
uint16_t g_oldE2; // 0xCA - Old 0xE2 value
uint8_t g_vehicleSpeedByte; // 0xCB - Vehicle speed sensor byte
uint16_t g_interruptEnableNormal; // 0xCC - IE value normally
uint16_t g_interruptEnableISR; // 0xCE - IE value in interrupt
uint16_t g_injectorTiming0; // 0xD0 - Injector timing slot 0
uint16_t g_injectorTiming1; // 0xD2 - Injector timing slot 1
uint16_t g_injectorTiming2; // 0xD4 - Injector timing slot 2
uint16_t g_injectorPulseWidth; // 0xD6 - Final fuel pulse width
uint16_t g_ignitionDwellStart; // 0xD8 - Ignition dwell start time
uint16_t g_ignitionFireTime; // 0xDA - Ignition fire time
uint16_t g_ignitionCalc1; // 0xDC - Ignition calculation temp
uint8_t g_ignitionCalc2; // 0xDE - Ignition calculation temp
uint8_t g_iacvDutyCycle; // 0xDF - IACV PWM duty cycle
/* ---- State Flags and Cycle Counters (0xE0-0xFF) ---- */
uint16_t g_timer1OldValue; // 0xE0 - Old Timer 1 for RPM calc
uint8_t g_timer1OverflowFlag; // 0xE2 - Timer 1 overflow indicator (VSS)
uint8_t g_tdcCounter; // 0xE3 - TDC position counter
uint8_t g_crankPosition; // 0xE4 - Crank position (0-3, 45° each)
uint8_t g_cylinderFiring; // 0xE5 - Cylinder firing order index
uint8_t g_firingOrderPhase; // 0xE6 - Firing order phase
uint8_t g_enginePosition; // 0xE7 - Engine position tracking
uint8_t g_celCodeCounter; // 0xE8 - CEL code timing counter
uint8_t g_diagnosticState; // 0xE9 - Diagnostic state machine
uint8_t g_syncState; // 0xEA - Crank sync state
uint8_t g_lifeCounter; // 0xEB - Reboot life counter (starts 0x20)
uint8_t g_mainLoopCounter; // 0xEC - Main loop iteration counter
uint8_t g_miscCounter; // 0xED - Miscellaneous counter
uint8_t g_timerCounter; // 0xEE - General timer counter
uint8_t g_rebootReason; // 0xF0 - Error code after reboot
uint8_t g_eldStatus; // 0xF1 - ELD (Electrical Load Detector)
uint8_t g_eldValue; // 0xF2 - ELD reading (twice per cycle)
uint8_t g_eldRelated; // 0xF3 - ELD related calculation
uint8_t g_savedInterruptLow; // 0xF4 - Saved IE low byte
uint8_t g_savedInterruptHigh; // 0xF5 - Saved IE high byte
uint8_t g_savedFlags; // 0xF6 - Saved flags
uint8_t g_timerScratch; // 0xF7 - Timer scratch register
uint8_t g_oilPressureSwitch; // 0xF8 - Oil pressure (>0x32 = OK)
uint8_t g_starterSignal; // 0xF9 - Starter signal input
uint8_t g_eldCalc; // 0xFA - ELD calculation temp
uint8_t g_eldTrim; // 0xFB - ELD fuel trim
uint8_t g_celBlinkPattern; // 0xFC - CEL blink pattern (high/low nibble)
uint8_t g_celBlinkState; // 0xFD - CEL blink state machine
uint8_t g_processingFlags; // 0xFE - Processing state flags
uint8_t g_externalInputs; // 0xFF - External input chip reading
/* ---- Extended Flags (0x100-0x13F) ---- */
uint8_t g_inputPortMirror; // 0x110 - External input mirror
uint8_t g_sensorFlags1; // 0x111 - Sensor validation flags
uint8_t g_errorFlags1; // 0x112 - Error condition flags 1
uint8_t g_errorFlags2; // 0x113 - Error condition flags 2
uint8_t g_errorFlags3; // 0x114 - Error condition flags 3
uint8_t g_errorFlags4; // 0x115 - Error condition flags 4
uint8_t g_vtecFlags1; // 0x116 - VTEC control flags 1
uint8_t g_vtecFlags2; // 0x117 - VTEC control flags 2
uint8_t g_engineStateFlags; // 0x118 - Engine state (CKP, VSS, starter)
uint8_t g_mapStateFlags; // 0x119 - MAP state flags
uint8_t g_tempStateFlags; // 0x11A - Temperature state flags
uint8_t g_o2SensorFlags; // 0x11B - O2 sensor state flags
uint8_t g_o2LoopFlags; // 0x11C - O2 closed loop flags
uint8_t g_fuelCutFlags; // 0x11D - Fuel cut conditions
uint8_t g_rpmStateFlags; // 0x11E - RPM state flags
uint8_t g_engineRunFlags; // 0x11F - Engine running flags
uint8_t g_ignitionFlags; // 0x120 - Ignition state flags
uint8_t g_tdcStateFlags; // 0x121 - TDC validation flags
uint8_t g_enginePhaseFlags; // 0x122 - Engine phase flags
uint8_t g_tpsChangeFlags; // 0x123 - TPS rate of change flags
uint8_t g_acFlags; // 0x124 - AC clutch control flags
uint8_t g_idleFlags; // 0x125 - Idle control flags
uint8_t g_miscFlags1; // 0x126 - Miscellaneous flags
uint8_t g_miscFlags2; // 0x127 - Miscellaneous flags
uint8_t g_miscFlags3; // 0x128 - Miscellaneous flags
uint8_t g_vtecStateFlags; // 0x129 - VTEC engagement state
uint8_t g_vtecQualifyFlags; // 0x12A - VTEC qualification counter
uint8_t g_vtecHoldCounter; // 0x12B - VTEC hold counter
uint8_t g_celSensorFlags; // 0x12C - CEL sensor error bits
uint8_t g_celSystemFlags; // 0x12D - CEL system error bits
uint8_t g_celCriticalFlags; // 0x12E - CEL critical error bits
uint8_t g_celMiscFlags; // 0x12F - CEL misc error bits
uint8_t g_faultCode1; // 0x130 - Fault codes 1-8
uint8_t g_faultCode2; // 0x131 - Fault codes 9-16
uint8_t g_faultCode3; // 0x132 - Fault codes 17-24
uint8_t g_faultCodeActive; // 0x133 - Currently active fault
uint8_t g_ignitionFinal; // 0x134 - Final ignition advance value
uint8_t g_ignitionRpmEctTrim; // 0x135 - RPM/ECT ignition trim
uint8_t g_ignitionComplement; // 0x136 - 2's complement of ignition
uint8_t g_ignitionCorrection1; // 0x137 - Ignition correction 1
uint8_t g_ignitionMapRaw; // 0x138 - Raw ignition map interpolation
uint8_t g_ignitionBrakeTrim; // 0x139 - Brake switch timing trim
uint8_t g_ignitionEctTrim; // 0x13A - ECT ignition trim
uint8_t g_ignitionIdleTrim; // 0x13B - Idle adjust timing trim
uint8_t g_ignitionCorrection2; // 0x13C - Ignition correction 2
uint8_t g_ignitionKnockTrim; // 0x13D - Knock retard correction
uint8_t g_ignitionCorrection3; // 0x13E - Ignition correction 3
uint8_t g_ignitionEctErrorTrim; // 0x13F - ECT error fallback trim
/* ---- Fuel Calculations (0x140-0x17F) ---- */
uint16_t g_fuelMapNonVtec; // 0x140 - Fuel map value (non-VTEC)
uint16_t g_fuelMapVtec; // 0x142 - Fuel map value (VTEC)
uint16_t g_fuelMainCorrected; // 0x144 - Main fuel with corrections
uint16_t g_fuelAllCorrections; // 0x146 - All fuel corrections combined
uint16_t g_fuelFinalNoO2; // 0x148 - Final fuel without O2
uint16_t g_fuelTpsDelta; // 0x14A - TPS acceleration enrichment
uint16_t g_fuelBatteryTrim; // 0x14C - Battery voltage trim
uint16_t g_fuelAcTrim; // 0x14E - AC compressor trim
uint16_t g_fuelTpsRelated; // 0x150 - TPS related fuel
uint16_t g_fuelTimingTrim; // 0x152 - Timing connector trim
uint16_t g_fuelScratch1; // 0x154 - Scratch register
uint16_t g_fuelScratch2; // 0x156 - Scratch register
uint16_t g_fuelVoltageTrim; // 0x158 - Voltage-based trim
uint16_t g_fuelIatTrim; // 0x15A - IAT fuel trim
uint16_t g_fuelScratch3; // 0x15C - Scratch register
uint16_t g_fuelWarmupMult; // 0x15E - Warmup enrichment multiplier
uint16_t g_fuelScratch4; // 0x160 - Scratch register
uint16_t g_fuelO2TrimPrimary; // 0x162 - Primary O2 fuel trim
uint16_t g_fuelO2TrimSecondary; // 0x164 - Secondary O2 fuel trim
uint16_t g_fuelTempTrim; // 0x166 - Temperature fuel trim
uint16_t g_fuelScratch5; // 0x168 - Scratch register
uint8_t g_fuelMapDependentTrim; // 0x169 - MAP-based fuel trim
uint16_t g_fuelEctTrim; // 0x16A - ECT fuel trim
uint16_t g_fuelEctTrim2; // 0x16C - ECT fuel trim 2
uint8_t g_fuelMiscFlag; // 0x16E - Fuel misc flag
uint8_t g_openClosedLoopFlag; // 0x16F - Open/closed loop selector
uint16_t g_targetIdleRpm; // 0x172 - Target idle RPM (timer format)
uint8_t g_ectIdleTrim; // 0x176 - ECT-based idle trim
uint8_t g_ectIdleAdjust; // 0x177 - ECT idle adjustment
uint8_t g_vtecRpmThreshold; // 0x178 - VTEC RPM threshold calc
/* ---- VTEC and O2 State (0x190-0x1FF) ---- */
uint8_t g_ectVcalResult; // 0x197 - ECT VCAL lookup result
uint8_t g_celBlinkCounter; // 0x1AA - CEL blink timing counter
uint8_t g_vtecHysteresis; // 0x1D5 - VTEC engage hysteresis
uint8_t g_celCurrentCode; // 0x1DF - Current CEL code being blinked
/* ---- IACV and Buffers (0x200-0x2FF) ---- */
uint16_t g_iacvDutyCalc; // 0x202 - IACV duty calculation
uint16_t g_iacvDutyCopy; // 0x204 - IACV duty copy
uint16_t g_rpmHistory0; // 0x206 - RPM history slot 0
uint16_t g_rpmHistory1; // 0x208 - RPM history slot 1
uint16_t g_rpmHistory2; // 0x20A - RPM history slot 2
uint16_t g_rpmHistory3; // 0x20C - RPM history slot 3
uint16_t g_rpmOldHistory0; // 0x20E - Old RPM history 0
uint16_t g_rpmOldHistory1; // 0x210 - Old RPM history 1
uint16_t g_rpmOldHistory2; // 0x212 - Old RPM history 2
uint16_t g_injectorTimingSlot0; // 0x214 - Injector timing buffer
uint16_t g_injectorTimingSlot1; // 0x216 - Injector timing buffer
uint16_t g_injectorTimingSlot2; // 0x218 - Injector timing buffer
uint8_t g_injectorMask; // 0x21A - Injector selection mask
uint8_t g_injectorMaskInverse; // 0x21B - Inverse injector mask
uint8_t g_injectorP2Mask; // 0x21C - P2 port injector mask
uint8_t g_iacvRelated; // 0x21D - IACV related
uint8_t g_stateFlags210; // 0x210 - State flags bank
uint8_t g_stateFlags211; // 0x211 - State flags bank
uint8_t g_stateFlags212; // 0x212 - State flags bank
uint8_t g_stateFlags213; // 0x213 - State flags bank
uint8_t g_stateFlags214; // 0x214 - State flags bank
uint8_t g_stateFlags215; // 0x215 - State flags bank
uint8_t g_stateFlags216; // 0x216 - State flags bank
uint8_t g_stateFlags217; // 0x217 - State flags bank
uint8_t g_stateFlags218; // 0x218 - State flags bank
uint8_t g_stateFlags219; // 0x219 - State flags bank
uint8_t g_stateFlags21A; // 0x21A - State flags bank
uint8_t g_stateFlags21B; // 0x21B - State flags bank
uint8_t g_stateFlags21C; // 0x21C - State flags bank
uint8_t g_stateFlags21D; // 0x21D - State flags bank
uint8_t g_stateFlags21E; // 0x21E - State flags bank
uint8_t g_stateFlags21F; // 0x21F - State flags bank
uint8_t g_stateFlags220; // 0x220 - State flags bank
uint8_t g_stateFlags221; // 0x221 - State flags bank
uint8_t g_stateFlags222; // 0x222 - State flags bank
uint8_t g_stateFlags223; // 0x223 - State flags bank
uint8_t g_stateFlags224; // 0x224 - State flags bank
uint8_t g_stateFlags225; // 0x225 - State flags bank
uint8_t g_stateFlags226; // 0x226 - State flags bank
uint8_t g_stateFlags227; // 0x227 - State flags bank
uint8_t g_stateFlags228; // 0x228 - State flags bank
uint8_t g_stateFlags229; // 0x229 - State flags bank
uint8_t g_stateFlags22A; // 0x22A - State flags bank
uint8_t g_stateFlags22B; // 0x22B - State flags bank
uint8_t g_stateFlags22C; // 0x22C - State flags bank
uint8_t g_stateFlags22D; // 0x22D - State flags bank
uint8_t g_stateFlags22E; // 0x22E - State flags bank
uint8_t g_stateFlags22F; // 0x22F - State flags bank
uint8_t g_stateFlags230; // 0x230 - State flags bank
uint8_t g_stateFlags231; // 0x231 - State flags bank
uint8_t g_tpsOldValue; // 0x278 - Previous TPS value
uint8_t g_tempOldValue; // 0x279 - Previous temp value
uint16_t g_o2OldPrimaryTrim; // 0x274 - Old primary O2 correction
uint16_t g_o2OldSecondaryTrim; // 0x276 - Old secondary O2 correction
uint8_t g_celBlinkRam1; // 0x27B - CEL blink buffer (codes 1-8)
uint8_t g_celBlinkRam2; // 0x27C - CEL blink buffer (codes 9-16)
uint8_t g_celBlinkRam3; // 0x27D - CEL blink buffer (codes 17-24)
/* ---- Serial Communication Buffer (0x350-0x3FF) ---- */
uint8_t g_serialFlags; // 0x354 - Serial communication flags
uint8_t g_serialBuffer[16]; // 0x358 - Serial data buffer
/*============================================================================
* SECTION 3: CONSTANTS AND TABLE ADDRESSES
*============================================================================*/
/* ---- Fuel Map Tables ---- */
#define TBL_FUEL_NONVTEC_ADDR 0x6800 // Non-VTEC fuel map (10x20)
#define TBL_FUEL_VTEC_ADDR 0x6900 // VTEC fuel map (10x20)
#define TBL_FUEL_CRANKING_ADDR 0x6A00 // Cranking fuel enrichment
/* ---- Ignition Map Tables ---- */
#define TBL_IGN_NONVTEC_ADDR 0x6A80 // Non-VTEC ignition map
#define TBL_IGN_VTEC_ADDR 0x6B00 // VTEC ignition map
#define TBL_IGN_CRANKING_ADDR 0x6B80 // Cranking ignition timing
/* ---- Correction Tables ---- */
#define TBL_ECT_FUEL_TRIM 0x6034 // ECT fuel enrichment curve
#define TBL_IAT_FUEL_TRIM 0x6042 // IAT fuel enrichment curve
#define TBL_BARO_FUEL_TRIM 0x6050 // Barometric fuel trim
#define TBL_O2_CLOSED_LOOP 0x605E // O2 closed loop parameters
#define TBL_WARMUP_ENRICHMENT 0x606C // Warmup enrichment curve
#define TBL_ACCEL_ENRICHMENT 0x607A // Acceleration enrichment
#define TBL_DECEL_ENLEAN 0x608F // Deceleration enleanment
#define TBL_VOLTAGE_TRIM 0x60A7 // Voltage compensation
#define TBL_RPM_AXIS_NONVTEC 0x60C8 // RPM axis (non-VTEC)
#define TBL_RPM_AXIS_VTEC 0x60CC // RPM axis (VTEC)
#define TBL_MAP_AXIS 0x60D0 // MAP axis breakpoints
#define TBL_IDLE_TARGET 0x6122 // Idle RPM target by ECT
#define TBL_IDLE_IACV_BASE 0x6132 // IACV base duty by ECT
#define TBL_VTEC_ENGAGE_RPM 0x6146 // VTEC engage RPM threshold
#define TBL_VTEC_DISENGAGE_RPM 0x6152 // VTEC disengage RPM threshold
#define TBL_VTEC_MIN_SPEED 0x615E // VTEC minimum vehicle speed
#define TBL_REV_LIMITER 0x616A // Rev limiter parameters
#define TBL_LAUNCH_CONTROL 0x6176 // Launch control parameters
#define TBL_KNOCK_RETARD 0x6182 // Knock retard curve
#define TBL_INJECTOR_DEAD_TIME 0x6190 // Injector dead time by voltage
#define TBL_DWELL_TIME 0x619E // Ignition dwell time
#define TBL_TIMING_CONNECTOR_TRIM 0x61AC // Timing connector adjustment
#define TBL_CEL_CODE_MAP 0x6CD2 // CEL code to blink pattern
#define TBL_CEL_TIMING 0x6CEA // CEL blink timing
/* ---- Serial/Diagnostic Tables ---- */
#define TBL_SERIAL_ADDRESSES 0x6B56 // Serial read addresses
#define TBL_DIAGNOSTIC_PARAMS 0x6D08 // Diagnostic parameters
/* ---- Configuration Constants ---- */
#define TBL_CONFIG_FLAGS 0x6000 // Configuration byte flags
/* ---- RPM Constants ---- */
#define RPM_COEF_NUMERATOR 1851562 // 7900000/32/8*60
#define TIMER_TICKS_PER_45DEG(rpm) (RPM_COEF_NUMERATOR / (rpm))
/* ---- Port Bit Definitions ---- */
// Port 0
#define P0_PURGE_SOLENOID (1 << 3) // P0.3 - Purge control
#define P0_CEL_DASH (1 << 6) // P0.6 - CEL dashboard light
#define P0_AC_CLUTCH (1 << 7) // P0.7 - AC clutch output
// Port 1
#define P1_ERROR_CODE3 (1 << 0) // P1.0 - Error code 3 indicator
#define P1_VTEC_SOLENOID (1 << 1) // P1.1 - VTEC solenoid output
#define P1_CEL_LED (1 << 2) // P1.2 - CEL LED output
// Port 2
#define P2_INJECTOR_1 (1 << 0) // P2.0 - Injector 1
#define P2_INJECTOR_2 (1 << 1) // P2.1 - Injector 2
#define P2_INJECTOR_3 (1 << 2) // P2.2 - Injector 3
#define P2_INJECTOR_4 (1 << 3) // P2.3 - Injector 4
#define P2_LIMP_MODE (1 << 4) // P2.4 - Limp mode indicator
// Port 4
#define P4_IACV_OUTPUT (1 << 3) // P4.3 - IACV PWM output
// External Inputs (0xFF)
#define EXT_KNOCK_LOCKUP (1 << 0) // FF.0 - Knock/Auto lockup
#define EXT_VTEC_FEEDBACK (1 << 2) // FF.2 - VTEC solenoid feedback
#define EXT_AC_SWITCH (1 << 6) // FF.6 - AC switch input
#define EXT_STARTER_SIGNAL (1 << 7) // FF.7 - Starter signal
/*============================================================================
* SECTION 4: INTERRUPT VECTOR TABLE (0x0000-0x0037)
*
* OKI M66207 interrupt vectors are 16-bit addresses stored sequentially.
*============================================================================*/
// Vector Table at 0x0000
const uint16_t VECTOR_TABLE[] = {
// addr handler description
0x21E2, // 0x0000: isr_systemStart - System startup
0x21E9, // 0x0002: isr_break - Software break
0x21D1, // 0x0004: isr_watchdog - Watchdog timer
0x003C, // 0x0006: isr_nmi - Non-maskable interrupt
0x01D3, // 0x0008: isr_crankPosition - INT0: Crank position signal
0x01FD, // 0x000A: isr_serialRx - Serial receive
0x21CB, // 0x000C: isr_serialTx - Serial transmit
0x03DC, // 0x000E: isr_serialRxBrg - Serial RX baud rate generator
0x21CB, // 0x0010: isr_timer0Overflow - Timer 0 overflow (unused)
0x0086, // 0x0012: isr_timer0Match - Timer 0 match: Injector pulse
0x21CB, // 0x0014: isr_timer1Overflow - Timer 1 overflow (unused)
0x0114, // 0x0016: isr_timer1Match - Timer 1 match: ADC/TDC
0x02DD, // 0x0018: isr_timer2Overflow - Timer 2 overflow
0x014D, // 0x001A: isr_timer2Match - Timer 2 match: Ignition
0x21CB, // 0x001C: isr_timer3Overflow - Timer 3 overflow (unused)
0x02FB, // 0x001E: isr_timer3Match - Timer 3 match
0x21CB, // 0x0020: isr_adcComplete - ADC conversion complete (unused)
0x031E, // 0x0022: isr_pwmTimer - PWM timer: IACV control
0x21CB, // 0x0024: isr_serialTxBrg - Serial TX baud rate (unused)
0x037B, // 0x0026: isr_externalInt1 - INT1: Main engine processing
// VCAL Vector Table (0x0028-0x0036)
0x4E62, // 0x0028: vcal_tableLookup1D - 1D table interpolation
0x4EC0, // 0x002A: vcal_tableLookup2D - 2D table interpolation
0x4E9C, // 0x002C: vcal_clampTableLookup - Clamped table lookup
0x4EAE, // 0x002E: vcal_rangeLimit - Value range limiter
0x25A1, // 0x0030: vcal_mainProcess - Main processing entry
0x4F7F, // 0x0032: vcal_multiply16 - 16-bit multiply helper
0x4F84, // 0x0034: vcal_divide16 - 16-bit divide helper
0x4FCE, // 0x0036: vcal_absValue - Absolute value helper
};
/*============================================================================
* SECTION 5: INTERRUPT SERVICE ROUTINES
*============================================================================*/
/**
* isr_nmi - Non-Maskable Interrupt Handler
* Address: 0x003C
*
* Handles power failure, backup RAM save, and system recovery.
* Called on power glitch or NMI pin assertion.
*/
void isr_nmi(void) {
// Clear processor status for clean state
REG_PSW = 0;
REG_LRB = 0x41; // Select register bank 0x41
// Check if we were in middle of error flag update
if (g_stateFlags230 & 0x80) {
// Save current DP to backup location
*(uint16_t*)0x0084 = REG_DP;
}
// Wait for power stabilization with timeout
REG_DP = 9; // Timeout counter
while (REG_DP > 0) {
// Check P4.1 for power-good signal
if (REG_P4 & 0x02)
goto nmi_powerGood;
REG_DP--;
}
// Power failed - jump to emergency shutdown
goto emergencyShutdown; // label_576b
nmi_powerGood:
// Power restored - resume normal operation
goto nmi_resume; // label_5a82
emergencyShutdown:
// Configure ADC for standby
REG_ADSEL = (uint8_t)REG_ACC;
REG_IE = 0x0040;
REG_TCON1 = 0xE0;
REG_IRQ = 0;
// Enable Timer 1 for wakeup
REG_P4SF |= 0x02;
REG_TM1 = 0xFFFF;
REG_TCON1 |= 0x10;
// Enter standby mode
REG_SBYCON |= 0x04;
REG_STPACP = 0x05;
REG_STPACP = 0x0A; // Double-write sequence
REG_SBYCON |= 0x01;
// Clear flag on wake
g_sensorFlags &= ~0x02;
nmi_resume:
// Jump to main recovery
return; // Actually jumps to label_5a82
}
/**
* isr_timer0Match - Injector Pulse Width Timer
* Address: 0x0086
*
* Controls injector on/off timing. Timer 0 generates interrupts
* when injector pulse starts and ends.
*
* Register bank 0x37 (r0-r7 at 0x1B8-0x1BF)
* r6 = injector pattern byte
* r7 = injector state accumulator
*/
void isr_timer0Match(void) {
REG_LRB = 0x37; // Bank at 0x1B8
// Clear timer 0 match flag
REG_TCON0 &= 0xFB;
// Check if all injectors done (r7 == 0x0F means all off)
uint8_t injState = *(uint8_t*)0x1BF;
if (injState == 0x0F)
return; // All injectors idle, nothing to do
// Get injector timing values
uint16_t slot0 = g_injectorTiming0; // er0
uint16_t slot1 = g_injectorTiming1; // er1
uint16_t slot2 = g_injectorTiming2; // er2
// Determine which slot is next based on timing values
if (slot0 != 0) {
// Slot 0 has pending pulse
REG_TMR0 += slot0;
// Update injector pattern
uint8_t pattern = *(uint8_t*)0x1BE;
pattern = (pattern << 1) | (REG_ACC >> 7); // Rotate with carry
*(uint8_t*)0x1BE = pattern;
// Update state
uint8_t newState = (pattern & 0x0F);
injState |= newState;
g_injectorP2Mask |= newState;
// Shift timing slots
g_injectorTiming0 = slot2;
g_injectorTiming1 = 1;
g_injectorTiming2 = 1;
} else if (slot1 != 0) {
// Slot 1 active
REG_TMR0 += slot1;
uint8_t pattern = *(uint8_t*)0x1BE;
pattern = (pattern >> 3) | (pattern & 0x0F);
// Update P2 for injector output
REG_P2 |= (pattern & 0x0F);
return;
} else if (slot2 != 0) {
// Slot 2 active - final pulse end
REG_TMR0 += slot2;
uint8_t pattern = *(uint8_t*)0x1BE;
pattern = (pattern >> 1) | ((REG_ACC & 0x01) << 7);
*(uint8_t*)0x1BE = pattern;
// Invert for off-pulse
uint8_t offPattern = (~pattern) & 0x0F;
injState |= offPattern;
g_injectorP2Mask |= offPattern;
// Update P2 and reset all slots
REG_P2 |= (pattern & 0x0F);
g_injectorTiming0 = 1;
g_injectorTiming1 = 1;
g_injectorTiming2 = 1;
return;
} else {
// All slots empty - set idle state
injState = 0x0F;
*(uint8_t*)0x1BF = 0x0F;
g_injectorP2Mask = 0x0F;
REG_P2 |= 0x0F; // All injectors off
return;
}
// Apply final pattern to P2
REG_P2 |= (injState & 0x0F);
}
/**
* isr_timer1Match - ADC/TDC Processing Timer
* Address: 0x0114
*
* Handles ADC sampling timing and TDC signal validation.
* Register bank 0x19 (r0-r7 at 0xC8-0xCF)
*/
void isr_timer1Match(void) {
REG_LRB = 0x19; // Bank at 0xC8
// Check TCON1.3 for TDC signal mode
if (!(REG_TCON1 & 0x08)) {
// Regular ADC sampling mode
g_sensorFlags &= ~0x20; // Clear flag 0x9E.5
if (g_sensorFlags & 0x20) {
// Already flagged - check for timeout
if (g_timer1CurrentCapture >= 0x064A) {
// Set extended flag
g_sensorFlags |= 0x20;
// Adjust timing by 0x3B6 (950 ticks)
g_timer1CurrentCapture -= 0x03B6;
REG_TMR1 += 0x03B6;
return;
}
}
// Normal sample - clear TDC mode flag
REG_TCON1 &= 0xF7;
// Capture TPS from ADC
g_timer1CurrentCapture = REG_ADCR4; // TPS to er2
// Schedule next sample based on saved timing
REG_TMR1 += g_timer1OldCapture; // Add 0xCA value
return;
}
// TDC signal processing mode
REG_TCON1 |= 0x08; // Set TCON1.3
// Increment counter
(*(uint8_t*)0xCE)++;
// Calculate delta from 0x0A00 base
uint16_t delta = 0x0A00 - g_timer1CurrentCapture;
g_timer1CurrentCapture = delta;
// Schedule next based on saved timing
REG_TMR1 += *(uint16_t*)0xC8;
}
/**
* isr_timer2Match - Ignition Output Timer
* Address: 0x014D
*
* Controls ignition coil dwell and spark timing.
* Timer 2 schedules dwell charge start and spark fire events.
*
* Register bank 0x1A (r0-r7 at 0xD0-0xD7)
*/
void isr_timer2Match(void) {
REG_LRB = 0x1A; // Bank at 0xD0
uint8_t phase = *(uint8_t*)0xD2; // Current phase counter
if (phase < 3) {
// Early phase - increment and check
phase++;
// On even phases, capture O2 sensor
if ((phase & 0x01) == 0)
g_o2SecondaryRaw = REG_ADCR6;
// Check if we match target
if (phase == *(uint8_t*)0xD0)
goto scheduleNextCycle;
if (phase > *(uint8_t*)0xD0)
goto clearCoilCharge;
// Schedule next check
uint16_t nextTime = REG_TM3 - 1;
REG_TMR3 = nextTime;
goto finishInterrupt;
}
if (phase == 3) {
// Phase 3 - increment and check limit
uint8_t target = *(uint8_t*)0xD0 + 1;
if (target >= 5)
goto finalPhase;
// Clear coil charge flag
REG_TCON3 &= 0xFB;
// Calculate minimum dwell
uint16_t dwell = *(uint16_t*)0xD4; // er2
if (dwell < 0x001F)
dwell = 0x001F; // Minimum 31 ticks
// Schedule dwell start
REG_TMR3 = REG_TMR2 + dwell;
goto finishIgnitionSchedule;
}
if ((phase & 0x01) == 0) {
// Even phase > 3
if (REG_TCON3 & 0x08)
goto scheduleNextCheck;
phase = 0;
REG_TCON3 |= 0x04; // Start dwell charge
goto checkPhase;
}
// Odd phase > 3
if (REG_TCON3 & 0x04)
goto scheduleNextCheck;
// Calculate spark timing
uint16_t sparkTime = REG_TM3 - REG_TMR2 + 6;
if (sparkTime < *(uint16_t*)0xD4) {
// Time until spark is less than remaining dwell
REG_TMR3 = REG_TMR2 + *(uint16_t*)0xD4;
} else {
REG_TMR3 = REG_TM3 + 4;
}
finishIgnitionSchedule:
REG_TCON3 |= 0x08; // Enable coil fire
finishInterrupt:
REG_IRQH &= 0xF7; // Clear interrupt flag
// Check transit register for sync
if (REG_TRNSIT & 0x01)
g_sensorFlags |= 0x04;
return;
clearCoilCharge:
REG_TCON3 &= 0xFB;
goto scheduleNextCheck;
finalPhase:
// Final phase - schedule next cycle
REG_TMR3 = REG_TMR2 + *(uint16_t*)0xD4;
*(uint16_t*)0xD6 = REG_TMR3; // er3
scheduleNextCycle:
REG_TMR3 = REG_TMR2 + g_timer1OldValue;
REG_TCON3 &= 0xF7;
goto finishInterrupt;
scheduleNextCheck:
uint16_t nextCheck = REG_TM3 - 1;
REG_TMR3 = nextCheck;
goto finishInterrupt;
checkPhase:
if (phase == *(uint8_t*)0xD0)
goto scheduleNextCycle;
if (phase < *(uint8_t*)0xD0)
goto scheduleNextCheck;
goto clearCoilCharge;
}
/**
* isr_crankPosition - INT0 Crank Position Signal
* Address: 0x01D3
*
* Triggered by distributor CKP (Crank Position) signal.
* Captures timer value for RPM calculation.
*
* Register bank 0x1B (r0-r7 at 0xD8-0xDF)
*/
void isr_crankPosition(void) {
// Save and restore IE around processing
uint16_t savedIE = g_savedInterruptLow | (g_savedInterruptHigh << 8);
REG_IE = savedIE;
// Capture Timer 2 value
uint16_t capturedTime = REG_TM2;
// Enable interrupts during processing
REG_PSWH |= 0x01;
REG_LRB = 0x1B; // Bank at 0xD8
// Check for overflow (ACCH.7 set)
if (REG_ACCH & 0x80)
goto ckpHandleOverflow;
// Check for spurious interrupt (IRQH.0)
if (!(REG_IRQH & 0x01))
goto ckpHandleOverflow;
// Valid CKP signal - increment counter
(*(uint8_t*)0xDB)++;
g_sensorFlags |= 0x02;
ckpHandleOverflow:
// Store captured time
*(uint16_t*)0xDA = capturedTime; // er2
*(uint16_t*)0xD8 = capturedTime; // er0
// Clear and swap counter
uint8_t count = *(uint8_t*)0xDB;
*(uint8_t*)0xDB = 0;
*(uint8_t*)0xDA = count;
// Set sync flag
g_sensorFlags |= 0x04;
// Restore IE and return
savedIE = *(uint16_t*)0xF2;
REG_PSWH &= 0xFE;
REG_IE = savedIE;
}
/**
* isr_serialRx - K-Line Serial Receive
* Address: 0x01FD
*
* Handles incoming serial data from diagnostic tools.
* Implements Honda K-line protocol for ECU communication.
*
* Register bank 0x6F (r0-r7 at 0x378-0x37F)
*/
void isr_serialRx(void) {
// Save IE and set processing mode
uint16_t savedIE = g_savedInterruptLow | (g_savedInterruptHigh << 8);
REG_IE = savedIE;
REG_PSW = 0x0102;
REG_LRB = 0x6F; // Bank at 0x378
// Check serial mode flag
if (!(g_serialFlags & 0x02)) {
// Response mode - sending data back
if (!(g_serialFlags & 0x40)) {
// Not in middle of response
goto receiveNewCommand;
}
// Continue sending response
uint8_t respIndex = *(uint8_t*)0x37D; // r5
if (respIndex == 2) {
// Send count byte
uint8_t count = *(uint8_t*)0x37A; // r2
(*(uint8_t*)0x37E) += count; // r6 checksum
REG_STBUF = count;
} else if (respIndex >= *(uint8_t*)0x37A) {
// Done sending - send checksum
uint8_t checksum = -(*(uint8_t*)0x37E);
REG_STBUF = checksum;
goto finishSerialRx;
} else {
// Send data byte
uint8_t dataOffset = respIndex + *(uint8_t*)0x37B; // r3 base
REG_DP = 0x6B56 + (dataOffset * 2); // Table address
uint16_t addrPtr = *(uint16_t*)REG_DP;
REG_DP = addrPtr;
uint8_t dataByte = *(uint8_t*)REG_DP;
(*(uint8_t*)0x37E) += dataByte; // Add to checksum
REG_STBUF = dataByte;
}
(*(uint8_t*)0x37D)++; // Increment index
g_serialFlags |= 0x40; // Mark response in progress
goto finishSerialRx;
}
receiveNewCommand:
// Receive mode - process incoming byte
uint8_t rxByte = REG_SRBUF;
uint8_t msgIndex = *(uint8_t*)0x37D;
if (*(uint8_t*)0x37F) {
// Already have header
if (msgIndex == 1) {
// Second byte is length
*(uint8_t*)0x37A = rxByte;
} else if (msgIndex == 2) {
// Third byte is address
*(uint8_t*)0x37B = rxByte;
} else {
// Data or checksum
*(uint8_t*)0x37C = rxByte;
}
(*(uint8_t*)0x37E) += rxByte; // Add to checksum
(*(uint8_t*)0x37D)++;
*(uint8_t*)0x37F = 0x02;
goto finishSerialRx;
}
// First byte - save as header
*(uint8_t*)0x378 = *(uint8_t*)0x379;
*(uint8_t*)0x379 = rxByte;
*(uint8_t*)0x37E = rxByte; // Start checksum
*(uint8_t*)0x37D = 1;
*(uint8_t*)0x37F = 0x02;
goto finishSerialRx;
finishSerialRx:
// Validate complete message
if (msgIndex + 1 >= *(uint8_t*)0x37A) {
// Check checksum
uint8_t finalChecksum = REG_SRBUF + *(uint8_t*)0x37E;
if (finalChecksum == 0) {
// Valid message - check header
uint8_t header = *(uint8_t*)0x379;
if ((header & 0xE0) == 0x20) {
// Valid read request
g_serialFlags |= 0x80;
}
}
*(uint8_t*)0x37F = 0; // Reset state
}
// Restore IE
savedIE = *(uint16_t*)0xF2;
REG_PSWH &= 0xFE;
REG_IE = savedIE;
}
/**
* isr_timer2Overflow - Timer 2 Overflow Handler
* Address: 0x02DD
*
* Handles Timer 2 overflow for extended timing.
* Updates overflow counters for ignition timing.
*/
void isr_timer2Overflow(void) {
uint16_t savedIE = g_savedInterruptLow | (g_savedInterruptHigh << 8);
REG_IE = savedIE;
REG_PSWH |= 0x01;
REG_LRB = 0x1B;
// Check and increment overflow counters
if (!(g_sensorFlags & 0x01))
(*(uint8_t*)0xDE)++; // r6
if (!(g_sensorFlags & 0x02))
(*(uint8_t*)0xDB)++; // r3
// Restore and return
savedIE = *(uint16_t*)0xF2;
REG_PSWH &= 0xFE;
REG_IE = savedIE;
}
/**
* isr_timer3Match - Timer 3 Match Handler
* Address: 0x02FB
*
* Supplementary timer for ignition control.
*/
void isr_timer3Match(void) {
uint16_t savedIE = g_savedInterruptLow | (g_savedInterruptHigh << 8);
REG_IE = savedIE;
REG_PSWH |= 0x01;
REG_LRB = 0x1A;
uint8_t count = *(uint8_t*)0xD0 + 1;
if (count >= 5) {
// Check TCON3.2 before firing
if (!(REG_TCON3 & 0x04)) {
REG_TMR3 = *(uint16_t*)0xD6; // er3
REG_TCON3 |= 0x08;
}
}
savedIE = *(uint16_t*)0xF2;
REG_PSWH &= 0xFE;
REG_IE = savedIE;
}
/**
* isr_pwmTimer - PWM Timer for IACV Control
* Address: 0x031E
*
* Controls Idle Air Control Valve PWM output.
* Runs at fixed frequency, adjusts duty cycle for idle speed.
*
* Register bank 0x70 (r0-r7 at 0x380-0x387)
*/
void isr_pwmTimer(void) {
uint16_t savedIE = g_savedInterruptLow | (g_savedInterruptHigh << 8);
REG_IE = savedIE;
REG_PSWH |= 0x01;
REG_LRB = 0x70; // Bank at 0x380
// Check operating mode
if (g_serialFlags & 0x01) {
// Special serial mode - use saved values
uint8_t duty = *(uint8_t*)0x382;
if (duty == 0) {
// Load new cycle parameters
*(uint8_t*)0x383 = g_firingOrderPhase; // 0xE6
*(uint16_t*)0x382 = g_crankPosition; // 0xE4
duty = 0x31; // Default duty
}
goto setDutyCycle;
}
// Normal IACV operation
uint8_t counter = *(uint8_t*)0x380;
counter++;
// Check for cycle wrap at 100 (0x64)
if (counter >= 0x64) {
// Start new cycle - load target duty
*(uint8_t*)0x381 = g_iacvDutyCycle;
counter = 0;
}
*(uint8_t*)0x380 = counter;
// Compare counter to duty for P4.3 output
if (counter < *(uint8_t*)0x381)
REG_P4 |= 0x08; // High (valve open)
else
REG_P4 &= ~0x08; // Low (valve closed)
// Set flag when counter hits zero
if (counter == 0)
g_sensorFlags |= 0x08;
goto finishPwm;
setDutyCycle:
*(uint8_t*)0x382 = duty;
// Check for special duty value
if (duty == 0x0D)
g_sensorFlags |= 0x40;
// Compare to target
if (duty == *(uint8_t*)0x383) {
// Match - load PWM value
REG_PWMR0 = *(uint16_t*)0x382;
} else {
// Calculate direction
if (duty >= *(uint8_t*)0x383)
REG_PWMR0 = 1;
else
REG_PWMR0 = 0xFFFF;
}
finishPwm:
savedIE = *(uint16_t*)0xF2;
REG_PSWH &= 0xFE;
REG_IE = savedIE;
}
/**
* isr_externalInt1 - Main Engine Processing Entry
* Address: 0x037B
*
* INT1 is triggered at key engine events.
* This is the main entry point for engine calculations.
*/
void isr_externalInt1(void) {
REG_IE = 0x00A0; // Minimal interrupts
REG_PSW = 0x0102;
REG_LRB = 0x21;
REG_USP = 0x0280;
// Call main processing function
call_mainSensorScan(); // label_5262
// Set processing flag
g_ignitionFlags |= 0x10; // 0x120.4
// Check various error conditions
if (g_errorFlags1 & 0x80) // 0x112.7
goto mainProcessingDone;
if (g_errorFlags1 & 0x08) // 0x112.3
goto processAdcAndTiming;
// Check IRQH.1
if (!(REG_IRQH & 0x02)) {
g_groundReference &= ~0x01; // 0x9C.0
g_vtecHoldCounter = 0x2D; // 0x1A9
} else {
g_groundReference |= 0x01;
}
goto mainProcessingDone;
processAdcAndTiming:
// Capture O2 sensor
g_o2SecondaryRaw = REG_ADCR6;
// Capture Timer 2 for ignition reference
g_ignitionDwellStart = REG_TM2;
REG_TMR2 = g_ignitionDwellStart;
// Initialize cycle counter
g_injectorTiming1 = 0; // 0xD2
// Check timing connector
uint8_t adjCount = g_vtecQualifyFlags;
if (!(REG_TRNSIT & 0x01)) {
adjCount += 6;
if (adjCount >= 0x18)
adjCount = 3;
}
g_vtecQualifyFlags = adjCount;
// Set P4.0 output
REG_P4 |= 0x01;
// Continue to main processing
goto call_mainProcessing; // label_5f74
}
/**
* isr_serialRxBrg - Serial Baud Rate Generator Handler
* Address: 0x03DC
*
* Also used as secondary main processing entry point.
* Copies flags and continues engine calculations.
*/
void isr_serialRxBrg(void) {
REG_IE = 0x00A0;
REG_PSW = 0x0102;
REG_LRB = 0x21;
REG_USP = 0x0280;
// Copy flag banks from stack area
g_errorFlags1 = *(uint8_t*)0x212; // USP-0x80+0x92
g_errorFlags3 = *(uint16_t*)0x214;
g_vtecFlags1 = *(uint16_t*)0x216;
g_vtecHoldCounter = 0x2D;
// Check processing flags
if (!(g_ignitionFlags & 0x08)) // 0x120.3
goto checkRevLimit;
// Check for rev limit conditions
if (g_errorFlags1 & 0x80) {
g_ignitionFlags |= 0x10;
goto processNormal;
}
if (!(REG_IRQH & 0x80) && !(g_sensorFlags & 0x80)) {
goto incrementCounter;
}
// Rev limiting active
g_ignitionFlags |= 0x10;
g_ignitionFlags &= ~0x40;
g_vtecHoldCounter = 0x2D;
// Check cycle count
uint16_t cycleCount = g_injectorTiming1;
if (cycleCount == 5)
goto fuelCutCheck;
g_fuelCutFlags |= 0x40; // 0x11D.6
if (cycleCount < 5) {
g_ignitionFlags |= 0x20;
goto fuelCutCheck;
}
if (cycleCount >= 0x105) {
g_timingAdjustInput |= 0x02; // 0x9D.1
goto clearCycleCount;
}
g_timingAdjustInput |= 0x01; // 0x9D.0
goto fuelCutCheck;
incrementCounter:
if (g_injectorTiming1 < 5) {
g_injectorTiming1++;
goto processIgnition;
}
if (!(g_errorFlags1 & 0x80)) {
g_groundReference |= 0x02;
g_ignitionFlags |= 0x40;
}
g_injectorTiming2++;
g_injectorTiming1 = 0;
goto processIgnition;
checkRevLimit:
REG_IRQH &= ~0x80;
g_sensorFlags &= ~0x80;
g_sensorFlags &= ~0x04;
if (g_sensorFlags & 0x01)
g_ignitionFlags |= 0x10;
goto fuelCutCheck;
fuelCutCheck:
g_sensorFlags &= ~0x04;
processIgnition:
// Continue processing...
goto continueMainProcessing;
clearCycleCount:
g_injectorTiming1 = 0;
goto processIgnition;
processNormal:
goto continueMainProcessing;
continueMainProcessing:
// Further processing in main engine routines
return;
}
/**
* isr_serialTx - Serial Transmit (placeholder)
* Address: 0x21CB
*
* Handles serial transmit complete interrupt.
* Also used as dummy handler for unused vectors.
*/
void isr_serialTx(void) {
// Set life counter to 'E' pattern (reboot marker)
g_lifeCounter = 0x45;
}
/**
* isr_watchdog - Watchdog Timer Reset
* Address: 0x21D1
*
* Called when watchdog timer expires.
* Sets reboot reason code.
*/
void isr_watchdog(void) {
g_lifeCounter = 0x44; // 'D' - WDT reset code
}
/**
* isr_systemStart - System Startup
* Address: 0x21E2
*
* First code executed after reset.
* Initializes registers and jumps to main init.
*/
void isr_systemStart(void) {
g_lifeCounter = 0x46; // 'F' - Normal start
// Jump to initialization code...
}
/**
* isr_break - Software Break Handler
* Address: 0x21E9
*
* Handles BRK instruction - used for debugging.
*/
void isr_break(void) {
REG_WDT = 0x3C; // Feed watchdog
// Handle break...
}
/*============================================================================
* SECTION 6: VCAL HELPER FUNCTIONS
*
* VCAL (Vector Call) functions are table lookup and math helpers.
* Called via special VCAL instruction with index 0-7.
*============================================================================*/
/**
* vcal_tableLookup1D - 1D Table Interpolation
* Address: 0x4E62 (VCAL 0)
*
* Performs linear interpolation on a 1D table.
* Input: A = lookup value, X1 = table base address
* Output: A = interpolated result
*
* Table format: pairs of (threshold, value) ending with 0xFF threshold
*/
uint8_t vcal_tableLookup1D(uint8_t input, uint16_t tableAddr) {
uint8_t* table = (uint8_t*)tableAddr;
// Walk table until we find input >= threshold
while (input >= table[2]) {
table += 2; // Move to next entry
}
// Store found threshold for interpolation
uint8_t upperThreshold = table[2];
uint8_t upperValue = table[3];
uint8_t lowerThreshold = table[1];
uint8_t lowerValue = table[0];
// Calculate interpolation
uint8_t thresholdDelta = input - upperThreshold;
int8_t valueDelta = lowerValue - upperValue;
// Handle negative delta
bool negative = false;
if (valueDelta < 0) {
negative = true;
valueDelta = -valueDelta;
}
// Interpolate: result = upperValue + (delta * valueDelta / thresholdDelta)
uint16_t product = thresholdDelta * valueDelta;
uint8_t interpolation = product / (lowerThreshold - upperThreshold);
if (negative)
return upperValue - interpolation;
else
return upperValue + interpolation;
}
/**
* vcal_tableLookup2D - 2D Table Interpolation
* Address: 0x4EC0 (VCAL 1)
*
* Performs bilinear interpolation on a 2D table.
* Input: A = row lookup value, X1 = table base with axis data
* Output: er3 = 16-bit interpolated result
*
* Table format: 3-byte entries (threshold, value_low, value_high)
*/
uint16_t vcal_tableLookup2D(uint8_t rowInput, uint16_t tableAddr) {
uint8_t* table = (uint8_t*)tableAddr;
// Walk table by 3-byte entries
while (rowInput >= table[3]) {
table += 3;
}
// Get boundary values
uint8_t upperThreshold = table[3];
uint8_t lowerThreshold = table[0];
uint8_t thresholdDelta = rowInput - upperThreshold;
// Get 16-bit values
uint16_t lowerValue = table[1] | (table[2] << 8);
uint16_t upperValue = table[4] | (table[5] << 8);
// Calculate delta and interpolate
int16_t valueDelta = lowerValue - upperValue;
bool negative = false;
if (valueDelta < 0) {
negative = true;
valueDelta = -valueDelta;
}
// 16-bit multiply and divide for precision
uint32_t product = (uint32_t)thresholdDelta * valueDelta;
uint16_t divisor = lowerThreshold - upperThreshold;
uint16_t interpolation = product / divisor;
if (negative)
return upperValue - interpolation;
else
return upperValue + interpolation;
}
/**
* vcal_clampTableLookup - Clamped Table Lookup
* Address: 0x4E9C (VCAL 2)
*
* Like VCAL 0 but clamps input to table range.
* If input < table[0], uses table[0].
* If input > table[2], uses table[2].
*/
uint8_t vcal_clampTableLookup(uint8_t input, uint16_t tableAddr) {
uint8_t* table = (uint8_t*)tableAddr;
// Clamp to minimum
if (input < table[0])
input = table[0];
// Clamp to maximum
if (input >= table[2])
input = table[2];
// Use standard lookup
return vcal_tableLookup1D(input, tableAddr);
}
/**
* vcal_rangeLimit - Value Range Limiter
* Address: 0x4EAE (VCAL 3)
*
* Clamps input to table-defined range, 3-byte entries.
* Similar to VCAL 2 but uses 3-byte table format.
*/
uint8_t vcal_rangeLimit(uint8_t input, uint16_t tableAddr) {
uint8_t* table = (uint8_t*)tableAddr;
// Clamp to range [table[0], table[3]]
if (input < table[0])
input = table[0];
if (input >= table[3])
input = table[3];
return vcal_tableLookup2D(input, tableAddr);
}
/**
* vcal_mainProcess - Main Processing Entry
* Address: 0x25A1 (VCAL 4)
*
* Entry point called during main engine calculations.
* Dispatches to various subsystem processors.
*/
void vcal_mainProcess(void) {
// This is a complex dispatcher - NOP in simple form
__asm("NOP");
// Actually continues into main engine processing
// See main engine section for full implementation
}
/**
* vcal_multiply16 - 16-bit Multiply Helper
* Address: 0x4F7F (VCAL 5)
*
* Performs 16x16 bit multiply with 32-bit result.
* Input: A, er0 = multiplicands
* Output: er1:A = 32-bit product
*/
uint32_t vcal_multiply16(uint16_t a, uint16_t b) {
// Check for sign
if (a & 0x8000) {
// Handle as signed
return (int16_t)a * (int16_t)b;
}
return a * b;
}
/**
* vcal_divide16 - 16-bit Divide Helper
* Address: 0x4F84 (VCAL 6)
*
* Performs 32/16 bit divide.
* Input: er1:A = 32-bit dividend, er0 = 16-bit divisor
* Output: A = quotient, er1 = remainder
*/
uint16_t vcal_divide16(uint32_t dividend, uint16_t divisor) {
if (divisor == 0) return 0xFFFF; // Saturate on divide by zero
return dividend / divisor;
}
/**
* vcal_absValue - Absolute Value Helper
* Address: 0x4FCE (VCAL 7)
*
* Returns absolute value of signed 16-bit number.
* Input: A = signed value
* Output: A = |A|
*/
uint16_t vcal_absValue(int16_t value) {
if (value < 0)
return -value;
return value;
}
/*============================================================================
* SECTION 7: MAIN ENGINE CONTROL FUNCTIONS
*
* Core engine management routines that coordinate fuel, ignition,
* VTEC, and diagnostics.
*============================================================================*/
/**
* call_mainSensorScan - Read All Sensors
* Address: 0x5262
*
* Scans all ADC channels and updates sensor variables.
* Called at start of each engine cycle.
*/
void call_mainSensorScan(void) {
// Capture battery voltage from ADC6 high byte
g_o2SecondaryRaw = REG_ADCR2H;
// Process delta calculation
uint8_t oldValue = *(uint8_t*)0x3D2; // Saved from last scan
*(uint8_t*)0x3D2 = g_batteryVoltageRaw; // c5h
uint8_t newValue = REG_ADCR2H;
g_batteryVoltageRaw = newValue;
// Calculate delta and set direction flag
int8_t delta = newValue - oldValue;
if (delta >= 0)
g_stateFlags22B |= 0x20;
else
g_stateFlags22B &= ~0x20;
// Store delta magnitude
if (delta < 0) delta = -delta;
g_ecuVoltageRaw = delta; // 0xC6
// Capture P2 injector state
g_stateFlags255 = REG_P2 & 0xE0;
// Prepare for ADC scan
uint16_t savedIE = *(uint16_t*)0xF4;
REG_IE = savedIE;
REG_PSWH &= 0xFE;
// Clear ADC scan flag and start conversion
REG_ADSCAN &= 0xEF;
REG_P2 &= 0x1F;
REG_ADSCAN |= 0x10;
REG_PSWH |= 0x01;
savedIE = *(uint16_t*)0xF2;
REG_IE = savedIE;
}
/**
* process_rpmCalculation - Calculate Engine RPM
* Address: 0x074E-0x07F3
*
* Calculates RPM from timer captures and updates history buffers.
* Uses formula: RPM = 1,851,562 / timer_ticks
*/
void process_rpmCalculation(void) {
REG_DP = 0x0360; // RPM history buffer
uint32_t sum = 0;
// Sum last 6 timer values
for (int i = 0; i < 6; i++) {
uint16_t value = *(uint16_t*)REG_DP;
if (value == 0) {
// Invalid reading - set error flag
g_stateFlags231 |= 0x20;
g_rpmTimerAverage = 0xFFFF;
return;
}
sum += value;
REG_DP += 2;
}
// Clear error flag
g_stateFlags217 &= ~0x10;
g_stateFlags231 &= ~0x20;
// Calculate average
uint16_t average = sum / 5;
if (sum % 5 != 0) {
g_stateFlags231 |= 0x20;
average = 0xFFFF;
}
// Store result
g_rpmTimerAverage = average;
// Shift history buffer
REG_DP = 0x036C;
uint16_t temp = g_mapSensorRaw; // 0xAC
g_mapSensorRaw = *(uint16_t*)REG_DP;
*(uint16_t*)REG_DP = temp;
REG_DP += 2;
temp = *(uint16_t*)REG_DP;
*(uint16_t*)REG_DP = g_mapSensorRaw;
REG_DP += 2;
*(uint16_t*)REG_DP = temp;
// Calculate delta from average
uint16_t delta = g_rpmTimerAverage - temp;
if (delta >= 0)
g_stateFlags21B |= 0x80;
else
g_stateFlags21B &= ~0x80;
// Absolute value
if (delta < 0) delta = -delta;
g_mapSensorRaw = delta; // Reusing for delta temp
// Second delta calculation
delta = g_rpmTimerAverage - g_mapSensorOld;
if (delta >= 0)
g_stateFlags21B |= 0x40;
else
g_stateFlags21B &= ~0x40;
// Convert timer ticks to RPM byte
// Using lookup table at 0x6D08 for breakpoints
if (g_mapSensorRaw >= 0x00EA && g_mapSensorRaw < 0x0EA6) {
// Normal operating range - calculate RPM index
uint16_t rpmValue = g_mapSensorRaw;
uint16_t mask = 0xFFC0;
uint8_t index = 7;
uint16_t tableOffset = 0x5300;
REG_DP = TBL_DIAGNOSTIC_PARAMS; // 0x6D08
while (1) {
uint16_t threshold = *(uint16_t*)REG_DP;
if (rpmValue >= threshold)
break;
index >>= 1;
tableOffset >>= 1;
mask += 0x0040;
REG_DP += 2;
}
// Calculate final RPM byte
uint16_t remainder = tableOffset / rpmValue;
remainder >>= 1;
mask += remainder;
// Check for edge cases
if (mask >= 0xFF) {
g_rpmByteNonVtec = 0xFE;
} else if (mask <= 1) {
g_rpmByteNonVtec = 1;
} else {
g_rpmByteNonVtec = mask;
}
} else if (g_mapSensorRaw < 0x00BB) {
// Very high RPM
g_rpmByteNonVtec = 0xFF;
} else if (g_mapSensorRaw >= 0x0EA6) {
// Very low RPM or stalled
g_rpmByteNonVtec = 0;
if (!(g_stateFlags217 & 0x10))
g_rpmByteNonVtec = 1;
}
// Set RPM direction flag
if (g_rpmByteNonVtec >= 0xFE)
g_sensorFlags |= 0x80; // 0xA0.7
else
g_sensorFlags &= ~0x80;
// Store to second RPM byte location
g_stateFlags236 = g_rpmByteNonVtec;
g_tpsSensorFiltered = g_rpmByteNonVtec;
}
/**
* process_mapSensor - Process MAP Sensor Reading
* Address: 0x09AB-0x09CF
*
* Reads manifold absolute pressure and calculates load.
* Updates g_mapImageBase (0xB4) for fuel/ignition lookups.
*/
void process_mapSensor(void) {
// Calculate MAP delta for transient detection
uint16_t mapDelta = g_mapSensorRaw - g_stateFlags258;
if (mapDelta >= 0)
g_stateFlags21A |= 0x20;
else
g_stateFlags21A &= ~0x20;
// Store delta direction
g_mapSensorOld = mapDelta; // 0xB2
// Check for closed throttle (high vacuum)
if (g_stateFlags22B & 0x01) {
// Already flagged as high vacuum
if (g_stateFlags236 < 0x98)
goto normalMapProcessing;
} else {
if (g_stateFlags236 >= 0xA0)
goto normalMapProcessing;
}
// Update closed throttle flag
if (g_stateFlags236 >= 0x98)
g_stateFlags22B |= 0x01;
else
g_stateFlags22B &= ~0x01;
normalMapProcessing:
// Check RPM threshold for decel fuel cut
if (g_stateFlags218 & 0x80) {
if (g_stateFlags236 < 0xCD)
goto updateMapImage;
} else {
if (g_stateFlags236 >= 0xD0)
goto updateMapImage;
}
g_stateFlags218 |= 0x80;
goto updateMapImage;
updateMapImage:
// Update MAP image for fuel/ignition lookups
// Scale raw ADC to 0-DF range
// MAP image determines column in 2D tables
}
/**
* process_tpsSensor - Process Throttle Position Sensor
* Address: 0x09DB-0x0A3D
*
* Reads TPS and calculates rate of change for accel enrichment.
*/
void process_tpsSensor(void) {
// Setup for table lookup
uint16_t tableAddr = TBL_RPM_AXIS_NONVTEC; // 0x700A
uint8_t lastInterp = *(uint8_t*)0x1D8; // Previous interpolation
uint8_t currentRpm = g_stateFlags236;
uint8_t interpFactor = 0x12;
// Check for VTEC active to select table
if (g_sensorFlags & 0x80) // 0xA0.7
interpFactor |= 0x80; // VTEC flag in high bit
// Call 2D interpolation
uint8_t rpmIndex = vcal_tableLookup1D(currentRpm, tableAddr);
*(uint8_t*)0x1DA = rpmIndex;
*(uint8_t*)0x1D8 = interpFactor;
// Second axis lookup for TPS
tableAddr = TBL_RPM_AXIS_VTEC; // 0x701E
lastInterp = *(uint8_t*)0x1D9;
uint8_t tpsValue = g_tpsSensorRaw;
interpFactor = 0x12;
// Check VTEC and direction flags
if (g_stateFlags227 & 0x20) {
currentRpm = g_stateFlags236;
}
if (g_sensorFlags & 0x40) // 0xA0.6
interpFactor |= 0x80;
rpmIndex = vcal_tableLookup1D(currentRpm, tableAddr);
*(uint8_t*)0x1DC = rpmIndex;
*(uint8_t*)0x1D9 = interpFactor;
// Process TPS for acceleration
uint8_t iatValue = g_iatProcessed; // 0xA4
if (!(g_stateFlags212 & 0x04) && !(g_stateFlags212 & 0x10))
iatValue = g_rpmByteVtec; // 0xA7
// TPS delta calculation for accel enrichment
tableAddr = TBL_ACCEL_ENRICHMENT; // 0x7000
lastInterp = *(uint8_t*)0x1D2;
interpFactor = 0x08;
// Clear VTEC flag for non-VTEC table
uint8_t result = vcal_tableLookup1D(iatValue, tableAddr);
*(uint8_t*)0x1D4 = result;
*(uint8_t*)0x1D2 = interpFactor;
// Repeat for VTEC table
tableAddr = TBL_ACCEL_ENRICHMENT;
lastInterp = *(uint8_t*)0x1D3;
iatValue = g_rpmByteVtec;
interpFactor = 0x08;
result = vcal_tableLookup1D(iatValue, tableAddr);
*(uint8_t*)0x1D6 = result;
*(uint8_t*)0x1D3 = interpFactor;
}
/**
* process_o2Sensor - Process Oxygen Sensor
* Address: 0x0B4C-0x0BE7
*
* Implements closed-loop fuel control using O2 sensor feedback.
* Adjusts g_fuelO2TrimPrimary (0x162) and secondary (0x164).
*/
void process_o2Sensor(void) {
// Check if closed-loop conditions are met
if (g_stateFlags227 & 0x20) {
// Special mode - use alternate registers
uint8_t o2Value = g_stateFlags236; // 0x236
goto processO2Value;
}
if (!(g_stateFlags21F & 0x02))
return; // Open loop - no O2 correction
processO2Value:
// Get O2 sensor reading
uint8_t o2Raw = g_o2PrimaryRaw; // 0xA1
// Compare to stoich threshold (typically 0x1F = 31 decimal)
// < 0x1F is lean, > 0x1F is rich
if (o2Raw < 0x1F) {
// Lean condition - add fuel
g_stateFlags21B |= 0x01; // Set lean flag
} else {
// Rich condition - remove fuel
g_stateFlags21B &= ~0x01; // Clear lean flag
}
// Apply proportional + integral correction
// Lookup correction rate from table
uint16_t tableAddr = TBL_O2_CLOSED_LOOP; // 0x605E
uint8_t correctionRate = vcal_tableLookup1D(g_rpmByteNonVtec, tableAddr);
// Update O2 trim value
if (g_stateFlags21B & 0x01) {
// Lean - increase fuel
if (g_fuelO2TrimPrimary < 0xFFFF)
g_fuelO2TrimPrimary += correctionRate;
} else {
// Rich - decrease fuel
if (g_fuelO2TrimPrimary > 0)
g_fuelO2TrimPrimary -= correctionRate;
}
// Clamp to valid range
if (g_fuelO2TrimPrimary > 0x0200)
g_fuelO2TrimPrimary = 0x0200; // Max +12.5% trim
if (g_fuelO2TrimPrimary < 0xFE00)
g_fuelO2TrimPrimary = 0xFE00; // Max -12.5% trim
}
/*============================================================================
* SECTION 8: FUEL CALCULATION FUNCTIONS
*
* Fuel injection pulse width calculations including all corrections.
*============================================================================*/
/**
* calc_fuelPulseWidth - Calculate Injector Pulse Width
* Address: 0x1C00-0x1F84
*
* Main fuel calculation routine. Combines:
* - Base fuel from 2D map
* - ECT/IAT corrections
* - O2 feedback trim
* - Accel/decel enrichment
* - Battery voltage compensation
* - AC load compensation
*/
void calc_fuelPulseWidth(void) {
// Select VTEC or non-VTEC fuel map
uint16_t fuelMapBase;
if (g_vtecStateFlags & 0x80) {
// VTEC engaged - use VTEC map
fuelMapBase = TBL_FUEL_VTEC_ADDR;
} else {
// Non-VTEC - use standard map
fuelMapBase = TBL_FUEL_NONVTEC_ADDR;
}
// Look up base fuel from 2D map
// Row = RPM index, Column = MAP index
uint8_t rpmIndex = *(uint8_t*)0x1DA; // From TPS processing
uint8_t mapIndex = g_mapImageFinal >> 4; // High nibble is column
// Calculate table address
uint16_t tableOffset = (rpmIndex * 20) + (mapIndex * 2);
uint16_t* fuelTable = (uint16_t*)(fuelMapBase + tableOffset);
// Get surrounding cells for interpolation
uint16_t cellLL = fuelTable[0];
uint16_t cellLR = fuelTable[1];
uint16_t cellUL = fuelTable[20];
uint16_t cellUR = fuelTable[21];
// Interpolate based on fractional position
uint8_t rpmFrac = *(uint8_t*)0x1D8 & 0x0F; // Low nibble is fraction
uint8_t mapFrac = g_mapImageFinal & 0x0F; // Low nibble is fraction
// Bilinear interpolation
uint16_t interpL = cellLL + ((cellUL - cellLL) * rpmFrac) / 16;
uint16_t interpR = cellLR + ((cellUR - cellLR) * rpmFrac) / 16;
uint16_t baseFuel = interpL + ((interpR - interpL) * mapFrac) / 16;
// Store base fuel value
if (g_vtecStateFlags & 0x80)
g_fuelMapVtec = baseFuel;
else
g_fuelMapNonVtec = baseFuel;
// Apply warmup enrichment (ECT based)
uint16_t warmupMult = g_fuelWarmupMult; // 0x15E
baseFuel = (baseFuel * warmupMult) / 256;
g_fuelMainCorrected = baseFuel;
// Apply all additional corrections
uint16_t totalCorrections = 0;
// TPS acceleration enrichment
totalCorrections += g_fuelTpsDelta; // 0x14A
// Battery voltage dead time compensation
totalCorrections += g_fuelBatteryTrim; // 0x14C
// AC compressor load
if (g_acFlags & 0x02)
totalCorrections += g_fuelAcTrim; // 0x14E
// Timing connector adjustment
totalCorrections += g_fuelTimingTrim; // 0x152
// TPS steady-state adjustment
totalCorrections += g_fuelTpsRelated; // 0x150
g_fuelAllCorrections = totalCorrections;
// Calculate final fuel before O2
g_fuelFinalNoO2 = baseFuel + totalCorrections - g_fuelAcTrim;
// Apply O2 sensor trim (closed loop)
uint16_t o2Multiplier;
if (g_openClosedLoopFlag & 0x01) {
// Use primary O2
o2Multiplier = g_fuelO2TrimPrimary;
} else {
// Use secondary O2
o2Multiplier = g_fuelO2TrimSecondary;
}
// Final fuel = base * o2Mult / 0x10000 * 2 + corrections
uint32_t finalCalc = (uint32_t)g_fuelMainCorrected * o2Multiplier;
finalCalc = (finalCalc / 0x10000) * 2;
finalCalc += totalCorrections;
g_injectorPulseWidth = (uint16_t)finalCalc;
// Store to injector timing register
g_injectorTiming0 = g_injectorPulseWidth;
}
/**
* calc_injectorDeadTime - Calculate Injector Dead Time
* Address: 0x158 reference
*
* Compensates for injector opening time based on battery voltage.
* Lower voltage = longer opening time needed.
*/
uint16_t calc_injectorDeadTime(uint8_t batteryVoltage) {
// Table lookup at TBL_INJECTOR_DEAD_TIME (0x6190)
return vcal_tableLookup1D(batteryVoltage, TBL_INJECTOR_DEAD_TIME);
}
/*============================================================================
* SECTION 9: IGNITION TIMING FUNCTIONS
*
* Spark advance calculation and dwell control.
*============================================================================*/
/**
* calc_ignitionTiming - Calculate Spark Advance
* Address: 0x1200-0x1400
*
* Calculates ignition timing from:
* - Base timing from 2D map
* - ECT advance/retard
* - IAT correction
* - Knock retard
* - Idle timing trim
*/
void calc_ignitionTiming(void) {
// Select VTEC or non-VTEC ignition map
uint16_t ignMapBase;
if (g_vtecStateFlags & 0x80) {
ignMapBase = TBL_IGN_VTEC_ADDR;
} else {
ignMapBase = TBL_IGN_NONVTEC_ADDR;
}
// Look up base timing from 2D map
uint8_t rpmIndex = *(uint8_t*)0x1DA;
uint8_t mapIndex = g_mapImageFinal >> 4;
// Calculate table address
uint16_t tableOffset = (rpmIndex * 20) + mapIndex;
uint8_t* ignTable = (uint8_t*)(ignMapBase + tableOffset);
// Get surrounding cells for interpolation
uint8_t cellLL = ignTable[0];
uint8_t cellLR = ignTable[1];
uint8_t cellUL = ignTable[20];
uint8_t cellUR = ignTable[21];
// Interpolate
uint8_t rpmFrac = *(uint8_t*)0x1D8 & 0x0F;
uint8_t mapFrac = g_mapImageFinal & 0x0F;
uint8_t interpL = cellLL + ((cellUL - cellLL) * rpmFrac) / 16;
uint8_t interpR = cellLR + ((cellUR - cellLR) * rpmFrac) / 16;
uint8_t baseAdvance = interpL + ((interpR - interpL) * mapFrac) / 16;
g_ignitionMapRaw = baseAdvance;
// Apply corrections
int8_t finalAdvance = baseAdvance;
// ECT correction (cold = more advance)
finalAdvance += g_ignitionEctTrim;
// Idle timing trim (from timing connector)
if (g_idleFlags & 0x01)
finalAdvance += g_ignitionIdleTrim;
// Knock retard (subtracts timing)
finalAdvance -= g_ignitionKnockTrim;
// Brake switch correction
if (g_externalInputs & 0x20) // Brake applied
finalAdvance += g_ignitionBrakeTrim;
// Clamp to valid range (0-60 degrees typical)
if (finalAdvance < 0) finalAdvance = 0;
if (finalAdvance > 60) finalAdvance = 60;
g_ignitionFinal = finalAdvance;
// Calculate complement for timer
g_ignitionComplement = -finalAdvance;
}
/**
* calc_dwellTime - Calculate Coil Dwell Time
* Address: 0x619E table reference
*
* Determines how long to charge ignition coil.
* Longer dwell at lower voltage.
*/
uint16_t calc_dwellTime(uint8_t batteryVoltage) {
return vcal_tableLookup1D(batteryVoltage, TBL_DWELL_TIME);
}
/*============================================================================
* SECTION 10: VTEC CONTROL LOGIC
*
* Variable valve timing engagement and disengagement.
*============================================================================*/
/**
* check_vtecEngagement - VTEC Engagement Logic
* Address: 0x3D00-0x3E00
*
* Checks conditions for VTEC engagement:
* - RPM above threshold
* - Vehicle speed above minimum
* - Oil pressure OK
* - No error codes
*/
void check_vtecEngagement(void) {
// Check if VTEC is currently engaged
if (g_vtecStateFlags & 0x80) {
// VTEC ON - check disengage conditions
goto checkVtecDisengage;
}
// VTEC OFF - check engage conditions
// 1. Check RPM threshold
uint8_t engageRpm = vcal_tableLookup1D(g_coolantTempRaw, TBL_VTEC_ENGAGE_RPM);
if (g_rpmByteNonVtec < engageRpm)
return; // RPM too low
// 2. Check vehicle speed minimum
uint8_t minSpeed = vcal_tableLookup1D(g_coolantTempRaw, TBL_VTEC_MIN_SPEED);
if (g_vehicleSpeedByte < minSpeed)
return; // Speed too low
// 3. Check oil pressure
if (g_oilPressureSwitch < 0x32)
return; // Oil pressure low
// 4. Check for blocking error codes
if (g_celSensorFlags & 0x40) // VTEC solenoid error
return;
if (g_celSystemFlags & 0x80) // Oil pressure switch error
return;
// All conditions met - engage VTEC
g_vtecStateFlags |= 0x80; // Set engaged flag
REG_P1 |= P1_VTEC_SOLENOID; // Activate solenoid
g_vtecHysteresis = 0x14; // Set hold timer (20 cycles)
return;
checkVtecDisengage:
// Check disengage RPM threshold (with hysteresis)
uint8_t disengageRpm = vcal_tableLookup1D(g_coolantTempRaw, TBL_VTEC_DISENGAGE_RPM);
if (g_rpmByteNonVtec > disengageRpm)
return; // RPM still above threshold
// Check hysteresis timer
if (g_vtecHysteresis > 0) {
g_vtecHysteresis--;
return; // Still in hold period
}
// Disengage VTEC
g_vtecStateFlags &= ~0x80; // Clear engaged flag
REG_P1 &= ~P1_VTEC_SOLENOID; // Deactivate solenoid
}
/*============================================================================
* SECTION 11: IDLE CONTROL (IACV)
*
* Idle Air Control Valve management for stable idle.
*============================================================================*/
/**
* update_idleControl - Update IACV Duty Cycle
* Address: 0x2000-0x2200
*
* PID-like control of idle air control valve.
* Adjusts airflow to maintain target idle RPM.
*/
void update_idleControl(void) {
// Get target idle RPM from table (ECT based)
uint16_t targetIdle = vcal_tableLookup1D(g_coolantTempRaw, TBL_IDLE_TARGET);
g_targetIdleRpm = targetIdle;
// Calculate RPM error
int16_t rpmError = g_rpmTimerAverage - targetIdle;
g_rpmTargetDiff = (rpmError < 0) ? -rpmError : rpmError;
// Set under/over target flag
if (rpmError < 0)
g_idleFlags |= 0x04; // Under target
else
g_idleFlags &= ~0x04;
// Get base IACV duty from table
uint8_t baseDuty = vcal_tableLookup1D(g_coolantTempRaw, TBL_IDLE_IACV_BASE);
// Apply proportional correction
int8_t correction = 0;
if (g_idleFlags & 0x04) {
// Under target - open valve more
correction = g_rpmTargetDiff / 10;
if (correction > 20) correction = 20;
} else {
// Over target - close valve
correction = -(g_rpmTargetDiff / 10);
if (correction < -20) correction = -20;
}
// Apply AC load compensation
if (g_acFlags & 0x02) {
correction += 15; // Add ~15% for AC
}
// Calculate final duty
int16_t finalDuty = baseDuty + correction;
// Clamp to valid range (0-100)
if (finalDuty < 0) finalDuty = 0;
if (finalDuty > 100) finalDuty = 100;
g_iacvDutyCycle = (uint8_t)finalDuty;
}
/*============================================================================
* SECTION 12: DIAGNOSTICS AND CEL FUNCTIONS
*
* Check Engine Light control and error code handling.
*============================================================================*/
/**
* check_diagnostics - Run Diagnostic Checks
* Address: 0x2300-0x2500
*
* Checks all sensors and systems for fault conditions.
* Sets appropriate error flags and CEL codes.
*/
void check_diagnostics(void) {
// Check MAP sensor (Code 3)
if (g_mapSensorRaw < 0x0010 || g_mapSensorRaw > 0x0FF0) {
g_celSensorFlags |= 0x01; // Code 3 - MAP
} else {
g_celSensorFlags &= ~0x01;
}
// Check ECT sensor (Code 6)
if (g_coolantTempRaw < 0x05 || g_coolantTempRaw > 0xFA) {
g_celSensorFlags |= 0x02; // Code 6 - ECT
} else {
g_celSensorFlags &= ~0x02;
}
// Check TPS sensor (Code 7)
if (g_tpsSensorRaw < 0x05 || g_tpsSensorRaw > 0xFA) {
g_celSensorFlags |= 0x04; // Code 7 - TPS
} else {
g_celSensorFlags &= ~0x04;
}
// Check CKP signal (Code 4)
if (g_engineStateFlags & 0x01) {
g_celCriticalFlags |= 0x01; // Code 4 - CKP
} else {
g_celCriticalFlags &= ~0x01;
}
// Check TDC signal (Code 8)
if (g_tdcStateFlags & 0x02) {
g_celCriticalFlags |= 0x02; // Code 8 - TDC
} else {
g_celCriticalFlags &= ~0x02;
}
// Check IAT sensor (Code 10)
if (g_intakeAirTempRaw < 0x05 || g_intakeAirTempRaw > 0xFA) {
g_celSensorFlags |= 0x80; // Code 10 - IAT
} else {
g_celSensorFlags &= ~0x80;
}
// Check VTEC solenoid (Code 21)
if (g_vtecStateFlags & 0x80) {
// VTEC should be on - check feedback
if (!(g_externalInputs & EXT_VTEC_FEEDBACK)) {
g_celSystemFlags |= 0x40; // Code 21 - VTEC
}
} else {
g_celSystemFlags &= ~0x40;
}
// Check oil pressure (Code 22)
if (g_oilPressureSwitch < 0x20 && g_rpmByteNonVtec > 0x30) {
g_celSystemFlags |= 0x80; // Code 22 - Oil pressure
} else {
g_celSystemFlags &= ~0x80;
}
// Update CEL output
if (g_celSensorFlags || g_celSystemFlags || g_celCriticalFlags) {
REG_P0 |= P0_CEL_DASH; // Turn on CEL
REG_P1 |= P1_CEL_LED; // Turn on LED
} else {
REG_P0 &= ~P0_CEL_DASH; // Turn off CEL
REG_P1 &= ~P1_CEL_LED; // Turn off LED
}
}
/**
* blink_celCode - CEL Blink Pattern Generator
* Address: 0x2500-0x2700
*
* Generates blink patterns for stored fault codes.
* Long blinks = tens digit, short blinks = ones digit.
*/
void blink_celCode(void) {
// Check for codes to blink
uint8_t codeToShow = 0;
// Scan fault bytes for set bits
if (g_faultCode1) {
for (int i = 0; i < 8; i++) {
if (g_faultCode1 & (1 << i)) {
codeToShow = i + 1; // Codes 1-8
break;
}
}
} else if (g_faultCode2) {
for (int i = 0; i < 8; i++) {
if (g_faultCode2 & (1 << i)) {
codeToShow = i + 9; // Codes 9-16
break;
}
}
} else if (g_faultCode3) {
for (int i = 0; i < 8; i++) {
if (g_faultCode3 & (1 << i)) {
codeToShow = i + 17; // Codes 17-24
break;
}
}
}
if (codeToShow == 0) {
// No codes - steady LED
REG_P1 |= P1_CEL_LED;
return;
}
// Calculate blink pattern
uint8_t longBlinks = codeToShow / 10; // Tens digit
uint8_t shortBlinks = codeToShow % 10; // Ones digit
g_celBlinkPattern = (longBlinks << 4) | shortBlinks;
// State machine for blinking
switch (g_celBlinkState) {
case 0: // Start of pattern
g_celBlinkCounter = longBlinks;
g_celBlinkState = 1;
break;
case 1: // Long blinks
if (g_celBlinkCounter > 0) {
// Long blink on
REG_P1 |= P1_CEL_LED;
g_celCodeCounter = 30; // 300ms on
g_celBlinkState = 2;
} else {
// Done with long blinks
g_celBlinkCounter = shortBlinks;
g_celBlinkState = 3;
}
break;
case 2: // Long blink off
if (g_celCodeCounter == 0) {
REG_P1 &= ~P1_CEL_LED;
g_celCodeCounter = 10; // 100ms off
g_celBlinkCounter--;
g_celBlinkState = 1;
}
break;
case 3: // Short blinks
if (g_celBlinkCounter > 0) {
REG_P1 |= P1_CEL_LED;
g_celCodeCounter = 10; // 100ms on
g_celBlinkState = 4;
} else {
// Pattern complete - pause
g_celCodeCounter = 100; // 1s pause
g_celBlinkState = 5;
}
break;
case 4: // Short blink off
if (g_celCodeCounter == 0) {
REG_P1 &= ~P1_CEL_LED;
g_celCodeCounter = 10;
g_celBlinkCounter--;
g_celBlinkState = 3;
}
break;
case 5: // Pause between codes
if (g_celCodeCounter == 0) {
g_celBlinkState = 0; // Restart pattern
}
break;
}
}
/*============================================================================
* SECTION 13: MAIN LOOP
*============================================================================*/
/**
* main - Main Program Entry
*
* After initialization, enters main loop that processes
* engine events and updates outputs.
*/
void main(void) {
// System initialization
system_init();
// Main loop - runs forever
while (1) {
// Feed watchdog
REG_WDT = 0x3C;
// Check for pending processing flags
if (!(g_processingFlags & 0x02)) {
// Idle - wait for next engine event
continue;
}
g_processingFlags &= ~0x02;
// Process sensors
process_mapSensor();
process_tpsSensor();
process_o2Sensor();
process_rpmCalculation();
// Calculate fuel and timing
calc_fuelPulseWidth();
calc_ignitionTiming();
// Check VTEC conditions
check_vtecEngagement();
// Check rev limiter
if (g_rpmByteNonVtec >= 0xF0) {
// Near rev limit - cut fuel
g_processingFlags |= 0x80;
}
// Update idle control (if at idle)
if (g_idleFlags & 0x01)
update_idleControl();
// Diagnostic checks (every 16 loops)
if ((g_mainLoopCounter & 0x0F) == 0)
check_diagnostics();
g_mainLoopCounter++;
}
}
/**
* system_init - System Initialization
*
* Configures all peripherals and initializes RAM.
*/
void system_init(void) {
// Disable interrupts during init
REG_IE = 0;
// Initialize ports
REG_P0 = 0x00;
REG_P0IO = 0xC8; // CEL, AC, Purge as outputs
REG_P1 = 0x00;
REG_P1IO = 0x07; // VTEC, LEDs as outputs
REG_P2 = 0x0F; // Injectors off (high = off)
REG_P2IO = 0x0F; // Injector outputs
REG_P4 = 0x00;
REG_P4IO = 0x09; // IACV output
// Initialize timers
REG_TCON0 = 0x00;
REG_TCON1 = 0x00;
REG_TCON2 = 0x00;
REG_TCON3 = 0x00;
// Initialize ADC
REG_ADSCAN = 0x00;
REG_ADSEL = 0x00;
// Initialize serial
REG_SRCON = 0x00;
REG_STCON = 0x00;
// Clear RAM
for (uint16_t addr = 0x0098; addr < 0x0400; addr++)
*(uint8_t*)addr = 0;
// Set initial values
g_lifeCounter = 0x20; // Life counter
g_rpmTimerAverage = 0xFFFF; // No RPM yet
g_fuelO2TrimPrimary = 0x0100; // Neutral O2 trim
g_fuelO2TrimSecondary = 0x0100;
// Enable interrupts
REG_IE = 0x00A0; // Enable key interrupts
}
/*============================================================================
* SECTION 14: DATA TABLES (REFERENCE)
*
* Calibration data tables stored in ROM.
* These are referenced but not reproduced in full.
*============================================================================*/
// Table: tbl_6000 - Configuration flags (16 bytes)
// Address: 0x6000-0x600F
// Format: Single bytes indicating feature enables
// Table: tbl_601C - Sensor scaling (6 bytes)
// Address: 0x601C-0x6021
// Format: Scaling factors for ADC readings
// Table: tbl_6022 - TPS breakpoints (4 bytes)
// Address: 0x6022-0x6025
// Table: tbl_6026 - Accel enrichment rates (6 bytes)
// Address: 0x6026-0x602B
// Table: tbl_602C - Decel enleanment (8 bytes)
// Address: 0x602C-0x6033
// Table: tbl_6034 - ECT fuel trim curve (14 bytes)
// Address: 0x6034-0x6041
// Format: (threshold, value) pairs
// Table: tbl_6042 - IAT fuel trim curve (14 bytes)
// Address: 0x6042-0x604F
// Table: tbl_6050 - Barometric fuel trim (14 bytes)
// Address: 0x6050-0x605D
// Table: tbl_605E - O2 closed loop params (14 bytes)
// Address: 0x605E-0x606B
// Table: tbl_606C - Warmup enrichment (14 bytes)
// Address: 0x606C-0x6079
// Table: tbl_607A - Acceleration enrichment (21 bytes)
// Address: 0x607A-0x608E
// Table: tbl_60A7 - Voltage compensation (21 bytes)
// Address: 0x60A7-0x60BB
// Table: tbl_60C8 - RPM axis non-VTEC (4 bytes)
// Address: 0x60C8-0x60CB
// Table: tbl_60CC - RPM axis VTEC (4 bytes)
// Address: 0x60CC-0x60CF
// Table: tbl_60D0 - MAP axis (2 bytes)
// Address: 0x60D0-0x60D1
// Table: tbl_6122 - Idle target RPM by ECT (16 bytes)
// Address: 0x6122-0x6131
// Table: tbl_6132 - IACV base duty (4 bytes)
// Address: 0x6132-0x6135
// Table: tbl_6136 - Idle speed additional (16 bytes)
// Address: 0x6136-0x6145
// Table: tbl_6146 - VTEC engage RPM (12 bytes)
// Address: 0x6146-0x6151
// Table: tbl_6152 - VTEC disengage RPM (12 bytes)
// Address: 0x6152-0x615D
// Table: tbl_615E - VTEC min speed (12 bytes)
// Address: 0x615E-0x6169
// Table: tbl_616A - Rev limiter (12 bytes)
// Address: 0x616A-0x6175
// Table: tbl_6176 - Launch control (12 bytes)
// Address: 0x6176-0x6181
// Table: tbl_6182 - Knock retard (14 bytes)
// Address: 0x6182-0x618F
// Table: tbl_6190 - Injector dead time (14 bytes)
// Address: 0x6190-0x619D
// Table: tbl_619E - Dwell time (14 bytes)
// Address: 0x619E-0x61AB
// Table: tbl_61AC - Timing connector trim (14 bytes)
// Address: 0x61AC-0x61B9
// Table: tbl_6CD2 - CEL code map (24 bytes)
// Address: 0x6CD2-0x6CE9
// Maps error bits to CEL code numbers
// Table: tbl_6CEA - CEL timing (12 bytes)
// Address: 0x6CEA-0x6CF5
// Timing parameters for CEL blink patterns
// Main Fuel Map (Non-VTEC): 0x6800-0x68FF
// 10 RPM rows x 20 MAP columns = 200 words (400 bytes)
// Main Fuel Map (VTEC): 0x6900-0x69FF
// 10 RPM rows x 20 MAP columns = 200 words (400 bytes)
// Ignition Map (Non-VTEC): 0x6A80-0x6AFF
// 10 RPM rows x 20 MAP columns = 200 bytes
// Ignition Map (VTEC): 0x6B00-0x6B7F
// 10 RPM rows x 20 MAP columns = 200 bytes
// Serial Address Table: 0x6B56-0x6BFF
// Addresses for serial read commands
// Diagnostic Parameters: 0x6D08-0x6D1F
// RPM breakpoints for diagnostic calculations
/*============================================================================
* END OF PSEUDO-C CONVERSION
*
* This document represents the Honda P30 OBD1 ECU firmware converted
* to readable pseudo-C format. The target processor is OKI M66207.
*
* Key differences from OBD0 (M66201/M37700):
* - Different timer architecture
* - Different interrupt vector layout
* - Different register addresses
* - VTEC logic included by default
* - Different serial protocol for diagnostics
*
* Original assembly: P30_203.asm (15,304 lines, 2,394 labels)
*
*============================================================================*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment