1
0
mirror of https://github.com/kalymos/PsNee.git synced 2026-05-09 16:46:23 +00:00
Files
kalymos.PsNee/PSNee/MCU.h
kalymos 0d2290aa68 Merge V9.0 into Main (#111)
* MUC-MCU

Fixed the MUC-MCU file name.
Fixed a bug that prevented additional MCUs from being compiled.
Modified the clock registers for ATtiny 48-88s; the TCCROB register is missing in these MUCs.

* Too many things to summarize

Refactoring of the setting file, to be able to have settings specifying the HYSTERESIS_MAX variable.
Renamed precompilation variable in BIOS_patching file.
Changing console selection in .ino file

* Renaming files to make updating easier

* Update README.md

* logo 8.7

* optimization on regin injection

* Ad bios patch 102A, and correct some images.

* SCPH_102A bios patch WIP

* Cleaning the selection area

Redesign of the selection area, and addition of the SCPH_hyma mode equivalent to the legacy mode with the difference of a hysteresis of 25

* Layout modification

* clining

* ad debug mode

* debug mesga

* creation of debug functions, and cleaning

* Update PSNee.ino

* serial debug cleaning

* added compilation message

* some comment cleaning

* removal of the TIMER

removal of the ISR(CTC_TIMER_VECTOR) function, and all its dependencies.

- Timer_Start
- Timer_Stop

modification
- Board detection
- inject_SCEX
- BIOS_PATCH
- MCU
- Setting

* Update PSNee.ino

Implementing a dedicated board_detection function with optimized logic.
Remodeling the inject_SCEX function.

* timer optimization

* Breaking down the main function into smaller modules.

Modular breakdown: Separated main logic into
 - captureSubQ,
 - logic_SCPH_5903,
 - logic_Standard,
 - performInjectionSequence.

Added support for SCPH-5903 by RepairBox

Co-Authored-By: RepairBox <33960601+danielfergisz@users.noreply.github.com>

* Optimization

performInjectionSequence(): Deep refactor with a cleaner.
captureSubQ(): Faster bit-banging and improved timing accuracy.
board_detection(): Optimized logic .
General Cleanup: Fixed all warnings and minimized memory footprint.

* Optimization

Optimization of the performInjectionSequence function
BIOS patch verification (work in progress)
and general code cleanup

* BIOS patch obtimisation

* opti patch bios 3500

* opti bios patch SCPH-1000

* opti BIOS patch SCPH-3000, SCPH-100.

* refactor: optimize BIOS patching sequence with refined timing nomenclature

Refined the BIOS patching and standardized
timing nomenclature for better technical clarity.

Changes:
- Ad technical documentation within the code.
- Standardized timing variables for better clarity:
    - BOOT_OFFSET: Replaces initial checkpoint.
    - FOLLOWUP_OFFSET: Replaces initial checkpoint2.
    - PULSE_COUNT: Replaces trigger .
    - BIT_OFFSET: Replaces hold .
    - OVERRIDE: Replaces patching.

* test refactor: optimize PS1 patch for SCPH-100 using zero-latency polling

Ported the BIOS patch from ISR to manual polling to achieve cycle-accurate
precision for 33.86MHz bus timing.

* test neo BIOS patch

* Refactor pulse counting logic for jitter reduction

* BIOS patch simplification

Removal of ISR and reduction of code in the BIOS patch, for improved portability and robustness.

For now it is only available for the SCPH-100 and 102.

* BIOS patche neo for SCPH-9000_7500 SCPH-7000 SCPH-5500

* BIOS patch neo SCPH-5000 SCPH-3500

* BIOS patche neo SCPH-3000 SCPH-1000

I finally completed the value conversion for the BIOS patch without IRS

* refactor: optimize core detection and injection logic for performance and size

- board_detection: Added early exit for newer boards and tightened the sampling loop to reduce CPU overhead.
- captureSubQ: Simplified clock-edge synchronization and localized buffers to improve register allocation.
- performInjectionSequence: Replaced bit-calculation math with a streamlined byte-shift approach. Refined WFCK modulation to ensure zero-jitter phase locking.
- logic_Standard/5903: Refactored pattern matching into a decision tree. Factorized redundant buffer checks (scbuf[1]/[6]) and replaced multiple equality tests with range comparisons.

Optimization results:
- Reduced Flash memory footprint (smaller binary size).
- Improved execution speed by removing redundant logical operations.
- Increased signal stability during the critical injection phase.

* PSNee v9.0 Update

New PSNeeCore v2: Completely rewritten core engine for all supported MCUs.
Auto-MCU Detection: Manual board selection removed. Automatically detects ATmega (328/168/128/PB), 32U4, and ATtiny families at compile time.
Deep Init Optimization: Hard-shutdown of unused internal modules (ADC, DAC, Timers) to minimize power draw and electrical noise.
Native PB Support: Full compatibility for 128PB and 328PB (PRR2 registers and extra Ports).

* PSNee v9.0 Update

New PSNeeCore v2: Completely rewritten core engine for all supported MCUs.
Auto-MCU Detection: Manual board selection removed. Automatically detects ATmega (328/168/128/PB), 32U4, and ATtiny families at compile time.
Deep Init Optimization: Hard-shutdown of unused internal modules (ADC, DAC, Timers) to minimize power draw and electrical noise.
Native PB Support: Full compatibility for 128PB and 328PB (PRR2 registers and extra Ports).
logo



---------

Co-authored-by: RepairBox <33960601+danielfergisz@users.noreply.github.com>
2026-04-19 19:31:47 +02:00

1033 lines
44 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// *****************************************************************************************************************
// Configuration for different microcontrollers (MCU) to ensure compatibility with the code:
// - Defines the clock speed, timers, and interrupts for each MCU.
// - Configures I/O pins for data, clocks, and switches according to the requirements.
// - Enables pull-up resistors on input pins where needed.
// - Manages external interrupts and LED outputs for system feedback.
// - Ensures the setup is compatible with various microcontroller models (e.g., ATmega328, ATtiny series, etc.)
// *****************************************************************************************************************
//******************************************************************************************************************
// Configuring the clock speed and associated registers. The formula for calculating
// the clock frequency is F_CPU / (TCCR0B |= (1<<CS00)) * (OCR0A = 159 +1) = 16000000 / (0 * (160)) = 100KHz
//******************************************************************************************************************
//******************************************************************************************************************
// Example: DDRB &= ~(1<<DDB0); // Create a mask by shifting the bit 1 to the left by DDB0's position (bit 0), and then inverting it.
// The bitwise AND operation (&=) updates the register DDRB by clearing the DDB0 bit (setting it to 0)
// without affecting the other bits.
//
// For instance, if DDRB = b11111111 (binary value), the operation shifts the bit 1 to the left to create the mask
// (1<<DDB0) = b00000001, and then inverts it, which results in b11111110. The AND operation with DDRB clears DDB0.
//
// Before: DDRB = b11111111 // Initial value of DDRB (all pins set as output)
// Mask: ~(b00000001) = b11111110 // Mask generated by shifting and inverting the bit
// After: DDRB = b11111110 // The DDB0 bit is cleared (set to 0), while other bits remain unchanged
//******************************************************************************************************************
//******************************************************************************************************************
// Example: DDRB |= (1<<DDB0); // Create a mask by shifting the bit 1 to the left by DDB0's position (bit 0),
// and then apply a bitwise OR operation to set DDB0 to 1 (configure pin PB0 as an output).
//
// For instance, if DDRB = b11111111 (binary value), the operation shifts the bit 1 to the left to create the mask
// (1<<DDB0) = b00000001. The OR operation with DDRB sets the DDB0 bit to 1, leaving other bits unchanged.
//
// Before: DDRB = b11111111 // Initial value of DDRB (all pins set as output)
// Mask: (1<<DDB0) = b00000001 // Mask generated by shifting the bit 1 to the left to position DDB0
// After: DDRB = b11111111 // The DDB0 bit is set to 1, configuring pin PB0 as an output
//******************************************************************************************************************
//******************************************************************************************************************
// Example: (PIND & (1<<PIND6)); // Create a mask by shifting the bit 1 to the left by PIND6's position (bit 6),
// and then apply a bitwise AND operation to read the state of the PIND6 pin.
// The result will be non-zero (true) if the PIND6 pin is high (1), and zero (false) if the PIND6 pin is low (0).
//
// For instance, if PIND = b10101010 (binary value), the operation shifts the bit 1 to the left to create the mask
// (1<<PIND6) = b01000000. The AND operation between PIND and the mask checks if the 6th bit is set to 1 (high).
//
// Before: PIND = b10101010 // Initial value of PIND (register containing input pin states)
// Mask: (1<<PIND6) = b01000000 // Mask generated by shifting the bit 1 to the left to position PIND6
// Operation: PIND & b01000000 = b00000000 // If PIND6 is low (0)
// Operation: PIND & b01000000 = b01000000 // If PIND6 is high (1)
//
//******************************************************************************************************************
//******************************************************************************************************************
// Example: EICRA |= (1<<ISC01) | (1<<ISC00);
// This operation configures the external interrupt sense control (ISC) for interrupt INT0 (External Interrupt Request 0).
// Specifically, it sets the mode of INT0 to "rising edge" trigger, meaning the interrupt will be triggered when the pin
// transitions from low to high (rising edge).
//
// EICRA (External Interrupt Control Register A) controls how external interrupts INT0 and INT1 are triggered.
// The bits ISC01 and ISC00 in this register define the trigger mode for interrupt INT0.
//
// - Setting ISC01 to 1 and ISC00 to 1 (via the OR operation) configures INT0 to trigger on the rising edge.
//
// Before: EICRA = b00000000 // Initial value of EICRA, all interrupt sense control bits are cleared (no trigger mode set).
// Operation: EICRA |= (1<<ISC01) | (1<<ISC00) // Set ISC01 and ISC00 to 1 for rising edge trigger.
// After: EICRA = b00000011 // The bits ISC01 and ISC00 are now set, configuring INT0 to trigger on rising edge.
//
// This technique is commonly used to configure external interrupts to trigger based on specific events like a rising
// or falling edge on the external interrupt pin (INT0 or INT1).
//******************************************************************************************************************
//******************************************************************************************************************
// Example: EICRA = (EICRA & ~(1<<ISC00)) | (1<<ISC01);
// This operation configures the external interrupt sense control (ISC) for interrupt INT0 (External Interrupt Request 0).
// Specifically, it sets INT0 to trigger on a "falling edge" (when the signal transitions from high to low).
//
// The bits ISC01 and ISC00 in the EICRA register define how the external interrupt INT0 is triggered. The operation
// clears the bit ISC00 while setting ISC01 to 1, configuring INT0 to trigger when the pin transitions from high to low,
// i.e., on the falling edge.
//
// EICRA (External Interrupt Control Register A) controls how external interrupts INT0 and INT1 are triggered.
// - ISC01 = 1, ISC00 = 0 configures INT0 to trigger on falling edge (high to low transition).
//
// Before: EICRA = b00000011 // Initial value with ISC01 = 1 and ISC00 = 1 (rising edge trigger for INT0)
// Operation: EICRA & ~(1<<ISC00) clears ISC00 bit (sets it to 0) while keeping ISC01 at 1. Then OR operation with (1<<ISC01) ensures ISC01 stays 1.
// After: EICRA = b00000010 // The bit ISC00 is now cleared, configuring INT0 to trigger on the falling edge.
//
// This technique is used to configure the interrupt to trigger on the falling edge (transition from high to low),
// without changing the state of other control bits in the EICRA register.
//******************************************************************************************************************
#pragma once
#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()
*
* 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.
------------------------------------------------------------------------------------------------*/
void OptimizePeripherals(void) __attribute__((naked, section(".init3")));
void OptimizePeripherals(void) {
// Watchdog Timer Shutdown (Prevent Boot-Loop)
MCUSR = 0;
WDTCSR |= (1 << WDCE) | (1 << WDE);
WDTCSR = 0x00;
// Disable Interrupts during setup
cli();
// Analog Modules Shutdown (Critical for Power)
ADCSRA = 0; // Disable ADC
ACSR |= (1 << ACD); // Disable Analog Comparator
DIDR0 = 0xFF; // Pins A0 to A7
#if defined(__AVR_ATmega128PB__)
DIDR2 = 0xFF;
#endif
// GPIO Strategy (Unused pins to Pull-up)
// PORTx = 0xFF (Pull-ups) | DDRx = 0x00 (Inputs)
PORTC |= 0xFF;
#if defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega128PB__)
PORTE |= 0x0F; // Le Port E existe sur la série PB (PE0 à PE3)
#endif
// Power Reduction Register (PRR)
// We KEEP PRUSART0 (UART) and shut down EVERYTHING else.
// _delay_ms() will still work (it's cycle-based, not timer-based).
#if defined(__AVR_ATmega328PB__)
PRR0 = (1 << PRTWI0) | // I2C Off
(1 << PRSPI0) | // SPI Off
(1 << PRTIM0) | // Timer 0 Off
(1 << PRTIM1) | // Timer 1 Off
(1 << PRTIM2) | // Timer 2 Off
(1 << PRADC); // ADC Clock Off
PRR1 = (1 << PRTWI1) | // TWI 1 Off
(1 << PRSPI1) | // SPI 1 Off
(1 << PRTIM3) | // Timer 3 Off
(1 << PRTIM4); // Timer 4 Off
#elif defined(__AVR_ATmega128PB__)
PRR0 = (1 << PRTWI0) | // I2C Off
(1 << PRSPI0) | // SPI Off
(1 << PRTIM0) | // Timer 0 Off
(1 << PRTIM1) | // Timer 1 Off
(1 << PRTIM2) | // Timer 2 Off
(1 << PRADC); // ADC Clock Off
PRR1 = (1 << PRTWI1) | // TWI 1 Off
(1 << PRSPI1) | // SPI 1 Off
(1 << PRTIM3) | // Timer 3 Off
(1 << PRTIM4); // Timer 4 Off
PRR2 = (1 << PRTIM5); // Timer 5 Off
#else
PRR = (1 << PRTWI) | // I2C Off
(1 << PRSPI) | // SPI Off
(1 << PRTIM0) | // Timer 0 Off
(1 << PRTIM1) | // Timer 1 Off
(1 << PRTIM2) | // Timer 2 Off
(1 << PRADC); // ADC Clock Off
#endif
// Double Security for Timer 0
TCCR0B = 0; TIMSK0 = 0; // Timer 0
TCCR1B = 0; TIMSK1 = 0; // Timer 1
TCCR2B = 0; TIMSK2 = 0; // Timer 2
#if defined(TCCR3B)
TCCR3B = 0; TIMSK3 = 0; // Timer 3 (série PB)
TCCR4B = 0; TIMSK4 = 0; // Timer 4 (série PB)
#endif
}
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sfr_defs.h>
#include <util/delay.h>
// Main pin configuration
// Define the main pins as inputs
#define PIN_DATA_INPUT DDRB &= ~(1 << DDB0) // Set DDRB register to configure PINB0 as input
#define PIN_WFCK_INPUT DDRB &= ~(1 << DDB1) // Set DDRB register to configure PINB1 as input
#define PIN_SQCK_INPUT DDRD &= ~(1 << DDD6) // Set DDRD register to configure PINB6 as input
#define PIN_SUBQ_INPUT DDRD &= ~(1 << DDD7) // Set DDRD register to configure PINB7 as input
// 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
// 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
// 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 PINB1 is high (1)
// --- 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
// --- BIOS Patching Configuration ---
#if defined(SCPH_102) || \
defined(SCPH_100) || \
defined(SCPH_7000_7500_9000) || \
defined(SCPH_7000) || \
defined(SCPH_3500_5000_5500) || \
defined(SCPH_3000) || \
defined(SCPH_1000)
// 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 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)))
// Hardware Interrupt (INT0) for AX pulse counting
#define PIN_AX_INTERRUPT_ENABLE EIMSK |= (1<<INT0) // Enable external interrupt on INT0 (PINB3)
#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)
// 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
// Hardware Bypass Switch (On-the-fly deactivation)
#ifdef PATCH_SWITCHE
#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(DEBUG_SERIAL_MONITOR)
// #define DEBUG_PRINT(x) Serial.print(x)
// #define DEBUG_PRINTHEX(x) Serial.print(x, HEX)
// #define DEBUG_PRINTLN(x) Serial.println(x)
// #define DEBUG_FLUSH Serial.flush()
// #endif
#endif
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32U2__)
#define IS_32U4_FAMILY
void OptimizePeripherals(void) __attribute__((naked, section(".init3")));
void OptimizePeripherals(void) {
// Ultra-Fast Boot (Clock & Watchdog)
CLKPR = 0x80;
CLKPR = 0x00;
MCUSR = 0;
// Global Interrupt Disable during hardware reconfiguration
cli();
// USB Hard-Shutdown (Kills USB Serial, use Hardware UART RX1/TX1 instead)
USBCON &= ~(1 << USBE);
USBCON &= ~(1 << OTGPADE);
UHWCON &= ~(1 << UVREGE);
PLLCSR &= ~(1 << PLLE);
UDINT = 0;
// Analog Front-End Shutdown
ADCSRA &= ~(1 << ADEN); // Disable ADC
ACSR |= (1 << ACD); // Disable Analog Comparator
// 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
// 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
// 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 << PRUSB) | // Disable USB Controller (Stops SOF interrupts)
(1 << PRTIM3) | // Timer 3 Off
// (1 << PRTIM4) | // Timer 4 Off (High speed timer)
(0 << PRUSART1); // KEEP SERIAL1 ACTIVE (PD1/TX1) - Must be 0
// Double Security for Timer 0 (Redundancy)
TCCR0B = 0;
TIMSK0 = 0;
TCCR1B = 0;
TIMSK1 = 0;
TCCR3B = 0;
TIMSK3 = 0;
TCCR4B = 0;
}
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sfr_defs.h>
#include <util/delay.h>
// --- 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)
// Configure lines as outputs (for injection/override)
#define PIN_DATA_OUTPUT DDRB |= (1 << DDB4)
#define PIN_WFCK_OUTPUT DDRB |= (1 << DDB5)
// 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
// 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) // LED on PB6
#define PIN_LED_ON PORTB |= (1 << PB6)
#define PIN_LED_OFF PORTB &= ~(1 << PB6)
#endif
// --- BIOS Patching Configuration (32U4 Mapping) ---
#if defined(SCPH_102) || \
defined(SCPH_100) || \
defined(SCPH_7000_7500_9000) || \
defined(SCPH_3500_5000_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)
#define PIN_AY_INTERRUPT_FALLING EICRA = (EICRA & ~((1 << ISC01) | (1 << ISC00))) | (1 << ISC01) // Configure INT1 for falling edge trigger
#endif
// Hardware Bypass Switch (On-the-fly deactivation)
#ifdef PATCH_SWITCHE
#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
#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny25__)
#define IS_ATTINY_FAMILY
void OptimizePeripherals(void) __attribute__((naked, section(".init3")));
void OptimizePeripherals(void) {
// Ultra-Fast Boot (Clock & Watchdog)
// Forced 8MHz is mandatory for stable SoftwareSerial baudrate
CLKPR = 0x80;
CLKPR = 0x00;
MCUSR = 0;
//Global Interrupt Disable during reconfiguration
cli();
// Analog Modules Shutdown
ADCSRA = 0; // Power off ADC completely
ACSR |= (1 << ACD); // Disable Analog Comparator
// 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) |
(0 << PRTIM0) | // KEEP TIMER 0 FOR SOFTWARE SERIAL
(1 << PRTIM1) |
(1 << PRUSI);
// Timer 0 Specific Shutdown (Hardware Redundancy)
TCCR0B = 0;
TCCR0B = 0;
TIMSK = 0; // Disable ALL timer interrupts (OCIE0A, OCIE0B, TOIE0, etc.)
// Watchdog: Ensure it's disabled to prevent random resets
MCUSR &= ~(1 << WDRF);
WDTCR |= (1 << WDCE) | (1 << WDE);
WDTCR = 0x00;
}
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sfr_defs.h>
#include <util/delay.h>
// --- Main Bus Interface (CD-ROM Controller) ---
// 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)
// Configure lines as outputs (for injection/override)
#define PIN_DATA_OUTPUT DDRB |= (1 << DDB2)
#define PIN_WFCK_OUTPUT DDRB |= (1 << DDB4)
// 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
// 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))
// --- Status Indication (LED) ---
#ifdef LED_RUN
#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(DEBUG_SERIAL_MONITOR)
#include <SoftwareSerial.h>
// 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)
#endif
// --- Safety Check: BIOS Patch Compatibility ---
#if defined(SCPH_1000) || \
defined(SCPH_3000) || \
defined(SCPH_3500_5000_5500) || \
defined(SCPH_7000_7500_9000) || \
defined(SCPH_100) || \
defined(SCPH_102)
#error "ATtiny85/45/25 architecture is not compatible with the BIOS patch feature."
#endif
#endif
// *****************************************************************************************************************
// WARNING:
// The following code is not functional as-is.
// *****************************************************************************************************************
#ifdef ATtiny88_48
#define F_CPU 16000000L
#define TIMER_TCNT_CLEAR TCNT0 = 0x00 //TCNT0 - Timer/Counter Register
#define SET_OCROA_DIV OCR0A = 159; //OCR0A Output Compare Register A, 0x10011111, 100KHz
#define SET_TIMER_TCCROA TCCR0A |= (1 << CTC0); //TCCR0A Timer/Counter Control Register A. turn on CTC mode, CTC0
// On ATtiny88, TCCR0B doesn't exist — clock select bits (CS01, CS00) are in TCCR0A.
// This sets the prescaler to 1, so the timer runs at full system clock (16 MHz).
#define SET_TIMER_TCCROB TCCR0A |= (1 << CS01) | (1 << CS00)
#define CTC_TIMER_VECTOR TIMER0_COMPA_vect //interrupt vector for match event, OCR0A comparison and Timer/Counter 0
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#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 pins input
#define PIN_DATA_INPUT DDRB &= ~(1 << DDB0)
#define PIN_WFCK_INPUT DDRB &= ~(1 << DDB1) // Create a mask (1<<0) with the first bit at 1 b00000001 uses the ~ operator to perform a bit inversion b11111110,
#define PIN_SQCK_INPUT DDRD &= ~(1 << DDD6) // &= updates the DDRB register with the AND operator and the mask, DDRB bxxxxxxxx OR mask b11111110 = bxxxxxxx0
#define PIN_SUBQ_INPUT DDRD &= ~(1 << DDD7)
// Main pin output
#define PIN_DATA_OUTPUT DDRB |= (1 << DDB0) // Create a mask (1<<0) with the first bit at 1 b00000001,
#define PIN_WFCK_OUTPUT DDRB |= (1 << DDB1) // |= updates the DDRB register with the OR operator and the mask, DDRB bxxxxxxxx OR mask b00000001 = bxxxxxxx1
// Define pull-ups and set high at the main pin
#define PIN_DATA_SET PORTB |= (1 << PB0) // Create a mask (1<<0) with the first bit at 1 b00000001,
// |= updates the PORTB register with the OR operator and the mask, PORTB bxxxxxxxx OR mask b00000001 = bxxxxxxx1
// Define pull-ups set down at the main pin
#define PIN_DATA_CLEAR PORTB &= ~(1 << PB0) // Create a mask (1<<0) with the first bit at 1 b00000001 uses the ~ operator to perform a bit inversion b11111110,
#define PIN_WFCK_CLEAR PORTB &= ~(1 << PB1) // &= updates the DDRB register with the AND operator and the mask, DDRB bxxxxxxxx OR mask b11111110 = bxxxxxxx0
// Read the main pins
#define PIN_SQCK_READ (PIND & (1 << PIND6)) // Create a mask (1<<6) with the six bit at 1 b00100000,
#define PIN_SUBQ_READ (PIND & (1 << PIND7)) // compare the PINB register and the mask with the AND operator, and returns the result, PINB bxx1xxxxx AND mask b00100000 = 1
#define PIN_WFCK_READ (PINB & (1 << PINB1))
// Handling and use of the LED pin
#ifdef LED_RUN
#define PIN_LED_OUTPUT DDRD |= (1 << DDD0)
#define PIN_LED_ON PORTD |= (1 << PD0)
#define PIN_LED_OFF PORTD &= ~(1 << PD0)
#endif
// Handling the BIOS patch
#if defined(SCPH_102) || defined(SCPH_100) || defined(SCPH_7000_9000) || defined(SCPH_5500) || defined(SCPH_3500_5000) || defined(SCPH_3000) || defined(SCPH_1000)
// BIOS interrupt seting
#define TIMER_INTERRUPT_ENABLE TIMSK0 |= (1 << OCIE0A)
#define TIMER_INTERRUPT_DISABLE TIMSK0 &= ~(1 << OCIE0A)
// BIOS timer clear
#define TIMER_TIFR_CLEAR TIFR0 |= (1 << OCF0A)
// Pins input
#define PIN_AX_INPUT DDRD &= ~(1 << DDD2)
#define PIN_AY_INPUT DDRD &= ~(1 << DDD3)
#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 << PIND2))
#define PIN_AY_READ (PIND & (1 << PIND3))
// Handling the external interrupt
#define PIN_AX_INTERRUPT_ENABLE EIMSK |= (1 << INT0)
#define PIN_AY_INTERRUPT_ENABLE EIMSK |= (1 << INT1)
#define PIN_AX_INTERRUPT_DISABLE EIMSK &= ~(1 << INT0)
#define PIN_AY_INTERRUPT_DISABLE EIMSK &= ~(1 << INT1)
#define PIN_AX_INTERRUPT_RISING EICRA |= (1 << ISC01) | (1 << ISC00)
#define PIN_AY_INTERRUPT_RISING EICRA |= (1 << ISC11) | (1 << ISC10)
#define PIN_AX_INTERRUPT_FALLING (EICRA = (EICRA & ~(1 << ISC00)) | (1 << ISC01))
#define PIN_AY_INTERRUPT_FALLING (EICRA = (EICRA & ~(1 << ISC10)) | (1 << ISC11))
#define PIN_AX_INTERRUPT_VECTOR INT0_vect
#define PIN_AY_INTERRUPT_VECTOR INT1_vect
// Handling and reading the switch pin for patch BIOS
#ifdef PATCH_SWITCH
#define PIN_SWITCH_INPUT DDRD &= ~(1 << DDD5)
#define PIN_SWITCH_SET PORTD |= (1 << PD5)
#define PIN_SWITCH_READ (PIND & (1 << PIND5))
#endif
#endif
#endif
#ifdef ATtiny214_414
//#define SET_CTRLA
#define DF_CPU 20000000L
#define TIMER_TCNT_CLEAR TCA0.SINGLE.CNT = 0x00 //TCNT0 - Timer/Counter Register
#define SET_OCROA_DIV TCA0.SINGLE.CMP0L = 100; //OCR0A Output Compare Register A, 0x10011111, 100KHz
#define SET_TIMER_TCCROA TCA0.SINGLE.CTRLB |= (1 << TCA_SINGLE_WGM0); //TCA_SINGLE_WGMODE_FRQ_gc //TCCR0A Timer/Counter Control Register A. turn on CTC mode, CTC0
#define SET_TIMER_TCCROB TCA0.SINGLE.CTRLA |= (1 << TCA_SINGLE_CLKSEL0); //TCA_SINGLE_CLKSEL_DIV1_gc//TCCR0B Timer/Counter Control Register B, CS00: Clock Select, clk I/O
//Waveform Generation Mode, Mode 2 CTC
#define CTC_TIMER_VECTOR TCA0_OVF_vect //TCA0_CMP0_vect //interrupt vector for match event, OCR0A comparison and Timer/Counter 0
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sfr_defs.h>
#include <util/delay.h>
// Globale interrupt seting
#define GLOBAL_INTERRUPT_ENABLE __asm__ __volatile__("sei" ::) //CPU.SREG |= (1<<7)
#define GLOBAL_INTERRUPT_DISABLE __asm__ __volatile__("cli" ::) //CPU.SREG &= ~(1<<7)
// Handling the main pins
// Main pins input
#define PIN_DATA_INPUT PORTA.DIR = PIN2_bm
#define PIN_WFCK_INPUT PORTA.DIR = PIN1_bm // Create a mask (1<<0) with the first bit at 1 b00000001 uses the ~ operator to perform a bit inversion b11111110,
#define PIN_SQCK_INPUT PORTA.DIR = PIN4_bm // &= updates the DDRB register with the AND operator and the mask, DDRB bxxxxxxxx OR mask b11111110 = bxxxxxxx0
#define PIN_SUBQ_INPUT PORTA.DIR = PIN3_bm
// Main pin output
#define PIN_DATA_OUTPUT PORTA.DIR |= PIN2_bm // Create a mask (1<<0) with the first bit at 1 b00000001,
#define PIN_WFCK_OUTPUT PORTA.DIR |= PIN1_bm // |= updates the DDRB register with the OR operator and the mask, DDRB bxxxxxxxx OR mask b00000001 = bxxxxxxx1
// Define pull-ups and set high at the main pin
#define PIN_DATA_SET PORTA.OUT |= PIN2_bm // Create a mask (1<<0) with the first bit at 1 b00000001,
// |= updates the PORTB register with the OR operator and the mask, PORTB bxxxxxxxx OR mask b00000001 = bxxxxxxx1
// Define pull-ups set down at the main pin
#define PIN_DATA_CLEAR PORTA.OUT &= ~PIN2_bm // Create a mask (1<<0) with the first bit at 1 b00000001 uses the ~ operator to perform a bit inversion b11111110,
#define PIN_WFCK_CLEAR PORTA.OUT &= ~PIN1_bm // &= updates the DDRB register with the AND operator and the mask, DDRB bxxxxxxxx OR mask b11111110 = bxxxxxxx0
// Read the main pins
#define PIN_SQCK_READ PORTA.IN& PIN4_bm // Create a mask (1<<6) with the six bit at 1 b00100000,
#define PIN_SUBQ_READ PORTA.IN& PIN3_bm // compare the PINB register and the mask with the AND operator, and returns the result, PINB bxx1xxxxx AND mask b00100000 = 1
#define PIN_WFCK_READ PORTA.IN& PIN1_bm
// Handling and use of the LED pin
#define LED_RUN
#define PIN_LED_OUTPUT PORTB.DIR |= PIN2_bm
#define PIN_LED_ON PORTB.OUT |= PIN2_bm
#define PIN_LED_OFF PORTB.OUT &= ~PIN2_bm
// Handling the BIOS patch
// BIOS interrupt seting
#define TIMER_INTERRUPT_ENABLE TCA0.SPLIT.INTCTRL |= TCA_SINGLE_CMP0_bm
#define TIMER_INTERRUPT_DISABLE TCA0.SPLIT.INTCTRL &= ~TCA_SPLIT_HCMP0_bm
// BIOS timer clear
#define TIMER_TIFR_CLEAR TCA0.SPLIT.INTFLAGS = TCA_SPLIT_HCMP0_bm
// Pins input
#define PIN_AX_INPUT PORTB.DIR &= ~PIN3_bm
#define PIN_AY_INPUT PORTA.DIR &= ~PIN7_bm
#define PIN_DX_INPUT PORTA.DIR &= ~PIN6_bm
// Pin output
#define PIN_DX_OUTPUT PORTA.DIR |= PIN6_bm
// Define pull-ups set high
#define PIN_DX_SET PORTA.OUT |= PIN6_bm
// Define pull-ups set down
#define PIN_DX_CLEAR PORTA.OUT &= ~PIN6_bm
// Read pins for BIOS patch
#define PIN_AX_READ PORTB.IN& PIN3_bm
#define PIN_AY_READ PORTA.IN& PIN6_bm
// Handling the external interrupt
//#define PIN_AX_INTERRUPT_ENABLE PORTB.PIN3CTRL |= (1<<INTn)
//#define PIN_AY_INTERRUPT_ENABLE PORTA.PIN7CTRL |= (1<<INTn)
#define PIN_AX_INTERRUPT_DISABLE PORTB.PIN3CTRL = PORT_ISC_INTDISABLE_gc
#define PIN_AY_INTERRUPT_DISABLE PORTA.PIN7CTRL = PORT_ISC_INTDISABLE_gc
#define PIN_AX_INTERRUPT_RISING PORTB.PIN3CTRL = PORT_ISC_RISING_gc
#define PIN_AY_INTERRUPT_RISING PORTA.PIN7CTRL = PORT_ISC_RISING_gc
#define PIN_AX_INTERRUPT_FALLING PORTB.PIN3CTRL = PORT_ISC_FALLING_gc
#define PIN_AY_INTERRUPT_FALLING PORTA.PIN7CTRL = PORT_ISC_FALLING_gc
//#define PB3_INTERRUPT PORTB.INTFLAGS & PIN3_bm
//#define PA7_INTERRUPT PORTB.INTFLAGS & PIN7_bm
#define PIN_AX_INTERRUPT_VECTOR PORTB_PORT_vect
#define PIN_AY_INTERRUPT_VECTOR PORTA_PORT_vect
// Handling and reading the switch pin for patch BIOS
#define PIN_SWITCH_INPUT PORTA.DIR &= ~PIN5_bm
#define PIN_SWITCH_SET PORTA.OUT |= PIN5_bm
#define PIN_SWITCH_READ PORTA.IN& PIN5_bm
#endif
#if defined(__LGT8F328P__) || defined(__LGT8F__)
/*------------------------------------------------------------------------------------------------
* FUNCTION : OptimizePeripherals() - LGT8F328P Edition
*
* DESCRIPTION :
* Optimisation spécifique pour l'architecture LGT8F (LogicGreen).
* Le LGT8F possède des périphériques analogiques plus complexes (DAC, OPAMP).
------------------------------------------------------------------------------------------------*/
static inline void OptimizePeripherals(void) {
cli();
// 1. Analog Modules Shutdown (LGT8F328P)
ADCSRA &= ~(1 << ADEN); // Disable ADC
ADCSRC &= ~(1 << ADEN); // Disable LGT8F specific ADC stage
DACON &= ~(1 << DACEN); // Disable DAC (Digital to Analog Converter)
OPACON &= ~(1 << OPAEN); // Disable OpAmp (Ampli Op interne)
// 2. Analog Comparator Shutdown
ACSR |= (1 << ACD);
// 3. Digital Input Disable (DIDR)
// Le LGT8F328P possède 8 canaux ADC (A0-A7)
DIDR0 = 0xFF;
// 4. GPIO Strategy (Pull-ups sur tous les ports)
// Le LGT8F possède les ports B, C, D et souvent un port E (PE0, PE2)
PORTB |= 0xFF;
PORTC |= 0xFF;
PORTD |= 0xFF;
PORTE |= 0x05; // PE0 et PE2 sur LGT8F
// 5. Power Reduction Register (PRR)
// Sur LGT8F, PRR gère les horloges.
// On garde PRUSART0 (bit 1) à 0 pour le Debug Serial.
PRR = (1 << PRTWI) | // I2C Off
(1 << PRSPI) | // SPI Off
(1 << PRTIM0) | // Timer 0 Off
(1 << PRTIM1) | // Timer 1 Off
(1 << PRTIM2) | // Timer 2 Off
(1 << PRADC); // ADC Clock Off
// Le LGT8F n'a généralement pas de PRR1/PRR2 comme le 128PB,
// mais possède PRR1 pour PCI (Pin Change Interrupt) sur certaines versions.
#if defined(PRR1)
PRR1 = (1 << PRPCI); // Disable Pin Change Interrupt clock if unused
#endif
// 6. Double Security for Timers
TCCR0B = 0; TIMSK0 = 0;
TCCR1B = 0; TIMSK1 = 0;
TCCR2B = 0; TIMSK2 = 0;
}
// --- Mapping des Pins (Identique au 328P pour la compatibilité) ---
#define PIN_DATA_INPUT DDRB &= ~(1 << DDB0)
#define PIN_WFCK_INPUT DDRB &= ~(1 << DDB1)
#define PIN_SQCK_INPUT DDRD &= ~(1 << DDD6)
#define PIN_SUBQ_INPUT DDRD &= ~(1 << DDD7)
#define PIN_DATA_OUTPUT DDRB |= (1 << DDB0)
#define PIN_WFCK_OUTPUT DDRB |= (1 << DDB1)
#define PIN_DATA_SET PORTB |= (1 << PB0)
#define PIN_DATA_CLEAR PORTB &= ~(1 << PB0)
#define PIN_WFCK_CLEAR PORTB &= ~(1 << PB1)
#define PIN_SQCK_READ (!!(PIND & (1 << PIND6)))
#define PIN_SUBQ_READ (!!(PIND & (1 << PIND7)))
#define PIN_WFCK_READ (!!(PINB & (1 << PINB1)))
// --- 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)
// --- DX (Data) sur PD4 ---
#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)
// --- AX (Address) sur PD1 (Utilise INT1 sur 32U4) ---
#define PIN_AX_INPUT DDRD &= ~(1 << DDD1)
#define WAIT_AX_RISING (!(PIND & (1 << PIND1)))
#define WAIT_AX_FALLING (PIND & (1 << PIND1))
#define PIN_AX_READ (PIND & (1 << PIND1))
// Interruption INT1 pour AX (PD1)
#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)
// --- AY (Secondary Address) sur PD0 (Utilise INT0 sur 32U4) ---
#if defined(SCPH_3000) || defined(SCPH_1000)
#define PIN_AY_INPUT DDRD &= ~(1 << DDD0)
#define PIN_AY_READ (PIND & (1 << PIND0))
#define WAIT_AY_RISING (!(PIND & (1 << PIND0)))
#define WAIT_AY_FALLING (PIND & (1 << PIND0))
// Interruption INT0 pour AY (PD0)
#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
// --- Switch Bypass sur PC6 (Pin 5 sur Arduino Micro) ---
#ifdef SCPH_7000
#define PIN_SWITCH_INPUT DDRC &= ~(1 << DDC6)
#define PIN_SWITCH_SET PORTC |= (1 << PC6)
#define PIN_SWITCH_READ (!!(PINC & (1 << PINC6)))
#endif
#endif // BIOS Patching
#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