diff options
| author | Tharo <17233964+Thar0@users.noreply.github.com> | 2022-06-03 21:33:18 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-06-03 16:33:18 -0400 |
| commit | 4775fd4a7ea8077f603900def093124f8aa7cec6 (patch) | |
| tree | 23d5e36dbe6283a58760136602706bdf68893e1b /src | |
| parent | e989cb7ace48435ef1de1ea10f8e81c61a8a46e2 (diff) | |
Rename and move handwritten asm files (#1254)
* Rename handwritten asm files and move them to src
* Fix progress.py
* Remove handling for asm dir from Makefile
Diffstat (limited to 'src')
36 files changed, 2903 insertions, 0 deletions
diff --git a/src/boot/mio0.s b/src/boot/mio0.s new file mode 100644 index 000000000..a3fb8eba2 --- /dev/null +++ b/src/boot/mio0.s @@ -0,0 +1,64 @@ +#include "ultra64/asm.h" + +.set noreorder + +.section .text + +.balign 16 + +/** + * void Mio0_Decompress(void* src, void* dst); + * + * Decompress Mio0 chunk + */ +LEAF(Mio0_Decompress) + lw $a3, 8($a0) // compressed offset + lw $t9, 0xC($a0) // uncompressed offset + lw $t8, 4($a0) // decompressed length + add $a3, $a3, $a0 // compressed start + add $t9, $t9, $a0 // uncompressed start + move $a2, $zero // 0 + addi $a0, $a0, 0x10 // move past header + add $t8, $t8, $a1 // dst + decompressed length = end +mainloop: + bnez $a2, 1f + nop + lw $t0, ($a0) + li $a2, 32 + addi $a0, $a0, 4 +1: + slt $t1, $t0, $zero + beqz $t1, read_comp + nop + lb $t2, ($t9) // read 1 byte from uncompressed data + addi $t9, $t9, 1 // advance uncompressed start + addi $a1, $a1, 1 + b next_iter + sb $t2, -1($a1) // store uncompressed byte +read_comp: + lhu $t2, ($a3) // read 2 bytes from compressed data + addi $a3, $a3, 2 // advance compressed start + srl $t3, $t2, 0xC + andi $t2, $t2, 0xFFF + beqz $t3, 3f + sub $t1, $a1, $t2 + addi $t3, $t3, 2 +2: + lb $t2, -1($t1) + addi $t3, $t3, -1 + addi $t1, $t1, 1 + addi $a1, $a1, 1 + bnez $t3, 2b + sb $t2, -1($a1) +next_iter: + sll $t0, $t0, 1 + bne $a1, $t8, mainloop // continue until decompressed length is reached + addi $a2, $a2, -1 + jr $ra + nop +3: + lbu $t3, ($t9) + addi $t9, $t9, 1 + b 2b + addi $t3, $t3, 0x12 +END(Mio0_Decompress) diff --git a/src/code/fp.s b/src/code/fp.s new file mode 100644 index 000000000..431348d89 --- /dev/null +++ b/src/code/fp.s @@ -0,0 +1,165 @@ +#include "ultra64/asm.h" + +.set noreorder + +.section .data + +.balign 16 + +DATA(qNaN0x3FFFFF) + .word 0x7FBFFFFF +ENDDATA(qNaN0x3FFFFF) + +DATA(qNaN0x10000) + .word 0x7F810000 +ENDDATA(qNaN0x10000) + +DATA(sNaN0x3FFFFF) + .word 0x7FFFFFFF +ENDDATA(sNaN0x3FFFFF) + +.section .text + +.balign 16 + +LEAF(floorf) + floor.w.s $f12, $f12 + jr $ra + cvt.s.w $f0, $f12 +END(floorf) + +LEAF(floor) + floor.w.d $f12, $f12 + jr $ra + cvt.d.w $f0, $f12 +END(floor) + +LEAF(lfloorf) + floor.w.s $f4, $f12 + mfc1 $v0, $f4 + jr $ra + nop +END(lfloorf) + +LEAF(lfloor) + floor.w.d $f4, $f12 + mfc1 $v0, $f4 + jr $ra + nop +END(lfloor) + +LEAF(ceilf) + ceil.w.s $f12, $f12 + jr $ra + cvt.s.w $f0, $f12 +END(ceilf) + +LEAF(ceil) + ceil.w.d $f12, $f12 + jr $ra + cvt.d.w $f0, $f12 +END(ceil) + +LEAF(lceilf) + ceil.w.s $f4, $f12 + mfc1 $v0, $f4 + jr $ra + nop +END(lceilf) + +LEAF(lceil) + ceil.w.d $f4, $f12 + mfc1 $v0, $f4 + jr $ra + nop +END(lceil) + +LEAF(truncf) + trunc.w.s $f12, $f12 + jr $ra + cvt.s.w $f0, $f12 +END(truncf) + +LEAF(trunc) + trunc.w.d $f12, $f12 + jr $ra + cvt.d.w $f0, $f12 +END(trunc) + +LEAF(ltruncf) + trunc.w.s $f4, $f12 + mfc1 $v0, $f4 + jr $ra + nop +END(ltruncf) + +LEAF(ltrunc) + trunc.w.d $f4, $f12 + mfc1 $v0, $f4 + jr $ra + nop +END(ltrunc) + +LEAF(nearbyintf) + round.w.s $f12, $f12 + jr $ra + cvt.s.w $f0, $f12 +END(nearbyintf) + +LEAF(nearbyint) + round.w.d $f12, $f12 + jr $ra + cvt.d.w $f0, $f12 +END(nearbyint) + +LEAF(lnearbyintf) + round.w.s $f4, $f12 + mfc1 $v0, $f4 + jr $ra + nop +END(lnearbyintf) + +LEAF(lnearbyint) + round.w.d $f4, $f12 + mfc1 $v0, $f4 + jr $ra + nop +END(lnearbyint) + +LEAF(roundf) + li.s $f4, 0.5 + nop + add.s $f0, $f12, $f4 + floor.w.s $f0, $f0 + jr $ra + cvt.s.w $f0, $f0 +END(roundf) + +LEAF(round) + li.d $f4, 0.5 + nop + add.d $f0, $f12, $f4 + floor.w.d $f0, $f0 + jr $ra + cvt.d.w $f0, $f0 +END(round) + +LEAF(lroundf) + li.s $f4, 0.5 + nop + add.s $f0, $f12, $f4 + floor.w.s $f0, $f0 + mfc1 $v0, $f0 + jr $ra + nop +END(lroundf) + +LEAF(lround) + li.d $f4, 0.5 + nop + add.d $f0, $f12, $f4 + floor.w.d $f0, $f0 + mfc1 $v0, $f0 + jr $ra + nop +END(lround) diff --git a/src/code/kanread.s b/src/code/kanread.s new file mode 100644 index 000000000..70a884870 --- /dev/null +++ b/src/code/kanread.s @@ -0,0 +1,216 @@ +#include "ultra64/asm.h" + +.set noat +.set noreorder + +.section .text + +.balign 16 + +/** + * s32 Kanji_OffsetFromShiftJIS(s32 sjis); + * + * Returns the offset of the glyph texture data in the file `kanji` corresponding + * to a given 2-byte Shift-JIS codepoint. No range validity check is carried out. + * + * A nice Shift-JIS codepoint table: https://uic.io/en/charset/show/shift_jis/ + * The file `kanji` contains the 'Level 1' kanji (0x889F-0x9872), and a reworked + * version of the non-kanji section that includes extra English and Hylian glyphs. + * + * @note This function assumes that its argument is a valid Shift-JIS codepoint; + * there is no range protection at all. + * + * @param sjis Shift-JIS Codepoint of glyph. + * @return s32 offset into `kanji` file. + * + * @remark Original name: "LeoGetKadr" + */ +LEAF(Kanji_OffsetFromShiftJIS) + // Characters with codepoints >= 0x8800 are kanji. Arrangement is regular, + // so convert index directly. + li $at, 0x8800 + slt $at, $a0, $at + bnez $at, .nonkanji + // 0xBC is number of glyphs in one block in the `kanji` file: + // 0x100 possible codepoints with the same byte1 + // - 0x40 unused at beginning + // - 1 unused at 0x7F + // - 3 unused at 0xFD, 0xFE, 0xFF + li $a2, 0xBC + // Get byte1 and adjust so starts at 0 + srl $a1, $a0, 8 + addi $a1, $a1, -0x88 + multu $a2, $a1 + // Get byte2 and adjust so starts at 0 + andi $a3, $a0, 0xFF + addi $a3, $a3, -0x40 + slti $at, $a3, (0x80 - 0x40) + mflo $a2 + // 0x__7F is always empty and elided in the file, so decrement if larger + bnezl $at, .kanji_lower_halfblock + mflo $a2 + addi $a3, $a3, -1 + mflo $a2 +.kanji_lower_halfblock: + addi $a3, $a3, 0x30A + add $a3, $a3, $a2 + jr $ra + sll $v0, $a3, 7 + // returns (0x30A + (adjusted byte2) + (adjusted byte1) * 0xBC) * FONT_CHAR_TEX_SIZE + +// Non-kanji are arranged with irregular gaps, use the lookup table. +.nonkanji: + // Get byte1 and adjust so starts at 0 + srl $a1, $a0, 8 + addi $a1, $a1, -0x81 + multu $a2, $a1 + // Get byte2 and adjust so starts at 0 + andi $a3, $a0, 0xFF + addi $a3, $a3, -0x40 + slti $at, $a3, (0x80 - 0x40) + mflo $a2 + // 0x__7F is always empty and elided in the file, so decrement if larger + bnezl $at, .nonkanji_lower_halfblock + mflo $a2 + addi $a3, $a3, -1 + mflo $a2 +.nonkanji_lower_halfblock: + add $a3, $a3, $a2 + lui $a2, %hi(sNonKanjiIndices) + sll $a3, $a3, 1 + addiu $a2, %lo(sNonKanjiIndices) + add $a3, $a3, $a2 + lh $a2, ($a3) + jr $ra + sll $v0, $a2, 7 + // returns sNonKanjiIndices[(adjusted byte2) + (adjusted byte1) * 0xBC] * FONT_CHAR_TEX_SIZE +END(Kanji_OffsetFromShiftJIS) + +/** + * Nearly equivalent C code (Equivalent for all valid input, will behave differently on overflow due to the use of `add` in the original): + * + * extern u16 sNonKanjiIndices[]; + * + * s32 Kanji_OffsetFromShiftJIS(s32 sjis) { + * u32 byte1 = (u32)sjis >> 8; + * u32 byte2 = sjis & 0xFF; + * + * byte2 -= 0x40; + * if (byte2 >= 0x40) { + * byte2--; + * } + * + * if (sjis >= 0x8800) { + * byte1 -= 0x88; + * return (0x30A + byte2 + byte1 * 0xBC) * FONT_CHAR_TEX_SIZE; + * } else { + * byte1 -= 0x81; + * return sNonKanjiIndices[byte2 + byte1 * 0xBC] * FONT_CHAR_TEX_SIZE; + * } + * } + */ + +/** + * Index table, formatting follows conventional Shift-JIS character table layout, + * with space for the missing 0x__7F,0x__FD,0x__FE,0x__FF entries, and split + * into blocks by high byte. + */ +DATA(sNonKanjiIndices) +// 0x___0 0x___1 0x___2 0x___3 0x___4 0x___5 0x___6 0x___7 0x___8 0x___9 0x___A 0x___B 0x___C 0x___D 0x___E 0x___F +/* 0x814_ */ .half 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F +/* 0x815_ */ .half 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F +/* 0x816_ */ .half 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F +/* 0x817_ */ .half 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E +/* 0x818_ */ .half 0x003F, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E +/* 0x819_ */ .half 0x004F, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E +/* 0x81A_ */ .half 0x005F, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x0000, 0x0000, 0x0000 +/* 0x81B_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073 +/* 0x81C_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x0000 +/* 0x81D_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F +/* 0x81E_ */ .half 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x81F_ */ .half 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, 0x0090, 0x0000, 0x0000, 0x0000, 0x0000, 0x0091 + +// 0x___0 0x___1 0x___2 0x___3 0x___4 0x___5 0x___6 0x___7 0x___8 0x___9 0x___A 0x___B 0x___C 0x___D 0x___E 0x___F +/* 0x824_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0092 +/* 0x825_ */ .half 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x826_ */ .half 0x009C, 0x009D, 0x009E, 0x009F, 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB +/* 0x827_ */ .half 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x828_ */ .half 0x0000, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4 +/* 0x829_ */ .half 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x0000, 0x0000, 0x0000, 0x0000, 0x00D0 +/* 0x82A_ */ .half 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0 +/* 0x82B_ */ .half 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0 +/* 0x82C_ */ .half 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, 0x0100 +/* 0x82D_ */ .half 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F, 0x0110 +/* 0x82E_ */ .half 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117, 0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F, 0x0120 +/* 0x82F_ */ .half 0x0121, 0x0122, 0x0123, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + +// 0x___0 0x___1 0x___2 0x___3 0x___4 0x___5 0x___6 0x___7 0x___8 0x___9 0x___A 0x___B 0x___C 0x___D 0x___E 0x___F +/* 0x834_ */ .half 0x0124, 0x0125, 0x0126, 0x0127, 0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F, 0x0130, 0x0131, 0x0132, 0x0133 +/* 0x835_ */ .half 0x0134, 0x0135, 0x0136, 0x0137, 0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x013F, 0x0140, 0x0141, 0x0142, 0x0143 +/* 0x836_ */ .half 0x0144, 0x0145, 0x0146, 0x0147, 0x0148, 0x0149, 0x014A, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F, 0x0150, 0x0151, 0x0152, 0x0153 +/* 0x837_ */ .half 0x0154, 0x0155, 0x0156, 0x0157, 0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F, 0x0160, 0x0161, 0x0162 +/* 0x838_ */ .half 0x0163, 0x0164, 0x0165, 0x0166, 0x0167, 0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F, 0x0170, 0x0171, 0x0172 +/* 0x839_ */ .half 0x0173, 0x0174, 0x0175, 0x0176, 0x0177, 0x0178, 0x0179, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x017A +/* 0x83A_ */ .half 0x017B, 0x017C, 0x017D, 0x017E, 0x017F, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185, 0x0186, 0x0187, 0x0188, 0x0189, 0x018A +/* 0x83B_ */ .half 0x018B, 0x018C, 0x018D, 0x018E, 0x018F, 0x0190, 0x0191, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192 +/* 0x83C_ */ .half 0x0193, 0x0194, 0x0195, 0x0196, 0x0197, 0x0198, 0x0199, 0x019A, 0x019B, 0x019C, 0x019D, 0x019E, 0x019F, 0x01A0, 0x01A1, 0x01A2 +/* 0x83D_ */ .half 0x01A3, 0x01A4, 0x01A5, 0x01A6, 0x01A7, 0x01A8, 0x01A9, 0x01AA, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x83E_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x83F_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + +// 0x___0 0x___1 0x___2 0x___3 0x___4 0x___5 0x___6 0x___7 0x___8 0x___9 0x___A 0x___B 0x___C 0x___D 0x___E 0x___F +/* 0x844_ */ .half 0x01AB, 0x01AC, 0x01AD, 0x01AE, 0x01AF, 0x01B0, 0x01B1, 0x01B2, 0x01B3, 0x01B4, 0x01B5, 0x01B6, 0x01B7, 0x01B8, 0x01B9, 0x01BA +/* 0x845_ */ .half 0x01BB, 0x01BC, 0x01BD, 0x01BE, 0x01BF, 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C4, 0x01C5, 0x01C6, 0x01C7, 0x01C8, 0x01C9, 0x01CA +/* 0x846_ */ .half 0x01CB, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x847_ */ .half 0x01CC, 0x01CD, 0x01CE, 0x01CF, 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7, 0x01D8, 0x01D9, 0x01DA +/* 0x848_ */ .half 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF, 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E4, 0x01E5, 0x01E6, 0x01E7, 0x01E8, 0x01E9, 0x01EA +/* 0x849_ */ .half 0x01EB, 0x01EC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x01ED +/* 0x84A_ */ .half 0x01EE, 0x01EF, 0x01F0, 0x01F1, 0x01F2, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, 0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD +/* 0x84B_ */ .half 0x01FE, 0x01FF, 0x0200, 0x0201, 0x0202, 0x0203, 0x0204, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209, 0x020A, 0x020B, 0x020C, 0x020D +/* 0x84C_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x84D_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x84E_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x84F_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + +// 0x___0 0x___1 0x___2 0x___3 0x___4 0x___5 0x___6 0x___7 0x___8 0x___9 0x___A 0x___B 0x___C 0x___D 0x___E 0x___F +/* 0x854_ */ .half 0x020E, 0x020F, 0x0210, 0x0211, 0x0212, 0x0213, 0x0214, 0x0215, 0x0216, 0x0217, 0x0218, 0x0219, 0x021A, 0x021B, 0x021C, 0x021D +/* 0x855_ */ .half 0x021E, 0x021F, 0x0220, 0x0221, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0222, 0x0223 +/* 0x856_ */ .half 0x0224, 0x0225, 0x0226, 0x0227, 0x0228, 0x0229, 0x022A, 0x022B, 0x022C, 0x022D, 0x022E, 0x022F, 0x0230, 0x0231, 0x0232, 0x0233 +/* 0x857_ */ .half 0x0234, 0x0235, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0236, 0x0237, 0x0238 +/* 0x858_ */ .half 0x0239, 0x023A, 0x023B, 0x023C, 0x023D, 0x023E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x859_ */ .half 0x0000, 0x023F, 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, 0x0248, 0x0000, 0x0000, 0x0000, 0x0000, 0x0249 +/* 0x85A_ */ .half 0x024A, 0x024B, 0x024C, 0x024D, 0x024E, 0x024F, 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257, 0x0000, 0x0000 +/* 0x85B_ */ .half 0x0000, 0x0000, 0x0000, 0x0258, 0x0259, 0x025A, 0x025B, 0x025C, 0x025D, 0x025E, 0x025F, 0x0260, 0x0261, 0x0262, 0x0263, 0x0264 +/* 0x85C_ */ .half 0x0265, 0x0266, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x85D_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0267, 0x0268, 0x0269, 0x026A, 0x026B +/* 0x85E_ */ .half 0x026C, 0x026D, 0x026E, 0x026F, 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, 0x0278, 0x0279, 0x027A, 0x027B +/* 0x85F_ */ .half 0x027C, 0x027D, 0x027E, 0x027F, 0x0280, 0x0281, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + +// 0x___0 0x___1 0x___2 0x___3 0x___4 0x___5 0x___6 0x___7 0x___8 0x___9 0x___A 0x___B 0x___C 0x___D 0x___E 0x___F +/* 0x864_ */ .half 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, 0x0288, 0x0289, 0x028A, 0x028B, 0x028C, 0x028D, 0x028E, 0x028F, 0x0290, 0x0291 +/* 0x865_ */ .half 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, 0x0298, 0x0299, 0x029A, 0x029B, 0x029C, 0x029D, 0x029E, 0x029F, 0x0000, 0x0000 +/* 0x866_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x867_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x868_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x869_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x02A4 +/* 0x86A_ */ .half 0x02A5, 0x02A6, 0x02A7, 0x02A8, 0x02A9, 0x02AA, 0x02AB, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x86B_ */ .half 0x0000, 0x0000, 0x0000, 0x02AC, 0x02AD, 0x02AE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x86C_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x02AF, 0x02B0, 0x02B1, 0x02B2, 0x02B3, 0x02B4, 0x02B5, 0x02B6, 0x02B7 +/* 0x86D_ */ .half 0x02B8, 0x02B9, 0x02BA, 0x02BB, 0x02BC, 0x02BD, 0x02BE, 0x02BF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x86E_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x86F_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + +// 0x___0 0x___1 0x___2 0x___3 0x___4 0x___5 0x___6 0x___7 0x___8 0x___9 0x___A 0x___B 0x___C 0x___D 0x___E 0x___F +/* 0x874_ */ .half 0x02C0, 0x02C1, 0x02C2, 0x02C3, 0x02C4, 0x02C5, 0x02C6, 0x02C7, 0x02C8, 0x02C9, 0x02CA, 0x02CB, 0x02CC, 0x02CD, 0x02CE, 0x02CF +/* 0x875_ */ .half 0x02D0, 0x02D1, 0x02D2, 0x02D3, 0x02D4, 0x02D5, 0x02D6, 0x02D7, 0x02D8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x876_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x877_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x878_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x879_ */ .half 0x0000, 0x02D9, 0x02DA, 0x02DB, 0x02DC, 0x02DD, 0x02DE, 0x02DF, 0x02E0, 0x02E1, 0x02E2, 0x02E3, 0x02E4, 0x02E5, 0x02E6, 0x02E7 +/* 0x87A_ */ .half 0x02E8, 0x02E9, 0x02EA, 0x02EB, 0x02EC, 0x02ED, 0x02EE, 0x02EF, 0x02F0, 0x02F1, 0x02F2, 0x02F3, 0x02F4, 0x02F5, 0x02F6, 0x02F7 +/* 0x87B_ */ .half 0x02F8, 0x02F9, 0x02FA, 0x02FB, 0x02FC, 0x02FD, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x02FE, 0x02FF, 0x0300 +/* 0x87C_ */ .half 0x0301, 0x0302, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x87D_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x87E_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0303, 0x0304, 0x0305, 0x0306, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +/* 0x87F_ */ .half 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0307, 0x0308, 0x0309 +ENDDATA(sNonKanjiIndices) diff --git a/src/libultra/gu/libm_vals.s b/src/libultra/gu/libm_vals.s new file mode 100644 index 000000000..18de1ae4f --- /dev/null +++ b/src/libultra/gu/libm_vals.s @@ -0,0 +1,9 @@ +#include "ultra64/asm.h" + +.section .rodata + +.balign 16 + +DATA(__libm_qnan_f) + .word 0x7F810000 +ENDDATA(__libm_qnan_f) diff --git a/src/libultra/libc/bcmp.s b/src/libultra/libc/bcmp.s new file mode 100644 index 000000000..df6692feb --- /dev/null +++ b/src/libultra/libc/bcmp.s @@ -0,0 +1,93 @@ +#include "ultra64/asm.h" + +.set noat +.set noreorder + +.section .text + +.balign 16 + +LEAF(bcmp) + slti $at, $a2, 0x10 + bnez $at, bytecmp + xor $v0, $a0, $a1 + andi $v0, $v0, 3 + bnez $v0, unaligncmp + negu $t8, $a0 + andi $t8, $t8, 3 + beqz $t8, wordcmp + subu $a2, $a2, $t8 + move $v0, $v1 + lwl $v0, ($a0) + lwl $v1, ($a1) + addu $a0, $a0, $t8 + addu $a1, $a1, $t8 + bne $v0, $v1, cmpne +wordcmp: + li $at, ~3 + and $a3, $a2, $at + beqz $a3, bytecmp + subu $a2, $a2, $a3 + addu $a3, $a3, $a0 + lw $v0, ($a0) +1: + lw $v1, ($a1) + addiu $a0, $a0, 4 + addiu $a1, $a1, 4 + bne $v0, $v1, cmpne + nop + bnel $a0, $a3, 1b + lw $v0, ($a0) + b bytecmp + nop +unaligncmp: + negu $a3, $a1 + andi $a3, $a3, 3 + beqz $a3, partaligncmp + subu $a2, $a2, $a3 + addu $a3, $a3, $a0 + lbu $v0, ($a0) +1: + lbu $v1, ($a1) + addiu $a0, $a0, 1 + addiu $a1, $a1, 1 + bne $v0, $v1, cmpne + nop + bnel $a0, $a3, 1b + lbu $v0, ($a0) +partaligncmp: + li $at, ~3 + and $a3, $a2, $at + beqz $a3, bytecmp + subu $a2, $a2, $a3 + addu $a3, $a3, $a0 + lwl $v0, ($a0) +1: + lw $v1, ($a1) + lwr $v0, 3($a0) + addiu $a0, $a0, 4 + addiu $a1, $a1, 4 + bne $v0, $v1, cmpne + nop + bnel $a0, $a3, 1b + lwl $v0, ($a0) +bytecmp: + blez $a2, cmpdone + addu $a3, $a2, $a0 + lbu $v0, ($a0) +1: + lbu $v1, ($a1) + addiu $a0, $a0, 1 + addiu $a1, $a1, 1 + bne $v0, $v1, cmpne + nop + bnel $a0, $a3, 1b + lbu $v0, ($a0) +cmpdone: + jr $ra + move $v0, $zero + +cmpne: + jr $ra + li $v0, 1 +END(bcmp) diff --git a/src/libultra/libc/bcopy.s b/src/libultra/libc/bcopy.s new file mode 100644 index 000000000..e1240f113 --- /dev/null +++ b/src/libultra/libc/bcopy.s @@ -0,0 +1,233 @@ +#include "ultra64/asm.h" + +.set noat +.set noreorder + +.section .text + +.balign 16 + +LEAF(bcopy) + beqz $a2, ret + move $a3, $a1 + beq $a0, $a1, ret + slt $at, $a1, $a0 + bnezl $at, goforwards + slti $at, $a2, 0x10 + add $v0, $a0, $a2 + slt $at, $a1, $v0 + beql $at, $zero, goforwards + slti $at, $a2, 0x10 + b gobackwards + slti $at, $a2, 0x10 + slti $at, $a2, 0x10 +goforwards: + bnez $at, forwards_bytecopy + nop + andi $v0, $a0, 3 + andi $v1, $a1, 3 + beq $v0, $v1, forwalignable + nop +forwards_bytecopy: + beqz $a2, ret + nop + addu $v1, $a0, $a2 +99: + lb $v0, ($a0) + addiu $a0, $a0, 1 + addiu $a1, $a1, 1 + bne $a0, $v1, 99b + sb $v0, -1($a1) +ret: + jr $ra + move $v0, $a3 + +forwalignable: + beqz $v0, forwards_32 + li $at, 1 + beq $v0, $at, forw_copy3 + li $at, 2 + beql $v0, $at, forw_copy2 + lh $v0, ($a0) + lb $v0, ($a0) + addiu $a0, $a0, 1 + addiu $a1, $a1, 1 + addiu $a2, $a2, -1 + b forwards_32 + sb $v0, -1($a1) + lh $v0, ($a0) +forw_copy2: + addiu $a0, $a0, 2 + addiu $a1, $a1, 2 + addiu $a2, $a2, -2 + b forwards_32 + sh $v0, -2($a1) +forw_copy3: + lb $v0, ($a0) + lh $v1, 1($a0) + addiu $a0, $a0, 3 + addiu $a1, $a1, 3 + addiu $a2, $a2, -3 + sb $v0, -3($a1) + sh $v1, -2($a1) + +forwards: +forwards_32: + slti $at, $a2, 0x20 + bnezl $at, forwards_16_ + slti $at, $a2, 0x10 + lw $v0, ($a0) + lw $v1, 4($a0) + lw $t0, 8($a0) + lw $t1, 0xC($a0) + lw $t2, 0x10($a0) + lw $t3, 0x14($a0) + lw $t4, 0x18($a0) + lw $t5, 0x1C($a0) + addiu $a0, $a0, 0x20 + addiu $a1, $a1, 0x20 + addiu $a2, $a2, -0x20 + sw $v0, -0x20($a1) + sw $v1, -0x1C($a1) + sw $t0, -0x18($a1) + sw $t1, -0x14($a1) + sw $t2, -0x10($a1) + sw $t3, -0xC($a1) + sw $t4, -8($a1) + b forwards_32 + sw $t5, -4($a1) +forwards_16: + slti $at, $a2, 0x10 +forwards_16_: // fake label due to branch likely optimization + bnezl $at, forwards_4_ + slti $at, $a2, 4 + lw $v0, ($a0) + lw $v1, 4($a0) + lw $t0, 8($a0) + lw $t1, 0xC($a0) + addiu $a0, $a0, 0x10 + addiu $a1, $a1, 0x10 + addiu $a2, $a2, -0x10 + sw $v0, -0x10($a1) + sw $v1, -0xC($a1) + sw $t0, -8($a1) + b forwards_16 + sw $t1, -4($a1) +forwards_4: + slti $at, $a2, 4 +forwards_4_: // fake label due to branch likely optimization + bnez $at, forwards_bytecopy + nop + lw $v0, ($a0) + addiu $a0, $a0, 4 + addiu $a1, $a1, 4 + addiu $a2, $a2, -4 + b forwards_4 + sw $v0, -4($a1) + slti $at, $a2, 0x10 +gobackwards: + add $a0, $a0, $a2 + bnez $at, backwards_bytecopy + add $a1, $a1, $a2 + andi $v0, $a0, 3 + andi $v1, $a1, 3 + beq $v0, $v1, backalignable + nop +backwards_bytecopy: + beqz $a2, ret + nop + addiu $a0, $a0, -1 + addiu $a1, $a1, -1 + subu $v1, $a0, $a2 +99: + lb $v0, ($a0) + addiu $a0, $a0, -1 + addiu $a1, $a1, -1 + bne $a0, $v1, 99b + sb $v0, 1($a1) + jr $ra + move $v0, $a3 + +backalignable: + beqz $v0, backwards_32 + li $at, 3 + beq $v0, $at, back_copy3 + li $at, 2 + beql $v0, $at, back_copy2 + lh $v0, -2($a0) + lb $v0, -1($a0) + addiu $a0, $a0, -1 + addiu $a1, $a1, -1 + addiu $a2, $a2, -1 + b backwards_32 + sb $v0, ($a1) + lh $v0, -2($a0) +back_copy2: + addiu $a0, $a0, -2 + addiu $a1, $a1, -2 + addiu $a2, $a2, -2 + b backwards_32 + sh $v0, ($a1) +back_copy3: + lb $v0, -1($a0) + lh $v1, -3($a0) + addiu $a0, $a0, -3 + addiu $a1, $a1, -3 + addiu $a2, $a2, -3 + sb $v0, 2($a1) + sh $v1, ($a1) + +backwards: +backwards_32: + slti $at, $a2, 0x20 + bnezl $at, backwards_16_ + slti $at, $a2, 0x10 + lw $v0, -4($a0) + lw $v1, -8($a0) + lw $t0, -0xc($a0) + lw $t1, -0x10($a0) + lw $t2, -0x14($a0) + lw $t3, -0x18($a0) + lw $t4, -0x1c($a0) + lw $t5, -0x20($a0) + addiu $a0, $a0, -0x20 + addiu $a1, $a1, -0x20 + addiu $a2, $a2, -0x20 + sw $v0, 0x1C($a1) + sw $v1, 0x18($a1) + sw $t0, 0x14($a1) + sw $t1, 0x10($a1) + sw $t2, 0xC($a1) + sw $t3, 8($a1) + sw $t4, 4($a1) + b backwards_32 + sw $t5, ($a1) +backwards_16: + slti $at, $a2, 0x10 +backwards_16_: // fake label due to branch likely optimization + bnezl $at, backwards_4_ + slti $at, $a2, 4 + lw $v0, -4($a0) + lw $v1, -8($a0) + lw $t0, -0xC($a0) + lw $t1, -0x10($a0) + addiu $a0, $a0, -0x10 + addiu $a1, $a1, -0x10 + addiu $a2, $a2, -0x10 + sw $v0, 0xC($a1) + sw $v1, 8($a1) + sw $t0, 4($a1) + b backwards_16 + sw $t1, ($a1) +backwards_4: + slti $at, $a2, 4 +backwards_4_: // fake label due to branch likely optimization + bnez $at, backwards_bytecopy + nop + lw $v0, -4($a0) + addiu $a0, $a0, -4 + addiu $a1, $a1, -4 + addiu $a2, $a2, -4 + b backwards_4 + sw $v0, ($a1) +END(bcopy) diff --git a/src/libultra/libc/bzero.s b/src/libultra/libc/bzero.s new file mode 100644 index 000000000..5323a92d7 --- /dev/null +++ b/src/libultra/libc/bzero.s @@ -0,0 +1,65 @@ +#include "ultra64/asm.h" + +.set noat +.set noreorder + +.section .text + +.balign 16 + +LEAF(bzero) + slti $at, $a1, 0xC + bnez $at, bytezero + negu $v1, $a0 + andi $v1, $v1, 3 + beqz $v1, blkzero + subu $a1, $a1, $v1 + swl $zero, ($a0) + addu $a0, $a0, $v1 +blkzero: + // align backwards to 0x20 + li $at, ~0x1F + and $a3, $a1, $at + // If the result is zero, the amount to zero is less than 0x20 bytes + beqz $a3, wordzero + subu $a1, $a1, $a3 + // zero in blocks of 0x20 at a time + addu $a3, $a3, $a0 +1: + addiu $a0, $a0, 0x20 + sw $zero, -0x20($a0) + sw $zero, -0x1C($a0) + sw $zero, -0x18($a0) + sw $zero, -0x14($a0) + sw $zero, -0x10($a0) + sw $zero, -0xC($a0) + sw $zero, -8($a0) + bne $a0, $a3, 1b + sw $zero, -4($a0) +wordzero: + // align backwards to 0x4 + li $at, ~3 + and $a3, $a1, $at + // If the result is zero, the amount to zero is less than 0x4 bytes + beqz $a3, bytezero + subu $a1, $a1, $a3 + // zero one word at a time + addu $a3, $a3, $a0 +1: + addiu $a0, $a0, 4 + bne $a0, $a3, 1b + sw $zero, -4($a0) +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 + bne $a0, $a1, 1b + sb $zero, -1($a0) +zerodone: + jr $ra + nop +END(bzero) diff --git a/src/libultra/mgu/mtxf2l.s b/src/libultra/mgu/mtxf2l.s new file mode 100644 index 000000000..edbb675a8 --- /dev/null +++ b/src/libultra/mgu/mtxf2l.s @@ -0,0 +1,40 @@ +#include "ultra64/asm.h" + +.set noat +.set noreorder + +.section .text + +.balign 32 + +#define MTX_INTPART 0 +#define MTX_FRACPART 0x20 + +LEAF(guMtxF2L) + li $at, 0x47800000 // 65536.0f + mtc1 $at, $f0 + li $t9, 0xFFFF0000 + addiu $t8, $a1, MTX_FRACPART +1: + lwc1 $f4, ($a0) + lwc1 $f10, 4($a0) + addiu $a1, $a1, 4 + mul.s $f6, $f4, $f0 + addiu $a0, $a0, 8 + mul.s $f16, $f10, $f0 + trunc.w.s $f8, $f6 + trunc.w.s $f18, $f16 + mfc1 $t0, $f8 + mfc1 $t1, $f18 + and $t2, $t0, $t9 + sll $t5, $t0, 0x10 + srl $t3, $t1, 0x10 + andi $t6, $t1, 0xFFFF + or $t4, $t2, $t3 + or $t7, $t5, $t6 + sw $t4, (MTX_INTPART-4)($a1) + bne $a1, $t8, 1b + sw $t7, (MTX_FRACPART-4)($a1) + jr $ra + nop +END(guMtxF2L) diff --git a/src/libultra/mgu/mtxident.s b/src/libultra/mgu/mtxident.s new file mode 100644 index 000000000..fb0e4c44a --- /dev/null +++ b/src/libultra/mgu/mtxident.s @@ -0,0 +1,29 @@ +#include "ultra64/asm.h" + +.set noreorder + +.section .text + +.balign 32 + +LEAF(guMtxIdent) + addi $t0, $zero, 1 + sll $t1, $t0, 0x10 + sw $t1, ($a0) + sw $zero, 4($a0) + sw $t0, 8($a0) + sw $zero, 0xc($a0) + sw $zero, 0x10($a0) + sw $t1, 0x14($a0) + sw $zero, 0x18($a0) + sw $t0, 0x1C($a0) + sw $zero, 0x20($a0) + sw $zero, 0x24($a0) + sw $zero, 0x28($a0) + sw $zero, 0x2c($a0) + sw $zero, 0x30($a0) + sw $zero, 0x34($a0) + sw $zero, 0x38($a0) + jr $ra + sw $zero, 0x3C($a0) +END(guMtxIdent) diff --git a/src/libultra/mgu/mtxidentf.s b/src/libultra/mgu/mtxidentf.s new file mode 100644 index 000000000..583fc2218 --- /dev/null +++ b/src/libultra/mgu/mtxidentf.s @@ -0,0 +1,28 @@ +#include "ultra64/asm.h" + +.set noreorder + +.section .text + +.balign 32 + +LEAF(guMtxIdentF) + li $t0, 0x3F800000 // 1.0f + sw $t0, ($a0) + sw $zero, 4($a0) + sw $zero, 8($a0) + sw $zero, 0xC($a0) + sw $zero, 0x10($a0) + sw $t0, 0x14($a0) + sw $zero, 0x18($a0) + sw $zero, 0x1C($a0) + sw $zero, 0x20($a0) + sw $zero, 0x24($a0) + sw $t0, 0x28($a0) + sw $zero, 0x2C($a0) + sw $zero, 0x30($a0) + sw $zero, 0x34($a0) + sw $zero, 0x38($a0) + jr $ra + sw $t0, 0x3C($a0) +END(guMtxIdentF) diff --git a/src/libultra/mgu/mtxl2f.s b/src/libultra/mgu/mtxl2f.s new file mode 100644 index 000000000..9298da37c --- /dev/null +++ b/src/libultra/mgu/mtxl2f.s @@ -0,0 +1,41 @@ +#include "ultra64/asm.h" + +.set noat +.set noreorder + +.section .text + +.balign 32 + +#define MTX_INTPART 0 +#define MTX_FRACPART 0x20 + +LEAF(guMtxL2F) + li $at, 0x37800000 // 1.0f / 65536.0f + mtc1 $at, $f0 + li $t9, 0xFFFF0000 + addiu $t8, $a1, MTX_FRACPART +1: + lw $t0, MTX_INTPART($a1) + lw $t1, MTX_FRACPART($a1) + addiu $a1, $a1, 4 + and $t2, $t0, $t9 + srl $t3, $t1, 0x10 + or $t4, $t2, $t3 + mtc1 $t4, $f4 + sll $t5, $t0, 0x10 + andi $t6, $t1, 0xFFFF + or $t7, $t5, $t6 + cvt.s.w $f6, $f4 + mtc1 $t7, $f10 + addiu $a0, $a0, 8 + cvt.s.w $f16, $f10 + mul.s $f8, $f6, $f0 + nop + mul.s $f18, $f16, $f0 + swc1 $f8, -8($a0) + bne $a1, $t8, 1b + swc1 $f18, -4($a0) + jr $ra + nop +END(guMtxL2F) diff --git a/src/libultra/mgu/normalize.s b/src/libultra/mgu/normalize.s new file mode 100644 index 000000000..7686317ea --- /dev/null +++ b/src/libultra/mgu/normalize.s @@ -0,0 +1,31 @@ +#include "ultra64/asm.h" + +.set noreorder + +.section .text + +.balign 32 + +LEAF(guNormalize) + lwc1 $f4, ($a0) + lwc1 $f6, ($a1) + lwc1 $f8, ($a2) + mul.s $f10, $f4, $f4 + li $t0, 0x3F800000 // 1.0f + mul.s $f16, $f6, $f6 + add.s $f18, $f10, $f16 + mul.s $f16, $f8, $f8 + add.s $f10, $f16, $f18 + mtc1 $t0, $f18 + sqrt.s $f16, $f10 + div.s $f10, $f18, $f16 + mul.s $f16, $f4, $f10 + nop + mul.s $f18, $f6, $f10 + nop + mul.s $f4, $f8, $f10 + swc1 $f16, ($a0) + swc1 $f18, ($a1) + jr $ra + swc1 $f4, ($a2) +END(guNormalize) diff --git a/src/libultra/mgu/scale.s b/src/libultra/mgu/scale.s new file mode 100644 index 000000000..80199c062 --- /dev/null +++ b/src/libultra/mgu/scale.s @@ -0,0 +1,52 @@ +#include "ultra64/asm.h" + +.set noat +.set noreorder + +.section .text + +.balign 32 + +LEAF(guScale) + li $at, 0x47800000 // 65536.0f + mtc1 $at, $f4 + mtc1 $a1, $f6 + sw $zero, 4($a0) + sw $zero, 0xC($a0) + mul.s $f8, $f6, $f4 + mtc1 $a2, $f6 + sw $zero, 0x10($a0) + sw $zero, 0x18($a0) + sw $zero, 0x24($a0) + sw $zero, 0x2C($a0) + sw $zero, 0x30($a0) + trunc.w.s $f10, $f8 + mul.s $f8, $f6, $f4 + mtc1 $a3, $f6 + sw $zero, 0x38($a0) + mfc1 $t1, $f10 + sw $zero, 0x3C($a0) + srl $t2, $t1, 0x10 + trunc.w.s $f10, $f8 + mul.s $f8, $f6, $f4 + sll $t0, $t2, 0x10 + sll $t2, $t1, 0x10 + mfc1 $t1, $f10 + sw $t0, ($a0) + sw $t2, 0x20($a0) + srl $t0, $t1, 0x10 + trunc.w.s $f10, $f8 + andi $t2, $t1, 0xFFFF + sw $t2, 0x28($a0) + sw $t0, 8($a0) + mfc1 $t1, $f10 + nop + srl $t2, $t1, 0x10 + sll $t0, $t2, 0x10 + sw $t0, 0x14($a0) + li $t0, 1 + sll $t2, $t1, 0x10 + sw $t2, 0x34($a0) + jr $ra + sw $t0, 0x1C($a0) +END(guScale) diff --git a/src/libultra/mgu/translate.s b/src/libultra/mgu/translate.s new file mode 100644 index 000000000..d059ad569 --- /dev/null +++ b/src/libultra/mgu/translate.s @@ -0,0 +1,61 @@ +#include "ultra64/asm.h" + +.set noat +.set noreorder + +.section .text + +.balign 32 + +LEAF(guTranslate) + li $at, 0x47800000 // 65536.0f + mtc1 $at, $f4 + mtc1 $a1, $f6 + sw $zero, ($a0) + sw $zero, 0x14($a0) + mul.s $f8, $f6, $f4 + mtc1 $a2, $f6 + sw $zero, 8($a0) + sw $zero, 4($a0) + sw $zero, 0xC($a0) + sw $zero, 0x10($a0) + sw $zero, 0x20($a0) + trunc.w.s $f10, $f8 + mul.s $f8, $f6, $f4 + mtc1 $a3, $f6 + sw $zero, 0x24($a0) + mfc1 $t1, $f10 + sw $zero, 0x28($a0) + sw $zero, 0x2C($a0) + srl $t2, $t1, 0x10 + trunc.w.s $f10, $f8 + mul.s $f8, $f6, $f4 + sll $t0, $t2, 0x10 + sw $zero, 0x30($a0) + mfc1 $t3, $f10 + sw $zero, 0x34($a0) + srl $t2, $t3, 0x10 + trunc.w.s $f10, $f8 + or $t0, $t0, $t2 + sw $t0, 0x18($a0) + sll $t0, $t1, 0x10 + sll $t2, $t3, 0x10 + mfc1 $t1, $f10 + srl $t2, $t2, 0x10 + or $t0, $t0, $t2 + sw $t0, 0x38($a0) + srl $t2, $t1, 0x10 + sll $t0, $t2, 0x10 + addiu $t0, $t0, 1 + sw $t0, 0x1C($a0) + lui $t0, 1 + ori $t0, $t0, 0 + sw $t0, ($a0) + sw $t0, 0x14($a0) + lui $t0, (0x00000001 >> 16) + ori $t0, (0x00000001 & 0xFFFF) + sll $t2, $t1, 0x10 + sw $t2, 0x3C($a0) + jr $ra + sw $t0, 8($a0) +END(guTranslate) diff --git a/src/libultra/os/exceptasm.s b/src/libultra/os/exceptasm.s new file mode 100644 index 000000000..79a6ed1a2 --- /dev/null +++ b/src/libultra/os/exceptasm.s @@ -0,0 +1,982 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" +#include "ultra64/rcp.h" +#include "ultra64/rsp.h" +#include "ultra64/message.h" +#include "ultra64/thread.h" +#include "ultra64/exception.h" + +.set noat +.set noreorder +.set gp=64 + +.section .data + +.balign 16 + +DATA(__osHwIntTable) + .word 0, 0 + .word 0, 0 // cart + .word 0, 0 + .word 0, 0 + .word 0, 0 +ENDDATA(__osHwIntTable) + +DATA(__osPiIntTable) + .word 0, 0 +ENDDATA(__osPiIntTable) + +.section .rodata + +.balign 16 + +__osIntOffTable: + .byte 0x00 /* redispatch */ + .byte 0x14 /* prenmi */ + .byte 0x18 /* IP6_Hdlr */ + .byte 0x18 /* IP6_Hdlr */ + .byte 0x1C /* IP7_Hdlr */ + .byte 0x1C /* IP7_Hdlr */ + .byte 0x1C /* IP7_Hdlr */ + .byte 0x1C /* IP7_Hdlr */ + .byte 0x20 /* counter */ + .byte 0x20 /* counter */ + .byte 0x20 /* counter */ + .byte 0x20 /* counter */ + .byte 0x20 /* counter */ + .byte 0x20 /* counter */ + .byte 0x20 /* counter */ + .byte 0x20 /* counter */ + .byte 0x00 /* redispatch */ + .byte 0x04 /* sw1 */ + .byte 0x08 /* sw2 */ + .byte 0x08 /* sw2 */ + .byte 0x0C /* rcp */ + .byte 0x0C /* rcp */ + .byte 0x0C /* rcp */ + .byte 0x0C /* rcp */ + .byte 0x10 /* cart */ + .byte 0x10 /* cart */ + .byte 0x10 /* cart */ + .byte 0x10 /* cart */ + .byte 0x10 /* cart */ + .byte 0x10 /* cart */ + .byte 0x10 /* cart */ + .byte 0x10 /* cart */ + +__osIntTable: + .word redispatch + .word sw1 + .word sw2 + .word rcp + .word cart + .word prenmi + .word IP6_Hdlr + .word IP7_Hdlr + .word counter + +.section .text + +.balign 16 + +/** + * 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) + lui $k0, %hi(__osException) + addiu $k0, %lo(__osException) + jr $k0 + nop +END(__osExceptionPreamble) + +LEAF(__osException) + // Load scratch space for thread saving + lui $k0, %hi(__osThreadSave) + addiu $k0, %lo(__osThreadSave) + // Save $at + sd $at, THREAD_AT($k0) + // Save sr + mfc0 $k1, C0_SR + sw $k1, THREAD_SR($k0) + // Disable interrupts + li $at, ~(SR_IE | SR_EXL) + and $k1, $k1, $at + mtc0 $k1, C0_SR + // Save some temp registers for use in the following + sd $t0, THREAD_T0($k0) + sd $t1, THREAD_T1($k0) + sd $t2, THREAD_T2($k0) + // Mark FPU as unused + sw $zero, THREAD_FP($k0) + // Left over from misplaced ifdef, immediately overwritten on next instruction + mfc0 $t0, C0_CAUSE +savecontext: + // Save the previously running thread's context to be restored when it resumes + move $t0, $k0 + lui $k0, %hi(__osRunningThread) + lw $k0, %lo(__osRunningThread)($k0) + ld $t1, THREAD_AT($t0) + sd $t1, THREAD_AT($k0) + ld $t1, THREAD_SR($t0) + sd $t1, THREAD_SR($k0) + ld $t1, THREAD_T0($t0) + sd $t1, THREAD_T0($k0) + ld $t1, THREAD_T1($t0) + sd $t1, THREAD_T1($k0) + ld $t1, THREAD_T2($t0) + sd $t1, THREAD_T2($k0) + lw $k1, THREAD_SR($k0) + mflo $t0 + sd $t0, THREAD_LO($k0) + mfhi $t0 + andi $t1, $k1, SR_IMASK + sd $v0, THREAD_V0($k0) + sd $v1, THREAD_V1($k0) + sd $a0, THREAD_A0($k0) + sd $a1, THREAD_A1($k0) + sd $a2, THREAD_A2($k0) + sd $a3, THREAD_A3($k0) + sd $t3, THREAD_T3($k0) + sd $t4, THREAD_T4($k0) + sd $t5, THREAD_T5($k0) + sd $t6, THREAD_T6($k0) + sd $t7, THREAD_T7($k0) + sd $s0, THREAD_S0($k0) + sd $s1, THREAD_S1($k0) + sd $s2, THREAD_S2($k0) + sd $s3, THREAD_S3($k0) + sd $s4, THREAD_S4($k0) + sd $s5, THREAD_S5($k0) + sd $s6, THREAD_S6($k0) + sd $s7, THREAD_S7($k0) + sd $t8, THREAD_T8($k0) + sd $t9, THREAD_T9($k0) + sd $gp, THREAD_GP($k0) + sd $sp, THREAD_SP($k0) + sd $fp, THREAD_S8($k0) + sd $ra, THREAD_RA($k0) + beqz $t1, savercp + sd $t0, THREAD_HI($k0) + // If any CPU interrupts are enabled in the previous thread's SR, bitwise-OR in the + // disabled CPU interrupts from the global interrupt mask. + // This is an attempt at reverting the effect of masking the thread's SR with the + // global interrupt mask. This is however broken, see comments for osSetIntMask. + lui $t0, %hi(__OSGlobalIntMask) + addiu $t0, %lo(__OSGlobalIntMask) + lw $t0, ($t0) + li $at, ~0 + xor $t2, $t0, $at + lui $at, ((~SR_IMASK) >> 0x10) & 0xFFFF + andi $t2, $t2, SR_IMASK + ori $at, (~SR_IMASK) & 0xFFFF + or $t4, $t1, $t2 + and $t3, $k1, $at + andi $t0, $t0, SR_IMASK + or $t3, $t3, $t4 + and $t1, $t1, $t0 + and $k1, $k1, $at + sw $t3, THREAD_SR($k0) + or $k1, $k1, $t1 +savercp: + // Save the currently masked RCP interrupts. + lui $t1, %hi(PHYS_TO_K1(MI_INTR_MASK_REG)) + lw $t1, %lo(PHYS_TO_K1(MI_INTR_MASK_REG))($t1) + beqz $t1, endrcp + nop + // Similar to the above comment, but for RCP interrupt enable bits rather than CPU. + // This suffers from the same problem as above. + lui $t0, %hi(__OSGlobalIntMask) + addiu $t0, %lo(__OSGlobalIntMask) + lw $t0, ($t0) + lw $t4, THREAD_RCP($k0) + li $at, ~0 + srl $t0, $t0, RCP_IMASKSHIFT + xor $t0, $t0, $at + andi $t0, $t0, (RCP_IMASK >> RCP_IMASKSHIFT) + and $t0, $t0, $t4 + or $t1, $t1, $t0 +endrcp: + sw $t1, THREAD_RCP($k0) + mfc0 $t0, C0_EPC + sw $t0, THREAD_PC($k0) + lw $t0, THREAD_FP($k0) + beqz $t0, handle_interrupt + nop + // Save FP Registers if FPU was used by the thread + cfc1 $t0, C1_FPCSR + nop + sw $t0, THREAD_FPCSR($k0) + sdc1 $f0, THREAD_FP0($k0) + sdc1 $f2, THREAD_FP2($k0) + sdc1 $f4, THREAD_FP4($k0) + sdc1 $f6, THREAD_FP6($k0) + sdc1 $f8, THREAD_FP8($k0) + sdc1 $f10, THREAD_FP10($k0) + sdc1 $f12, THREAD_FP12($k0) + sdc1 $f14, THREAD_FP14($k0) + sdc1 $f16, THREAD_FP16($k0) + sdc1 $f18, THREAD_FP18($k0) + sdc1 $f20, THREAD_FP20($k0) + sdc1 $f22, THREAD_FP22($k0) + sdc1 $f24, THREAD_FP24($k0) + sdc1 $f26, THREAD_FP26($k0) + sdc1 $f28, THREAD_FP28($k0) + sdc1 $f30, THREAD_FP30($k0) + +handle_interrupt: + // Determine the cause of the exception or interrupt and + // enter appropriate handling routine + mfc0 $t0, C0_CAUSE + sw $t0, THREAD_CAUSE($k0) + li $t1, OS_STATE_RUNNABLE + sh $t1, THREAD_STATE($k0) + andi $t1, $t0, CAUSE_EXCMASK + // Test for break exception + li $t2, EXC_BREAK + beq $t1, $t2, handle_break + nop + // Test for CpU (coprocessor unusable) exception + li $t2, EXC_CPU + beq $t1, $t2, handle_CpU + nop + // Test for interrupt, if it's not an interrupt, panic + li $t2, EXC_INT + bne $t1, $t2, panic + nop + and $s0, $k1, $t0 + +next_interrupt: + // Handle external interrupt causes, using a jump table + // to enter into the appropriate handler + andi $t1, $s0, CAUSE_IPMASK + srl $t2, $t1, CAUSE_IPSHIFT + 4 + bnez $t2, 1f + nop + srl $t2, $t1, CAUSE_IPSHIFT + addi $t2, $t2, 0x10 +1: + lui $at, %hi(__osIntOffTable) + addu $at, $at, $t2 + lbu $t2, %lo(__osIntOffTable)($at) + lui $at, %hi(__osIntTable) + addu $at, $at, $t2 + lw $t2, %lo(__osIntTable)($at) + jr $t2 + nop + +/** + * IP6 Interrupt + * Only signalled by development hardware + */ +IP6_Hdlr: + // Mask out interrupt and continue + li $at, ~CAUSE_IP6 + b next_interrupt + and $s0, $s0, $at + +/** + * IP7 Interrupt + * Only signalled by development hardware + */ +IP7_Hdlr: + // Mask out interrupt and continue + li $at, ~CAUSE_IP7 + b next_interrupt + and $s0, $s0, $at + +/** + * IP8/Counter Interrupt + * Once the cop0 count register reaches the value of the + * cop0 compare register, this interrupt is triggered + */ +counter: + mfc0 $t1, C0_COMPARE + mtc0 $t1, C0_COMPARE + // Post counter message + jal send_mesg + li $a0, OS_EVENT_COUNTER*8 + // Mask out interrupt and continue + li $at, ~CAUSE_IP8 + b next_interrupt + and $s0, $s0, $at + +/** + * IP4/Cartridge Interrupt + * Signalled by the N64 Disk Drive + */ +cart: + // Load cart callback set by __osSetHWIntrRoutine + lui $t1, %hi(__osHwIntTable) + addiu $t1, %lo(__osHwIntTable) + lw $t2, (OS_INTR_CART*HWINT_SIZE+HWINT_CALLBACK)($t1) + // Mask out interrupt + li $at, ~CAUSE_IP4 + and $s0, $s0, $at + // If the callback is NULL, handling is done + beqz $t2, send_cart_mesg + addi $t1, $t1, (OS_INTR_CART*HWINT_SIZE) + // Set up a stack and run the callback + jalr $t2 + lw $sp, HWINT_SP($t1) + beqz $v0, send_cart_mesg + nop + // Redispatch immediately if the callback returned nonzero + b redispatch + nop +send_cart_mesg: + // Post a cart event message + jal send_mesg + li $a0, OS_EVENT_CART*8 + // Continue + b next_interrupt + nop + +/** + * 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. + lui $t0, %hi(__OSGlobalIntMask) + addiu $t0, %lo(__OSGlobalIntMask) + lw $t0, ($t0) + lui $s1, %hi(PHYS_TO_K1(MI_INTR_REG)) + lw $s1, %lo(PHYS_TO_K1(MI_INTR_REG))($s1) + srl $t0, $t0, RCP_IMASKSHIFT + and $s1, $s1, $t0 + +/** + * Signal Processor (SP) Interrupt + */ +sp: + // Test for sp interrupt + andi $t1, $s1, MI_INTR_SP + beqz $t1, vi + nop + // Test for yielded or done signals in particular + lui $t4, %hi(PHYS_TO_K1(SP_STATUS_REG)) + lw $t4, %lo(PHYS_TO_K1(SP_STATUS_REG))($t4) + li $t1, (SP_CLR_INTR | SP_CLR_SIG3) + lui $at, %hi(PHYS_TO_K1(SP_STATUS_REG)) + andi $t4, $t4, (SP_STATUS_YIELDED | SP_STATUS_TASKDONE) + // Mask out SP interrupt + andi $s1, $s1, (MI_INTR_SI | MI_INTR_AI | MI_INTR_VI | MI_INTR_PI | MI_INTR_DP) + beqz $t4, sp_other_break + // Clear interrupt and signal 3 + sw $t1, %lo(PHYS_TO_K1(SP_STATUS_REG))($at) + // Post an SP event message + jal send_mesg + li $a0, OS_EVENT_SP*8 + beqz $s1, NoMoreRcpInts + nop + // Step over sp_other_break handler + b vi + nop + +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 + jal send_mesg + li $a0, OS_EVENT_SP_BREAK*8 + beqz $s1, NoMoreRcpInts + nop + +/** + * Video Interface (VI) Interrupt + */ +vi: + // Test for vi interrupt + andi $t1, $s1, MI_INTR_VI + beqz $t1, ai + lui $at, %hi(PHYS_TO_K1(VI_CURRENT_REG)) + // 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, %lo(PHYS_TO_K1(VI_CURRENT_REG))($at) + // Post vi event message + jal send_mesg + li $a0, OS_EVENT_VI*8 + beqz $s1, NoMoreRcpInts + nop + +/** + * Audio Interface (AI) Interrupt + */ +ai: + // Test for ai interrupt + andi $t1, $s1, MI_INTR_AI + beqz $t1, si + nop + li $t1, 1 + lui $at, %hi(PHYS_TO_K1(AI_STATUS_REG)) + // Mask out ai interrupt + andi $s1, $s1, (MI_INTR_SP | MI_INTR_SI | MI_INTR_VI | MI_INTR_PI | MI_INTR_DP) + // Clear interrupt + sw $t1, %lo(PHYS_TO_K1(AI_STATUS_REG))($at) + // Post ai event message + jal send_mesg + li $a0, OS_EVENT_AI*8 + beqz $s1, NoMoreRcpInts + nop + +/** + * Serial Interface (SI) Interrupt + */ +si: + // Test for si interrupt + andi $t1, $s1, MI_INTR_SI + beqz $t1, pi + lui $at, %hi(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, %lo(PHYS_TO_K1(SI_STATUS_REG))($at) + // Post si event message + jal send_mesg + li $a0, OS_EVENT_SI*8 + beqz $s1, NoMoreRcpInts + nop + +/** + * Parallel Interface (PI) Interrupt + */ +pi: + // Test for pi interrupt + andi $t1, $s1, MI_INTR_PI + beqz $t1, dp + nop + // Clear interrupt + li $t1, PI_STATUS_CLR_INTR + lui $at, %hi(PHYS_TO_K1(PI_STATUS_REG)) + sw $t1, %lo(PHYS_TO_K1(PI_STATUS_REG))($at) + // Load pi callback + lui $t1, %hi(__osPiIntTable) + addiu $t1, %lo(__osPiIntTable) + lw $t2, HWINT_CALLBACK($t1) + // Mask out pi interrupt + andi $s1, $s1, (MI_INTR_SP | MI_INTR_SI | MI_INTR_AI | MI_INTR_VI | MI_INTR_DP) + // Skip callback if NULL + beqz $t2, no_pi_callback + nop + // Set up a stack and run the callback + lw $sp, HWINT_SP($t1) + jalr $t2 + move $a0, $v0 + // If the callback returns non-zero, don't post a pi event message + bnez $v0, skip_pi_mesg + nop +no_pi_callback: + // Post pi event message + jal send_mesg + li $a0, OS_EVENT_PI*8 +skip_pi_mesg: + beqz $s1, NoMoreRcpInts + nop + +/** + * Display Processor (DP) Interrupt + */ +dp: + // Test for dp interrupt + andi $t1, $s1, MI_INTR_DP + beqz $t1, NoMoreRcpInts + nop + // Clear dp interrupt + li $t1, MI_CLR_DP_INTR + lui $at, %hi(PHYS_TO_K1(MI_INIT_MODE_REG)) + // Mask out dp interrupt + andi $s1, $s1, (MI_INTR_SP | MI_INTR_SI | MI_INTR_AI | MI_INTR_VI | MI_INTR_PI) + sw $t1, %lo(PHYS_TO_K1(MI_INIT_MODE_REG))($at) + // Post dp event message + jal send_mesg + li $a0, OS_EVENT_DP*8 + +NoMoreRcpInts: + // Mask out interrupt and continue + li $at, ~CAUSE_IP3 + b next_interrupt + and $s0, $s0, $at + +/** + * IP5/PreNMI Interrupt + * Reset button has been pressed + */ +prenmi: + // Disable IP5/PreNMI interrupt for the previously running thread + lw $k1, THREAD_SR($k0) + li $at, ~SR_IBIT5 + lui $t1, %hi(__osShutdown) + and $k1, $k1, $at + sw $k1, THREAD_SR($k0) + addiu $t1, %lo(__osShutdown) + // Test __osShutdown for first PreNMI event + lw $t2, ($t1) + beqz $t2, firstnmi + li $at, ~CAUSE_IP5 + // Mask out interrupt and redispatch immediately + b redispatch + and $s0, $s0, $at + +firstnmi: + // Set __osShutdown + li $t2, 1 + sw $t2, ($t1) + // Post a PreNMI event message + jal send_mesg + li $a0, OS_EVENT_PRENMI*8 + // Mask out and disable IP5/PreNMI interrupt for the highest priority thread + lui $t2, %hi(__osRunQueue) + lw $t2, %lo(__osRunQueue)($t2) + li $at, ~SR_IBIT5 + and $s0, $s0, $at + lw $k1, THREAD_SR($t2) + and $k1, $k1, $at + // Redispatch immediately + b redispatch + sw $k1, THREAD_SR($t2) + +sw2: + // Mask out interrupt + li $at, ~CAUSE_SW2 + and $t0, $t0, $at + mtc0 $t0, C0_CAUSE + // Post sw2 event message + jal send_mesg + li $a0, OS_EVENT_SW2*8 + li $at, ~CAUSE_SW2 + // Mask out interrupt and continue + b next_interrupt + and $s0, $s0, $at + +sw1: + // Mask out interrupt + li $at, ~CAUSE_SW1 + and $t0, $t0, $at + mtc0 $t0, C0_CAUSE + // Post sw1 event message + jal send_mesg + li $a0, OS_EVENT_SW1*8 + li $at, ~CAUSE_SW1 + // Mask out interrupt and continue + b next_interrupt + and $s0, $s0, $at + +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 + jal send_mesg + li $a0, OS_EVENT_CPU_BREAK*8 + // Redispatch + b redispatch + nop + +redispatch: + lui $t2, %hi(__osRunQueue) + lw $t2, %lo(__osRunQueue)($t2) + // Get priority of previously running thread + lw $t1, THREAD_PRI($k0) + // Get highest priority from waiting threads + lw $t3, THREAD_PRI($t2) + slt $at, $t1, $t3 + beqz $at, enqueueRunning + nop + // The previously running thread is no longer the highest priority, + // enqueue it to the run queue to wait its turn again + lui $a0, %hi(__osRunQueue) + move $a1, $k0 + jal __osEnqueueThread + addiu $a0, $a0, %lo(__osRunQueue) + j __osDispatchThread + nop + +/** + * Resume the previously running thread by placing it at the top of + * the run queue and dispatching it + */ +enqueueRunning: + lui $t1, %hi(__osRunQueue) + addiu $t1, $t1, %lo(__osRunQueue) + lw $t2, ($t1) + sw $t2, THREAD_NEXT($k0) + j __osDispatchThread + sw $k0, ($t1) + +/** + * Unhandled exceptions & interrupts end up here, + * trap to software by posting a fault message + */ +panic: + // Mark the thread as having faulted + lui $at, %hi(__osFaultedThread) + sw $k0, %lo(__osFaultedThread)($at) + li $t1, OS_STATE_STOPPED + sh $t1, THREAD_STATE($k0) + li $t1, OS_FLAG_FAULT + sh $t1, THREAD_FLAGS($k0) + // Save C0_BADVADDR + mfc0 $t2, C0_BADVADDR + sw $t2, THREAD_BADVADDR($k0) + // Post the fault message + jal send_mesg + li $a0, OS_EVENT_FAULT*8 + // Dispatch next thread + j __osDispatchThread + nop + +/** + * Handles posting event messages to the listening message queue, if there is one + */ +send_mesg: + // Load pointer to listening message queue + lui $t2, %hi(__osEventStateTab) + addiu $t2, %lo(__osEventStateTab) + addu $t2, $t2, $a0 + lw $t1, ($t2) + // Save return address + move $s2, $ra + // If there is no listening message queue, done + beqz $t1, send_done + nop + // Test if the message queue is full, if so don't post the message + lw $t3, MQ_VALIDCOUNT($t1) + lw $t4, MQ_MSGCOUNT($t1) + slt $at, $t3, $t4 + beqz $at, send_done + nop + // Add validcount to first and modulo with msgcount + lw $t5, MQ_FIRST($t1) + addu $t5, $t5, $t3 + // Modulo + div $zero, $t5, $t4 + bnez $t4, 1f + nop + break 7 // div0 +1: + li $at, -1 + bne $t4, $at, 2f + li $at, -0x80000000 + bne $t5, $at, 2f + nop + break 6 // overflow +2: + // End Modulo + lw $t4, MQ_MSG($t1) + mfhi $t5 + sll $t5, $t5, 2 + addu $t4, $t4, $t5 + // Fetch the message to post + lw $t5, 4($t2) + addiu $t2, $t3, 1 + // Post the message to the message queue + sw $t5, ($t4) + // Increment the validCount + 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, ($t2) + beqz $t3, send_done + nop + jal __osPopThread + move $a0, $t1 + move $t2, $v0 + lui $a0, %hi(__osRunQueue) + move $a1, $t2 + jal __osEnqueueThread + addiu $a0, %lo(__osRunQueue) +send_done: + jr $s2 + nop + +/** + * Handle coprocessor unusable exception + */ +handle_CpU: + li $at, CAUSE_CEMASK + and $t1, $t0, $at + srl $t1, $t1, CAUSE_CESHIFT + li $t2, 1 // if not coprocessor 1, panic + bne $t1, $t2, panic + nop + // Mark cop1 as usable for previous thread + lw $k1, THREAD_SR($k0) + li $at, SR_CU1 + li $t1, 1 + or $k1, $k1, $at + sw $t1, THREAD_FP($k0) + b enqueueRunning + sw $k1, THREAD_SR($k0) +END(__osException) + +/** + * 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) + lui $a1, %hi(__osRunningThread) + lw $a1, %lo(__osRunningThread)($a1) + // Save SR + mfc0 $t0, C0_SR + lw $k1, THREAD_FP($a1) + ori $t0, $t0, SR_EXL + sw $t0, THREAD_SR($a1) + // Save callee-saved registers + sd $s0, THREAD_S0($a1) + sd $s1, THREAD_S1($a1) + sd $s2, THREAD_S2($a1) + sd $s3, THREAD_S3($a1) + sd $s4, THREAD_S4($a1) + sd $s5, THREAD_S5($a1) + sd $s6, THREAD_S6($a1) + sd $s7, THREAD_S7($a1) + sd $gp, THREAD_GP($a1) + sd $sp, THREAD_SP($a1) + sd $fp, THREAD_S8($a1) + sd $ra, THREAD_RA($a1) + // Save FPU callee-saved registers if the current thread has used the FPU + beqz $k1, 1f + sw $ra, THREAD_PC($a1) + cfc1 $k1, C1_FPCSR + sdc1 $f20, THREAD_FP20($a1) + sdc1 $f22, THREAD_FP22($a1) + sdc1 $f24, THREAD_FP24($a1) + sdc1 $f26, THREAD_FP26($a1) + sdc1 $f28, THREAD_FP28($a1) + sdc1 $f30, THREAD_FP30($a1) + sw $k1, THREAD_FPCSR($a1) +1: + lw $k1, THREAD_SR($a1) + andi $t1, $k1, SR_IMASK + beqz $t1, 2f + nop + // This code does the same thing as the block just above the `savercp` label. + // See the comment there for more about this. + lui $t0, %hi(__OSGlobalIntMask) + addiu $t0, %lo(__OSGlobalIntMask) + lw $t0, ($t0) + li $at, ~0 + xor $t0, $t0, $at + lui $at, ((~SR_IMASK) >> 0x10) & 0xFFFF + andi $t0, $t0, SR_IMASK + ori $at, (~SR_IMASK) & 0xFFFF + or $t1, $t1, $t0 + and $k1, $k1, $at + or $k1, $k1, $t1 + sw $k1, THREAD_SR($a1) +2: + lui $k1, %hi(PHYS_TO_K1(MI_INTR_MASK_REG)) + lw $k1, %lo(PHYS_TO_K1(MI_INTR_MASK_REG))($k1) + beqz $k1, 3f + nop + // This code does the same thing as the block just below the `savercp` label. + // See the comment there for more about this. + lui $k0, %hi(__OSGlobalIntMask) + addiu $k0, %lo(__OSGlobalIntMask) + lw $k0, ($k0) + lw $t0, THREAD_RCP($a1) + li $at, ~0 + srl $k0, $k0, RCP_IMASKSHIFT + xor $k0, $k0, $at + andi $k0, $k0, (RCP_IMASK >> RCP_IMASKSHIFT) + and $k0, $k0, $t0 + or $k1, $k1, $k0 +3: + // If the specified thread queue is null, skip + // straight to dispatching + beqz $a0, no_enqueue + sw $k1, THREAD_RCP($a1) + jal __osEnqueueThread + nop +no_enqueue: + j __osDispatchThread + nop +END(__osEnqueueAndYield) + +/** + * void __osEnqueueThread(OSThread** threadQueue, OSThread* thread); + * + * Enqueues `thread` to the thread queue `threadQueue`, inserted by priority + */ +LEAF(__osEnqueueThread) + lw $t8, ($a0) + lw $t7, THREAD_PRI($a1) + move $t9, $a0 + lw $t6, THREAD_PRI($t8) + slt $at, $t6, $t7 + // If the current highest priority thread is a lower priority than + // the new thread, skip searching the queue + bnez $at, 2f + nop +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 $t6, THREAD_PRI($t8) + slt $at, $t6, $t7 + beqz $at, 1b + nop +2: + // Insert the thread into the queue + lw $t8, ($t9) + sw $t8, THREAD_NEXT($a1) + sw $a1, ($t9) + jr $ra + sw $a0, THREAD_QUEUE($a1) +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, ($a0) + lw $t9, THREAD_NEXT($v0) + jr $ra + sw $t9, ($a0) +END(__osPopThread) + +LEAF(__osNop) + jr $ra + nop +END(__osNop) + +/** + * void __osDispatchThread(void); + * + * Dispatches the next thread to run after restoring the context + */ +LEAF(__osDispatchThread) + // Obtain highest priority thread from the active run queue + lui $a0, %hi(__osRunQueue) + jal __osPopThread + addiu $a0, $a0, %lo(__osRunQueue) + // Set thread as running + lui $at, %hi(__osRunningThread) + sw $v0, %lo(__osRunningThread)($at) + 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 + lui $t0, %hi(__OSGlobalIntMask) + lw $k1, THREAD_SR($k0) + addiu $t0, %lo(__OSGlobalIntMask) + lw $t0, ($t0) + lui $at, ((~SR_IMASK) >> 0x10) & 0xFFFF + andi $t1, $k1, SR_IMASK + ori $at, (~SR_IMASK) & 0xFFFF + andi $t0, $t0, SR_IMASK + and $t1, $t1, $t0 + and $k1, $k1, $at + or $k1, $k1, $t1 + mtc0 $k1, C0_SR + // Restore GPRs + ld $k1, THREAD_LO($k0) + ld $at, THREAD_AT($k0) + ld $v0, THREAD_V0($k0) + mtlo $k1 + ld $k1, THREAD_HI($k0) + ld $v1, THREAD_V1($k0) + ld $a0, THREAD_A0($k0) + ld $a1, THREAD_A1($k0) + ld $a2, THREAD_A2($k0) + ld $a3, THREAD_A3($k0) + ld $t0, THREAD_T0($k0) + ld $t1, THREAD_T1($k0) + ld $t2, THREAD_T2($k0) + ld $t3, THREAD_T3($k0) + ld $t4, THREAD_T4($k0) + ld $t5, THREAD_T5($k0) + ld $t6, THREAD_T6($k0) + ld $t7, THREAD_T7($k0) + ld $s0, THREAD_S0($k0) + ld $s1, THREAD_S1($k0) + ld $s2, THREAD_S2($k0) + ld $s3, THREAD_S3($k0) + ld $s4, THREAD_S4($k0) + ld $s5, THREAD_S5($k0) + ld $s6, THREAD_S6($k0) + ld $s7, THREAD_S7($k0) + ld $t8, THREAD_T8($k0) + ld $t9, THREAD_T9($k0) + ld $gp, THREAD_GP($k0) + mthi $k1 + ld $sp, THREAD_SP($k0) + ld $fp, THREAD_S8($k0) + ld $ra, THREAD_RA($k0) + // Move thread pc to EPC so that eret will return execution to where the thread left off + lw $k1, THREAD_PC($k0) + 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 + nop + lw $k1, THREAD_FPCSR($k0) + ctc1 $k1, C1_FPCSR + ldc1 $f0, THREAD_FP0($k0) + ldc1 $f2, THREAD_FP2($k0) + ldc1 $f4, THREAD_FP4($k0) + ldc1 $f6, THREAD_FP6($k0) + ldc1 $f8, THREAD_FP8($k0) + ldc1 $f10, THREAD_FP10($k0) + ldc1 $f12, THREAD_FP12($k0) + ldc1 $f14, THREAD_FP14($k0) + ldc1 $f16, THREAD_FP16($k0) + ldc1 $f18, THREAD_FP18($k0) + ldc1 $f20, THREAD_FP20($k0) + ldc1 $f22, THREAD_FP22($k0) + ldc1 $f24, THREAD_FP24($k0) + 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 + lw $k1, THREAD_RCP($k0) + lui $k0, %hi(__OSGlobalIntMask) + addiu $k0, %lo(__OSGlobalIntMask) + lw $k0, ($k0) + srl $k0, $k0, RCP_IMASKSHIFT + and $k1, $k1, $k0 + sll $k1, $k1, 1 + lui $k0, %hi(__osRcpImTable) + addiu $k0, %lo(__osRcpImTable) + addu $k1, $k1, $k0 + lhu $k1, ($k1) + lui $k0, %hi(PHYS_TO_K1(MI_INTR_MASK_REG)) + addiu $k0, %lo(PHYS_TO_K1(MI_INTR_MASK_REG)) + sw $k1, ($k0) + // Empty pipeline + nop + nop + nop + nop + // Resume thread execution + eret +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) + jal osDestroyThread + move $a0, $zero + // Despite being a jal, this function does not return as the thread will have been destroyed +END(__osCleanupThread) diff --git a/src/libultra/os/getcause.s b/src/libultra/os/getcause.s new file mode 100644 index 000000000..48fbf3236 --- /dev/null +++ b/src/libultra/os/getcause.s @@ -0,0 +1,14 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noreorder + +.section .text + +.balign 16 + +LEAF(__osGetCause) + mfc0 $v0, C0_CAUSE + jr $ra + nop +END(__osGetCause) diff --git a/src/libultra/os/getcount.s b/src/libultra/os/getcount.s new file mode 100644 index 000000000..bad47d0bc --- /dev/null +++ b/src/libultra/os/getcount.s @@ -0,0 +1,14 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noreorder + +.section .text + +.balign 16 + +LEAF(osGetCount) + mfc0 $v0, C0_COUNT + jr $ra + nop +END(osGetCount) diff --git a/src/libultra/os/getfpccsr.s b/src/libultra/os/getfpccsr.s new file mode 100644 index 000000000..d86734ad0 --- /dev/null +++ b/src/libultra/os/getfpccsr.s @@ -0,0 +1,14 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noreorder + +.section .text + +.balign 16 + +LEAF(__osGetFpcCsr) + cfc1 $v0, C1_FPCSR + jr $ra + nop +END(__osGetFpcCsr) diff --git a/src/libultra/os/getsr.s b/src/libultra/os/getsr.s new file mode 100644 index 000000000..aed66d40a --- /dev/null +++ b/src/libultra/os/getsr.s @@ -0,0 +1,14 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noreorder + +.section .text + +.balign 16 + +LEAF(__osGetSR) + mfc0 $v0, C0_SR + jr $ra + nop +END(__osGetSR) diff --git a/src/libultra/os/interrupt.s b/src/libultra/os/interrupt.s new file mode 100644 index 000000000..82090742b --- /dev/null +++ b/src/libultra/os/interrupt.s @@ -0,0 +1,53 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" +#include "ultra64/thread.h" + +.set noat +.set noreorder + +.section .text + +.balign 16 + +LEAF(__osDisableInt) + lui $t2, %hi(__OSGlobalIntMask) + addiu $t2, $t2, %lo(__OSGlobalIntMask) + lw $t3, ($t2) + andi $t3, $t3, SR_IMASK + mfc0 $t0, C0_SR + li $at, ~SR_IE + and $t1, $t0, $at + mtc0 $t1, C0_SR + andi $v0, $t0, SR_IE + lw $t0, ($t2) + andi $t0, $t0, SR_IMASK + beq $t0, $t3, No_Change_Global_Int + lui $t2, %hi(__osRunningThread) + //! @bug this addiu should be lw, it may never come up in practice as to reach this code + //! the CPU bits of __OSGlobalIntMask must have changed while this function is running. + addiu $t2, $t2, %lo(__osRunningThread) + lw $t1, THREAD_SR($t2) + andi $t2, $t1, SR_IMASK + and $t2, $t2, $t0 + li $at, ~SR_IMASK + and $t1, $t1, $at + or $t1, $t1, $t2 + li $at, ~SR_IE + and $t1, $t1, $at + mtc0 $t1, C0_SR + nop + nop +No_Change_Global_Int: + jr $ra + nop +END(__osDisableInt) + +LEAF(__osRestoreInt) + mfc0 $t0, C0_SR + or $t0, $t0, $a0 + mtc0 $t0, C0_SR + nop + nop + jr $ra + nop +END(__osRestoreInt) diff --git a/src/libultra/os/invaldcache.s b/src/libultra/os/invaldcache.s new file mode 100644 index 000000000..41799d318 --- /dev/null +++ b/src/libultra/os/invaldcache.s @@ -0,0 +1,94 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noat +.set noreorder + +.section .text + +.balign 16 + +/** + * 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 + nop + // If the amount to invalidate is as large as or larger than + // the data cache size, invalidate all + li $t3, DCACHE_SIZE + sltu $at, $a1, $t3 + beqz $at, 4f + nop + // Ensure end address doesn't wrap around and end up smaller + // than the start address + move $t0, $a0 + addu $t1, $a0, $a1 + sltu $at, $t0, $t1 + beqz $at, 3f + nop + // Mask start with cache line + andi $t2, $t0, DCACHE_LINEMASK + // If mask is not zero, the start is not cache aligned + beqz $t2, 1f + addiu $t1, $t1, -DCACHE_LINESIZE + // Subtract mask result to align to cache line + subu $t0, $t0, $t2 + // Hit-Writeback-Invalidate unaligned part + cache (CACH_PD | C_HWBINV), ($t0) + sltu $at, $t0, $t1 + // If that's all there is to do, return early + beqz $at, 3f + nop + 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, 1f + nop + // Subtract mask result to align to cache line + subu $t1, $t1, $t2 + // Hit-Writeback-Invalidate unaligned part + cache (CACH_PD | C_HWBINV), DCACHE_LINESIZE($t1) + sltu $at, $t1, $t0 + // If that's all there is to do, return early + bnez $at, 3f + nop + // Invalidate the rest +1: + // Hit-Invalidate + cache (CACH_PD | C_HINV), ($t0) + sltu $at, $t0, $t1 + bnez $at, 1b + addiu $t0, $t0, DCACHE_LINESIZE +3: + jr $ra + nop + +4: + li $t0, K0BASE + addu $t1, $t0, $t3 + addiu $t1, $t1, -DCACHE_LINESIZE +5: + // Index-Writeback-Invalidate + cache (CACH_PD | C_IWBINV), ($t0) + sltu $at, $t0, $t1 + bnez $at, 5b + addiu $t0, DCACHE_LINESIZE + jr $ra + nop +END(osInvalDCache) diff --git a/src/libultra/os/invalicache.s b/src/libultra/os/invalicache.s new file mode 100644 index 000000000..79d576fba --- /dev/null +++ b/src/libultra/os/invalicache.s @@ -0,0 +1,52 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noat +.set noreorder + +.section .text + +.balign 16 + +LEAF(osInvalICache) + // If the amount to invalidate is less than or equal to 0, return immediately + blez $a1, 2f + nop + // If the amount to invalidate is as large as or larger than + // the instruction cache size, invalidate all + li $t3, ICACHE_SIZE + sltu $at, $a1, $t3 + beqz $at, 3f + nop + // ensure end address doesn't wrap around and end up smaller + // than the start address + move $t0, $a0 + addu $t1, $a0, $a1 + sltu $at, $t0, $t1 + beqz $at, 2f + nop + // Mask and subtract to align to cache line + andi $t2, $t0, ICACHE_LINEMASK + addiu $t1, $t1, -ICACHE_LINESIZE + subu $t0, $t0, $t2 +1: + cache (CACH_PI | C_HINV), ($t0) + sltu $at, $t0, $t1 + bnez $at, 1b + addiu $t0, $t0, ICACHE_LINESIZE +2: + jr $ra + nop + +3: + li $t0, K0BASE + addu $t1, $t0, $t3 + addiu $t1, $t1, -ICACHE_LINESIZE +4: + cache (CACH_PI | C_IINV), ($t0) + sltu $at, $t0, $t1 + bnez $at, 4b + addiu $t0, ICACHE_LINESIZE + jr $ra + nop +END(osInvalICache) diff --git a/src/libultra/os/maptlbrdb.s b/src/libultra/os/maptlbrdb.s new file mode 100644 index 000000000..ea8fe4aa4 --- /dev/null +++ b/src/libultra/os/maptlbrdb.s @@ -0,0 +1,36 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" +#include "ultra64/rdb.h" + +.set noreorder + +.section .text + +.balign 16 + +LEAF(osMapTLBRdb) + mfc0 $t0, C0_ENTRYHI + li $t1, NTLBENTRIES + mtc0 $t1, C0_INX + mtc0 $zero, C0_PAGEMASK + li $t2, (TLBLO_UNCACHED | TLBLO_D | TLBLO_V | TLBLO_G) + li $t1, (RDB_BASE_REG & TLBHI_VPN2MASK) + mtc0 $t1, C0_ENTRYHI + // Possible bug? Virtual address instead of physical address + // set as page frame number + li $t1, RDB_BASE_VIRTUAL_ADDR + srl $t3, $t1, TLBLO_PFNSHIFT + or $t3, $t3, $t2 + mtc0 $t3, C0_ENTRYLO0 + li $t1, TLBLO_G + mtc0 $t1, C0_ENTRYLO1 + nop + tlbwi + nop + nop + nop + nop + mtc0 $t0, C0_ENTRYHI + jr $ra + nop +END(osMapTLBRdb) diff --git a/src/libultra/os/parameters.s b/src/libultra/os/parameters.s new file mode 100644 index 000000000..c0020ddbe --- /dev/null +++ b/src/libultra/os/parameters.s @@ -0,0 +1,22 @@ +#include "ultra64/asm.h" + +.section .text + +.macro IPL_SYMBOL name, address, size + .global \name + .set \name, \address + .type \name, @object + .size \name, \size +.endm + +IPL_SYMBOL leoBootID, 0x800001A0, 4 +IPL_SYMBOL osTvType, 0x80000300, 4 +IPL_SYMBOL osRomType, 0x80000304, 4 +IPL_SYMBOL osRomBase, 0x80000308, 4 +IPL_SYMBOL osResetType, 0x8000030C, 4 +IPL_SYMBOL osCicId, 0x80000310, 4 +IPL_SYMBOL osVersion, 0x80000314, 4 +IPL_SYMBOL osMemSize, 0x80000318, 4 +IPL_SYMBOL osAppNMIBuffer, 0x8000031C, 0x40 + +.fill 0x60 diff --git a/src/libultra/os/probetlb.s b/src/libultra/os/probetlb.s new file mode 100644 index 000000000..ce655faca --- /dev/null +++ b/src/libultra/os/probetlb.s @@ -0,0 +1,86 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noat +.set noreorder + +.section .text + +.balign 16 + +/** + * 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 + li $at, TLBHI_VPN2MASK + and $t2, $a0, $at + 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 + li $at, TLBINX_PROBE + and $t3, $t3, $at + // 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, 0x2000 + srl $t3, $t3, 1 + // & with vaddr + and $t4, $t3, $a0 + // Select C0_ENTRYLO0 or C0_ENTRYLO1 + bnez $t4, 1f + addi $t3, $t3, -1 // make bitmask out of page size + mfc0 $v0, C0_ENTRYLO0 + b 2f + nop +1: + mfc0 $v0, C0_ENTRYLO1 +2: + // Check valid bit and branch if not valid + andi $t5, $v0, TLBLO_V + beqz $t5, 3f + nop + // Extract the Page Frame Number from the entry + li $at, TLBLO_PFNMASK + and $v0, $v0, $at + sll $v0, $v0, TLBLO_PFNSHIFT + // Mask vaddr with page size mask + and $t5, $a0, $t3 + // Add masked vaddr to pfn to obtain the physical address + add $v0, $v0, $t5 + b 4f + nop +3: + // No physical address for the supplied virtual address was found, + // return -1 + li $v0, -1 +4: + // Restore original C0_ENTRYHI value before returning + mtc0 $t0, C0_ENTRYHI + jr $ra + nop +END(__osProbeTLB) diff --git a/src/libultra/os/setcompare.s b/src/libultra/os/setcompare.s new file mode 100644 index 000000000..4b69b2ea9 --- /dev/null +++ b/src/libultra/os/setcompare.s @@ -0,0 +1,14 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noreorder + +.section .text + +.balign 16 + +LEAF(__osSetCompare) + mtc0 $a0, C0_COMPARE + jr $ra + nop +END(__osSetCompare) diff --git a/src/libultra/os/setfpccsr.s b/src/libultra/os/setfpccsr.s new file mode 100644 index 000000000..9b6b368f3 --- /dev/null +++ b/src/libultra/os/setfpccsr.s @@ -0,0 +1,15 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noreorder + +.section .text + +.balign 16 + +LEAF(__osSetFpcCsr) + cfc1 $v0, C1_FPCSR + ctc1 $a0, C1_FPCSR + jr $ra + nop +END(__osSetFpcCsr) diff --git a/src/libultra/os/setintmask.s b/src/libultra/os/setintmask.s new file mode 100644 index 000000000..3afadb73a --- /dev/null +++ b/src/libultra/os/setintmask.s @@ -0,0 +1,168 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" +#include "ultra64/rcp.h" +#include "ultra64/exception.h" + +.set noat +.set noreorder + +.section .rodata + +.balign 16 + +/** + * LUT to convert between an interrupt mask value and a value for MI_INTR_MASK_REG. + * The interrupt mask value is a single bit 0 = disabled, 1 = enabled, while writes to MI_INTR_MASK_REG has two distinct non-zero + * values for set and clear, hence the need for a conversion step. + */ +DATA(__osRcpImTable) + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP + .half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP +ENDDATA(__osRcpImTable) + +.section .text + +.balign 16 + +/** + * 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 $t4, C0_SR + andi $v0, $t4, (SR_IMASK | SR_IE) + // Get value of __OSGlobalIntMask + lui $t0, %hi(__OSGlobalIntMask) + addiu $t0, %lo(__OSGlobalIntMask) + lw $t3, ($t0) + // Bitwise-OR in the disabled CPU bits of __OSGlobalIntMask + li $at, ~0 + xor $t0, $t3, $at + andi $t0, $t0, SR_IMASK + or $v0, $v0, $t0 + // Fetch MI_INTR_MASK_REG + lui $t2, %hi(PHYS_TO_K1(MI_INTR_MASK_REG)) + lw $t2, %lo(PHYS_TO_K1(MI_INTR_MASK_REG))($t2) + // If there are RCP interrupts masked + beqz $t2, 1f + srl $t1, $t3, RCP_IMASKSHIFT + // Bitwise-OR in the disabled RCP bits of __OSGlobalIntMask + li $at, ~0 + xor $t1, $t1, $at + andi $t1, $t1, (RCP_IMASK >> RCP_IMASKSHIFT) + or $t2, $t2, $t1 +1: + // 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 + // Extract RCP interrupt enable bits from requested mask and mask with __OSGlobalIntMask + li $at, RCP_IMASK + and $t0, $a0, $at + and $t0, $t0, $t3 + // Convert to a value for MI_INTR_MASK_REG and set it + srl $t0, $t0, (RCP_IMASKSHIFT-1) + lui $t2, %hi(__osRcpImTable) + addu $t2, $t2, $t0 + lhu $t2, %lo(__osRcpImTable)($t2) + lui $at, %hi(PHYS_TO_K1(MI_INTR_MASK_REG)) + sw $t2, %lo(PHYS_TO_K1(MI_INTR_MASK_REG))($at) + // 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 + li $at, ~SR_IMASK + and $t4, $t4, $at + // Bitwise OR in the remaining bits of SR and set new SR + or $t4, $t4, $t0 + mtc0 $t4, C0_SR + nop + nop + jr $ra + nop +END(osSetIntMask) diff --git a/src/libultra/os/setsr.s b/src/libultra/os/setsr.s new file mode 100644 index 000000000..382f2eada --- /dev/null +++ b/src/libultra/os/setsr.s @@ -0,0 +1,15 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noreorder + +.section .text + +.balign 16 + +LEAF(__osSetSR) + mtc0 $a0, C0_SR + nop + jr $ra + nop +END(__osSetSR) diff --git a/src/libultra/os/setwatchlo.s b/src/libultra/os/setwatchlo.s new file mode 100644 index 000000000..749b1dbd8 --- /dev/null +++ b/src/libultra/os/setwatchlo.s @@ -0,0 +1,15 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noreorder + +.section .text + +.balign 16 + +LEAF(__osSetWatchLo) + mtc0 $a0, C0_WATCHLO + nop + jr $ra + nop +END(__osSetWatchLo) diff --git a/src/libultra/os/unmaptlball.s b/src/libultra/os/unmaptlball.s new file mode 100644 index 000000000..d7fe7cf53 --- /dev/null +++ b/src/libultra/os/unmaptlball.s @@ -0,0 +1,29 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noreorder + +.section .text + +.balign 16 + +LEAF(osUnmapTLBAll) + mfc0 $t0, C0_ENTRYHI + li $t1, (NTLBENTRIES - 1) + li $t2, (K0BASE & TLBHI_VPN2MASK) + mtc0 $t2, C0_ENTRYHI + mtc0 $zero, C0_ENTRYLO0 + mtc0 $zero, C0_ENTRYLO1 +1: + mtc0 $t1, C0_INX + nop + tlbwi + nop + nop + addi $t1, $t1, -1 + bgez $t1, 1b + nop + mtc0 $t0, C0_ENTRYHI + jr $ra + nop +END(osUnmapTLBAll) diff --git a/src/libultra/os/writebackdcache.s b/src/libultra/os/writebackdcache.s new file mode 100644 index 000000000..4eea0d83a --- /dev/null +++ b/src/libultra/os/writebackdcache.s @@ -0,0 +1,60 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noat +.set noreorder + +.section .text + +.balign 16 + +/** + * 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, .ret + nop + // If the amount to write back is as large as or larger than + // the data cache size, write back all + li $t3, DCACHE_SIZE + sltu $at, $a1, $t3 + beqz $at, .all + nop + // ensure end address doesn't wrap around and end up smaller + // than the start address + move $t0, $a0 + addu $t1, $a0, $a1 + sltu $at, $t0, $t1 + beqz $at, .ret + nop + // Mask and subtract to align to cache line + andi $t2, $t0, DCACHE_LINEMASK + addiu $t1, $t1, -DCACHE_LINESIZE + subu $t0, $t0, $t2 +1: + cache (CACH_PD | C_HWB), ($t0) + sltu $at, $t0, $t1 + bnez $at, 1b + addiu $t0, $t0, DCACHE_LINESIZE +.ret: + jr $ra + nop + +// same as osWritebackDCacheAll in operation +.all: + li $t0, K0BASE + addu $t1, $t0, $t3 + addiu $t1, $t1, -DCACHE_LINESIZE +1: + cache (CACH_PD | C_IWBINV), ($t0) + sltu $at, $t0, $t1 + bnez $at, 1b + addiu $t0, DCACHE_LINESIZE + jr $ra + nop +END(osWritebackDCache) diff --git a/src/libultra/os/writebackdcacheall.s b/src/libultra/os/writebackdcacheall.s new file mode 100644 index 000000000..837495c76 --- /dev/null +++ b/src/libultra/os/writebackdcacheall.s @@ -0,0 +1,23 @@ +#include "ultra64/asm.h" +#include "ultra64/r4300.h" + +.set noat +.set noreorder + +.section .text + +.balign 16 + +LEAF(osWritebackDCacheAll) + li $t0, K0BASE + li $t2, DCACHE_SIZE + addu $t1, $t0, $t2 + addiu $t1, $t1, -DCACHE_LINESIZE +1: + cache (CACH_PD | C_IWBINV), ($t0) + sltu $at, $t0, $t1 + bnez $at, 1b + addiu $t0, DCACHE_LINESIZE + jr $ra + nop +END(osWritebackDCacheAll) diff --git a/src/makerom/entry.s b/src/makerom/entry.s new file mode 100644 index 000000000..6be493e6b --- /dev/null +++ b/src/makerom/entry.s @@ -0,0 +1,34 @@ +#include "ultra64/asm.h" +#include "boot.h" + +.set noreorder + +.section .text + +.balign 16 + +LEAF(entrypoint) + // Clear boot segment .bss + la $t0, _bootSegmentBssStart +#ifndef AVOID_UB + // UB: li only loads the lower 16 bits of _bootSegmentBssSize when it may be larger than this, + // so not all of bss may be cleared if it is too large + li $t1, _bootSegmentBssSize +#else + la $t1, _bootSegmentBssSize +#endif +.clear_bss: + addi $t1, $t1, -8 + sw $zero, ($t0) + sw $zero, 4($t0) + bnez $t1, .clear_bss + addi $t0, $t0, 8 + // Set up stack and enter program code + lui $t2, %hi(bootproc) + lui $sp, %hi(sBootThreadStack + BOOT_STACK_SIZE) + addiu $t2, %lo(bootproc) + jr $t2 + addiu $sp, %lo(sBootThreadStack + BOOT_STACK_SIZE) +END(entrypoint) + +.fill 0x60 - (. - entrypoint) diff --git a/src/makerom/ipl3.s b/src/makerom/ipl3.s new file mode 100644 index 000000000..2efa7b53d --- /dev/null +++ b/src/makerom/ipl3.s @@ -0,0 +1,4 @@ + +.section .text + +.incbin "baserom.z64", 0x40, 0xFC0 diff --git a/src/makerom/rom_header.s b/src/makerom/rom_header.s new file mode 100644 index 000000000..883b8b0ab --- /dev/null +++ b/src/makerom/rom_header.s @@ -0,0 +1,18 @@ +/* + * The Legend of Zelda: Ocarina of Time ROM header + */ + +.byte 0x80, 0x37, 0x12, 0x40 /* PI BSD Domain 1 register */ +.word 0x0000000F /* Clockrate setting */ +.word 0x80000400 /* Entrypoint function (`entrypoint`) */ +.word 0x0000144C /* Revision */ +.word 0x917D18F6 /* Checksum 1 */ +.word 0x69BC5453 /* Checksum 2 */ +.word 0x00000000 /* Unknown */ +.word 0x00000000 /* Unknown */ +.ascii "THE LEGEND OF ZELDA " /* Internal ROM name */ +.word 0x00000000 /* Unknown */ +.word 0x0000004E /* Cartridge */ +.ascii "ZL" /* Cartridge ID */ +.ascii "P" /* Region */ +.byte 0x0F /* Version */ |
