Skip to content

Instantly share code, notes, and snippets.

@VIRUXE
Last active November 26, 2025 22:18
Show Gist options
  • Select an option

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

Select an option

Save VIRUXE/c21a25a70c240a07f491ab4b174246de to your computer and use it in GitHub Desktop.
/**
* ============================================================================
* HONDA OBD0 PW0 ECU FIRMWARE - PSEUDO-C CONVERSION (OKI 66201)
* ============================================================================
*
* Original File: EuroPw0Datalogging.asm (7079 lines)
* Target MCU: OKI MSM66201 (16-bit CMOS Microcontroller)
* ECU Type: Honda PW0 (European D16A9/ZC DOHC VTEC)
*
* This is a FULL line-by-line pseudo-C representation of the OBD0 ECU
* firmware with meaningful names for all registers, variables, and functions.
*
* NOTE: This is NOT compilable C code. It's a documentation format to
* understand the assembly logic in a more readable way.
*
* ============================================================================
* OKI MSM66201 MICROCONTROLLER SPECIFICATIONS
* ============================================================================
*
* - Architecture: 16-bit CMOS microcontroller
* - Crystal: 7.9 MHz (used in Honda ECU)
* - Timer Prescaler: CLK/32 for main timers
* - Internal RAM: 256 bytes (0x80-0xFF direct page)
* - External RAM: 512 bytes (0x100-0x2FF)
* - ROM: 32KB (0x0000-0x7FFF)
*
* RPM Calculation:
* RPM_Coef = 7,900,000 / 32 / 8 * 60 = 1,851,562.5
* Where:
* 7,900,000 = crystal frequency
* 32 = timer prescaler (CLK/32)
* 8 = 16 teeth on distributor / 2 (8 per crank revolution)
* 60 = seconds to minutes conversion
*
* RPM = RPM_Coef / timer_count
*
* ============================================================================
* MODIFICATIONS FROM STOCK (Datalogging Version)
* ============================================================================
*
* 1. Serial port configured for 9600 baud datalogging
* 2. Stack relocated to 0x025B for logging buffer space
* 3. Fuel/ignition row indices stored for logging (storerow)
* 4. Logging table at 0x7F10 defines RAM addresses to transmit
* 5. Serial RX handler sends RAM values back to tuning software
*
* ============================================================================
* AUTHORS AND CONTRIBUTORS
* ============================================================================
*
* Original Disassembly: Ben Ogle
* Contributors: Mr X, Nico, Malte, Anton, Ximon, Tinker_Tim
* Pseudo-C Conversion: Auto-generated documentation
*
* ============================================================================
*/
#include <stdint.h>
#include <stdbool.h>
/*============================================================================
* SECTION 1: OKI 66201 INSTRUCTION SET REFERENCE
* ============================================================================
*
* Common OKI 66201 instructions used in this firmware:
*
* Data Movement:
* L/LB - Load word/byte into accumulator
* ST/STB - Store word/byte from accumulator
* MOV/MOVB - Move between registers/memory
* PUSHS - Push to system stack
* POPS - Pop from system stack
* PUSHU - Push to user stack
* POPU - Pop from user stack
* XCHG - Exchange accumulator with memory
*
* Arithmetic:
* ADD/ADDB - Add word/byte
* SUB/SUBB - Subtract word/byte
* MUL/MULB - Multiply (unsigned)
* DIV/DIVB - Divide (unsigned)
* INC/INCB - Increment
* DEC/DECB - Decrement
* CMP/CMPB - Compare
*
* Logic:
* AND/ANDB - Logical AND
* OR/ORB - Logical OR
* XOR/XORB - Logical XOR
* SLL/SLLB - Shift left logical
* SRL/SRLB - Shift right logical
* ROL/ROLB - Rotate left through carry
* ROR/RORB - Rotate right through carry
*
* Bit Operations:
* SB - Set bit
* RB - Reset (clear) bit
* MB - Move bit to/from carry
* JBS - Jump if bit set
* JBR - Jump if bit reset
*
* Branching:
* J - Unconditional jump
* JEQ - Jump if equal (Z=1)
* JNE - Jump if not equal (Z=0)
* JLT - Jump if less than (N=1)
* JGE - Jump if greater or equal (N=0)
* JLE - Jump if less or equal
* CAL - Call subroutine
* SCAL - Short call subroutine
* RT - Return from subroutine
* RTI - Return from interrupt
* VCAL - Vector call (table-based)
*
* Special:
* EXTND - Sign extend byte to word
* SWAP - Swap high/low bytes
* CLR - Clear register/memory
* NOP - No operation
* BRK - Software break
*
*============================================================================*/
/*============================================================================
* SECTION 2: OKI 66201 HARDWARE REGISTER DEFINITIONS
* ============================================================================
*
* These are the hardware registers at fixed addresses in the OKI 66201.
* Register names match the official OKI documentation.
*
*============================================================================*/
/* ========== CPU CORE REGISTERS ========== */
/* These occupy addresses 0x00-0x0F in the direct page */
#define REG_PSW (*(volatile uint16_t*)0x0004) /* Processor Status Word (16-bit) */
#define REG_PSWL (*(volatile uint8_t*)0x0004) /* PSW Low byte (flags: Z,N,C,V) */
#define REG_PSWH (*(volatile uint8_t*)0x0005) /* PSW High byte (interrupt enable) */
/*
* PSWH bit definitions:
* Bit 0: DD (Data page Direct) - when set, allows 16-bit direct addressing
* Bit 1-3: Reserved
* Bit 4: Bank select for user stack
* Bit 5-7: Interrupt priority level
*/
#define REG_ACC (*(volatile uint16_t*)0x0006) /* Accumulator (16-bit A register) */
#define REG_ACCL (*(volatile uint8_t*)0x0006) /* Accumulator Low byte */
#define REG_ACCH (*(volatile uint8_t*)0x0007) /* Accumulator High byte */
#define REG_LRB (*(volatile uint8_t*)0x0008) /* Local Register Bank pointer */
/*
* LRB selects which 8-byte register bank (r0-r7) is active.
* Common values in this firmware:
* 0x00 = Bank 0 (default)
* 0x10 = Bank 1 (0x080)
* 0x20 = Bank 2 (0x100)
* 0x21 = Bank 2+1 (0x108)
* 0x22 = Bank 2+2 (0x110)
* 0x40 = Bank 4 (0x200)
*/
#define REG_DP (*(volatile uint16_t*)0x000A) /* Data Pointer (16-bit index) */
#define REG_DPL (*(volatile uint8_t*)0x000A) /* DP Low byte */
#define REG_DPH (*(volatile uint8_t*)0x000B) /* DP High byte */
#define REG_USP (*(volatile uint16_t*)0x000C) /* User Stack Pointer */
#define REG_SSP (*(volatile uint16_t*)0x000E) /* System Stack Pointer */
/* ========== SYSTEM CONTROL REGISTERS ========== */
#define REG_SBYCON (*(volatile uint8_t*)0x0010) /* Standby Control */
/*
* SBYCON bit definitions:
* Bit 0: STOP mode enable
* Bit 1: HALT mode enable
* Bit 2: Standby mode enable
*/
#define REG_WDT (*(volatile uint8_t*)0x0011) /* Watchdog Timer */
/* Write 0x3C to reset watchdog, prevents system reset */
#define REG_PRPHF (*(volatile uint8_t*)0x0012) /* Peripheral Control Flag */
#define REG_STPACP (*(volatile uint8_t*)0x0013) /* Stop/Accept control */
/* Used in power-down sequencing */
/* ========== INTERRUPT CONTROL REGISTERS ========== */
#define REG_IRQ (*(volatile uint8_t*)0x0018) /* Interrupt Request flags (low) */
/*
* IRQ bit definitions:
* Bit 0: INT0 (external interrupt 0 - CKP signal)
* Bit 1: Serial RX
* Bit 2: Serial TX
* Bit 3: Serial RX BRG
* Bit 4: Timer 0 overflow
* Bit 5: Timer 0 compare
* Bit 6: Timer 1 overflow
* Bit 7: Timer 1 compare
*/
#define REG_IRQH (*(volatile uint8_t*)0x0019) /* Interrupt Request flags (high) */
/*
* IRQH bit definitions:
* Bit 0: Timer 2 overflow
* Bit 1: Timer 2 compare
* Bit 2: Timer 3 overflow
* Bit 3: Timer 3 compare
* Bit 4: A/D conversion complete
* Bit 5: PWM timer
* Bit 6: Serial TX BRG
* Bit 7: INT1 (external interrupt 1 - CYP/TDC signal)
*/
#define REG_IE (*(volatile uint16_t*)0x001A) /* Interrupt Enable (16-bit) */
#define REG_IEL (*(volatile uint8_t*)0x001A) /* IE Low byte */
#define REG_IEH (*(volatile uint8_t*)0x001B) /* IE High byte */
/* Bits correspond to IRQ/IRQH - set bit to enable interrupt */
#define REG_EXION (*(volatile uint8_t*)0x001C) /* External I/O Enable */
/* ========== PORT REGISTERS (I/O PINS) ========== */
/* Each port has: Data, Direction (IO), and Special Function (SF) registers */
/* --- Port 0 (General Purpose + CEL light) --- */
#define REG_P0 (*(volatile uint8_t*)0x0020) /* Port 0 Data */
#define REG_P0IO (*(volatile uint8_t*)0x0021) /* Port 0 Direction (1=output) */
/*
* P0 bit assignments:
* P0.3: Purge control solenoid output
* P0.6: CEL dashboard light output (0=on, 1=off)
* P0.7: A/C clutch relay output
*/
/* --- Port 1 (VTEC + CEL LED) --- */
#define REG_P1 (*(volatile uint8_t*)0x0022) /* Port 1 Data */
#define REG_P1IO (*(volatile uint8_t*)0x0023) /* Port 1 Direction */
/*
* P1 bit assignments:
* P1.0: VTEC error indicator (1 if code 3 error)
* P1.1: VTEC solenoid output (1=engaged)
* P1.2: CEL LED on ECU case output
*/
/* --- Port 2 (Fuel Injectors) --- */
#define REG_P2 (*(volatile uint8_t*)0x0024) /* Port 2 Data */
#define REG_P2IO (*(volatile uint8_t*)0x0025) /* Port 2 Direction */
#define REG_P2SF (*(volatile uint8_t*)0x0026) /* Port 2 Special Function */
/*
* P2 bit assignments:
* P2.0: Injector 1 driver (0=open, 1=closed)
* P2.1: Injector 2 driver
* P2.2: Injector 3 driver
* P2.3: Injector 4 driver
* P2.4: Limp mode indicator (1=limp mode active)
*/
/* --- Port 3 (Timer I/O + Ignition) --- */
#define REG_P3 (*(volatile uint8_t*)0x0028) /* Port 3 Data */
#define REG_P3IO (*(volatile uint8_t*)0x0029) /* Port 3 Direction */
#define REG_P3SF (*(volatile uint8_t*)0x002A) /* Port 3 Special Function */
/*
* P3 bit assignments:
* P3.6: Timer 0 output (TM0IO) - Ignitor coil driver
*/
/* --- Port 4 (Power sense + External interfaces) --- */
#define REG_P4 (*(volatile uint8_t*)0x002C) /* Port 4 Data */
#define REG_P4IO (*(volatile uint8_t*)0x002D) /* Port 4 Direction */
#define REG_P4SF (*(volatile uint8_t*)0x002E) /* Port 4 Special Function */
/*
* P4 bit assignments:
* P4.1: Main power detect input (1=power OK)
*/
/* --- Port 5 (Miscellaneous inputs) --- */
#define REG_P5 (*(volatile uint8_t*)0x0030) /* Port 5 Data */
/*
* P5 bit assignments:
* P5.1: Rear window de-mister input
*/
/* ========== TIMER REGISTERS ========== */
/* OKI 66201 has 4 16-bit timers (Timer 0-3) */
/* --- Timer 0 (Injector timing / Ignition output) --- */
#define REG_TM0 (*(volatile uint16_t*)0x0030) /* Timer 0 Counter */
#define REG_TMR0 (*(volatile uint16_t*)0x0032) /* Timer 0 Reload/Compare */
/* --- Timer 1 (Main timing / RPM measurement) --- */
#define REG_TM1 (*(volatile uint16_t*)0x0034) /* Timer 1 Counter */
#define REG_TMR1 (*(volatile uint16_t*)0x0036) /* Timer 1 Reload/Compare */
/* --- Timer 2 (Ignition timing) --- */
#define REG_TM2 (*(volatile uint16_t*)0x0038) /* Timer 2 Counter */
#define REG_TMR2 (*(volatile uint16_t*)0x003A) /* Timer 2 Reload/Compare */
/* --- Timer 3 (Auxiliary) --- */
#define REG_TM3 (*(volatile uint16_t*)0x003C) /* Timer 3 Counter */
#define REG_TMR3 (*(volatile uint16_t*)0x003E) /* Timer 3 Reload/Compare */
/* --- Timer Control Registers --- */
#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 */
#define REG_TCON3 (*(volatile uint8_t*)0x0043) /* Timer 3 Control */
/*
* TCONx bit definitions:
* Bit 0-2: Clock source select (CLK/1, CLK/4, CLK/16, CLK/32, etc.)
* Bit 3: Output mode
* Bit 4: Timer enable
* Bit 5: Count direction
* Bit 6: Capture/Compare select
* Bit 7: Output polarity
*
* TCON2 special bits for ignition:
* Bit 2: TM0IO output state (ignitor driver)
* Bit 3: TM0IO primer - loaded into bit 2 on compare match
*/
#define REG_TRNSIT (*(volatile uint8_t*)0x0046) /* Timer Transit register */
/*
* TRNSIT.0: Timer transit flag, used in RPM overflow detection
*/
/* ========== SERIAL COMMUNICATION REGISTERS ========== */
/* Used for datalogging communication with tuning software */
/* --- Serial TX (Transmit) --- */
#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 Timer Control */
#define REG_STCON (*(volatile uint8_t*)0x0050) /* Serial TX Control */
#define REG_STBUF (*(volatile uint8_t*)0x0051) /* Serial TX Buffer */
/* --- Serial RX (Receive) --- */
#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_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 */
/*
* SRSTAT bit definitions:
* Bit 2: Framing error
* Bit 3: Overrun error
*/
/* ========== A/D CONVERTER REGISTERS ========== */
/* 8-channel 10-bit ADC for sensor readings */
#define REG_ADSCAN (*(volatile uint8_t*)0x0058) /* ADC Scan Control */
#define REG_ADSEL (*(volatile uint8_t*)0x0059) /* ADC Channel Select */
/* ADC Result Registers (10-bit values, right-aligned in 16-bit register) */
#define REG_ADCR0 (*(volatile uint16_t*)0x0060) /* ADC Ch0 - Multiplexed (ECT/IAT via IC6) */
#define REG_ADCR0H (*(volatile uint8_t*)0x0061) /* ADC Ch0 High byte */
#define REG_ADCR1 (*(volatile uint16_t*)0x0062) /* ADC Ch1 - Window de-mister (B17) */
#define REG_ADCR1H (*(volatile uint8_t*)0x0063) /* ADC Ch1 High byte */
#define REG_ADCR2 (*(volatile uint16_t*)0x0064) /* ADC Ch2 - O2 Sensor Secondary (Lambda 2) */
#define REG_ADCR2H (*(volatile uint8_t*)0x0065) /* ADC Ch2 High byte */
#define REG_ADCR3 (*(volatile uint16_t*)0x0066) /* ADC Ch3 - O2 Sensor Primary (Lambda 1) */
#define REG_ADCR3H (*(volatile uint8_t*)0x0067) /* ADC Ch3 High byte */
#define REG_ADCR4 (*(volatile uint16_t*)0x0068) /* ADC Ch4 - PA Sensor (Atmospheric) */
#define REG_ADCR4H (*(volatile uint8_t*)0x0069) /* ADC Ch4 High byte */
#define REG_ADCR5 (*(volatile uint16_t*)0x006A) /* ADC Ch5 - MAP Sensor (Manifold Pressure) */
#define REG_ADCR5H (*(volatile uint8_t*)0x006B) /* ADC Ch5 High byte */
#define REG_ADCR6 (*(volatile uint16_t*)0x006C) /* ADC Ch6 - Alternator / Battery */
#define REG_ADCR6H (*(volatile uint8_t*)0x006D) /* ADC Ch6 High byte */
#define REG_ADCR7 (*(volatile uint16_t*)0x006E) /* ADC Ch7 - TPS (Throttle Position) */
#define REG_ADCR7H (*(volatile uint8_t*)0x006F) /* ADC Ch7 High byte */
/* ========== PWM REGISTERS ========== */
/* Pulse Width Modulation for IACV (Idle Air Control Valve) */
#define REG_PWMC0 (*(volatile uint16_t*)0x0070) /* PWM 0 Counter */
#define REG_PWMR0 (*(volatile uint16_t*)0x0072) /* PWM 0 Reload (IACV duty cycle) */
#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 3: ECU RAM VARIABLES - MEMORY MAP
* ============================================================================
*
* Working RAM variables used by the ECU firmware.
* OKI 66201 memory layout:
* 0x0080 - 0x00FF: Direct page RAM (256 bytes, fast access via r0-r7)
* 0x0100 - 0x027F: Extended RAM (flags, buffers, calculations)
*
* Variable naming convention:
* g_xxx = global variable
* f_xxx = flag byte/word
* c_xxx = counter/timer
* t_xxx = temporary/scratch
*
* Documentation source: pw0ram.txt by Ben Ogle et al.
*
*============================================================================*/
/* ====================== SENSOR READINGS (0x98-0xBF) ====================== */
/* --- Temperature Sensors (via analog multiplexer IC6) --- */
#define g_coolantTemp (*(volatile uint8_t*)0x0098) /* ECT: Engine Coolant Temperature */
/* Lower value = colder, Higher value = hotter. Raw ADC from multiplexed ADCR0 */
#define g_intakeAirTemp (*(volatile uint8_t*)0x0099) /* IAT: Intake Air Temperature */
/* Lower value = colder air, Higher = hotter. Raw ADC from multiplexed ADCR0 */
/* --- Voltage/Power Sensors --- */
#define g_batteryVoltage (*(volatile uint8_t*)0x009A) /* 12V Battery voltage (scaled) */
#define g_ecuVoltage5V (*(volatile uint8_t*)0x009B) /* 5V ECU internal reference */
#define g_groundReference (*(volatile uint8_t*)0x009C) /* Ground reference (should be ~0) */
/* --- Switch Inputs --- */
#define g_timingAdjustConn (*(volatile uint8_t*)0x009D) /* Timing adjust connector (pin B20) */
#define g_brakeSwitch (*(volatile uint8_t*)0x009E) /* Brake switch input (pin B9) */
#define g_inputB18 (*(volatile uint8_t*)0x009F) /* Unknown input B18 */
/* --- Oxygen Sensors --- */
#define g_o2Sensor1_raw (*(volatile uint8_t*)0x00A1) /* Primary O2 sensor (Lambda 1) */
/* Value 0-50 decimal: < 0x1F = lean, > 0x1F = rich */
#define g_o2Sensor2_raw (*(volatile uint8_t*)0x00A2) /* Secondary O2 sensor (Lambda 2) */
/* Value 0-50 decimal: < 0x1F = lean, > 0x1F = rich */
/* --- Processed Temperature --- */
#define g_tempProcessed (*(volatile uint8_t*)0x00A3) /* Processed temperature value */
#define g_iatProcessed (*(volatile uint8_t*)0x00A4) /* Processed IAT for lookups */
/* --- Alternator --- */
#define g_alternatorVolts (*(volatile uint8_t*)0x00A5) /* Alternator voltage (from ADCR6H) */
/* --- RPM Values (1-byte indices for table lookup) --- */
#define g_rpmIndexNonVtec (*(volatile uint8_t*)0x00A6) /* RPM row index for non-VTEC maps */
#define g_rpmIndexVtec (*(volatile uint8_t*)0x00A7) /* RPM row index for VTEC maps */
/* --- Atmospheric/Barometric Pressure --- */
#define g_atmPressure (*(volatile uint16_t*)0x00A8) /* Atmospheric pressure (PA sensor) */
#define g_ambientPressure (*(volatile uint8_t*)0x00A9) /* Ambient pressure (inside ECU) */
/* --- Throttle Position Sensor (TPS) --- */
#define g_tpsRaw (*(volatile uint16_t*)0x00AA) /* Raw TPS from ADCR7 (16-bit) */
#define g_tpsValue (*(volatile uint8_t*)0x00AB) /* TPS value 0-255 (with idle offset) */
#define g_tpsDelta (*(volatile uint8_t*)0x00AC) /* TPS rate of change (calculated) */
#define g_tpsDeltaOld (*(volatile uint8_t*)0x00AD) /* Previous TPS delta */
#define g_tpsCopy (*(volatile uint8_t*)0x00AE) /* TPS copy (same as AB) */
#define g_tpsRelated (*(volatile uint8_t*)0x00AF) /* TPS-related calculation */
/* --- MAP Sensor (Manifold Absolute Pressure) --- */
#define g_mapSensorRaw (*(volatile uint16_t*)0x00B0) /* Raw MAP from ADCR5 (16-bit) */
#define g_mapSensorHigh (*(volatile uint8_t*)0x00B1) /* MAP sensor high byte */
#define g_mapFiltered (*(volatile uint16_t*)0x00B2) /* Filtered MAP (follows B4 slowly) */
#define g_mapFilteredHigh (*(volatile uint8_t*)0x00B3) /* Filtered MAP high byte */
#define g_mapImageRaw (*(volatile uint8_t*)0x00B4) /* MAP image 0-DF before delta adjust */
/*
* MAP Image format:
* High nibble (4 bits): Column index in fuel/ignition maps
* Low nibble (4 bits): Interpolation value (0=use column, F=use column+1)
*/
#define g_mapImageFinal (*(volatile uint8_t*)0x00B5) /* MAP image after delta adjustment */
#define g_mapInitialHigh (*(volatile uint8_t*)0x00B6) /* Initial MAP high (for code 5 check) */
#define g_mapDeltaCalc (*(volatile uint8_t*)0x00B7) /* Calculated from B4 in delta_map */
/* --- RPM Measurement --- */
#define g_rpmTimerDelta (*(volatile uint16_t*)0x00B8) /* Timer1 delta (current - previous) */
#define g_rpmTimerDeltaHi (*(volatile uint8_t*)0x00B9) /* Delta high byte */
#define g_rpmTimerCount (*(volatile uint16_t*)0x00BA) /* Current RPM timer count */
/*
* RPM = 1,851,562.5 / g_rpmTimerCount
* This is the timer ticks for 45° of crank rotation
*/
#define g_rpmTimerCountHi (*(volatile uint8_t*)0x00BB) /* RPM timer high byte */
#define g_rpmAccelDecel (*(volatile uint16_t*)0x00BC) /* RPM change rate (accel/decel) */
/* Calculated from BA, positive = accelerating, f_accelFlags.4 = 1 if accel */
#define g_rpmAverage (*(volatile uint16_t*)0x00BE) /* Average of last 4 RPM samples */
#define g_rpmAverageHi (*(volatile uint8_t*)0x00BF) /* Average high byte */
/* ====================== TIMING & RPM BUFFERS (0xC0-0xCF) ====================== */
#define g_rpmSmoothed (*(volatile uint16_t*)0x00C0) /* Asymptotic smoothed RPM */
/*
* Follows g_rpmAverage asymptotically:
* C0 = (C0 - C0*er0/10000h) + (A*er0/10000h) where er0 = 0x3000 or 0xD000
*/
#define g_rpmSmoothedHi (*(volatile uint8_t*)0x00C1) /* Smoothed high byte */
#define g_idleRpmError (*(volatile uint16_t*)0x00C2) /* |current RPM - target idle| */
#define g_idleRpmErrorHi (*(volatile uint8_t*)0x00C3) /* Error high byte */
#define g_vehicleSpeedWord (*(volatile uint16_t*)0x00C4) /* Vehicle speed (16-bit) */
#define g_vehicleSpeedHi (*(volatile uint8_t*)0x00C5) /* Speed high byte */
#define g_timer1Previous (*(volatile uint16_t*)0x00C6) /* Previous Timer1 capture */
#define g_timer1Capture (*(volatile uint16_t*)0x00C8) /* Timer1 value at INT0 (CKP) */
#define g_timerOverflowOld (*(volatile uint8_t*)0x00CA) /* Previous overflow indicator */
#define g_vehicleSpeedByte (*(volatile uint8_t*)0x00CB) /* Vehicle speed (8-bit) */
/* --- Interrupt Enable Storage --- */
#define g_ieNormal (*(volatile uint16_t*)0x00CC) /* IE value during normal operation */
#define g_ieNormalHi (*(volatile uint8_t*)0x00CD) /* IE normal high byte */
#define g_ieInterrupt (*(volatile uint16_t*)0x00CE) /* IE value inside interrupts */
#define g_ieInterruptHi (*(volatile uint8_t*)0x00CF) /* IE interrupt high byte */
/* ====================== INJECTOR CALCULATIONS (0xD0-0xDF) ====================== */
#define g_injectorCalc0 (*(volatile uint16_t*)0x00D0) /* Injector timing calculation 0 */
#define g_injectorCalc1 (*(volatile uint16_t*)0x00D2) /* Injector timing calculation 1 */
#define g_injectorCalc2 (*(volatile uint16_t*)0x00D4) /* Injector timing calculation 2 */
#define g_finalFuelPulse (*(volatile uint16_t*)0x00D6) /* FINAL fuel pulse width! */
/*
* This is the actual injector open time!
* Formula: D6 = (0x144 * (0x162 or 0x164) / 0x10000) * 2 + 0x146
* Where:
* 0x144 = main fuel from map
* 0x162/0x164 = O2 correction (primary/secondary)
* 0x146 = all other fuel corrections
*/
#define g_finalFuelHi (*(volatile uint8_t*)0x00D7) /* Final fuel high byte */
#define g_ignitorTiming0 (*(volatile uint16_t*)0x00D8) /* Ignitor firing timing 0 */
#define g_ignitorTiming1 (*(volatile uint16_t*)0x00DA) /* Ignitor firing timing 1 */
#define g_ignitorTiming2 (*(volatile uint16_t*)0x00DC) /* Ignitor firing timing 2 */
#define g_ignitorTiming3 (*(volatile uint16_t*)0x00DE) /* Ignitor firing timing 3 */
#define g_ignitorCounter (*(volatile uint8_t*)0x00DF) /* Ignitor sequence counter */
/* ====================== ENGINE POSITION (0xE0-0xEF) ====================== */
#define g_timer1Old (*(volatile uint16_t*)0x00E0) /* Previous Timer1 for 45° calc */
#define g_timer1Overflow (*(volatile uint8_t*)0x00E2) /* Timer1 overflow indicator (VSS) */
#define g_tdcPosition (*(volatile uint8_t*)0x00E3) /* TDC-related position */
#define g_crankPosition (*(volatile uint8_t*)0x00E4) /* Crank position 0-3 (45° each) */
#define g_cylinderIndex (*(volatile uint8_t*)0x00E5) /* Current cylinder (firing order) */
/*
* Cylinder mapping: 0=Cyl1, 1=Cyl3, 2=Cyl4, 3=Cyl2 (firing order)
*/
#define g_unused_E6 (*(volatile uint8_t*)0x00E6) /* Unused/unknown */
#define g_unused_E7 (*(volatile uint8_t*)0x00E7) /* Unused/unknown */
#define g_celCodeCounter (*(volatile uint8_t*)0x00E8) /* CEL code iteration counter */
#define g_unused_E9 (*(volatile uint8_t*)0x00E9) /* Unused/unknown */
#define g_unused_EA (*(volatile uint8_t*)0x00EA) /* Unused/unknown */
#define g_lifeCounter (*(volatile uint8_t*)0x00EB) /* Reboot life counter */
/*
* Starts at 0x20, decremented periodically.
* When reaches 0, MCU reboots! (watchdog-like functionality)
*/
#define g_unused_EC (*(volatile uint8_t*)0x00EC) /* Unused/unknown */
#define g_errorCodeReboot (*(volatile uint8_t*)0x00ED) /* Error code after reboot */
/*
* Error codes stored here on abnormal reset:
* 0x47 = NMI (Non-Maskable Interrupt / power fail)
* 0x44 = WDT (Watchdog Timer reset)
* 0x42 = System error
* 0x48 = Checksum error
* 0x49 = Life counter reached 0
* 0x4A = ADC error
* 0x4C, 0x4D = Unknown errors
*/
#define g_unused_EE (*(volatile uint8_t*)0x00EE) /* Temp/scratch for VCAL */
/* ====================== SPECIAL REGISTERS (0xF0-0xFF) ====================== */
#define g_rebootErrorCode (*(volatile uint8_t*)0x00F0) /* Error code storage on reboot */
#define g_eldValue (*(volatile uint8_t*)0x00F1) /* ELD (Electrical Load Detector) */
#define g_eldRelated (*(volatile uint8_t*)0x00F2) /* ELD-related value */
#define g_eldCalc (*(volatile uint8_t*)0x00F3) /* ELD calculation */
#define g_accelEnrichTimer (*(volatile uint8_t*)0x00F4) /* Accel enrichment timer */
#define g_accelEnrichValue (*(volatile uint8_t*)0x00F5) /* Accel enrichment amount */
#define g_unused_F6 (*(volatile uint8_t*)0x00F6) /* Unused */
#define g_unused_F7 (*(volatile uint8_t*)0x00F7) /* Unused */
#define g_oilPressure (*(volatile uint8_t*)0x00F8) /* Oil pressure switch value */
/* If > 0x32 there is enough oil pressure for VTEC */
#define g_unused_F9 (*(volatile uint8_t*)0x00F9) /* Unused */
#define g_eldRelated2 (*(volatile uint8_t*)0x00FA) /* ELD-related (JDM PW0 only) */
#define g_eldRelated3 (*(volatile uint8_t*)0x00FB) /* ELD-related */
#define g_celBlinkPattern (*(volatile uint8_t*)0x00FC) /* CEL blink pattern */
/*
* High nibble: number of slow blinks
* Low nibble: number of fast blinks
*/
/* --- Critical Flag Bytes --- */
#define f_flags_FD (*(volatile uint8_t*)0x00FD) /* Misc flags FD */
/*
* FD.3: Setting error bits flag (1 = currently setting 130h-132h)
* FD.5: Timer overflow flag
* FD.6: Power failure detected
*/
#define f_flags_FE (*(volatile uint8_t*)0x00FE) /* Processing/Status flags */
/*
* FE.0: Unknown flag
* FE.1: Serial RX BRG interrupt occurred
* FE.2: Unknown flag (reset in VCAL 4)
* FE.3: Unknown flag (reset in VCAL 4)
* FE.4: CEL blink requested
* FE.5: Unknown flag
* FE.6: LIMP MODE flag (bad ignition/CYP/TDC/CKP)
* FE.7: REV LIMITER active
*/
#define g_externalInputs (*(volatile uint8_t*)0x00FF) /* External inputs from IC @ 18FC */
/*
* FF.0: Knock sensor / Auto trans lockup
* FF.1: Unknown
* FF.2: VTEC solenoid feedback (verification)
* FF.3: Unknown
* FF.4: Unknown
* FF.5: Unknown
* FF.6: A/C switch input
* FF.7: Starter signal (cranking)
*/
/* ====================== EXTENDED RAM - FLAGS (0x100-0x12F) ====================== */
/* Note: Addresses 0x100-0x10F are often used as extended register banks */
#define f_flags_118 (*(volatile uint8_t*)0x0118) /* Engine state flags */
/*
* 118.0: CKP error flag (reset in Timer0 ISR)
* 118.1: Unknown
* 118.2: Unknown
* 118.3: VSS error OR speed > 105mph
* 118.4: Starter signal active (cranking)
* 118.5: Unknown
* 118.6: Low battery voltage (< 0x54)
* 118.7: Automatic transmission flag
*/
#define f_flags_119 (*(volatile uint8_t*)0x0119) /* Ignition state flags */
/*
* 119.0: Unknown
* 119.1: Ignition final = 0 at crank pos 3
* 119.2: Unknown
* 119.3: High MAP load (b4h > 0xB3 or 0xB8)
* 119.4: Unknown
* 119.5: Previous 119.3 state
* 119.6: Unknown
* 119.7: Unknown
*/
#define f_flags_11A (*(volatile uint8_t*)0x011A) /* Sensor/warmup flags */
/*
* 11A.0: First TDC code set
* 11A.1: First CYP code set
* 11A.2: Unknown
* 11A.3: Unknown
* 11A.4: Unknown
* 11A.5: Engine warming up (temp delta > 0x10)
* 11A.6: High MAP (b4h > 0xB9 or 0xC0)
* 11A.7: Idle timing connector active
*/
#define f_flags_11B (*(volatile uint8_t*)0x011B) /* O2 primary flags */
/* 11B.0: O2 related (primary sensor) */
#define f_flags_11C (*(volatile uint8_t*)0x011C) /* O2 secondary flags */
/* 11C.0: O2 related (secondary sensor) */
#define f_flags_11E (*(volatile uint8_t*)0x011E) /* RPM/VSS flags */
/*
* 11E.0: VSS code NOT set (0 = VSS error)
* 11E.1-3: Unknown
* 11E.4: Engine ACCELERATING (1) / decelerating (0)
* 11E.5: Rev count calculation OK (0 = OK)
* 11E.6: Unknown
* 11E.7: Unknown
*/
#define f_flags_11F (*(volatile uint8_t*)0x011F) /* Engine run state flags */
/*
* 11F.0: Key ON, engine OFF
* 11F.1: Unknown
* 11F.2: TPS increasing (old < new)
* 11F.3: Unknown
* 11F.4: Engine running detection
* 11F.5: TPS history (newest)
* 11F.6: TPS history (middle)
* 11F.7: TPS history (oldest)
*/
#define f_flags_120 (*(volatile uint8_t*)0x0120) /* RPM threshold flags */
/*
* 120.5: RPM > 0xC9 (high RPM)
* 120.6: RPM > 0x08 (engine running)
*/
#define f_flags_121 (*(volatile uint8_t*)0x0121) /* Ignition ready flags */
/*
* 121.1: TDC checking issue (e3h != 4)
* 121.2: CKP error persisted >= 6 cycles
* 121.3: Ignition fault (0 = ready, 1 = fault)
*/
#define f_flags_122 (*(volatile uint8_t*)0x0122) /* Engine state flags 2 */
/* 122.2: Car is running */
#define f_flags_123 (*(volatile uint8_t*)0x0123) /* TPS history flags */
/*
* 123.3: TPS increasing (newest)
* 123.4: TPS increasing (middle)
* 123.5: TPS increasing (oldest)
*/
#define f_flags_125 (*(volatile uint8_t*)0x0125) /* Idle control flags */
/*
* 125.0: Idle related
* 125.1: Idle related
* 125.2: RPM under target idle (bah < 172h)
*/
#define f_flags_126 (*(volatile uint8_t*)0x0126) /* Accessory flags */
/* 126.5: Rear window de-mister ON */
/* --- VTEC Control Byte --- */
#define f_vtecFlags (*(volatile uint8_t*)0x0129) /* VTEC status flags */
/*
* 129.0: Unknown
* 129.1: Unknown
* 129.2: Unknown
* 129.3: Speed > 0x20-0x28 (VSS threshold)
* 129.4: RPM > VTEC engage RPM threshold 1
* 129.5: RPM > VTEC engage RPM threshold 3
* 129.6: VTEC primed (all conditions met, no error)
* 129.7: VTEC IS ON!
*/
#define f_flags_12A (*(volatile uint8_t*)0x012A) /* Temp/AC flags */
/*
* 12A.0: Cold engine (< ~170°C), low speed, low RPM
* 12A.1: A/C is ON
* 12A.2: Unknown
* 12A.3: A/C is OFF (inverse of 12A.1?)
* 12A.4: Very high RPM (> 0xFE-0xFF)
*/
/* --- CEL Code Detection Bytes --- */
#define f_celDetect1 (*(volatile uint8_t*)0x012C) /* CEL detection byte 1 */
/*
* Bits set by sensor checks, used to set 130h-132h:
* 12C.0: Code 3 - MAP sensor
* 12C.1: Code 6 - ECT (coolant temp)
* 12C.2: Code 7 - TPS (throttle)
* 12C.3: Code 5 - MAP (mechanical failure)
* 12C.4: Code 13 - Barometric sensor
* 12C.5: Code 18 - Unknown
* 12C.6: Code 19 - Auto lockup
* 12C.7: Code 10 - IAT (intake air temp)
*/
#define f_celDetect2 (*(volatile uint8_t*)0x012D) /* CEL detection byte 2 */
/*
* 12D.0: Code 14 - IACV
* 12D.1: Code 8 - TDC sensor
* 12D.2: Code 17 - VSS (vehicle speed)
* 12D.3: Code 20 - ELD
* 12D.4: Code 23 - Knock sensor
* 12D.5: Code 24 - Unknown
* 12D.6: Code 21 - VTEC solenoid
* 12D.7: Code 22 - Oil pressure switch
*/
#define f_celDetect3 (*(volatile uint8_t*)0x012E) /* CEL detection byte 3 */
/*
* 12E.0: Code 4 - CKP (crankshaft)
* 12E.1: Code 8 - TDC
* 12E.2: Code 9 - CYP (camshaft)
* 12E.3: Code 15 - Ignition output
* 12E.4: Code 4 - CKP (duplicate)
* 12E.5: Code 8 - TDC (duplicate)
* 12E.6: Code 9 - CYP (duplicate)
* 12E.7: Code 16 - Fuel injector system
*/
/* --- Stored Fault Codes --- */
#define g_faultCode1 (*(volatile uint8_t*)0x0130) /* Stored faults: codes 1-8 */
#define g_faultCode2 (*(volatile uint8_t*)0x0131) /* Stored faults: codes 9-16 */
#define g_faultCode3 (*(volatile uint8_t*)0x0132) /* Stored faults: codes 17-24 */
/*
* Fault code bit structure (example for 130h):
* Bit 0 = Code 1
* Bit 1 = Code 2
* ...
* Bit 7 = Code 8
*/
/* ====================== IGNITION CALCULATIONS (0x133-0x13F) ====================== */
#define g_ignitionTemp (*(volatile uint8_t*)0x0133) /* Ignition temp correction */
#define g_ignitionFinal (*(volatile uint8_t*)0x0134) /* FINAL ignition advance! */
/* This is the actual timing value used */
#define g_ignitionVcalCalc (*(volatile uint8_t*)0x0135) /* VCAL timing calculation */
/* Formula: vcal0(a7h,0x38C9) * vcal(9Ah,0x38D7) * 2 * 2 / 0x100 */
/* Range: 0x0F to 0xB3 */
#define g_ignitionInverse (*(volatile uint8_t*)0x0136) /* 2's complement of 0x134 */
#define g_ignitionCorrect1 (*(volatile uint8_t*)0x0137) /* Ignition correction 1 (accel) */
#define g_ignitionMapRaw (*(volatile uint8_t*)0x0138) /* Raw value from ignition map */
#define g_ignitionBrake (*(volatile uint8_t*)0x0139) /* Brake switch timing correction */
#define g_ignitionEctTrim (*(volatile uint8_t*)0x013A) /* ECT ignition trim */
/* If ECT error, uses 0x13F instead */
#define g_ignitionIdleAdj (*(volatile uint8_t*)0x013B) /* Idle adjust connector timing */
/* Correction from ECU pin B20 (0 if not connected) */
#define g_ignitionCorrect2 (*(volatile uint8_t*)0x013C) /* Ignition correction 2 */
#define g_knockRetard (*(volatile uint8_t*)0x013D) /* Knock sensor retard amount */
#define g_ignitionCorrect3 (*(volatile uint8_t*)0x013E) /* Ignition correction 3 */
#define g_ignitionEctError (*(volatile uint8_t*)0x013F) /* ECT error trim (fallback) */
/* Essentially vcal_2(a3h, 0x3907), used when ECT has error */
/* ====================== FUEL CALCULATIONS (0x140-0x16F) ====================== */
#define g_fuelMapNonVtec (*(volatile uint16_t*)0x0140) /* Fuel from non-VTEC map */
#define g_fuelMapNonVtecHi (*(volatile uint8_t*)0x0141) /* High byte */
#define g_fuelMapVtec (*(volatile uint16_t*)0x0142) /* Fuel from VTEC map */
#define g_fuelMapVtecHi (*(volatile uint8_t*)0x0143) /* High byte */
#define g_fuelMainFinal (*(volatile uint16_t*)0x0144) /* Main fuel value (no O2) */
/*
* Formula: (0x140 or 0x142) * 0x15E / 0x10000 / 2
* This is the map-based fuel before O2 correction
*/
#define g_fuelMainFinalHi (*(volatile uint8_t*)0x0145) /* High byte */
#define g_fuelCorrections (*(volatile uint16_t*)0x0146) /* All fuel corrections */
/*
* Formula: (0x16A * (0x14A * 0x166 / 0x100) / 0x100) + 0x14C + 0x150 + 0x152 + 0x14E
* Includes: ECT, IAT, battery, TPS delta, A/C, etc.
*/
#define g_fuelCorrectionsHi (*(volatile uint8_t*)0x0147) /* High byte */
#define g_fuelWithCorrect (*(volatile uint16_t*)0x0148) /* Fuel + corrections (no O2, no AC) */
/* Formula: 0x144 + 0x146 - 0x14E */
#define g_fuelWithCorrectHi (*(volatile uint8_t*)0x0149) /* High byte */
#define g_fuelTpsDelta (*(volatile uint16_t*)0x014A) /* Delta TPS fuel enrichment */
#define g_fuelTpsDeltaHi (*(volatile uint8_t*)0x014B) /* High byte */
#define g_fuelBatteryTrim (*(volatile uint16_t*)0x014C) /* Battery voltage fuel trim */
/* VCAL_1 with vector at ROM 0x37E3 */
#define g_fuelBatteryHi (*(volatile uint8_t*)0x014D) /* High byte */
#define g_fuelAcTrim (*(volatile uint16_t*)0x014E) /* A/C compressor fuel trim */
#define g_fuelAcTrimHi (*(volatile uint8_t*)0x014F) /* High byte */
#define g_fuelTpsRelated (*(volatile uint16_t*)0x0150) /* TPS-related fuel trim */
#define g_fuelIdleAdjust (*(volatile uint16_t*)0x0152) /* Idle adjust connector fuel */
/* Fuel from ECU pin B20 (0 if not connected) */
#define g_fuelVoltageCorr (*(volatile uint16_t*)0x0158) /* Voltage-based fuel correction */
/* Uses vector at 0x37D7 in JDM PW0 */
#define g_fuelIatTrim (*(volatile uint16_t*)0x015A) /* IAT-based fuel trim */
#define g_fuelScaler (*(volatile uint16_t*)0x015E) /* Fuel scaling factor */
#define g_fuelUnused_160 (*(volatile uint16_t*)0x0160) /* Unused fuel value */
#define g_o2TrimPrimary (*(volatile uint16_t*)0x0162) /* Primary O2 fuel trim */
/* Applied to final fuel for closed-loop control */
#define g_o2TrimSecondary (*(volatile uint16_t*)0x0164) /* Secondary O2 fuel trim */
/* Used when secondary O2 sensor is active */
#define g_fuelTempTrim (*(volatile uint16_t*)0x0166) /* Temperature fuel trim */
/* Typical value: 0x340-0x400 */
#define g_fuelTempTrimHi (*(volatile uint8_t*)0x0167) /* High byte */
#define g_fuelMapImageTrim (*(volatile uint8_t*)0x0169) /* MAP image fuel trim */
/* Based on b4h, value between 0x51 and 0xDF */
#define g_fuelEctTrim (*(volatile uint16_t*)0x016A) /* ECT-based fuel trim */
/* Range: 0x00-0x100 */
#define g_fuelEctTrimHi (*(volatile uint8_t*)0x016B) /* High byte */
#define g_fuelEctTrim2 (*(volatile uint16_t*)0x016C) /* Another ECT fuel trim */
#define g_fuelEctTrim2Hi (*(volatile uint8_t*)0x016D) /* High byte */
#define g_openClosedLoop (*(volatile uint8_t*)0x016F) /* Open/closed loop selector */
/* Determines if O2 feedback is active */
/* ====================== IDLE CONTROL (0x170-0x19F) ====================== */
#define g_targetIdleRpm (*(volatile uint16_t*)0x0172) /* Target idle RPM (timer format) */
/* Same format as g_rpmTimerCount (0xBA) */
#define g_targetIdleHi (*(volatile uint8_t*)0x0173) /* Target idle high byte */
#define g_idleEctFactor (*(volatile uint8_t*)0x0176) /* ECT-based idle adjustment */
/* vcal_1(a3h, 0x39E1), used in IACV calculation */
#define g_idleTempFactor (*(volatile uint8_t*)0x0197) /* Temp-based idle factor */
/* vcal_0(a3h, 0x39BD) */
/* ====================== CEL BLINK COUNTERS (0x1AA-0x1DF) ====================== */
#define c_celBlinkIndex (*(volatile uint8_t*)0x01AA) /* CEL code blink index */
/* Incremented each pass through blink function */
/* --- CEL Code Error Counters --- */
/* These are decremented each time corresponding 12E bit is set */
#define c_celCkp1 (*(volatile uint8_t*)0x01B4) /* CKP counter (12E.0) */
#define c_celTdc1 (*(volatile uint8_t*)0x01B5) /* TDC counter (12E.1) */
#define c_celCyp1 (*(volatile uint8_t*)0x01B6) /* CYP counter (12E.2) */
#define c_celIgnOut (*(volatile uint8_t*)0x01B7) /* Ignition out (12E.3) */
#define c_celCkp2 (*(volatile uint8_t*)0x01B8) /* CKP counter 2 (12E.4) */
#define c_celTdc2 (*(volatile uint8_t*)0x01B9) /* TDC counter 2 (12E.5) */
#define c_celCyp2 (*(volatile uint8_t*)0x01BA) /* CYP counter 2 (12E.6) */
#define c_celFuelInj (*(volatile uint8_t*)0x01BB) /* Fuel injector (12E.7) */
#define c_vtecEngageTimer (*(volatile uint8_t*)0x01D5) /* VTEC engage timer */
/* Set to 0x14 when VTEC engages, cleared on disengage */
#define g_fuelRowIndex (*(volatile uint8_t*)0x01D8) /* Current fuel map row */
#define g_ignRowIndex (*(volatile uint8_t*)0x01D9) /* Current ignition map row */
#define c_celBlinkCounter (*(volatile uint8_t*)0x01DF) /* Current CEL blink counter */
/* ====================== MISC COUNTERS (0x1EA-0x1FF) ====================== */
#define c_misc_1EA (*(volatile uint8_t*)0x01EA) /* Misc counter */
#define c_acCounter (*(volatile uint8_t*)0x01EE) /* A/C routine counter */
#define c_acCounter2 (*(volatile uint8_t*)0x01EF) /* A/C routine counter 2 */
/* Counters 0x1CE-0x1FF are decremented in CEL blink routine */
/* ====================== IACV / INJECTOR CONTROL (0x200-0x21F) ====================== */
#define g_iacvDutyCycle (*(volatile uint16_t*)0x0202) /* IACV duty cycle */
/* Calculated in IACV routine, written to PWMR0 in PWM ISR */
#define g_iacvDutyCopy (*(volatile uint16_t*)0x0204) /* Copy of 0x202 */
/* --- RPM Sample Buffer (4 samples for averaging) --- */
#define g_rpmSample0 (*(volatile uint16_t*)0x0206) /* RPM sample 0 (newest) */
#define g_rpmSample1 (*(volatile uint16_t*)0x0208) /* RPM sample 1 */
#define g_rpmSample2 (*(volatile uint16_t*)0x020A) /* RPM sample 2 */
#define g_rpmSample3 (*(volatile uint16_t*)0x020C) /* RPM sample 3 (oldest) */
/* --- RPM History (older values for filtering) --- */
#define g_rpmHistory0 (*(volatile uint16_t*)0x020E) /* RPM history 0 (newest) */
#define g_rpmHistory1 (*(volatile uint16_t*)0x0210) /* RPM history 1 */
#define g_rpmHistory2 (*(volatile uint16_t*)0x0212) /* RPM history 2 (oldest) */
/* --- Injector Timing --- */
#define g_injTiming0 (*(volatile uint16_t*)0x0214) /* Injector timing buffer 0 */
#define g_injTiming1 (*(volatile uint16_t*)0x0216) /* Injector timing buffer 1 */
#define g_injTiming2 (*(volatile uint16_t*)0x0218) /* Injector timing buffer 2 */
#define g_injectorMask (*(volatile uint8_t*)0x021A) /* Injector select mask */
/*
* Bit pattern shifts with firing order:
* 0111_0111 = Cyl 1
* 1011_1011 = Cyl 3
* 1101_1101 = Cyl 4
* 1110_1110 = Cyl 2
*/
#define g_injectorMaskInv (*(volatile uint8_t*)0x021B) /* Inverse of 0x21A */
#define g_injectorOutput (*(volatile uint8_t*)0x021C) /* P2 injector output mask */
/* ANDed with P2 to control injectors. 0x0F = all off */
#define g_iacvControl (*(volatile uint8_t*)0x021D) /* IACV control flags */
/* ====================== O2 SENSOR BUFFERS (0x274-0x279) ====================== */
#define g_o2TrimOldPrimary (*(volatile uint16_t*)0x0274) /* Old primary O2 trim */
/* Follows 0x162 asymptotically like g_rpmSmoothed */
#define g_o2TrimOldSecondary (*(volatile uint16_t*)0x0276) /* Old secondary O2 trim */
/* Follows 0x164 asymptotically */
#define g_tpsOld (*(volatile uint8_t*)0x0278) /* Previous TPS value */
#define g_tempOld (*(volatile uint8_t*)0x0279) /* Previous temp value */
/* ====================== CEL LED BLINK CODES (0x27B-0x27D) ====================== */
#define g_celBlinkCode1 (*(volatile uint8_t*)0x027B) /* CEL LED blink: codes 1-8 */
#define g_celBlinkCode2 (*(volatile uint8_t*)0x027C) /* CEL LED blink: codes 9-16 */
#define g_celBlinkCode3 (*(volatile uint8_t*)0x027D) /* CEL LED blink: codes 17-24 */
/* Same structure as g_faultCode1-3 but for active blinking */
/*============================================================================
* SECTION 4: INTERRUPT VECTOR TABLE
* ============================================================================
*
* The OKI 66201 interrupt vector table starts at address 0x0000.
* Each vector is a 16-bit pointer to the interrupt service routine.
*
* Original assembly (0x0000-0x0037):
* org 0000h
* int_start_vec: DW int_start ; 0000 -> 0x1673
* int_break_vec: DW int_break ; 0002 -> 0x169A
* int_WDT_vec: DW int_WDT ; 0004 -> 0x1696
* ... etc
*
*============================================================================*/
/* --- Forward Declarations: Interrupt Service Routines --- */
void isr_systemReset(void); /* 0x1673: Power-on reset */
void isr_softwareBreak(void); /* 0x169A: BRK instruction */
void isr_watchdogTimeout(void); /* 0x1696: Watchdog timer reset */
void isr_nonMaskableInterrupt(void); /* 0x008F: NMI / power failure */
void isr_externalInt0_CKP(void); /* 0x151F: CKP crankshaft signal */
void isr_serialReceive(void); /* 0x0067: Serial RX (datalogging) */
void isr_serialRxBaudRate(void); /* 0x155D: Serial RX baud generator */
void isr_timer0Overflow(void); /* 0x1565: Timer0 overflow (injector) */
void isr_timer0Compare(void); /* 0x0137: Timer0 match (TDC event) */
void isr_timer1Overflow(void); /* 0x160C: Timer1 overflow (RPM) */
void isr_timer1Compare(void); /* 0x00CD: Timer1 match (ignition) */
void isr_timer2Compare(void); /* 0x00D1: Timer2 match */
void isr_pwmTimer(void); /* 0x1636: PWM timer (IACV) */
void isr_externalInt1_CYP(void); /* 0x00F2: CYP/TDC camshaft signal */
/* --- Forward Declarations: VCAL Table Lookup Functions --- */
uint8_t vcal_0_interpolate1D(uint8_t input, uint16_t tableAddr); /* 0x2BF9 */
uint8_t vcal_1_lookupInverted(uint8_t input, uint16_t tableAddr); /* 0x2C57 */
uint8_t vcal_2_clampedLookup(uint8_t input, uint16_t tableAddr); /* 0x2C33 */
uint8_t vcal_3_tripletLookup(uint8_t input, uint16_t tableAddr); /* 0x2C45 */
void vcal_4_mainProcessing(void); /* 0x189B */
uint16_t vcal_5_fuelMapLookup(void); /* 0x2D96 */
uint16_t vcal_6_ignMapLookup(void); /* 0x2EB2 */
uint16_t vcal_7_ignMapLookupVtec(void); /* 0x2EB4 */
/* --- Forward Declarations: Main Engine Functions --- */
void main_engineLoop(void);
void calc_rpmFromTimerCapture(void); /* label_0416 */
void calc_rpmAveraging(void); /* label_0436 */
void calc_mapSensorProcessing(void); /* label_04xx */
void calc_fuelFromMaps(void); /* label_08B3 */
void calc_ignitionFromMaps(void); /* label_07xx */
void calc_injectorPulseWidth(void); /* label_0270 */
void update_ignitorTiming(void); /* label_2911 */
void update_injectorOutputs(void); /* label_28ED */
void process_rpmSignal(void); /* label_2995 */
/* --- Forward Declarations: VTEC Control --- */
void check_vtecConditions(void); /* label_13xx */
void engage_vtecSolenoid(void);
void disengage_vtecSolenoid(void);
/* --- Forward Declarations: O2 Sensor Processing --- */
void process_o2Feedback(void); /* label_25xx */
void calc_o2FuelTrim(void);
/* --- Forward Declarations: Idle Control --- */
void calc_idleAirControl(void); /* label_1Axx */
void update_iacvDuty(void);
/* --- Forward Declarations: Error Code Handling --- */
void check_sensorErrors(void); /* label_2xxx */
void set_faultCode(uint8_t code); /* label_2F1B */
void blink_celLight(void); /* label_20xx */
void store_frozenFrame(void);
/* --- Forward Declarations: Utility Functions --- */
void handle_powerFailure(void); /* label_2ECC */
void check_lowVoltageShutdown(void); /* label_3223 */
void storerow_forLogging(void); /* Custom: store fuel/ign row */
/*
* INTERRUPT VECTOR TABLE (Address 0x0000-0x0037)
*
* In C pseudo-code, this would be an array of function pointers:
*/
typedef void (*isr_handler_t)(void);
const isr_handler_t INTERRUPT_VECTORS[] = {
/* 0x0000 */ isr_systemReset, /* Reset/Power-on */
/* 0x0002 */ isr_softwareBreak, /* BRK instruction */
/* 0x0004 */ isr_watchdogTimeout, /* WDT timeout */
/* 0x0006 */ isr_nonMaskableInterrupt, /* NMI (power fail) */
/* 0x0008 */ isr_externalInt0_CKP, /* INT0: Crankshaft position */
/* 0x000A */ isr_serialReceive, /* Serial RX complete */
/* 0x000C */ isr_softwareBreak, /* Serial TX complete (unused) */
/* 0x000E */ isr_serialRxBaudRate, /* Serial RX baud rate gen */
/* 0x0010 */ isr_timer0Overflow, /* Timer 0 overflow */
/* 0x0012 */ isr_timer0Compare, /* Timer 0 compare match */
/* 0x0014 */ isr_timer1Overflow, /* Timer 1 overflow */
/* 0x0016 */ isr_timer1Compare, /* Timer 1 compare match */
/* 0x0018 */ isr_softwareBreak, /* Timer 2 overflow (unused) */
/* 0x001A */ isr_timer2Compare, /* Timer 2 compare match */
/* 0x001C */ isr_softwareBreak, /* Timer 3 overflow (unused) */
/* 0x001E */ isr_softwareBreak, /* Timer 3 compare (unused) */
/* 0x0020 */ isr_softwareBreak, /* A/D complete (unused) */
/* 0x0022 */ isr_pwmTimer, /* PWM timer */
/* 0x0024 */ isr_softwareBreak, /* Serial TX baud (unused) */
/* 0x0026 */ isr_externalInt1_CYP, /* INT1: Camshaft position */
/* 0x0028 */ (isr_handler_t)vcal_0_interpolate1D, /* VCAL 0 */
/* 0x002A */ (isr_handler_t)vcal_1_lookupInverted, /* VCAL 1 */
/* 0x002C */ (isr_handler_t)vcal_2_clampedLookup, /* VCAL 2 */
/* 0x002E */ (isr_handler_t)vcal_3_tripletLookup, /* VCAL 3 */
/* 0x0030 */ (isr_handler_t)vcal_4_mainProcessing, /* VCAL 4 */
/* 0x0032 */ (isr_handler_t)vcal_5_fuelMapLookup, /* VCAL 5 */
/* 0x0034 */ (isr_handler_t)vcal_6_ignMapLookup, /* VCAL 6 */
/* 0x0036 */ (isr_handler_t)vcal_7_ignMapLookupVtec /* VCAL 7 */
};
/*
* Code between 0x0038-0x0066 is compressed/encoded data bytes:
* code_start: DB 008h,00Eh,00Eh,000h,0E5h,0CEh,0D5h,01Ah...
* This appears to be part of the serial receive handler or lookup tables.
*/
/*============================================================================
* SECTION 5: INTERRUPT SERVICE ROUTINES
* ============================================================================
*
* Full pseudo-C conversion of all interrupt handlers.
* Each includes the original assembly address in comments.
*
*============================================================================*/
/**
* isr_serialReceive() - Serial Data Receive Handler (Datalogging)
*
* Address: 0x0067 (label: _int_serial_rx)
*
* This is the heart of the datalogging system. When tuning software
* sends a byte (RAM address), this handler reads that RAM location
* and transmits the value back.
*
* MODIFIED from stock for datalogging support.
*/
void isr_serialReceive(void)
{
/* 0x0067: L A, 0CEh - Load interrupt IE value */
/* 0x0069: ST A, IE - Enable higher-priority interrupts */
REG_IE = g_ieInterrupt; /* Allow nested interrupts */
/* 0x006B: SB PSWH.0 - Set DD flag for 16-bit addressing */
REG_PSWH |= 0x01;
/* 0x006D: L A, DP - Save current DP */
/* 0x006E: PUSHS A - Push to system stack */
uint16_t savedDP = REG_DP; /* Save data pointer */
/* 0x006F: CLRB A - Clear accumulator (error flags) */
uint8_t errorFlags = 0;
/* 0x0070: RB SRSTAT.3 - Check overrun error, move to carry */
/* 0x0073: JEQ label_0077 - Skip if no overrun */
/* 0x0075: ADDB A, #001h - Add 1 to error flags if overrun */
if (REG_SRSTAT & 0x08) /* Bit 3: Overrun error */
errorFlags += 1;
/* label_0077: */
/* 0x0077: RB SRSTAT.2 - Check framing error */
/* 0x007A: JEQ label_007e */
/* 0x007C: ADDB A, #002h - Add 2 if framing error */
if (REG_SRSTAT & 0x04) /* Bit 2: Framing error */
errorFlags += 2;
/* label_007e: */
/* 0x007E: STB A, ACCH - Store error flags in high byte */
uint8_t addrHigh = errorFlags; /* High byte of address (with errors) */
/* 0x0080: LB A, SRBUF - Read received byte (RAM address) */
uint8_t addrLow = REG_SRBUF;
/* 0x0082: MOV DP, A - Use received byte as address */
/* 0x0083: LB A, [DP] - Read RAM at that address */
REG_DP = (addrHigh << 8) | addrLow;
uint8_t ramValue = *(volatile uint8_t*)REG_DP;
/* 0x0084: STB A, STBUF - Transmit RAM value back */
REG_STBUF = ramValue;
/* 0x0086: POPS A - Restore saved DP */
/* 0x0087: MOV DP, A */
REG_DP = savedDP;
/* 0x0088: L A, 0CCh - Load normal IE value */
/* 0x008A: RB PSWH.0 - Clear DD flag */
/* 0x008C: ST A, IE - Restore interrupt enables */
REG_PSWH &= ~0x01;
REG_IE = g_ieNormal;
/* 0x008E: RTI - Return from interrupt */
return;
}
/**
* isr_nonMaskableInterrupt() - NMI Handler (Power Failure)
*
* Address: 0x008F (label: int_NMI)
*
* Called when power is failing (main relay opening) or other
* non-maskable events. Attempts to save state and enter low-power mode.
*/
void isr_nonMaskableInterrupt(void)
{
/* 0x008F: MOV LRB, #00020h - Switch to register bank 2 (0x100) */
REG_LRB = 0x20;
/* 0x0092: J label_3223 - Jump to power failure handler */
check_lowVoltageShutdown(); /* Inline: checks voltage, may return */
/* label_0095: (return point from label_3223) */
/* 0x0095: JEQ label_009a - Skip power save if voltage OK */
if (/* voltage OK condition */ 0) {
goto skip_powerSave;
}
/* 0x0097: CAL label_2ecc - Call power failure routine */
handle_powerFailure();
skip_powerSave:
/* label_009a: */
/* 0x009A: MOV DP, #00036h - Set DP to timeout counter */
REG_DP = 0x0036; /* Counter value */
wait_forPowerStable:
/* label_009d: */
/* 0x009D: MB C, P4.1 - Check power pin */
/* 0x00A0: JGE label_00c8 - If power stable, exit wait */
if (REG_P4 & 0x02) { /* P4.1 = main power detect */
goto power_recovered;
}
/* 0x00A2: JRNZ DP, label_009d - Loop until timeout */
REG_DP--;
if (REG_DP != 0)
goto wait_forPowerStable;
/* Power failed - enter standby mode */
/* 0x00A4: MOV IE, #00040h - Disable most interrupts */
REG_IE = 0x0040;
/* 0x00A9: MOVB TCON1, #0E0h - Configure timer for standby */
REG_TCON1 = 0xE0;
/* 0x00AD: CLR IRQ - Clear pending interrupts */
REG_IRQ = 0x00;
/* 0x00B0: SB P4SF.1 - Set P4 special function */
REG_P4SF |= 0x02;
/* 0x00B3: MOV TM1, #0FFFFh - Set timer to max */
REG_TM1 = 0xFFFF;
/* 0x00B8: SB TCON1.4 - Enable timer */
REG_TCON1 |= 0x10;
/* 0x00BB: SB SBYCON.2 - Enter standby mode */
REG_SBYCON |= 0x04;
/* 0x00BE: LB A, #005h - Stop sequence */
/* 0x00C0: STB A, STPACP - First stop command */
REG_STPACP = 0x05;
/* 0x00C2: SLLB A - Shift left (0x05 -> 0x0A) */
/* 0x00C3: STB A, STPACP - Second stop command */
REG_STPACP = 0x0A;
/* 0x00C5: SB SBYCON.0 - Final standby enable */
REG_SBYCON |= 0x01;
power_recovered:
/* label_00c8: */
/* 0x00C8: MOVB 0EDh, #047h - Store NMI error code */
g_errorCodeReboot = 0x47; /* 0x47 = NMI occurred */
/* 0x00CC: BRK - Force software break/reset */
/* This triggers isr_softwareBreak and system reset */
asm("BRK");
}
/**
* isr_timer1Compare() - Timer 1 Compare Match (Ignition Timing)
*
* Address: 0x00CD (label: int_timer_1)
*
* Triggers when Timer1 matches TMR1 - used for ignition coil timing.
* Very short handler - just calls the timing update routine.
*/
void isr_timer1Compare(void)
{
/* 0x00CD: CAL label_2911 - Call ignition update routine */
update_ignitorTiming();
/* 0x00D0: RTI - Return from interrupt */
return;
}
/**
* isr_timer2Compare() - Timer 2 Compare Match
*
* Address: 0x00D1 (label: int_timer_2)
*
* Timer2 is used for auxiliary timing. This handler manages
* ignitor sequencing and overflow detection.
*/
void isr_timer2Compare(void)
{
/* 0x00D1: L A, 0CEh - Load interrupt IE */
/* 0x00D3: ST A, IE - Enable nested interrupts */
REG_IE = g_ieInterrupt;
/* 0x00D5: SB PSWH.0 - Enable 16-bit addressing */
REG_PSWH |= 0x01;
/* 0x00D7: CLR LRB - Switch to register bank 0 */
REG_LRB = 0x00;
/* 0x00D9: LB A, 0DFh - Load ignitor counter */
uint8_t counter = g_ignitorCounter;
/* 0x00DB: ADDB A, #001h - Increment counter */
counter++;
/* 0x00DD: CMPB A, #003h - Check if counter >= 3 */
/* 0x00DF: JLT label_00eb - Skip if counter < 3 */
if (counter >= 3) {
/* 0x00E1: JBR off(07FF42h).2, label_00eb - Check TCON2.2 */
if (!(REG_TCON2 & 0x04)) {
/* 0x00E4: MOV off(07FF3Ah), 0DCh - Copy timing value */
REG_TMR2 = g_ignitorTiming2;
}
/* 0x00E8: RB TCON2.3 - Clear TCON2 bit 3 */
REG_TCON2 &= ~0x08;
}
/* label_00eb: */
/* 0x00EB: L A, 0CCh - Load normal IE */
/* 0x00ED: RB PSWH.0 - Clear 16-bit mode */
/* 0x00EF: ST A, IE - Restore interrupts */
REG_PSWH &= ~0x01;
REG_IE = g_ieNormal;
/* 0x00F1: RTI */
return;
}
/**
* isr_externalInt1_CYP() - External Interrupt 1 (Camshaft Position)
*
* Address: 0x00F2 (label: int_INT1)
*
* Triggered by CYP (Cylinder Position) or TDC (Top Dead Center)
* signal from the distributor. This synchronizes the ECU to the
* camshaft and determines which cylinder is firing.
*/
void isr_externalInt1_CYP(void)
{
/* 0x00F2: L A, IE - Save current IE */
/* 0x00F4: PUSHS A - Push to stack */
uint16_t savedIE = REG_IE;
/* 0x00F5: L A, #00010h - Minimal IE (timer1 only) */
/* 0x00F8: SCAL label_012c - Call setup routine */
REG_IE = 0x0010;
setup_interruptMode(); /* Sets up proper register bank */
/* 0x00FA: JBS off(07FF30h).7, label_010c - Check limp mode flag */
if (f_flags_FE & 0x80) { /* FE.7 = rev limiter active */
goto exit_isr; /* label_010c */
}
/* 0x00FD: JBS off(07FF30h).3, label_0112 - Check other flag */
if (f_flags_FE & 0x08) { /* Some processing flag */
goto continue_processing; /* label_0112 */
}
/* 0x0100: RB IRQ.7 - Clear pending IRQ bit 7 */
REG_IRQH &= ~0x80;
/* 0x0103: JEQ label_010f - Check if condition met */
if (/* some condition */ 0) {
goto set_flag; /* label_010f */
}
/* 0x0105: RB off(07FF2Eh).0 - Clear flag bit */
f_celDetect3 &= ~0x01;
/* 0x0108: MOVB off(07FFBAh), #02Dh - Set timing counter */
g_rpmTimerCountHi = 0x2D;
exit_isr:
/* label_010c: */
/* 0x010C: J label_03cd - Jump to interrupt exit */
goto interrupt_exit;
set_flag:
/* label_010f: */
/* 0x010F: SB off(07FF2Eh).0 - Set flag bit */
f_celDetect3 |= 0x01;
continue_processing:
/* label_0112: */
/* 0x0112: L A, ADCR5 - Read MAP sensor */
g_mapSensorRaw = REG_ADCR5;
/* 0x0114: ST A, 0B0h - Store MAP value */
/* Already done above */
/* 0x0116: L A, TM1 - Read timer1 capture */
/* 0x0118: ST A, TMR1 - Store as compare value */
REG_TMR1 = REG_TM1;
g_timer1Capture = REG_TM1;
/* 0x011A: LB A, #001h - Load constant 1 */
/* 0x011C: CAL label_31d3 - Call injector timing update */
calc_injectorTimingUpdate(1);
/* 0x011F: NOP */
/* 0x0120: SB P2.4 - Set P2.4 (limp mode indicator?) */
REG_P2 |= 0x10;
/* 0x0123: CAL label_2995 - Call RPM signal processing */
process_rpmSignal();
/* 0x0126: J label_022d - Continue to main processing */
goto main_engine_processing;
main_engine_processing:
/* ... continues with fuel/ignition calculations ... */
/* This is a large block - will be expanded in engine calcs section */
interrupt_exit:
/* label_03cd: */
/* 0x03CD: RB PSWH.0 - Clear 16-bit mode */
REG_PSWH &= ~0x01;
/* label_03cf: */
/* 0x03CF: POPS A - Restore IE */
/* 0x03D0: ST A, IE */
REG_IE = savedIE;
/* 0x03D2: RTI */
return;
}
/**
* setup_interruptMode() - Setup for interrupt processing
*
* Address: 0x0129 / 0x012C (labels: label_0129, label_012c)
*
* Configures the processor for interrupt handling with proper
* register bank and interrupt priority.
*/
void setup_interruptMode(void)
{
/* label_0129: */
/* 0x0129: L A, #00011h - Load alternate IE value */
/* Used when called from different paths */
/* label_012c: */
/* 0x012C: ST A, IE - Store new IE value */
/* 0x012E: MOV PSW, #00102h - Set processor status */
REG_PSW = 0x0102;
/* 0x0133: MOV LRB, #00022h - Switch to register bank */
REG_LRB = 0x22; /* Bank 2 + offset 2 = 0x110 */
/* 0x0136: RT - Return */
return;
}
/**
* isr_timer0Compare() - Timer 0 Compare Match (Main Engine Control)
*
* Address: 0x0137 (label: int_timer_0)
*
* THIS IS THE HEART OF THE ENGINE CONTROL SYSTEM!
*
* Called every TDC (Top Dead Center) event - once per cylinder per
* 720° engine cycle (4 times per cycle for a 4-cylinder).
*
* This ISR performs:
* - Crank position tracking (0-3 for 4 cylinders)
* - RPM calculation and averaging
* - CEL code detection for ignition signals
* - Fuel injection timing calculations
* - Ignition timing calculations
* - O2 feedback processing
* - VTEC condition checking
*/
void isr_timer0Compare(void)
{
/* 0x0137: L A, IE - Save current IE */
/* 0x0139: PUSHS A - Push to stack */
uint16_t savedIE = REG_IE;
/* 0x013A: SCAL label_0129 - Call setup routine */
setup_interruptMode();
/* 0x013C: MOVB off(07FFBAh), #02Dh - Set RPM timer high byte */
g_rpmTimerCountHi = 0x2D; /* Default/timeout value */
/* 0x0140: SB off(07FF20h).0 - Set flag 120.0 */
f_flags_120 |= 0x01;
/* 0x0143: JNE label_0151 - If already running, skip init */
if (f_flags_120 != 0x01) {
goto timer0_running; /* Already initialized */
}
/* First-time initialization path */
/* 0x0145: RB IRQH.7 - Clear INT1 pending */
REG_IRQH &= ~0x80;
/* 0x0148: RB off(07FF18h).0 - Clear CKP error flag */
f_flags_118 &= ~0x01;
/* 0x014B: RB TRNSIT.0 - Clear timer transit flag */
REG_TRNSIT &= ~0x01;
/* 0x014E: J label_029f - Jump to RPM calculation */
goto calculate_rpmDelta;
timer0_running:
/* label_0151: Engine is running, process normally */
/* 0x0151: LB A, 0E3h - Load TDC position counter */
uint8_t tdcCounter = g_tdcPosition;
/* 0x0153: ADDB A, #001h - Increment TDC counter */
tdcCounter++;
/* 0x0155: JBS off(07FF30h).7, label_0193 - Check rev limiter */
if (f_flags_FE & 0x80) {
/* Rev limiter active - skip error checking */
goto store_crankPosition;
}
/* 0x0158: RB IRQH.7 - Check/clear INT1 pending */
uint8_t int1Pending = REG_IRQH & 0x80;
REG_IRQH &= ~0x80;
/* 0x015B: JNE label_0170 - If INT1 was pending, handle error */
if (int1Pending) {
goto tdc_errorCheck;
}
/* 0x015D: RB off(07FF18h).0 - Check CKP error flag */
/* 0x0160: JNE label_0170 - If CKP error, handle it */
if (f_flags_118 & 0x01) {
f_flags_118 &= ~0x01; /* Clear it */
goto tdc_errorCheck;
}
/* No errors - normal processing */
/* 0x0162: STB A, r0 - Store counter temporarily */
uint8_t tempCounter = tdcCounter;
/* 0x0163: ANDB A, #003h - Check if counter is multiple of 4 */
/* 0x0165: JNE label_016d - Skip if not aligned */
if ((tdcCounter & 0x03) == 0) {
/* Every 4th TDC - set detection flags */
/* 0x0167: SB off(07FF2Eh).1 - Set TDC detection bit */
f_celDetect3 |= 0x02;
/* 0x016A: SB off(07FF1Ah).0 - Set first-TDC flag */
f_flags_11A |= 0x01;
}
/* label_016d: */
/* 0x016D: LB A, r0 - Restore counter */
/* 0x016E: SJ label_0193 - Jump to store position */
goto store_crankPosition;
tdc_errorCheck:
/* label_0170: TDC/CKP error handling */
/* 0x0170: RB off(07FF1Ah).0 - Clear first-TDC flag */
f_flags_11A &= ~0x01;
/* 0x0173: MOVB off(07FFBBh), #02Dh - Reset RPM counter */
g_rpmTimerCountHi = 0x2D;
/* 0x0177: CMPB A, #004h - Check if counter == 4 */
/* 0x0179: JEQ label_0192 - If == 4, reset counter */
if (tdcCounter == 4) {
tdcCounter = 0; /* Reset to 0 */
goto store_crankPosition;
}
/* 0x017B: SB off(07FF21h).1 - Set ignition flag */
f_flags_121 |= 0x02;
/* 0x017E: JLT label_0189 - If counter < 4, check more */
if (tdcCounter < 4) {
goto check_9a_flags;
}
/* 0x0180: CMPB A, #008h - Check if counter < 8 */
/* 0x0182: JLT label_018f - If < 8, set error bit 4 */
if (tdcCounter < 8) {
goto set_celDetect_4;
}
/* Counter >= 8 - set error bit 5 */
/* label_0184: */
/* 0x0184: SB off(07FF2Eh).5 - Set CEL detect bit 5 */
f_celDetect3 |= 0x20;
tdcCounter = 0;
goto store_crankPosition;
check_9a_flags:
/* label_0189: Check 9A flags */
/* 0x0189: JBR off(07FF9Ah).0, label_018f - Check bit 0 */
if (!(g_batteryVoltage & 0x01)) {
goto set_celDetect_4;
}
/* 0x018C: JBS off(07FF9Ah).1, label_0184 - Check bit 1 */
if (g_batteryVoltage & 0x02) {
f_celDetect3 |= 0x20;
tdcCounter = 0;
goto store_crankPosition;
}
set_celDetect_4:
/* label_018f: */
/* 0x018F: SB off(07FF2Eh).4 - Set CEL detect bit 4 */
f_celDetect3 |= 0x10;
/* label_0192: */
tdcCounter = 0; /* Reset counter */
store_crankPosition:
/* label_0193: Store the crank position */
/* 0x0193: STB A, 0E3h - Store TDC counter */
g_tdcPosition = tdcCounter;
/* 0x0195: ANDB A, #003h - Get crank position 0-3 */
/* 0x0197: STB A, 0E4h - Store crank position */
g_crankPosition = tdcCounter & 0x03;
/*
* Now process the 16ms cycle counter (slower timing)
* This handles VSS (Vehicle Speed Sensor) timing
*/
/* 0x0199: LB A, off(07FF9Ah) - Load 16ms counter */
uint8_t cycleCounter = g_batteryVoltage; /* Using 9A for cycle */
/* 0x019B: ADDB A, #001h - Increment */
cycleCounter++;
/* 0x019D: JBS off(07FF31h).0, label_01d0 - Check skip flag */
if (g_faultCode2 & 0x01) {
goto store_cycleCounter;
}
/* 0x01A0: RB TRNSIT.0 - Check timer transit */
uint8_t transitFlag = REG_TRNSIT & 0x01;
REG_TRNSIT &= ~0x01;
/* 0x01A3: JNE label_01b3 - If transit set, handle overflow */
if (transitFlag) {
goto handle_cycleOverflow;
}
/* No overflow - check for sync */
/* 0x01A5: STB A, r0 */
/* 0x01A6: ANDB A, #00Fh - Check if cycle is multiple of 16 */
/* 0x01A8: JNE label_01b0 - Skip if not aligned */
if ((cycleCounter & 0x0F) == 0) {
/* Every 16th cycle - set CYP detection flags */
/* 0x01AA: SB off(07FF2Eh).2 - Set CYP detect bit */
f_celDetect3 |= 0x04;
/* 0x01AD: SB off(07FF1Ah).1 - Set first-CYP flag */
f_flags_11A |= 0x02;
}
/* label_01b0: */
goto store_cycleCounter;
handle_cycleOverflow:
/* label_01b3: Timer overflow during cycle */
/* 0x01B3: RB off(07FF1Ah).1 - Clear first-CYP flag */
f_flags_11A &= ~0x02;
/* 0x01B6: MOVB off(07FFBCh), #007h - Set overflow marker */
g_rpmAccelDecel = 0x0007;
/* 0x01BA: CMPB A, #010h - Check if counter == 16 */
/* 0x01BC: JEQ label_01c5 - If 16, reset */
if (cycleCounter == 0x10) {
f_flags_121 &= ~0x02; /* Clear ignition flag */
if (g_crankPosition != 0) {
f_celDetect3 |= 0x40; /* Set CYP error */
}
cycleCounter = 0;
goto store_cycleCounter;
}
/* 0x01BE: JGE label_01cf - If >= 16, clear and reset */
if (cycleCounter >= 0x10) {
cycleCounter = 0;
goto store_cycleCounter;
}
/* 0x01C0: JBR off(07FF21h).1, label_01cc - Check ignition flag */
if (!(f_flags_121 & 0x02)) {
cycleCounter = 0;
goto store_cycleCounter;
}
/* Set CYP error bit */
/* label_01cc: */
f_celDetect3 |= 0x40;
cycleCounter = 0;
store_cycleCounter:
/* label_01d0: Store the cycle counter */
/* 0x01D0: STB A, off(07FF9Ah) - Store cycle counter */
g_batteryVoltage = cycleCounter; /* 9A used as cycle counter */
/* 0x01D2: ANDB A, #00Fh - Check low nibble */
/* 0x01D4: JNE label_01eb - Skip cylinder update if not 0 */
if ((cycleCounter & 0x0F) != 0) {
goto check_flags_for_limiter;
}
/*
* Update cylinder index (firing order)
* Cylinder order: 0=Cyl1, 1=Cyl3, 2=Cyl4, 3=Cyl2
*/
/* 0x01D6: LB A, 0E7h - Load some counter */
/* 0x01D8: JEQ label_01df - If zero, calculate cylinder */
if (g_unused_E7 == 0) {
/* 0x01DF: MOV DP, #0021Ah - Load injector mask address */
/* 0x01E2: MB C, [DP].0 - Get bit 0 of mask */
/* 0x01E4: LB A, #001h - Load 1 */
/* 0x01E6: JGE label_01e9 - If carry set, use 1 */
uint8_t injMask = g_injectorMask;
g_cylinderIndex = (injMask & 0x01) ? 1 : 0;
} else {
/* 0x01DA: DECB 0E7h - Decrement counter */
g_unused_E7--;
g_cylinderIndex = 0;
}
/* label_01e9: */
/* 0x01E9: STB A, 0E5h - Store cylinder index */
/* Already set above */
check_flags_for_limiter:
/* label_01eb: Check various flags */
/* 0x01EB: JBS off(07FF30h).7, label_01f1 - Check rev limiter */
if (f_flags_FE & 0x80) {
goto update_e3_from_9a;
}
/* 0x01EE: JBR off(07FF1Ah).0, label_01fe - Check first-TDC flag */
if (!(f_flags_11A & 0x01)) {
goto check_first_cyp;
}
update_e3_from_9a:
/* label_01f1: Update TDC counter from cycle counter */
/* 0x01F1: ANDB 0E3h, #0FCh - Clear low 2 bits of E3 */
g_tdcPosition &= 0xFC;
/* 0x01F5: LB A, off(07FF9Ah) - Load cycle counter */
/* 0x01F7: ANDB A, #003h - Get low 2 bits */
/* 0x01F9: ORB 0E3h, A - Merge into E3 */
g_tdcPosition |= (g_batteryVoltage & 0x03);
/* 0x01FC: STB A, 0E4h - Update crank position */
g_crankPosition = g_batteryVoltage & 0x03;
check_first_cyp:
/* label_01fe: */
/* Similar logic for CYP synchronization */
if (g_faultCode2 & 0x01) {
goto update_9a_from_e4;
}
if (!(f_flags_11A & 0x02)) {
goto check_ignition_state;
}
update_9a_from_e4:
/* label_0204: Update 9A from E4 */
g_batteryVoltage &= 0xFC;
g_batteryVoltage |= (g_crankPosition & 0x03);
check_ignition_state:
/* label_020d: Determine ignition state */
/* 0x020D: RC - Clear carry */
bool ignitionBad = false;
/* Check various conditions for limp mode */
if (!(f_flags_FE & 0x80)) { /* Not rev limited */
if (!(f_flags_11A & 0x01)) { /* No TDC sync */
if (!(f_flags_11A & 0x40)) { /* Some other flag */
ignitionBad = false;
} else {
ignitionBad = true;
}
} else {
ignitionBad = true;
}
} else {
if (!(g_faultCode2 & 0x01)) {
if (!(f_flags_11A & 0x02)) {
ignitionBad = false;
} else {
ignitionBad = true;
}
} else {
ignitionBad = true;
}
}
/* label_021e: Store ignition state */
/* 0x021E: MB off(07FF21h).3, C - Store bad flag in 121.3 */
if (ignitionBad) {
f_flags_121 |= 0x08;
f_flags_FE |= 0x40; /* Set limp mode flag */
} else {
f_flags_121 &= ~0x08;
}
/* label_0226: Check if we should skip processing */
/* 0x0226: JBS off(07FF2Bh).6, label_022d - Check skip flag */
if (!(f_flags_12A & 0x40)) {
/* 0x0229: ANDB off(07FF2Eh), #08Fh - Clear some detect bits */
f_celDetect3 &= 0x8F;
}
main_engine_processing:
/* label_022d: Main engine calculation entry point */
/* 0x022D: JBS off(07FF1Fh).4, label_029f - Check if engine not running */
if (f_flags_11F & 0x10) { /* Engine running flag */
goto calculate_rpmDelta; /* Skip calculations */
}
/* 0x0230: JBS off(07FF21h).2, label_0252 - Check ignition ready */
if (f_flags_121 & 0x04) {
goto calculate_fuel_injection; /* Ignition ready */
}
/*
* Check cylinder synchronization
* Uses address 0x0199 as a table lookup
*/
/* 0x0233: MOV DP, #00199h - Load sync table address */
/* 0x0236: LB A, 0E5h - Load cylinder index */
/* 0x0238: SRLB A - Shift right (divide by 2) */
/* 0x0239: LB A, off(07FF9Ah) - Load cycle counter */
/* 0x023B: JLT label_023f - Check sign */
/* 0x023D: ADDB A, #004h - Add offset */
uint8_t syncIndex = g_cylinderIndex >> 1;
uint8_t cycleVal = g_batteryVoltage;
if (cycleVal >= 0) {
cycleVal += 4;
}
/* 0x023F: ANDB A, #007h - Mask to 3 bits */
syncIndex = cycleVal & 0x07;
/* 0x0241: CMPB A, [DP] - Compare with table value */
/* 0x0243: JNE label_029f - If no match, skip to RPM calc */
/* ... synchronization check ... */
/* If synchronized, continue to fuel calculation */
calculate_fuel_injection:
/* label_0252: Calculate fuel injection */
/*
* This section calculates the final fuel pulse width
* using the O2 sensor feedback loop.
*
* Formula: D6 = (0x144 * O2_trim / 0x10000) * 2 + 0x146
*/
/* 0x0252: CLR A - Clear for 16-bit ops */
/* 0x0253: LB A, 0E5h - Load cylinder index */
/* 0x0255: SLLB A - Multiply by 2 for word index */
uint8_t cylIndex = g_cylinderIndex * 2;
/* 0x0256: MOV DP, A - Use as offset */
/* 0x0257: ANDB A, #002h - Get bit 1 (odd/even cylinder pair) */
/* 0x0259: MOV X1, A - Store for O2 selection */
uint8_t o2Select = cylIndex & 0x02; /* 0 or 2 */
/* 0x025A: L A, 00162h[X1] - Load O2 trim (primary or secondary) */
uint16_t o2Trim;
if (o2Select == 0) {
o2Trim = g_o2TrimPrimary; /* 0x0162 */
} else {
o2Trim = g_o2TrimSecondary; /* 0x0164 */
}
/* 0x025D: MOV er0, #0944Eh - Load upper limit */
/* 0x0261: CMP A, #0B6E0h - Compare O2 trim with max */
/* 0x0264: JGE label_0270 - If too high, use limit */
uint16_t o2Limited = o2Trim;
if (o2Trim >= 0xB6E0) {
o2Limited = 0x944E; /* Upper clamp */
} else if (o2Trim <= 0x5720) {
/* 0x0266: MOV er0, #0682Ah - Load lower limit */
o2Limited = 0x682A; /* Lower clamp */
}
/* Otherwise use actual O2 trim value */
/* label_0270: Continue with fuel calculation */
/* 0x0270: SRL X1 - Divide index by 2 */
/* 0x0272: LB A, 0011Bh[X1] - Load O2 flags */
/* 0x0275: SRLB A - Check bit 0 */
/* 0x0276: JGE label_027f - Skip if not set */
/* 0x0278: CLR A - Clear for table lookup */
/* 0x0279: LC A, 037CCh[DP] - Load from fuel correction table */
/* 0x027D: ADD er0, A - Add correction */
/* label_027f: Final fuel calculation */
/* 0x027F: L A, off(07FF44h) - Load main fuel value (0x144) */
uint16_t mainFuel = g_fuelMainFinal;
/* 0x0281: MUL - Multiply by O2 trim */
uint32_t fuelProduct = (uint32_t)mainFuel * o2Limited;
/* 0x0283: SLL A - Shift for scaling */
/* 0x0284: L A, er1 - Get high word (result / 65536) */
/* 0x0285: ROL A - Double it */
uint16_t scaledFuel = (uint16_t)(fuelProduct >> 15); /* * 2 / 65536 */
/* 0x0286: JLT label_028c - Check for overflow */
if (scaledFuel & 0x8000) {
scaledFuel = 0xFFFF; /* Clamp to max */
}
/* 0x0288: ADD A, off(07FF46h) - Add fuel corrections (0x146) */
uint16_t finalFuel = scaledFuel + g_fuelCorrections;
/* 0x028A: JGE label_028f - Check for overflow */
if (finalFuel < scaledFuel) { /* Overflow check */
finalFuel = 0xFFFF;
}
/* label_028f: Store final fuel pulse width */
/* 0x028F: ST A, 0D6h - Store to final fuel register! */
g_finalFuelPulse = finalFuel;
/* 0x0291: CAL label_29b1 - Call injector update routine */
update_injectorPulseWidth();
/* 0x0294: MOV LRB, #00022h - Restore register bank */
REG_LRB = 0x22;
/* 0x0297: LB A, 0E5h - Load cylinder index */
/* 0x0299: ADDB A, #001h - Increment for next cylinder */
/* 0x029B: ANDB A, #003h - Wrap around 0-3 */
/* 0x029D: STB A, 0E5h - Store updated cylinder */
g_cylinderIndex = (g_cylinderIndex + 1) & 0x03;
calculate_rpmDelta:
/* label_029f: Calculate RPM from timer delta */
/*
* This section calculates RPM by measuring the time
* between TDC events (45° of crank rotation each).
*/
/* 0x029F: L A, TMR1 - Load timer1 compare value */
uint16_t currentTimer = REG_TMR1;
/* 0x02A1: ST A, er0 - Save to er0 */
uint16_t savedTimer = currentTimer;
/* 0x02A2: SUB A, 0E0h - Subtract previous timer */
int16_t timerDelta = currentTimer - g_timer1Old;
/* 0x02A5: JBR off(07FF21h).2, label_02bd - Check if running */
if (!(f_flags_121 & 0x04)) {
goto timer_overflow_check;
}
/* Check for valid delta (no overflow) */
/* 0x02A8: JBS off(07FF1Eh).7, label_02b0 - Check overflow flag */
if (f_flags_11E & 0x80) {
timerDelta = 0; /* Overflow - zero delta */
goto clear_rpm_samples;
}
/* 0x02AB: JBR off(07FF1Eh).6, label_02b1 - Check another flag */
if (!(f_flags_11E & 0x40)) {
goto store_valid_delta;
}
/* 0x02AE: JLT label_02b1 - Check sign */
if (timerDelta < 0) {
goto store_valid_delta;
}
/* Overflow or invalid - clear delta */
timerDelta = 0;
clear_rpm_samples:
/* label_02b0/02b1: Clear/init RPM sample buffer */
/* 0x02B1: MOV USP, #0020Dh - Set user stack pointer */
/* 0x02B5-0x02B8: PUSHU A (x4) - Clear 4 samples to zero */
g_rpmSample0 = 0;
g_rpmSample1 = 0;
g_rpmSample2 = 0;
g_rpmSample3 = 0;
/* 0x02B9: ST A, 0B8h - Store zero delta */
g_rpmTimerDelta = 0;
goto update_old_timer;
timer_overflow_check:
/* label_02bd: Check for timer overflow during measurement */
/* 0x02BD: MB C, TCON1.2 - Check timer overflow bit */
if (REG_TCON1 & 0x04) {
timerDelta = 0; /* Overflow - invalid measurement */
}
store_valid_delta:
/* label_02c3: Store the timer delta */
/* 0x02C3: ST A, 0B8h - Store delta for RPM calc */
g_rpmTimerDelta = timerDelta;
/* Store in rotating sample buffer */
/* 0x02C5: LB A, 0E4h - Load crank position (0-3) */
/* 0x02C7: SLLB A - Multiply by 2 for word offset */
/* 0x02C8: EXTND - Sign extend to 16-bit */
/* 0x02C9: MOV X1, A - Use as index */
uint8_t sampleIndex = g_crankPosition * 2;
/* 0x02CA: L A, 0B8h - Load delta */
/* 0x02CC: ST A, 00206h[X1] - Store in sample buffer */
switch (g_crankPosition) {
case 0: g_rpmSample0 = timerDelta; break;
case 1: g_rpmSample1 = timerDelta; break;
case 2: g_rpmSample2 = timerDelta; break;
case 3: g_rpmSample3 = timerDelta; break;
}
update_old_timer:
/* label_02cf: Update old timer value */
/* 0x02CF: L A, er0 - Load saved timer */
/* 0x02D0: ST A, 0E0h - Store as previous timer */
g_timer1Old = savedTimer;
/* 0x02D2: SLL A - Check if timer high bit set */
/* 0x02D3: JLT label_02db - If negative, skip flag update */
if (!(savedTimer & 0x8000)) {
/* 0x02D5: MB C, IRQ.6 - Check timer IRQ */
/* 0x02D8: MB 0FDh.5, C - Store to flag */
if (REG_IRQ & 0x40) {
f_flags_FD |= 0x20;
} else {
f_flags_FD &= ~0x20;
}
}
/* label_02db: Clear overflow flags */
/* 0x02DB: ANDB off(07FF1Eh), #03Fh - Clear bits 6-7 */
f_flags_11E &= 0x3F;
/* 0x02DF: LB A, 0E4h - Load crank position */
/* 0x02E1: JEQ label_02f6 - If position 0, check engine start */
if (g_crankPosition == 0) {
goto check_engine_starting;
}
/* 0x02E3: CMPB A, #003h - Check if position 3 */
/* 0x02E5: JEQ label_0341 - If position 3, calculate ignition */
if (g_crankPosition == 3) {
goto calculate_ignitionDwell;
}
/* Position 1 or 2 - calculate injector timing */
/* ... injector timing calculations ... */
goto interrupt_exit;
check_engine_starting:
/* label_02f6: Check if engine is starting */
/* Compare RPM with threshold */
/* 0x02F6: LB A, #012h - High threshold (cranking) */
uint8_t rpmThreshold = 0x12;
/* 0x02F8: JBR off(07FF18h).1, label_02fd - Check starter flag */
if (!(f_flags_118 & 0x02)) {
rpmThreshold = 0x0B; /* Low threshold (running) */
}
/* label_02fd: */
/* 0x02FD: CMPB A, 0BBh - Compare with RPM high byte */
if (g_rpmTimerCountHi > rpmThreshold) {
/* Engine running */
f_flags_118 |= 0x02; /* Set running flag */
} else {
f_flags_118 &= ~0x02; /* Clear running flag */
}
/* 0x0316: MB P2.4, C - Update limp mode output */
if (f_flags_118 & 0x02) {
REG_P2 |= 0x10;
} else {
REG_P2 &= ~0x10;
}
/* 0x0319: CAL label_2995 - Call RPM processing */
process_rpmSignal();
goto interrupt_exit;
calculate_ignitionDwell:
/* label_0341: Calculate ignition coil dwell time */
/*
* This calculates when to turn on the ignition coil
* so it's fully charged before the spark event.
*/
/* 0x0341: CLR A */
/* 0x0342: CLRB A */
/* 0x0343: STB A, r1 */
/* 0x0344: SUBB A, off(07FF35h) - Get ignition timing */
int8_t ignTiming = -(int8_t)g_ignitionVcalCalc;
/* 0x0346: L A, ACC - Load full word */
/* 0x0348: SLL A - Multiply by 2 */
int16_t dwellCalc = ignTiming * 2;
/* 0x0349: MOVB r0, off(07FF34h) - Load final ignition */
uint8_t ignFinal = g_ignitionFinal;
/* 0x034C: SUB A, er0 - Subtract */
dwellCalc -= ignFinal;
/* 0x034D: SLL A - Multiply by 2 again */
dwellCalc *= 2;
/* 0x034E: CMPB ACCH, #0FEh - Check for max */
if ((dwellCalc >> 8) == 0xFE) {
dwellCalc = 0xFF00; /* Clamp to max */
}
/* label_0357: Store dwell time */
/* 0x0357: ST A, 0DEh - Store ignitor timing */
g_ignitorTiming3 = dwellCalc;
/* Calculate inverse for other banks */
/* 0x0359: LB A, off(07FF34h) - Load final ignition */
/* 0x035B: XORB A, #0FFh - Invert */
/* 0x035D: SLLB A - Multiply by 2 */
/* 0x035E: INCB ACC - Add 1 */
/* 0x0361: STB A, off(07FF36h) - Store inverted timing */
g_ignitionInverse = ((~ignFinal) << 1) + 1;
/* Continue to ignitor update */
goto update_ignitor_state;
update_ignitor_state:
/* label_0366-03c5: Update ignitor output timing */
/* ... complex timing calculations for spark output ... */
/* Final store of dwell time */
/* 0x03C5: ST A, 0D8h - Store final ignitor timing */
g_ignitorTiming0 = dwellCalc;
interrupt_exit:
/* label_03cd: Common interrupt exit */
/* 0x03CD: RB PSWH.0 - Clear 16-bit mode */
REG_PSWH &= ~0x01;
/* 0x03CF: POPS A - Restore IE */
/* 0x03D0: ST A, IE */
REG_IE = savedIE;
/* 0x03D2: RTI - Return from interrupt */
return;
}
/**
* isr_externalInt0_CKP() - External Interrupt 0 (Crankshaft Position)
*
* Address: 0x151F (label: int_INT0)
*
* Triggered by CKP (Crankshaft Position Sensor) signal from
* the distributor. This provides the primary timing reference
* for the engine control system.
*
* The CKP signal occurs 8 times per crank revolution (45° apart).
*/
void isr_externalInt0_CKP(void)
{
/* 0x151F: L A, IE - Save current IE */
/* 0x1521: PUSHS A - Push to stack */
uint16_t savedIE = REG_IE;
/* 0x1522: L A, 0CEh - Load interrupt IE value */
/* 0x1524: ST A, IE - Enable nested interrupts */
REG_IE = g_ieInterrupt;
/* 0x1526: SB PSWH.0 - Enable 16-bit addressing */
REG_PSWH |= 0x01;
/* 0x1528: MOV LRB, #00020h - Switch to register bank 2 */
REG_LRB = 0x20;
/* 0x152B: SB 0FEh.0 - Set CKP flag (pulse received) */
f_flags_FE |= 0x01;
/* Capture timer value for RPM calculation */
/* 0x152E: L A, TM1 - Read Timer1 current value */
/* 0x1530: XCHG A, 0C8h - Exchange with previous capture */
uint16_t currentTimer = REG_TM1;
uint16_t previousTimer = g_timer1Capture;
g_timer1Capture = currentTimer;
/* 0x1533: ST A, 0C6h - Store previous as old-previous */
g_timer1Previous = previousTimer;
/* 0x1535: LB A, 0E2h - Load overflow counter */
/* 0x1537: STB A, 0CAh - Store as old overflow */
g_timerOverflowOld = g_timer1Overflow;
/* 0x1539: CLRB 0E2h - Clear overflow counter */
g_timer1Overflow = 0;
/* 0x153C: RB IRQ.6 - Check/clear Timer1 overflow IRQ */
uint8_t overflowed = REG_IRQ & 0x40;
REG_IRQ &= ~0x40; /* Clear flag */
/* 0x153F: JEQ label_1557 - If no overflow, exit */
if (overflowed == 0) {
goto ckp_exit;
}
/* Timer overflow occurred - update flags */
/* 0x1541: MB C, off(0011Eh).6 - Copy bit 6 to carry */
/* 0x1544: MB off(0011Eh).7, C - Move carry to bit 7 */
uint8_t oldBit6 = (f_flags_11E >> 6) & 0x01;
f_flags_11E = (f_flags_11E & 0x7F) | (oldBit6 << 7);
/* 0x1547: SB off(0011Eh).6 - Set overflow flag bit 6 */
f_flags_11E |= 0x40;
/* 0x154A: MB C, 0C9h.7 - Check engine sync flag */
/* 0x154D: JGE label_1554 - Branch based on sync state */
if (g_engineSync & 0x80) {
/* 0x154F: INCB 0E2h - Increment overflow counter */
g_timer1Overflow++;
goto ckp_exit;
}
/* label_1554: */
/* 0x1554: INCB 0CAh - Increment old overflow */
g_timerOverflowOld++;
ckp_exit:
/* label_1557: Restore and exit */
/* 0x1557: RB PSWH.0 - Clear 16-bit mode */
REG_PSWH &= ~0x01;
/* 0x1559: POPS A - Restore IE */
/* 0x155A: ST A, IE */
REG_IE = savedIE;
/* 0x155C: RTI */
return;
}
/**
* isr_serialRxBaudRate() - Serial RX Baud Rate Generator Interrupt
*
* Address: 0x155D (label: int_serial_rx_BRG)
*
* Triggered periodically by the serial baud rate generator.
* Used to sample the TPS (Throttle Position Sensor) at a
* consistent rate for smooth throttle response.
*/
void isr_serialRxBaudRate(void)
{
/* 0x155D: SB 0FEh.1 - Set TPS sample flag */
f_flags_FE |= 0x02;
/* 0x1560: L A, ADCR7 - Read TPS from ADC channel 7 */
/* 0x1562: ST A, 0AAh - Store raw TPS value */
g_tpsRaw = REG_ADCR7;
/* 0x1564: RTI */
return;
}
/**
* isr_timer0Overflow() - Timer 0 Overflow (Injector Control)
*
* Address: 0x1565 (label: int_timer_0_overflow)
*
* Controls the fuel injector timing. When Timer0 overflows or
* matches, this ISR updates the injector output pins to turn
* injectors on or off at precisely the right time.
*
* Uses a rotating bit pattern to sequence through cylinders:
* 0111_0111 -> 1011_1011 -> 1101_1101 -> 1110_1110
*/
void isr_timer0Overflow(void)
{
/* 0x1565: MOV LRB, #00040h - Switch to register bank 4 (0x200) */
REG_LRB = 0x40;
/* 0x1568: L A, off(00214h) - Load injector timing 0 */
uint16_t injTiming0 = g_injTiming0;
/* 0x156A: JNE label_159e - If timing0 != 0, use it */
if (injTiming0 != 0) {
goto use_timing0;
}
/* Timing0 is 0, check timing1 */
/* 0x156C: L A, off(00216h) - Load injector timing 1 */
uint16_t injTiming1 = g_injTiming1;
/* 0x156E: JEQ label_15d3 - If timing1 also 0, check timing2 */
if (injTiming1 == 0) {
goto check_timing2;
}
/* Use timing1 - rotate injector mask and update outputs */
/* 0x1570: LB A, off(0021Bh) - Load injector mask inverse */
uint8_t injMaskInv = g_injectorMaskInv;
/* Rotate left through carry (barrel shift) */
/* 0x1572: MB C, ACC.7 - Get high bit to carry */
/* 0x1575: ROLB A - Rotate left */
uint8_t carryBit = (injMaskInv >> 7) & 0x01;
injMaskInv = (injMaskInv << 1) | carryBit;
/* 0x1576: ORB off(0021Ch), A - OR into output mask */
g_injectorOutput |= injMaskInv;
/* Rotate again for next cylinder */
/* 0x1579: MB C, ACC.7 */
/* 0x157C: ROLB A */
carryBit = (injMaskInv >> 7) & 0x01;
injMaskInv = (injMaskInv << 1) | carryBit;
/* 0x157D: STB A, off(0021Bh) - Store updated mask */
g_injectorMaskInv = injMaskInv;
/* 0x157F: ORB A, off(0021Ch) - Combine masks */
/* 0x1581: ANDB A, #00Fh - Keep only injector bits */
/* 0x1583: STB A, off(0021Ch) - Store output pattern */
g_injectorOutput = (g_injectorOutput | injMaskInv) & 0x0F;
/* 0x1585: CAL label_28ed - Call output update */
update_injectorOutputs();
/* 0x1588: ORB P2, off(0021Ch) - Apply to port (turn off injectors) */
REG_P2 |= g_injectorOutput;
/* 0x158C: L A, off(00216h) - Load timing1 */
/* 0x158E: ST A, TM0 - Set as next timer compare */
REG_TM0 = g_injTiming1;
/* 0x1590: CAL label_2906 - Call timing setup */
setup_injectorTimer();
/* Shift timing buffer: 2->0, next->1 */
/* 0x1593: MOV off(00214h), off(00218h) */
g_injTiming0 = g_injTiming2;
/* 0x1597: L A, #0FFFFh - Load "no event" value */
/* 0x159A: ST A, off(00216h) - Clear timing1 */
g_injTiming1 = 0xFFFF;
goto store_timing2;
use_timing0:
/* label_159e: Use timing0 */
/* Similar rotation logic for this path */
injMaskInv = g_injectorMaskInv;
carryBit = (injMaskInv >> 7) & 0x01;
injMaskInv = (injMaskInv << 1) | carryBit;
g_injectorMaskInv = injMaskInv;
g_injectorOutput = (g_injectorOutput | (injMaskInv & 0x0F)) & 0x0F;
update_injectorOutputs();
REG_P2 |= g_injectorOutput;
REG_TM0 = g_injTiming0;
setup_injectorTimer();
/* Shift: 1->0, 2->1 */
g_injTiming0 = g_injTiming1;
g_injTiming1 = g_injTiming2;
store_timing2:
/* 0x15C4: ST A, off(00218h) - Store 0xFFFF to timing2 */
g_injTiming2 = 0xFFFF;
/* 0x15C6: CMPB off(0021Ch), #00Fh - Check if all injectors off */
/* 0x15CA: JNE label_15d2 - If not all off, continue */
if (g_injectorOutput == 0x0F) {
/* All injectors off - disable timer interrupt */
/* 0x15CC: RB TCON0.4 - Disable Timer0 */
REG_TCON0 &= ~0x10;
/* 0x15CF: RB IRQ.4 - Clear pending interrupt */
REG_IRQ &= ~0x10;
}
/* label_15d2: RTI */
return;
check_timing2:
/* label_15d3: Both timing0 and timing1 are 0, check timing2 */
/* 0x15D3: L A, off(00218h) - Load timing2 */
uint16_t injTiming2 = g_injTiming2;
/* 0x15D5: JEQ label_15ff - If timing2 also 0, all done */
if (injTiming2 == 0) {
goto all_injectors_off;
}
/* Process timing2 with inverse rotation */
/* 0x15D7: LB A, off(0021Bh) - Load mask inverse */
/* 0x15D9: XORB A, #0FFh - Invert it */
/* 0x15DB: ANDB A, #00Fh - Keep low nibble */
/* 0x15DD: ORB off(0021Ch), A - Merge into output */
uint8_t invMask = (~g_injectorMaskInv) & 0x0F;
g_injectorOutput |= invMask;
/* Rotate right for previous cylinder */
injMaskInv = g_injectorMaskInv;
carryBit = injMaskInv & 0x01;
injMaskInv = (injMaskInv >> 1) | (carryBit << 7);
g_injectorMaskInv = injMaskInv;
update_injectorOutputs();
REG_P2 |= g_injectorOutput;
REG_TM0 = g_injTiming2;
goto clear_all_timings;
all_injectors_off:
/* label_15ff: No more injector events */
/* 0x15FF: MOVB off(0021Ch), #00Fh - All injectors off */
g_injectorOutput = 0x0F;
update_injectorOutputs();
REG_P2 |= 0x0F; /* Turn off all injectors */
clear_all_timings:
/* label_15f3: Clear timing buffer */
setup_injectorTimer();
g_injTiming0 = 0xFFFF;
g_injTiming1 = 0xFFFF;
g_injTiming2 = 0xFFFF;
return;
}
/**
* isr_timer1Overflow() - Timer 1 Overflow (RPM Timing)
*
* Address: 0x160C (label: int_timer_1_overflow)
*
* Occurs when Timer1 overflows (every 65536 counts at CLK/32).
* Used to detect very low RPM or stalled engine conditions.
* Also manages the RPM measurement overflow flags.
*/
void isr_timer1Overflow(void)
{
/* 0x160C: AND IE, #00080h - Disable most interrupts */
REG_IE &= 0x0080;
/* 0x1611: SB PSWH.0 - Enable 16-bit mode */
REG_PSWH |= 0x01;
/* 0x1613: MOV LRB, #00020h - Switch to register bank 2 */
REG_LRB = 0x20;
/* Shift overflow history flags */
/* 0x1616: MB C, off(0011Eh).6 - Get bit 6 */
/* 0x1619: MB off(0011Eh).7, C - Move to bit 7 */
uint8_t bit6 = (f_flags_11E >> 6) & 0x01;
f_flags_11E = (f_flags_11E & 0x7F) | (bit6 << 7);
/* 0x161C: SB off(0011Eh).6 - Set bit 6 (current overflow) */
f_flags_11E |= 0x40;
/* 0x161F: L A, 0CEh - Load interrupt IE */
/* 0x1621: ST A, IE - Restore interrupts */
REG_IE = g_ieInterrupt;
/* 0x1623: RB 0FDh.5 - Check/clear flag FD.5 */
if (f_flags_FD & 0x20) {
f_flags_FD &= ~0x20;
/* 0x1628: ANDB off(0011Eh), #03Fh - Clear overflow bits */
f_flags_11E &= 0x3F;
}
/* label_162c: */
/* 0x162C: INCB 0E2h - Increment overflow counter */
g_timer1Overflow++;
/* 0x162F: L A, 0CCh - Load normal IE */
/* 0x1631: RB PSWH.0 - Clear 16-bit mode */
/* 0x1633: ST A, IE - Restore interrupts */
REG_PSWH &= ~0x01;
REG_IE = g_ieNormal;
/* 0x1635: RTI */
return;
}
/**
* isr_pwmTimer() - PWM Timer Interrupt (IACV Control)
*
* Address: 0x1636 (label: int_PWM_timer)
*
* Controls the IACV (Idle Air Control Valve) PWM output.
* The duty cycle determines how much air bypasses the throttle
* plate at idle, controlling idle speed.
*
* Also samples the PA (atmospheric pressure) sensor.
*/
void isr_pwmTimer(void)
{
/* 0x1636: L A, 0CEh - Load interrupt IE */
/* 0x1638: ST A, IE - Enable nested interrupts */
REG_IE = g_ieInterrupt;
/* 0x163A: SB PSWH.0 - Enable 16-bit mode */
REG_PSWH |= 0x01;
/* 0x163C: MOV LRB, #00040h - Switch to register bank 4 (0x200) */
REG_LRB = 0x40;
/* 0x163F: JBR off(0021Dh).0, label_1661 - Check IACV phase flag */
if (!(g_iacvControl & 0x01)) {
goto iacv_phase2;
}
/* IACV Phase 1: Apply calculated duty cycle */
/* 0x1642: RB off(0021Dh).0 - Clear phase flag (toggle) */
g_iacvControl &= ~0x01;
/* 0x1645: MOV PWMR1, #0FD58h - Set PWM1 reload value */
REG_PWMR1 = 0xFD58; /* Fixed timing for IACV pulse */
/* 0x164A: L A, ADCR4 - Read PA sensor (atmospheric) */
/* 0x164C: ST A, 0A8h - Store PA value */
g_atmPressure = REG_ADCR4;
/* 0x164E: L A, off(00202h) - Load IACV duty cycle */
/* 0x1650: ST A, off(00204h) - Copy to output buffer */
g_iacvDutyCopy = g_iacvDutyCycle;
/* 0x1652: JBS off(00203h).4, label_1658 - Check max duty flag */
if (!(g_iacvDutyCycle & 0x1000)) {
/* Not at max - use calculated value */
/* 0x1655: L A, #0E001h - Load minimum duty value */
goto apply_pwm;
}
/* Use calculated duty cycle */
apply_pwm:
/* label_1658: Apply PWM value */
/* 0x1658: ST A, PWMR0 - Set PWM0 reload (IACV duty) */
REG_PWMR0 = g_iacvDutyCycle;
goto pwm_exit;
iacv_phase2:
/* label_1661: IACV Phase 2 */
/* 0x1661: SB off(0021Dh).0 - Set phase flag (toggle) */
g_iacvControl |= 0x01;
/* 0x1664: MOV PWMR1, #0FFFFh - Set max PWM1 reload */
REG_PWMR1 = 0xFFFF;
/* 0x1669: L A, off(00204h) - Load duty cycle copy */
uint16_t dutyCycle = g_iacvDutyCopy;
/* 0x166B: JBR off(00205h).4, label_1658 - Check min duty flag */
if (!(dutyCycle & 0x1000)) {
/* 0x166E: L A, #0FFFFh - Load max value (off) */
dutyCycle = 0xFFFF;
}
REG_PWMR0 = dutyCycle;
pwm_exit:
/* 0x165A: L A, 0CCh - Load normal IE */
/* 0x165C: RB PSWH.0 - Clear 16-bit mode */
/* 0x165E: ST A, IE - Restore interrupts */
REG_PSWH &= ~0x01;
REG_IE = g_ieNormal;
/* 0x1660: RTI */
return;
}
/*============================================================================
* SECTION 6: SYSTEM INITIALIZATION
* ============================================================================
*
* This section handles power-on reset and system initialization.
* Configures all hardware peripherals and prepares the ECU for operation.
*
* Address: 0x1673-0x189A (labels: int_start, int_break, int_WDT)
*
*============================================================================*/
/**
* isr_watchdogTimeout() - Watchdog Timer Reset Handler
*
* Address: 0x1696 (label: int_WDT)
*
* Called when the watchdog timer expires (ECU hung).
* Stores error code 0x44 and triggers reset.
*/
void isr_watchdogTimeout(void)
{
/* 0x1696: MOVB 0EDh, #044h - Store WDT error code */
g_errorCodeReboot = 0x44;
/* Falls through to isr_softwareBreak */
isr_softwareBreak();
}
/**
* isr_softwareBreak() - Software Break / Reset Handler
*
* Address: 0x169A (label: int_break)
*
* Common entry point for various reset conditions.
* Called from BRK instruction, WDT timeout, and unused vectors.
*/
void isr_softwareBreak(void)
{
/* 0x169A: CLR PSW - Clear processor status (reset state) */
REG_PSW = 0x0000;
/* 0x169D: SJ label_1678 - Jump to reset continuation */
goto reset_continue;
reset_continue:
/* Continue with system initialization */
isr_systemReset();
}
/**
* isr_systemReset() - Power-On Reset / System Initialization
*
* Address: 0x1673 (label: int_start)
*
* This is the ECU entry point after power-on or reset.
* Initializes all hardware and RAM, then enters the main loop.
*
* MODIFIED for datalogging: Stack relocated to 0x025B
*/
void isr_systemReset(void)
{
/* 0x1673: MOV PSW, #00010h - Set initial processor status */
REG_PSW = 0x0010; /* Basic mode, interrupts disabled */
reset_watchdog:
/* label_1678: Feed watchdog and initialize stack */
/* 0x1678: MOVB WDT, #03Ch - Reset watchdog timer */
REG_WDT = 0x3C; /* Feed the watchdog */
/*
* DATALOGGING MODIFICATION:
* Stack relocated from 0x0264 to 0x025B for logging buffer space
*/
/* 0x167C: MOV SSP, #0025Bh - Set system stack pointer */
REG_SSP = 0x025B; /* Modified for datalogging */
/* 0x1680: MOV LRB, #00010h - Switch to register bank 1 (0x080) */
REG_LRB = 0x10;
/* 0x1683: CLR er1 - Clear extended register pair */
/* (er1 = r2:r3 in current bank) */
/* 0x1685: JBR PSW.4, label_169f - Check if warm reset */
if (!(REG_PSW & 0x10)) {
goto check_warm_reset;
}
cold_boot:
/* label_1688: Cold boot initialization */
/* 0x1688: MOV DP, #04000h - Point to ROM for checksum? */
REG_DP = 0x4000;
/* 0x168B: MOVB A, [DP] - Read first byte */
uint8_t romByte = *(volatile uint8_t*)REG_DP;
/* 0x168D: ANDB A, #080h - Check high bit */
uint8_t configBit = romByte & 0x80;
/* Store boot configuration */
/* 0x1690: MOVB r1, #020h - Set life counter init */
uint8_t lifeInit = 0x20;
/* 0x1692: MOVB r2, #014h - Set some counter */
uint8_t counter2 = 0x14;
goto check_power_pin;
check_warm_reset:
/* label_169f: Check for warm reset (NMI recovery) */
/* 0x169F: CMPB 0EDh, #047h - Check for NMI error code */
if (g_errorCodeReboot == 0x47) {
/* Was NMI - treat as cold boot */
goto cold_boot;
}
/* 0x16A5: SB 0FDh.6 - Set warm reset flag */
f_flags_FD |= 0x40;
/* Preserve some state from before reset */
configBit = f_flags_FD;
lifeInit = g_unused_E9;
counter2 = g_errorCodeReboot;
/* 0x16B1: JBS 0EDh.3, label_16b6 - Check error bit */
if (g_errorCodeReboot & 0x08) {
goto check_power_pin;
}
/* 0x16B4: SB PSWL.4 - Set PSW bit 4 */
REG_PSWL |= 0x10;
check_power_pin:
/* label_16b6: Check main power before continuing */
/* 0x16B6: JBR P4.1, label_16bc - Check power pin */
if (!(REG_P4 & 0x02)) {
/* Power not stable - enter NMI handler */
isr_nonMaskableInterrupt();
return;
}
init_ports:
/* label_16bc: Initialize I/O ports */
/* 0x16BC: CLRB PRPHF - Clear peripheral flags */
REG_PRPHF = 0x00;
/* === Port 0: General purpose + CEL light + A/C === */
/* 0x16BF: MOVB P0, #09Fh - Initial port 0 state */
REG_P0 = 0x9F; /* CEL off (bit 6=1), A/C off (bit 7=1) */
/* 0x16C3: LB A, #0FFh - All bits output */
/* 0x16C5: STB A, P0IO - Set port 0 direction */
REG_P0IO = 0xFF; /* All outputs */
/* === Port 1: VTEC + CEL LED === */
/* 0x16C7: MOVB P1, #0FFh - Initial port 1 state */
REG_P1 = 0xFF; /* VTEC off, CEL LED off */
/* 0x16CB: STB A, P1IO - Set port 1 direction */
REG_P1IO = 0xFF; /* All outputs */
/* === Port 2: Fuel injectors === */
/* 0x16CD: MOVB P2, #01Fh - Initial port 2 state */
REG_P2 = 0x1F; /* All injectors OFF (1 = off) */
/* 0x16D1: STB A, P2IO - Set port 2 direction */
REG_P2IO = 0xFF; /* All outputs */
/* 0x16D3: MOVB P2SF, #000h - No special functions */
REG_P2SF = 0x00;
/* === Port 3: Ignition output === */
/* 0x16D7: STB A, P3 - Initial port 3 state */
REG_P3 = 0xFF;
init_serial:
/*
* DATALOGGING MODIFICATION:
* Serial port configured for 9600 baud datalogging
* instead of stock diagnostic rate.
*/
/* 0x16D9: MOVB STTMC, #002h - Serial TX timer control */
REG_STTMC = 0x02;
/* 0x16DD: MOVB STCON, #031h - Serial TX control (MODIFIED) */
REG_STCON = 0x31; /* Changed from 0x3C for datalogging */
/* 0x16E1: MOVB SRCON, #021h - Serial RX control (MODIFIED) */
REG_SRCON = 0x21; /* Changed from 0x2C for datalogging */
/* 0x16E5: MOVB STTM, #0FCh - Serial TX timer (MODIFIED) */
REG_STTM = 0xFC; /* Changed from 0xF3 for baud rate */
/* 0x16E9: MOVB STTMR, #0FCh - Serial TX timer reload (MODIFIED) */
REG_STTMR = 0xFC;
/* 0x16ED: MOVB SRTMC, #0C0h - Serial RX timer control */
REG_SRTMC = 0xC0;
/* 0x16F1: LB A, #064h - RX timer value */
/* 0x16F3: STB A, SRTM - Set RX timer */
/* 0x16F5: STB A, SRTMR - Set RX timer reload */
REG_SRTM = 0x64;
REG_SRTMR = 0x64;
init_external_io:
/* 0x16F7: CLRB EXION - Disable external I/O expansion */
REG_EXION = 0x00;
init_timers:
/* 0x16FA: CLR A - Clear accumulator for timer init */
/* === Timer 0: Injector timing / Ignition output === */
/* 0x16FB: MOVB TCON0, #08Ch - Timer 0 control */
REG_TCON0 = 0x8C; /* CLK/32, output mode, enabled */
/* 0x16FF: MOV TM0, #00001h - Timer 0 initial count */
REG_TM0 = 0x0001;
/* 0x1704: ST A, TMR0 - Timer 0 reload (0) */
REG_TMR0 = 0x0000;
/* === Timer 1: Main timing / RPM measurement === */
/* 0x1706: MOVB TCON1, #08Eh - Timer 1 control */
REG_TCON1 = 0x8E; /* CLK/32, capture mode */
/* 0x170A: ST A, TM1 - Timer 1 initial count (0) */
REG_TM1 = 0x0000;
/* 0x170C: ST A, TMR1 - Timer 1 reload (0) */
REG_TMR1 = 0x0000;
/* === Timer 2: Ignition coil dwell === */
/* 0x170E: MOVB TCON2, #08Fh - Timer 2 control */
REG_TCON2 = 0x8F; /* CLK/32, compare mode */
/* 0x1712: MOV TM2, #00001h - Timer 2 initial count */
REG_TM2 = 0x0001;
/* 0x1717: ST A, TMR2 - Timer 2 reload (0) */
REG_TMR2 = 0x0000;
/* === Timer 3: Auxiliary === */
/* 0x1719: MOVB TCON3, #08Fh - Timer 3 control */
REG_TCON3 = 0x8F;
init_port3_4:
/* 0x171D: MOVB P3IO, #041h - Port 3 direction */
REG_P3IO = 0x41; /* Ignition output + some inputs */
/* 0x1721: MOVB P3SF, #06Fh - Port 3 special functions */
REG_P3SF = 0x6F; /* Timer outputs enabled */
/* 0x1725: MOVB P4, #0FFh - Port 4 initial state */
REG_P4 = 0xFF;
init_pwm:
/* 0x1729: L A, #0FF00h - PWM initial value (off) */
uint16_t pwmInit = 0xFF00;
/* === PWM 0: IACV duty cycle === */
/* 0x172C: MOVB PWCON0, #02Eh - PWM 0 control */
REG_PWCON0 = 0x2E;
/* 0x1730: ST A, PWMC0 - PWM 0 counter */
REG_PWMC0 = pwmInit;
/* 0x1732: ST A, PWMR0 - PWM 0 reload */
REG_PWMR0 = pwmInit; /* Initially off (max duty = no air) */
/* === PWM 1: Auxiliary === */
/* 0x1734: MOVB PWCON1, #06Eh - PWM 1 control */
REG_PWCON1 = 0x6E;
/* 0x1738: ST A, PWMC1 - PWM 1 counter */
REG_PWMC1 = pwmInit;
/* 0x173A: ST A, PWMR1 - PWM 1 reload */
REG_PWMR1 = pwmInit;
init_port4:
/* 0x173C: MOVB P4IO, #00Dh - Port 4 direction */
REG_P4IO = 0x0D;
/* 0x1740: MOVB P4SF, #0BCh - Port 4 special functions */
REG_P4SF = 0xBC;
enable_timers:
/* 0x1744: SB TCON1.4 - Enable Timer 1 */
REG_TCON1 |= 0x10;
/* 0x174A: SB TCON2.4 - Enable Timer 2 */
REG_TCON2 |= 0x10;
/* 0x174D: CLR IRQ - Clear all pending interrupts */
REG_IRQ = 0x0000;
wait_for_power_stable:
/*
* Wait loop to ensure power supply is stable before
* continuing. Checks power pin repeatedly.
*/
/* 0x1750-0x177C: Power stability check loop */
uint8_t waitCounter;
for (int i = 0; i < 4; i++) {
/* Wait for power stable high */
waitCounter = 0x60;
while (waitCounter > 0) {
waitCounter--;
if (!(REG_P4 & 0x02)) break; /* Power dipped */
}
if (waitCounter == 0) {
/* Power not stable - error */
g_errorCodeReboot = 0x4C; /* Power error code */
asm("BRK"); /* Trigger reset */
}
}
test_ram:
/* 0x178F-0x17A7: RAM test loop */
/* Tests RAM by writing patterns and reading back */
uint16_t testAddr;
if (REG_PSW & 0x10) {
testAddr = 0x0269;
} else {
testAddr = 0x027F;
}
while (testAddr >= 0x0086) {
uint8_t testVal = 0x55;
*(volatile uint8_t*)testAddr = testVal;
if (*(volatile uint8_t*)testAddr != testVal) {
g_errorCodeReboot = 0x42; /* RAM error */
asm("BRK");
}
testVal = 0xAA; /* Shifted pattern */
*(volatile uint8_t*)testAddr = testVal;
if (*(volatile uint8_t*)testAddr != testVal) {
g_errorCodeReboot = 0x42; /* RAM error */
asm("BRK");
}
*(volatile uint8_t*)testAddr = 0; /* Clear */
testAddr--;
}
restore_state:
/* 0x17A9-0x17B6: Restore preserved state from registers */
f_flags_FD = configBit;
g_unused_E9 = lifeInit;
g_errorCodeReboot = counter2;
init_adc:
/* 0x17B7: CLR A - Clear accumulator */
/* 0x17B8: ST A, IE - Disable interrupts for ADC init */
REG_IE = 0x0000;
/* 0x17BA: CLR DP - Clear data pointer */
REG_DP = 0x0000;
/* Delay loop for ADC stabilization */
/* 0x17BC-0x17C1: Short delay */
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 17; j++) {
/* Busy wait */
}
}
/* 0x17C3: CLRB ADSEL - Select ADC channel 0 */
REG_ADSEL = 0x00;
/* 0x17C6: MOVB ADSCAN, #010h - Enable ADC scan mode */
REG_ADSCAN = 0x10;
/* 0x17CA: MOVB 0EBh, #001h - Initialize life counter */
g_lifeCounter = 0x01;
wait_for_adc:
/* 0x17CE-0x17DC: Wait for ADC to complete first scan */
REG_IRQH &= ~0x10; /* Clear A/D complete flag */
/* Wait for conversion complete */
while (!(REG_IRQH & 0x10)) {
/* Check injector pins while waiting */
if ((REG_P2 & 0xE0) != 0) {
continue; /* Injector activity - keep waiting */
}
break;
}
read_initial_sensors:
/* 0x17DE-0x180E: Read initial sensor values */
/* Read PA (atmospheric pressure) sensor */
g_atmPressure = REG_ADCR4;
/* Read battery/alternator voltage */
g_alternatorVolts = REG_ADCR6H;
/* Read MAP sensor */
g_mapSensorRaw = REG_ADCR5;
g_mapInitialHigh = g_mapSensorRaw >> 8; /* High byte for code 5 check */
/* Set initial MAP image */
g_mapImageRaw = 0xA0; /* Default ~100 kPa */
/* Read TPS */
g_tpsRaw = REG_ADCR7;
/* Set default temperature values (cold engine assumed) */
g_tempProcessed = 0x3C; /* ~60°C default */
g_iatProcessed = 0x57; /* ~25°C default */
g_unused_EE = 0x94; /* Temp scratch */
/* Initialize TPS delta values */
g_tpsDelta = 0x2B;
g_tpsCopy = 0x2B;
g_tpsDeltaOld = 0x80;
g_tpsRelated = 0x80;
/* Initialize ground reference */
g_groundReference = 0x80;
/* 0x1810: SB off(001Eh).7 - Set initialization flag */
f_flags_11E |= 0x80;
/* Continue with sensor calibration and main loop entry... */
/* (Additional initialization code continues at 0x1813+) */
/*
* After initialization, control passes to vcal_4_mainProcessing()
* which contains the main ECU loop.
*/
}
/*============================================================================
* SECTION 7: MAIN ENGINE CALCULATIONS
* ============================================================================
*
* Core engine control algorithms including:
* - RPM calculation from timer captures
* - MAP sensor processing and filtering
* - Fuel map lookups and corrections
* - Ignition map lookups and corrections
* - Injector pulse width calculations
*
*============================================================================*/
/**
* calc_rpmFromTimerCapture() - Calculate RPM from timer capture values
*
* Address: 0x0416 and related (scattered)
*
* RPM = 1,851,562.5 / timer_count
*
* Timer counts the time between CKP pulses (45° of crank rotation).
* Lower count = higher RPM.
*/
void calc_rpmFromTimerCapture(void)
{
/*
* RPM calculation is performed in the timer ISR.
* The 32-bit division is done using the OKI 66201's MUL/DIV
* instructions with the coefficient 0x1C4000 (1,851,562).
*
* Steps:
* 1. Capture timer value at CKP edge
* 2. Calculate delta from previous capture
* 3. Store in rotating 4-sample buffer
* 4. Average 4 samples for stability
* 5. Convert to RPM for map indexing
*/
/* Sample: divide RPM coefficient by timer count */
uint32_t rpmCoef = 0x001C4000; /* 1,851,562.5 truncated */
uint16_t timerCount = g_rpmTimerCount;
if (timerCount > 0) {
uint16_t rpmValue = rpmCoef / timerCount;
g_rpmIndexNonVtec = rpmValue >> 8; /* High byte for table lookup */
}
}
/**
* calc_rpmAveraging() - Average RPM samples for stability
*
* Uses a 4-sample rotating buffer at 0x0206-0x020C.
* Result stored in g_rpmAverage (0xBE).
*/
void calc_rpmAveraging(void)
{
/*
* Average calculation:
* g_rpmAverage = (sample0 + sample1 + sample2 + sample3) / 4
*
* Then asymptotic smoothing:
* g_rpmSmoothed = g_rpmSmoothed * 0.8 + g_rpmAverage * 0.2
* (Approximately - actual uses fixed-point math)
*/
uint32_t sum = g_rpmSample0 + g_rpmSample1 + g_rpmSample2 + g_rpmSample3;
g_rpmAverage = sum >> 2; /* Divide by 4 */
/* Asymptotic smoothing (simplified) */
uint16_t oldSmoothed = g_rpmSmoothed;
g_rpmSmoothed = (oldSmoothed * 13 + g_rpmAverage * 3) >> 4;
}
/**
* calc_mapSensorProcessing() - Process MAP sensor with filtering
*
* Processes raw MAP ADC value through:
* 1. Low-pass filtering
* 2. Delta MAP calculation (acceleration enrichment)
* 3. Conversion to map index (0-DF)
*/
void calc_mapSensorProcessing(void)
{
/*
* MAP processing steps:
*
* 1. Read raw ADC value from ADCR5 (10-bit, 0-1023)
* 2. Filter to remove noise
* 3. Calculate delta from previous for accel enrichment
* 4. Convert to 8-bit index (high nibble = column, low = interp)
*
* MAP Image format (g_mapImageFinal at 0xB5):
* Bits 7-4: Column index (0-D for fuel/ign maps)
* Bits 3-0: Interpolation fraction
*/
/* Read raw MAP */
uint16_t mapRaw = REG_ADCR5;
g_mapSensorRaw = mapRaw;
/* Low-pass filter: filtered = filtered * 0.9 + raw * 0.1 */
uint16_t oldFiltered = g_mapFiltered;
g_mapFiltered = (oldFiltered * 9 + mapRaw) / 10;
/* Calculate MAP image for table lookup */
/* Scale from ADC range to 0-DF range */
uint8_t mapImage = (g_mapFiltered >> 4) & 0xDF;
g_mapImageRaw = mapImage;
/* Delta MAP for acceleration enrichment */
int16_t mapDelta = mapRaw - oldFiltered;
g_mapDeltaCalc = (mapDelta > 0) ? (mapDelta >> 4) : 0;
/* Apply delta correction */
g_mapImageFinal = mapImage + g_mapDeltaCalc;
if (g_mapImageFinal > 0xDF)
g_mapImageFinal = 0xDF;
}
/**
* calc_fuelFromMaps() - Look up fuel value from 3D maps
*
* Address: 0x08B3 and related
*
* Uses RPM (row) and MAP (column) to look up base fuel value.
* Selects VTEC or non-VTEC map based on VTEC state.
*/
void calc_fuelFromMaps(void)
{
/*
* 3D fuel map lookup:
*
* Row selection: based on g_rpmIndexNonVtec or g_rpmIndexVtec
* Column selection: based on g_mapImageFinal high nibble
* Interpolation: between 4 cells using low nibbles
*
* Maps are located in ROM:
* Non-VTEC fuel: 0x4000-0x4FFF typically
* VTEC fuel: 0x5000-0x5FFF typically
*/
/* Determine which map to use */
uint16_t fuelValue;
if (f_vtecFlags & 0x80) {
/* VTEC is ON - use VTEC map */
fuelValue = vcal_5_fuelMapLookup(); /* VCAL 5 */
g_fuelMapVtec = fuelValue;
} else {
/* VTEC is OFF - use non-VTEC map */
fuelValue = vcal_5_fuelMapLookup();
g_fuelMapNonVtec = fuelValue;
}
/* Apply base corrections (ECT, IAT) */
/* Formula: main_fuel = map_value * correction_factor / 65536 */
uint32_t corrected = (uint32_t)fuelValue * g_fuelScaler;
g_fuelMainFinal = corrected >> 16;
}
/**
* calc_ignitionFromMaps() - Look up ignition from 3D maps
*
* Address: 0x07xx and related (via VCAL 6/7)
*
* Similar to fuel, uses RPM and MAP to determine base timing.
*/
void calc_ignitionFromMaps(void)
{
/*
* Ignition map lookup:
*
* Returns timing in degrees BTDC (Before Top Dead Center)
* Value range: approximately 0-60 degrees
*
* Maps located in ROM:
* Non-VTEC ignition: 0x6000-0x6FFF typically
* VTEC ignition: 0x7000-0x7FFF typically
*/
uint8_t ignValue;
if (f_vtecFlags & 0x80) {
/* VTEC ON - use VTEC ignition map */
ignValue = vcal_7_ignMapLookupVtec(); /* VCAL 7 */
} else {
/* VTEC OFF - use non-VTEC map */
ignValue = vcal_6_ignMapLookup(); /* VCAL 6 */
}
g_ignitionMapRaw = ignValue;
/* Apply corrections: ECT, knock, idle, etc. */
int8_t finalIgn = ignValue;
finalIgn += g_ignitionEctTrim; /* ECT correction */
finalIgn -= g_knockRetard; /* Knock retard (subtract) */
finalIgn += g_ignitionBrake; /* Brake switch correction */
finalIgn += g_ignitionIdleAdj; /* Idle connector adjustment */
/* Clamp to valid range */
if (finalIgn < 0) finalIgn = 0;
if (finalIgn > 60) finalIgn = 60;
g_ignitionFinal = finalIgn;
g_ignitionInverse = (~finalIgn) + 1; /* 2's complement for timer calc */
}
/**
* calc_injectorPulseWidth() - Calculate final injector pulse width
*
* Address: 0x0270 area
*
* Combines base fuel with all corrections for final pulse width.
*/
void calc_injectorPulseWidth(void)
{
/*
* Final fuel pulse width calculation:
*
* g_finalFuelPulse = (g_fuelMainFinal * O2_trim / 65536) * 2 + g_fuelCorrections
*
* Where:
* g_fuelMainFinal = base fuel from map with some corrections
* O2_trim = closed-loop O2 correction (0x162 or 0x164)
* g_fuelCorrections = all additive corrections (battery, etc.)
*/
/* Get O2 trim based on cylinder bank */
uint16_t o2Trim;
if (g_cylinderIndex & 0x01) {
o2Trim = g_o2TrimSecondary;
} else {
o2Trim = g_o2TrimPrimary;
}
/* Clamp O2 trim to safe range */
if (o2Trim > 0xB6E0) o2Trim = 0x944E;
if (o2Trim < 0x5720) o2Trim = 0x682A;
/* Calculate: (main * O2) >> 15 + corrections */
uint32_t product = (uint32_t)g_fuelMainFinal * o2Trim;
uint16_t scaledFuel = product >> 15;
uint16_t finalPulse = scaledFuel + g_fuelCorrections;
if (finalPulse < scaledFuel) finalPulse = 0xFFFF; /* Overflow check */
g_finalFuelPulse = finalPulse;
}
/**
* update_ignitorTiming() - Update ignition coil timing
*
* Address: 0x2911 (label: label_2911)
*
* Called from Timer1 compare ISR to set up next ignition event.
*/
void update_ignitorTiming(void)
{
/*
* Ignition timing update:
*
* Sets up Timer2 compare values to:
* 1. Start coil charging (dwell)
* 2. Fire the spark at the right moment
*
* TCON2.2 controls the ignitor output directly.
* TCON2.3 is the "primer" - loaded into .2 on compare match.
*/
/* Calculate dwell time based on battery voltage */
uint16_t dwellTime = 0x0400; /* Base dwell ~1ms */
/* Adjust for battery voltage (lower voltage = longer dwell) */
if (g_batteryVoltage < 0x80) {
dwellTime += (0x80 - g_batteryVoltage) * 4;
}
/* Set up Timer2 for spark event */
REG_TMR2 = REG_TM1 + g_ignitorTiming0;
/* Prime the ignitor output */
if (g_crankPosition == 3) {
REG_TCON2 |= 0x08; /* Set primer - coil will charge */
}
}
/**
* update_injectorOutputs() - Update injector port outputs
*
* Address: 0x28ED (label: label_28ed)
*
* Applies the calculated injector mask to Port 2.
*/
void update_injectorOutputs(void)
{
/*
* Injector output control:
*
* P2.0-P2.3 control injectors 1-4
* 0 = injector ON (grounded, current flowing)
* 1 = injector OFF
*
* g_injectorOutput contains the mask:
* 0x0F = all off, 0x0E = inj1 on, 0x0D = inj2 on, etc.
*/
/* Apply mask to port (injectors are active-low) */
REG_P2 = (REG_P2 & 0xF0) | (g_injectorOutput & 0x0F);
}
/**
* setup_injectorTimer() - Configure Timer0 for next injector event
*
* Address: 0x2906 (label: label_2906)
*/
void setup_injectorTimer(void)
{
/* Enable Timer0 compare interrupt */
REG_TCON0 |= 0x10;
}
/**
* process_rpmSignal() - Process RPM signal and set flags
*
* Address: 0x2995 (label: label_2995)
*/
void process_rpmSignal(void)
{
/*
* RPM processing:
* 1. Check if engine is running (RPM > threshold)
* 2. Calculate acceleration/deceleration
* 3. Update RPM-related flags
*/
/* Check engine running */
if (g_rpmTimerCountHi > 0x08) {
f_flags_120 |= 0x40; /* Engine running flag */
} else {
f_flags_120 &= ~0x40;
}
/* Check for acceleration */
if (g_rpmTimerCount < g_rpmHistory0) {
f_flags_11E |= 0x10; /* Accelerating */
} else {
f_flags_11E &= ~0x10; /* Decelerating */
}
}
/*============================================================================
* SECTION 8: VTEC CONTROL
* ============================================================================
*
* Honda VTEC (Variable Valve Timing and Lift Electronic Control)
* Changes cam profile at high RPM for better power.
*
* Address: 0x13xx area
*
*============================================================================*/
/**
* check_vtecConditions() - Check if VTEC should engage/disengage
*
* Conditions for VTEC engagement:
* 1. RPM above threshold (typically ~5000)
* 2. Vehicle speed above threshold (~20 mph)
* 3. Oil pressure sufficient (for solenoid)
* 4. No relevant error codes
* 5. Engine fully warmed up
*/
void check_vtecConditions(void)
{
/*
* VTEC flag byte (0x129) bit definitions:
* .3 = Speed threshold met
* .4 = RPM threshold 1 met
* .5 = RPM threshold 2 met
* .6 = All conditions primed
* .7 = VTEC IS ON
*/
/* Check speed threshold */
if (g_vehicleSpeedByte > 0x20) {
f_vtecFlags |= 0x08; /* Speed OK */
} else if (g_vehicleSpeedByte < 0x18) {
f_vtecFlags &= ~0x08; /* Speed too low - hysteresis */
}
/* Check RPM threshold */
uint8_t rpmThreshHigh = 0xC8; /* ~5000 RPM */
uint8_t rpmThreshLow = 0xB0; /* ~4500 RPM hysteresis */
if (g_rpmIndexVtec > rpmThreshHigh) {
f_vtecFlags |= 0x10; /* RPM high enough */
} else if (g_rpmIndexVtec < rpmThreshLow) {
f_vtecFlags &= ~0x10;
}
/* Check oil pressure */
if (g_oilPressure > 0x32) {
/* Oil pressure sufficient */
f_vtecFlags |= 0x20;
} else {
f_vtecFlags &= ~0x20;
}
/* Check if all conditions met */
if ((f_vtecFlags & 0x38) == 0x38) {
/* All conditions met */
if (!(f_vtecFlags & 0x80)) {
/* Not currently engaged - engage now */
engage_vtecSolenoid();
}
} else {
/* Conditions not met */
if (f_vtecFlags & 0x80) {
/* Currently engaged - disengage */
disengage_vtecSolenoid();
}
}
}
/**
* engage_vtecSolenoid() - Activate VTEC solenoid
*/
void engage_vtecSolenoid(void)
{
/* Set VTEC output (P1.1 = 1) */
REG_P1 |= 0x02;
/* Set VTEC engaged flag */
f_vtecFlags |= 0x80;
/* Start engage timer */
c_vtecEngageTimer = 0x14; /* ~200ms verification delay */
}
/**
* disengage_vtecSolenoid() - Deactivate VTEC solenoid
*/
void disengage_vtecSolenoid(void)
{
/* Clear VTEC output (P1.1 = 0) */
REG_P1 &= ~0x02;
/* Clear VTEC engaged flag */
f_vtecFlags &= ~0x80;
/* Clear engage timer */
c_vtecEngageTimer = 0;
}
/*============================================================================
* SECTION 9: O2 SENSOR CLOSED LOOP
* ============================================================================
*
* Closed-loop fuel control using oxygen sensor feedback.
* Adjusts fuel trim to maintain stoichiometric air-fuel ratio.
*
* Address: 0x25xx area
*
*============================================================================*/
/**
* process_o2Feedback() - Process O2 sensor for closed-loop control
*
* Primary O2 sensor at 0x162, Secondary at 0x164.
* Lean = sensor value < 0x1F
* Rich = sensor value > 0x1F
*/
void process_o2Feedback(void)
{
/*
* O2 closed-loop operation:
*
* If sensor reads LEAN (< 0x1F):
* Increase fuel trim (richer)
* If sensor reads RICH (> 0x1F):
* Decrease fuel trim (leaner)
*
* Uses integrator for smooth corrections.
* Rate limited to prevent oscillation.
*/
/* Check if closed-loop conditions met */
if (g_openClosedLoop == 0) {
/* Open loop - no O2 correction */
g_o2TrimPrimary = 0x8000; /* Neutral (1.0x) */
g_o2TrimSecondary = 0x8000;
return;
}
/* Process primary O2 sensor */
int16_t o2Reading = g_o2Sensor1_raw;
int16_t error = 0x1F - o2Reading; /* Target is 0x1F (stoich) */
/* Integrator with limits */
int32_t newTrim = g_o2TrimPrimary + (error * 16);
/* Clamp to valid range */
if (newTrim < 0x5720) newTrim = 0x5720; /* Min ~0.7x */
if (newTrim > 0xB6E0) newTrim = 0xB6E0; /* Max ~1.4x */
g_o2TrimPrimary = newTrim;
/* Similar for secondary (if equipped) */
o2Reading = g_o2Sensor2_raw;
error = 0x1F - o2Reading;
newTrim = g_o2TrimSecondary + (error * 16);
if (newTrim < 0x5720) newTrim = 0x5720;
if (newTrim > 0xB6E0) newTrim = 0xB6E0;
g_o2TrimSecondary = newTrim;
}
/**
* calc_o2FuelTrim() - Calculate O2-based fuel correction
*
* Combines primary and secondary O2 readings into final trim.
*/
void calc_o2FuelTrim(void)
{
/* Use primary or secondary based on cylinder */
/* Bank 1 (cyl 1,3) uses primary, Bank 2 (cyl 2,4) uses secondary */
/* (This is simplified - actual may vary by configuration) */
}
/*============================================================================
* SECTION 10: IDLE AIR CONTROL (IACV)
* ============================================================================
*
* Controls idle speed via PWM-controlled bypass air valve.
*
* Address: 0x1Axx area
*
*============================================================================*/
/**
* calc_idleAirControl() - Calculate IACV duty cycle
*
* Uses PID-style control to maintain target idle RPM.
* Target varies with coolant temperature (higher when cold).
*/
void calc_idleAirControl(void)
{
/*
* IACV Control Algorithm:
*
* 1. Determine target idle RPM from ECT (cold = higher)
* 2. Calculate error (current - target)
* 3. Apply proportional + integral correction
* 4. Add A/C load compensation if needed
* 5. Clamp to valid duty cycle range
*/
/* Get target idle from ECT lookup */
uint16_t targetIdle = g_targetIdleRpm;
/* Calculate RPM error */
int16_t rpmError = g_rpmTimerCount - targetIdle;
g_idleRpmError = (rpmError < 0) ? -rpmError : rpmError;
/* If RPM below target, increase air (lower duty = more air) */
/* If RPM above target, decrease air (higher duty = less air) */
int16_t correction;
if (rpmError > 0) {
/* RPM too high - need less air */
correction = rpmError >> 4;
if (g_iacvDutyCycle < 0xE000) {
g_iacvDutyCycle += correction;
}
} else {
/* RPM too low - need more air */
correction = (-rpmError) >> 4;
if (g_iacvDutyCycle > 0x2000) {
g_iacvDutyCycle -= correction;
}
}
/* A/C compensation - open more when A/C is on */
if (g_externalInputs & 0x40) { /* A/C switch on */
if (g_iacvDutyCycle > 0x1000) {
g_iacvDutyCycle -= 0x0800; /* Add ~5% more air */
}
}
}
/**
* update_iacvDuty() - Apply IACV duty cycle to PWM
*
* Called from PWM timer ISR.
*/
void update_iacvDuty(void)
{
/* Copy calculated duty to output register */
REG_PWMR0 = g_iacvDutyCycle;
}
/*============================================================================
* SECTION 11: ERROR CODE HANDLING
* ============================================================================
*
* Detects sensor faults and stores diagnostic trouble codes (DTCs).
* Blinks CEL light to communicate codes.
*
* Address: 0x2xxx area
*
*============================================================================*/
/**
* check_sensorErrors() - Check all sensors for out-of-range values
*
* Sets bits in f_celDetect1/2/3 (0x12C-0x12E) when faults detected.
* These are then copied to g_faultCode1/2/3 (0x130-0x132) for storage.
*/
void check_sensorErrors(void)
{
/*
* Sensor range checks:
*
* MAP: Should be 10-100 kPa (varies with altitude/load)
* TPS: Should be 0-100% (with valid idle offset)
* ECT: Should be -40 to 120°C (ADC values)
* IAT: Should be -40 to 80°C
* O2: Should oscillate when in closed loop
*/
/* MAP sensor check (Code 3) */
if (g_mapSensorRaw < 0x0100 || g_mapSensorRaw > 0x0F00) {
f_celDetect1 |= 0x01; /* Code 3: MAP sensor */
} else {
f_celDetect1 &= ~0x01;
}
/* ECT sensor check (Code 6) */
if (g_coolantTemp < 0x10 || g_coolantTemp > 0xF0) {
f_celDetect1 |= 0x02; /* Code 6: ECT */
} else {
f_celDetect1 &= ~0x02;
}
/* TPS sensor check (Code 7) */
if (g_tpsValue < 0x05 || g_tpsValue > 0xFA) {
f_celDetect1 |= 0x04; /* Code 7: TPS */
} else {
f_celDetect1 &= ~0x04;
}
/* IAT sensor check (Code 10) */
if (g_intakeAirTemp < 0x10 || g_intakeAirTemp > 0xF0) {
f_celDetect1 |= 0x80; /* Code 10: IAT */
} else {
f_celDetect1 &= ~0x80;
}
/* VTEC solenoid check (Code 21) */
if (f_vtecFlags & 0x80) { /* VTEC commanded ON */
if (!(g_externalInputs & 0x04)) { /* But feedback says OFF */
f_celDetect2 |= 0x40; /* Code 21: VTEC solenoid */
}
}
}
/**
* set_faultCode() - Set a fault code in permanent storage
*
* Address: 0x2F1B
*/
void set_faultCode(uint8_t code)
{
uint8_t byteIndex = (code - 1) / 8;
uint8_t bitMask = 1 << ((code - 1) % 8);
switch (byteIndex) {
case 0: g_faultCode1 |= bitMask; break;
case 1: g_faultCode2 |= bitMask; break;
case 2: g_faultCode3 |= bitMask; break;
}
}
/**
* blink_celLight() - Blink CEL to display stored codes
*
* Address: 0x20xx area
*
* Long blinks = tens digit
* Short blinks = ones digit
*/
void blink_celLight(void)
{
/*
* CEL blink pattern:
*
* For code 14:
* 1 long blink (tens)
* pause
* 4 short blinks (ones)
* long pause
* repeat
*
* Codes are displayed in sequence if multiple stored.
*/
/* Check if any codes to display */
uint8_t allCodes = g_celBlinkCode1 | g_celBlinkCode2 | g_celBlinkCode3;
if (allCodes == 0) {
/* No codes - CEL off */
REG_P0 |= 0x40; /* CEL light OFF (P0.6 = 1) */
REG_P1 &= ~0x04; /* ECU LED OFF (P1.2 = 0) */
return;
}
/* Display current code in sequence */
uint8_t currentCode = c_celBlinkIndex;
uint8_t tens = currentCode / 10;
uint8_t ones = currentCode % 10;
/* State machine for blink timing */
/* (Simplified - actual uses counters at 0x1CE-0x1FF) */
if (c_celBlinkCounter > 0) {
c_celBlinkCounter--;
/* Keep current state */
} else {
/* Toggle CEL */
REG_P0 ^= 0x40; /* Toggle P0.6 */
}
}
/**
* store_frozenFrame() - Capture freeze frame data on error
*/
void store_frozenFrame(void)
{
/*
* Freeze frame captures sensor values at time of fault:
* - RPM
* - MAP
* - TPS
* - ECT
* - IAT
* - Vehicle speed
*
* (Location varies by ROM version)
*/
}
/*============================================================================
* SECTION 12: VCAL TABLE LOOKUP FUNCTIONS
* ============================================================================
*
* Vector call (VCAL) routines for table lookups.
* These are called via the VCAL instruction using the vector table
* at 0x0028-0x0036.
*
*============================================================================*/
/**
* vcal_0_interpolate1D() - 1D Table Lookup with Interpolation
*
* Address: 0x2BF9 (label: vcal_0)
*
* Performs linear interpolation between two table entries.
*
* @param input - Input value (0-255)
* @param tableAddr - ROM address of lookup table
* @return Interpolated result
*/
uint8_t vcal_0_interpolate1D(uint8_t input, uint16_t tableAddr)
{
/*
* Table format:
* Byte 0: Number of entries
* Byte 1: X value 1
* Byte 2: Y value 1
* Byte 3: X value 2
* Byte 4: Y value 2
* ...
*
* Finds the two entries bracketing 'input' and interpolates.
*/
uint8_t* table = (uint8_t*)tableAddr;
uint8_t numEntries = table[0];
/* Find bracketing entries */
uint8_t i;
for (i = 0; i < numEntries - 1; i++) {
uint8_t x1 = table[1 + i * 2];
uint8_t x2 = table[1 + (i + 1) * 2];
if (input >= x1 && input <= x2) {
/* Found bracket */
uint8_t y1 = table[2 + i * 2];
uint8_t y2 = table[2 + (i + 1) * 2];
/* Linear interpolation */
int16_t dx = x2 - x1;
int16_t dy = y2 - y1;
int16_t offset = input - x1;
return y1 + (dy * offset / dx);
}
}
/* Out of range - return last value */
return table[numEntries * 2];
}
/**
* vcal_1_lookupInverted() - 1D Lookup with Inverted Result
*
* Address: 0x2C57 (label: vcal_1)
*
* Same as vcal_0 but result is inverted (255 - result).
*/
uint8_t vcal_1_lookupInverted(uint8_t input, uint16_t tableAddr)
{
return 255 - vcal_0_interpolate1D(input, tableAddr);
}
/**
* vcal_2_clampedLookup() - 1D Lookup with Clamped Range
*
* Address: 0x2C33 (label: vcal_2)
*
* Same as vcal_0 but clamps input to valid table range first.
*/
uint8_t vcal_2_clampedLookup(uint8_t input, uint16_t tableAddr)
{
uint8_t* table = (uint8_t*)tableAddr;
uint8_t minX = table[1];
uint8_t maxX = table[(table[0] - 1) * 2 + 1];
if (input < minX) input = minX;
if (input > maxX) input = maxX;
return vcal_0_interpolate1D(input, tableAddr);
}
/**
* vcal_3_tripletLookup() - 1D Lookup with 3-byte entries
*
* Address: 0x2C45 (label: vcal_3)
*
* Table has 3-byte entries (X, Y_high, Y_low) for 16-bit results.
*/
uint8_t vcal_3_tripletLookup(uint8_t input, uint16_t tableAddr)
{
/* Similar to vcal_0 but with 16-bit Y values */
/* Returns high byte of interpolated 16-bit result */
return vcal_0_interpolate1D(input, tableAddr); /* Simplified */
}
/**
* vcal_4_mainProcessing() - Main Loop Entry Point
*
* Address: 0x189B (label: vcal_4)
*
* This is the main ECU processing loop, called after initialization.
* Coordinates all sensor reading, calculations, and output updates.
*/
void vcal_4_mainProcessing(void)
{
/*
* Main processing loop:
*
* 1. Reset watchdog timer
* 2. Read ADC channels (ECT, IAT, TPS, etc.)
* 3. Process sensor values
* 4. Update fuel calculations
* 5. Update ignition calculations
* 6. Check VTEC conditions
* 7. Process O2 feedback
* 8. Update IACV duty
* 9. Check for error codes
* 10. Handle CEL blinking
* 11. Handle serial datalogging
*
* Loop repeats indefinitely while engine running.
*/
while (1) {
/* 1. Feed watchdog */
REG_WDT = 0x3C;
/* 2. Read sensors (ADC auto-scans, values in ADCR0-7) */
g_coolantTemp = REG_ADCR0H; /* Multiplexed via IC6 */
g_intakeAirTemp = REG_ADCR0H; /* Alternates with ECT */
g_alternatorVolts = REG_ADCR6H;
/* 3. Process MAP sensor */
calc_mapSensorProcessing();
/* 4. Calculate fuel */
calc_fuelFromMaps();
/* 5. Calculate ignition */
calc_ignitionFromMaps();
/* 6. Check VTEC */
check_vtecConditions();
/* 7. O2 feedback */
process_o2Feedback();
/* 8. Idle control */
calc_idleAirControl();
/* 9. Error code check */
check_sensorErrors();
/* 10. CEL blink */
if (f_flags_FE & 0x10) {
blink_celLight();
}
/* 11. Datalogging handled in serial RX ISR */
/* Clear periodic flags for next cycle */
f_flags_FE &= ~0x1E; /* Clear processed flags */
}
}
/**
* vcal_5_fuelMapLookup() - 3D Fuel Map Lookup
*
* Address: 0x2D96 (label: vcal_5)
*
* Performs bilinear interpolation on fuel map.
*/
uint16_t vcal_5_fuelMapLookup(void)
{
/*
* 3D map interpolation:
*
* 1. Use RPM index to select row
* 2. Use MAP image to select column
* 3. Interpolate between 4 surrounding cells
*
* Map format: 16x16 grid of 16-bit values
*/
uint8_t row = g_rpmIndexNonVtec >> 4; /* 0-15 */
uint8_t col = g_mapImageFinal >> 4; /* 0-15 */
uint8_t rowFrac = g_rpmIndexNonVtec & 0x0F; /* 0-15 */
uint8_t colFrac = g_mapImageFinal & 0x0F; /* 0-15 */
/* Get 4 corner values from map */
uint16_t* mapBase;
if (f_vtecFlags & 0x80) {
mapBase = (uint16_t*)0x5000; /* VTEC fuel map */
} else {
mapBase = (uint16_t*)0x4000; /* Non-VTEC fuel map */
}
uint16_t v00 = mapBase[row * 16 + col];
uint16_t v01 = mapBase[row * 16 + col + 1];
uint16_t v10 = mapBase[(row + 1) * 16 + col];
uint16_t v11 = mapBase[(row + 1) * 16 + col + 1];
/* Bilinear interpolation */
uint16_t v0 = v00 + ((v01 - v00) * colFrac) / 16;
uint16_t v1 = v10 + ((v11 - v10) * colFrac) / 16;
uint16_t result = v0 + ((v1 - v0) * rowFrac) / 16;
return result;
}
/**
* vcal_6_ignMapLookup() - 3D Ignition Map Lookup (Non-VTEC)
*
* Address: 0x2EB2 (label: vcal_6)
*/
uint16_t vcal_6_ignMapLookup(void)
{
/* Similar to vcal_5 but for ignition timing */
/* Returns timing value in degrees BTDC */
return 0; /* Placeholder */
}
/**
* vcal_7_ignMapLookupVtec() - 3D Ignition Map Lookup (VTEC)
*
* Address: 0x2EB4 (label: vcal_7)
*/
uint16_t vcal_7_ignMapLookupVtec(void)
{
/* VTEC ignition map - more aggressive timing */
return 0; /* Placeholder */
}
/*============================================================================
* SECTION 13: DATALOGGING MODIFICATIONS
* ============================================================================
*
* This section contains the datalogging code modifications
* that enable real-time tuning via serial communication.
*
* Original code modified by the tuning community.
*
*============================================================================*/
/**
* Datalogging Overview:
*
* The datalogging modification allows tuning software to:
* 1. Request any RAM location value
* 2. Log fuel and ignition map indices for real-time display
*
* Protocol:
* - Software sends a byte (RAM address to read)
* - ECU responds with the value at that address
*
* Serial configuration: 9600 baud, 8N1
*
* Key modifications from stock:
* 1. Serial port reconfigured for 9600 baud (was diagnostic rate)
* 2. isr_serialReceive modified to send RAM values
* 3. Stack relocated to 0x025B for buffer space
* 4. storerow() added to save map row indices
*/
/**
* storerow_forLogging() - Store fuel/ignition row indices
*
* Custom function added for datalogging.
* Saves the current fuel and ignition map row indices
* so tuning software can display which cells are active.
*/
void storerow_forLogging(void)
{
/*
* Called during fuel/ignition calculation.
* Stores row indices at known RAM locations so
* datalogging can read them.
*/
g_fuelRowIndex = g_rpmIndexNonVtec; /* 0x1D8 */
g_ignRowIndex = g_rpmIndexVtec; /* 0x1D9 */
}
/*
* Logging Table (ROM address 0x7F10)
*
* This table defines which RAM addresses are included in
* high-speed data logging. Each entry is a 16-bit address.
*/
#define LOGGING_TABLE_ADDR 0x7F10
const uint16_t logging_table[] = {
/* Address 0x7F10 - Logging entries */
0x00BA, /* g_rpmTimerCount - RPM */
0x00B5, /* g_mapImageFinal - MAP */
0x00AB, /* g_tpsValue - TPS */
0x0098, /* g_coolantTemp - ECT */
0x0099, /* g_intakeAirTemp - IAT */
0x00D6, /* g_finalFuelPulse - Fuel pulse width */
0x0134, /* g_ignitionFinal - Ignition timing */
0x0162, /* g_o2TrimPrimary - O2 correction */
0x0129, /* f_vtecFlags - VTEC status */
0x0130, /* g_faultCode1 - Error codes */
0x01D8, /* g_fuelRowIndex - Fuel map row */
0x01D9, /* g_ignRowIndex - Ignition map row */
0x0202, /* g_iacvDutyCycle - IACV duty */
0x00CB, /* g_vehicleSpeedByte - Speed */
0x00A5, /* g_alternatorVolts - Battery */
0xFFFF /* End marker */
};
/*============================================================================
* SECTION 14: DATA TABLE LOCATIONS
* ============================================================================
*
* ROM address map for calibration data tables.
*
* Note: Addresses are for Euro PW0 ROM. Other versions may differ.
*
*============================================================================*/
/*
* EURO PW0 ROM DATA MAP:
*
* 0x0000-0x0037: Interrupt vector table
* 0x0038-0x0066: Compressed code / constants
* 0x0067-0x189A: Main executable code
* 0x189B-0x2EFF: VCAL functions and subroutines
* 0x2F00-0x36FF: Lookup tables (1D)
* 0x3700-0x3FFF: Stock calibration data
* 0x4000-0x4FFF: Non-VTEC fuel maps
* 0x5000-0x5FFF: VTEC fuel maps
* 0x6000-0x6FFF: Non-VTEC ignition maps
* 0x7000-0x7EFF: VTEC ignition maps
* 0x7F00-0x7FFF: Option bytes and logging table
*/
/*
* KEY TABLE ADDRESSES (Euro PW0):
*
* Sensor Calibration:
* 0x38C9: RPM scaling table
* 0x38D7: Battery voltage table
* 0x3907: ECT error fallback
* 0x39BD: Temperature table
* 0x39E1: Idle RPM vs ECT
* 0x37CC: Fuel correction table
* 0x37D7: Voltage correction table
* 0x37E3: Battery voltage VCAL table
*
* Fuel Maps:
* 0x4000: Non-VTEC low RPM base fuel
* 0x4100: Non-VTEC mid RPM base fuel
* 0x4200: Non-VTEC high RPM base fuel
* 0x5000: VTEC fuel maps (same structure)
*
* Ignition Maps:
* 0x6000: Non-VTEC ignition timing
* 0x7000: VTEC ignition timing
*
* VTEC Settings:
* 0x7F00: VTEC engage RPM threshold
* 0x7F02: VTEC disengage RPM threshold
* 0x7F04: VTEC speed threshold
*
* Rev Limiter:
* 0x7F06: Rev limit RPM value
* 0x7F08: Rev limit fuel cut value
*
* Option Bytes:
* 0x7FF8: Delta TPS fuel scale
* 0x7FF9: Speed limiter enable
* 0x7FFA: A/C idle-up amount
* 0x7FFB: Cold start enrichment
*
* Datalogging (Modified):
* 0x7F10: Logging table (RAM addresses to log)
* 0x3262-0x32FA: Datalogging code patch area
*/
/*============================================================================
* HELPER FUNCTIONS / MACROS
* ============================================================================*/
/* Common patterns converted to inline functions */
/**
* feed_watchdog() - Reset watchdog timer
* Must be called periodically or ECU resets.
*/
static inline void feed_watchdog(void)
{
REG_WDT = 0x3C;
}
/**
* enable_interrupts() - Enable all configured interrupts
*/
static inline void enable_interrupts(void)
{
REG_IE = g_ieNormal;
}
/**
* disable_interrupts() - Disable all interrupts
*/
static inline void disable_interrupts(void)
{
REG_IE = 0x0000;
}
/**
* set_cel_on() - Turn on dashboard CEL light
*/
static inline void set_cel_on(void)
{
REG_P0 &= ~0x40; /* P0.6 = 0 (active low) */
}
/**
* set_cel_off() - Turn off dashboard CEL light
*/
static inline void set_cel_off(void)
{
REG_P0 |= 0x40; /* P0.6 = 1 */
}
/**
* all_injectors_off() - Turn off all fuel injectors
*/
static inline void all_injectors_off(void)
{
REG_P2 |= 0x0F; /* P2.0-3 = 1 (injectors off) */
}
/**
* calculate_rpm() - Get RPM from timer count
* @timer_count: Timer ticks for 45° rotation
* @return: RPM value
*/
static inline uint16_t calculate_rpm(uint16_t timer_count)
{
if (timer_count == 0) return 0;
return (uint16_t)(1851562UL / timer_count);
}
/*============================================================================
* END OF PSEUDO-C CONVERSION
* ============================================================================
*
* This file represents a complete pseudo-C conversion of the
* EuroPw0Datalogging.asm file (7079 lines of OKI 66201 assembly).
*
* Key sections converted:
* 1. Hardware register definitions (OKI 66201 specific)
* 2. RAM variable map with meaningful names
* 3. Interrupt vector table
* 4. All interrupt service routines
* 5. System initialization
* 6. Main engine calculations (RPM, MAP, fuel, ignition)
* 7. VTEC control logic
* 8. O2 sensor closed-loop
* 9. Idle air control (IACV)
* 10. Error code handling and CEL blinking
* 11. VCAL table lookup functions
* 12. Datalogging modifications
* 13. Data table locations
*
* For detailed assembly-level understanding, refer to:
* - Original EuroPw0Datalogging.asm file
* - OKI 66201 Instruction Manual
* - pw0ram.txt RAM documentation
*
*============================================================================*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment