同一プロセス内でIPC通信できるのか? マイナーすぎる3DS備忘録
結論: できる!
しかし普通にsvcConnectToPortを呼び出すとWould blockが発生するので、srvSetBlockingPolicyからnonblockingをfalseにする必要があった。
なんで同じプロセス内でIPC通信する必要があんねん!ってツッコミは置いといてください。
追記: 通信時、ポインタをパラメータとして渡すとTranslation errorでカーネルがパニックを起こすので注意。
STM, LDMのスタック更新のタイミング
過去一備忘録
書き込み/読み込み前に更新されるやつ
・STMFD
・LDMDB
・STMIB
・LDMIB
書き込み/読み込み後に更新されるやつ
・LDMFD
・STMIA
・STMDA
・LDMDA
CTRPFのKeyboardについてのお話 マイナーすぎる3DS備忘録
CTRPFを作っていた時につまずいた時の話です。
何があったのか
いつからかCTRPFの選択式のキーボードは、このようにデフォルトで1番目の要素が選択されるようになっていました。

自分的に嫌なのでどうにか選択をクリアできないかと思い探してみると、

それっぽいのを見つけました。引数に-1を渡すとすべての選択が解除されると書いてあります。しかし正直に-1を渡してみると、3DSがクラッシュしてしまいました。書いてある通りPopulateもしています。
原因を探るべく、ChangeSelectedEntryのソースを見てみると、

entryの値をまともにチェックせずに配列のインデックスとして使ってました。entryに-1入れていいよって書いてたのに-1かチェックしてないなんて何事だよ。。。
しかしentryがキーボードの要素数より大きければ-1として扱われるみたいなので、
と使えば-1を入れた時の本来の動作が期待できそうなので実行してみると、

無事、クラッシュすることなくすべての選択を解除することができました。
結論
-1の代わりにINT_MAXを使おう。
ChangeSelectedEntry実装したのは予想通りPabloさんでした。Pabloなにやってんだよ毎回やっぱNanquitasは神それでは。
citro3dを学ぶ #1 GPUのShader命令
完全に備忘録です。#1とありますが順番になっているわけではありません。内容はバラバラです。そもそも#2をかくかどうかすらわかりません。
今回はShader命令について書いていきます。オペランドの指定の仕方などはある程度はわかることを前提とします。
目次:
DP4
dp4 r0, r1, r2
一番出てくる。Dot Product 4-componentの略。四次元ベクトルの内積を計算します。ちなみにDot Productは内積という意味。
例: r0 = r1 ・r2
MOV
mov r0, r1
みんな大好きARMでお馴染みのmov命令!値コピー。
例: r0 = r1
RCP
rcp r0, r1
最初の要素の逆数を計算し、各要素に格納する。
例: r0[0 ~ n] = 1/r1.x
MUL
mul r0, r1, r2
ベクトルの各要素ごとで乗算をする。
例: r1(1, 2, 3, 4) * r2(0.1, 0.2, 0.3, 0.4) = r0(0.1, 0.4, 0.9, 1.6)
ADD
add r0, r1, r2
ベクトルの各要素ごとで加算をする。
例: r1(1, 2, 3, 4) + r2(0.1, 0.2, 0.3, 0.4) = r0(1.1, 2.2, 3.3, 4.4)
MAX
max r0, r1, r2
ベクトルの各要素ごとで最大値をとる。
例: r1(1.2, 4.9, 3.0, 2.5), r2(1.8, 3.4, 0.3, 2.5) -> r0(1.8, 4.9, 3.0, 2.5)
MIN
min r0, r1, r2
ベクトルの各要素ごとで最小値をとる。
例: r1(1.2, 0.9, 0, 0.5), r2(1.8, 3.4, 0.3, 0.5) -> r0(1.2, 0.3, 0, 0.5)
MAD
mad r0, r1, r2, r3
2つのベクトルを乗算して、4つ目のベクトルを加算する。
例: r0 = r1 * r2 + r3
マルチスレッドとイベント マイナーすぎる3DS備忘録
3DSでマルチスレッディングを行う際に使用するEventについて書いていきます。
イベントの作成
Result svcCreateEvent(Handle* event, ResetType reset_type);
引数にポインタを渡して作成したイベントのハンドルを取得しましょう。ResetTypeについてはこちらをご覧ください。
イベントを待つ
Result svcWaitSynchronization(Handle handle, s64 nanoseconds);
handleには作成したイベントのハンドルを渡しましょう。nanosecondはタイムアウトです。タイムアウトした場合、0x09401BFEが返ってきます。
シグナルの送信
Result svcSignalEvent(Handle handle);
handleはお察しの通りイベントのハンドルです。イベントにシグナルします。
イベントのクリア
Result svcClearEvent(Handle handle);
handleはイベントのハンドルです。ResetTypeをRESET_STICKYにした場合に使用します。RESET_STICKYだとイベントをクリアしないとシグナルがずっと送信されたままになります。クリアするともう一度イベントを待つことができます。
例
#include <stdio.h> #include <3ds.h> // イベントのハンドル Handle eventHandle; // スレッドのフラグ bool runThread = true; void threadMain(void *arg) { while(runThread) { // イベントを待つ svcWaitSynchronization(eventHandle, U64_MAX); printf("Hello World!\n"); } } int main(void) { // 画面を初期化 gfxInitDefault(); consoleInit(GFX_TOP, NULL); // イベントを作成 svcCreateEvent(&eventHandle, RESET_ONESHOT); // スレッドを作成 Thread threadHandle = threadCreate(threadMain, 0, 0x1000, 0x3f, -2, true); while (aptMainLoop()) { // キー入力を更新 hidScanInput(); u32 key = hidKeysDown(); if (key & KEY_START) break; // Aボタンが押されたら if (key & KEY_A) { // イベントにシグナルを送信 svcSignalEvent(eventHandle); } // 画面を更新 gfxFlushBuffers(); gfxSwapBuffers(); gspWaitForVBlank(); } // スレッドのフラグを更新 runThread = false; // スレッドはイベントを待機中なので、シグナルを送りスレッドを動かせる svcSignalEvent(eventHandle); // スレッドの終了を待つ threadJoin(threadHandle, U64_MAX); // イベントハンドルを閉じる svcCloseHandle(eventHandle); gfxExit(); return 0; }
Aボタンを押したらシグナルを送信し、待機スレッドはシグナルを検知したらHello World!を出力します。
例にある通り、使わなくなったイベントはsvcCloseHandleでハンドルを閉じましょう。
終わりに
前回よりはわかりやすいと思います。わからないことがあれば気軽にどうぞ!
EventのResetTypeについて マイナーすぎる3DS備忘録
ResetTypeとはlibctruで定義されているEventやTimerのリセットに使用される列挙型です。Eventのリセットに使用されるのは、
- RESET_ONESHOT
- RESET_STICKY
の2つです。今回はこの2つの違いについて書いていきます。
RESET_ONESHOT
RESET_ONESHOTは、Signalが送信され、Waitしているスレッドが動き出したとき自動でSignalがクリアされるのが特徴です。一般的に2つのスレッド(Signalするスレッド, Waitするスレッド)間で使用するときに用いられます。
RESET_STICKY
RESET_STICKYはRESET_ONESHOTと違い、Signalが自動でクリアされることはありません。2つ以上のスレッドが同時にその他のスレッドのSignalを待っているときに使用されます。自動でクリアされないのでクリアのし忘れに注意してください。
例
先ほどの説明をもう少しわかりやすく説明します。
例として3つのスレッドA, B, CとイベントXがあるとします。
スレッドA, Bは共にイベントXを待っています。
- イベントXがRESET_ONESHOTでリセットされている時
この時、スレッドCがイベントXにSignalを送信すると、スレッドA, BのどちらかのみがWait状態から起動し、もう片方のスレッドはWaitし続けます。もう一度イベントXにSignalを送信するともう片方のスレッドも起動します。
- イベントXがRESET_STICKYでリセットされている時
この時、スレッドCがイベントXにSignalを送信すると、スレッドA, Bの両方が起動します。もう一度イベントXを使用する場合はイベントXをクリアする必要があります。
いかがでしたでしょうか。今回は少し難しい内容になってしまいました。RESET_ONESHOTは1つのスレッド、RESET_STICKYは複数のスレッドに効果があるという認識で大丈夫だと思います。
それでは。
3DSにおけるPortとServiceの違い マイナーすぎる3DS備忘録
3DSにはsvcSendSyncRequestというプロセス間通信に使用する関数があります。この関数ではセッションハンドルを用いて他プロセスに処理を頼んだり、情報を取得したりすることができます。このセッションハンドルは、svcConnectToPortまたはsrvGetSessionHandleを用いて取得することが出来ます。svcConnectToPortはSVC(システムコール)で、srvGetSessionHandleはServiceManagerによって提供される関数です。
では、PortとServiceの違いとは何なのでしょうか。
とても簡単に説明すると、ServiceManagerによって管理されているPortをServiceと呼ぶのです。
ServiceManagerはPortを管理するプログラムであり、ServiceManagerに登録されたPortはServiceManagerを介してのみアクセスできます。
ServiceManagerに登録されていないPortの例としては、"srv:"(ServiceManagerそのもの)や"plg:ldr"(Luma3DSのみ)などです。よく使われる"fs:USER"や"hid:USER"などは全てサービスになります。
いかがでしたでしょうか。自分的にはこの違いがずっとわからずモヤモヤしてましたがわかるとなるほどってなりました。
以上