;
; Crystal Chip hardware interface library
;

CC_MAGIC1               EQU 0xC0
CC_MAGIC2               EQU 0xCA

CC_WRITE_EEP            EQU 0x00
CC_READ_EEP             EQU 0x81
CC_SET_BIOS_CTRL        EQU 0x02
CC_SET_AUTH_CTRL        EQU 0x03
CC_DISABLE_IF           EQU 0x04
CC_WRITE_SRAM           EQU 0x05
CC_GET_VERSION          EQU 0x06
CC_SPI_TXFER            EQU 0x87
CC_SPI_TXFER_BURST      EQU 0xC7

; Bits for CC BIOS_CTRL register
BIOS_MCEXEC_EN          EQU (1 << 0)
BIOS_MM16_EN            EQU (1 << 1)
BIOS_LOGO_EN            EQU (1 << 2)
BIOS_READKEY_EN         EQU (1 << 3)
BIOS_MCBOOT_EN          EQU (1 << 4)
BIOS_OSDBOOT_EN         EQU (1 << 5)
BIOS_IOPBOOT_EN         EQU (1 << 6)

; Bits for CC AUTH_CTRL register.
AUTH_MECHA_EN           EQU (1 << 0)
AUTH_SCEX_EN            EQU (1 << 1)
AUTH_BT_EN              EQU (1 << 7)

; Bits for PS1 disc authentication region in the CC Auth Control register
AUTH_SCEI               EQU (0 << 2)
AUTH_SCEA               EQU (1 << 2)
AUTH_SCEE               EQU (2 << 2)

CC_send_pkt             PROC

                        addiu       sp, sp, -0x20
                        sw          ra, 0x00(sp)
                        sw          s0, 0x04(sp)
                        sw          s1, 0x08(sp)
                        sw          s2, 0x0C(sp)
                        sw          s3, 0x10(sp)

                        or          s0, zero, a0
                        lui         s1, 0x1FC0

_l1:
                        li          at, CC_MAGIC1
                        sb          at, 0x01AD(s1)
                        
                        jal         usleep
                        li          a0, 2
                        
                        li          at, CC_MAGIC2
                        sb          at, 0x01AD(s1)

                        jal         usleep
                        li          a0, 2

                        li          s2, 0                               ; addsum = 0
                        li          s3, 0                               ; i = 0
_l2:
                        addu        at, s0, s3
                        lbu         v0, 0x00(at)
                        sb          v0, 0x01AD(s1)

                        addu        s2, s2, v0                          ; addsum += pkt[i]

                        jal         usleep
                        li          a0, 2

                        sltiu       at, s3, 3
                        bne         at, zero, _l2
                        addiu       s3, s3, 1

                        sb          s2, 0x01AD(s1)                      ; write the addsum

                        jal         usleep
                        li          a0, 2

                        lbu         v0, 0x01AD(s1)                      ; get result
                        andi        at, v0, 0xF0
                        bnez        at, _l1                             ; start over if (result & 0xF0) != 0
                        nop

                        lw          ra, 0x00(sp)
                        lw          s0, 0x04(sp)
                        lw          s1, 0x08(sp)
                        lw          s2, 0x0C(sp)
                        lw          s3, 0x10(sp)
                        jr          ra
                        addiu       sp, sp, 0x20

CC_send_pkt             ENDP

CC_getRevision          PROC

                        addiu       sp, sp, -0x10
                        sw          ra, 0x00(sp)

                        li          at, CC_GET_VERSION
                        sw          at, 0x10(sp)

                        jal         CC_send_pkt
                        addiu       a0, sp, 0x10

                        lw          ra, 0x00(sp)
                        jr          ra
                        addiu       sp, sp, 0x10

CC_getRevision          ENDP

usleep                  PROC

                        li          at, 300
                        mult        t0, a0, at

                        mfc0        t1, Count

_l1:
                        mfc0        t2, Count
                        subu        t2, t2, t1
                        sltu        at, t2, t0
                        bnez        at, _l1
                        nop

                        jr          ra
                        nop

usleep                  ENDP

IF _F_CC_spi_txfer
CC_spi_txfer               PROC

                        addiu       sp, sp, -0x20
                        sw          ra, 0x00(sp)
                        sw          s0, 0x04(sp)
                        sw          s1, 0x08(sp)
                        sw          s2, 0x0C(sp)

                        or          s0, zero, a0
                        or          s1, zero, a1
                        or          s2, zero, a2

_l1:
                        li          at, CC_SPI_TXFER
                        sw          at, 0x10(sp)

                        sll         a0, s0, 1
                        or          a0, a0, s1
                        sb          a0, 0x12(sp)
                        sb          s2, 0x13(sp)

                        jal         CC_send_pkt
                        addiu       a0, sp, 0x10

                        jal         usleep
                        li          a0, 3

                        lui         t0, 0x1FC0
                        lbu         v0, 0x01AD(t0)
                        xori        t1, v0, 0xFF
                        lbu         t2, 0x01AD(t0)
                        bne         t1, t2, _l1
                        nop

                        lw          ra, 0x00(sp)
                        lw          s0, 0x04(sp)
                        lw          s1, 0x08(sp)
                        lw          s2, 0x0C(sp)
                        jr          ra
                        addiu       sp, sp, 0x20

CC_spi_txfer            ENDP
ENDIF

IF _F_CC_spi_txfer_burst
CC_spi_txfer_burst         PROC

                        addiu       sp, sp, -0x20
                        sw          ra, 0x00(sp)

                        li          at, CC_SPI_TXFER_BURST
                        sw          at, 0x10(sp)

                        sll         a0, a0, 1
                        or          a0, a0, a1
                        sb          a0, 0x12(sp)
                        sb          a2, 0x13(sp)

                        jal         CC_send_pkt
                        addiu       a0, sp, 0x10

                        lw          ra, 0x00(sp)
                        jr          ra
                        addiu       sp, sp, 0x20

CC_spi_txfer_burst         ENDP
ENDIF

IF _F_CC_spi_read_sr
CC_read_sr              PROC

                        addiu       sp, sp, -0x10
                        sw          ra, 0x00(sp)

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        li          a2, 0xD7

                        li          a0, 0
                        li          a1, 1
                        jal         CC_spi_txfer
                        li          a2, 0xD7

                        lw          ra, 0x00(sp)
                        jr          ra
                        addiu       sp, sp, 0x10

CC_read_sr              ENDP
ENDIF

IF _F_CC_SetBIOSCtrl
CC_SetBIOSCtrl          PROC

                        addiu       sp, sp, -0x20
                        sw          ra, 0x00(sp)

                        li          at, CC_SET_BIOS_CTRL
                        sw          at, 0x10(sp)

                        sb          a0, 0x11(sp)

                        jal         CC_send_pkt
                        addiu       a0, sp, 0x10

                        lw          ra, 0x00(sp)
                        jr          ra
                        addiu       sp, sp, 0x20

CC_SetBIOSCtrl          ENDP
ENDIF

IF _F_CC_SetAuthCtrl
CC_SetAuthCtrl          PROC

                        addiu       sp, sp, -0x20
                        sw          ra, 0x00(sp)                        
                        sw          zero, 0x10(sp)

                        li          at, CC_SET_AUTH_CTRL
                        sb          at, 0x10(sp)
                        sb          a0, 0x11(sp)

                        jal         CC_send_pkt
                        addiu       a0, sp, 0x10

                        lw          ra, 0x00(sp)
                        jr          ra
                        addiu       sp, sp, 0x20

CC_SetAuthCtrl          ENDP
ENDIF

IF _F_CC_DisableIF
CC_DisableIF            PROC

                        addiu       sp, sp, -0x20
                        sw          ra, 0x00(sp)

                        li          at, CC_DISABLE_IF
                        sw          at, 0x10(sp)

                        li          at, 0xFF
                        sb          at, 0x11(sp)
                        sb          at, 0x12(sp)
                        jal         CC_send_pkt
                        addiu       a0, sp, 0x10

                        lw          ra, 0x00(sp)
                        jr          ra
                        addiu       sp, sp, 0x20

CC_DisableIF            ENDP
ENDIF

IF _F_CC_WriteSRAM
CC_WriteSRAM            PROC

                        addiu       sp, sp, -0x20
                        sw          ra, 0x00(sp)
                        sw          s0, 0x04(sp)
                        sw          s1, 0x08(sp)
                        sw          s2, 0x0C(sp)

                        or          s0, zero, a0                        ; s0 = addr
                        or          s1, zero, a1                        ; s1 = buf
                        or          s2, zero, a2                        ; s2 = len
_l1:

                        li          at, CC_WRITE_SRAM
                        sb          at, 0x10(sp)

                        srl         at, s0, 8
                        andi        at, at, 0xFF
                        sb          at, 0x11(sp)

                        andi        at, s0, 0xFF
                        sb          at, 0x12(sp)

                        lbu         at, 0x00(s1)
                        sb          at, 0x13(sp)

                        jal         CC_send_pkt
                        addiu       a0, sp, 0x10

                        addiu       s0, s0, 1                           ; addr++
                        addiu       s2, s2, -1                          ; len--
                        bgtz        s2, _l1
                        addiu       s1, s1, 1                           ; buf++

                        lw          ra, 0x00(sp)
                        lw          s0, 0x04(sp)
                        lw          s1, 0x08(sp)
                        lw          s2, 0x0C(sp)
                        jr          ra
                        addiu       sp, sp, 0x20

CC_WriteSRAM            ENDP
ENDIF

IF _F_CC_ReadEEPROM
CC_ReadEEPROM           PROC

                        addiu       sp, sp, -0x20
                        sw          ra, 0x00(sp)
                        sw          s0, 0x04(sp)
                        sw          s1, 0x08(sp)
                        sw          s2, 0x0C(sp)

                        or          s0, zero, a0                        ; s0 = addr
                        or          s1, zero, a1                        ; s1 = buf
                        or          s2, zero, a2                        ; s2 = len

_l1:
                        li          at, CC_READ_EEP
                        sb          at, 0x10(sp)

                        srl         at, s0, 8
                        andi        at, at, 0xFF
                        sb          at, 0x11(sp)

                        andi        at, s0, 0xFF
                        sb          at, 0x12(sp)

                        sb          zero, 0x13(sp)

                        jal         CC_send_pkt
                        addiu       a0, sp, 0x10

                        jal         usleep                              ; delay 10 ms
                        li          a0, 10

                        lui         t0, 0x1FC0
                        lbu         v0, 0x01AD(t0)                      ; result
                        lbu         at, 0x01AD(t0)                      ; result2
                        xori        at, at, 0xFF
                        bne         at, v0, _l1                         ; start over if 2nd result != ~(result)
                        nop

                        sb          v0, 0x00(s1)

                        addiu       s0, s0, 1                           ; addr++
                        addiu       s2, s2, -1                          ; len--
                        bgtz        s2, _l1
                        addiu       s1, s1, 1                           ; buf++

                        lw          ra, 0x00(sp)
                        lw          s0, 0x04(sp)
                        lw          s1, 0x08(sp)
                        lw          s2, 0x0C(sp)
                        jr          ra
                        addiu       sp, sp, 0x20

CC_ReadEEPROM           ENDP
ENDIF

IF _F_CC_getPageSize

CC_getPageSize          PROC

                        addiu       sp, sp, -0x10
                        sw          ra, 0x00(sp)

                        jal         CC_read_sr
                        nop

                        srl         t0, v0, 2
                        andi        t0, t0, 0x0F

                        sltiu       at, t0, 0x0B
                        beqz        at, _done
                        li          v0, 528

                        li          v0, 264

_done:
                        lw          ra, 0x00(sp)
                        jr          ra
                        addiu       sp, sp, 0x10

CC_getPageSize          ENDP

ENDIF

IF _F_CC_df_read_block
CC_df_read_block        PROC

                        addiu       sp, sp, -0x30
                        sw          ra, 0x00(sp)
                        sw          s0, 0x04(sp)
                        sw          s1, 0x08(sp)
                        sw          s2, 0x0C(sp)
                        sw          s3, 0x10(sp)
                        sw          s4, 0x14(sp)
                        sw          s5, 0x18(sp)
                        sw          s6, 0x1C(sp)
                        sw          s7, 0x20(sp)

                        or          s0, zero, a0
                        or          s2, zero, a1
                        or          s3, zero, a2

                        jal         CC_getPageSize
                        nop

                        divu        s0, v0
                        mflo        s0                                  ; s0 = page address
                        mfhi        s1                                  ; s1 = buffer address

                        li          s4, 100                             ; retries = 100

_l1:
                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        li          a2, 0xE8

                        li          a0, 0
                        li          a1, 0
                        srl         a2, s0, 7
                        jal         CC_spi_txfer
                        andi        a2, a2, 0xFF

                        li          a0, 0
                        li          a1, 0

                        andi        a2, s0, 0xFF
                        sll         a2, a2, 1
                        srl         at, s1, 8
                        andi        at, at, 1
                        jal         CC_spi_txfer
                        or          a2, a2, at

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        andi        a2, s1, 0xFF

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        li          a2, 0

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        li          a2, 0

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        li          a2, 0

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer_burst
                        andi        a2, 0

                        jal         usleep
                        li          a0, 3

                        li          s5, 0x1FC001AD
                        lbu         zero, 0x00(s5)                      ; dummy read

                        li          s6, 0                               ; count = 0
                        li          s7, 0                               ; csum = 0
_l2:
                        sltu        at, s6, s3
                        beqz        at, _loop_done                      ; while(count < len)
                        nop

                        jal         usleep
                        li          a0, 2

                        lbu         at, 0x00(s5)                        ; byte = FPGA_RD()
                        addu        s7, s7, at                          ; csum += byte

                        addu        t0, s2, s6
                        sb          at, 0x00(t0)

                        bu          _l2
                        addiu       s6, s6, 1                           ; count++

_loop_done:

                        sb          zero, 0x00(s5)                      ; FPGA_WR(0)

                        jal         usleep
                        li          a0, 2

                        lbu         at, 0x00(s5)                        ; at = checksum from CC
                        sw          at, 0x24(sp)

                        jal         usleep
                        li          a0, 2

                        li          a0, 0
                        li          a1, 1
                        jal         CC_spi_txfer
                        li          a2, 0

                        lw          at, 0x24(sp)
                        beq         s7, at, _done
                        li          v0, 0

_fail:
                        addiu       s4, s4, -1
                        bgtz        s4, _l1
                        li          v0, -1

_done:
                        lw          ra, 0x00(sp)
                        lw          s0, 0x04(sp)
                        lw          s1, 0x08(sp)
                        lw          s2, 0x0C(sp)
                        lw          s3, 0x10(sp)
                        lw          s4, 0x14(sp)
                        lw          s5, 0x18(sp)
                        lw          s6, 0x1C(sp)
                        lw          s7, 0x20(sp)
                        jr          ra
                        addiu       sp, sp, 0x30

CC_df_read_block        ENDP
ENDIF

IF _F_CC_df_main_read_byte
CC_df_main_read_byte    PROC
                        addiu       sp, sp, -0x10
                        sw          ra, 0x00(sp)
                        sw          s0, 0x04(sp)
                        sw          s1, 0x08(sp)

                        or          s0, zero, a0
                        or          s1, zero, a1

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        li          a2, 0xD2

                        li          a0, 0
                        li          a1, 0
                        srl         a2, s0, 7
                        jal         CC_spi_txfer
                        andi        a2, a2, 0xFF

                        li          a0, 0
                        li          a1, 0
                        andi        a2, s0, 0xFF
                        sll         a2, a2, 1
                        srl         at, s1, 8
                        andi        at, at, 1
                        jal         CC_spi_txfer
                        or          a2, a2, at

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        andi        a2, s1, 0xFF

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        li          a2, 0

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        li          a2, 0

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        li          a2, 0

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        li          a2, 0

                        li          a0, 0
                        li          a1, 1
                        jal         CC_spi_txfer
                        li          a2, 0

                        lw          ra, 0x00(sp)
                        lw          s0, 0x04(sp)
                        lw          s1, 0x08(sp)
                        jr          ra
                        addiu       sp, sp, 0x10

CC_df_main_read_byte    ENDP
ENDIF

IF _F_CC_df_buffer_read_byte
CC_df_buffer_read_byte  PROC
                        addiu       sp, sp, -0x10
                        sw          ra, 0x00(sp)
                        sw          s0, 0x04(sp)
                        sw          s1, 0x08(sp)

                        or          s0, zero, a0

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        li          a2, 0xD4

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        li          a2, 0

                        li          a0, 0
                        li          a1, 0
                        srl         a2, s0, 1
                        jal         CC_spi_txfer
                        andi        a2, a2, 1

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        andi        a2, s0, 0xFF

                        li          a0, 0
                        li          a1, 0
                        jal         CC_spi_txfer
                        li          a2, 0

                        li          a0, 0
                        li          a1, 1
                        jal         CC_spi_txfer
                        li          a2, 0

                        lw          ra, 0x00(sp)
                        lw          s0, 0x04(sp)
                        lw          s1, 0x08(sp)
                        jr          ra
                        addiu       sp, sp, 0x10

CC_df_buffer_read_byte  ENDP
ENDIF
