*********************************** * Playstation Pad Driver * * For 68Hc11A1FN * * December 1st, 2001 * * Laurent SAINT-MARCEL * * lstmarcel@yahoo.fr * *********************************** * ************************** * REGISTER DECLARATION * ************************** BASE EQU $1000 PILE EQU $1F * serial port BAUD EQU $2B SCCR1 EQU $2C SCCR2 EQU $2D SCSR EQU $2E SCDR EQU $2F TDRE EQU $80 * bit in SCSR RDRF EQU $20 * bit in SCSR * io port PORTF EQU $04 * Output // in fact it is port B but I used port F on a 68CV11F1FN PORTC EQU $03 * Input DDRC EQU $07 * ************ * PINOUT * ************ * Controller pin Inputs (pad->uc) PIN_DATA EQU $20 * (1) Brown PIN_ACK EQU $80 * (9) Green * Controller pin Outputs (uc->pad) *PIN_COMMAND EQU $04 * (2) Orange *PIN_CLOCK EQU $02 * (7) Blue *PIN_ATT EQU $01 * (6) Yellow or White * ********* * RAM * ********* CMD RMB 1 * COMMAND(from uc) DATA RMB 1 * DATA(from pad) COUNT RMB 1 * bit counter when sending/receiving data PAD_T RMB 1 * Pad type PAD_D0 RMB 1 * DATA sent by the pad PAD_D1 RMB 1 * DATA sent by the pad PAD_D2 RMB 1 * DATA sent by the pad PAD_D3 RMB 1 * DATA sent by the pad PAD_D4 RMB 1 * DATA sent by the pad PAD_D5 RMB 1 * DATA sent by the pad * ***************************** * PROGRAM POSITION IN EPROM * ***************************** ORG $B600 ** START OF EEPROM. $F800 FOR 68hc11E2 $FE00 FOR 68hc11F1 $B600 FOR 68hc11A1 LDX #BASE ** Base register LDS #PILE ** Stack address BRA RESET * ********* * RESET * ********* RESET BSR SCI_INI ** initialize serial port JSR IO_INI ** initialize io JMP MAIN ** jump to main program * ***************** * SERIAL PORT * ***************** **** Init serial port **** SCI_INI CLR SCCR1,X LDD #$300C STAA BAUD,X ** 9600 bauds STAB SCCR2,X ** Transmitter and receiver enabled RTS * **** send one byte on serial port : register A **** SCI_SND PSHA SCI_SN1 LDAA SCSR,X ** sci status register ANDA #TDRE ** Write Data register empty ? BEQ SCI_SN1 ** if No => retry PULA STAA SCDR,X ** write data on serial port RTS * **** receive one bytes from serial port and store it in register A (if no Byte waiting, return 0xFF)**** SCI_RCV LDAA SCSR,X ** sci status register ANDA #RDRF ** Read Data register full ? BEQ SCI_RC2 ** if No => do not retry but put FF in register A LDAA SCDR,X ** read data from serial port RTS SCI_RC2 LDAA #$FF ** Register A filled with FF if nothing waiting on serial port RTS * *************************** * 68HC11 board, init IO * *************************** **** IO_ INITIALIZE **** IO_INI LDAA #$FF ** set one on all ouputs STAA PORTF,X CLR DDRC,X ** set C as input STAA PORTC,X RTS * ************************* * PSX PAD SET ATT BIT * ************************* **** ATT Hight **** PAD_AH LDAA #$07 ** cmd=1, clk=1, att=1 STAA PORTF,X RTS * **** ATT Low **** PAD_AL LDAA #$06 ** cmd=1, clk=1, att=0 STAA PORTF,X RTS * *********************************** * PSX PAD SEND/RECEIVE ONE BYTE * *********************************** **** Send a request from register A and get response in register B **** *-- Init counter (for i=1; i<8; ++i) PAD_SR STAA CMD LDAA #$08 ** wait 8 bits STAA COUNT *-- rotate B bits (DATA received fron the pad) PAD_S1 LSRB ** move bits from B to the right * **** Send a bit (Command) to the PAD **** LDAA CMD *-- If (A.bit[0] == 1) SND1 else SND0 ANDA #$01 CMPA #$01 BEQ SND1 *-- cmd == 0 & clock down SND0 LDAA #$00 ** cmd=0, clk=0, att=0 STAA PORTF,X NOP NOP *-- cmd == 0 & clock up LDAA #$02 ** cmd=0, clk=1, att=0 STAA PORTF,X *-- jump read data BRA PAD_R *-- cmd == 1 & clock down SND1 LDAA #$04 ** cmd=1, clk=0, att=0 STAA PORTF,X NOP NOP *-- cmd == 0 & clock up LDAA #$06 ** cmd=1, clk=1, att=0 STAA PORTF,X *-- jump read data BRA PAD_R * **** Reveive a bit (Data) from PAD **** PAD_R NOP NOP LDAA PORTC,X ANDA #$20 ** data=1 CMPA #$20 BNE PAD_WA ** if data==0 => jump to wai ack *-- Bit received=1 PAD_R1 ORAB #$80 ** B = B | 0x80 BRA PAD_WA * **** Wait Ack **** PAD_WA BRA PAD_E1 ** do not wait ack else infinite loop... why? LDAA PORTC,X ANDA #$80 ** ack=2 CMPA #$80 BEQ PAD_WA ** while ack up, wait ack * **** End of the loop *** PAD_E1 LDAA COUNT DECA ** --i (loop) STAA COUNT CMPA #$00 BEQ PAD_E ** if(count == 0) exit *-- Get next bit to send LDAA CMD LSRA ** rotate bits of CMD STAA CMD BRA PAD_S1 *-- Exit PAD_E RTS * ****************** * PSX PAD READ * ****************** PAD_RCV * Set ATT/Select JSR PAD_AL * Start LDAA #$01 ** start request JSR PAD_SR * Read LDAA #$42 ** read request JSR PAD_SR STAB PAD_T ** store the result in PAD_TYPE * Pad will answer ? LDAA #$00 ** idle (wait data from pad) JSR PAD_SR CMPB #$5A ** pad ready to write its data BNE PAD_END ** pad not ready => stop * Data0 LDAA #$00 ** idle (wait data from pad) JSR PAD_SR STAB PAD_D0 ** store the result in PAD_DATA_0 * Data1 LDAA #$00 ** idle (wait data from pad) JSR PAD_SR STAB PAD_D1 ** store the result in PAD_DATA_1 * Check data type LDAB PAD_T CMPB #$41 BEQ PAD_END ** if pad type=Standard Digital Pad => stop waiting data (only 2 bytes already read) * Data2 LDAA #$00 ** idle (wait data from pad) JSR PAD_SR STAB PAD_D2 ** store the result in PAD_DATA_2 * Data3 LDAA #$00 ** idle (wait data from pad) JSR PAD_SR STAB PAD_D3 ** store the result in PAD_DATA_3 * Data4 LDAA #$00 ** idle (wait data from pad) JSR PAD_SR STAB PAD_D4 ** store the result in PAD_DATA_4 * Data5 LDAA #$00 ** idle (wait data from pad) JSR PAD_SR STAB PAD_D5 ** store the result in PAD_DATA_5 * End : unset ATT PAD_END JSR PAD_AH RTS * ****************************** * SEND DATA ON SERIAL PORT * ****************************** PAD_SND LDAA PAD_T JSR SCI_SND LDAA PAD_D0 JSR SCI_SND LDAA PAD_D1 JSR SCI_SND LDAA PAD_D2 JSR SCI_SND LDAA PAD_D3 JSR SCI_SND LDAA PAD_D4 JSR SCI_SND LDAA PAD_D5 JSR SCI_SND RTS * **************** * MAIN PROGRAM * **************** MAIN JSR PAD_RCV * read data from playstation pad JSR SCI_RCV * read a character from serial port CMPA #$FF * if no character on serial port BEQ MAIN * then continue loop JSR PAD_SND * else send last pad data on serial port BRA MAIN * *********************************** * SET Boot stack pointer position * *********************************** ORG $FFFE * reset vector address FDB $B600 * go to the begin of the eeprom * ORG $BFFE * reset vector address (special mode) FDB $B600 * go to the begin of the eeprom * END