Chipping 

Posted on: Dec 22, 2018 7:18 PM UTC

Bill of materials

1ATTiny13

Contents

Goal

Here I'm trying to mod a PS1.
After a lot of research I found that the info about chipping was not easily understandable, at least for me.
The reason is that there are many PS1 motherboards, several different modchips and scarce precise how-to's.
A list of PS1 boards can be found on Wikipedia.
The one I bought is a PU-18.
In all the info I found, nearly everybody use PIC modchips.
As I have some ATtiny chips, I prefered to use one: an ATtiny13 that was laying around.
As you are reading this kind of article, I think you likely know about the protection used in the PS1.
If not, read this Twitter thread from @foone (my local copy).
Now the problem is: where and how should I inject the "SCEx" string so that the Playstation can read burned games?

Hardware

The SCEE string should replace the one (if any) actually read on the disk.
This string is sent on a DATA line that is accessible on the motherboard.
The actual output must be muted so that we can send the SCEE string without it being messed with with the actual data.
Fortunately this muting can be done by putting low another signal: a GATE signal.
Back of a PU-18 PCB.
(1) is VCC, (8) is GND, (6) is DATA and (5) is GATE.
Now that we know the pin to monitor, I used my logic analyzer to see the signal I'll have to reproduce.
I put an original game CD in the PS1, put my D3 channel on the DATA pin and logged the signal.
UART, 250 bps, LSB-first.
And here it is, we can see the "SCEE" string.
This is what we can read here: https://problemkaputt.de/psx-spx.htm#cdromprotectionmodchips

Chip firmware

With this info I made the following software and uploaded it on my ATtiny13 (fuses: H:FF, L:6A).
You can find it on my repo.
c
#define SETOUTPUT(ddr, n) ddr |= _BV(n); #define SETINPUT(ddr, n) ddr &= ~_BV(n); #define SETHIGH(port, n) port |= _BV(n); #define SETLOW(port, n) port &= ~_BV(n); #include <avr/io.h> #include <util/delay.h> #define gate 3 #define data 4 #define bitdur 4 #define pause 72 char scee[4] = "SCEE"; void wb(){_delay_ms(bitdur);} void uart_start(){SETHIGH(PORTB, data);wb();} void uart_stop(){SETLOW(PORTB, data);wb();} void inject_scee(){ for(int i=0;i<4;i++){ uart_start(); for(int j=0;j<8;j++){ char val = ((scee[i] & (1<<j)) == 0); if(val){ SETHIGH(PORTB, data); }else{ SETLOW(PORTB, data); } wb(); } uart_stop(); uart_stop(); } _delay_ms(pause); } int main(){ OSCCAL = 69; SETOUTPUT(DDRB, data); SETOUTPUT(DDRB, gate); while(1){ inject_scee(); } }
After analyzing the output, it's really close to the expected signal.
If your timings are a bit off, try editing the OSCCAL value.

Results

The PS1 loads burned disks so the chip works.
The next thing to do is making it stealth as some games can detect chips that send SCEE all the time instead of only right after inserting the CD, as it is the case for legit disks.
In order to fix this, only a few dozens of SCEE strings must be injected and the sequence must be injected each time the lid is closed (mandatory for games with more than one disk).



Comments (0)
No comments yet