|
Nugget
Bare-metal libraries and examples for the original PlayStation
|

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) |
| cester_assert_int_eq | ( | 0 | , |
| peak | |||
| ) |
| cester_assert_int_eq | ( | 3 | , |
| xaCommand(CDL_GETMODE, NULL, 0, response, &size) | |||
| ) |
| cester_assert_int_eq | ( | 3 | , |
| xaCommand(CDL_SETFILTER, filter, 2, NULL, NULL) | |||
| ) |
| cester_assert_int_eq | ( | 3 | , |
| xaCommand(CDL_SETMODE, &mode, 1, NULL, NULL) | |||
| ) |
| cester_assert_int_ge | ( | peak | , |
| 22400 | |||
| ) |
| cester_assert_int_le | ( | peak | , |
| 22900 | |||
| ) |
| cester_assert_true | ( | done | ) |
| cester_assert_uint_eq | ( | 0 | , |
| audio | |||
| ) |
| cester_assert_uint_eq | ( | 0 | , |
| response | [2] | ||
| ) |
| cester_assert_uint_eq | ( | 0 | , |
| stats. | nonDataCauses | ||
| ) |
| cester_assert_uint_eq | ( | 0xc8 | , |
| response | [1] | ||
| ) |
| cester_assert_uint_eq | ( | 1 | , |
| response | [3] | ||
| ) |
| cester_assert_uint_eq | ( | 3 | , |
| response | [4] | ||
| ) |
| cester_assert_uint_eq | ( | 5 | , |
| size | |||
| ) |
| cester_assert_uint_ge | ( | changes | , |
| 4 | |||
| ) |
| cester_assert_uint_ge | ( | stats. | lastLBABusy, |
| 156504 | |||
| ) |
| cester_assert_uint_gt | ( | stats. | firstLBAClear, |
| 156744 | |||
| ) |
| cester_assert_uint_ne | ( | 0 | , |
| fillers | |||
| ) |
| cester_assert_uint_ne | ( | 0 | , |
| stats. | busySet | ||
| ) |
| 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 | ( | 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 | ( | 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 | ( | 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 | ( | 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 | ( | 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 | ( | "GetParam: %02x %02x %02x %02x %02x\n" | , |
| response | [0], | ||
| response | [1], | ||
| response | [2], | ||
| response | [3], | ||
| response | [4] | ||
| ) |
| uint32_t audio = stats.slotMask & 0x00ff |
| unsigned changes = 0 |
| uint32_t fillers = stats.slotMask & 0xff00 |
| uint8_t filter[2] = {1, 3} |
| uint8_t mode = 0xc8 |
| uint8_t response[16] |
| uint8_t size = 0 |
| struct XAReadStats stats |
| test_instance |