diff --git a/include/PRinternal/viint.h b/include/PRinternal/viint.h index ffe0927..3645d11 100644 --- a/include/PRinternal/viint.h +++ b/include/PRinternal/viint.h @@ -67,5 +67,5 @@ extern __OSViContext *__osViNext; extern u32 __additional_scanline; __OSViContext *__osViGetCurrentContext(void); void __osViInit(void); -extern OSDevMgr __osViDevMgr; +extern OSDevMgr __osViDevMgr; #endif diff --git a/src/io/aigetlen.c b/src/io/aigetlen.c index 6b83682..aadf891 100644 --- a/src/io/aigetlen.c +++ b/src/io/aigetlen.c @@ -3,6 +3,12 @@ // TODO: this comes from a header #ident "$Revision: 1.17 $" +/** + * Returns the number of bytes remaining in a currently ongoing audio DMA. + * + * Note that audio DMA is double-buffered, a DMA can be queued while another is in-progress. This only returns + * information about the currently in-progress DMA. + */ u32 osAiGetLength(void) { return IO_READ(AI_LEN_REG); } diff --git a/src/io/aigetstat.c b/src/io/aigetstat.c index c7a3cf7..270b66e 100644 --- a/src/io/aigetstat.c +++ b/src/io/aigetstat.c @@ -3,6 +3,6 @@ // TODO: this comes from a header #ident "$Revision: 1.17 $" -u32 osAiGetStatus() { +u32 osAiGetStatus(void) { return IO_READ(AI_STATUS_REG); } diff --git a/src/io/aisetfreq.c b/src/io/aisetfreq.c index df324b0..2b0efca 100644 --- a/src/io/aisetfreq.c +++ b/src/io/aisetfreq.c @@ -7,6 +7,12 @@ extern s32 osViClock; // TODO: this comes from a header #ident "$Revision: 1.17 $" +/** + * Programs the operating frequency of the Audio DAC. + * + * @param frequency Target Playback frequency. + * @return The actual playback frequency, or -1 if the supplied frequency cannot be used. + */ s32 osAiSetFrequency(u32 frequency) { register unsigned int dacRate; register unsigned char bitRate; @@ -31,15 +37,20 @@ s32 osAiSetFrequency(u32 frequency) { } #endif + // Calculate the DAC sample period ("dperiod") (dperiod + 1 = vid_clock / frequency) f = osViClock / (float)frequency + .5f; dacRate = f; + // Upcoming division by 66. If dacRate is smaller than 2 * 66 = 132, bitrate will be 1 and AI_BITRATE_REG will be + // programmed with 0, which results in no audio output. Return -1 to indicate an unusable frequency. if (dacRate < AI_MIN_DAC_RATE) { return -1; } + // Calculate the largest "bitrate" (ABUS clock half period, "aclockhp") supported for this dacrate. These two + // quantities must satisfy (dperiod + 1) >= 66 * (aclockhp + 1), here this is taken as equality. bitRate = dacRate / 66; - + // Clamp to max value if (bitRate > AI_MAX_BIT_RATE) { bitRate = AI_MAX_BIT_RATE; } @@ -49,5 +60,7 @@ s32 osAiSetFrequency(u32 frequency) { #if BUILD_VERSION < VERSION_J IO_WRITE(AI_CONTROL_REG, AI_CONTROL_DMA_ON); #endif + // Return the true playback frequency (frequency = vid_clock / (dperiod + 1)), which may differ from the target + // frequency. return osViClock / (s32)dacRate; } diff --git a/src/io/contquery.c b/src/io/contquery.c index f2869f0..d3c06fc 100644 --- a/src/io/contquery.c +++ b/src/io/contquery.c @@ -2,6 +2,10 @@ #include "PRinternal/controller.h" #include "PRinternal/siint.h" +/** + * Starts to read the values for SI device status and type which are connected to the controller port and joyport + * connector. + */ s32 osContStartQuery(OSMesgQueue* mq) { s32 ret = 0; @@ -19,6 +23,9 @@ s32 osContStartQuery(OSMesgQueue* mq) { return ret; } +/** + * Returns the values from osContStartQuery to status. Both functions must be paired for use. + */ void osContGetQuery(OSContStatus* data) { u8 pattern; __osContGetInitData(&pattern, data); diff --git a/src/io/controller.c b/src/io/controller.c index 6c95555..f4bf72b 100644 --- a/src/io/controller.c +++ b/src/io/controller.c @@ -11,7 +11,7 @@ OSTimer __osEepromTimer; OSMesgQueue __osEepromTimerQ ALIGNED(8); OSMesg __osEepromTimerMsg; -s32 __osContinitialized = 0; +s32 __osContinitialized = FALSE; s32 osContInit(OSMesgQueue* mq, u8* bitpattern, OSContStatus* data) { OSMesg dummy; @@ -20,11 +20,11 @@ s32 osContInit(OSMesgQueue* mq, u8* bitpattern, OSContStatus* data) { OSTimer mytimer; OSMesgQueue timerMesgQueue; - if (__osContinitialized != 0) { + if (__osContinitialized) { return 0; } - __osContinitialized = 1; + __osContinitialized = TRUE; t = osGetTime(); if (t < OS_USEC_TO_CYCLES(500000)) { diff --git a/src/io/contsetch.c b/src/io/contsetch.c index f784161..73a1ac1 100644 --- a/src/io/contsetch.c +++ b/src/io/contsetch.c @@ -2,6 +2,10 @@ #include "PRinternal/controller.h" #include "PRinternal/siint.h" +/* + * This function specifies the number of devices for the functions to access when those functions access to multiple + * direct SI devices. + */ s32 osContSetCh(u8 ch) { s32 ret = 0; diff --git a/src/io/crc.c b/src/io/crc.c index 3293b2d..bb6eb20 100644 --- a/src/io/crc.c +++ b/src/io/crc.c @@ -1,56 +1,154 @@ +/** + * File: crc.c + * Description: Functions to compute Cyclic Redundancy Check for specific addresses and data. + * + * CRC notes: + * + * General + * === + * - CRC (Cyclic Redundancy Check) is a way of verifying that no errors were introduced in transmitted data. + * - It reads the entire message and generates a check number that is appended to it. + * - A CRC is specified by the length `n` of the check number and a number (called the generator) smaller than `1 << n`. + * - Different generators have different error-checking capabilities. The choice of a generator is a sophisticated + * mathematical problem. + * + * Mathematical basis + * === + * - The algorithm is based on division of polynomials. The polynomials have coefficients in the field with two + * elements, 0 and 1, with addition given by XOR and multiplication by AND (it turns out this really is a field). + * Subtraction is the same as addition. + * - There is a one-to-one correspondence between binary polynomials and binary numbers: just evaluate the polynomial at + * 2, or write down an \f$ X^k \f$ corresponding to each `1 << k` the number is composed of. + * - The message bits `m{L}m{L-1}...m{1}m{0}` correspond to a polynomial \f$ m(X) = m_L X^L + m_{L-1} X^{L-1} + \dotsb + + * m_1 X^1 + m_0 X^0 \f$. We multiply this by \f$ X^n \f$ to make a space to insert the remainder at the end; this new + * polynomial will be the dividend. + * - The generator `p{n-1}p{n-2}...p{1}p{0}` corresponds to a polynomial \f$ p(X) = X^n + p_{n-1} X^{n-1} + \dotsb + p_1 + * X^1 + p_0 X^0 \f$: the leading term is omitted in the binary description because it is always \f$ X^n \f$. The + * generator polynomial is the divisor. + * - The usual division algorithm is followed: we look along the dividend until we see a nonzero coefficient, then + * subtract an appropriate multiple of the divisor to cancel it out. We repeat this until we reach the end of the + * number. + * - Arithmetic in the field with two elements is particularly simple: subtraction is identical to addition, so also + * given by XOR, and the only multipliers required for subtracting the divisor are \f$ X^k \f$. + * - After applying the algorithm, the output is a polynomial \f$ R(X) \f$ so that we have + * \f[ m(X) X^n = Q(X) p(X) + R(X) \f] + * (\f$ R(X) \f$ is the *remainder after dividing by \f$ p(X) \f$*). + * - Therefore, \f$ m(X) X^n - R(X) \f$ is divisible by the generator polynomial. This means that if we append the + * binary number corresponding to \f$ R(X) \f$ to the message and rerun the algorithm, we will get 0 if no errors have + * been introduced. + * + * + * Implementation + * === + * - We translate the binary polynomials to binary numbers by evaluating them at 2. The leading term in the generator + * polynomial is always \f$ X^n \f$, so we discard it to save space. In the binary field, subtraction is the same as + * addition, and given by XOR. Multiplication by \f$ X \f$ is given by shifting left. + * - Instead of fixing the message and moving the divisor polynomial right, we scan the message from the most + * significant digit, adding it to the end of the return value, (that is, for 1s, we shift and add 1, for 0s we just + * shift, effectively using the return value as a shift register). + * - When the return value has a 1 in the nth position (corresponding to the leading term in the generator polynomial), + * we binary-subtract (i.e. XOR) the return value with the generator polynomial's number. + * - This is repeated until we reach the end of the message. + * - Finally, to take into account the final multiplication by \f$ X^n \f$, we run another loop, which acts like we + * passed \f$ n \f$ more digits in the message that are all zero. Remember this gives us the extra space at the end for + * the check digits to be added. + * + * + * - To specify a CRC, at minimum we need the length of the check (i.e. the degree of the generator polynomial), \f$ n + * \f$, and the rest of the generator polynomial. This is usually expressed in the binary form, written as hex for + * compactness. Algorithms may also reverse or invert certain parts of the data or check to improve particular aspects + * of the algorithm, but the libultra functions use the simplest version. + * + * + * Resources + * === + * - Wikipedia: [Cyclic redundancy check](https://en.wikipedia.org/wiki/Cyclic_redundancy_check), and more specifically + * [Computation of cyclic redundancy checks](https://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks) + * - Ben Eater has two videos on CRCs, the last two linked on [Error Detection | Ben Eater](https://eater.net/crc) + * - A page that specifically describes the same shift-register-style algorithms as libultra uses: [Understanding and + * implementing CRC (Cyclic Redundancy Check) calculation + * ](http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html) + */ #include "PR/os_internal.h" #if BUILD_VERSION >= VERSION_J +#define ADDRESS_CRC_MESSAGE_LENGTH 10 +#define ADDRESS_CRC_LENGTH 5 +#define ADDRESS_CRC_GENERATOR 0x15 +#define ADDRESS_CRC_MASK ((1 << ADDRESS_CRC_LENGTH) - 1) + +/** + * CRC-5 with the generating polynomial \f$ x^5 + x^4 + x^2 + 1 \f$, AKA 0x15 = 0b(1)1 0101. + * It only works on the bits from 0x7FF = 11 11111111, i.e. 10 bits. + * + * Usually used as __osContAddressCrc(addr) | (addr << 5) to add the CRC to the end. The overall length of 10 + 5 bits + * allows the address + CRC to fit into one s16. + * + * `addr` is the address of a block in the mempak, only valid up to 0x7FF. + */ u8 __osContAddressCrc(u16 addr) { u32 temp = 0; - u32 i = 0x400; + u32 i = (1 << ADDRESS_CRC_MESSAGE_LENGTH); do { + // temp is used as a shift register for the CRC temp <<= 1; if ((u32)addr & i) { - if (temp & 0x20) { - temp ^= 0x14; + if (temp & (1 << ADDRESS_CRC_LENGTH)) { + // Same as temp++; temp ^= 0x15 since last bit always 0 after the shift + temp ^= ADDRESS_CRC_GENERATOR - 1; } else { ++temp; } - } else if (temp & 0x20) { - temp ^= 0x15; + } else if (temp & (1 << ADDRESS_CRC_LENGTH)) { + temp ^= ADDRESS_CRC_GENERATOR; } i >>= 1; } while (i != 0); - i = 5; - + // Acts like 5 bits of 0s are appended to addr + i = ADDRESS_CRC_LENGTH; do { temp <<= 1; - if (temp & 0x20) { - temp ^= 0x15; + if (temp & (1 << ADDRESS_CRC_LENGTH)) { + temp ^= ADDRESS_CRC_GENERATOR; } } while (--i != 0); - return temp & 0x1F; + // Discard the irrelevant bits above the actual remainder + return temp & ADDRESS_CRC_MASK; } +#define DATA_CRC_MESSAGE_BYTES 32 +#define DATA_CRC_LENGTH 8 +#define DATA_CRC_GENERATOR 0x85 + +/** + * CRC-8 with generating polynomial \f$ x^8 + x^7 + x^2 + 1 \f$, AKA 0x85 = 0b(1) 1000 0101. + * Expects exactly 0x20 = 32 bytes of data. + */ u8 __osContDataCrc(u8* data) { u32 temp = 0; u32 i; u32 j; - for (i = 0x20; i; --i) { - for (j = 0x80; j; j >>= 1) { + for (i = DATA_CRC_MESSAGE_BYTES; i; --i) { + // Loop over each bit in the byte starting with most significant + for (j = (1 << (DATA_CRC_LENGTH - 1)); j; j >>= 1) { temp <<= 1; if ((*data & j) != 0) { - if ((temp & 0x100) != 0) { - temp ^= 0x84; + if ((temp & (1 << DATA_CRC_LENGTH)) != 0) { + // Same as ret++; ret ^= 0x85 since last bit always 0 after the shift + temp ^= DATA_CRC_GENERATOR - 1; } else { ++temp; } - } else if (temp & 0x100) { - temp ^= 0x85; + } else if (temp & (1 << DATA_CRC_LENGTH)) { + temp ^= DATA_CRC_GENERATOR; } } @@ -59,10 +157,10 @@ u8 __osContDataCrc(u8* data) { do { temp <<= 1; - if (temp & 0x100) { - temp ^= 0x85; + if (temp & (1 << DATA_CRC_LENGTH)) { + temp ^= DATA_CRC_GENERATOR; } - } while (++i < 8U); + } while (++i < DATA_CRC_LENGTH); return temp; } diff --git a/src/io/dpgetstat.c b/src/io/dpgetstat.c index af3ccee..54dd3ac 100644 --- a/src/io/dpgetstat.c +++ b/src/io/dpgetstat.c @@ -4,6 +4,6 @@ // TODO: this comes from a header #ident "$Revision: 1.17 $" -u32 osDpGetStatus() { +u32 osDpGetStatus(void) { return IO_READ(DPC_STATUS_REG); } diff --git a/src/io/driverominit.c b/src/io/driverominit.c index d73d349..0370542 100644 --- a/src/io/driverominit.c +++ b/src/io/driverominit.c @@ -4,7 +4,7 @@ OSPiHandle DriveRomHandle ALIGNED(8); -OSPiHandle *osDriveRomInit() { +OSPiHandle *osDriveRomInit(void) { u32 saveMask; if (DriveRomHandle.baseAddress == PHYS_TO_K1(PI_DOM1_ADDR1)) { diff --git a/src/io/leodiskinit.c b/src/io/leodiskinit.c index e9f140b..f587b6e 100644 --- a/src/io/leodiskinit.c +++ b/src/io/leodiskinit.c @@ -7,7 +7,7 @@ OSPiHandle LeoDiskHandle ALIGNED(8); OSPiHandle *__osDiskHandle; -OSPiHandle *osLeoDiskInit() { +OSPiHandle *osLeoDiskInit(void) { u32 saveMask; LeoDiskHandle.type = DEVICE_TYPE_64DD; diff --git a/src/io/leointerrupt.c b/src/io/leointerrupt.c index de8e59e..ae3b9fd 100644 --- a/src/io/leointerrupt.c +++ b/src/io/leointerrupt.c @@ -11,7 +11,7 @@ u8 leoDiskStack[OS_PIM_STACKSIZE] ALIGNED(16); static void __osLeoAbnormalResume(void); static void __osLeoResume(void); -s32 __osLeoInterrupt() { +s32 __osLeoInterrupt(void) { u32 stat = 0; volatile u32 pi_stat; u32 bm_stat; diff --git a/src/io/pfsallocatefile.c b/src/io/pfsallocatefile.c index 2fc1c72..fa7ceaf 100644 --- a/src/io/pfsallocatefile.c +++ b/src/io/pfsallocatefile.c @@ -241,7 +241,7 @@ s32 osPfsAllocateFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name backup_inode.inode_page[old_last_page].inode_t.bank = bank; backup_inode.inode_page[old_last_page].inode_t.page = start_page; - ERRCK(__osPfsRWInode(pfs, &backup_inode, OS_WRITE, old_bank)); + ERRCK(__osPfsRWInode(pfs, &backup_inode, PFS_WRITE, old_bank)); dir.start_page = fpage; dir.company_code = company_code; diff --git a/src/io/pfschecker.c b/src/io/pfschecker.c index 599acec..65f1193 100644 --- a/src/io/pfschecker.c +++ b/src/io/pfschecker.c @@ -56,7 +56,7 @@ s32 osPfsChecker(OSPfs* pfs) { bank = next_page.inode_t.bank; if (oldbank != bank) { - ret = __osPfsRWInode(pfs, &tmp_inode, OS_READ, bank); + ret = __osPfsRWInode(pfs, &tmp_inode, PFS_READ, bank); oldbank = bank; } @@ -91,7 +91,7 @@ s32 osPfsChecker(OSPfs* pfs) { while (CHECK_IPAGE(next_page)) { if (bank != next_page.inode_t.bank) { bank = next_page.inode_t.bank; - ret = __osPfsRWInode(pfs, &tmp_inode, OS_READ, bank); + ret = __osPfsRWInode(pfs, &tmp_inode, PFS_READ, bank); if (ret != 0 && ret != PFS_ERR_INCONSISTENT) { return ret; } @@ -143,7 +143,7 @@ s32 osPfsChecker(OSPfs* pfs) { } for (bank = 0; bank < pfs->banks; bank++) { - ret = __osPfsRWInode(pfs, &tmp_inode, 0, bank); + ret = __osPfsRWInode(pfs, &tmp_inode, PFS_READ, bank); if (ret != 0 && ret != PFS_ERR_INCONSISTENT) { return ret; @@ -165,7 +165,7 @@ s32 osPfsChecker(OSPfs* pfs) { file_next_node[j] = checked_inode.inode_page[pp] = tmp_inode.inode_page[pp]; } } - ERRCK(__osPfsRWInode(pfs, &checked_inode, OS_WRITE, bank)); + ERRCK(__osPfsRWInode(pfs, &checked_inode, PFS_WRITE, bank)); } if (fixed) { @@ -194,7 +194,7 @@ s32 corrupted_init(OSPfs* pfs, __OSInodeCache* cache) { for (bank = 0; bank < pfs->banks; bank++) { offset = bank > 0 ? 1 : pfs->inode_start_page; - ret = __osPfsRWInode(pfs, &tmp_inode, OS_READ, bank); + ret = __osPfsRWInode(pfs, &tmp_inode, PFS_READ, bank); if (ret != 0 && ret != PFS_ERR_INCONSISTENT) { return ret; @@ -235,7 +235,7 @@ s32 corrupted(OSPfs* pfs, __OSInodeUnit fpage, __OSInodeCache* cache) { if (bank == fpage.inode_t.bank || cache->map[n] & (1 << (bank % PFS_BANK_LAPPED_BY))) { if (bank != cache->bank) { - ret = __osPfsRWInode(pfs, &cache->inode, 0, bank); + ret = __osPfsRWInode(pfs, &cache->inode, PFS_READ, bank); if (ret != 0 && ret != PFS_ERR_INCONSISTENT) { return ret; diff --git a/src/io/pfsdeletefile.c b/src/io/pfsdeletefile.c index 60a8b3e..67e0bf6 100644 --- a/src/io/pfsdeletefile.c +++ b/src/io/pfsdeletefile.c @@ -39,13 +39,13 @@ s32 osPfsDeleteFile(OSPfs* pfs, u16 company_code, u32 game_code, u8* game_name, startpage = dir.start_page.inode_t.page; for (bank = dir.start_page.inode_t.bank; bank < pfs->banks;) { - ERRCK(__osPfsRWInode(pfs, &inode, OS_READ, bank)); + ERRCK(__osPfsRWInode(pfs, &inode, PFS_READ, bank)); #if BUILD_VERSION >= VERSION_J ERRCK(__osPfsReleasePages(pfs, &inode, startpage, bank, &last_page)); #else ERRCK(__osPfsReleasePages(pfs, &inode, startpage, &sum, bank, &last_page, TRUE)); #endif - ERRCK(__osPfsRWInode(pfs, &inode, OS_WRITE, bank)); + ERRCK(__osPfsRWInode(pfs, &inode, PFS_WRITE, bank)); if (last_page.ipage == PFS_EOF) { break; diff --git a/src/io/pfsfilestate.c b/src/io/pfsfilestate.c index 5ed630a..ec66445 100644 --- a/src/io/pfsfilestate.c +++ b/src/io/pfsfilestate.c @@ -73,7 +73,7 @@ s32 osPfsFileState(OSPfs* pfs, s32 file_no, OSPfsState* state) { bank = dir.start_page.inode_t.bank; while (bank < pfs->banks) { - ERRCK(__osPfsRWInode(pfs, &inode, OS_READ, bank)); + ERRCK(__osPfsRWInode(pfs, &inode, PFS_READ, bank)); next_page = inode.inode_page[start_page]; pages++; diff --git a/src/io/pfsfreeblocks.c b/src/io/pfsfreeblocks.c index 2ee92e4..f0b1ece 100644 --- a/src/io/pfsfreeblocks.c +++ b/src/io/pfsfreeblocks.c @@ -17,7 +17,7 @@ s32 osPfsFreeBlocks(OSPfs* pfs, s32* bytes_not_used) { PFS_CHECK_ID(); #endif for (bank = 0; bank < pfs->banks; bank++) { - ERRCK(__osPfsRWInode(pfs, &inode, OS_READ, bank)); + ERRCK(__osPfsRWInode(pfs, &inode, PFS_READ, bank)); offset = ((bank > 0) ? 1 : pfs->inode_start_page); for (j = offset; j < ARRLEN(inode.inode_page); j++) { diff --git a/src/io/pfsreadwritefile.c b/src/io/pfsreadwritefile.c index 507b12c..5a365b2 100644 --- a/src/io/pfsreadwritefile.c +++ b/src/io/pfsreadwritefile.c @@ -2,20 +2,22 @@ #include "PR/os_internal.h" #include "PRinternal/controller.h" +#define CHECK_IPAGE(p) \ + (((p).ipage >= pfs->inode_start_page) && ((p).inode_t.bank < pfs->banks) && ((p).inode_t.page >= 0x01) && \ + ((p).inode_t.page < 0x80)) + static s32 __osPfsGetNextPage(OSPfs* pfs, u8* bank, __OSInode* inode, __OSInodeUnit* page) { s32 ret; if (page->inode_t.bank != *bank) { *bank = page->inode_t.bank; - ERRCK(__osPfsRWInode(pfs, inode, 0, *bank)); + ERRCK(__osPfsRWInode(pfs, inode, PFS_READ, *bank)); } *page = inode->inode_page[page->inode_t.page]; - if (page->ipage < pfs->inode_start_page || page->inode_t.bank >= pfs->banks || page->inode_t.page <= 0 || - page->inode_t.page >= ARRLEN(inode->inode_page)) { - - if (page->ipage == 1) { + if (!CHECK_IPAGE(*page)) { + if (page->ipage == PFS_EOF) { return PFS_ERR_INVALID; } @@ -55,9 +57,8 @@ s32 osPfsReadWriteFile(OSPfs* pfs, s32 file_no, u8 flag, int offset, int size_in return PFS_ERR_INVALID; } - if (dir.start_page.ipage < pfs->inode_start_page || dir.start_page.inode_t.bank >= pfs->banks || - dir.start_page.inode_t.page <= 0 || dir.start_page.inode_t.page >= ARRLEN(inode.inode_page)) { - if ((dir.start_page.ipage == 1)) { + if (!CHECK_IPAGE(dir.start_page)) { + if ((dir.start_page.ipage == PFS_EOF)) { return PFS_ERR_INVALID; } diff --git a/src/io/pi.c b/src/io/pi.c index 3fd3a63..f2cc4b9 100644 --- a/src/io/pi.c +++ b/src/io/pi.c @@ -5,7 +5,7 @@ // TODO: this comes from a header #ident "$Revision: 1.17 $" -int __osPiDeviceBusy() { +int __osPiDeviceBusy(void) { register u32 stat = IO_READ(PI_STATUS_REG); if (stat & (PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY)) { return TRUE; diff --git a/src/io/pigetstat.c b/src/io/pigetstat.c index eef1cc1..a5ba497 100644 --- a/src/io/pigetstat.c +++ b/src/io/pigetstat.c @@ -4,6 +4,6 @@ // TODO: this comes from a header #ident "$Revision: 1.17 $" -u32 osPiGetStatus() { +u32 osPiGetStatus(void) { return IO_READ(PI_STATUS_REG); } diff --git a/src/io/pigettype.c b/src/io/pigettype.c index f918306..67fdc72 100644 --- a/src/io/pigettype.c +++ b/src/io/pigettype.c @@ -3,6 +3,6 @@ // TODO: this comes from a header #ident "$Revision: 1.17 $" -s32 osPiGetDeviceType() { +s32 osPiGetDeviceType(void) { return osRomType; } diff --git a/src/io/si.c b/src/io/si.c index 128858f..78794f5 100644 --- a/src/io/si.c +++ b/src/io/si.c @@ -4,7 +4,7 @@ // TODO: this comes from a header #ident "$Revision: 1.17 $" -int __osSiDeviceBusy() { +int __osSiDeviceBusy(void) { register u32 stat = IO_READ(SI_STATUS_REG); if (stat & (SI_STATUS_DMA_BUSY | SI_STATUS_RD_BUSY)) { diff --git a/src/io/sigetstat.c b/src/io/sigetstat.c index 8dad4c7..e21e50a 100644 --- a/src/io/sigetstat.c +++ b/src/io/sigetstat.c @@ -4,6 +4,6 @@ // TODO: this comes from a header #ident "$Revision: 1.17 $" -u32 __osSiGetStatus() { +u32 __osSiGetStatus(void) { return IO_READ(SI_STATUS_REG); } diff --git a/src/io/sirawdma.c b/src/io/sirawdma.c index 57c5a45..ea2c228 100644 --- a/src/io/sirawdma.c +++ b/src/io/sirawdma.c @@ -39,16 +39,16 @@ - - // Adjust line numbers to match assert #if BUILD_VERSION < VERSION_J -#line 49 +#line 47 #endif +#define PIF_RAM_SIZE (PIF_RAM_END + 1 - PIF_RAM_START) + // TODO: this comes from a header #ident "$Revision: 1.17 $" @@ -66,7 +66,7 @@ s32 __osSiRawStartDma(s32 direction, void* dramAddr) { #endif if (direction == OS_WRITE) { - osWritebackDCache(dramAddr, 64); + osWritebackDCache(dramAddr, PIF_RAM_SIZE); } IO_WRITE(SI_DRAM_ADDR_REG, osVirtualToPhysical(dramAddr)); @@ -78,7 +78,7 @@ s32 __osSiRawStartDma(s32 direction, void* dramAddr) { } if (direction == OS_READ) { - osInvalDCache(dramAddr, 64); + osInvalDCache(dramAddr, PIF_RAM_SIZE); } return 0; diff --git a/src/io/sp.c b/src/io/sp.c index c6b4081..98e7c40 100644 --- a/src/io/sp.c +++ b/src/io/sp.c @@ -6,7 +6,7 @@ // TODO: this comes from a header #ident "$Revision: 1.17 $" -int __osSpDeviceBusy() { +int __osSpDeviceBusy(void) { register u32 stat = IO_READ(SP_STATUS_REG); if (stat & (SP_STATUS_DMA_BUSY | SP_STATUS_DMA_FULL | SP_STATUS_IO_FULL)) { diff --git a/src/io/spgetstat.c b/src/io/spgetstat.c index 0cdfda6..8125b64 100644 --- a/src/io/spgetstat.c +++ b/src/io/spgetstat.c @@ -4,6 +4,6 @@ // TODO: this comes from a header #ident "$Revision: 1.17 $" -u32 __osSpGetStatus() { +u32 __osSpGetStatus(void) { return IO_READ(SP_STATUS_REG); } diff --git a/src/io/sptask.c b/src/io/sptask.c index 487d7b8..3c3ef15 100644 --- a/src/io/sptask.c +++ b/src/io/sptask.c @@ -11,7 +11,7 @@ #define _osVirtualToPhysical(ptr) \ if (ptr != NULL) { \ ptr = (void*)osVirtualToPhysical(ptr); \ - } + } (void)0 static OSTask tmp_task; diff --git a/src/io/viswapcontext.c b/src/io/viswapcontext.c index 77618c6..a19fd40 100644 --- a/src/io/viswapcontext.c +++ b/src/io/viswapcontext.c @@ -5,7 +5,7 @@ // TODO: this comes from a header #ident "$Revision: 1.17 $" -void __osViSwapContext() { +void __osViSwapContext(void) { register OSViMode* vm; register __OSViContext* vc; u32 origin; @@ -38,7 +38,7 @@ void __osViSwapContext() { } #if BUILD_VERSION >= VERSION_J - vStart = (vm->fldRegs[field].vStart - (__additional_scanline << 0x10)) + __additional_scanline; + vStart = (vm->fldRegs[field].vStart - (__additional_scanline << VI_SUBPIXEL_SH)) + __additional_scanline; #endif hStart = vm->comRegs.hStart; diff --git a/src/libc/bzero.s b/src/libc/bzero.s index 894c186..b34c4a3 100644 --- a/src/libc/bzero.s +++ b/src/libc/bzero.s @@ -22,10 +22,13 @@ XLEAF(_blkclr) swl zero, 0(a0) addu a0, a0, v1 blkzero: + /* align backwards to 0x20 */ and a3, a1, ~31 subu a1, a1, a3 + /* If the result is zero, the amount to zero is less than 0x20 bytes */ beqz a3, wordzero + /* zero in blocks of 0x20 at a time */ addu a3, a3, a0 1: sw zero, 0(a0) @@ -40,10 +43,13 @@ blkzero: bne a0, a3, 1b wordzero: + /* align backwards to 0x4 */ and a3, a1, ~3 subu a1, a1, a3 + /* If the result is zero, the amount to zero is less than 0x4 bytes */ beqz a3, bytezero + /* zero one word at a time */ addu a3, a3, a0 1: addiu a0, a0, 4 @@ -51,8 +57,10 @@ wordzero: bne a0, a3, 1b bytezero: + /* test if nothing left to zero */ blez a1, zerodone #nop + /* zero one byte at a time */ addu a1, a1, a0 1: addiu a0, a0, 1 diff --git a/src/libc/ll.c b/src/libc/ll.c index 4334b03..512a998 100644 --- a/src/libc/ll.c +++ b/src/libc/ll.c @@ -1,5 +1,3 @@ -#include "PR/os.h" - unsigned long long __ull_rshift(unsigned long long a0, unsigned long long a1) { return a0 >> a1; } diff --git a/src/libc/llbit.c b/src/libc/llbit.c index 0680726..3e7e03b 100644 --- a/src/libc/llbit.c +++ b/src/libc/llbit.c @@ -1,4 +1,3 @@ -#include "PR/os.h" #include "PR/ultratypes.h" s64 __ll_bit_extract(u64* addr, unsigned int start_bit, unsigned int length) { diff --git a/src/libc/xldtob.c b/src/libc/xldtob.c index 1dc1434..023c8bd 100644 --- a/src/libc/xldtob.c +++ b/src/libc/xldtob.c @@ -41,7 +41,7 @@ static const double pows[] = {10e0L, 10e1L, 10e3L, 10e7L, 10e15L, 10e31L, 10e63L #define _D2 2 #define _D3 3 -#define ALIGN(s, align) (((u32)(s) + ((align)-1)) & ~((align)-1)) +#define ALIGN(s, align) (((u32)(s) + ((align)-1)) & ~((align)-1)) void _Ldtob(_Pft* px, char code) { char buff[BUFF_LEN]; diff --git a/src/os/ackramromread.c b/src/os/ackramromread.c index 3de1f6f..992a4f7 100644 --- a/src/os/ackramromread.c +++ b/src/os/ackramromread.c @@ -12,5 +12,5 @@ #ident "$Revision: 1.3 $" #endif -void osAckRamromRead() { +void osAckRamromRead(void) { } diff --git a/src/os/ackramromwrite.c b/src/os/ackramromwrite.c index a99e951..32301ab 100644 --- a/src/os/ackramromwrite.c +++ b/src/os/ackramromwrite.c @@ -11,5 +11,5 @@ #ident "$Revision: 1.3 $" #endif -void osAckRamromWrite() { +void osAckRamromWrite(void) { } diff --git a/src/os/afterprenmi.c b/src/os/afterprenmi.c index 03b5b24..7568251 100644 --- a/src/os/afterprenmi.c +++ b/src/os/afterprenmi.c @@ -1,5 +1,5 @@ #include "PR/os_internal.h" -s32 osAfterPreNMI() { +s32 osAfterPreNMI(void) { return __osSpSetPc(0); } diff --git a/src/os/exceptasm.s b/src/os/exceptasm.s index b7699a8..59e57d5 100644 --- a/src/os/exceptasm.s +++ b/src/os/exceptasm.s @@ -7,6 +7,7 @@ #include "exceptasm.h" #include "threadasm.h" #include "PR/os_version.h" + #define KMC_CODE_ENTRY 0xBFF00014 #define KMC_WPORT 0xBFF08000 #define KMC_STAT 0xBFF08004 @@ -101,10 +102,14 @@ __os_Kdebug_Pkt: __osPreviousThread: .word 0 #endif -#endif +#endif .text +/** + * The exception preamble is copied to the exception vectors at + * UT_VEC, XUT_VEC, ECC_VEC, E_VEC, to direct execution to __osException + */ LEAF(__osExceptionPreamble) la k0, __osException jr k0 @@ -174,25 +179,26 @@ pt_prof: END(__ptException) #endif -LEAF(__osException) +LEAF(__osException) + /* Load scratch space for thread saving */ la k0, __osThreadSave - /* save AT */ + /* Save AT */ .set noat sd $1, THREAD_GP1(k0); .set at - /* save sr */ + /* Save SR */ STAY2(mfc0 k1, C0_SR) sw k1, THREAD_SR(k0) - /* clear interrupts */ - and k1, k1, -4 + /* Disable interrupts */ + and k1, k1, ~(SR_IE | SR_EXL) STAY2(mtc0 k1, C0_SR) - /* save other regs */ + /* Save some temp registers for use in the following */ sd $8, THREAD_GP8(k0) sd $9, THREAD_GP9(k0) sd $10, THREAD_GP10(k0) - /* say fp has not been used */ + /* Mark FPU as unused */ sw zero, THREAD_FP(k0) - /* this instruction is useless, leftover because of bad placement of an ifdef for the debug version */ + /* This instruction is useless, leftover because of bad placement of an ifdef for the debug version */ STAY2(mfc0 t0, C0_CAUSE) #ifndef _FINALROM lw t2, __kmc_pt_mode @@ -390,8 +396,9 @@ skip_kmc_mode: #endif savecontext: + /* Save the context of the previously running thread to be restored when it resumes */ move t0, k0 - lw k0, __osRunningThread + lw k0, __osRunningThread #if !defined(_FINALROM) && BUILD_VERSION >= VERSION_K sw k0, __osPreviousThread #endif @@ -440,8 +447,13 @@ savecontext: lw k1, THREAD_SR(k0) andi t1, k1, SR_IMASK beqz t1, savercp - -/*if any interrupts are enabled*/ + + /* + * If any CPU interrupts are enabled in the SR of the previous thread, bitwise-OR in the + * disabled CPU interrupts from the global interrupt mask. + * This is an attempt at reverting the effect of masking the SR of the thread with the + * global interrupt mask. This is however broken, see comments for osSetIntMask. + */ la t0, __OSGlobalIntMask lw t0, 0(t0) xor t2, t0, ~0 /* not except not using not */ @@ -456,9 +468,14 @@ savecontext: or k1, k1, t1 savercp: + /* Save the currently masked RCP interrupts. */ lw t1, PHYS_TO_K1(MI_INTR_MASK_REG) beqz t1, endrcp + /* + * Similar to the above comment, but for RCP interrupt enable bits rather than CPU. + * This suffers from the same problem as above. + */ la t0, __OSGlobalIntMask lw t0, 0(t0) @@ -474,6 +491,7 @@ STAY2(mfc0 t0, C0_EPC) sw t0, THREAD_PC(k0) lw t0, THREAD_FP(k0) beqz t0, 1f + /* Save FP Registers if FPU was used by the thread */ STAY2(cfc1 t0, fcr31) NOP sw t0, THREAD_FPCSR(k0) @@ -494,6 +512,10 @@ STAY2(cfc1 t0, fcr31) sdc1 $f28, THREAD_FP28(k0) sdc1 $f30, THREAD_FP30(k0) 1: + /* + * Determine the cause of the exception or interrupt and + * enter appropriate handling routine + */ STAY2(mfc0 t0, C0_CAUSE) sw t0, THREAD_CAUSE(k0) @@ -518,21 +540,28 @@ no_rdb_mesg: #endif andi t1, t0, CAUSE_EXCMASK + /* Test for break exception */ li t2, EXC_BREAK beq t1, t2, handle_break - + + /* Test for CpU (coprocessor unusable) exception */ li t2, EXC_CPU beq t1, t2, handle_CpU - + + /* Test for interrupt, if it is not an interrupt, panic */ li t2, EXC_INT bne t1, t2, panic handle_interrupt: and s0, k1, t0 next_interrupt: + /* + * Handle external interrupt causes, using a jump table + * to enter into the appropriate handler + */ andi t1, s0, SR_IMASK srl t2, t1, 0xc bnez t2, 1f - + srl t2, t1, SR_IMASKSHIFT addi t2, t2, 16 1: @@ -542,272 +571,425 @@ next_interrupt: lw t2, __osIntTable(t2) jr t2 +/** + * IP6 Interrupt + * Only signalled by development hardware + */ IP6_Hdlr: + /* Mask out interrupt and continue */ and s0, s0, ~CAUSE_IP6 b next_interrupt - + +/** + * IP7 Interrupt + * Only signalled by development hardware + */ IP7_Hdlr: + /* Mask out interrupt and continue */ and s0, s0, ~CAUSE_IP7 b next_interrupt +/** + * IP8/Counter Interrupt + * Once the cop0 count register reaches the value of the + * cop0 compare register, this interrupt is triggered + */ counter: STAY2(mfc0 t1, C0_COMPARE) STAY2(mtc0 t1, C0_COMPARE) li a0, MESG(OS_EVENT_COUNTER) + /* Post counter message */ jal send_mesg + /* Mask out interrupt and continue */ and s0, s0, ~CAUSE_IP8 b next_interrupt +/** + * IP4/Cartridge Interrupt + * Signalled by the N64 Disk Drive + */ cart: #if BUILD_VERSION >= VERSION_J + /* Mask out interrupt */ and s0, s0, ~CAUSE_IP4 + /* Load cart callback set by __osSetHWIntrRoutine */ la t1, __osHwIntTable add t1, HWINTR_SIZE lw t2, HWINTR_CALLBACK(t1) + /* If the callback is NULL, handling is done */ beqz t2, 1f + /* Set up a stack and run the callback */ lw sp, HWINTR_SP(t1) jalr t2 - + beqz v0, 1f + /* Redispatch immediately if the callback returned nonzero */ b redispatch - + 1: + /* Post a cart event message */ li a0, MESG(OS_EVENT_CART) jal send_mesg + /* Continue */ b next_interrupt #else li a0, MESG(OS_EVENT_CART) + /* Mask out interrupt */ and s0, s0, ~CAUSE_IP4 - la sp, leoDiskStack + la sp, leoDiskStack addiu sp, 0x1000 - 0x10 # Stack size minus initial frame + /* Load cart callback set by __osSetHWIntrRoutine */ li t2, HWINTR_SIZE lw t2, __osHwIntTable(t2) + /* If the callback is NULL, handling is done */ beqz t2, 1f - + + /* Set up a stack and run the callback */ jalr t2 li a0, MESG(OS_EVENT_CART) - + beqz v0, 1f + /* Redispatch immediately if the callback returned nonzero */ b redispatch - + 1: + /* Post a cart event message */ jal send_mesg + /* Continue */ b next_interrupt #endif +/** + * IP3/RCP Interrupt + * Signalled by the RCP for various reasons, described below + */ rcp: + /* + * Load the MI interrupts and mask with the RCP bits in the global interrupt mask + * + * @bug this clobbers the t0 register which is expected to hold the value of the + * C0_CAUSE register in the sw1 and sw2 handlers. If the sw1 or sw2 handler runs + * after this, the interrupt will not be cleared properly. + */ lw s1, PHYS_TO_K1(MI_INTR_REG) la t0, __OSGlobalIntMask lw t0, (t0) srl t0, t0, 0x10 and s1, s1, t0 + +/** + * Signal Processor (SP) Interrupt + */ + /* Test for sp interrupt */ andi t1, s1, MI_INTR_SP beqz t1, vi - andi s1, s1, 0x3e + /* Test for yielded or done signals in particular */ + + /* Mask out SP interrupt */ + andi s1, s1, (MI_INTR_SI | MI_INTR_AI | MI_INTR_VI | MI_INTR_PI | MI_INTR_DP) lw ta0, PHYS_TO_K1(SP_STATUS_REG) li t1, (SP_CLR_INTR | SP_CLR_SIG3) + /* Clear interrupt and signal 3 */ sw t1, PHYS_TO_K1(SP_STATUS_REG) - andi ta0, ta0, 0x300 + andi ta0, ta0, (SP_STATUS_YIELDED | SP_STATUS_TASKDONE) beqz ta0, sp_other_break + /* Post an SP event message */ li a0, MESG(OS_EVENT_SP) jal send_mesg beqz s1, NoMoreRcpInts + /* Step over sp_other_break handler */ b vi sp_other_break: + /* + * An sp signal that is not due to yielding or task completion, such as + * an sp breakpoint. Post a different event message + */ li a0, MESG(OS_EVENT_SP_BREAK) jal send_mesg beqz s1, NoMoreRcpInts - + +/** + * Video Interface (VI) Interrupt + */ vi: - andi t1, s1, 0x8 + /* Test for vi interrupt */ + andi t1, s1, MI_INTR_VI beqz t1, ai - - andi s1, s1, 0x37 - + + /* Mask out vi interrupt */ + andi s1, s1, (MI_INTR_SP | MI_INTR_SI | MI_INTR_AI | MI_INTR_PI | MI_INTR_DP) + + /* Clear interrupt */ sw zero, PHYS_TO_K1(VI_CURRENT_REG) + + /* Post vi event message */ li a0, MESG(OS_EVENT_VI) jal send_mesg beqz s1, NoMoreRcpInts - + +/** + * Audio Interface (AI) Interrupt + */ ai: - andi t1, s1, 0x4 + /* Test for ai interrupt */ + andi t1, s1, MI_INTR_AI beqz t1, si - andi s1, s1, 0x3b - + /* Mask out ai interrupt */ + andi s1, s1, (MI_INTR_SP | MI_INTR_SI | MI_INTR_VI | MI_INTR_PI | MI_INTR_DP) + li t1, 1 + /* Clear interrupt */ sw t1, PHYS_TO_K1(AI_STATUS_REG) + /* Post ai event message */ li a0, MESG(OS_EVENT_AI) jal send_mesg beqz s1, NoMoreRcpInts - + +/** + * Serial Interface (SI) Interrupt + */ si: - andi t1, s1, 0x2 + /* Test for si interrupt */ + andi t1, s1, MI_INTR_SI beqz t1, pi - - andi s1, s1, 0x3d - /* any write clears interrupts */ - sw zero, PHYS_TO_K1(SI_STATUS_REG) + + /* Mask out si interrupt */ + andi s1, s1, (MI_INTR_SP | MI_INTR_AI | MI_INTR_VI | MI_INTR_PI | MI_INTR_DP) + /* Clear interrupt */ + sw zero, PHYS_TO_K1(SI_STATUS_REG) + + /* Post si event message */ li a0, MESG(OS_EVENT_SI) jal send_mesg beqz s1, NoMoreRcpInts - + +/** + * Parallel Interface (PI) Interrupt + */ pi: - andi t1, s1, 0x10 + /* Test for pi interrupt */ + andi t1, s1, MI_INTR_PI beqz t1, dp - andi s1, s1, 0x2f - + /* Mask out pi interrupt */ + andi s1, s1, (MI_INTR_SP | MI_INTR_SI | MI_INTR_AI | MI_INTR_VI | MI_INTR_DP) + + /* Clear interrupt */ li t1, PI_STATUS_CLR_INTR sw t1, PHYS_TO_K1(PI_STATUS_REG) #if BUILD_VERSION >= VERSION_J + /* Load pi callback */ la t1, __osPiIntTable lw t2, (t1) + /* Skip callback if NULL */ beqz t2, 1f + /* Set up a stack and run the callback */ lw sp, 4(t1) move a0, v0 jalr t2 + /* If the callback returns non-zero, do not post a pi event message */ bnez v0, 2f 1: #endif + /* Post pi event message */ li a0, MESG(OS_EVENT_PI) jal send_mesg #if BUILD_VERSION >= VERSION_J 2: #endif beqz s1, NoMoreRcpInts - + +/** + * Display Processor (DP) Interrupt + */ dp: - andi t1, s1, 0x20 + /* Test for dp interrupt */ + andi t1, s1, MI_INTR_DP beqz t1, NoMoreRcpInts - andi s1, s1, 0x1f + /* Mask out dp interrupt */ + andi s1, s1, (MI_INTR_SP | MI_INTR_SI | MI_INTR_AI | MI_INTR_VI | MI_INTR_PI) + /* Clear dp interrupt */ li t1, MI_CLR_DP_INTR sw t1, PHYS_TO_K1(MI_INIT_MODE_REG) - + + /* Post dp event message */ li a0, MESG(OS_EVENT_DP) jal send_mesg NoMoreRcpInts: + /* Mask out interrupt and continue */ and s0, s0, ~CAUSE_IP3 b next_interrupt +/** + * IP5/PreNMI Interrupt + * Reset button has been pressed + */ prenmi: + /* Disable IP5/PreNMI interrupt for the previously running thread */ lw k1, THREAD_SR(k0) and k1, k1, ~CAUSE_IP5 sw k1, THREAD_SR(k0) + /* Test __osShutdown for first PreNMI event */ la t1, __osShutdown lw t2, 0(t1) beqz t2, firstnmi - + + /* Mask out interrupt and redispatch immediately */ and s0, s0, ~CAUSE_IP5 b redispatch firstnmi: + /* Set __osShutdown */ li t2, 1 - sw t2, 0(t1) /* __osShutdown */ + sw t2, (t1) + /* Post a PreNMI event message */ li a0, MESG(OS_EVENT_PRENMI) jal send_mesg + /* Mask out and disable IP5/PreNMI interrupt for the highest priority thread */ and s0, s0, ~CAUSE_IP5 lw t2, __osRunQueue lw k1, THREAD_SR(t2) and k1, k1, ~CAUSE_IP5 sw k1, THREAD_SR(t2) + /* Redispatch immediately */ b redispatch sw2: + /* Mask out interrupt */ and t0, t0, ~CAUSE_SW2 STAY2(mtc0 t0, C0_CAUSE) + /* Post sw2 event message */ li a0, MESG(OS_EVENT_SW2) jal send_mesg + /* Mask out interrupt and continue */ and s0, s0, ~CAUSE_SW2 b next_interrupt sw1: + /* Mask out interrupt */ and t0, t0, ~CAUSE_SW1 STAY2(mtc0 t0, C0_CAUSE) + /* Post sw1 event message */ li a0, MESG(OS_EVENT_SW1) jal send_mesg + /* Mask out interrupt and continue */ and s0, s0, ~CAUSE_SW1 b next_interrupt handle_break: + /* Set last thread as having hit a break exception */ li t1, OS_FLAG_CPU_BREAK sh t1, THREAD_FLAGS(k0) + /* Post a cpu break event message */ li a0, MESG(OS_EVENT_CPU_BREAK) jal send_mesg + + /* Redispatch */ b redispatch - + redispatch: + /* Get priority of previously running thread */ lw t1, THREAD_PRI(k0) lw t2, __osRunQueue + /* Get highest priority from waiting threads */ lw t3, THREAD_PRI(t2) - + bge t1, t3, enqueueRunning - + + /* + * The previously running thread is no longer the highest priority, + * enqueue it to the run queue to wait its turn again + */ move a1, k0 la a0, __osRunQueue - + jal __osEnqueueThread - + j __osDispatchThread - + +/** + * Resume the previously running thread by placing it at the top of + * the run queue and dispatching it + */ enqueueRunning: la t1, __osRunQueue lw t2, MQ_MTQUEUE(t1) sw t2, THREAD_NEXT(k0) sw k0, MQ_MTQUEUE(t1) j __osDispatchThread + +/** + * Unhandled exceptions & interrupts end up here, + * trap to software by posting a fault message + */ panic: + /* Mark the thread as having faulted */ sw k0, __osFaultedThread li t1, OS_STATE_STOPPED sh t1, THREAD_STATE(k0) li t1, OS_FLAG_FAULT sh t1, THREAD_FLAGS(k0) + /* Save C0_BADVADDR */ STAY2(mfc0 t2, C0_BADVADDR) sw t2, THREAD_BADVADDR(k0) + /* Post the fault message */ li a0, MESG(OS_EVENT_FAULT) jal send_mesg + + /* Dispatch next thread */ j __osDispatchThread END(__osException) - + +/** + * Handles posting event messages to the listening message queue, if there is one + */ LEAF(send_mesg) + /* Save return address */ move s2, ra + + /* Load pointer to listening message queue */ la t2, __osEventStateTab addu t2, t2, a0 lw t1, OS_EVENTSTATE_MESSAGE_QUEUE(t2) + + /* If there is no listening message queue, done */ beqz t1, send_done - + + /* Test if the message queue is full, if so do not post the message */ lw t3, MQ_VALIDCOUNT(t1) lw ta0, MQ_MSGCOUNT(t1) - + bge t3, ta0, send_done + /* Add validcount to first and modulo with msgcount */ lw ta1, MQ_FIRST(t1) addu ta1, ta1, t3 @@ -815,19 +997,27 @@ LEAF(send_mesg) lw ta0, MQ_MSG(t1) mul ta1, ta1, 4 addu ta0, ta0, ta1 + + /* Fetch the message to post */ lw ta1, OS_EVENTSTATE_MESSAGE(t2) - sw ta1, 0(ta0) /* msg[ta1] = */ + /* Post the message to the message queue */ + sw ta1, 0(ta0) + /* Increment the validCount */ addiu t2, t3, 1 sw t2, MQ_VALIDCOUNT(t1) + /* + * If there was a thread blocked on this message queue, + * wake it up + */ lw t2, MQ_MTQUEUE(t1) lw t3, THREAD_NEXT(t2) beqz t3, send_done - + move a0, t1 jal __osPopThread move t2, v0 - + move a1, t2 la a0, __osRunQueue jal __osEnqueueThread @@ -835,13 +1025,17 @@ send_done: jr s2 END(send_mesg) -LEAF(handle_CpU) /* coprocessor error */ +/** + * Handle coprocessor unusable exception + */ +LEAF(handle_CpU) and t1, t0, CAUSE_CEMASK srl t1, t1, CAUSE_CESHIFT - li t2, 1 /* cp1 error */ + /* if not coprocessor 1, panic */ + li t2, 1 bne t1, t2, panic - /* enable cp1 (fpu) for this thread */ + /* Mark cop1 as usable for previous thread */ li t1, 1 sw t1, THREAD_FP(k0) lw k1, THREAD_SR(k0) @@ -850,14 +1044,25 @@ LEAF(handle_CpU) /* coprocessor error */ b enqueueRunning END(handle_CpU) +/** + * void __osEnqueueAndYield(OSThread** threadQueue); + * + * Voluntary thread yielding. + * Enqueues the currently running thread to the top of the + * thread queue `threadQueue` and yields to the highest priority + * unblocked runnable thread. + */ LEAF(__osEnqueueAndYield) lw a1, __osRunningThread #if !defined(_FINALROM) && BUILD_VERSION >= VERSION_K sw a1, __osPreviousThread #endif + /* Save SR */ STAY2(mfc0 t0, C0_SR) ori t0, t0, SR_EXL sw t0, THREAD_SR(a1) + + /* Save callee-saved registers */ sd s0, THREAD_GP16(a1) sd s1, THREAD_GP17(a1) sd s2, THREAD_GP18(a1) @@ -871,6 +1076,8 @@ STAY2(mfc0 t0, C0_SR) sd s8, THREAD_GP30(a1) sd ra, THREAD_GP31(a1) sw ra, THREAD_PC(a1) + + /* Save FPU callee-saved registers if the current thread has used the FPU */ lw k1, THREAD_FP(a1) beqz k1, 1f cfc1 k1, fcr31 @@ -886,6 +1093,10 @@ STAY2(mfc0 t0, C0_SR) andi t1, k1, SR_IMASK beqz t1, 2f + /* + * This code does the same thing as the block just above the `savercp` label. + * See the comment there for more about this. + */ la t0, __OSGlobalIntMask lw t0, 0(t0) xor t0, t0, ~0 @@ -898,36 +1109,57 @@ STAY2(mfc0 t0, C0_SR) lw k1, PHYS_TO_K1(MI_INTR_MASK_REG) beqz k1, 3f + /* + * This code does the same thing as the block just below the `savercp` label. + * See the comment there for more about this. + */ la k0, __OSGlobalIntMask lw k0, 0(k0) - srl k0, k0, 0x10 + srl k0, k0, RCP_IMASKSHIFT xor k0, k0, ~0 - andi k0, k0, 0x3f + andi k0, k0, (RCP_IMASK >> RCP_IMASKSHIFT) lw t0, THREAD_RCP(a1) and k0, k0, t0 or k1, k1, k0 3: + /* + * If the specified thread queue is null, skip + * straight to dispatching + */ sw k1, THREAD_RCP(a1) beqz a0, noEnqueue jal __osEnqueueThread noEnqueue: j __osDispatchThread END(__osEnqueueAndYield) - -/*__osEnqueueThread(OSThread **, OSThread *)*/ + +/** + * void __osEnqueueThread(OSThread** threadQueue, OSThread* thread); + * + * Enqueues `thread` to the thread queue `threadQueue`, inserted by priority + */ LEAF(__osEnqueueThread) move t9, a0 lw t8, 0(a0) lw ta3, THREAD_PRI(a1) lw ta2, THREAD_PRI(t8) + /* + * If the current highest priority thread is a lower priority than + * the new thread, skip searching the queue + */ blt ta2, ta3, 2f 1: + /* + * Search the queue for the position to insert the thread to maintain + * ordering by priority + */ move t9, t8 lw t8, THREAD_NEXT(t8) lw ta2, THREAD_PRI(t8) bge ta2, ta3, 1b 2: + /* Insert the thread into the queue */ lw t8, THREAD_NEXT(t9) sw t8, THREAD_NEXT(a1) sw a1, THREAD_NEXT(t9) @@ -935,23 +1167,42 @@ LEAF(__osEnqueueThread) jr ra END(__osEnqueueThread) +/** + * OSThread* __osPopThread(OSThread** threadQueue); + * + * Pops the highest priority thread from the top of the + * thread queue `threadQueue` and returns it + */ LEAF(__osPopThread) lw v0, 0(a0) /* a0 is OSThread** */ lw t9, THREAD_NEXT(v0) sw t9, 0(a0) jr ra END(__osPopThread) + #if BUILD_VERSION >= VERSION_K LEAF(__osNop) jr ra END(__osNop) #endif + +/** + * void __osDispatchThread(void); + * + * Dispatches the next thread to run after restoring the context + */ LEAF(__osDispatchThread) + /* Obtain highest priority thread from the active run queue */ la a0, __osRunQueue jal __osPopThread + /* Set thread as running */ sw v0, __osRunningThread li t0, OS_STATE_RUNNING sh t0, THREAD_STATE(v0) + /* + * Restore SR, masking out any interrupts that are not also + * enabled in the global interrupt mask + */ move k0, v0 #if !defined(_FINALROM) && BUILD_VERSION >= VERSION_K @@ -964,7 +1215,7 @@ LEAF(__osDispatchThread) jalr t0 #endif -/* There's another 1: label somewhere around here in version J and below */ +/* There is another 1: label somewhere around here in version J and below */ #if BUILD_VERSION < VERSION_K 1: #endif @@ -979,6 +1230,7 @@ __osDispatchThreadSave: and k1, k1, ~SR_IMASK or k1, k1, t1 STAY2(mtc0 k1, C0_SR) +/* Restore GPRs */ .set noat ld $1, THREAD_GP1(k0) .set at @@ -1014,8 +1266,11 @@ STAY2(mtc0 k1, C0_SR) mtlo k1 ld k1, THREAD_HI(k0) mthi k1 + /* Move thread pc to EPC so that eret will return execution to where the thread left off */ lw k1, THREAD_PC(k0) STAY2(mtc0 k1, C0_EPC) + + /* Check if the FPU was used by this thread and if so also restore the FPU registers */ lw k1, THREAD_FP(k0) beqz k1, 1f @@ -1037,8 +1292,12 @@ STAY2(ctc1 k1, fcr31) ldc1 $f26, THREAD_FP26(k0) ldc1 $f28, THREAD_FP28(k0) ldc1 $f30, THREAD_FP30(k0) - + 1: + /* + * Restore RCP interrupt mask, masking out any RCP interrupts that + * are not also enabled in the global interrupt mask + */ .set noreorder lw k1, THREAD_RCP(k0) la k0, __OSGlobalIntMask @@ -1052,18 +1311,29 @@ STAY2(ctc1 k1, fcr31) la k0, PHYS_TO_K1(MI_INTR_MASK_REG) sw k1, 0(k0) + /* Empty pipeline */ nop nop nop nop + + /* Resume thread execution */ eret .set reorder END(__osDispatchThread) +/** + * void __osCleanupThread(void); + * + * When a thread entrypoint function returns, it returns to this function. + * This function is responsible for cleaning up the thread, signalling for the + * current thread to be destroyed. + */ LEAF(__osCleanupThread) move a0, zero #if !defined(BBPLAYER) && !defined(__sgi) nop #endif + /* Despite being a jal, this function does not return as the thread will have been destroyed */ jal osDestroyThread END(__osCleanupThread) diff --git a/src/os/exit.c b/src/os/exit.c index 24a873f..05582c5 100644 --- a/src/os/exit.c +++ b/src/os/exit.c @@ -1,6 +1,6 @@ #include "PR/os_internal.h" -void osExit() { +void osExit(void) { __osGIOInterrupt(16); for (;;) { diff --git a/src/os/getcurrfaultthread.c b/src/os/getcurrfaultthread.c index 800d414..f8bea0e 100644 --- a/src/os/getcurrfaultthread.c +++ b/src/os/getcurrfaultthread.c @@ -1,6 +1,6 @@ #include "PR/os_internal.h" #include "PRinternal/osint.h" -OSThread* __osGetCurrFaultedThread() { +OSThread* __osGetCurrFaultedThread(void) { return __osFaultedThread; } diff --git a/src/os/gettime.c b/src/os/gettime.c index 8b59ebd..38839ba 100644 --- a/src/os/gettime.c +++ b/src/os/gettime.c @@ -3,7 +3,7 @@ #include "PRinternal/osint.h" #include "PRinternal/viint.h" -OSTime osGetTime() { +OSTime osGetTime(void) { u32 tmptime; u32 elapseCount; OSTime currentCount; diff --git a/src/os/initialize.c b/src/os/initialize.c index 799096a..5e7991b 100644 --- a/src/os/initialize.c +++ b/src/os/initialize.c @@ -184,17 +184,17 @@ void INITIALIZE_FUNC() { } #if !defined(_FINALROM) && BUILD_VERSION < VERSION_J -void ptstart() { +void ptstart(void) { } #elif !defined(_FINALROM) && BUILD_VERSION < VERSION_K -static void ptstart() { +static void ptstart(void) { } #endif #if BUILD_VERSION >= VERSION_K -void __osInitialize_autodetect() { +void __osInitialize_autodetect(void) { #ifndef _FINALROM if (__checkHardware_msp()) { __osInitialize_msp(); diff --git a/src/os/interrupt.s b/src/os/interrupt.s index 01efe1a..02c885f 100644 --- a/src/os/interrupt.s +++ b/src/os/interrupt.s @@ -2,31 +2,32 @@ #include "sys/asm.h" #include "sys/regdef.h" #include "PR/os_version.h" +#include "threadasm.h" .text .set noreorder LEAF(__osDisableInt) #if BUILD_VERSION >= VERSION_J - la t2, __OSGlobalIntMask - lw t3, (t2) - andi t3, 0xFF00 + la t2, __OSGlobalIntMask + lw t3, (t2) + andi t3, SR_IMASK mfc0 t0, C0_SR and t1, t0, ~SR_IE mtc0 t1, C0_SR andi v0, t0, SR_IE lw t0, (t2) - andi t0, 0xFF00 + andi t0, SR_IMASK beq t0, t3, No_Change_Global_Int la t2, __osRunningThread # this is intentionally a macro in the branch delay slot - lw t1, 280(t2) - andi t2, t1, 0xFF00 + lw t1, THREAD_SR(t2) + andi t2, t1, SR_IMASK and t2, t0 - and t1, 0xFFFF00FF + and t1, ~SR_IMASK or t1, t2 - and t1, -2 - mtc0 t1, $12 - nop - nop + and t1, ~SR_IE + mtc0 t1, C0_SR + nop + nop No_Change_Global_Int: jr ra nop @@ -40,7 +41,7 @@ No_Change_Global_Int: nop #endif END(__osDisableInt) - + LEAF(__osRestoreInt) mfc0 t0, C0_SR or t0, t0, a0 diff --git a/src/os/invaldcache.s b/src/os/invaldcache.s index ea6a657..5117010 100644 --- a/src/os/invaldcache.s +++ b/src/os/invaldcache.s @@ -3,37 +3,69 @@ #include "sys/regdef.h" .text +/** + * void osInvalDCache(void* vaddr, s32 nbytes); + * + * Invalidates the CPU Data Cache for `nbytes` at `vaddr`. + * The cache is not automatically synced with physical memory, so cache + * lines must be invalidated to ensure old data is not used in place of + * newly available data supplied by an external agent in a DMA operation. + * + * If `vaddr` is not aligned to a cache line boundary, or nbytes is not a + * multiple of the data cache line size (16 bytes) a larger region is + * invalidated. + * + * If the amount to invalidate is at least the data cache size (DCACHE_SIZE), + * the entire data cache is invalidated. + */ LEAF(osInvalDCache) + /* If the amount to invalidate is less than or equal to 0, return immediately */ blez a1, 3f + /* + * If the amount to invalidate is as large as or larger than + * the data cache size, invalidate all + */ li t3, DCACHE_SIZE bgeu a1, t3, 4f - + /* + * Ensure end address does not wrap around and end up smaller + * than the start address + */ move t0, a0 addu t1, a0, a1 bgeu t0, t1, 3f - + /* Mask start with cache line */ addiu t1, t1, -DCACHE_LINESIZE andi t2, t0, DCACHE_LINEMASK + /* If mask is not zero, the start is not cache aligned */ beqz t2, 1f - + /* Subtract mask result to align to cache line */ subu t0, t0, t2 + /* Hit-Writeback-Invalidate unaligned part */ CACHE((C_HWBINV|CACH_PD), (t0)) + /* If that is all there is to do, return early */ bgeu t0, t1, 3f addiu t0, t0, DCACHE_LINESIZE 1: + /* Mask end with cache line */ andi t2, t1, DCACHE_LINEMASK + /* If mask is not zero, the end is not cache aligned */ beqz t2, 2f + /* Subtract mask result to align to cache line */ subu t1, t1, t2 - CACHE((C_HWBINV|CACH_PD), 0x10(t1)) + + /* Hit-Writeback-Invalidate unaligned part */ + CACHE((C_HWBINV|CACH_PD), DCACHE_LINESIZE(t1)) bltu t1, t0, 3f 2: + /* Hit-Invalidate */ CACHE((C_HINV|CACH_PD), (t0)) .set noreorder bltu t0, t1, 2b @@ -43,10 +75,11 @@ LEAF(osInvalDCache) jr ra 4: - li t0, KUSIZE + li t0, K0BASE addu t1, t0, t3 addiu t1, t1, -DCACHE_LINESIZE 5: + /* Index-Writeback-Invalidate */ CACHE((C_IINV|CACH_PD), (t0)) .set noreorder bltu t0, t1, 5b diff --git a/src/os/invalicache.s b/src/os/invalicache.s index f5ceb58..29c4907 100644 --- a/src/os/invalicache.s +++ b/src/os/invalicache.s @@ -4,38 +4,48 @@ .text LEAF(osInvalICache) - blez a1, 2f + /* If the amount to invalidate is less than or equal to 0, return immediately */ + blez a1, 2f - li t3, ICACHE_SIZE - bgeu a1, t3, 3f + /* + * If the amount to invalidate is as large as or larger than + * the instruction cache size, invalidate all + */ + li t3, ICACHE_SIZE + bgeu a1, t3, 3f - move t0, a0 - addu t1, a0, a1 - bgeu t0, t1, 2f + /* + * ensure end address does not wrap around and end up smaller + * than the start address + */ + move t0, a0 + addu t1, a0, a1 + bgeu t0, t1, 2f - addiu t1, t1, -ICACHE_LINESIZE - andi t2, t0, ICACHE_LINEMASK - subu t0, t0, t2 + /* Mask and subtract to align to cache line */ + addiu t1, t1, -ICACHE_LINESIZE + andi t2, t0, ICACHE_LINEMASK + subu t0, t0, t2 1: - CACHE((C_HINV|CACH_PI), (t0)) + CACHE((C_HINV|CACH_PI), (t0)) .set noreorder - bltu t0, t1, 1b - addiu t0, t0, ICACHE_LINESIZE + bltu t0, t1, 1b + addiu t0, t0, ICACHE_LINESIZE .set reorder 2: - jr ra + jr ra 3: - li t0, KUSIZE - addu t1, t0, t3 - addiu t1, t1, -ICACHE_LINESIZE + li t0, K0BASE + addu t1, t0, t3 + addiu t1, t1, -ICACHE_LINESIZE 4: - CACHE((C_IINV|CACH_PI), (t0)) + CACHE((C_IINV|CACH_PI), (t0)) .set noreorder - bltu t0, t1, 4b - addiu t0, t0, ICACHE_LINESIZE + bltu t0, t1, 4b + addiu t0, t0, ICACHE_LINESIZE .set reorder - jr ra + jr ra END(osInvalICache) diff --git a/src/os/maptlbrdb.s b/src/os/maptlbrdb.s index c004362..b7db6c3 100644 --- a/src/os/maptlbrdb.s +++ b/src/os/maptlbrdb.s @@ -1,4 +1,5 @@ #include "PR/R4300.h" +#include "PR/rdb.h" #include "sys/asm.h" #include "sys/regdef.h" @@ -6,13 +7,13 @@ .set noreorder LEAF(osMapTLBRdb) mfc0 t0, C0_ENTRYHI - li t1, 31 + li t1, NTLBENTRIES mtc0 t1, C0_INX mtc0 zero, C0_PAGEMASK /*4k*/ li t2, TLBLO_UNCACHED | TLBLO_D | TLBLO_V | TLBLO_G li t1, K2BASE mtc0 t1, C0_ENTRYHI - li t1, KUSIZE + li t1, RDB_BASE_VIRTUAL_ADDR srl t3, t1,TLBLO_PFNSHIFT or t3, t3,t2 mtc0 t3, C0_ENTRYLO0 diff --git a/src/os/probetlb.s b/src/os/probetlb.s index 237db23..1f59afb 100644 --- a/src/os/probetlb.s +++ b/src/os/probetlb.s @@ -4,31 +4,54 @@ .text .set noreorder +/** + * u32 __osProbeTLB(void* vaddr); + * + * Searches the TLB for the physical address associated with + * the virtual address `vaddr`. + * + * Returns the physical address if found, or -1 if not found. + */ LEAF(__osProbeTLB) + /* Set C0_ENTRYHI based on supplied vaddr */ mfc0 t0, C0_ENTRYHI andi t1, t0, TLBHI_PIDMASK - and t2, a0, -8192 # This also works: (TLBHI_VPN2MASK << 32) >> 32 + and t2, a0, (TLBHI_VPN2MASK << 32) >> 32 or t1, t1, t2 mtc0 t1, C0_ENTRYHI nop nop nop + /* + * TLB probe, sets C0_INX to a value matching C0_ENTRYHI. + * If no match is found the TLBINX_PROBE bit is set to indicate this. + */ tlbp nop nop + /* Read result */ mfc0 t3, C0_INX and t3, t3, TLBINX_PROBE + /* Branch if no match was found */ bnez t3, 3f nop + /* + * Read TLB, sets C0_ENTRYHI, C0_ENTRYLO0, C0_ENTRYLO1 and C0_PAGEMASK for the TLB + * entry indicated by C0_INX + */ tlbr nop nop nop + /* Calculate page size = (page mask + 0x2000) >> 1 */ mfc0 t3, C0_PAGEMASK - addi t3, t3, DCACHE_SIZE + addi t3, t3, 0x2000 srl t3, t3, 0x1 + /* & with vaddr */ and ta0, t3, a0 + /* Select C0_ENTRYLO0 or C0_ENTRYLO1 */ bnez ta0, 1f + /* make bitmask out of page size */ addi t3, t3,-1 mfc0 v0, C0_ENTRYLO0 b 2f @@ -36,19 +59,27 @@ LEAF(__osProbeTLB) 1: mfc0 v0, C0_ENTRYLO1 2: + /* Check valid bit and branch if not valid */ andi ta1, v0,TLBLO_V beqz ta1, 3f nop + /* Extract the Page Frame Number from the entry */ and v0, v0, TLBLO_PFNMASK sll v0, v0, TLBLO_PFNSHIFT + /* Mask vaddr with page size mask */ and ta1, a0, t3 + /* Add masked vaddr to pfn to obtain the physical address */ add v0, v0, ta1 b 4f nop 3: + /* + * No physical address for the supplied virtual address was found, + * return -1 + */ li v0, -1 4: mtc0 t0, C0_ENTRYHI jr ra - nop + nop END(__osProbeTLB) diff --git a/src/os/setintmask.s b/src/os/setintmask.s index f19ed17..74e7bd2 100644 --- a/src/os/setintmask.s +++ b/src/os/setintmask.s @@ -10,40 +10,78 @@ .text .set noreorder -LEAF(osSetIntMask) +/** + * OSIntMask osSetIntMask(OSIntMask); + * + * Sets the interrupt enable mask for the current thread. External interrupts + * originating either in the CPU or the RCP may be "masked out" so that they + * are not handled. This is sometimes important for critical code sections + * that must not be interrupted. + * Interrupts that are not enabled in the global interrupt mask __OSGlobalIntMask + * cannot be set here. The global interrupt mask is OS-internal and is not + * expected to change during runtime. + * The returned value is the previous interrupt enable mask so that it can be + * restored later. + * + * @bug Some usage of the global interrupt mask is broken both in here and in the + * exception handler routines. + * While a thread is running, the C0_SR interrupt enable bits contain the + * interrupt enable bits for the current thread masked by the global + * interrupt mask. There is an attempt to recover only the original interrupt + * enable bits belonging to the thread itself using the operation + * (SR | ~__OSGlobalIntMask). + * However, this does not work as intended and can cause interrupts to end + * up enabled when not intended to be. The same issue is present for the + * RCP interrupt enable bits in MI_INTR_MASK_REG. + * This does not cause issues in practice as __OSGlobalIntMask is almost always + * OS_IM_ALL, so the operation is usually simply (SR | 0). + */ +LEAF(osSetIntMask) + /* Extract interrupt enable bits from current SR */ mfc0 ta0, C0_SR andi v0, ta0, OS_IM_CPU + /* Get value of __OSGlobalIntMask */ la t0, __OSGlobalIntMask lw t3, 0(t0) - - xor t0, t3,-1 + + /* Bitwise-OR in the disabled CPU bits of __OSGlobalIntMask */ + xor t0, t3, ~0 andi t0, t0,(SR_IMASK) or v0, v0,t0 + /* Fetch MI_INTR_MASK_REG */ lw t2, PHYS_TO_K1(MI_INTR_MASK_REG) + /* If there are RCP interrupts masked */ beqz t2, 1f srl t1, t3,0x10 - xor t1, t1,-1 - andi t1, t1, MI_INTR_MASK + /* Bitwise-OR in the disabled RCP bits of __OSGlobalIntMask */ + xor t1, t1, ~0 + andi t1, t1, (RCP_IMASK >> RCP_IMASKSHIFT) or t2, t2,t1 1: - sll t2, t2,0x10 + /* Shift the RCP bits to not conflict with the CPU bits */ + sll t2, t2, RCP_IMASKSHIFT + /* OR the CPU and RCP bits together */ or v0, v0,t2 - and t0, a0, MI_INTR_MASK<<0x10 + /* Extract RCP interrupt enable bits from requested mask and mask with __OSGlobalIntMask */ + and t0, a0, RCP_IMASK and t0, t0,t3 - srl t0, t0,0xf + /* Convert to a value for MI_INTR_MASK_REG and set it */ + srl t0, t0,(RCP_IMASKSHIFT - 1) lhu t2, __osRcpImTable(t0) sw t2, PHYS_TO_K1(MI_INTR_MASK_REG) - + + /* Extract CPU interrupt enable bits from requested mask and mask with __OSGlobalIntMask */ andi t0, a0, OS_IM_CPU andi t1, t3, SR_IMASK and t0, t0,t1 and ta0, ta0, ~SR_IMASK + /* Bitwise OR in the remaining bits of SR and set new SR */ or ta0, ta0,t0 mtc0 ta0, C0_SR diff --git a/src/os/thread.c b/src/os/thread.c index 89f10f2..5a15a61 100644 --- a/src/os/thread.c +++ b/src/os/thread.c @@ -4,8 +4,8 @@ struct __osThreadTail __osThreadTail = { NULL, -1 }; OSThread* __osRunQueue = (OSThread*)&__osThreadTail; OSThread* __osActiveQueue = (OSThread*)&__osThreadTail; -OSThread* __osRunningThread = { 0 }; -OSThread* __osFaultedThread = { 0 }; +OSThread* __osRunningThread = NULL; +OSThread* __osFaultedThread = NULL; void __osDequeueThread(register OSThread** queue, register OSThread* t) { register OSThread* pred; diff --git a/src/os/unmaptlb.s b/src/os/unmaptlb.s index 362fd1e..6c9f631 100644 --- a/src/os/unmaptlb.s +++ b/src/os/unmaptlb.s @@ -40,6 +40,6 @@ LEAF(osUnmapTLB) nop mtc0 t0, C0_ENTRYHI jr ra - nop + nop END(osUnmapTLB) diff --git a/src/os/unmaptlball.s b/src/os/unmaptlball.s index 6d4b264..2c4175a 100644 --- a/src/os/unmaptlball.s +++ b/src/os/unmaptlball.s @@ -7,7 +7,7 @@ LEAF(osUnmapTLBAll) mfc0 t0, C0_ENTRYHI li t1, NTLBENTRIES-1 /* last reserved for rdb */ - li t2, KUSIZE + li t2, (K0BASE & TLBHI_VPN2MASK) mtc0 t2, C0_ENTRYHI mtc0 zero, C0_ENTRYLO0 mtc0 zero, C0_ENTRYLO1 diff --git a/src/os/writebackdcache.s b/src/os/writebackdcache.s index 5f5b485..0d9678a 100644 --- a/src/os/writebackdcache.s +++ b/src/os/writebackdcache.s @@ -3,33 +3,52 @@ #include "sys/regdef.h" .text +/** + * void osWritebackDCache(void* vaddr, s32 nbytes); + * + * Writes back the contents of the data cache to main memory for `nbytes` at `vaddr`. + * If `nbytes` is as large as or larger than the data cache size, the entire cache is + * written back. + */ LEAF(osWritebackDCache) + /* If the amount to write back is less than or equal to 0, return immediately */ blez a1, 2f + /* + * If the amount to write back is as large as or larger than + * the data cache size, write back all + */ li t3, DCACHE_SIZE bgeu a1,t3, 3f + /* + * ensure end address does not wrap around and end up smaller + * than the start address + */ move t0, a0 addu t1, a0,a1 bgeu t0, t1, 2f + /* Mask and subtract to align to cache line */ addiu t1, t1, -DCACHE_LINESIZE andi t2, t0, DCACHE_LINEMASK subu t0, t0,t2 1: - .set noreorder + .set noreorder cache (C_HWB|CACH_PD), (t0) bltu t0, t1, 1b addiu t0, t0, DCACHE_LINESIZE - .set reorder + .set reorder 2: jr ra + +/* same as osWritebackDCacheAll in operation */ 3: - li t0, KUSIZE + li t0, K0BASE addu t1, t0,t3 addiu t1, t1, -DCACHE_LINESIZE 4: - .set noreorder + .set noreorder cache (C_IWBINV|CACH_PD), (t0) bltu t0, t1, 4b addiu t0, t0, DCACHE_LINESIZE - .set reorder + .set reorder jr ra END(osWritebackDCache) diff --git a/src/os/writebackdcacheall.s b/src/os/writebackdcacheall.s index ee8df88..044e1ca 100644 --- a/src/os/writebackdcacheall.s +++ b/src/os/writebackdcacheall.s @@ -4,7 +4,7 @@ .text LEAF(osWritebackDCacheAll) - li t0, KUSIZE + li t0, K0BASE li t2, DCACHE_SIZE addu t1, t0,t2 addiu t1, t1, -DCACHE_LINESIZE diff --git a/src/voice/voicecheckresult.c b/src/voice/voicecheckresult.c index 12ab5b6..625200e 100644 --- a/src/voice/voicecheckresult.c +++ b/src/voice/voicecheckresult.c @@ -1,3 +1,7 @@ +/** + * File: voicecheckresult.c + */ + #include "PR/os_internal.h" #include "PRinternal/controller.h" #include "PR/os_voice.h" diff --git a/src/voice/voicecheckword.c b/src/voice/voicecheckword.c index 4c0f820..9d2e3f8 100644 --- a/src/voice/voicecheckword.c +++ b/src/voice/voicecheckword.c @@ -1,3 +1,9 @@ +/** + * File: voicecheckwork.c + * + * Checks whether or not a word can be registered in the dictionary + */ + #include "PR/os_internal.h" #include "PRinternal/controller.h" #include "PR/os_voice.h" @@ -6,7 +12,7 @@ s32 osVoiceCheckWord(u8* word) { s32 k; s32 ret = 0; u16 sjis; - u16 old = 0; + u16 old = '\0'; for (k = 0; word[k] != 0; k += 2) { sjis = (word[k] << 8) + word[k + 1]; diff --git a/src/voice/voicecleardictionary.c b/src/voice/voicecleardictionary.c index eda733b..ed43c1d 100644 --- a/src/voice/voicecleardictionary.c +++ b/src/voice/voicecleardictionary.c @@ -1,3 +1,15 @@ +/** + * File: voicecleardictionary.c + * + * Initializes Voice Recognition System word registration dictionary. + * + * The dictionary is initialized so that the specified "numWords" can be + * registered in the dictionary. 1-255 words can be registered in the dictionary. + * + * Words cannot be registered with the osVoiceSetWord before the dictionary + * is initialized with the osVoiceClearDictionary function + */ + #include "PR/os_internal.h" #include "PRinternal/controller.h" #include "PR/os_voice.h" diff --git a/src/voice/voicecontread2.c b/src/voice/voicecontread2.c index f905641..95972f9 100644 --- a/src/voice/voicecontread2.c +++ b/src/voice/voicecontread2.c @@ -1,3 +1,7 @@ +/** + * File: voicecontread2.c + */ + #include "macros.h" #include "PR/os_internal.h" #include "PRinternal/controller.h" diff --git a/src/voice/voicecontread36.c b/src/voice/voicecontread36.c index c7a0033..edabcec 100644 --- a/src/voice/voicecontread36.c +++ b/src/voice/voicecontread36.c @@ -1,3 +1,7 @@ +/** + * File: voicecontread36.c + */ + #include "macros.h" #include "PR/os_internal.h" #include "PRinternal/controller.h" diff --git a/src/voice/voicecontrolgain.c b/src/voice/voicecontrolgain.c index f03c814..1770856 100644 --- a/src/voice/voicecontrolgain.c +++ b/src/voice/voicecontrolgain.c @@ -1,3 +1,9 @@ +/** + * File: voicecontrolgain.c + * + * Adjusts the input gain of the Voice Recognition System + */ + #include "macros.h" #include "PR/os_internal.h" #include "PRinternal/controller.h" diff --git a/src/voice/voicecontwrite20.c b/src/voice/voicecontwrite20.c index b8bb86d..e32c606 100644 --- a/src/voice/voicecontwrite20.c +++ b/src/voice/voicecontwrite20.c @@ -1,3 +1,7 @@ +/** + * File: voicecontwrite20.c + */ + #include "macros.h" #include "PR/os_internal.h" #include "PRinternal/controller.h" diff --git a/src/voice/voicecontwrite4.c b/src/voice/voicecontwrite4.c index b4ca043..10287da 100644 --- a/src/voice/voicecontwrite4.c +++ b/src/voice/voicecontwrite4.c @@ -1,3 +1,7 @@ +/** + * File: voicecontwrite4.c + */ + #include "macros.h" #include "PR/os_internal.h" #include "PRinternal/controller.h" diff --git a/src/voice/voicecountsyllables.c b/src/voice/voicecountsyllables.c index 3324248..dbe2847 100644 --- a/src/voice/voicecountsyllables.c +++ b/src/voice/voicecountsyllables.c @@ -1,10 +1,14 @@ +/** + * File: voicecountsyllables.c + */ + #include "PR/os_internal.h" #include "PRinternal/controller.h" #include "PR/os_voice.h" // The VRU can store only 880 semisyllables of words in its dictionary. // Use this function to determine the semisyllable count before adding a word with osVoiceSetWord, -// to properly see whether it will fit. +// to properly see whether it will fit. void osVoiceCountSyllables(u8* data, u32* syllable) { s32 k; diff --git a/src/voice/voicecrc.c b/src/voice/voicecrc.c index ba2dab0..308862e 100644 --- a/src/voice/voicecrc.c +++ b/src/voice/voicecrc.c @@ -1,3 +1,9 @@ +/** + * File: voicecrc.c + * Description: CRC check used by the voice files + * + * For general information about CRC, see the crc.c file + */ #include "PR/os_internal.h" #include "PRinternal/controller.h" #include "PR/os_voice.h" @@ -5,6 +11,10 @@ #define VOICE_CRC_LENGTH 8 #define VOICE_CRC_GENERATOR 0x85 +/** + * This function is essentially the same as __osContDataCrc, but allows for a variable message length, specified by + * `numBytes`. + */ u8 __osVoiceContDataCrc(u8* data, u32 length) { s32 temp = 0; u32 i; diff --git a/src/voice/voicegetreaddata.c b/src/voice/voicegetreaddata.c index ccd099a..c4f8f1b 100644 --- a/src/voice/voicegetreaddata.c +++ b/src/voice/voicegetreaddata.c @@ -1,3 +1,9 @@ +/** + * File: voicegetreaddata.c + * + * Gets voice recognition result from the Voice Recognition System + */ + #include "PR/os_internal.h" #include "PRinternal/controller.h" #include "PR/os_voice.h" diff --git a/src/voice/voicegetstatus.c b/src/voice/voicegetstatus.c index 85e6455..bafa4dd 100644 --- a/src/voice/voicegetstatus.c +++ b/src/voice/voicegetstatus.c @@ -1,3 +1,7 @@ +/** + * File: voicegetstatus.c + */ + #include "PR/os_internal.h" #include "PRinternal/controller.h" #include "PR/os_voice.h" diff --git a/src/voice/voiceinit.c b/src/voice/voiceinit.c index 0ba8b63..a9d8d76 100644 --- a/src/voice/voiceinit.c +++ b/src/voice/voiceinit.c @@ -1,3 +1,9 @@ +/** + * File: voiceinit.c + * + * Initializes Voice Recognition System control structure and hardware + */ + #include "macros.h" #include "PR/os_internal.h" #include "PRinternal/controller.h" diff --git a/src/voice/voicemaskdictionary.c b/src/voice/voicemaskdictionary.c index 166ba2e..2e85dad 100644 --- a/src/voice/voicemaskdictionary.c +++ b/src/voice/voicemaskdictionary.c @@ -1,3 +1,9 @@ +/** + * File: voicemaskdictionary.c + * + * Mask words registered in the voice recognition system + */ + #include "macros.h" #include "PR/os_internal.h" #include "PRinternal/controller.h" diff --git a/src/voice/voicesetadconverter.c b/src/voice/voicesetadconverter.c index c44ecc6..f3f8591 100644 --- a/src/voice/voicesetadconverter.c +++ b/src/voice/voicesetadconverter.c @@ -1,3 +1,7 @@ +/** + * File: voicesetadconverter.c + */ + #include "PR/os_internal.h" #include "PRinternal/controller.h" #include "PR/os_voice.h" diff --git a/src/voice/voicesetword.c b/src/voice/voicesetword.c index 6426ddb..7569047 100644 --- a/src/voice/voicesetword.c +++ b/src/voice/voicesetword.c @@ -1,3 +1,9 @@ +/** + * File: voicesetword.c + * + * Registers words to the Voice Recognition System dictionary + */ + #include "macros.h" #include "PR/os_internal.h" #include "PRinternal/controller.h" diff --git a/src/voice/voicestartreaddata.c b/src/voice/voicestartreaddata.c index 629b956..4381e5b 100644 --- a/src/voice/voicestartreaddata.c +++ b/src/voice/voicestartreaddata.c @@ -1,3 +1,9 @@ +/** + * File: voicestartreaddata.c + * + * Start voice recognition by the Voice Recognition System + */ + #include "PR/os_internal.h" #include "PRinternal/controller.h" #include "PR/os_voice.h" diff --git a/src/voice/voicestopreaddata.c b/src/voice/voicestopreaddata.c index fb96895..b28143f 100644 --- a/src/voice/voicestopreaddata.c +++ b/src/voice/voicestopreaddata.c @@ -1,3 +1,9 @@ +/** + * File: voicestopreaddata.c + * + * Forcibly stops voice recognition processing by the Voice Recognition System + */ + #include "PR/os_internal.h" #include "PRinternal/controller.h" #include "PR/os_voice.h"