shithub: psxe

ref: a024a29ac274ef63712d94e62ce73dcbb8306794
dir: /psx/dev/cdrom/cdrom.h/

View raw version
#ifndef CDROM_H
#define CDROM_H

#include <stdint.h>

#include "queue.h"
#include "disc.h"
#include "../ic.h"

#define PSX_CDROM_BEGIN 0x1f801800
#define PSX_CDROM_END   0x1f801803
#define PSX_CDROM_SIZE  0x4

/*
    Command                Average   Min       Max
    GetStat (normal)       000c4e1h  0004a73h..003115bh
    GetStat (when stopped) 0005cf4h  000483bh..00093f2h
    Pause (single speed)   021181ch  020eaefh..0216e3ch ;\time equal to
    Pause (double speed)   010bd93h  010477Ah..011B302h ;/about 5 sectors
    Pause (when paused)    0001df2h  0001d25h..0001f22h
    Stop (single speed)    0d38acah  0c3bc41h..0da554dh
    Stop (double speed)    18a6076h  184476bh..192b306h
    Stop (when stopped)    0001d7bh  0001ce8h..0001eefh
    GetID                  0004a00h  0004922h..0004c2bh
    Init                   0013cceh  000f820h..00xxxxxh
*/

#define CD_DELAY_1MS 33869
#define CD_DELAY_FR 50401
#define CD_DELAY_INIT_FR 81102
#define CD_DELAY_PAUSE_SS 2168860
#define CD_DELAY_PAUSE_DS 1097107
#define CD_DELAY_STOP_SS 13863626
#define CD_DELAY_STOP_DS 25845878
#define CD_DELAY_READ_SS (33868800 / 75)
#define CD_DELAY_READ_DS (33868800 / (2*75))
#define CD_DELAY_START_READ (cdrom_get_read_delay(cdrom) + cdrom_get_seek_delay(cdrom, ts))
#define CD_DELAY_ONGOING_READ (cdrom_get_read_delay(cdrom) + (CD_DELAY_1MS * 4))

#define XA_STEREO_SAMPLES 2016 // Samples per sector
#define XA_MONO_SAMPLES 4032 // Samples per sector
#define XA_STEREO_RESAMPLE_SIZE 2352 // 2352 * 2
#define XA_MONO_RESAMPLE_SIZE 4704 // 4704 * 2
#define XA_UPSAMPLE_SIZE 28224 // 4032 * 7
#define XA_RINGBUF_SIZE 32

/*
    7   Speed       (0=Normal speed, 1=Double speed)
    6   XA-ADPCM    (0=Off, 1=Send XA-ADPCM sectors to SPU Audio Input)
    5   Sector Size (0=800h=DataOnly, 1=924h=WholeSectorExceptSyncBytes)
    4   Ignore Bit  (0=Normal, 1=Ignore Sector Size and Setloc position)
    3   XA-Filter   (0=Off, 1=Process only XA-ADPCM sectors that match Setfilter)
    2   Report      (0=Off, 1=Enable Report-Interrupts for Audio Play)
    1   AutoPause   (0=Off, 1=Auto Pause upon End of Track) ;for Audio Play
    0   CDDA        (0=Off, 1=Allow to Read CD-DA Sectors; ignore missing EDC)
*/

#define MODE_CDDA           0x01
#define MODE_AUTOPAUSE      0x02
#define MODE_REPORT         0x04
#define MODE_XA_FILTER      0x08
#define MODE_IGNORE         0x10
#define MODE_SECTOR_SIZE    0x20
#define MODE_XA_ADPCM       0x40
#define MODE_SPEED          0x80

/*
    Command          Parameters      Response(s)
    00h -            -               INT5(11h,40h)  ;reportedly "Sync" uh?
    01h Getstat      -               INT3(stat)
    02h Setloc     E amm,ass,asect   INT3(stat)
    03h Play       E (track)         INT3(stat), optional INT1(report bytes)
    04h Forward    E -               INT3(stat), optional INT1(report bytes)
    05h Backward   E -               INT3(stat), optional INT1(report bytes)
    06h ReadN      E -               INT3(stat), INT1(stat), datablock
    07h MotorOn    E -               INT3(stat), INT2(stat)
    08h Stop       E -               INT3(stat), INT2(stat)
    09h Pause      E -               INT3(stat), INT2(stat)
    0Ah Init         -               INT3(late-stat), INT2(stat)
    0Bh Mute       E -               INT3(stat)
    0Ch Demute     E -               INT3(stat)
    0Dh Setfilter  E file,channel    INT3(stat)
    0Eh Setmode      mode            INT3(stat)
    0Fh Getparam     -               INT3(stat,mode,null,file,channel)
    10h GetlocL    E -               INT3(amm,ass,asect,mode,file,channel,sm,ci)
    11h GetlocP    E -               INT3(track,index,mm,ss,sect,amm,ass,asect)
    12h SetSession E session         INT3(stat), INT2(stat)
    13h GetTN      E -               INT3(stat,first,last)  ;BCD
    14h GetTD      E track (BCD)     INT3(stat,mm,ss)       ;BCD
    15h SeekL      E -               INT3(stat), INT2(stat)  ;\use prior Setloc
    16h SeekP      E -               INT3(stat), INT2(stat)  ;/to set target
    17h -            -               INT5(11h,40h)  ;reportedly "SetClock" uh?
    18h -            -               INT5(11h,40h)  ;reportedly "GetClock" uh?
    19h Test         sub_function    depends on sub_function (see below)
    1Ah GetID      E -               INT3(stat), INT2/5(stat,flg,typ,atip,"SCEx")
    1Bh ReadS      E?-               INT3(stat), INT1(stat), datablock
    1Ch Reset        -               INT3(stat), Delay
    1Dh GetQ       E adr,point       INT3(stat), INT2(10bytesSubQ,peak_lo) ;\not
    1Eh ReadTOC      -               INT3(late-stat), INT2(stat)           ;/vC0
    1Fh VideoCD      sub,a,b,c,d,e   INT3(stat,a,b,c,d,e)   ;<-- SCPH-5903 only
    1Fh..4Fh -       -               INT5(11h,40h)  ;-Unused/invalid
    50h Secret 1     -               INT5(11h,40h)  ;\
    51h Secret 2     "Licensed by"   INT5(11h,40h)  ;
    52h Secret 3     "Sony"          INT5(11h,40h)  ; Secret Unlock Commands
    53h Secret 4     "Computer"      INT5(11h,40h)  ; (not in version vC0, and,
    54h Secret 5     "Entertainment" INT5(11h,40h)  ; nonfunctional in japan)
    55h Secret 6     "<region>"      INT5(11h,40h)  ;
    56h Secret 7     -               INT5(11h,40h)  ;/
    57h SecretLock   -               INT5(11h,40h)  ;-Secret Lock Command
    58h..5Fh Crash   -               Crashes the HC05 (jumps into a data area)
    6Fh..FFh -       -               INT5(11h,40h)  ;-Unused/invalid
*/

#define CDL_GETSTAT    0x01
#define CDL_SETLOC     0x02
#define CDL_PLAY       0x03
#define CDL_FORWARD    0x04
#define CDL_BACKWARD   0x05
#define CDL_READN      0x06
#define CDL_MOTORON    0x07
#define CDL_STOP       0x08
#define CDL_PAUSE      0x09
#define CDL_INIT       0x0a
#define CDL_MUTE       0x0b
#define CDL_DEMUTE     0x0c
#define CDL_SETFILTER  0x0d
#define CDL_SETMODE    0x0e
#define CDL_GETPARAM   0x0f
#define CDL_GETLOCL    0x10
#define CDL_GETLOCP    0x11
#define CDL_SETSESSION 0x12
#define CDL_GETTN      0x13
#define CDL_GETTD      0x14
#define CDL_SEEKL      0x15
#define CDL_SEEKP      0x16
#define CDL_TEST       0x19
#define CDL_GETID      0x1a
#define CDL_READS      0x1b
#define CDL_RESET      0x1c
#define CDL_GETQ       0x1d
#define CDL_READTOC    0x1e
#define CDL_VIDEOCD    0x1f

/*
    ___These values appear in the FIRST response; with stat.bit0 set___
    10h - Invalid Sub_function (for command 19h), or invalid parameter value
    20h - Wrong number of parameters (most CD commands need an exact number of parameters)
    40h - Invalid command
    80h - Cannot respond yet (eg. required info was not yet read from disk yet)
            (namely, TOC not-yet-read or so)
            (also appears if no disk inserted at all)
    ___These values appear in the SECOND response; with stat.bit2 set___
    04h - Seek failed (when trying to use SeekL on Audio CDs)
    ___These values appear even if no command was sent; with stat.bit2 set___
    08h - Drive door became opened
*/

#define CD_ERR_SEEK_FAILED           0x04
#define CD_ERR_DOOR_OPENED           0x08
#define CD_ERR_INVALID_SUBFUNCTION   0x10
#define CD_ERR_WRONG_PARAMETER_COUNT 0x20
#define CD_ERR_INVALID_COMMAND       0x40
#define CD_ERR_NO_DISC               0x80

/*
    7  Play          Playing CD-DA         ;\only ONE of these bits can be set
    6  Seek          Seeking               ; at a time (ie. Read/Play won't get
    5  Read          Reading data sectors  ;/set until after Seek completion)
    4  ShellOpen     Once shell open (0=Closed, 1=Is/was Open)
    3  IdError       (0=Okay, 1=GetID denied) (also set when Setmode.Bit4=1)
    2  SeekError     (0=Okay, 1=Seek error)     (followed by Error Byte)
    1  Spindle Motor (0=Motor off, or in spin-up phase, 1=Motor on)
    0  Error         Invalid Command/parameters (followed by Error Byte)
*/

#define CD_STAT_PLAY        0x80
#define CD_STAT_SEEK        0x40
#define CD_STAT_READ        0x20
#define CD_STAT_SHELLOPEN   0x10
#define CD_STAT_IDERROR     0x08
#define CD_STAT_SEEKERROR   0x04
#define CD_STAT_SPINDLE     0x02
#define CD_STAT_ERROR       0x01

// #define SET_INT(n) cdrom->ifr = n;

enum {
    CD_STATE_IDLE,
    CD_STATE_TX_RESP1,
    CD_STATE_TX_RESP2,
    CD_STATE_READ,
    CD_STATE_PLAY
};

enum {
    QUERY_TRACK_COUNT,
    QUERY_TRACK_ADDR,
    QUERY_TRACK_TYPE
};

typedef struct {
    int mute;
    uint32_t bus_delay;
    uint32_t io_base, io_size;
    psx_disc_t* disc;
    psx_ic_t* ic;
    int disc_type;
    int version;
    int region;
    int index;
    int pending_speed_switch_delay;
    int seek_precision;
    int fake_getlocl_data;
    uint8_t ier;
    uint8_t ifr;
    uint8_t vol_pending[4];
    uint8_t vol[4];
    uint8_t mode;
    int data_req;
    queue_t* data;
    queue_t* response;
    queue_t* parameters;
    uint8_t pending_command;
    int busy;
    uint32_t xa_lba;
    int xa_playing;
    int xa_mute;
    int xa_channel;
    int xa_file;
    int xa_remaining_samples;
    int16_t xa_left_h[2];
    int16_t xa_right_h[2];
    int16_t xa_prev_left_sample;
    int16_t xa_prev_right_sample;
    int xa_sample_index;
    int state;
    int prev_state;
    int int1_pending;
    int int2_pending;
    int delay;
    uint32_t pending_lba;
    uint32_t lba;
    int16_t cdda_buf[CD_SECTOR_SIZE >> 1];
    int32_t cdda_remaining_samples;
    uint32_t cdda_sample_index;
    uint32_t cdda_sectors_played;
    int cdda_playing;
    int cdda_prev_track;
    int read_ongoing;
    uint8_t xa_buf[CD_SECTOR_SIZE];
    int16_t xa_left_buf[XA_STEREO_SAMPLES];
    int16_t xa_right_buf[XA_STEREO_SAMPLES];
    int16_t xa_mono_buf[XA_MONO_SAMPLES];
    int16_t xa_upsample_buf[XA_UPSAMPLE_SIZE];
    int16_t xa_left_resample_buf[XA_STEREO_RESAMPLE_SIZE];
    int16_t xa_right_resample_buf[XA_STEREO_RESAMPLE_SIZE];
    int16_t xa_mono_resample_buf[XA_MONO_RESAMPLE_SIZE];
} psx_cdrom_t;

enum {
    CDR_VERSION_01,  // DTL-H2000                 (??-???-????)
    CDR_VERSION_C0A, // PSX (PU-7)                (19-Sep-1994)
    CDR_VERSION_C0B, // PSX (PU-7)                (18-Nov-1994)
    CDR_VERSION_C1A, // PSX (EARLY-PU-8)          (16-May-1995)
    CDR_VERSION_C1B, // PSX (LATE-PU-8)           (24-Jul-1995)
    CDR_VERSION_D1,  // PSX (LATE-PU-8, Debug)    (24-Jul-1995)
    CDR_VERSION_C2V, // PSX (PU-16, Video CD)     (15-Aug-1996)
    CDR_VERSION_C1Y, // PSX (LATE-PU-8, Yaroze)   (18-Aug-1996)
    CDR_VERSION_C2J, // PSX (PU-18) (J)           (12-Sep-1996)
    CDR_VERSION_C2A, // PSX (PU-18) (U/E)         (10-Jan-1997)
    CDR_VERSION_C2B, // PSX (PU-20)               (14-Aug-1997)
    CDR_VERSION_C3A, // PSX (PU-22)               (10-Jul-1998)
    CDR_VERSION_C3B, // PSX/PSone (PU-23, PM-41)  (01-Feb-1999)
    CDR_VERSION_C3C  // PSone/late (PM-41(2))     (06-Jun-2001)
};

enum {
    CDR_REGION_JAPAN,
    CDR_REGION_EUROPE,
    CDR_REGION_AMERICA
};

uint8_t cdrom_get_stat(psx_cdrom_t* cdrom);
void cdrom_error(psx_cdrom_t* cdrom, uint8_t stat, uint8_t err);
int cdrom_get_seek_delay(psx_cdrom_t* cdrom, int ts);
int cdrom_get_pause_delay(psx_cdrom_t* cdrom);
int cdrom_get_read_delay(psx_cdrom_t* cdrom);
void cdrom_set_int(psx_cdrom_t* cdrom, int n);
void cdrom_process_setloc(psx_cdrom_t* cdrom);

psx_cdrom_t* psx_cdrom_create(void);
void psx_cdrom_init(psx_cdrom_t* cdrom, psx_ic_t* ic);
void psx_cdrom_set_version(psx_cdrom_t* cdrom, int version);
void psx_cdrom_set_region(psx_cdrom_t* cdrom, int region);
void psx_cdrom_open(psx_cdrom_t* cdrom, const char* path);
void psx_cdrom_close(psx_cdrom_t* cdrom);
uint32_t psx_cdrom_read32(psx_cdrom_t* cdrom, uint32_t addr);
uint32_t psx_cdrom_read16(psx_cdrom_t* cdrom, uint32_t addr);
uint32_t psx_cdrom_read8(psx_cdrom_t* cdrom, uint32_t addr);
void psx_cdrom_write32(psx_cdrom_t* cdrom, uint32_t addr, uint32_t value);
void psx_cdrom_write16(psx_cdrom_t* cdrom, uint32_t addr, uint32_t value);
void psx_cdrom_write8(psx_cdrom_t* cdrom, uint32_t addr, uint32_t value);
void psx_cdrom_update(psx_cdrom_t* cdrom, int cycles);
void psx_cdrom_get_audio_samples(psx_cdrom_t* cdrom, void* buf, size_t size);
void psx_cdrom_destroy(psx_cdrom_t* cdrom);

#endif