mirror of
https://github.com/zeldaret/oot.git
synced 2025-08-10 08:50:23 +00: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:
parent
e989cb7ace
commit
4775fd4a7e
39 changed files with 47 additions and 59 deletions
9
src/libultra/gu/libm_vals.s
Normal file
9
src/libultra/gu/libm_vals.s
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include "ultra64/asm.h"
|
||||
|
||||
.section .rodata
|
||||
|
||||
.balign 16
|
||||
|
||||
DATA(__libm_qnan_f)
|
||||
.word 0x7F810000
|
||||
ENDDATA(__libm_qnan_f)
|
93
src/libultra/libc/bcmp.s
Normal file
93
src/libultra/libc/bcmp.s
Normal file
|
@ -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)
|
233
src/libultra/libc/bcopy.s
Normal file
233
src/libultra/libc/bcopy.s
Normal file
|
@ -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)
|
65
src/libultra/libc/bzero.s
Normal file
65
src/libultra/libc/bzero.s
Normal file
|
@ -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)
|
40
src/libultra/mgu/mtxf2l.s
Normal file
40
src/libultra/mgu/mtxf2l.s
Normal file
|
@ -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)
|
29
src/libultra/mgu/mtxident.s
Normal file
29
src/libultra/mgu/mtxident.s
Normal file
|
@ -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)
|
28
src/libultra/mgu/mtxidentf.s
Normal file
28
src/libultra/mgu/mtxidentf.s
Normal file
|
@ -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)
|
41
src/libultra/mgu/mtxl2f.s
Normal file
41
src/libultra/mgu/mtxl2f.s
Normal file
|
@ -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)
|
31
src/libultra/mgu/normalize.s
Normal file
31
src/libultra/mgu/normalize.s
Normal file
|
@ -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)
|
52
src/libultra/mgu/scale.s
Normal file
52
src/libultra/mgu/scale.s
Normal file
|
@ -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)
|
61
src/libultra/mgu/translate.s
Normal file
61
src/libultra/mgu/translate.s
Normal file
|
@ -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)
|
982
src/libultra/os/exceptasm.s
Normal file
982
src/libultra/os/exceptasm.s
Normal file
|
@ -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)
|
14
src/libultra/os/getcause.s
Normal file
14
src/libultra/os/getcause.s
Normal file
|
@ -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)
|
14
src/libultra/os/getcount.s
Normal file
14
src/libultra/os/getcount.s
Normal file
|
@ -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)
|
14
src/libultra/os/getfpccsr.s
Normal file
14
src/libultra/os/getfpccsr.s
Normal file
|
@ -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)
|
14
src/libultra/os/getsr.s
Normal file
14
src/libultra/os/getsr.s
Normal file
|
@ -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)
|
53
src/libultra/os/interrupt.s
Normal file
53
src/libultra/os/interrupt.s
Normal file
|
@ -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)
|
94
src/libultra/os/invaldcache.s
Normal file
94
src/libultra/os/invaldcache.s
Normal file
|
@ -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)
|
52
src/libultra/os/invalicache.s
Normal file
52
src/libultra/os/invalicache.s
Normal file
|
@ -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)
|
36
src/libultra/os/maptlbrdb.s
Normal file
36
src/libultra/os/maptlbrdb.s
Normal file
|
@ -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)
|
22
src/libultra/os/parameters.s
Normal file
22
src/libultra/os/parameters.s
Normal file
|
@ -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
|
86
src/libultra/os/probetlb.s
Normal file
86
src/libultra/os/probetlb.s
Normal file
|
@ -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)
|
14
src/libultra/os/setcompare.s
Normal file
14
src/libultra/os/setcompare.s
Normal file
|
@ -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)
|
15
src/libultra/os/setfpccsr.s
Normal file
15
src/libultra/os/setfpccsr.s
Normal file
|
@ -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)
|
168
src/libultra/os/setintmask.s
Normal file
168
src/libultra/os/setintmask.s
Normal file
|
@ -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)
|
15
src/libultra/os/setsr.s
Normal file
15
src/libultra/os/setsr.s
Normal file
|
@ -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)
|
15
src/libultra/os/setwatchlo.s
Normal file
15
src/libultra/os/setwatchlo.s
Normal file
|
@ -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)
|
29
src/libultra/os/unmaptlball.s
Normal file
29
src/libultra/os/unmaptlball.s
Normal file
|
@ -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)
|
60
src/libultra/os/writebackdcache.s
Normal file
60
src/libultra/os/writebackdcache.s
Normal file
|
@ -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)
|
23
src/libultra/os/writebackdcacheall.s
Normal file
23
src/libultra/os/writebackdcacheall.s
Normal file
|
@ -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)
|
Loading…
Add table
Add a link
Reference in a new issue