mirror of
https://github.com/kalymos/PsNee.git
synced 2026-05-09 00:32:52 +00:00
338 lines
11 KiB
C
338 lines
11 KiB
C
#pragma once
|
|
|
|
/*
|
|
* ======================================================================================
|
|
* FUNCTION : Bios_Patching()
|
|
* TARGET : Data Bus (DX) synchronized via Address Bus (AX / AY)
|
|
*
|
|
* OPERATIONAL LOGIC:
|
|
* Intercepts specific memory transactions by monitoring address lines (AX/AY).
|
|
* Uses hardware interrupts (ISR) for high-speed pulse counting and cycle-accurate
|
|
* delays to inject modified data onto the Data line (DX) in real-time.
|
|
*
|
|
* KEY PHASES:
|
|
* 1. STABILIZATION & ALIGNMENT (AX): Synchronizes execution with a clean rising
|
|
* edge of the AX signal to establish a deterministic timing reference.
|
|
*
|
|
* 2. ADDRESS CALL DETECTION (PHASE 2): Scans the bus for specific address calls
|
|
* by validating consecutive polling blocks (SILENCE_THRESHOLD).
|
|
*
|
|
* 3. SILENCE CONFIRMATION (GATING): Counts the exact number of validated silence
|
|
* windows (CONFIRM_COUNTER_TARGET) to reach the correct pre-patching stage.
|
|
*
|
|
* 4. HARDWARE PULSE COUNTING (ISR): Uses INT0/INT1 to decrement the 'impulse'
|
|
* counter on each rising edge with minimal hardware latency.
|
|
*
|
|
* 5. DATA OVERDRIVE (DX): Upon reaching the target pulse, triggers a calibrated
|
|
* delay (BIT_OFFSET) and momentarily forces the DX pin to OUTPUT mode to
|
|
* overwrite the BIOS bit for a precise duration (OVERRIDE).
|
|
* ======================================================================================
|
|
*/
|
|
|
|
#ifdef BIOS_PATCH
|
|
|
|
/**
|
|
* Shared state variables between ISRs and the main patching loop.
|
|
* Declared 'volatile' to prevent compiler optimization during busy-wait loops.
|
|
*/
|
|
volatile uint8_t impulse = 0; // Down-counter for physical address pulses
|
|
volatile uint8_t patch = 0; // Synchronization flag (0: Idle, 1: AX Done, 2: AY Done)
|
|
|
|
/**
|
|
* PHASE 3: Primary Interrupt Service Routine (AX)
|
|
* Triggered on rising edges to perform the real-time bus override.
|
|
*/
|
|
ISR(PIN_AX_INTERRUPT_VECTOR) {
|
|
if (--impulse == 0) {
|
|
// Precise bit-alignment delay within the memory cycle
|
|
__builtin_avr_delay_cycles(BIT_OFFSET_CYCLES);
|
|
|
|
#ifdef PHASE_TWO_PATCH
|
|
PIN_DX_SET; // Pre-drive high if required by specific logic
|
|
#endif
|
|
|
|
// DATA OVERDRIVE: Pull the DX bus to the custom state
|
|
PIN_DX_OUTPUT;
|
|
__builtin_avr_delay_cycles(OVERRIDE_CYCLES);
|
|
|
|
#ifdef PHASE_TWO_PATCH
|
|
PIN_DX_CLEAR;
|
|
#endif
|
|
|
|
// BUS RELEASE: Return DX to High-Z (Input) mode
|
|
PIN_DX_INPUT;
|
|
|
|
PIN_AX_INTERRUPT_DISABLE; // Stop tracking AX pulses
|
|
PIN_LED_OFF;
|
|
patch = 1; // Signal Phase 3 completion
|
|
}
|
|
}
|
|
|
|
#ifdef PHASE_TWO_PATCH
|
|
/**
|
|
* PHASE 5: Secondary Interrupt Service Routine (AY)
|
|
* Handles the second injection stage if multi-patching is active.
|
|
*/
|
|
ISR(PIN_AY_INTERRUPT_VECTOR) {
|
|
if (--impulse == 0) {
|
|
__builtin_avr_delay_cycles(BIT_OFFSET_2_CYCLES);
|
|
|
|
PIN_DX_OUTPUT;
|
|
__builtin_avr_delay_cycles(OVERRIDE_2_CYCLES);
|
|
PIN_DX_INPUT;
|
|
|
|
PIN_AY_INTERRUPT_DISABLE;
|
|
PIN_LED_OFF;
|
|
patch = 2; // Signal Phase 5 completion
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void Bios_Patching(void) {
|
|
|
|
// --- HARDWARE BYPASS OPTION (SCPH-7000 specific) ---
|
|
#if defined(SCPH_7000)
|
|
PIN_SWITCH_INPUT; // Configure Pin D5 as Input
|
|
PIN_SWITCH_SET; // Enable internal Pull-up (D5 defaults to HIGH)
|
|
__builtin_avr_delay_cycles(10); // Short delay for voltage stabilization
|
|
|
|
/**
|
|
* Exit immediately if the switch pulls the pin to GND (Logic LOW).
|
|
* This allows the user to disable the BIOS patch on-the-fly.
|
|
*/
|
|
if (PIN_SWITCH_READ == 0) {
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
uint8_t current_confirms = 0;
|
|
//uint16_t count;
|
|
|
|
patch = 0; // Reset sync flag
|
|
sei(); // Enable Global Interrupts
|
|
PIN_AX_INPUT; // Set AX to monitor mode
|
|
|
|
// --- PHASE 1: STABILIZATION & ALIGNMENT ---
|
|
// Align execution pointer to a known rising edge state.
|
|
if (PIN_AX_READ != 0) {
|
|
while (WAIT_AX_FALLING); // Wait if bus is busy
|
|
while (WAIT_AX_RISING); // Sync with next pulse start
|
|
} else {
|
|
while (WAIT_AX_RISING); // Sync with upcoming pulse
|
|
}
|
|
|
|
// --- PHASE 2: SILENCE DETECTION ---
|
|
// Validate the exact number of silence windows to identify the boot stage.
|
|
while (current_confirms < CONFIRM_COUNTER_TARGET) {
|
|
uint16_t count = SILENCE_THRESHOLD;
|
|
while (count > 0) {
|
|
if (PIN_AX_READ != 0) {
|
|
while (WAIT_AX_FALLING);
|
|
break; // Impulse detected: retry current silence block
|
|
}
|
|
#ifdef IS_32U4_FAMILY
|
|
__asm__ __volatile__ ("nop");
|
|
#endif
|
|
|
|
count--;
|
|
}
|
|
if (count == 0) {
|
|
current_confirms++; // Validated one silence window
|
|
}
|
|
}
|
|
|
|
// --- PHASE 3: LAUNCH HARDWARE COUNTING (AX) ---
|
|
impulse = PULSE_COUNT;
|
|
PIN_LED_ON;
|
|
PIN_AX_INTERRUPT_CLEAR;
|
|
PIN_AX_INTERRUPT_RISING; // Setup rising-edge trigger
|
|
PIN_AX_INTERRUPT_ENABLE; // Engage ISR
|
|
|
|
while (patch != 1);
|
|
|
|
|
|
// --- PHASE 4 & 5: SECONDARY PATCHING SEQUENCE ---
|
|
#ifdef PHASE_TWO_PATCH
|
|
PIN_AY_INPUT;
|
|
current_confirms = 0;
|
|
impulse = PULSE_COUNT_2;
|
|
// Monitor for the specific silent gap before the second patch window
|
|
while (current_confirms < CONFIRM_COUNTER_TARGET_2) {
|
|
uint16_t count = SILENCE_THRESHOLD;
|
|
while (count > 0) {
|
|
if (PIN_AX_READ != 0) {
|
|
while (WAIT_AX_FALLING);
|
|
break;
|
|
}
|
|
|
|
#ifdef IS_32U4_FAMILY
|
|
__asm__ __volatile__ ("nop");
|
|
#endif
|
|
|
|
count--;
|
|
}
|
|
if (count == 0) {
|
|
current_confirms++;
|
|
}
|
|
}
|
|
|
|
PIN_LED_ON;
|
|
PIN_AY_INTERRUPT_CLEAR;
|
|
PIN_AY_INTERRUPT_FALLING;
|
|
PIN_AY_INTERRUPT_ENABLE;
|
|
|
|
while (patch != 2); // Busy-wait for secondary ISR completion
|
|
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Portability Note: The non-ISR (polling-based) version of the code is maintained
|
|
* to facilitate porting to other platforms and architectures that may not support
|
|
* AVR-specific hardware interrupts.
|
|
*
|
|
* Stability Limitation: While the polling version is more portable, it was found
|
|
* that at 16MHz, achieving consistent DATA OVERDRIVE stability is nearly impossible
|
|
* without using a Hardware ISR. The latency and jitter of software polling at this
|
|
* frequency are too high to guarantee a sub-microsecond cycle-accurate injection.
|
|
* Therefore, for ATmega328P @ 16MHz, the ISR-driven implementation remains the
|
|
* tandard.
|
|
*/
|
|
|
|
// #ifdef BIOS_PATCH
|
|
|
|
// volatile uint8_t impulse = 0;
|
|
// volatile uint8_t patch = 0;
|
|
|
|
|
|
// ISR(PIN_AX_INTERRUPT_VECTOR) {
|
|
// //impulse--;
|
|
// if (--impulse == 0){ // If impulse reaches the value defined by TRIGGER, the following actions are performed:
|
|
// // Precise cycle-accurate delay before triggering
|
|
// __builtin_avr_delay_cycles(BIT_OFFSET_CYCLES);
|
|
|
|
// #ifdef PHASE_TWO_PATCH
|
|
// PIN_DX_SET;
|
|
// #endif
|
|
|
|
// PIN_DX_OUTPUT; // Pull the line (Override start)
|
|
// __builtin_avr_delay_cycles(OVERRIDE_CYCLES);
|
|
|
|
// #ifdef PHASE_TWO_PATCH
|
|
// PIN_DX_CLEAR; // Release the bus (Override end)
|
|
// #endif
|
|
|
|
// PIN_DX_INPUT;
|
|
|
|
// PIN_LED_OFF;
|
|
// PIN_AX_INTERRUPT_DISABLE;
|
|
// patch = 1; // patch is set to 1, indicating that the first patch is completed.
|
|
// }
|
|
// }
|
|
|
|
// #ifdef PHASE_TWO_PATCH
|
|
|
|
|
|
// ISR(PIN_AY_INTERRUPT_VECTOR){
|
|
|
|
// //impulse--;
|
|
// if (--impulse == 0) // If impulse reaches the value defined by TRIGGER2, the following actions are performed:
|
|
// {
|
|
// __builtin_avr_delay_cycles(BIT_OFFSET_2_CYCLES);
|
|
|
|
// PIN_DX_OUTPUT;
|
|
// __builtin_avr_delay_cycles(OVERRIDE_2_CYCLES);
|
|
// PIN_DX_INPUT;
|
|
|
|
// PIN_AY_INTERRUPT_DISABLE;
|
|
// PIN_LED_OFF;
|
|
// patch = 2; // patch is set to 2, indicating that the second patch is completed.
|
|
// }
|
|
// }
|
|
// #endif
|
|
|
|
// // --- BIOS Patching Main Function ---
|
|
// void Bios_Patching(void) {
|
|
|
|
// uint8_t current_confirms = 0;
|
|
// uint8_t count = 0;
|
|
// patch = 0;
|
|
// sei();
|
|
// PIN_AX_INPUT;
|
|
// // --- PHASE 1: Signal Stabilization & Alignment (AX) ---
|
|
// if (PIN_AX_READ != 0) {
|
|
// while (WAIT_AX_FALLING); // Wait for falling edge
|
|
// while (WAIT_AX_RISING); // Wait for next rising edge to sync
|
|
// } else {
|
|
// while (WAIT_AX_RISING); // Wait for first rising edge
|
|
// }
|
|
|
|
// // --- PHASE 2: Silence Detection (AX) ---
|
|
|
|
// while (current_confirms < CONFIRM_COUNTER_TARGET) {
|
|
// uint16_t count = SILENCE_THRESHOLD;
|
|
|
|
// // --- Scan for ONE continuous block of silence ---
|
|
// while (count > 0) {
|
|
// if (PIN_AX_READ != 0) {
|
|
// while (WAIT_AX_FALLING); // Pulse detected: wait for bus to clear
|
|
// break; // Reset and try a new silence block
|
|
// }
|
|
// count--;
|
|
// }
|
|
|
|
// // If count reaches 0, a silent block is validated
|
|
// if (count == 0) {
|
|
// current_confirms++;
|
|
// }
|
|
// }
|
|
// impulse = PULSE_COUNT;
|
|
// PIN_LED_ON;
|
|
// PIN_AX_INTERRUPT_RISING;
|
|
// PIN_AX_INTERRUPT_ENABLE;
|
|
// while (patch != 1); // Wait for the first stage of the patch to complete:
|
|
|
|
// //PIN_LED_OFF;
|
|
// // -------- Secondary Patch ----------
|
|
// #ifdef PHASE_TWO_PATCH
|
|
|
|
// current_confirms = 0;
|
|
// while (current_confirms < CONFIRM_COUNTER_TARGET_2) {
|
|
// uint16_t count = SILENCE_THRESHOLD;
|
|
|
|
// while (count > 0) {
|
|
// if (PIN_AX_READ != 0) {
|
|
|
|
// while (WAIT_AX_FALLING);
|
|
// break;
|
|
// }
|
|
// count--;
|
|
// }
|
|
|
|
// if (count == 0) {
|
|
// current_confirms++;
|
|
// }
|
|
// }
|
|
|
|
// PIN_LED_ON;
|
|
// impulse = PULSE_COUNT_2;
|
|
// PIN_AY_INTERRUPT_RISING;
|
|
// PIN_AY_INTERRUPT_ENABLE;
|
|
|
|
// while (patch != 2); // Wait for the second stage of the patch to complete:
|
|
|
|
// #endif
|
|
|
|
// cli();
|
|
// }
|
|
// #endif
|
|
|
|
|