mirror of
https://github.com/kalymos/PsNee.git
synced 2026-05-08 16:32:17 +00:00
Commit: System Optimization & Unified Architecture
Unified BIOS Patching: Merged management for SCPH-5500, 5000, and 3500. New Hardware Bypass: Added a physical switch option for SCPH-7000 to disable the BIOS patch on-the-fly. Compilation Feedback: Integrated #pragma messages to display during the build process. Code Documentation: improved technical clarity.
This commit is contained in:
@@ -11,21 +11,21 @@
|
||||
* 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
|
||||
* 1. STABILIZATION & ALIGNMENT (AX): Synchronizes execution with a clean rising
|
||||
* edge of the AX signal to establish a deterministic timing reference.
|
||||
*
|
||||
* 2. SILENCE DETECTION (GATING): Scans for a specific window of bus inactivity
|
||||
* (SILENCE_THRESHOLD) to ensure the system is at the correct pre-patching stage.
|
||||
* 2. ADDRESS CALL DETECTION (PHASE 2): Scans the bus for specific address calls
|
||||
* by validating consecutive polling blocks (SILENCE_THRESHOLD).
|
||||
*
|
||||
* 3. HARDWARE PULSE COUNTING (ISR): Switches to interrupt-driven logic (INT0/INT1)
|
||||
* to count address pulses with minimal latency and high-priority execution.
|
||||
* 3. SILENCE CONFIRMATION (GATING): Counts the exact number of validated silence
|
||||
* windows (CONFIRM_COUNTER_TARGET) to reach the correct pre-patching stage.
|
||||
*
|
||||
* 4. DATA OVERDRIVE (DX): Upon reaching the target pulse, triggers a calibrated
|
||||
* delay (BIT_OFFSET) and momentarily forces the DX pin to OUTPUT mode to
|
||||
* 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).
|
||||
*
|
||||
* 5. SECONDARY PATCH (AY): If enabled, repeats the silence/counting sequence
|
||||
* on a secondary address line (AY) for multi-stage memory patching.
|
||||
* ======================================================================================
|
||||
*/
|
||||
|
||||
@@ -35,12 +35,12 @@
|
||||
* 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; // Current address pulse countdown
|
||||
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)
|
||||
* Executes the real-time override on the target address cycle.
|
||||
* Triggered on rising edges to perform the real-time bus override.
|
||||
*/
|
||||
ISR(PIN_AX_INTERRUPT_VECTOR) {
|
||||
if (--impulse == 0) {
|
||||
@@ -89,10 +89,26 @@ ISR(PIN_AY_INTERRUPT_VECTOR) {
|
||||
#endif
|
||||
|
||||
void Bios_Patching(void) {
|
||||
uint8_t current_confirms = 0;
|
||||
uint16_t count;
|
||||
|
||||
patch = 0;
|
||||
// --- 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(2); // 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
|
||||
|
||||
@@ -106,9 +122,9 @@ void Bios_Patching(void) {
|
||||
}
|
||||
|
||||
// --- PHASE 2: SILENCE DETECTION ---
|
||||
// Accumulate validated silence blocks to filter boot noise.
|
||||
// Validate the exact number of silence windows to identify the boot stage.
|
||||
while (current_confirms < CONFIRM_COUNTER_TARGET) {
|
||||
count = SILENCE_THRESHOLD;
|
||||
uint16_t count = SILENCE_THRESHOLD;
|
||||
while (count > 0) {
|
||||
if (PIN_AX_READ != 0) {
|
||||
while (WAIT_AX_FALLING);
|
||||
@@ -117,7 +133,7 @@ void Bios_Patching(void) {
|
||||
count--;
|
||||
}
|
||||
if (count == 0) {
|
||||
current_confirms++; // Silence block confirmed
|
||||
current_confirms++; // Validated one silence window
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
489
PSNee/MCU.h
489
PSNee/MCU.h
@@ -225,8 +225,19 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef ATmega328_168
|
||||
|
||||
static inline void optimizePeripherals(void) {
|
||||
/*------------------------------------------------------------------------------------------------
|
||||
* FUNCTION : optimizePeripherals()
|
||||
*
|
||||
* DESCRIPTION :
|
||||
* Minimizes power consumption and internal noise by disabling unused hardware modules.
|
||||
* Performs a hard shutdown of peripherals to reduce current leakage and CPU jitter.
|
||||
*
|
||||
* 1. ANALOG SHUTDOWN: Disables ADC and Analog Comparator to prevent parasitic drain.
|
||||
* 2. BUFFER DISABLE: Disconnects digital input buffers on analog pins (A0-A5).
|
||||
* 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.
|
||||
------------------------------------------------------------------------------------------------*/
|
||||
static inline void OptimizePeripherals(void) {
|
||||
// 1. Disable Interrupts during setup
|
||||
cli();
|
||||
|
||||
@@ -275,59 +286,57 @@
|
||||
#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
|
||||
// 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_5000_5500) || defined(SCPH_3500) || defined(SCPH_3000) || defined(SCPH_1000)
|
||||
|
||||
// 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 output pins for the BIOS patch
|
||||
#define PIN_DX_OUTPUT DDRD |= (1 << DDD4) // Set DDRD register to configure PIND4 as output
|
||||
|
||||
// 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
|
||||
// --- 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)
|
||||
|
||||
// Address (AX) and Data (DX) lines for BIOS override
|
||||
#define PIN_AX_INPUT DDRD &= ~(1 << DDD2)
|
||||
#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)
|
||||
|
||||
// Blocking wait macros for AX synchronization
|
||||
#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)))
|
||||
|
||||
// Read the input pins for the BIOS patch
|
||||
#define PIN_AX_READ (!!(PIND & (1 << PIND2))) // Read the state of PIND2
|
||||
|
||||
// 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)
|
||||
|
||||
// Defin PIN_AY for HIGH_PATCH
|
||||
#if defined(SCPH_3000) || defined(SCPH_1000)
|
||||
// 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))
|
||||
@@ -336,10 +345,9 @@
|
||||
#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_VECTOR INT1_vect // Interrupt vector for INT1 (external interrupt)
|
||||
|
||||
|
||||
#endif
|
||||
// Handle switch input for BIOS patch
|
||||
|
||||
// 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)
|
||||
@@ -360,34 +368,42 @@
|
||||
|
||||
#ifdef ATmega32U4_16U4
|
||||
|
||||
static inline void optimizePeripherals(void) {
|
||||
// --- Digital Input Configuration (A0-A5) ---
|
||||
// On 32U4, A0-A5 are spread across Port F (F7-F4) and Port D (D4, D7)
|
||||
// 1. Set all Analog/Digital pins to Input
|
||||
DDRF &= ~((1<<DDF7)|(1<<DDF6)|(1<<DDF5)|(1<<DDF4)); // A0-A3
|
||||
DDRD &= ~((1<<DDD4)|(1<<DDD7)); // A4-A5
|
||||
|
||||
// 2. Disable Digital Input Buffers (DIDR0/DIDR2)
|
||||
// On 32U4, DIDR0 and DIDR2 control the digital buffer for ADC pins.
|
||||
// Setting these bits to 0 ENABLES digital reads (PINF/PIND).
|
||||
DIDR0 &= ~((1<<ADC7D)|(1<<ADC6D)|(1<<ADC5D)|(1<<ADC4D)); // A0-A3
|
||||
DIDR2 &= ~((1<<ADC10D)|(1<<ADC8D)); // A4-A5
|
||||
static inline void OptimizePeripherals(void) {
|
||||
// 1. Global Interrupt Disable during hardware reconfiguration
|
||||
cli();
|
||||
|
||||
// --- Analog Modules Shutdown (32U4 specific) ---
|
||||
// 1. Disable the ADC module
|
||||
ADCSRA &= ~(1 << ADEN);
|
||||
// 2. Disable the Analog Comparator
|
||||
ACSR |= (1 << ACD);
|
||||
// 2. Analog Front-End Shutdown
|
||||
ADCSRA &= ~(1 << ADEN); // Disable ADC
|
||||
ACSR |= (1 << ACD); // Disable Analog Comparator
|
||||
|
||||
// --- Power Reduction Register (32U4 Hard Clock Shut Off) ---
|
||||
// PRR0 and PRR1 handle the clocks on 32U4.
|
||||
// Note: We DO NOT touch PRUSB if we want to keep the Serial/USB alive.
|
||||
PRR0 |= (1 << PRADC) | (1 << PRTIM0) | (1 << PRTIM1);
|
||||
PRR1 |= (1 << PRTIM3); // 32U4 has an extra Timer 3
|
||||
// 3. Digital Input Buffer Disable (DIDR0 & DIDR2)
|
||||
// 32U4 has more analog channels (ADC0-ADC7 and ADC8-ADC13)
|
||||
DIDR0 = 0xFF; // Disable digital buffers on F0-F7
|
||||
DIDR2 = 0x3F; // Disable digital buffers on D4, D6, D7, B4, B5, B6
|
||||
|
||||
// --- Timer 0 Specific Shutdown ---
|
||||
TCCR0B = 0;
|
||||
TIMSK0 = 0;
|
||||
// 4. GPIO Strategy (Unused pins to Pull-up)
|
||||
// On 32U4, Port C is small (only PC6/PC7). Adjusting to cover most unused pins.
|
||||
PORTC |= 0xFF;
|
||||
PORTE |= 0xFF; // Extra port on 32U4
|
||||
|
||||
// 5. Power Reduction Registers (PRR0 & PRR1)
|
||||
// PRR0 handles TWI, SPI, Timers 0, 1 and ADC.
|
||||
PRR0 = (1 << PRTWI) | // I2C Off
|
||||
(1 << PRSPI) | // SPI Off
|
||||
(1 << PRTIM0) | // Timer 0 Off
|
||||
(1 << PRTIM1) | // Timer 1 Off
|
||||
(1 << PRADC); // ADC Clock Off
|
||||
|
||||
// PRR1 handles Timer 3, Timer 4 and USB.
|
||||
// We KEEP PRUSART1 (Serial1) and PRUSB active for communication.
|
||||
PRR1 = (1 << PRTIM3) | // Timer 3 Off
|
||||
(1 << PRTIM4); // Timer 4 Off (High speed timer)
|
||||
|
||||
// 6. Double Security for Timer 0 (Redundancy)
|
||||
TCCR0B = 0;
|
||||
TIMSK0 = 0;
|
||||
|
||||
// 7. Note: USB/Serial1 remain functional unless PRUSB/PRUSART1 are set.
|
||||
}
|
||||
|
||||
//#define F_CPU 16000000L
|
||||
@@ -400,111 +416,184 @@
|
||||
#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) ---
|
||||
|
||||
// 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)
|
||||
|
||||
// Handling the main pins
|
||||
|
||||
// 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)
|
||||
|
||||
// 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_102_legacy) || defined(SCPH_100) || \
|
||||
defined(SCPH_7000_9000) || defined(SCPH_5500) || defined(SCPH_3500_5000) || \
|
||||
defined(SCPH_3000) || defined(SCPH_1000)
|
||||
|
||||
// Address (AX / AY) and Data (DX) lines for BIOS override
|
||||
#define PIN_AX_INPUT DDRD &= ~(1 << DDD1) // AX on PD1 (INT1)
|
||||
#define PIN_AY_INPUT DDRD &= ~(1 << DDD0) // AY on PD0 (INT0)
|
||||
#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)
|
||||
|
||||
// Blocking wait macros for synchronization
|
||||
#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
|
||||
|
||||
// Secondary Address line (AY) for multi-stage patching (INT0)
|
||||
#if defined(SCPH_3000) || defined(SCPH_1000)
|
||||
#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
|
||||
#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
|
||||
|
||||
// // Globale interrupt seting
|
||||
// #define GLOBAL_INTERRUPT_ENABLE SREG |= (1 << 7)
|
||||
// #define GLOBAL_INTERRUPT_DISABLE SREG &= ~(1 << 7)
|
||||
|
||||
|
||||
|
||||
// // Handling the main pins
|
||||
|
||||
// // 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 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))
|
||||
|
||||
// // Handling and use of the LED pin
|
||||
// #ifdef LED_RUN
|
||||
// #define PIN_LED_OUTPUT DDRB |= (1 << DDB6)
|
||||
// #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))
|
||||
// #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
|
||||
|
||||
// #endif
|
||||
|
||||
//#endif
|
||||
|
||||
#ifdef ATtiny85_45_25
|
||||
|
||||
static inline void optimizePeripherals(void) {
|
||||
// --- Analog Modules Shutdown (ATtiny Specific) ---
|
||||
// 1. Disable the ADC module
|
||||
ADCSRA &= ~(1 << ADEN);
|
||||
// 2. Disable the Analog Comparator
|
||||
ACSR |= (1 << ACD);
|
||||
static inline void OptimizePeripherals(void) {
|
||||
// 1. Global Interrupt Disable during reconfiguration
|
||||
cli();
|
||||
|
||||
// --- Power Reduction Register (Hard Clock Shut Off) ---
|
||||
// On ATtiny85, PRR controls Timer 0, Timer 1, USI, and ADC.
|
||||
// We stop the ADC and Timer 0 clocks.
|
||||
PRR |= (1 << PRADC) | (1 << PRTIM0);
|
||||
// 2. Analog Modules Shutdown
|
||||
ADCSRA &= ~(1 << ADEN); // Disable ADC
|
||||
ACSR |= (1 << ACD); // Disable Analog Comparator
|
||||
|
||||
// --- Timer 0 Specific Shutdown ---
|
||||
TCCR0B = 0;
|
||||
TIMSK = 0; // On ATtiny85, it's TIMSK (not TIMSK0)
|
||||
}
|
||||
// 3. Digital Input Buffer Disable (DIDR0)
|
||||
// Disconnects digital buffers on PB0-PB5 to prevent leakage
|
||||
DIDR0 = 0x3F;
|
||||
|
||||
#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
|
||||
// 4. Power Reduction Register (PRR)
|
||||
// Shuts down clocks to ADC and Timer 0.
|
||||
// We KEEP USI or Timer 1 if required for specific logic.
|
||||
PRR |= (1 << PRADC) | (1 << PRTIM0);
|
||||
|
||||
// 5. Timer 0 Specific Shutdown (Hardware Redundancy)
|
||||
TCCR0B = 0;
|
||||
TIMSK &= ~(1 << OCIE0A); // Disable Timer 0 interrupts
|
||||
}
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -514,59 +603,109 @@ 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)
|
||||
|
||||
// Handling the main pins
|
||||
// --- Main Bus Interface (CD-ROM Controller) ---
|
||||
|
||||
// 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)
|
||||
// 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 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)
|
||||
// Timer Interrupt Management
|
||||
#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_9000) || \
|
||||
defined(SCPH_100) || \
|
||||
defined(SCPH_102)
|
||||
#error "ATtiny85/45/25 architecture is not compatible with the BIOS patch feature."
|
||||
#endif
|
||||
#endif
|
||||
// // Handling the main pins
|
||||
|
||||
// // 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
|
||||
// #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)
|
||||
|
||||
// // Define pull-ups set down at the main pin
|
||||
// #define PIN_DATA_CLEAR PORTB &= ~(1 << PB2)
|
||||
// #define PIN_WFCK_CLEAR PORTB &= ~(1 << PB4)
|
||||
|
||||
// // 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
|
||||
// #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"
|
||||
// #endif
|
||||
|
||||
// #if defined(PSNEE_DEBUG_SERIAL_MONITOR)
|
||||
// #include <SoftwareSerial.h>
|
||||
// SoftwareSerial mySerial(-1, 3); // RX, TX. (RX -1 = off)
|
||||
// #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
|
||||
|
||||
// #endif
|
||||
|
||||
// *****************************************************************************************************************
|
||||
// WARNING:
|
||||
|
||||
276
PSNee/PSNee.ino
276
PSNee/PSNee.ino
@@ -47,8 +47,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_5000_5500 // DX - D0 | AX - A15 | | 3.0j - CRC FF3EEB8C, 2.2j - CRC 24FC7E17
|
||||
//#define SCPH_3500 // DX - D0 | AX - A15 | AX - A15 | 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
|
||||
|
||||
@@ -130,7 +129,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
volatile uint8_t wfck_mode = 0;
|
||||
|
||||
// Variables de contrôle globales
|
||||
// Global buffer to store the 12-byte Sub-Q channel data
|
||||
// Global buffer to store the 12-byte SUBQ channel data
|
||||
uint8_t subqBuffer[12];
|
||||
uint8_t hysteresis = 0;
|
||||
|
||||
@@ -145,58 +144,67 @@ 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:
|
||||
|
||||
WFCK: __----------------------- // CONTINUOUS (PU-7 .. PU-20)(GATE)
|
||||
|
||||
WFCK: __-_-_-_-_-_-_-_-_-_-_-_- // FREQUENCY (PU-22 or newer)
|
||||
|
||||
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() {
|
||||
// Default to static signal (PU-7 to PU-20)
|
||||
void BoardBetection() {
|
||||
// Default state: 0 (Static/GATE mode for PU-7 to PU-20)
|
||||
wfck_mode = 0;
|
||||
|
||||
/*
|
||||
INITIAL STABILIZATION DELAY (300ms)
|
||||
PU-7 to PU-20: Voltage climbs slowly (up to 54ms) then stays HIGH (static).
|
||||
PU-22+: Signal only starts oscillating (~7.3kHz) after approximately 297ms.
|
||||
Waiting 300ms bypasses all power-up transients and initial noise.
|
||||
*/
|
||||
/**
|
||||
* 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);
|
||||
|
||||
// Sampling window to detect the oscillating signal
|
||||
// Define a sampling window to capture potential oscillations
|
||||
uint16_t detectionWindow = 10000;
|
||||
|
||||
while (--detectionWindow) {
|
||||
/*
|
||||
On older boards (PU-7/20), the signal is now a solid HIGH.
|
||||
If we detect a LOW state, it's a potential oscillation from a newer board.
|
||||
*/
|
||||
/**
|
||||
* 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) {
|
||||
// Small debounce delay to filter out micro-glitches or remaining noise
|
||||
// Software debounce to filter out micro-glitches or parasitic noise
|
||||
uint8_t debounce = 100;
|
||||
while (--debounce);
|
||||
|
||||
/*
|
||||
VERIFICATION: If the signal is STILL low, it confirms a real
|
||||
clock cycle (WFCK). Older boards will never reach this state
|
||||
once stabilized at HIGH.
|
||||
*/
|
||||
/**
|
||||
* 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: PU-22 or newer
|
||||
wfck_mode = 1; // Target confirmed: PU-22 or newer (Frequency mode)
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -207,14 +215,18 @@ void board_detection() {
|
||||
#endif
|
||||
}
|
||||
|
||||
//******************************************************************************************************************
|
||||
// Reads a complete 12-byte SUBQ transmission from the CD drive.
|
||||
// Uses clock-edge synchronization and includes a safety timeout for malformatted streams.
|
||||
//******************************************************************************************************************
|
||||
/******************************************************************************************************************
|
||||
* 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).
|
||||
******************************************************************************************************************/
|
||||
|
||||
void captureSubQ(void) {
|
||||
// Total bytes to read from the CD-ROM subcode channel
|
||||
uint8_t bytesRemaining = 12;
|
||||
void CaptureSUBQ(void) {
|
||||
uint8_t bytesRemaining = 12; // Total frame size for a complete SUBQ
|
||||
uint8_t* bufferPtr = subqBuffer;
|
||||
|
||||
do {
|
||||
@@ -222,12 +234,19 @@ void captureSubQ(void) {
|
||||
uint8_t bitsToRead = 8;
|
||||
|
||||
while (bitsToRead--) {
|
||||
// PHASE 1: Wait for Clock (SQCK) to go LOW then HIGH (Sampling on Rising Edge)
|
||||
// This ensures data is stable on the SUBQ pin before reading.
|
||||
/**
|
||||
* 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
|
||||
|
||||
// PHASE 2: Shift bit into the byte (LSB first)
|
||||
/**
|
||||
* 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) {
|
||||
currentByte |= 0x80;
|
||||
@@ -235,39 +254,46 @@ void captureSubQ(void) {
|
||||
}
|
||||
// Store reconstructed byte and advance pointer
|
||||
*bufferPtr++ = currentByte;
|
||||
} while (--bytesRemaining); // Faster than (bytesRemaining < 12)
|
||||
|
||||
} while (--bytesRemaining); // Efficient countdown for AVR binary size
|
||||
|
||||
#if defined(PSNEE_DEBUG_SERIAL_MONITOR)
|
||||
logSubQ(subqBuffer);
|
||||
LogSUBQ(subqBuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************************
|
||||
* Processes sector data for the SCPH-5903 (Dual-interface PS1) to differentiate
|
||||
* between PlayStation games and Video CDs (VCD).
|
||||
/******************************************************************************************
|
||||
* FUNCTION : Filter_SUBQ_Samples() [SCPH_5903 Dual-Interface Variant]
|
||||
*
|
||||
* 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.
|
||||
|
||||
**************************************************************************************/
|
||||
* 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 processLogic(uint8_t isDataSector) {
|
||||
void FilterSUBQSamples(uint8_t isDataSector) {
|
||||
uint8_t currentHysteresis = hysteresis;
|
||||
|
||||
// Fast filtering: most sectors fail here by checking sync markers (index 1 and 6)
|
||||
// --- 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];
|
||||
|
||||
/*
|
||||
INCREMENT CONDITIONS:
|
||||
1. Valid PSX Lead-In: data sector AND Point A0-A2 range AND NOT VCD (sub-mode 0x02).
|
||||
2. Tracking Maintenance: Valid sector (Mode 0x01 or Data) while already synchronized.
|
||||
*/
|
||||
/**
|
||||
* 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)) )
|
||||
{
|
||||
@@ -276,46 +302,45 @@ void captureSubQ(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
DECREMENT CONDITION:
|
||||
No match found or VCD Lead-In detected. Slowly decrease confidence level.
|
||||
*/
|
||||
// --- 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
|
||||
|
||||
/******************************************************************************************
|
||||
* Heuristic logic for standard PlayStation hardware (Non-VCD models).
|
||||
* FUNCTION : Filter_SUBQ_Samples()
|
||||
*
|
||||
* 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.
|
||||
* 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 processLogic(uint8_t isDataSector) {
|
||||
void FilterSUBQSamples(uint8_t isDataSector) {
|
||||
uint8_t currentHysteresis = hysteresis;
|
||||
|
||||
// Fast filtering: most sectors fail here by checking sync markers (index 1 and 6)
|
||||
// --- 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];
|
||||
|
||||
/*
|
||||
INCREMENT CONDITIONS:
|
||||
1. Lead-In Detection:
|
||||
- Point A0-A2 or higher (TOC info).
|
||||
- OR Point 01 with a timestamp near the spiral start:
|
||||
Checking if index 3 is >= 98 or <= 02 using unsigned wrap-around:
|
||||
(uint8_t)(subqBuffer[3] - 0x03) >= 0xF5 (245) covers 0x98 to 0x02.
|
||||
2. Tracking Maintenance:
|
||||
- Valid sector (Mode 0x01 or Data) while already synchronized.
|
||||
*/
|
||||
/*
|
||||
* 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)) )
|
||||
{
|
||||
@@ -324,10 +349,8 @@ void processLogic(uint8_t isDataSector) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
DECREMENT CONDITION:
|
||||
No valid match found. Slowly decrease confidence level.
|
||||
*/
|
||||
// --- STEP 2: Signal Decay / Missed Hits ---
|
||||
// Reduce the hit counter if the current SUBQ sample fails validation.
|
||||
if (currentHysteresis > 0) {
|
||||
hysteresis = currentHysteresis - 1;
|
||||
}
|
||||
@@ -349,7 +372,7 @@ void processLogic(uint8_t isDataSector) {
|
||||
* handles both speeds as it syncs directly to the signal edges.
|
||||
*********************************************************************************************/
|
||||
|
||||
void performInjectionSequence(uint8_t injectSCEx) {
|
||||
void PerformInjectionSequence(uint8_t injectSCEx) {
|
||||
/*
|
||||
Security strings (44-bit SCEx) for the three main regions:
|
||||
0: NTSC-J (SCEI - Sony Computer Entertainment Inc.)
|
||||
@@ -454,40 +477,30 @@ void performInjectionSequence(uint8_t injectSCEx) {
|
||||
|
||||
|
||||
#if defined(PSNEE_DEBUG_SERIAL_MONITOR)
|
||||
Debug_Inject();
|
||||
DebugInject();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Init() {
|
||||
|
||||
// --- Hardware Power & Peripheral Optimization ---
|
||||
#if defined(ATmega328_168)
|
||||
optimizePeripherals();
|
||||
OptimizePeripherals();
|
||||
#endif
|
||||
|
||||
#ifdef LED_RUN
|
||||
PIN_LED_OUTPUT;
|
||||
#endif
|
||||
|
||||
// --- Critical Boot Patching ---
|
||||
#ifdef BIOS_PATCH
|
||||
//uint8_t skipPatch = 0;
|
||||
|
||||
// #ifdef SCPH_7000
|
||||
// // Check hardware switch for SCPH-7000 models
|
||||
// PIN_SWITCH_INPUT;
|
||||
// PIN_SWITCH_SET;
|
||||
// if (PIN_SWITCH_READ == 0){
|
||||
// skipPatch =1; // Disable patching if switch is triggered
|
||||
// }
|
||||
// #endif
|
||||
|
||||
// #ifdef LED_RUN
|
||||
// PIN_LED_ON;
|
||||
// #endif
|
||||
|
||||
// Execute BIOS patching unless bypassed by switch
|
||||
// if (skipPatch == 0) {
|
||||
Bios_Patching();
|
||||
// }
|
||||
// Execute BIOS patching
|
||||
Bios_Patching();
|
||||
|
||||
// #ifdef LED_RUN
|
||||
// PIN_LED_OFF;
|
||||
@@ -497,6 +510,7 @@ void Init() {
|
||||
PIN_SQCK_INPUT;
|
||||
PIN_SUBQ_INPUT;
|
||||
|
||||
// --- Debug Interface Setup ---
|
||||
#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
|
||||
@@ -504,38 +518,38 @@ void Init() {
|
||||
Serial.begin(500000); // 60 bytes in 12ms (expected data: ~26 bytes / 12ms) // update: this is actually quicker
|
||||
#endif
|
||||
|
||||
// Detect board generation (PU-7 to PU-22+) before starting the main loop
|
||||
board_detection();
|
||||
}
|
||||
// --- Console Analysis ---
|
||||
// Identify board revision (PU-7 to PU-22+) to set correct injection timings
|
||||
BoardBetection();
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
Init();
|
||||
|
||||
|
||||
while (1) {
|
||||
|
||||
// Small delay to prevent re-reading the tail end of the same SUBQ packet
|
||||
// 1. Timing Sync: Prevent reading the tail end of the previous SUBQ packet
|
||||
_delay_ms(1);
|
||||
|
||||
//Capture the 12-byte Sub-Q channel data into subqBuffer
|
||||
captureSubQ();
|
||||
// 2. Data Acquisition: Capture 12-byte SUBQ channel stream into buffer
|
||||
CaptureSUBQ();
|
||||
|
||||
// Optimized Sector Filtering:
|
||||
// 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);
|
||||
|
||||
|
||||
// Execute selected logic
|
||||
processLogic(isDataSector);
|
||||
FilterSUBQSamples(isDataSector);
|
||||
|
||||
//Trigger SCEx injection once the confidence threshold is reached
|
||||
// 5. Execution: Trigger SCEx injection once confidence (hysteresis) is reached
|
||||
if (hysteresis >= HYSTERESIS_MAX) {
|
||||
performInjectionSequence(INJECT_SCEx);
|
||||
PerformInjectionSequence(INJECT_SCEx);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
295
PSNee/settings.h
295
PSNee/settings.h
@@ -1,27 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
The _delay_us function uses loops to generate an approximate delay for the specified number of microseconds.
|
||||
It calculates the number of clock cycles required to achieve the requested delay and loops the corresponding number of times.
|
||||
|
||||
The temporal precision of _delay_us depends on the microcontroller's clock frequency (F_CPU).
|
||||
For the ATmega328 operating at a typical frequency of 16 MHz, here are some details on the precision.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/*------------------------------------------------------------------------------------------------
|
||||
Specific parameter section for BIOS patches
|
||||
------------------------------------------------------------------------------------------------*/
|
||||
* BIOS PATCH PARAMETERS EXPLANATION
|
||||
*
|
||||
* 1. SILENCE_THRESHOLD:
|
||||
* Defines the size of a polling block where the AX pin must remain LOW.
|
||||
* It serves as a "bus address call detector" for specific idle windows.
|
||||
*
|
||||
* 2. CONFIRM_COUNTER_TARGET:
|
||||
* Defines the exact number of SILENCE_THRESHOLD blocks that must be validated
|
||||
* consecutively before arming the hardware interrupt (ISR).
|
||||
*
|
||||
* 3. PULSE_COUNT:
|
||||
* The starting value for the 'impulse' down-counter. It counts physical
|
||||
* rising edges on the AX pin until it reaches zero to trigger the injection.
|
||||
*
|
||||
* 4. BIT_OFFSET_CYCLES (Inside ISR):
|
||||
* The sub-microsecond delay (CPU cycles) applied after the final pulse to
|
||||
* precisely align the DX injection with the target bit in the memory cycle.
|
||||
*
|
||||
* 5. OVERRIDE_CYCLES (Inside ISR):
|
||||
* The duration for which the DX pin is forced to OUTPUT mode to overwrite
|
||||
* the original BIOS data with the custom state.
|
||||
------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// tested with an Atmega328P
|
||||
|
||||
|
||||
|
||||
// ------ SCPH 100 / 102 ------
|
||||
#if defined(SCPH_100) || \
|
||||
defined(SCPH_102)
|
||||
|
||||
#define BIOS_PATCH
|
||||
#define SILENCE_THRESHOLD 1500
|
||||
#define CONFIRM_COUNTER_TARGET 8
|
||||
@@ -53,8 +62,8 @@
|
||||
#endif
|
||||
|
||||
|
||||
// // ----- SCPH 5000 / 5500 -----
|
||||
#ifdef SCPH_5000_5500
|
||||
// // ----- SCPH 3500 / 5000 / 5500 -----
|
||||
#ifdef SCPH_3500_5500
|
||||
#define BIOS_PATCH
|
||||
#define SILENCE_THRESHOLD 35600
|
||||
#define CONFIRM_COUNTER_TARGET 1
|
||||
@@ -63,30 +72,6 @@
|
||||
#define OVERRIDE_CYCLES 3
|
||||
#endif
|
||||
|
||||
|
||||
// // // -------- SCPH 5000 --------
|
||||
// #ifdef SCPH_5000
|
||||
// #define BIOS_PATCH_3
|
||||
// #define INTERRUPT_RISING
|
||||
// #define SILENCE_THRESHOLD 35000
|
||||
// #define CONFIRM_COUNTER_TARGET 1
|
||||
// #define PULSE_COUNT 84
|
||||
// #define BIT_OFFSET_CYCLES 60
|
||||
// #define OVERRIDE_CYCLES 3
|
||||
// #endif
|
||||
// // #endif
|
||||
|
||||
// // -------- SCPH 3500 --------
|
||||
#ifdef SCPH_3500
|
||||
#define BIOS_PATCH
|
||||
#define SILENCE_THRESHOLD 34000
|
||||
#define CONFIRM_COUNTER_TARGET 1
|
||||
#define PULSE_COUNT 85
|
||||
#define BIT_OFFSET_CYCLES 44
|
||||
#define OVERRIDE_CYCLES 3
|
||||
#endif
|
||||
|
||||
|
||||
// // -------- SCPH 3000 --------
|
||||
#ifdef SCPH_3000
|
||||
#define BIOS_PATCH
|
||||
@@ -118,7 +103,7 @@
|
||||
#define BIT_OFFSET_2_CYCLES 54
|
||||
#define OVERRIDE_2_CYCLES 3
|
||||
#endif
|
||||
// #endif
|
||||
|
||||
/*------------------------------------------------------------------------------------------------
|
||||
Region Settings Section
|
||||
------------------------------------------------------------------------------------------------*/
|
||||
@@ -126,7 +111,7 @@
|
||||
#if defined(SCPH_100) || \
|
||||
defined(SCPH_7500_9000) || \
|
||||
defined(SCPH_7000) || \
|
||||
defined(SCPH_5000_5500) || \
|
||||
defined(SCPH_3500_5500) || \
|
||||
defined(SCPH_3500) || \
|
||||
defined(SCPH_3000) || \
|
||||
defined(SCPH_1000) || \
|
||||
@@ -156,39 +141,81 @@
|
||||
serial debug section
|
||||
------------------------------------------------------------------------------------------------*/
|
||||
|
||||
/******************************************************************************************
|
||||
* FUNCTION : Debug_Log
|
||||
*
|
||||
* DESCRIPTION :
|
||||
* Transmits hardware status and system configuration via the serial interface.
|
||||
* Displays MCU frequency, WFCK detection mode, and active regional settings.
|
||||
*
|
||||
* - ATtiny: Uses a compact "Short-Code" format to minimize serial bus overhead.
|
||||
* - Standard MCUs: Provides verbose, human-readable system diagnostics.
|
||||
*
|
||||
* INPUT : Wfck_mode (int) - The detected board generation (0: Static, 1: Frequency).
|
||||
******************************************************************************************/
|
||||
#if defined(PSNEE_DEBUG_SERIAL_MONITOR)
|
||||
|
||||
void Debug_Log (int Wfck_mode){ //Information about the MCU, and old or late console mode.
|
||||
void Debug_Log (int Wfck_mode){
|
||||
|
||||
#if defined(ATtiny85_45_25)
|
||||
mySerial.print("m "); mySerial.println(Wfck_mode);
|
||||
#else
|
||||
Serial.print(" MCU frequency: "); Serial.print(F_CPU); Serial.println(" Hz");
|
||||
//Serial.print(" lows: "); Serial.println(Lows);
|
||||
Serial.print(" wfck_mode: "); Serial.println(Wfck_mode);
|
||||
Serial.print(" region: "); Serial.print(region[0]); Serial.print(region[1]); Serial.println(region[2]);
|
||||
#endif
|
||||
}
|
||||
#if defined(ATtiny85_45_25)
|
||||
// --- COMPACT SYSTEM LOG (ATtiny) ---
|
||||
// Minimalistic output to save CPU cycles and maintain timing precision.
|
||||
mySerial.print("m ");
|
||||
mySerial.println(Wfck_mode); // Mode indicator
|
||||
#else
|
||||
// --- VERBOSE DIAGNOSTICS (ATmega) ---
|
||||
// Detailed system information for standard development and debugging.
|
||||
Serial.print(" MCU frequency: ");
|
||||
Serial.print(F_CPU);
|
||||
Serial.println(" Hz");
|
||||
|
||||
// Logs SUBQ packets to serial. We only have 12ms to write logs before the next packet.
|
||||
// Slower MCUs (like ATtiny) receive minimal formatting to save cycles.
|
||||
void logSubQ(uint8_t *dataBuffer) {
|
||||
Serial.print(" wfck_mode: ");
|
||||
Serial.println(Wfck_mode); // Board generation (0: Legacy, 1: Modern)
|
||||
|
||||
Serial.print(" region: ");
|
||||
Serial.print(region[0]);
|
||||
Serial.print(region[1]);
|
||||
Serial.println(region[2]); // Active injection string (e.g., SCEE)
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************************
|
||||
* FUNCTION : LogSUBQ
|
||||
*
|
||||
* DESCRIPTION :
|
||||
* Logs captured SUBQ frames to the serial interface.
|
||||
* Timing is critical: the entire 12-byte frame must be processed and transmitted
|
||||
* within the ~12ms window before the next SUBQ packet arrives.
|
||||
*
|
||||
* - ATtiny: Uses minimal formatting (no spaces) to stay within the timing budget.
|
||||
* - Standard MCUs: Includes spaces for better readability.
|
||||
*
|
||||
* INPUT : dataBuffer (uint8_t*) - Pointer to the 12-byte SUBQ frame.
|
||||
******************************************************************************************/
|
||||
|
||||
void LogSUBQ(uint8_t *dataBuffer) {
|
||||
|
||||
// A bad sector read results in zeros (except for CRC). Skip logging if first 4 bytes are 0.
|
||||
/**
|
||||
* ERROR FILTERING:
|
||||
* A failed sector read usually results in zeroed data (excluding CRC).
|
||||
* Skip logging if the first 4 bytes are null to reduce bus traffic.
|
||||
*/
|
||||
if (!(dataBuffer[0] == 0 && dataBuffer[1] == 0 && dataBuffer[2] == 0 && dataBuffer[3] == 0)) {
|
||||
|
||||
#if defined(ATtiny85_45_25)
|
||||
// Compact formatting for ATtiny to meet the 12ms timing constraint
|
||||
// --- 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
|
||||
mySerial.print("0"); // Leading zero padding for hex alignment
|
||||
}
|
||||
mySerial.print(dataBuffer[i], HEX);
|
||||
}
|
||||
mySerial.println("");
|
||||
|
||||
#else
|
||||
// Standard formatting with spaces for more powerful MCUs
|
||||
// --- STANDARD FORMATTING (ATmega) ---
|
||||
// More descriptive output with space separation for easier debugging.
|
||||
for (uint8_t i = 0; i < 12; i++) {
|
||||
if (dataBuffer[i] < 0x10) {
|
||||
Serial.print("0"); // Leading zero padding
|
||||
@@ -202,66 +229,134 @@ void logSubQ(uint8_t *dataBuffer) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Debug_Inject(){ // Confirmation of region code injection
|
||||
/******************************************************************************************
|
||||
* FUNCTION : Debug_Inject
|
||||
*
|
||||
* DESCRIPTION :
|
||||
* Provides real-time visual confirmation during SCEx region code injection.
|
||||
* Used to verify that the hysteresis threshold has been met and the
|
||||
* injection sequence is active.
|
||||
*
|
||||
* - ATtiny: Prints a single '!' to minimize CPU blocking during the critical
|
||||
* injection timing window.
|
||||
* - Standard MCUs: Prints a clear, verbose "INJECT !" message.
|
||||
******************************************************************************************/
|
||||
void DebugInject(){
|
||||
|
||||
#if defined(ATtiny85_45_25)
|
||||
mySerial.print("!");
|
||||
// --- MINIMALIST NOTIFICATION (ATtiny) ---
|
||||
mySerial.print("!");
|
||||
|
||||
#else
|
||||
// --- VERBOSE NOTIFICATION (ATmega) ---
|
||||
// Standard visual feedback for debugging and monitoring.
|
||||
Serial.println(" INJECT ! ");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------------------------
|
||||
Compilation message
|
||||
-----------------------------------------------------------------------------------------------*/
|
||||
/*
|
||||
* =============================================================
|
||||
* COMPILATION CHECKS
|
||||
* =============================================================
|
||||
*/
|
||||
|
||||
#if !defined(SCPH_xxx3) && \
|
||||
!defined(SCPH_102) && \
|
||||
!defined(SCPH_101) && \
|
||||
!defined(SCPH_100) && \
|
||||
!defined(SCPH_7500_9000) && \
|
||||
!defined(SCPH_7000) && \
|
||||
!defined(SCPH_5000_5500) && \
|
||||
!defined(SCPH_3500) && \
|
||||
// --- CONSOLE SELECTION CHECK ---
|
||||
#if !defined(SCPH_1000) && \
|
||||
!defined(SCPH_3000) && \
|
||||
!defined(SCPH_1000) && \
|
||||
!defined(SCPH_5903) && \
|
||||
!defined(SCPH_3500_5500) && \
|
||||
!defined(SCPH_7000) && \
|
||||
!defined(SCPH_7500_9000) && \
|
||||
!defined(SCPH_100) && \
|
||||
!defined(SCPH_101) && \
|
||||
!defined(SCPH_102) && \
|
||||
!defined(SCPH_xxx1) && \
|
||||
!defined(SCPH_xxx2) && \
|
||||
!defined(SCPH_xxx3) && \
|
||||
!defined(SCPH_5903) && \
|
||||
!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_5000_5500) ^ \
|
||||
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."
|
||||
#error "No console selected! Please uncomment your SCPH model."
|
||||
|
||||
#elif (defined(SCPH_1000) + \
|
||||
defined(SCPH_3000) + \
|
||||
defined(SCPH_3500_5500) + \
|
||||
defined(SCPH_7000) + \
|
||||
defined(SCPH_7500_9000) + \
|
||||
defined(SCPH_100) + \
|
||||
defined(SCPH_101) + \
|
||||
defined(SCPH_102) + \
|
||||
defined(SCPH_xxx1) + \
|
||||
defined(SCPH_xxx2) + \
|
||||
defined(SCPH_xxx3) + \
|
||||
defined(SCPH_5903) + \
|
||||
defined(SCPH_xxxx) > 1)
|
||||
#error "Multiple consoles selected! Please enable only one SCPH model."
|
||||
#endif
|
||||
|
||||
// --- MCU SELECTION CHECK ---
|
||||
#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"
|
||||
#error "No MCU selected! Please choose one supported architecture."
|
||||
|
||||
#elif (defined(ATmega328_168) + \
|
||||
defined(ATmega32U4_16U4) + \
|
||||
defined(ATtiny85_45_25) > 1)
|
||||
#error "Multiple MCUs selected! Please enable only one architecture."
|
||||
#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"
|
||||
// --- RESOURCE CONFLICT CHECK (ATtiny) ---
|
||||
#if defined(ATtiny85_45_25) && \
|
||||
defined(LED_RUN) && \
|
||||
defined(PSNEE_DEBUG_SERIAL_MONITOR)
|
||||
#error "Resource conflict: LED_RUN and DEBUG_SERIAL are incompatible on ATtiny."
|
||||
#endif
|
||||
|
||||
// --- Console Model Info ---
|
||||
#if defined(SCPH_1000)
|
||||
#pragma message "Target Console: SCPH-1000 (NTSC-J)"
|
||||
#elif defined(SCPH_3000)
|
||||
#pragma message "Target Console: SCPH-3000 (NTSC-J)"
|
||||
#elif defined(SCPH_3500_5500)
|
||||
#pragma message "Target Console: SCPH-3500/5000/5500 (NTSC-J)"
|
||||
#elif defined(SCPH_7000)
|
||||
#pragma message "Target Console: SCPH-7000 (Internal Switch enabled)"
|
||||
#elif defined(SCPH_7500_9000)
|
||||
#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"
|
||||
#elif defined(SCPH_xxx2)
|
||||
#pragma message "Target Console: Generic PAL"
|
||||
#elif defined(SCPH_xxx3)
|
||||
#pragma message "Target Console: 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"
|
||||
#endif
|
||||
|
||||
// --- MCU Architecture Info ---
|
||||
#if defined(ATmega328_168)
|
||||
#pragma message "Microcontroller: ATmega328/168 (Arduino Nano/Uno)"
|
||||
#elif defined(ATmega32U4_16U4)
|
||||
#pragma message "Microcontroller: ATmega32U4/16U4 (Leonardo/Pro Micro)"
|
||||
#elif defined(ATtiny85_45_25)
|
||||
#pragma message "Microcontroller: ATtiny85/45/25"
|
||||
#endif
|
||||
|
||||
// --- Feature Status ---
|
||||
|
||||
#ifdef PSNEE_DEBUG_SERIAL_MONITOR
|
||||
#pragma message "Feature: Serial Debug Monitor ENABLED"
|
||||
#endif
|
||||
|
||||
#ifdef LED_RUN
|
||||
#pragma message "Feature: Status LED (PB5) ENABLED"
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user