suspendrdp.c
3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*---------------------------------------------------------------------
File : suspendrdp.c
Date Dec 5, 1996.
Author Yoshitaka Yasumoto.(yasu@rd3.nintendo.co.jp)
Copyright Nintendo, Co., Ltd. 1996.
---------------------------------------------------------------------*/
#define F3DNCom_GBI
#include <ultra64.h>
/*
* RDP を停止させるためのルーチンです.
*
* 動作原理:
* 予め DL に停止可能位置を示すためのタグ (XTag) を埋め込んでおき,
* RDP を停止させたいときに RDP の処理位置から順に XTag をサーチし
* 見つかった XTag を FullSync コマンドに置き換えます.
*
* 使用方法:
* F3DNCom_GBI を定義すると, RDP の Sync 系コマンド ( FullSync,
* LoadSync, PipeSync, TileSync ) と NoOp コマンドに XTag が埋め込ま
* れます. これらのコマンドの位置が RDP の停止可能位置となります.
* 停止処理を円滑に行なうために, これらの命令をうまく配置することが
* 必要です. 実際には gsSPVertex() の前とかに gsDPNoOp() を置いたり
* するのが良いでしょう. むろん Texture のロードコマンドがあればそこに
* は Sync 系のコマンドがあるでしょうから, わざわざ gsDPNoOp を追加す
* る必要はありません.
*
* fifo バッファの書換えに IO_WRITE を使用していますが, 別にデータキャッ
* シュ経由でも問題はありません. その際はキャッシュの振る舞いにご注意
* ください. (osWritebackDCache/osInvalDCache)
*
*/
void osRDPSuspend(OSTask *taskp)
{
u32 dpc_cur, dpc_end, buf_start, buf_end;
u32 i, j;
/*
* fifo バッファの情報の取得 (引数で直接渡してもよいでしょう)
*/
buf_start = ((u32)taskp->t.output_buff )&0x00ffffff;
buf_end = ((u32)taskp->t.output_buff_size)&0x00ffffff;
/*
* RDP 処理停止
*/
IO_WRITE(DPC_STATUS_REG, DPC_SET_FREEZE);
/*
* RDP 停止確認
*/
while (!(IO_READ(DPC_STATUS_REG) & DPC_STATUS_FREEZE));
/*
* RDP レジスタ値取得
*/
dpc_cur = IO_READ(DPC_CURRENT_REG);
dpc_end = IO_READ(DPC_END_REG);
/*
* 既に RDP が終了しているか, あるいは残りが少ないかのチェック
*/
if (dpc_end < dpc_cur || dpc_cur + 176 < dpc_end){
/*
* XTag を探す
* + DP コマンドは 8 バイトアラインされている
* + 安全のために 3 角形 1 つ分後ろから検索を始める
*/
for (i = dpc_cur + 176; i != dpc_end; i += 8){
/*
* バッファの最後のデータは当てにならない
* + 最悪で NCom_Rej 使用時の 3 角形 4 つ分が意味のないデータになる
*/
if (i >= buf_end - 176*4 + 8 && i > dpc_end){
i = buf_start;
}
/*
* XTag 値と fifo 内データの比較
*/
if (IO_READ(i+4) == GDP_XTAG_LOW &&
(IO_READ(i) & 0x00ffffff) == GDP_XTAG_HI){
/*
* 見つかった XTag を Full Sync コマンドに置き換える
*/
IO_WRITE(i, 0x29000000);
/*
* DPC_END と XTag の位置の関係の判定
*/
if (i <= dpc_end){
/*
* XTag が DPC_END より前なら, DPC_END への書き込みが
* すぐに反映される
*/
IO_WRITE(DPC_END_REG, i + 8);
} else {
/*
* XTag が DPC_END の後ろなら, DPC_END への書き込みは
* 現在の fifo 領域処理後に反映される.
* このとき fifo バッファ先頭から参照されるので DPC_END に
* fifo の先頭アドレスを書き込むことで現在の fifo 領域処理後に
* 停止させることができる.
*/
IO_WRITE(DPC_END_REG, buf_start);
/*
* XTag 以降の fifo 領域の DP コマンドを NoOp に置き換える
*/
for (j = i + 8; j < buf_end; j += 8){
/*
* NoOp に置き換える
*/
IO_WRITE(j, 0x0000000);
}
}
break;
}
}
}
#if 0 /* DEBUG 用 */
osSyncPrintf("S=%06x E=%06x C=%06x XTag=%06x ",
buf_start, dpc_end, dpc_cur, i);
for (i = 0; i < 0x80; i += 4){
if (!(i & 0x3f)) osSyncPrintf("\n ");
osSyncPrintf("%08x ", IO_READ(dpc_cur+i));
}
osSyncPrintf("\n");
#endif
/*
* RDP 処理再開
*/
IO_WRITE(DPC_STATUS_REG, DPC_CLR_FREEZE);
}