1
0
mirror of https://github.com/kalymos/PsNee.git synced 2026-05-08 16:32:17 +00:00

Refactor: Clean up SCPH and MCU pragma messages

This commit is contained in:
kalymos
2026-03-20 19:50:31 +01:00
parent 42b4e7aafe
commit 951e44937f
5 changed files with 1000 additions and 1150 deletions

View File

@@ -1,262 +1,337 @@
#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
uint8_t current_pulses = 0;
volatile uint8_t pulse_counter = 0;
volatile uint8_t patch_done = 0;
#ifdef TEST_BIOS
/**
* 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)
void Bios_Patching() {
PIN_DX_INPUT;
//PIN_DX_LOW;
/**
* 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);
cli(); // Disable interrupts for timing integrity
/*
* PHASE 1: Signal Stabilization & Alignment
* Synchronizes the MCU with the PS1 startup state (Cold Boot vs Reset).
*/
if (PIN_AX_READ != 0) { // Case: Power-on / Line high (---__-_-_)
while (PIN_AX_READ != 0); // Wait for falling edge
while (PIN_AX_READ == 0); // Sync on first clean rising edge
} else { // Case: Reset / Line low (_____-_-_)
while (PIN_AX_READ == 0); // Wait for rising edge
#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
}
}
/*
* PHASE 2: Address Bus Window Alignment
* Bypassing initial boot routines to reach one window with a
* known "idle gap" in the address bus activity, positioned
* immediately before the target memory-access cycle.
* BOOT_OFFSET: |----//----------|
* AX: ___-_-_//-_-_-________________-_-_
*/
_delay_ms(BOOT_OFFSET);
PIN_LED_ON;
#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);
/*
* PHASE 3: Edge Trigger
* Capture the moment AX go HIGH.
* Edge Triger: |
* AX: _-_-_-_-_-________________-_-_-_-_-_-__
*/
#ifdef LOW_TRIGGER
while (PIN_AX_READ);
#else
while (! PIN_AX_READ);
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
/*
* PHASE 4: Precision Bit Alignment
* Delay to shift from AX address edge to the DX data bit.
* BIT_OFFSET: |-------//-----|
* AX: _-_-_-_-_-________________-_-_-_-_//_-_-_-_
*/
_delay_us(BIT_OFFSET);
uint8_t current_confirms = 0;
//uint16_t count;
/*
* PHASE 5: Data Bus Overdrive (The Patch)
* Briefly forcing PIN_DX to OUTPUT to pull the line and "nullify" the target bit.
* This effectively overwrites the BIOS data on-the-fly
* before reverting the pin to INPUT to release the bus.
*/
PIN_DX_OUTPUT; // Force line (Low/High-Z override)
_delay_us(OVERRIDE);
PIN_DX_INPUT; // Release bus immediately
PIN_LED_OFF;
sei(); // Restore global interrupts
patch = 0; // Reset sync flag
sei(); // Enable Global Interrupts
PIN_AX_INPUT; // Set AX to monitor mode
patch_done = 1;
}
#endif
#ifdef HIGH_PATCH_A
ISR(PIN_AY_INTERRUPT_VECTOR){
pulse_counter++;
if (pulse_counter == PULSE_COUNT_2)
{
_delay_us (BIT_OFFSET_2);
PIN_DX_OUTPUT;
_delay_us (OVERRIDE_2);
PIN_DX_INPUT;
PIN_AY_INTERRUPT_DISABLE;
patch_done = 2;
}
// --- 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
}
void Bios_Patching(){
PIN_DX_INPUT;
cli(); // Disable interrupts for timing integrity
if (PIN_AX_READ != 0)
{
while (PIN_AX_READ != 0);
while (PIN_AX_READ == 0);
}
else
{
while (PIN_AX_READ == 0);
}
_delay_ms(BOOT_OFFSET);
PIN_LED_ON;
while (! PIN_AX_READ);
_delay_us(BIT_OFFSET);
PIN_DX_SET;
PIN_DX_OUTPUT; // Force line (Low/High-Z override)
_delay_us(OVERRIDE);
PIN_DX_CLEAR;
PIN_DX_INPUT; // Release bus immediately
PIN_LED_OFF;
sei(); // Restore global interrupts
PIN_LED_OFF;
_delay_ms(FOLLOWUP_OFFSET);
PIN_AY_INTERRUPT_RISING;
PIN_AY_INTERRUPT_ENABLE;
while (patch_done != 2);
// --- 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
}
}
#endif
// --- 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
#ifdef HIGH_PATCH_B
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
void Bios_Patching(){
PIN_DX_INPUT;
cli(); // Disable interrupts for timing integrity
if (PIN_AX_READ != 0)
{
while (PIN_AX_READ != 0);
while (PIN_AX_READ == 0);
}
else
{
while (PIN_AX_READ == 0);
}
_delay_ms(BOOT_OFFSET);
//PIN_LED_ON;
while (! PIN_AX_READ);
_delay_us(BIT_OFFSET);
PIN_DX_SET;
PIN_DX_OUTPUT; // Force line (Low/High-Z override)
_delay_us(OVERRIDE);
PIN_DX_CLEAR;
PIN_DX_INPUT; // Release bus immediately
PIN_LED_OFF;
sei(); // Restore global interrupts
//PIN_LED_OFF;
PIN_LED_ON;
while (PIN_AY_READ != 0);
_delay_ms(FOLLOWUP_OFFSET);
while (PIN_AY_READ);
_delay_us (BIT_OFFSET_2);
PIN_DX_OUTPUT;
_delay_us (OVERRIDE_2);
PIN_DX_INPUT;
PIN_LED_OFF;
}
#endif
#ifdef INTERRUPT_RISING_HIGH_PATCH
ISR(PIN_AX_INTERRUPT_VECTOR) {
pulse_counter++;
if (pulse_counter == PULSE_COUNT){
_delay_us (BIT_OFFSET);
PIN_DX_SET;
PIN_DX_OUTPUT;
_delay_us (OVERRIDE);
PIN_DX_CLEAR;
PIN_DX_INPUT;
PIN_AX_INTERRUPT_DISABLE;
pulse_counter = 0;
patch_done = 1;
}
}
ISR(PIN_AY_INTERRUPT_VECTOR){
pulse_counter++;
if (pulse_counter == PULSE_COUNT_2)
{
_delay_us (BIT_OFFSET_2);
PIN_DX_OUTPUT;
_delay_us (OVERRIDE_2);
PIN_DX_INPUT;
PIN_AY_INTERRUPT_DISABLE;
patch_done = 2;
}
}
void Bios_Patching(){
if (PIN_AX_READ != 0)
{
while (PIN_AX_READ != 0);
while (PIN_AX_READ == 0);
}
else
{
while (PIN_AX_READ == 0);
}
_delay_ms(BOOT_OFFSET);
PIN_AX_INTERRUPT_RISING;
PIN_AX_INTERRUPT_ENABLE;
while (patch_done != 1);
while (PIN_AY_READ != 0);
_delay_ms(FOLLOWUP_OFFSET);
PIN_LED_ON;
PIN_AY_INTERRUPT_RISING;
PIN_AY_INTERRUPT_ENABLE;
while (patch_done != 2);
PIN_LED_OFF;
}
#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

View File

@@ -93,14 +93,14 @@
#pragma once
<<<<<<< Updated upstream
=======
#if defined(__AVR_ATmega328__) || defined(__AVR_ATmega328A__) || \
defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PA__) || \
defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168P__) || \
defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega168PB__) || \
defined(__AVR_ATmega128A__) || defined(__AVR_ATmega128PB__)
#define IS_328_168_FAMILY
/*------------------------------------------------------------------------------------------------
* FUNCTION : optimizePeripherals()
*
@@ -113,59 +113,15 @@
* 3. CLOCK GATING (PRR): Shuts down clocks to TWI, SPI, and all Timers (0, 1, 2).
* 4. UART MAINTENANCE: Keeps PRUSART0 active to allow Serial communication.
------------------------------------------------------------------------------------------------*/
#define IS_328_168_FAMILY
static inline void OptimizePeripherals(void) {
// 1. Disable Interrupts during setup
cli();
>>>>>>> Stashed changes
#ifdef ATmega328_168
// 2. Analog Modules Shutdown (Critical for Power)
ADCSRA &= ~(1 << ADEN); // Disable ADC
ACSR |= (1 << ACD); // Disable Analog Comparator
<<<<<<< Updated upstream
static inline void optimizePeripherals(void) {
// Configuring Port C (A0-A5) as Digital Inputs
// DDRC at 0 = Input. Ensure that the first 6 bits are 0.
DDRC &= ~0x3F;
// Disable the ADC (Analog-to-Digital Converter)
// ADEN at 0 disables the module. PRADC at 1 disables the module's clock.
ADCSRA &= ~(1 << ADEN);
PRR |= (1 << PRADC);
// Configure DIDR0 (Digital Input Disable Register)
// To read digitally via PINC, the bits of DIDR0 MUST be set to 0.
// (0 = Digital Buffer enabled)
DIDR0 &= ~0x3F;
// Stop Timer 0 (Stops Arduino millis/micros)
// Setting TCCR0B to 0 stops the clock source. Setting TIMSK0 to 0 disables interrupts.
TCCR0B = 0;
//#define F TIMSK0 = 0;
// Disable the Analog Comparator (Frees up resources on PD6/PD7)
// ACD at 1 = Comparator off.
ACSR |= (1 << ACD);
}
// Define the clock speed for the microcontroller
#define F_CPU 16000000L
// Clear the timer count register (TCNT0)
//#define TIMER_TCNT_CLEAR TCNT0 = 0x00 // TCNT0 - Timer/Counter Register, clears the timer count
// Set OCR0A to achieve a 100KHz clock frequency
//#define SET_OCROA_DIV OCR0A = 159; // OCR0A Output Compare Register A, 100KHz clock generation, 0x10011111
// Configure Timer/Counter 0 for CTC mode and enable the clock source
//#define SET_TIMER_TCCROA TCCR0A |= (1 << WGM01); // TCCR0A Timer/Counter Control Register A, enable CTC mode (WGM01)
//#define SET_TIMER_TCCROB TCCR0B |= (1 << CS00); // TCCR0B Timer/Counter Control Register B, set clock source to I/O clock
//Waveform Generation Mode, Mode 2 CTC
// Interrupt vector for timer compare match event
//#define CTC_TIMER_VECTOR TIMER0_COMPA_vect //interrupt vector for match event, OCR0A comparison and Timer/Counter 0
=======
// 3. Digital Input Disable (Set bits to 1 to DISABLE)
// Disconnects digital buffers on analog pins to stop leakage
DIDR0 = 0xFF; // Pins A0 to A7
#if defined(__AVR_ATmega128PB__)
DIDR2 = 0xFF;
@@ -228,8 +184,6 @@ static inline void optimizePeripherals(void) {
TCCR4B = 0; TIMSK4 = 0; // Timer 4 (série PB)
#endif
}
>>>>>>> Stashed changes
#include <stdint.h>
#include <stdbool.h>
@@ -238,15 +192,10 @@ static inline void optimizePeripherals(void) {
#include <avr/sfr_defs.h>
#include <util/delay.h>
// Global interrupt control settings
#define GLOBAL_INTERRUPT_ENABLE SREG |= (1 << 7) // Set the I-bit (bit 7) in the Status Register to enable global interrupts
#define GLOBAL_INTERRUPT_DISABLE SREG &= ~(1 << 7) // Clear the I-bit (bit 7) in the Status Register to disable global interrupts
}
// Enable/Disable timer interrupts
//#define TIMER_INTERRUPT_ENABLE TIMSK0 |= (1 << OCIE0A) // Enable interrupt on Timer0 Compare Match A
//#define TIMER_INTERRUPT_DISABLE TIMSK0 &= ~(1 << OCIE0A) // Disable interrupt on Timer0 Compare Match A
// Main pin configuration for input and output
// Main pin configuration
// Define the main pins as inputs
#define PIN_DATA_INPUT DDRB &= ~(1 << DDB0) // Set DDRB register to configure PINB0 as input
@@ -254,82 +203,78 @@ static inline void optimizePeripherals(void) {
#define PIN_SQCK_INPUT DDRD &= ~(1 << DDD6) // Set DDRB register to configure PINB6 as input
#define PIN_SUBQ_INPUT DDRD &= ~(1 << DDD7) // Set DDRB register to configure PINB7 as input
// Enable pull-ups and set high on the main pins
// Configure lines as outputs (for injection/override)
#define PIN_DATA_OUTPUT DDRB |= (1 << DDB0) // Set DDRB register to configure PINB0 as output
#define PIN_WFCK_OUTPUT DDRB |= (1 << DDB1) // Set DDRB register to configure PINB1 as output
// Define pull-ups and set high at the main pin
#define PIN_DATA_SET PORTB |= (1 << PB0) // Set PORTB register to make PINB0 high (enable pull-up)
// Clear the main pins (set low)
// Bus line state control (Set High / Clear Low)
#define PIN_DATA_SET PORTB |= (1 << PB0) // Set PORTB register to make PINB0 high (enable pull-up))
#define PIN_DATA_CLEAR PORTB &= ~(1 << PB0) // Set PORTB register to make PINB0 low
#define PIN_WFCK_CLEAR PORTB &= ~(1 << PB1) // Set PORTB register to make PINB1 low
// Read the state of the main input pins
#define PIN_SQCK_READ (PIND & (1 << PIND6)) // Check if the value of PIND6 is high (1)
#define PIN_SUBQ_READ (PIND & (1 << PIND7)) // Check if the value of PIND7 is high (1)
#define PIN_WFCK_READ (PINB & (1 << PINB1)) // Check if the value of PIND1 is high (1)
// Direct Register Reading (High-speed polling)
#define PIN_SQCK_READ (!!(PIND & (1 << PIND6))) // Check if the value of PIND6 is high (1)
#define PIN_SUBQ_READ (!!(PIND & (1 << PIND7))) // Check if the value of PIND7 is high (1)
#define PIN_WFCK_READ (!!(PINB & (1 << PINB1))) // Check if the value of PIND1 is high (1)
// LED pin handling (for indication)
// --- Status Indication (LED) ---
#ifdef LED_RUN
#define PIN_LED_OUTPUT DDRB |= (1 << DDB5) // Configure PINB5 as output (for LED)
#define PIN_LED_ON PORTB |= (1 << PB5) // Set PINB5 high (turn on LED)
#define PIN_LED_OFF PORTB &= ~(1 << PB5) // Set PINB5 low (turn off LED)
#endif
// Handling the BIOS patch
#if defined(SCPH_102) || defined(SCPH_100) || defined(SCPH_7500_9000) || defined(SCPH_7000) || defined(SCPH_5500) || defined(SCPH_5000) || defined(SCPH_3500) || defined(SCPH_3000) || defined(SCPH_1000)
// --- BIOS Patching Configuration ---
#if defined(SCPH_102) || \
defined(SCPH_100) || \
defined(SCPH_7500_9000) || \
defined(SCPH_7000) || \
defined(SCPH_3500_5500) || \
defined(SCPH_3000) || \
defined(SCPH_1000)
// Clear the timer interrupt flag
//#define TIMER_TIFR_CLEAR TIFR0 |= (1 << OCF0A) // Clear the Timer0 Compare Match A interrupt flag
// Address (AX) and Data (DX) lines for BIOS override
#define PIN_DX_INPUT DDRD &= ~(1 << DDD4)
#define PIN_DX_OUTPUT DDRD |= (1 << DDD4)
#define PIN_DX_SET PORTD |= (1 << PD4)
#define PIN_DX_CLEAR PORTD &= ~(1 << PD4)
// Define input pins for the BIOS patch
#define PIN_AX_INPUT DDRD &= ~(1 << DDD2) // Set DDRD register to configure PIND2 as input
#define PIN_DX_INPUT DDRD &= ~(1 << DDD4) // Set DDRD register to configure PIND4 as input
#define PIN_AX_INPUT DDRD &= ~(1 << DDD2)
#define WAIT_AX_RISING (!(PIND & (1 << PIND2))) // Wait for pulse start (Blocking until Rising Edge)
#define WAIT_AX_FALLING (PIND & (1 << PIND2)) // Wait for pulse end (Blocking until Falling Edge)
#define PIN_AX_READ (!!(PIND & (1 << PIND2)))
// Define output pins for the BIOS patch
#define PIN_DX_OUTPUT DDRD |= (1 << DDD4) // Set DDRD register to configure PIND4 as output
// Hardware Interrupt (INT0) for AX pulse counting
#define PIN_AX_INTERRUPT_ENABLE EIMSK |= (1<<INT0) // Enable external interrupt on INT0 (PINB2)
#define PIN_AX_INTERRUPT_DISABLE EIMSK &= ~(1<<INT0) // Disable external interrupt on INT0
#define PIN_AX_INTERRUPT_RISING EICRA |= (1<<ISC01)|(1<<ISC00) // Configure INT0 for rising edge trigger
#define PIN_AX_INTERRUPT_VECTOR INT0_vect // Interrupt vector for INT0 (external interrupt)
#define PIN_AX_INTERRUPT_CLEAR EIFR |= (1 << INTF0)
// Set pull-ups high on output pins
#define PIN_DX_SET PORTD |= (1 << PD4) // Set PORTD register to make PIND4 high
// Set pull-ups low on output pins
#define PIN_DX_CLEAR PORTD &= ~(1 << PD4) // Set PORTD register to make PIND4 low
// Read the input pins for the BIOS patch
#define PIN_AX_READ (PIND & (1 << PIND2)) // Read the state of PIND2
// External interrupt configuration for BIOS patch
#define PIN_AX_INTERRUPT_ENABLE EIMSK |= (1 << INT0) // Enable external interrupt on INT0 (PINB2)
#define PIN_AX_INTERRUPT_DISABLE EIMSK &= ~(1 << INT0) // Disable external interrupt on INT0
#define PIN_AX_INTERRUPT_RISING EICRA |= (1 << ISC01) | (1 << ISC00) // Configure INT0 for rising edge trigger
#define PIN_AX_INTERRUPT_FALLING (EICRA = (EICRA & ~(1 << ISC00)) | (1 << ISC01)) // Configure INT0 for falling edge trigger
// Interrupt vectors for external interrupts
#define PIN_AX_INTERRUPT_VECTOR INT0_vect // Interrupt vector for INT0 (external interrupt)
// Defin PIN_AY for HIGH_PATCH
#if defined(SCPH_3000) || defined(SCPH_1000)
#define PIN_AY_INPUT DDRD &= ~(1 << DDD3) // Set DDRD register to configure PIND3 as input
#define PIN_AY_READ (PIND & (1 << PIND3)) // Read the state of PIND3
#define PIN_AY_INTERRUPT_ENABLE EIMSK |= (1 << INT1) // Enable external interrupt on INT1 (PINB3)
#define PIN_AY_INTERRUPT_DISABLE EIMSK &= ~(1 << INT1) // Disable external interrupt on INT1
#define PIN_AY_INTERRUPT_RISING EICRA |= (1 << ISC11) | (1 << ISC10) // Configure INT1 for rising edge trigger
#define PIN_AY_INTERRUPT_FALLING (EICRA = (EICRA & ~(1 << ISC10)) | (1 << ISC11)) // Configure INT1 for falling edge trigger
#define PIN_AY_INTERRUPT_VECTOR INT1_vect // Interrupt vector for INT1 (external interrupt)
// Secondary Address line (AY) for multi-stage patching (INT1)
#if defined(SCPH_3000) || \
defined(SCPH_1000)
#define PIN_AY_INPUT DDRD &= ~(1 << DDD3) // Set DDRD register to configure PIND3 as input
#define WAIT_AY_RISING (!(PIND & (1 << PIND3)))
#define WAIT_AY_FALLING (PIND & (1 << PIND3))
#define PIN_AY_INTERRUPT_ENABLE EIMSK |= (1<<INT1) // Enable external interrupt on INT1 (PINB3)
#define PIN_AY_INTERRUPT_DISABLE EIMSK &= ~(1<<INT1) // Disable external interrupt on INT1
#define PIN_AY_INTERRUPT_RISING EICRA |= (1<<ISC11)|(1<<ISC10) // Configure INT1 for rising edge trigger
#define PIN_AY_INTERRUPT_FALLING EICRA = (EICRA & ~((1 << ISC11) | (1 << ISC10))) | (1 << ISC11) // Configure INT1 for falling edge trigger
#define PIN_AY_INTERRUPT_VECTOR INT1_vect // Interrupt vector for INT1 (external interrupt)
#define PIN_AY_INTERRUPT_CLEAR EIFR |= (1 << INTF1)
#endif
// Handle switch input for BIOS patch
#if defined(SCPH_7000)
#define PIN_SWITCH_INPUT DDRD &= ~(1 << DDD5) // Configure PIND5 as input for switch
#define PIN_SWITCH_SET PORTD |= (1 << PD5) // Set PIND5 high (enable pull-up)
#define PIN_SWITCH_READ (PIND & (1 << PIND5)) // Read the state of PIND5 (switch input)
#endif
// Hardware Bypass Switch (On-the-fly deactivation)
#if defined(SCPH_7000)
#define PIN_SWITCH_INPUT DDRD &= ~(1 << DDD5) // Configure PIND5 as input for switch
#define PIN_SWITCH_SET PORTD |= (1 << PD5) // Set PIND5 high (enable pull-up)
#define PIN_SWITCH_READ (!!(PIND & (1 << PIND5))) // Read the state of PIND5 (switch input)
#endif
#endif
// #if defined(PSNEE_DEBUG_SERIAL_MONITOR)
// #define DEBUG_PRINT(x) Serial.print(x)
// #define DEBUG_PRINTHEX(x) Serial.print(x, HEX)
@@ -343,14 +288,6 @@ static inline void optimizePeripherals(void) {
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
#define IS_32U4_FAMILY
<<<<<<< Updated upstream
#define F_CPU 16000000L
// #define TIMER_TCNT_CLEAR TCNT0 = 0x00;
// #define SET_OCROA_DIV OCR0A = 159;
// #define SET_TIMER_TCCROA TCCR0A |= (1 << WGM01);
// #define SET_TIMER_TCCROB TCCR0B |= (1 << CS00);
// #define CTC_TIMER_VECTOR TIMER0_COMPA_vect
=======
static inline void OptimizePeripherals(void) {
// 1. Global Interrupt Disable during hardware reconfiguration
cli();
@@ -394,7 +331,6 @@ static inline void optimizePeripherals(void) {
TCCR4B = 0;
}
>>>>>>> Stashed changes
#include <stdint.h>
#include <stdbool.h>
@@ -403,103 +339,99 @@ static inline void optimizePeripherals(void) {
#include <avr/sfr_defs.h>
#include <util/delay.h>
// Globale interrupt seting
// #define GLOBAL_INTERRUPT_ENABLE SREG |= (1 << 7)
#define GLOBAL_INTERRUPT_DISABLE SREG &= ~(1 << 7)
// #define TIMER_INTERRUPT_ENABLE TIMSK0 |= (1 << OCIE0A)
// #define TIMER_INTERRUPT_DISABLE TIMSK0 &= ~(1 << OCIE0A)
// Handling the main pins
// --- Main Bus Interface (CD-ROM Controller) ---
// Main pins
#define PIN_DATA_INPUT DDRB &= ~(1 << DDB4)
#define PIN_WFCK_INPUT DDRB &= ~(1 << DDB5)
#define PIN_SQCK_INPUT DDRD &= ~(1 << DDD7)
#define PIN_SUBQ_INPUT DDRE &= ~(1 << DDE6)
// Define the main pins as inputs
#define PIN_DATA_INPUT DDRB &= ~(1 << DDB4) // DATA line (PB4)
#define PIN_WFCK_INPUT DDRB &= ~(1 << DDB5) // WFCK / GATE line (PB5)
#define PIN_SQCK_INPUT DDRD &= ~(1 << DDD7) // SQCK Clock (PD7)
#define PIN_SUBQ_INPUT DDRE &= ~(1 << DDE6) // SUBQ Data (PE6)
// Configure lines as outputs (for injection/override)
#define PIN_DATA_OUTPUT DDRB |= (1 << DDB4)
#define PIN_WFCK_OUTPUT DDRB |= (1 << DDB5)
// Define pull-ups and set high at the main pin
#define PIN_DATA_SET PORTB |= (1 << PB4)
// Define pull-ups set down at the main pin
#define PIN_DATA_CLEAR PORTB &= ~(1 << PB4)
#define PIN_WFCK_CLEAR PORTB &= ~(1 << PB5)
// Read the main pins
#define PIN_SQCK_READ (PIND & (1 << PIND7))
#define PIN_SUBQ_READ (PINE & (1 << PINE6))
#define PIN_WFCK_READ (PINB & (1 << PINB5))
// Bus line state control (Set High / Clear Low)
#define PIN_DATA_SET PORTB |= (1 << PB4) // Enable pull-up or drive HIGH
#define PIN_DATA_CLEAR PORTB &= ~(1 << PB4) // Drive line LOW
#define PIN_WFCK_CLEAR PORTB &= ~(1 << PB5) // Drive line LOW
// Handling and use of the LED pin
// Direct Register Reading (High-speed polling)
#define PIN_SQCK_READ (!!(PIND & (1 << PIND7)))
#define PIN_SUBQ_READ (!!(PINE & (1 << PINE6)))
#define PIN_WFCK_READ (!!(PINB & (1 << PINB5)))
// --- Status Indication (LED) ---
#ifdef LED_RUN
#define PIN_LED_OUTPUT DDRB |= (1 << DDB6)
#define PIN_LED_ON PORTB |= (1 << PB6)
#define PIN_LED_OFF PORTB &= ~(1 << PB6)
#define PIN_LED_OUTPUT DDRB |= (1 << DDB6) // LED on PB6
#define PIN_LED_ON PORTB |= (1 << PB6)
#define PIN_LED_OFF PORTB &= ~(1 << PB6)
#endif
// Handling the BIOS patch
#if defined(SCPH_102) || defined(SCPH_102_legacy) || defined(SCPH_100) || defined(SCPH_7000_9000) || defined(SCPH_5500) || defined(SCPH_3500_5000) || defined(SCPH_3000) || defined(SCPH_1000)
// Pins input
#define PIN_AX_INPUT DDRD &= ~(1 << DDD1)
#define PIN_AY_INPUT DDRD &= ~(1 << DDD0)
#define PIN_DX_INPUT DDRD &= ~(1 << DDD4)
// Pin output
#define PIN_DX_OUTPUT DDRD |= (1 << DDD4)
// Define pull-ups set high
#define PIN_DX_SET PORTD |= (1 << PD4)
// Define pull-ups set down
#define PIN_DX_CLEAR PORTD &= ~(1 << PD4)
// Read pins for BIOS patch
#define PIN_AX_READ (PIND & (1 << PIND1))
#define PIN_AY_READ (PIND & (1 << PIND0))
// Handling and reading the switch pin for patch BIOS
#ifdef PATCH_SWITCH
#define PIN_SWITCH_INPUT DDRC &= ~(1 << DDC6)
#define PIN_SWITCH_SET PORTC |= (1 << PC6)
#define PIN_SWITCH_READ (PINC & (1 << PINC6))
// --- BIOS Patching Configuration (32U4 Mapping) ---
#if defined(SCPH_102) || \
defined(SCPH_100) || \
defined(SCPH_7500_9000) || \
defined(SCPH_7000) || \
defined(SCPH_3500_5500) || \
defined(SCPH_3000) || \
defined(SCPH_1000)
// Address (AX) and Data (DX) lines for BIOS override
#define PIN_DX_INPUT DDRD &= ~(1 << DDD4) // DX on PD4
#define PIN_DX_OUTPUT DDRD |= (1 << DDD4)
#define PIN_DX_SET PORTD |= (1 << PD4)
#define PIN_DX_CLEAR PORTD &= ~(1 << PD4)
#define PIN_AX_INPUT DDRD &= ~(1 << DDD1) // AX on PD1 (INT1)
#define WAIT_AX_RISING (!(PIND & (1 << PIND1))) // Wait for pulse start
#define WAIT_AX_FALLING (PIND & (1 << PIND1)) // Wait for pulse end
#define PIN_AX_READ (PIND & (1 << PIND1))
// Hardware Interrupt (INT1) for AX pulse counting
#define PIN_AX_INTERRUPT_ENABLE EIMSK |= (1 << INT1)
#define PIN_AX_INTERRUPT_DISABLE EIMSK &= ~(1 << INT1)
#define PIN_AX_INTERRUPT_RISING EICRA |= (1 << ISC11) | (1 << ISC10)
#define PIN_AX_INTERRUPT_VECTOR INT1_vect
#define PIN_AX_INTERRUPT_CLEAR EIFR |= (1 << INTF1)
// Secondary Address line (AY) for multi-stage patching (INT0)
#if defined(SCPH_3000) || defined(SCPH_1000)
#define PIN_AY_INPUT DDRD &= ~(1 << DDD0) // AY on PD0 (INT0)
#define PIN_AY_READ (PIND & (1 << PIND0))
#define WAIT_AY_RISING (!(PIND & (1 << PIND0)))
#define WAIT_AY_FALLING (PIND & (1 << PIND0))
#define PIN_AY_INTERRUPT_ENABLE EIMSK |= (1 << INT0)
#define PIN_AY_INTERRUPT_DISABLE EIMSK &= ~(1 << INT0)
#define PIN_AY_INTERRUPT_RISING EICRA |= (1 << ISC01) | (1 << ISC00)
#define PIN_AY_INTERRUPT_VECTOR INT0_vect
#define PIN_AY_INTERRUPT_CLEAR EIFR |= (1 << INTF0)
#endif
// BIOS timer clear
#define TIMER_TIFR_CLEAR TIFR0 |= (1 << OCF0A)
// Handling the external interrupt
#define PIN_AX_INTERRUPT_ENABLE EIMSK |= (1 << INT1)
#define PIN_AY_INTERRUPT_ENABLE EIMSK |= (1 << INT0)
#define PIN_AX_INTERRUPT_DISABLE EIMSK &= ~(1 << INT1)
#define PIN_AY_INTERRUPT_DISABLE EIMSK &= ~(1 << INT0)
#define PIN_AX_INTERRUPT_RISING EICRA |= (1 << ISC11) | (1 << ISC10)
#define PIN_AY_INTERRUPT_RISING EICRA |= (1 << ISC01) | (1 << ISC00)
#define PIN_AX_INTERRUPT_FALLING (EICRA = (EICRA & ~(1 << ISC10)) | (1 << ISC11))
#define PIN_AY_INTERRUPT_FALLING (EICRA = (EICRA & ~(1 << ISC00)) | (1 << ISC01))
#define PIN_AX_INTERRUPT_VECTOR INT1_vect
#define PIN_AY_INTERRUPT_VECTOR INT0_vect
// Hardware Bypass Switch (On-the-fly deactivation)
#ifdef SCPH_7000
#define PIN_SWITCH_INPUT DDRC &= ~(1 << DDC6) // Bypass on PC6
#define PIN_SWITCH_SET PORTC |= (1 << PC6) // Enable pull-up
#define PIN_SWITCH_READ (!!(PINC & (1 << PINC6)))
#endif
#endif
#endif
<<<<<<< Updated upstream
#ifdef ATtiny85_45_25
=======
#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny25__)
#define IS_ATTINY_FAMILY
>>>>>>> Stashed changes
#define DF_CPU 8000000L
#define TIMER_TCNT_CLEAR TCNT0 = 0x00;
#define SET_OCROA_DIV OCR0A = 79; //OCR0A Output Compare Register A,100KHz
#define SET_TIMER_TCCROA TCCR0A |= (1 << WGM01);
#define SET_TIMER_TCCROB TCCR0B |= (1 << CS00);
#define CTC_TIMER_VECTOR TIMER0_COMPA_vect
static inline void OptimizePeripherals(void) {
// 1. Global Interrupt Disable during reconfiguration
cli();
<<<<<<< Updated upstream
=======
// 2. Analog Modules Shutdown
ADCSRA = 0; // Power off ADC completely
ACSR |= (1 << ACD); // Disable Analog Comparator
@@ -527,7 +459,7 @@ static inline void optimizePeripherals(void) {
WDTCR = 0x00;
}
>>>>>>> Stashed changes
#include <stdint.h>
@@ -537,58 +469,55 @@ static inline void optimizePeripherals(void) {
#include <avr/sfr_defs.h>
#include <util/delay.h>
// Globale interrupt seting
#define GLOBAL_INTERRUPT_ENABLE SREG |= (1 << 7)
#define GLOBAL_INTERRUPT_DISABLE SREG &= ~(1 << 7)
// --- Main Bus Interface (CD-ROM Controller) ---
// Handling the main pins
// Define the main pins as inputs
#define PIN_DATA_INPUT DDRB &= ~(1 << DDB2) // DATA line (PB2)
#define PIN_WFCK_INPUT DDRB &= ~(1 << DDB4) // WFCK / GATE line (PB4)
#define PIN_SQCK_INPUT DDRB &= ~(1 << DDB0) // SQCK Clock (PB0)
#define PIN_SUBQ_INPUT DDRB &= ~(1 << DDB1) // SUBQ Data (PB1)
// Main pins input
#define PIN_DATA_INPUT DDRB &= ~(1 << DDB2)
#define PIN_WFCK_INPUT DDRB &= ~(1 << DDB4)
#define PIN_SQCK_INPUT DDRB &= ~(1 << DDB0)
#define PIN_SUBQ_INPUT DDRB &= ~(1 << DDB1)
// Main pin output
// Configure lines as outputs (for injection/override)
#define PIN_DATA_OUTPUT DDRB |= (1 << DDB2)
#define PIN_WFCK_OUTPUT DDRB |= (1 << DDB4)
// Define pull-ups and set high at the main pin
#define PIN_DATA_SET PORTB |= (1 << PB2)
// Bus line state control (Set High / Clear Low)
#define PIN_DATA_SET PORTB |= (1 << PB2) // Enable pull-up or drive HIGH
#define PIN_DATA_CLEAR PORTB &= ~(1 << PB2) // Drive line LOW
#define PIN_WFCK_CLEAR PORTB &= ~(1 << PB4) // Drive line LOW
// Define pull-ups set down at the main pin
#define PIN_DATA_CLEAR PORTB &= ~(1 << PB2)
#define PIN_WFCK_CLEAR PORTB &= ~(1 << PB4)
// Direct Register Reading (High-speed polling)
#define PIN_SQCK_READ (PINB & (1 << PINB0))
#define PIN_SUBQ_READ (PINB & (1 << PINB1))
#define PIN_WFCK_READ (PINB & (1 << PINB4))
// Read the main pins
#define PIN_SQCK_READ (PINB & (1 << PINB0))
#define PIN_SUBQ_READ (PINB & (1 << PINB1))
#define PIN_WFCK_READ (PINB & (1 << PINB4))
#define TIMER_INTERRUPT_ENABLE TIMSK |= (1 << OCIE0A)
#define TIMER_INTERRUPT_DISABLE TIMSK &= ~(1 << OCIE0A)
// Handling and use of the LED pin
// --- Status Indication (LED) ---
#ifdef LED_RUN
#define PIN_LED_OUTPUT DDRB |= (1 << DDB3)
#define PIN_LED_ON PORTB |= (1 << PB3)
#define PIN_LED_OFF PORTB &= ~(1 << PB3)
#endif
#if defined(SCPH_1000) || defined(SCPH_3000) || defined(SCPH_3500_5000) || defined(SCPH_5500) || defined(SCPH_7000_9000) || defined(SCPH_100) || defined(SCPH_102_legacy) || defined(SCPH_102)
#error "ATtiny85_45_25 Not compatible with BIOS patch"
#define PIN_LED_OUTPUT DDRB |= (1 << DDB3) // LED on PB3
#define PIN_LED_ON PORTB |= (1 << PB3)
#define PIN_LED_OFF PORTB &= ~(1 << PB3)
#endif
// --- Debug Serial (Software Serial) ---
#if defined(PSNEE_DEBUG_SERIAL_MONITOR)
#include <SoftwareSerial.h>
SoftwareSerial mySerial(-1, 3); // RX, TX. (RX -1 = off)
// SoftwareSerial(RX, TX): RX set to -1 (disabled), TX on PB3
// Note: Resource conflict if LED_RUN is also on PB3
SoftwareSerial mySerial(-1, 3);
#define PIN_TXD_OUTPUT DDRB |= (1 << DDB3)
// #define DEBUG_PRINT(x) mySerial.print(x)
// #define DEBUG_PRINTHEX(x) mySerial.print(x, HEX)
// #define DEBUG_PRINTLN(x) mySerial.println(x)
// #define DEBUG_FLUSH mySerial.flush()
#endif
// --- Safety Check: BIOS Patch Compatibility ---
#if defined(SCPH_1000) || \
defined(SCPH_3000) || \
defined(SCPH_3500_5000) || \
defined(SCPH_5500) || \
defined(SCPH_7000) || \
defined(SCPH_7500_9000) || \
defined(SCPH_100) || \
defined(SCPH_102)
#error "ATtiny85/45/25 architecture is not compatible with the BIOS patch feature."
#endif
#endif
// *****************************************************************************************************************

View File

@@ -1,19 +1,6 @@
// PSNee-8.7
// PSNee-V9.0
/*------------------------------------------------------------------------------------------------
<<<<<<< Updated upstream
MCU selection
------------------------------------------------------------------------------------------------*/
// MCU // Arduino
//------------------------------------------------------------------------------------------------
#define ATmega328_168 // Nano, Pro Mini, Uno
//#define ATmega32U4_16U4 // Micro, Pro Micro
//#define ATtiny85_45_25 // ATtiny
/*------------------------------------------------------------------------------------------------
=======
>>>>>>> Stashed changes
Console selection
--------------------------------------------------------------------------------------------------
@@ -22,12 +9,8 @@
SCPH model number // region code | region
-------------------------------------------------------------------------------------------------*/
<<<<<<< Updated upstream
//#define SCPH_xxx1 // NTSC U/C | America.
=======
//#define SCPH_xxxx // | Universal.
#define SCPH_xxx1 // NTSC U/C | America.
>>>>>>> Stashed changes
//#define SCPH_xxx2 // PAL | Europ.
//#define SCPH_xxx3 // NTSC J | Asia.
//#define SCPH_xxxx // Universal
@@ -56,9 +39,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//#define SCPH_100 // DX - D0 | AX - A7 | | 4.3j - CRC F2AF798B
//#define SCPH_7500_9000 // DX - D0 | AX - A7 | | 4.0j - CRC EC541CD0
//#define SCPH_7000 // DX - D0 | AX - A7 | | 4.0j - CRC EC541CD0 Enables hardware support for disabling BIOS patching.
//#define SCPH_5500 // DX - D0 | AX - A5 | | 3.0j - CRC FF3EEB8C
//#define SCPH_5000 // DX - D0 | AX - A5 | AX - A4 | 2.2j - CRC 24FC7E17
//#define SCPH_3500 // DX - D0 | AX - A5 | AX - A4 | 2.1j - CRC BC190209
//#define SCPH_3500_5500 // DX - D0 | AX - A16 | AX - A15 | 3.0j - CRC FF3EEB8C, 2.2j - CRC 24FC7E17, 2.1j - CRC BC190209
//#define SCPH_3000 // DX - D5 | AX - A7, AY - A8 | AX - A6, AY - A7 | 1.1j - CRC 3539DEF6
//#define SCPH_1000 // DX - D5 | AX - A7, AY - A8 | AX - A6, AY - A7 | 1.0j - CRC 3B601FC8
@@ -81,9 +62,9 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
/*------------------------------------------------------------------------------------------------
Hysteresis
------------------------------------------------------------------------------------------------*/
#define HYSTERESIS_MAX 15 // All model.
//#define HYSTERESIS_MAX 25 // Only FAT! For models with problematic CD players.
// Determines the number of times the data in the DATA line must match the filter of the region code injection function to trigger the injection.
#define HYSTERESIS_MAX 25 // Coupled with hysteresis-reset post-injection; allows for a
// wider tuning range without drifting out of the sweet spot
// between hysteresis_max and hysteresis_reset.
/*------------------------------------------------------------------------------------------------
Summary of practical information. Fuses. Pinout
@@ -136,28 +117,13 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//Flag initializing for automatic console generation selection 0 = old, 1 = pu-22 end ++
uint8_t wfck_mode = 0;
// --- Prototypes (Forward declarations) ---
// These tell the compiler that the functions exist later in the code.
void logic_Standard(uint8_t isDataSector);
void logic_SCPH_5903(uint8_t isDataSector);
// Function pointer type definition for the console detection logic.
// This allows switching between 'Standard' and 'SCPH-5903' heuristics dynamically.
typedef void (*ConsoleLogicPtr)(uint8_t isDataSector);
// Global pointer holding the currently active logic function.
// Using a function pointer eliminates the need for repetitive 'if/else' checks in the main loop.
volatile ConsoleLogicPtr currentLogic = logic_Standard;
// Variables de contrôle globales
uint8_t scbuf[12] = { 0 };
// Global buffer to store the 12-byte SUBQ channel data
uint8_t subqBuffer[12];
uint8_t hysteresis = 0;
//Initializing values for region code injection timing
#define DELAY_BETWEEN_BITS 4000 // 250 bits/s (microseconds) (ATtiny 8Mhz works from 3950 to 4100) PU-23 PU-22 MAX 4250 MIN 3850
#define DELAY_BETWEEN_INJECTIONS 90 // The sweet spot is around 80~100. For all observed models, the worst minimum time seen is 72, and it works well up to 250.
/*------------------------------------------------------------------------------------------------
Code section
@@ -165,440 +131,386 @@ uint8_t hysteresis = 0;
/*----------------------------------------------------------------------
Function: board_detection
* FUNCTION : BoardDetection
*
* DESCRIPTION :
* Distinguishes motherboard generations (PU-7 through PU-22+) by analyzing
* the behavior of the WFCK signal.
* SIGNAL CHARACTERISTICS:
* - Legacy Boards (PU-7 to PU-20): WFCK acts as a static GATE signal.
* It remains HIGH (continuous) during the region-check window.
* - Modern Boards (PU-22 or newer): WFCK is an oscillating clock signal
* (Frequency-based).
*
* WFCK: __----------------------- // CONTINUOUS (PU-7 .. PU-20)(GATE)
*
* WFCK: __-_-_-_-_-_-_-_-_-_-_-_- // FREQUENCY (PU-22 or newer)
*
*
* HISTORICAL CONTEXT:
* Traditionally, WFCK was referred to as the "GATE" signal. On early models,
* modchips functioned as a synchronized gate, pulling the signal LOW
* precisely when the region-lock data was being processed.
*
* FREQUENCY DATA:
* - Initial/Protection Phase: ~7.3 kHz.
* - Standard Data Reading: ~14.6 kHz.
*
*-----------------------------------------------------------------------*/
This function distinguishes motherboard generations by detecting
the nature of the WFCK signal:
void BoardDetection() {
// Default state: 0 (Static/GATE mode for PU-7 to PU-20)
wfck_mode = 0;
WFCK: __----------------------- // CONTINUOUS (PU-7 .. PU-20)(GATE)
/**
* INITIAL STABILIZATION DELAY (300ms)
* - PU-7/20: Voltage ramp-up takes ~54ms before stabilizing at a logic HIGH.
* - PU-22+: Clock oscillation (~7.3kHz) typically begins after ~297ms.
* This delay ensures all power-up transients and initial noise are bypassed.
*/
_delay_ms(300);
WFCK: __-_-_-_-_-_-_-_-_-_-_-_- // FREQUENCY (PU-22 or newer)
// Define a sampling window to capture potential oscillations
uint16_t detectionWindow = 10000;
while (--detectionWindow) {
/**
* DETECTION LOGIC:
* On legacy boards (PU-7/20), WFCK is now a steady HIGH.
* Detecting a LOW state indicates a potential clock cycle from a newer board.
*/
if (!PIN_WFCK_READ) {
// Software debounce to filter out micro-glitches or parasitic noise
uint8_t debounce = 100;
while (--debounce);
Traditionally, the WFCK signal was called GATE. This is because, on early models,
modchips acted like a gate that would open to pull the signal down
at the exact moment the region code was being passed (which is still the case today).
During the initialization and region protection zone reading phases,
the WFCK clock frequency is approximately 7.3 kHz.
During normal data reading, the frequency shifts to 14.6 kHz.
-----------------------------------------------------------------------*/
void board_detection() {
uint16_t pulses = 0;
uint32_t totalSamples = 600000; // Timeout/Sampling window to limit detection duration
// Runs until 600,000 cycles pass
while (totalSamples--) {
// If the current pin state is HIGH, wait for it to go LOW
if (PIN_WFCK_READ) {
// Wait for falling edge OR timeout to prevent infinite hang
while (PIN_WFCK_READ && --totalSamples);
pulses++;
// High count (> 500) oscillating signal (Newer boards)
if (pulses > 500) {
wfck_mode = 1; // Target: PU-22 or newer
/**
* VERIFICATION:
* If the signal remains LOW after the debounce, we confirm a genuine
* clock oscillation (WFCK). Legacy boards never transition to LOW
* once stabilized at HIGH during this phase.
*/
if (!PIN_WFCK_READ) {
wfck_mode = 1; // Target confirmed: PU-22 or newer (Frequency mode)
return;
}
}
}
// Low count implies a static signal (Older boards)
wfck_mode = 0; // Target: PU-7 to PU-20
#if defined(PSNEE_DEBUG_SERIAL_MONITOR)
Debug_Log(debounce, wfck_mode);
#endif
}
//******************************************************************************************************************
// Reads a complete 12-byte SUBQ transmission from the CD drive.
// Uses clock-edge synchronization and includes a safety timeout for malformatted streams.
//******************************************************************************************************************
void captureSubQ(void) {
/******************************************************************************************************************
* FUNCTION : CaptureSUBQ
*
* DESCRIPTION :
* Captures a complete 12-byte SUBQ frame from the CD controller.
* Synchronizes with the SQCK (Sub-Q Clock) pin to shift in serial data from
* the SUBQ pin. This implementation follows the standard PlayStation CDIC
* protocol (Synchronous Serial, LSB first).
******************************************************************************************************************/
uint8_t scpos = 0;
//uint8_t bitbuf = 0;
void CaptureSUBQ(void) {
uint8_t bytesRemaining = 12; // Total frame size for a complete SUBQ
uint8_t* bufferPtr = subqBuffer;
do {
uint8_t bitbuf = 0;
for (uint8_t i = 0; i < 8; i++) {
// Wait for Clock to go LOW then HIGH (Sampling on Rising Edge)
while (PIN_SQCK_READ); // Wait for LOW
while (! PIN_SQCK_READ); // Wait for HIGH
uint8_t currentByte = 0;
uint8_t bitsToRead = 8;
while (bitsToRead--) {
/**
* PHASE 1: BIT SYNCHRONIZATION (SQCK)
* The CD controller signals a new bit by toggling the Clock line.
* Data is sampled on the RISING EDGE of SQCK for maximum stability.
*/
while (PIN_SQCK_READ); // Wait for falling edge
while (!PIN_SQCK_READ); // Wait for rising edge
// Shift buffer and sample the SUBQ pin
bitbuf >>= 1;
/**
* PHASE 2: BIT ACQUISITION & SHIFTING
* The PlayStation SUBQ bus transmits data LSB (Least Significant Bit) first.
* We shift the current byte right and inject the new bit into the MSB (0x80).
*/
currentByte >>= 1;
if (PIN_SUBQ_READ) {
bitbuf |= 0x80;
currentByte |= 0x80;
}
}
scbuf[scpos++] = bitbuf;
} while (scpos < 12);
// Store reconstructed byte and advance pointer
*bufferPtr++ = currentByte;
} while (--bytesRemaining); // Efficient countdown for AVR binary size
#if defined(PSNEE_DEBUG_SERIAL_MONITOR)
LogSUBQ(subqBuffer);
#endif
}
/**************************************************************************************
* Processes sector data for the SCPH-5903 (Dual-interface PS1) to differentiate
* between PlayStation games and Video CDs (VCD).
*
* This heuristic uses an 'hysteresis' counter to stabilize disc detection:
* - Increases when a PSX Lead-In or valid game sector is identified.
* - Remains neutral/ignores VCD-specific Lead-In patterns.
* - Decreases (fades out) when the data does not match known patterns.
*
* isDataSector Boolean flag indicating if the current sector contains data.
**************************************************************************************/
// void logic_SCPH_5903(uint8_t isDataSector) {
// // Identify VCD Lead-In: Specific SCBUF patterns (0xA0/A1/A2) with sub-mode 0x02
// uint8_t isVcdLeadIn = isDataSector && scbuf[1] == 0x00 && scbuf[6] == 0x00 &&
// (scbuf[2] == 0xA0 || scbuf[2] == 0xA1 || scbuf[2] == 0xA2) &&
// (scbuf[3] == 0x02);
// // Identify PSX Lead-In: Same SCBUF patterns but different sub-mode (!= 0x02)
// uint8_t isPsxLeadIn = isDataSector && scbuf[1] == 0x00 && scbuf[6] == 0x00 &&
// (scbuf[2] == 0xA0 || scbuf[2] == 0xA1 || scbuf[2] == 0xA2) &&
// (scbuf[3] != 0x02);
// if (isPsxLeadIn) {
// hysteresis++;
// }
// else if (hysteresis > 0 && !isVcdLeadIn &&
// ((scbuf[0] == 0x01 || isDataSector) && scbuf[1] == 0x00 && scbuf[6] == 0x00)) {
// hysteresis++; // Maintain/Increase confidence for valid non-VCD sectors
// }
// else if (hysteresis > 0) {
// hysteresis--; // Patterns stop matching
// }
// }
void logic_SCPH_5903(uint8_t isDataSector) {
// Optimization: Pre-check common markers (1 and 6) to save CPU cycles
if (scbuf[1] == 0x00 && scbuf[6] == 0x00) {
// Identify Lead-In patterns (0xA0, 0xA1, 0xA2)
if (isDataSector && (scbuf[2] >= 0xA0 && scbuf[2] <= 0xA2)) {
// Identify PSX Lead-In: same patterns but sub-mode is NOT 0x02
if (scbuf[3] != 0x02) {
hysteresis++;
return;
}
// If it is 0x02, it's a VCD Lead-In: we fall through to the final else if
}
// Maintain/Increase confidence for valid non-VCD sectors (0x01 or Data)
else if (hysteresis > 0 && (scbuf[0] == 0x01 || isDataSector)) {
hysteresis++;
return;
}
}
// Patterns stop matching or VCD Lead-In detected: decrease confidence
if (hysteresis > 0) {
hysteresis--;
}
}
/******************************************************************************************
* Heuristic logic for standard PlayStation hardware (Non-VCD models).
* FUNCTION : Filter_SUBQ_Samples() [SCPH_5903 Dual-Interface Variant]
*
* This function monitors disc sectors to identify genuine PlayStation discs:
* 1. Checks for specific Lead-In markers (Point A0, A1, A2 or Track 01).
* 2. Uses an incrementing 'hysteresis' counter to confirm disc validity.
* 3. Includes a 'fade-out' mechanism to reduce the counter if valid patterns are lost,
* effectively filtering out noise or read errors.
*
* isDataSector Boolean flag: true if the current sector is a data sector.
* DESCRIPTION :
* Parses and filters the raw serial data stream from the SUBQ pin specifically
* for the SCPH-5903 model to differentiate between Game Discs and Video CDs (VCD).
*
* 1. VCD EXCLUSION: Specifically filters out VCD Lead-In patterns (sub-mode 0x02)
* to prevent incorrect region injection on non-game media.
* 2. SUBQ HIT COUNTING: Increments 'hysteresis' for valid PlayStation TOC (A0-A2)
* markers or active game tracking.
* 3. SIGNAL DECAY: Decrements the counter when SUBQ samples match VCD patterns
* or unknown data, ensuring stable disc identification.
*
* INPUT : isDataSector (bool) - Filtered flag based on raw sector control bits.
******************************************************************************************/
#ifdef SCPH_5903
******************************************************************************************/
void FilterSUBQSamples(uint8_t isDataSector) {
uint8_t currentHysteresis = hysteresis;
// void logic_Standard(uint8_t isDataSector) {
// // Detect specific Lead-In patterns
// if ((isDataSector && scbuf[1] == 0x00 && scbuf[6] == 0x00) &&
// (scbuf[2] == 0xA0 || scbuf[2] == 0xA1 || scbuf[2] == 0xA2 ||
// (scbuf[2] == 0x01 && (scbuf[3] >= 0x98 || scbuf[3] <= 0x02)))) {
// hysteresis++;
// }
// // Maintain confidence if general valid sector markers are found
// else if (hysteresis > 0 &&
// ((scbuf[0] == 0x01 || isDataSector) && scbuf[1] == 0x00 && scbuf[6] == 0x00)) {
// hysteresis++;
// }
// else if (hysteresis > 0) {
// hysteresis--;
// }
// }
// --- STEP 1: SUBQ Frame Synchronization ---
// Fast filtering: ignore raw data if sync markers (index 1 and 6) are not 0x00.
if (subqBuffer[1] == 0x00 && subqBuffer[6] == 0x00) {
uint8_t pointAddress = subqBuffer[2];
void logic_Standard(uint8_t isDataSector) {
// Optimization: Check common markers once (scbuf[1] and scbuf[6])
if (scbuf[1] == 0x00 && scbuf[6] == 0x00) {
// Detect specific Lead-In patterns (A0, A1, A2 or 01 with specific time ranges)
if (isDataSector && (scbuf[2] >= 0xA0 ||
(scbuf[2] == 0x01 && (scbuf[3] >= 0x98 || scbuf[3] <= 0x02)))) {
hysteresis++;
return; // Pattern found, exit early
}
// Maintain confidence if general valid sector markers are found
if (hysteresis > 0 && (scbuf[0] == 0x01 || isDataSector)) {
hysteresis++;
/**
* HIT INCREMENT CONDITIONS:
* A. VALID PSX LEAD-IN: Data sector AND Point A0-A2 range AND NOT VCD (sub-mode != 0x02).
* (uint8_t)(pointAddress - 0xA0) <= 2 is an optimized check for 0xA0, 0xA1, 0xA2.
* B. TRACKING MAINTENANCE: Keeps count if already synced and reading Mode 0x01 or Data.
*/
if ( (isDataSector && (uint8_t)(pointAddress - 0xA0) <= 2 && subqBuffer[3] != 0x02) ||
(currentHysteresis > 0 && (subqBuffer[0] == 0x01 || isDataSector)) )
{
hysteresis = currentHysteresis + 1;
return;
}
}
// No valid pattern found: decrease confidence
if (hysteresis > 0) {
hysteresis--;
// --- STEP 2: Signal Decay / Pattern Mismatch ---
// Decrement the hit counter if no valid PSX pattern is detected in the SUBQ stream.
if (currentHysteresis > 0) {
hysteresis = currentHysteresis - 1;
}
}
}
#else
/******************************************************************************************
* FUNCTION : Filter_SUBQ_Samples()
*
* DESCRIPTION :
* Parses and filters the raw serial data stream from the SUBQ pin.
* Increments a hit counter (hysteresis) when specific patterns are identified
* in the SUBQ stream, confirming the laser is reading the region-check area.
*
* 1. RAW BUS FILTERING: Validates SUBQ framing by checking sync markers (index 1 & 6).
* 2. PATTERN MATCHING: Detects Lead-In TOC (A0-A2) or Track 01 at the spiral start.
* 3. SIGNAL DECAY: Decrements the counter if the current SUBQ sample does not
* match expected PlayStation protection patterns.
*
* INPUT : isDataSector (bool) - Filtered flag based on raw sector control bits.
******************************************************************************************/
void FilterSUBQSamples(uint8_t isDataSector) {
uint8_t currentHysteresis = hysteresis;
// --- STEP 1: SUBQ Frame Synchronization ---
// Ignore the raw bitstream unless sync markers (1 & 6) are 0x00.
if (subqBuffer[1] == 0x00 && subqBuffer[6] == 0x00) {
uint8_t pointAddress = subqBuffer[2];
/*
* HIT INCREMENT CONDITIONS:
* A. LEAD-IN PATTERNS: Detects TOC markers (A0-A2) or Track 01 at spiral start.
* (uint8_t)(subqBuffer[3] - 0x03) >= 0xF5 handles the 0x98 to 0x02 wrap-around.
* B. TRACKING LOCK: Maintains count if already synced and reading valid sectors.
*/
if ( (isDataSector && (pointAddress >= 0xA0 || (pointAddress == 0x01 && ( (uint8_t)(subqBuffer[3] - 0x03) >= 0xF5)))) ||
(currentHysteresis > 0 && (subqBuffer[0] == 0x01 || isDataSector)) )
{
hysteresis = currentHysteresis + 1;
return;
}
}
// --- STEP 2: Signal Decay / Missed Hits ---
// Reduce the hit counter if the current SUBQ sample fails validation.
if (currentHysteresis > 0) {
hysteresis = currentHysteresis - 1;
}
}
#endif
/*********************************************************************************************
* Executes the SCEx signal injection sequence to bypass regional lockout.
* Executes the SCEx injection sequence to bypass the CD-ROM regional lockout.
*
* This function handles the precise timing required to send the 44-bit security
* strings. It supports both legacy "Logic Gate" mode and modern "WFCK Modulation"
* for compatibility across all console revisions (PU-7 to PM-41).
* This function supports two hardware-specific injection methods:
* 1. Legacy Gate Mode (PU-7 to PU-20): Modchip acts as a logic gate to pull
* the signal down. WFCK is simulated by the chip if necessary.
* 2. WFCK Modulation (PU-22+): Modchip modulates the DATA signal in
* sync with the console's real WFCK clock.
*
* injectSCEx 0:NTSC-J SCEI, 1:NTSC-U/C SCEA, 2:PAL SCEE, 3:Universal (Cycles through all).
* NOTE: WFCK frequency is approx. 7.3 kHz during initialization/region check,
* but doubles to 14.6 kHz during normal data reading. The modulation loop
* handles both speeds as it syncs directly to the signal edges.
*********************************************************************************************/
void performInjectionSequence(uint8_t injectSCEx) {
// 44-bit SCEx strings for Japan Asia, USA, and Europe
void PerformInjectionSequence(uint8_t injectSCEx) {
/*
Security strings (44-bit SCEx) for the three main regions:
0: NTSC-J (SCEI - Sony Computer Entertainment Inc.)
1: NTSC-U/C (SCEA - Sony Computer Entertainment America)
2: PAL (SCEE - Sony Computer Entertainment Europe)
Stored in 6 bytes (48 bits); only the first 44 bits are used during injection.
*/
static const uint8_t allRegionsSCEx[3][6] = {
{ 0b01011001, 0b11001001, 0b01001011, 0b01011101, 0b11011010, 0b00000010 }, // SCEI
{ 0b01011001, 0b11001001, 0b01001011, 0b01011101, 0b11111010, 0b00000010 }, // SCEA
{ 0b01011001, 0b11001001, 0b01001011, 0b01011101, 0b11101010, 0b00000010 } // SCEE
{ 0x59, 0xC9, 0x4B, 0x5D, 0xDA, 0x02 }, // SCEI
{ 0x59, 0xC9, 0x4B, 0x5D, 0xFA, 0x02 }, // SCEA
{ 0x59, 0xC9, 0x4B, 0x5D, 0xEA, 0x02 } // SCEE
};
hysteresis = 11;
hysteresis = (HYSTERESIS_MAX - 10); // Reset hysteresis to mid-point after triggering
#ifdef LED_RUN
PIN_LED_ON;
#endif
// Pin initialization
// Cache wfck_mode to save CPU cycles during the bit loop
uint8_t isWfck = wfck_mode;
PIN_DATA_OUTPUT;
PIN_DATA_CLEAR;
if (!wfck_mode) {
PIN_WFCK_OUTPUT; PIN_WFCK_CLEAR;
// Legacy boards require the chip to drive the simulated WFCK/Gate
if (!isWfck) {
PIN_WFCK_OUTPUT;
PIN_WFCK_CLEAR;
}
_delay_ms(DELAY_BETWEEN_INJECTIONS);
// Injection loop (3 cycles)
// Loop through the selected region(s)
for (uint8_t i = 0; i < 3; i++) {
// Mode 3: cycles through all regions; Others: stay on fixed region
uint8_t regionIndex = (injectSCEx == 3) ? i : injectSCEx;
const uint8_t* ByteSet = allRegionsSCEx[regionIndex];
const uint8_t* bytePtr = allRegionsSCEx[regionIndex];
uint8_t currentByte = *bytePtr++;
uint8_t bitIdx = 0;
// Process 6 bytes to reach 44 bits
for (uint8_t b = 0; b < 6; b++) {
uint8_t currentByte = ByteSet[b];
for (uint8_t bit = 0; bit < 8; bit++) {
// Stop exactly at 44 bits (6th byte, 4th bit)
if (b == 5 && bit == 4) break;
// Bit-level extraction: isolate the target bit and prepare next
uint8_t currentBit = currentByte & 0x01;
currentByte >>= 1;
// Process the 44-bit SCEx stream
for (uint8_t totalBits = 44; totalBits > 0; totalBits--) {
uint8_t currentBit = currentByte & 0x01;
currentByte >>= 1;
bitIdx++;
if (!wfck_mode) {
// LOGIC GATE MODE (Old boards)
if (currentBit == 0) {
PIN_DATA_OUTPUT; PIN_DATA_CLEAR;
}
else {
PIN_DATA_INPUT; // High Impedance = 1
}
// Reload next byte every 8 bits (except the last partial one)
if (bitIdx == 8 && totalBits > 4) {
currentByte = *bytePtr++;
bitIdx = 0;
}
if (currentBit == 0) {
// BIT 0: Pull DATA low-
PIN_DATA_CLEAR;
if (!isWfck) PIN_DATA_OUTPUT;
_delay_us(DELAY_BETWEEN_BITS);
}
else {
// WFCK MODULATION (Newer boards / PU-18+)
if (currentBit == 0) {
PIN_DATA_CLEAR;
} else {
// BIT 1: Handle based on board generation
if (!isWfck) {
// Legacy Mode: Set DATA to High-Z (floating)
PIN_DATA_INPUT;
_delay_us(DELAY_BETWEEN_BITS);
} else {
// Synchronize injection with WFCK clock edges
uint8_t count = 30;
while (count--) {
while (PIN_WFCK_READ); // Wait for LOW
PIN_DATA_CLEAR;
while (!PIN_WFCK_READ); // Wait for HIGH
PIN_DATA_SET;
}
} else {
/*
WFCK Modulation Loop: Syncs to 7.3kHz or 14.6kHz.
Follows hardware edges to stay bit-perfect with the console.
*/
uint8_t count = 30;
while (count--) {
while (PIN_WFCK_READ); // Wait for Falling Edge
PIN_DATA_CLEAR;
while (!PIN_WFCK_READ); // Wait for Rising Edge
PIN_DATA_SET;
}
}
}
}
// Inter-string silence
/*
EXIT CONDITION:
If we are NOT in Universal mode (3), we stop after the first
successful region injection.
*/
if (injectSCEx != 3) {
PIN_DATA_OUTPUT;
PIN_DATA_CLEAR;
if (!isWfck) {
PIN_WFCK_INPUT;
PIN_DATA_INPUT;
}
break;
}
// Clean up state between region cycles
PIN_DATA_OUTPUT;
PIN_DATA_CLEAR;
_delay_ms(DELAY_BETWEEN_INJECTIONS);
_delay_ms(180);
}
// Cleanup: Set pins to High-Z (Safe mode)
if (!wfck_mode) {
PIN_WFCK_INPUT;
PIN_DATA_INPUT;
// Restore pins to Input/High-Z to avoid signal interference after injection
if (!isWfck) {
PIN_WFCK_INPUT;
PIN_DATA_INPUT;
}
#ifdef LED_RUN
PIN_LED_OFF;
PIN_LED_OFF;
#endif
#if defined(PSNEE_DEBUG_SERIAL_MONITOR)
DebugInject();
#endif
}
// void performInjectionSequence(uint8_t injectSCEx) {
// // 44-bit SCEx strings for Japan Asia, USA, and Europe
// static const uint8_t allRegionsSCEx[3][6] = {
// { 0b01011001, 0b11001001, 0b01001011, 0b01011101, 0b11011010, 0b00000010 }, // NTSC-J SCEI SCPH-xxx0 SCPH-xxx3
// { 0b01011001, 0b11001001, 0b01001011, 0b01011101, 0b11111010, 0b00000010 }, // NTSC-U/C SCEA SCPH-xxx1
// { 0b01011001, 0b11001001, 0b01001011, 0b01011101, 0b11101010, 0b00000010 } // PAL SCEE SCPH-xxx2
// };
// // if (hysteresis < HYSTERESIS_MAX) return;
// hysteresis = 11;
// #ifdef LED_RUN
// PIN_LED_ON;
// #endif
// // Pin initialization
// PIN_DATA_OUTPUT;
// PIN_DATA_CLEAR;
// if (!wfck_mode) {
// PIN_WFCK_OUTPUT;
// PIN_WFCK_CLEAR;
// }
// _delay_ms(DELAY_BETWEEN_INJECTIONS);
// // Injection loop (3 cycles)
// for (uint8_t i = 0; i < 3; i++) {
// // Mode 3: cycles through all regions; Others: stay on fixed region
// uint8_t regionIndex = (injectSCEx == 3) ? i : injectSCEx;
// const uint8_t* ByteSet = allRegionsSCEx[regionIndex];
// for (uint8_t bit_counter = 0; bit_counter < 44; bit_counter++) {
// // Bit-level extraction:
// // 1. bit_counter >> 3 identifies the byte index (integer division by 8).
// // 2. bit_counter & 0x07 identifies the bit position within that byte (modulo 8).
// // 3. Right-shift and mask (& 0x01) isolates the target bit for injection.
// uint8_t currentByte = ByteSet[bit_counter >> 3];
// uint8_t currentBit = (currentByte >> (bit_counter & 0x07)) & 0x01;
// if (!wfck_mode) {
// // LOGIC GATE MODE (Old boards)
// if (currentBit == 0) {
// PIN_DATA_OUTPUT;
// PIN_DATA_CLEAR;
// }
// else {
// PIN_DATA_INPUT; // High Impedance = 1
// }
// _delay_us(DELAY_BETWEEN_BITS);
// }
// else {
// // WFCK MODULATION (Newer boards / PU-18+)
// // PIN_DATA_OUTPUT;
// if (currentBit == 0) {
// PIN_DATA_CLEAR;
// _delay_us(DELAY_BETWEEN_BITS);
// }
// else {
// // Synchronize injection with WFCK clock edges
// uint8_t count = 30;
// uint8_t last_wfck = PIN_WFCK_READ;
// while (count > 0) {
// uint8_t current_wfck = PIN_WFCK_READ;
// if (current_wfck != last_wfck) {
// if (current_wfck) {
// PIN_DATA_SET; count--;
// }
// else {
// PIN_DATA_CLEAR;
// }
// last_wfck = current_wfck;
// }
// }
// }
// }
// }
// // Inter-string silence
// PIN_DATA_OUTPUT;
// PIN_DATA_CLEAR;
// _delay_ms(DELAY_BETWEEN_INJECTIONS);
// }
// // Cleanup: Set pins to High-Z (Safe mode)
// if (!wfck_mode) {
// PIN_WFCK_INPUT;
// PIN_DATA_INPUT;
// }
// #ifdef LED_RUN
// PIN_LED_OFF;
// #endif
// }
void Init() {
#if defined(ATmega328_168)
optimizePeripherals();
#endif
// --- Hardware Power & Peripheral Optimization ---
#ifdef LED_RUN
PIN_LED_OUTPUT;
#endif
OptimizePeripherals();
#ifdef BIOS_PATCH
uint8_t Flag_Switch = 0;
GLOBAL_INTERRUPT_ENABLE;
#ifdef SCPH_7000
PIN_SWITCH_INPUT;
PIN_SWITCH_SET;
if (PIN_SWITCH_READ == 0){
Flag_Switch =1;
}
#endif
#ifdef LED_RUN
//PIN_LED_ON;
#endif
#ifdef LED_RUN
PIN_LED_OUTPUT;
#endif
if (Flag_Switch == 0) {
Bios_Patching();
}
// --- Critical Boot Patching ---
#ifdef BIOS_PATCH
#ifdef LED_RUN
//PIN_LED_OFF;
#endif
// #ifdef LED_RUN
// PIN_LED_ON;
// #endif
#endif
// Execute BIOS patching
Bios_Patching();
cli();
// #ifdef LED_RUN
// PIN_LED_OFF;
// #endif
#endif
GLOBAL_INTERRUPT_DISABLE;
PIN_SQCK_INPUT;
PIN_SUBQ_INPUT;
<<<<<<< Updated upstream
#if defined(PSNEE_DEBUG_SERIAL_MONITOR) && defined(ATtiny85_45_25)
//pinMode(debugtx, OUTPUT); // software serial tx pin
mySerial.begin(115200); // 13,82 bytes in 12ms, max for softwareserial. (expected data: ~13 bytes / 12ms) // update: this is actually quicker
#elif defined(PSNEE_DEBUG_SERIAL_MONITOR) && !defined(ATtiny85_45_25)
Serial.begin(500000); // 60 bytes in 12ms (expected data: ~26 bytes / 12ms) // update: this is actually quicker
#endif
}
=======
// --- Debug Interface Setup ---
#if defined(PSNEE_DEBUG_SERIAL_MONITOR) && defined(IS_ATTINY_FAMILY)
//pinMode(debugtx, OUTPUT); // software serial tx pin
@@ -609,60 +521,36 @@ void Init() {
// --- Console Analysis ---
// Identify board revision (PU-7 to PU-22+) to set correct injection timings
BoardBetection();
BoardDetection();
}
>>>>>>> Stashed changes
int main() {
Init();
#ifdef SCPH_5903
currentLogic = logic_SCPH_5903;
#else
currentLogic = logic_Standard;
#endif
board_detection();
#if defined(PSNEE_DEBUG_SERIAL_MONITOR)
Debug_Log(lows, wfck_mode);
#endif
while (1) {
_delay_ms(1); /* Start with a small delay, which can be necessary
in cases where the MCU loops too quickly and picks up the laster SUBQ trailing end*/
captureSubQ();
// 1. Timing Sync: Prevent reading the tail end of the previous SUBQ packet
_delay_ms(1);
#if defined(PSNEE_DEBUG_SERIAL_MONITOR)
Debug_Scbuf(scbuf);
#endif
// 2. Data Acquisition: Capture 12-byte SUBQ channel stream into buffer
CaptureSUBQ();
/*-------------------------------------------------------------------------------
Check if read head is in wobble area
We only want to unlock game discs (0x41) and only if the read head is in the outer TOC area.
We want to see a TOC sector repeatedly before injecting (helps with timing and marginal lasers).
All this logic is because we don't know if the HC-05 is actually processing a getSCEX() command.
Hysteresis is used because older drives exhibit more variation in read head positioning.
While the laser lens moves to correct for the error, they can pick up a few TOC sectors.
-------------------------------------------------------------------------------*/
// 3. Sector Validation (Data/TOC check):
// Masking bits 7, 6, and 4 simultaneously using 0xD0 (binary 11010000).
// This verifies that the "Data/TOC" bit (0x40) is SET, while bits 7 and 4 are CLEARED.
// Equivalent to: (bit7 == 0 && bit6 == 1 && bit4 == 0).
//uint8_t isDataSector = ((scbuf[0] & 0xD0) == 0x40);
uint8_t isDataSector = ((subqBuffer[0] & 0xD0) == 0x40);
//This variable initialization macro is to replace (0x41) with a filter that will check that only the three most significant bits are correct. 0x001xxxxx
uint8_t isDataSector = (((scbuf[0] & 0x40) == 0x40) && (((scbuf[0] & 0x10) == 0) && ((scbuf[0] & 0x80) == 0)));
// Execute selected logic through function pointer
currentLogic(isDataSector);
if (hysteresis >= HYSTERESIS_MAX) {
performInjectionSequence(INJECT_SCEx);
}
#if defined(PSNEE_DEBUG_SERIAL_MONITOR)
Debug_Inject();
#endif
// Execute selected logic
FilterSUBQSamples(isDataSector);
// 5. Execution: Trigger SCEx injection once confidence (hysteresis) is reached
if (hysteresis >= HYSTERESIS_MAX) {
PerformInjectionSequence(INJECT_SCEx);
}
}
return 0;
}

View File

@@ -22,8 +22,7 @@
// Results of the maximum values
// tested with an Atmega328P
<<<<<<< Updated upstream
=======
#if defined(IS_32U4_FAMILY)
// ------ SCPH 100 / 102 ------
@@ -36,184 +35,179 @@
#define BIT_OFFSET_CYCLES 47 //60
#define OVERRIDE_CYCLES 3
#endif
>>>>>>> Stashed changes
// #ifdef SCPH_102
// #define BIOS_PATCH
// #define INTERRUPT_RISING
// #define BOOT_OFFSET 83.9
// #define PULSE_COUNT 48 !!! -1
// #define BIT_OFFSET 2.75
// #define OVERRIDE 0.2
// #endif
// // -------- SCPH 7500 / 9000 --------
#ifdef SCPH_7500_9000
#define BIOS_PATCH
#define SILENCE_THRESHOLD 1100
#define CONFIRM_COUNTER_TARGET 1
#define PULSE_COUNT 15 //15
#define BIT_OFFSET_CYCLES 47 //60
#define OVERRIDE_CYCLES 3
#endif
// #ifdef SCPH_100
// #define BIOS_PATCH
// #define INTERRUPT_RISING
// #define BOOT_OFFSET 83.9 //83.72 - 84.15
// #define PULSE_COUNT 47
// #define BIT_OFFSET 2.75 //2.63 - 2.87
// #define OVERRIDE 0.2
// #endif
#ifdef SCPH_102
#define BIOS_PATCH
#define TEST_BIOS
#define BOOT_OFFSET 83.9 // Stabilization window (ms)
#define BIT_OFFSET 225.6 // Precision data alignment (us)
#define OVERRIDE 0.2 // DX injection width (us)
// -------- SCPH 7000 --------
#ifdef SCPH_7000
#define BIOS_PATCH
#define SILENCE_THRESHOLD 1100
#define CONFIRM_COUNTER_TARGET 1
#define PULSE_COUNT 15
#define BIT_OFFSET_CYCLES 47
#define OVERRIDE_CYCLES 3
#endif
// // ----- SCPH 3500 / 5000 / 5500 -----
#ifdef SCPH_3500_5500
#define BIOS_PATCH
#define SILENCE_THRESHOLD 25000
#define CONFIRM_COUNTER_TARGET 1
#define PULSE_COUNT 84 //84
#define BIT_OFFSET_CYCLES 47 //60
#define OVERRIDE_CYCLES 3
#endif
// // -------- SCPH 3000 --------
#ifdef SCPH_3000
#define BIOS_PATCH
#define PHASE_TWO_PATCH
#define SILENCE_THRESHOLD 1100
#define CONFIRM_COUNTER_TARGET 9
#define PULSE_COUNT 59
#define BIT_OFFSET_CYCLES 45
#define OVERRIDE_CYCLES 3
#define CONFIRM_COUNTER_TARGET_2 206
#define PULSE_COUNT_2 42
#define BIT_OFFSET_2_CYCLES 48
#define OVERRIDE_2_CYCLES 3
#endif
// // -------- SCPH 1000 --------
#ifdef SCPH_1000
#define BIOS_PATCH
#define PHASE_TWO_PATCH
#define SILENCE_THRESHOLD 1100
#define CONFIRM_COUNTER_TARGET 9
#define PULSE_COUNT 91
#define BIT_OFFSET_CYCLES 45
#define OVERRIDE_CYCLES 3
#define CONFIRM_COUNTER_TARGET_2 222
#define PULSE_COUNT_2 70
#define BIT_OFFSET_2_CYCLES 48
#define OVERRIDE_2_CYCLES 3
#endif
#endif
#ifdef SCPH_100
#define BIOS_PATCH
#define TEST_BIOS
#define BOOT_OFFSET 83.9 // Stabilization window (ms)
#define BIT_OFFSET 225.6 // Precision data alignment (us)
#define OVERRIDE 0.2 // DX injection width (us)
#endif
#if defined(IS_328_168_FAMILY)
#ifdef SCPH_7500_9000
#define BIOS_PATCH
#define TEST_BIOS
#define BOOT_OFFSET 75.2
#define BIT_OFFSET 71.5
#define OVERRIDE 0.2
#endif
// ------ SCPH 100 / 102 ------
#if defined(SCPH_100) || \
defined(SCPH_102)
#define BIOS_PATCH
#define SILENCE_THRESHOLD 1500
#define CONFIRM_COUNTER_TARGET 8
#define PULSE_COUNT 47 //47
#define BIT_OFFSET_CYCLES 47 //60
#define OVERRIDE_CYCLES 3
#endif
#ifdef SCPH_7000
#define BIOS_PATCH
#define TEST_BIOS
#define BOOT_OFFSET 75.2
#define BIT_OFFSET 71.5
#define OVERRIDE 0.2
#endif
#ifdef SCPH_5500
#define BIOS_PATCH
#define TEST_BIOS
#define LOW_TRIGGER
#define BOOT_OFFSET 76.07 //75.99 - 76.14
#define BIT_OFFSET 95.6
#define OVERRIDE 0.2
#endif
// // -------- SCPH 7500 / 9000 --------
#ifdef SCPH_7500_9000
#define BIOS_PATCH
#define SILENCE_THRESHOLD 1500
#define CONFIRM_COUNTER_TARGET 1
#define PULSE_COUNT 15 //15
#define BIT_OFFSET_CYCLES 47 //60
#define OVERRIDE_CYCLES 3
#endif
#ifdef SCPH_5000
#define BIOS_PATCH
#define TEST_BIOS
#define LOW_TRIGGER
#define BOOT_OFFSET 75.2 //75.12 - 75.27
#define BIT_OFFSET 95.65
#define OVERRIDE 0.2
#endif
#ifdef SCPH_3500
#define BIOS_PATCH
#define TEST_BIOS
#define LOW_TRIGGER
#define BOOT_OFFSET 75.2 //75.12 - 75.27
#define BIT_OFFSET 95.4
#define OVERRIDE 0.2
#endif
// -------- SCPH 7000 --------
#ifdef SCPH_7000
#define BIOS_PATCH
#define SILENCE_THRESHOLD 1500
#define CONFIRM_COUNTER_TARGET 1
#define PULSE_COUNT 15
#define BIT_OFFSET_CYCLES 47
#define OVERRIDE_CYCLES 3
#endif
// #ifdef SCPH_3000
// #define BIOS_PATCH
// #define HIGH_PATCH_A
// #define BOOT_OFFSET 82.9 //82.65 - 83.26
// #define BIT_OFFSET 283.25
// #define OVERRIDE 0.15
// #define HIGH_PATCH
// #define FOLLOWUP_OFFSET 253.3
// #define PULSE_COUNT_2 43
// #define BIT_OFFSET_2 2.88
// #define OVERRIDE_2 0.15
// #endif
#ifdef SCPH_3000
#define BIOS_PATCH
#define HIGH_PATCH_B
#define BOOT_OFFSET 82.9 //82.65 - 83.26
#define BIT_OFFSET 283.25
#define OVERRIDE 0.15
#define HIGH_PATCH
#define FOLLOWUP_OFFSET 253.3
#define BIT_OFFSET_2 201.8
#define OVERRIDE_2 0.15
#endif
// // ----- SCPH 3500 / 5000 / 5500 -----
#ifdef SCPH_3500_5500
#define BIOS_PATCH
#define SILENCE_THRESHOLD 32000
#define CONFIRM_COUNTER_TARGET 1
#define PULSE_COUNT 84 //84
#define BIT_OFFSET_CYCLES 47 //60
#define OVERRIDE_CYCLES 3
#endif
// #ifdef SCPH_3000
// #define BIOS_PATCH
// #define INTERRUPT_RISING_HIGH_PATCH
// #define BOOT_OFFSET 82.9 //82.65 - 83.26
// #define PULSE_COUNT 60
// #define BIT_OFFSET 2.7 //2.58 - 2.8
// #define OVERRIDE 0.15
// #define HIGH_PATCH
// #define FOLLOWUP_OFFSET 253.3
// #define PULSE_COUNT_2 43
// #define BIT_OFFSET_2 2.88
// #define OVERRIDE_2 0.15
// #endif
// // -------- SCPH 3000 --------
#ifdef SCPH_3000
#define BIOS_PATCH
#define PHASE_TWO_PATCH
#define SILENCE_THRESHOLD 1500
#define CONFIRM_COUNTER_TARGET 9
#define PULSE_COUNT 59
#define BIT_OFFSET_CYCLES 45
#define OVERRIDE_CYCLES 3
#define CONFIRM_COUNTER_TARGET_2 206
#define PULSE_COUNT_2 42
#define BIT_OFFSET_2_CYCLES 48
#define OVERRIDE_2_CYCLES 3
#endif
// #ifdef SCPH_1000
// #define BIOS_PATCH
// #define INTERRUPT_RISING_HIGH_PATCH
// #define BOOT_OFFSET 82.9 // 82.63 - 83.26
// #define PULSE_COUNT 92
// #define BIT_OFFSET 2.65 // 2.58 - 2.75
// #define OVERRIDE 0.15
// #define HIGH_PATCH
// #define FOLLOWUP_OFFSET 272.8
// #define PULSE_COUNT_2 71
// #define BIT_OFFSET_2 2.88
// #define OVERRIDE_2 0.15
// #endif
// #ifdef SCPH_1000
// #define BIOS_PATCH
// #define HIGH_PATCH_A
// #define BOOT_OFFSET 82.9 // 82.63 - 83.26
// #define BIT_OFFSET 437.1 // 2.58 - 2.75
// #define OVERRIDE 0.15
// #define HIGH_PATCH
// #define FOLLOWUP_OFFSET 272.8
// #define PULSE_COUNT_2 71
// #define BIT_OFFSET_2 2.88
// #define OVERRIDE_2 0.15
// #endif
#ifdef SCPH_1000
#define BIOS_PATCH
#define HIGH_PATCH_B
#define BOOT_OFFSET 82.9 // 82.63 - 83.26
#define BIT_OFFSET 437.1 // 2.58 - 2.75
#define OVERRIDE 0.15
#define HIGH_PATCH
#define FOLLOWUP_OFFSET 272.8
#define BIT_OFFSET_2 336.05
#define OVERRIDE_2 0.15
// // -------- SCPH 1000 --------
#ifdef SCPH_1000
#define BIOS_PATCH
#define PHASE_TWO_PATCH
#define SILENCE_THRESHOLD 1500
#define CONFIRM_COUNTER_TARGET 9
#define PULSE_COUNT 91
#define BIT_OFFSET_CYCLES 45
#define OVERRIDE_CYCLES 3
#define CONFIRM_COUNTER_TARGET_2 222
#define PULSE_COUNT_2 70
#define BIT_OFFSET_2_CYCLES 48
#define OVERRIDE_2_CYCLES 3
#endif
#endif
/*------------------------------------------------------------------------------------------------
Region Settings Section
------------------------------------------------------------------------------------------------*/
#if defined(SCPH_100) || defined(SCPH_7500_9000) || defined(SCPH_7000) || \
defined(SCPH_5500) || defined(SCPH_5000) ||defined(SCPH_3500) || defined(SCPH_3000) || \
defined(SCPH_1000) || defined(SCPH_xxx3) || defined(SCPH_5903)
#define INJECT_SCEx 0 // NTSC-J
#endif
#if defined(SCPH_100) || \
defined(SCPH_7500_9000) || \
defined(SCPH_7000) || \
defined(SCPH_3500_5500) || \
defined(SCPH_3500) || \
defined(SCPH_3000) || \
defined(SCPH_1000) || \
defined(SCPH_xxx3) || \
defined(SCPH_5903)
#if defined(SCPH_xxx1)
#define INJECT_SCEx 1 // NTSC-U/C
#endif
#define INJECT_SCEx 0 // NTSC-J
#if defined(SCPH_xxx2) || defined(SCPH_102)
#define INJECT_SCEx 2 // PAL
#endif
#elif defined(SCPH_xxx1)
#define INJECT_SCEx 1 // NTSC-U/C
#elif defined(SCPH_xxx2) || \
defined(SCPH_102)
#define INJECT_SCEx 2 // PAL
#elif defined(SCPH_xxxx)
#define INJECT_SCEx 3 // Universal: NTSC-J -> NTSC-U/C -> PAL
#if defined(SCPH_xxxx)
#define INJECT_SCEx 3 // Universal: NTSC-J -> NTSC-U/C -> PAL
#endif
@@ -224,14 +218,13 @@
#if defined(PSNEE_DEBUG_SERIAL_MONITOR)
void Debug_Log (uint16_t Lows, int Wfck_mode){ //Information about the MCU, and old or late console mode.
void Debug_Log (uint16_t debounce, int Wfck_mode){ //Information about the MCU, and old or late console mode.
<<<<<<< Updated upstream
#if defined(ATtiny85_45_25)
#if defined(IS_ATTINY_FAMILY)
mySerial.print("m "); mySerial.println(Wfck_mode);
#elif !defined(ATtiny85_45_25)
#else
Serial.print(" MCU frequency: "); Serial.print(F_CPU); Serial.println(" Hz");
Serial.print(" lows: "); Serial.println(Lows);
Serial.print(" debounce: "); Serial.println(debounce);
Serial.print(" wfck_mode: "); Serial.println(Wfck_mode);
Serial.print(" region: "); Serial.print(region[0]); Serial.print(region[1]); Serial.println(region[2]);
#endif
@@ -239,12 +232,11 @@ void Debug_Log (uint16_t Lows, int Wfck_mode){ //Information about the
// log SUBQ packets. We only have 12ms to get the logs written out. Slower MCUs get less formatting.
void Debug_Scbuf (uint8_t *Scbuf){ // Data from the DATA bus
#if defined(ATtiny85_45_25)
#if defined(IS_ATTINY_FAMILY)
if (!(Scbuf[0] == 0 && Scbuf[1] == 0 && Scbuf[2] == 0 && Scbuf[3] == 0)) { // a bad sector read is all 0 except for the CRC fields. Don't log it.
for (int i = 0; i < 12; i++) {
if (Scbuf[i] < 0x10) {
mySerial.print("0"); // padding
=======
#if defined(IS_ATTINY_FAMILY)
// --- COMPACT SYSTEM LOG (ATtiny) ---
// Minimalistic output to save CPU cycles and maintain timing precision.
@@ -266,7 +258,7 @@ void Debug_Scbuf (uint8_t *Scbuf){ // Data from the DATA bus
Serial.println(region[2]); // Active injection string (e.g., SCEE)
#endif
}
#endif
/******************************************************************************************
* FUNCTION : LogSUBQ
*
@@ -290,47 +282,41 @@ void LogSUBQ(uint8_t *dataBuffer) {
*/
if (!(dataBuffer[0] == 0 && dataBuffer[1] == 0 && dataBuffer[2] == 0 && dataBuffer[3] == 0)) {
#if defined(IS_ATTINY_FAMILY)
// --- COMPACT FORMATTING (ATtiny) ---
// Minimal formatting to meet the strict 12ms timing constraint on slower MCUs.
for (uint8_t i = 0; i < 12; i++) {
if (dataBuffer[i] < 0x10) {
mySerial.print("0"); // Leading zero padding for hex alignment
>>>>>>> Stashed changes
#if defined(IS_ATTINY_FAMILY)
// --- COMPACT FORMATTING (ATtiny) ---
// Minimal formatting to meet the strict 12ms timing constraint on slower MCUs.
for (uint8_t i = 0; i < 12; i++) {
if (dataBuffer[i] < 0x10) {
mySerial.print("0"); // Leading zero padding for hex alignment
}
mySerial.print(Scbuf[i, HEX]);
}
mySerial.print(Scbuf[i, HEX]);
mySerial.println("");
}
mySerial.println("");
}
#elif !defined(ATtiny85_45_25)
if (!(Scbuf[0] == 0 && Scbuf[1] == 0 && Scbuf[2] == 0 && Scbuf[3] == 0)) {
for (int i = 0; i < 12; i++) {
if (Scbuf[i] < 0x10) {
Serial.print("0"); // padding
#elif !defined(IS_ATTINY_FAMILY)
if (!(Scbuf[0] == 0 && Scbuf[1] == 0 && Scbuf[2] == 0 && Scbuf[3] == 0)) {
for (int i = 0; i < 12; i++) {
if (Scbuf[i] < 0x10) {
Serial.print("0"); // padding
}
Serial.print(Scbuf[i], HEX);
Serial.print(" ");
}
Serial.print(Scbuf[i], HEX);
Serial.print(" ");
Serial.println("");
}
Serial.println("");
#endif
}
#endif
}
void Debug_Inject(){ // Confirmation of region code injection
<<<<<<< Updated upstream
#if defined(ATtiny85_45_25)
mySerial.print("!");
#elif !defined(ATtiny85_45_25)|| defined(SCPH_102_legacy)
=======
#if defined(IS_ATTINY_FAMILY)
// --- MINIMALIST NOTIFICATION (ATtiny) ---
mySerial.print("!");
#else
// --- VERBOSE NOTIFICATION (ATmega) ---
// Standard visual feedback for debugging and monitoring.
>>>>>>> Stashed changes
Serial.println(" INJECT ! ");
#endif
}
@@ -341,52 +327,20 @@ void Debug_Inject(){ // Confirmation of region code injection
Compilation message
-----------------------------------------------------------------------------------------------*/
#if !defined(SCPH_xxx3) && \
!defined(SCPH_102) && !defined(SCPH_101) && !defined(SCPH_100) && !defined(SCPH_7500_9000) && \
!defined(SCPH_7000) && !defined(SCPH_5500) && !defined(SCPH_5000) && !defined(SCPH_3500) && !defined(SCPH_3000) && \
!defined(SCPH_1000) && !defined(SCPH_5903) &&\
!defined(SCPH_xxx1) && !defined(SCPH_xxx2) && !defined(SCPH_xxxx)
#error "Console not selected! Please uncoment #define with SCPH model number."
#elif !defined(SCPH_xxx3) ^ \
defined(SCPH_102) ^ defined(SCPH_101) ^ defined(SCPH_100) ^ defined(SCPH_7500_9000) ^ \
defined(SCPH_7000) ^ defined(SCPH_5500) ^ defined(SCPH_5000) ^ defined(SCPH_3500) ^ defined(SCPH_3000) ^ \
defined(SCPH_1000) ^ defined(SCPH_xxxx) ^ defined(SCPH_5903) ^ \
defined(SCPH_xxx1) ^ defined(SCPH_xxx2)
#error "May be selected only one console! Please check #define with SCPH model number."
#ifdef LED_RUN
#pragma message "Feature: Status LED ENABLED"
#endif
<<<<<<< Updated upstream
#if !defined(ATmega328_168) && !defined(ATmega32U4_16U4) && !defined(ATtiny85_45_25)
#error "MCU not selected! Please choose one"
#elif !defined(ATmega328_168) ^ defined(ATmega32U4_16U4 ) ^ defined(ATtiny85_45_25)
#error "May be selected only one MCU"
// SECURITY CHECK: Ensure only one console is selected
// If you get "not portable" warnings here, it's only because multiple models are active.
#if (defined(SCPH_1000) + defined(SCPH_3000) + defined(SCPH_3500_5500) + \
defined(SCPH_7000) + defined(SCPH_7500_9000) + defined(SCPH_100) + \
defined(SCPH_102) + defined(SCPH_xxx1) + defined(SCPH_xxx2) + \
defined(SCPH_xxx3) + defined(SCPH_5903) + defined(SCPH_xxxx)) > 1
#error "Too many consoles selected! Please uncomment ONLY ONE model."
#endif
#if defined(LED_RUN) && defined(PSNEE_DEBUG_SERIAL_MONITOR) && defined(ATtiny85_45_25)
#error"Compilation options LED_RUN and PSNEE_DEBUG_SERIAL_MONITOR are not simultaneously compatible with ATtiny85_45_25"
=======
// // --- MCU SELECTION CHECK ---
// #if !defined(ATmega328_168) && \
// !defined(ATmega328_168PB) && \
// !defined(ATmega32U4_16U4) && \
// !defined(ATtiny85_45_25)
// #error "No MCU selected! Please choose one supported architecture."
// #elif (defined(ATmega328_168) + \
// defined(ATmega328_168PB) + \
// defined(ATmega32U4_16U4) + \
// defined(ATtiny85_45_25) > 1)
// #error "Multiple MCUs selected! Please enable only one architecture."
// #endif
// --- RESOURCE CONFLICT CHECK (ATtiny) ---
#if defined(IS_ATTINY_FAMILY) && \
defined(LED_RUN) && \
defined(PSNEE_DEBUG_SERIAL_MONITOR)
#error "Resource conflict: LED_RUN and DEBUG_SERIAL are incompatible on ATtiny."
#endif
// --- Console Model Info ---
// Show target console.
#if defined(SCPH_1000)
#pragma message "Target Console: SCPH-1000 (NTSC-J)"
#elif defined(SCPH_3000)
@@ -399,29 +353,36 @@ void Debug_Inject(){ // Confirmation of region code injection
#pragma message "Target Console: SCPH-7500/9000 (NTSC-J)"
#elif defined(SCPH_100)
#pragma message "Target Console: SCPH-100 (NTSC-J)"
#elif defined(SCPH_101)
#pragma message "Target Console: SCPH-101 (NTSC-U/C)"
#elif defined(SCPH_102)
#pragma message "Target Console: SCPH-102 (PAL)"
#elif defined(SCPH_xxx1)
#pragma message "Target Console: Generic NTSC-U/C"
#pragma message "Target Console: SCPH_xxx1 Generic NTSC-U/C"
#elif defined(SCPH_xxx2)
#pragma message "Target Console: Generic PAL"
#pragma message "Target Console: SCPH_xxx2 Generic PAL"
#elif defined(SCPH_xxx3)
#pragma message "Target Console: Generic NTSC-J"
#pragma message "Target Console: SCPH_xxx3 Generic NTSC-J"
#elif defined(SCPH_5903)
#pragma message "Target Console: SCPH-5903 (Video CD Dual-Interface)"
#elif defined(SCPH_xxxx)
#pragma message "Target Console: Universal Region Mode"
#pragma message "Target Console: SCPH_xxxx Universal Region Mode"
#else
// Error if no console is uncommented
#error "Console not selected! Please uncomment one SCPH model."
#endif
// --- MCU Architecture Info ---
#if defined(IS_328_168_FAMILY)
#pragma message "Microcontroller: ATmega328/168 (Arduino Nano/Uno)"
#elif defined(IS_32U_FAMILY)
#pragma message "Microcontroller: ATmega32U4/16U4 (Leonardo/Pro Micro)"
#elif defined(IS_ATTINY_FAMILY)
#pragma message "Microcontroller: ATtiny85/45/25"
// Show detected microcontroller (e.g. __AVR_atmega328p__)
#define STRINGIZE(x) #x
#define TO_STR(x) STRINGIZE(x)
#ifdef __AVR_DEVICE_NAME__
#pragma message "Microcontroller: __AVR_" TO_STR(__AVR_DEVICE_NAME__) "__"
#endif
// --- RESOURCE CONFLICT CHECK (ATtiny) ---
#if defined(IS_ATTINY_FAMILY) && \
defined(LED_RUN) && \
defined(PSNEE_DEBUG_SERIAL_MONITOR)
#error "Resource conflict: LED_RUN and DEBUG_SERIAL are incompatible on ATtiny."
#endif
// --- Feature Status ---
@@ -430,7 +391,4 @@ void Debug_Inject(){ // Confirmation of region code injection
#pragma message "Feature: Serial Debug Monitor ENABLED"
#endif
#ifdef LED_RUN
#pragma message "Feature: Status LED (PB5) ENABLED"
>>>>>>> Stashed changes
#endif

View File

Before

Width:  |  Height:  |  Size: 524 KiB

After

Width:  |  Height:  |  Size: 524 KiB