mirror of
https://github.com/zeldaret/oot
synced 2026-08-08 18:43:38 -04:00
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
This commit is contained in:
@@ -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)
|
||||
+165
@@ -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)
|
||||
@@ -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)
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "ultra64/asm.h"
|
||||
|
||||
.section .rodata
|
||||
|
||||
.balign 16
|
||||
|
||||
DATA(__libm_qnan_f)
|
||||
.word 0x7F810000
|
||||
ENDDATA(__libm_qnan_f)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
.section .text
|
||||
|
||||
.incbin "baserom.z64", 0x40, 0xFC0
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user