Nugget
Bare-metal libraries and examples for the original PlayStation
Loading...
Searching...
No Matches
Functions | Variables
xa.c File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

 CESTER_BODY (struct XAReadStats { unsigned events;unsigned nonDataCauses;unsigned unstamped;uint32_t slotMask;unsigned form2Seen;unsigned audioRealTime;unsigned audioNotRealTime;unsigned busySet;unsigned busyClear;uint32_t lastLBABusy;uint32_t firstLBAClear;unsigned busyAfterClear;uint32_t minLBA;uint32_t maxLBA;};static int xaCommand(uint8_t command, const uint8_t *params, unsigned count, uint8_t *response, uint8_t *responseSize) { CDROM_REG0=0;for(unsigned i=0;i< count;i++) CDROM_REG2=params[i];CDROM_REG1=command;uint32_t timeout=2000000;if(!waitCDRomIRQWithTimeout(&timeout)) return -1;uint8_t cause=ackCDRomCause();uint8_t buffer[16];uint8_t size=readResponse(response ? response :buffer);if(responseSize) *responseSize=size;return cause;} static int xaWaitCause(uint8_t expected, uint32_t timeoutUs) { uint8_t response[16];uint32_t timeout=timeoutUs;if(!waitCDRomIRQWithTimeout(&timeout)) return 0;uint8_t cause=ackCDRomCause();readResponse(response);return cause==expected;} static int xaSeekL(uint32_t lba) { uint32_t total=lba+150;uint8_t msf[3]={itob(total/4500), itob((total/75) % 60), itob(total % 75)};if(xaCommand(CDL_SETLOC, msf, 3, NULL, NULL) !=3) return 0;if(xaCommand(CDL_SEEKL, NULL, 0, NULL, NULL) !=3) return 0;return xaWaitCause(2, 4000000);} static void xaStop() { CDROM_REG0=0;CDROM_REG1=CDL_PAUSE;for(unsigned i=0;i< 64;i++) { uint8_t response[16];uint32_t timeout=1000000;if(!waitCDRomIRQWithTimeout(&timeout)) return;uint8_t cause=ackCDRomCause();readResponse(response);if(cause==2) return;} } static void xaReadHead(uint8_t *head, unsigned count) { CDROM_REG0=0;CDROM_REG3=0x80;for(unsigned t=0;t< 50000;t++) { if(CDROM_REG0 &0x40) break;} for(unsigned i=0;i< count;i++) head[i]=CDROM_REG2;CDROM_REG0=0;CDROM_REG3=0;} static int xaRead(uint8_t mode, int filter, uint8_t file, uint8_t channel, uint32_t startLBA, uint32_t durationUs, unsigned stopAfterClear, struct XAReadStats *stats) { __builtin_memset(stats, 0, sizeof(*stats));stats->minLBA=0xffffffff;if(!resetCDRom()) return 0;if(xaCommand(CDL_SETMODE, &mode, 1, NULL, NULL) !=3) return 0;if(filter) { uint8_t params[2]={file, channel};if(xaCommand(CDL_SETFILTER, params, 2, NULL, NULL) !=3) return 0;} if(!xaSeekL(startLBA)) return 0;if(xaCommand(CDL_READS, NULL, 0, NULL, NULL) !=3) return 0;initializeTime();uint32_t elapsed=0;while((elapsed< durationUs) &&(stats->events< 2000)) { uint32_t slice=30000;int got=waitCDRomIRQWithTimeout(&slice);elapsed=slice;if(!got) continue;int busy=(CDROM_REG0 &0x04) !=0;uint8_t cause=ackCDRomCause();uint8_t response[16];readResponse(response);stats->events++;if(cause !=1) { stats->nonDataCauses++;continue;} uint8_t head[16];const uint8_t *payload=head;if(mode &0x20) { xaReadHead(head, 16);payload=head+12;uint8_t submode=head[6];if(submode &0x04) { if(submode &0x40) { stats->audioRealTime++;} else { stats->audioNotRealTime++;} continue;} } else { xaReadHead(head, 4);} uint32_t lba=payload[0]|(payload[1]<< 8)|(payload[2]<< 16);if(lba< startLBA||lba > startLBA+20000) { stats->unstamped++;continue;} if(lba< stats->minLBA) stats->minLBA=lba;if(lba > stats->maxLBA) stats->maxLBA=lba;stats->slotMask|=1<<((lba - startLBA) % 16);if(payload[3]=='D') stats->form2Seen++;if(busy) { stats->busySet++;stats->lastLBABusy=lba;if(stats->busyClear) stats->busyAfterClear++;} else { if(!stats->busyClear) stats->firstLBAClear=lba;stats->busyClear++;if(stopAfterClear &&(stats->busyClear >=stopAfterClear)) break;} } xaStop();ramsyscall_printf("XA mode %02x filter %i %i/%i from %i: %i events, %i not data ready, %i unstamped, slots %04x, LBA %i-%i, " "form 2 %i, audio RT %i not RT %i, ADPBUSY set %i clear %i (last set %i, first clear %i)\n", mode, filter, file, channel, startLBA, stats->events, stats->nonDataCauses, stats->unstamped, stats->slotMask, stats->minLBA, stats->maxLBA, stats->form2Seen, stats->audioRealTime, stats->audioNotRealTime, stats->busySet, stats->busyClear, stats->lastLBABusy, stats->firstLBAClear);return 1;})
 
 cester_assert_int_eq (3, xaCommand(CDL_SETMODE, &mode, 1, NULL, NULL))
 
 cester_assert_int_eq (3, xaCommand(CDL_SETFILTER, filter, 2, NULL, NULL))
 
 cester_assert_int_eq (3, xaCommand(CDL_GETMODE, NULL, 0, response, &size))
 
 cester_assert_uint_eq (5, size)
 
 cester_assert_uint_eq (0xc8, response[1])
 
 cester_assert_uint_eq (0, response[2])
 
 cester_assert_uint_eq (1, response[3])
 
 cester_assert_uint_eq (3, response[4])
 
 ramsyscall_printf ("GetParam: %02x %02x %02x %02x %02x\n", response[0], response[1], response[2], response[3], response[4])
 
 CESTER_TEST (xaRealTimeFilteredWithholdsAudio, test_instance, struct XAReadStats stats;int done=xaRead(0xc8, 1, 1, 0, 135000, 1500000, 0, &stats);cester_assert_true(done);uint32_t fillers=stats.slotMask &0xff00;uint32_t audio=stats.slotMask &0x00ff;cester_assert_uint_ne(0, fillers);cester_assert_uint_eq(0, audio);cester_assert_uint_eq(0, stats.nonDataCauses);cester_assert_uint_eq(0, stats.unstamped);cester_assert_uint_eq(0, stats.busyClear);) CESTER_TEST(xaRealTimeOtherChannelWithholdsAudio
 
 cester_assert_true (done)
 
 cester_assert_uint_ne (0, fillers)
 
 cester_assert_uint_eq (0, audio)
 
 cester_assert_uint_eq (0, stats.nonDataCauses)
 
 CESTER_TEST (xaFilterWithoutRealTimeWithholdsAudio, test_instance, struct XAReadStats stats;int done=xaRead(0x88, 1, 1, 0, 135000, 1500000, 0, &stats);cester_assert_true(done);uint32_t fillers=stats.slotMask &0xff00;uint32_t audio=stats.slotMask &0x00ff;cester_assert_uint_ne(0, fillers);cester_assert_uint_eq(0, audio);cester_assert_uint_eq(0, stats.nonDataCauses);cester_assert_uint_eq(0, stats.unstamped);cester_assert_uint_eq(0, stats.busySet);) CESTER_TEST(xaRealTimeUnfilteredWithholdsAudio
 
 CESTER_TEST (xaForm2AndNonRealTimeAudioReachHost, test_instance, struct XAReadStats stats;int done=xaRead(0xe8, 1, 1, 0, 152744, 1500000, 0, &stats);cester_assert_true(done);cester_assert_uint_ne(0, stats.form2Seen);cester_assert_uint_ne(0, stats.audioNotRealTime);cester_assert_uint_eq(0, stats.audioRealTime);cester_assert_uint_eq(0, stats.nonDataCauses);cester_assert_uint_eq(0, stats.unstamped);) CESTER_TEST(xaEndOfFileAndRecordStopsADPCM
 
 cester_assert_uint_ne (0, stats.busySet)
 
 cester_assert_uint_ge (stats.lastLBABusy, 156504)
 
 cester_assert_uint_gt (stats.firstLBAClear, 156744)
 
 CESTER_BODY (static int xaPeak(const uint8_t atv[4], int demute, unsigned *signChanges) { if(!cddaAudioSetup(atv, demute)) return -1;uint8_t mode=0xc8;if(xaCommand(CDL_SETMODE, &mode, 1, NULL, NULL) !=3) return -1;uint8_t filter[2]={1, 0};if(xaCommand(CDL_SETFILTER, filter, 2, NULL, NULL) !=3) return -1;if(!xaSeekL(135016)) return -1;if(xaCommand(CDL_READS, NULL, 0, NULL, NULL) !=3) return -1;initializeTime();uint32_t elapsed=0;while(elapsed< 600000u) { uint32_t budget=10000u;int ok=waitCDRomIRQWithTimeout(&budget);elapsed=budget;if(!ok) continue;uint8_t response[16];ackCDRomCause();readResponse(response);} int peak=cddaCapturePeak(signChanges);xaStop();return peak;})
 
 ramsyscall_printf ("XA level at unity ATV: peak %i, %u sign changes\n", peak, changes)
 
 cester_assert_int_ge (peak, 22400)
 
 cester_assert_int_le (peak, 22900)
 
 cester_assert_uint_ge (changes, 4)
 
 CESTER_TEST (xaLevelClipped, test_instance, static const uint8_t atv[4]={0x80, 0x80, 0x80, 0x80};unsigned changes=0;int peak=xaPeak(atv, 1, &changes);ramsyscall_printf("XA level at double ATV: peak %i, %u sign changes\n", peak, changes);cester_assert_int_ge(peak, 31700);cester_assert_int_le(peak, 32050);cester_assert_uint_ge(changes, 4);) CESTER_TEST(xaLevelMuted
 
 ramsyscall_printf ("XA level when muted: peak %i\n", peak)
 
 cester_assert_int_eq (0, peak)
 

Variables

uint8_t mode = 0xc8
 
uint8_t filter [2] = {1, 3}
 
uint8_t response [16]
 
uint8_t size = 0
 
 test_instance
 
struct XAReadStats stats
 
int done = xaRead(0xc8, 1, 1, 3, 135000, 1500000, 0, &stats)
 
uint32_t fillers = stats.slotMask & 0xff00
 
uint32_t audio = stats.slotMask & 0x00ff
 
unsigned changes = 0
 
int peak = xaPeak(atv, 1, &changes)
 

Function Documentation

◆ cester_assert_int_eq() [1/4]

cester_assert_int_eq ( 0  ,
peak   
)

◆ cester_assert_int_eq() [2/4]

cester_assert_int_eq ( 3  ,
xaCommand(CDL_GETMODE, NULL, 0, response, &size)   
)

◆ cester_assert_int_eq() [3/4]

cester_assert_int_eq ( 3  ,
xaCommand(CDL_SETFILTER, filter, 2, NULL, NULL)   
)

◆ cester_assert_int_eq() [4/4]

cester_assert_int_eq ( 3  ,
xaCommand(CDL_SETMODE, &mode, 1, NULL, NULL)   
)

◆ cester_assert_int_ge()

cester_assert_int_ge ( peak  ,
22400   
)

◆ cester_assert_int_le()

cester_assert_int_le ( peak  ,
22900   
)

◆ cester_assert_true()

cester_assert_true ( done  )

◆ cester_assert_uint_eq() [1/7]

cester_assert_uint_eq ( 0  ,
audio   
)

◆ cester_assert_uint_eq() [2/7]

cester_assert_uint_eq ( 0  ,
response  [2] 
)

◆ cester_assert_uint_eq() [3/7]

cester_assert_uint_eq ( 0  ,
stats.  nonDataCauses 
)

◆ cester_assert_uint_eq() [4/7]

cester_assert_uint_eq ( 0xc8  ,
response  [1] 
)

◆ cester_assert_uint_eq() [5/7]

cester_assert_uint_eq ( 1  ,
response  [3] 
)

◆ cester_assert_uint_eq() [6/7]

cester_assert_uint_eq ( 3  ,
response  [4] 
)

◆ cester_assert_uint_eq() [7/7]

cester_assert_uint_eq ( 5  ,
size   
)

◆ cester_assert_uint_ge() [1/2]

cester_assert_uint_ge ( changes  ,
4   
)

◆ cester_assert_uint_ge() [2/2]

cester_assert_uint_ge ( stats.  lastLBABusy,
156504   
)

◆ cester_assert_uint_gt()

cester_assert_uint_gt ( stats.  firstLBAClear,
156744   
)

◆ cester_assert_uint_ne() [1/2]

cester_assert_uint_ne ( 0  ,
fillers   
)

◆ cester_assert_uint_ne() [2/2]

cester_assert_uint_ne ( 0  ,
stats.  busySet 
)

◆ CESTER_BODY() [1/2]

CESTER_BODY ( static int xaPeak(const uint8_t atv[4], int demute, unsigned *signChanges) { if(!cddaAudioSetup(atv, demute)) return -1;uint8_t mode=0xc8;if(xaCommand(CDL_SETMODE, &mode, 1, NULL, NULL) !=3) return -1;uint8_t filter[2]={1, 0};if(xaCommand(CDL_SETFILTER, filter, 2, NULL, NULL) !=3) return -1;if(!xaSeekL(135016)) return -1;if(xaCommand(CDL_READS, NULL, 0, NULL, NULL) !=3) return -1;initializeTime();uint32_t elapsed=0;while(elapsed< 600000u) { uint32_t budget=10000u;int ok=waitCDRomIRQWithTimeout(&budget);elapsed=budget;if(!ok) continue;uint8_t response[16];ackCDRomCause();readResponse(response);} int peak=cddaCapturePeak(signChanges);xaStop();return peak;}  )

◆ CESTER_BODY() [2/2]

CESTER_BODY ( struct XAReadStats { unsigned events;unsigned nonDataCauses;unsigned unstamped;uint32_t slotMask;unsigned form2Seen;unsigned audioRealTime;unsigned audioNotRealTime;unsigned busySet;unsigned busyClear;uint32_t lastLBABusy;uint32_t firstLBAClear;unsigned busyAfterClear;uint32_t minLBA;uint32_t maxLBA;};static int xaCommand(uint8_t command, const uint8_t *params, unsigned count, uint8_t *response, uint8_t *responseSize) { CDROM_REG0=0;for(unsigned i=0;i< count;i++) CDROM_REG2=params[i];CDROM_REG1=command;uint32_t timeout=2000000;if(!waitCDRomIRQWithTimeout(&timeout)) return -1;uint8_t cause=ackCDRomCause();uint8_t buffer[16];uint8_t size=readResponse(response ? response :buffer);if(responseSize) *responseSize=size;return cause;} static int xaWaitCause(uint8_t expected, uint32_t timeoutUs) { uint8_t response[16];uint32_t timeout=timeoutUs;if(!waitCDRomIRQWithTimeout(&timeout)) return 0;uint8_t cause=ackCDRomCause();readResponse(response);return cause==expected;} static int xaSeekL(uint32_t lba) { uint32_t total=lba+150;uint8_t msf[3]={itob(total/4500), itob((total/75) % 60), itob(total % 75)};if(xaCommand(CDL_SETLOC, msf, 3, NULL, NULL) !=3) return 0;if(xaCommand(CDL_SEEKL, NULL, 0, NULL, NULL) !=3) return 0;return xaWaitCause(2, 4000000);} static void xaStop() { CDROM_REG0=0;CDROM_REG1=CDL_PAUSE;for(unsigned i=0;i< 64;i++) { uint8_t response[16];uint32_t timeout=1000000;if(!waitCDRomIRQWithTimeout(&timeout)) return;uint8_t cause=ackCDRomCause();readResponse(response);if(cause==2) return;} } static void xaReadHead(uint8_t *head, unsigned count) { CDROM_REG0=0;CDROM_REG3=0x80;for(unsigned t=0;t< 50000;t++) { if(CDROM_REG0 &0x40) break;} for(unsigned i=0;i< count;i++) head[i]=CDROM_REG2;CDROM_REG0=0;CDROM_REG3=0;} static int xaRead(uint8_t mode, int filter, uint8_t file, uint8_t channel, uint32_t startLBA, uint32_t durationUs, unsigned stopAfterClear, struct XAReadStats *stats) { __builtin_memset(stats, 0, sizeof(*stats));stats->minLBA=0xffffffff;if(!resetCDRom()) return 0;if(xaCommand(CDL_SETMODE, &mode, 1, NULL, NULL) !=3) return 0;if(filter) { uint8_t params[2]={file, channel};if(xaCommand(CDL_SETFILTER, params, 2, NULL, NULL) !=3) return 0;} if(!xaSeekL(startLBA)) return 0;if(xaCommand(CDL_READS, NULL, 0, NULL, NULL) !=3) return 0;initializeTime();uint32_t elapsed=0;while((elapsed< durationUs) &&(stats->events< 2000)) { uint32_t slice=30000;int got=waitCDRomIRQWithTimeout(&slice);elapsed=slice;if(!got) continue;int busy=(CDROM_REG0 &0x04) !=0;uint8_t cause=ackCDRomCause();uint8_t response[16];readResponse(response);stats->events++;if(cause !=1) { stats->nonDataCauses++;continue;} uint8_t head[16];const uint8_t *payload=head;if(mode &0x20) { xaReadHead(head, 16);payload=head+12;uint8_t submode=head[6];if(submode &0x04) { if(submode &0x40) { stats->audioRealTime++;} else { stats->audioNotRealTime++;} continue;} } else { xaReadHead(head, 4);} uint32_t lba=payload[0]|(payload[1]<< 8)|(payload[2]<< 16);if(lba< startLBA||lba > startLBA+20000) { stats->unstamped++;continue;} if(lba< stats->minLBA) stats->minLBA=lba;if(lba > stats->maxLBA) stats->maxLBA=lba;stats->slotMask|=1<<((lba - startLBA) % 16);if(payload[3]=='D') stats->form2Seen++;if(busy) { stats->busySet++;stats->lastLBABusy=lba;if(stats->busyClear) stats->busyAfterClear++;} else { if(!stats->busyClear) stats->firstLBAClear=lba;stats->busyClear++;if(stopAfterClear &&(stats->busyClear >=stopAfterClear)) break;} } xaStop();ramsyscall_printf("XA mode %02x filter %i %i/%i from %i: %i events, %i not data ready, %i unstamped, slots %04x, LBA %i-%i, " "form 2 %i, audio RT %i not RT %i, ADPBUSY set %i clear %i (last set %i, first clear %i)\n", mode, filter, file, channel, startLBA, stats->events, stats->nonDataCauses, stats->unstamped, stats->slotMask, stats->minLBA, stats->maxLBA, stats->form2Seen, stats->audioRealTime, stats->audioNotRealTime, stats->busySet, stats->busyClear, stats->lastLBABusy, stats->firstLBAClear);return 1;}  )

◆ CESTER_TEST() [1/4]

CESTER_TEST ( xaFilterWithoutRealTimeWithholdsAudio  ,
test_instance  ,
struct XAReadStats stats;int  done = xaRead(0x88, 1, 1, 0, 135000, 1500000, 0, &stats); cester_assert_true(done); uint32_t fillers = stats.slotMask & 0xff00; uint32_t audio = stats.slotMask & 0x00ff; cester_assert_uint_ne(0, fillers); cester_assert_uint_eq(0, audio); cester_assert_uint_eq(0, stats.nonDataCauses); cester_assert_uint_eq(0, stats.unstamped); cester_assert_uint_eq(0, stats.busySet); 
)

◆ CESTER_TEST() [2/4]

CESTER_TEST ( xaForm2AndNonRealTimeAudioReachHost  ,
test_instance  ,
struct XAReadStats stats;int  done = xaRead(0xe8, 1, 1, 0, 152744, 1500000, 0, &stats); cester_assert_true(done); cester_assert_uint_ne(0, stats.form2Seen); cester_assert_uint_ne(0, stats.audioNotRealTime); cester_assert_uint_eq(0, stats.audioRealTime); cester_assert_uint_eq(0, stats.nonDataCauses); cester_assert_uint_eq(0, stats.unstamped); 
)

◆ CESTER_TEST() [3/4]

CESTER_TEST ( xaLevelClipped  ,
test_instance  ,
static const uint8_t  atv[4] = {0x80, 0x80, 0x80, 0x80}; unsigned changes = 0; int peak = xaPeak(atv, 1, &changes); ramsyscall_printf("XA level at double ATV: peak %i, %u sign changes\n", peak, changes); cester_assert_int_ge(peak, 31700); cester_assert_int_le(peak, 32050); cester_assert_uint_ge(changes, 4); 
)

◆ CESTER_TEST() [4/4]

CESTER_TEST ( xaRealTimeFilteredWithholdsAudio  ,
test_instance  ,
struct XAReadStats stats;int  done = xaRead(0xc8, 1, 1, 0, 135000, 1500000, 0, &stats); cester_assert_true(done); uint32_t fillers = stats.slotMask & 0xff00; uint32_t audio = stats.slotMask & 0x00ff; cester_assert_uint_ne(0, fillers); cester_assert_uint_eq(0, audio); cester_assert_uint_eq(0, stats.nonDataCauses); cester_assert_uint_eq(0, stats.unstamped); cester_assert_uint_eq(0, stats.busyClear); 
)

◆ ramsyscall_printf() [1/3]

ramsyscall_printf ( "GetParam: %02x %02x %02x %02x %02x\n"  ,
response  [0],
response  [1],
response  [2],
response  [3],
response  [4] 
)

◆ ramsyscall_printf() [2/3]

ramsyscall_printf ( "XA level at unity ATV: peak %  i,
%u sign changes\n"  ,
peak  ,
changes   
)

◆ ramsyscall_printf() [3/3]

ramsyscall_printf ( "XA level when muted: peak %i\n"  ,
peak   
)

Variable Documentation

◆ audio

uint32_t audio = stats.slotMask & 0x00ff

◆ changes

unsigned changes = 0

◆ done

int done = xaRead(0xc8, 1, 1, 3, 135000, 1500000, 0, &stats)

◆ fillers

uint32_t fillers = stats.slotMask & 0xff00

◆ filter

uint8_t filter[2] = {1, 3}

◆ mode

uint8_t mode = 0xc8

◆ peak

int peak = xaPeak(atv, 1, &changes)

◆ response

uint8_t response[16]

◆ size

uint8_t size = 0

◆ stats

struct XAReadStats stats

◆ test_instance

test_instance