page0025
の編集
http://osecpu.osask.jp/wiki/?page0025
[
トップ
] [
編集
|
差分
|
バックアップ
|
添付
|
リロード
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
-- 雛形とするページ --
BracketName
FormattingRules
FrontPage
Fulyn
Fulyn-v2
Fulyn_Samples
Help
InterWiki
InterWikiName
InterWikiSandBox
K
KOR_PIT8254
KWVM.NET
Liva
MANA
MenuBar
OSECPU_FPGA
PG_MANA
PHP
PukiWiki
PukiWiki/1.4
PukiWiki/1.4/Manual
PukiWiki/1.4/Manual/Plugin
PukiWiki/1.4/Manual/Plugin/A-D
PukiWiki/1.4/Manual/Plugin/E-G
PukiWiki/1.4/Manual/Plugin/H-K
PukiWiki/1.4/Manual/Plugin/L-N
PukiWiki/1.4/Manual/Plugin/O-R
PukiWiki/1.4/Manual/Plugin/S-U
PukiWiki/1.4/Manual/Plugin/V-Z
RecentDeleted
SandBox
WikiEngines
WikiName
WikiWikiWeb
YukiWiki
hikalium
hikarupsp
hikarupsp_ELCHNOS
hikarupsp_ELCHNOS_IDE
hikarupsp_FrontEndCode
hikarupsp_WebCPU-VM
hikarupsp_WebCPU-VM_internal
hikarupsp_study_hh4
impressions
impressions0000
jpag0000
jpag0001
jpag0002
jpag0003
jpag0004
jpag0005
lambdalice
mandel59
members
memo0000
memo0001
memo0002
memo0003
memo0004
memo0005
memo0006
memo0007
memo0008
memo0009
memo0010
osask
osecpu4android
page0000
page0001
page0002
page0003
page0004
page0005
page0006
page0007
page0008
page0009
page0010
page0011
page0012
page0013
page0014
page0015
page0016
page0017
page0018
page0019
page0020
page0021
page0022
page0023
page0024
page0025
page0026
page0027
page0028
page0029
page0030
page0031
page0032
page0033
page0034
page0035
page0036
page0037
page0038
page0039
page0040
page0041
page0042
page0043
page0044
page0045
page0046
page0047
page0048
page0049
page0050
page0051
page0052
page0053
page0054
page0055
page0056
page0057
page0058
page0059
page0060
page0061
page0062
page0063
page0064
page0065
page0066
page0067
page0068
page0069
page0070
page0071
page0072
page0073
page0074
page0075
page0076
page0077
page0078
page0079
page0080
page0081
page0082
page0083
page0084
page0085
page0086
page0087
page0088
page0089
page0090
page0091
page0092
page0093
page0094
page0095
page0096
page0097
page0098
page0099
page0100
page0101
page0102
page0103
page0104
page0105
page0106
page0107
page0108
page0109
pagenames
populars
seccamp2013
seccamp2014
seccamp2017
ttwilb
ttwilb-asmi
yao
* lbstk ver.0.03の説明 -(by [[K]], 2013.04.15) ** lbstkとは? -簡単に言うと、OSECPUのアセンブラを支援するためのツールで、これがあると煩雑なラベル管理を肩代わりしてくれます。osectolsの中に含まれます。 --x86などの一般的なCPUの開発ツールでいうと、リンカに相当すると思われます。 -語源はlabel-stackです。 -前バージョンのlbstk01やlbstk02と比較すると、内部仕様が変更され、より使いやすい方向に進化しました。 --仕様が変わったので互換性はありません。 //-C言語の標準ライブラリだけで書いた場合は210行くらいの非常に簡単なものです。できれば将来OSECPUアプリとして移植したいと思っています。 -できれば将来OSECPUアプリとして移植したいと思っています。 -最初のバージョンはosecpu022aにバンドルされています。 ** きっかけ -OSECPUでは関数を呼ぶときに関数呼び出しの命令があるわけではなく、ただ目的の関数へJMPしています。しかしそれでは当然戻ってこられません。ということで、JMPの直前に、P1Eレジスタに「終わったらここへJMPしてください」というアドレスを格納する命令を置きます。 PLIMM(P1E, 4); JMP(12); LB0(4); --この例では、LB0(12);の関数を呼んでいます。 -もしこの関数を連続で2度呼ぶとしたら、こうなります。 PLIMM(P1E, 4); JMP(12); LB0(4); PLIMM(P1E, 5); JMP(12); LB0(5); -つまり関数呼び出しのたびにラベルを作る必要があって、しかもその番号は重複してはいけないのです。このラベル番号の管理はプログラムが長くなってくると非常に面倒になってきます。 -このような仕様なのには理由があります。OSECPUはラベルのあるところ以外には絶対に分岐できないようになっています。どこでも好きなところに分岐できてしまう普通のCPUとは違います。好きなところに分岐できてしまうことはセキュリティ的に危険ですし(だからx86にはコールゲートなどの仕組みを使って、分岐先を制限する仕組みを持っているわけです)、プログラム上のどこで他から処理が合流するか事前に分かるこの仕様はJITコンパイラにとっては有利です。 -それにこのような仕様だからこそ、OSECPUでは分岐命令はJMP命令(=P00への代入)だけで済んでいて、JITコンパイラがシンプルになっています。 -それならosecpu.exeがもっとがんばってうまく処理すればいいではないかという指摘もあるかと思います(CALLの直後に自動でラベルを発行するとか)。しかしそれはosecpu.exeが複雑になってしまいます。osecpu.exeは移植しやすい規模を維持するべきです。・・・とまあそんなわけで、この問題を解決するためのツールをosecpu.exeの外に作ることになりました。 ** 仕組み -上記の関数呼び出しを次のように書くことにしました。 lbstk2(0,1); PLIMM(P1E, lbstk1(0,0)); JMP(12); LB0(lbstk1(0,0)); lbstk3(0); -これは次のような意味を持ちます。 --lbstk2(j, sz); : 新規にラベル用の連続した番号をsz個発行し、その番号のうち一番小さいものをスタックにつみます。使用するスタックはj番目のスタックです(lbstk03ではスタックを4本持っていて、0~3を指定できます)。 ---上記例でj=0としたのは、関数コール用のスタックとしてj=0を使っているからです。 --この命令自身は、ラベルの発行を促す以上の意味を持たないので、出力ソースには現れません(消滅します)。 --lbstk1(j, ofs) : スタック[j]から一番上のラベル番号を取得します。popはしません。peekです。その数値にofsを加えラベル番号とし、lbstk1(j, ofs)の記述と置換して出力します。 --lbstl3(j); : スタック[j]から一番上のラベル番号をpopし、値を読み捨てます。この命令もスタック状態を制御する以上の意味を持たないので、出力ソースには現れません(消滅します)。 -このような機構により、以下のように完全に同一の記述を何度書いても問題なくなりました。~ lbstk2(0,1); PLIMM(P1E, lbstk1(0,0)); JMP(12); LB0(lbstk1(0,0)); lbstk3(0); lbstk2(0,1); PLIMM(P1E, lbstk1(0,0)); JMP(12); LB0(lbstk1(0,0)); lbstk3(0); -ということで、これはマクロ化されて、 CALL(12); とだけ書くことになっています。 #define CALL(label) lbstk2(0,1); PLIMM(P1E, lbstk1(0,0)); JMP(label); LB0(lbstk1(0,0)); lbstk3(0) -このスタック操作は、ソースの書き換えの際にラベル番号を求めるために仮想的に行うものであって、アプリの実行時に行うわけではありません。 ** 応用 -osecpu_asm.hには以下のような記述があります。 #define LOOP() lbstk2(0,2); LB0(lbstk1(0,0)) #define CONTINUE lbstk1(0,0) #define BREAK lbstk1(0,1) #define ENDLOOP0() lbstk3(0) /* BREAKを使わない場合用 */ #define ENDLOOP1() LB0(lbstk1(0,1)); lbstk3(0) /* BREAKを使う場合用 */ -これがあると以下のような表記が可能になります。 #define sum R00 #define i R01 LIMM(sum, 0); LIMM(i, 0); LOOP(); ADD2(sum, i); ADDI(i, i, 1); CMPIJNE(i, 10001, CONTINUE); ENDLOOP0(); /* BREAKを使わない場合用 */ -このようにループを書く際にラベル番号を気にしないで済みます。またこのループは入れ子にしていても問題なく機能します。 -なおこのマクロによるループは、ENDLOOPしても次のループを開始しません(そのままループから抜け出てしまいます)。繰り返しを意図するときは、JMP(CONTINUE);をENDLOOPの直前に入れてください。 ** 発展 -他にlbstk0(n);とlbstk4(n);とlbstk5(i)という表記をサポートしています。これは関数内でネストしないローカルなラベルにうまくラベル番号を振るためのものです。 -まずlbstk0(n); はlbstkが発行するラベル番号の開始番号を指定するためのものです。この番号よりも小さな数字でグローバルラベルを定義します。グローバルラベルというのは、関数の外からも参照可能なラベル番号のことです(publicな関数の呼び出しポイントなど)。 -lbstk4(n);は関数の先頭で宣言されるべきもので、関数内でいくつのローカルラベルを使うかを規定します。このローカルラベルには、先のlbstk2(j, sz);で発行する分を含めません。その分についてはlbstkが自動で数えてうまくやってくれます。 -lbstk5(i)はi番目のローカルラベル番号を返します。iはlbstk5(n);で指定したnよりも小さくなければいけません。0から(n-1)が有効です。 -これらについてはosecpu_asm.hで以下のように整備されています。 #define GLOBALLABELS(n) lbstk0(n) #define LOCALLABELS(n) lbstk4(n) #define LOCAL(i) lbstk5(i) ** こめんと欄 -このページにこめんと欄はありません。このページの内容にコメントしたいときは[[impressions]]にお願いします。
タイムスタンプを変更しない
* lbstk ver.0.03の説明 -(by [[K]], 2013.04.15) ** lbstkとは? -簡単に言うと、OSECPUのアセンブラを支援するためのツールで、これがあると煩雑なラベル管理を肩代わりしてくれます。osectolsの中に含まれます。 --x86などの一般的なCPUの開発ツールでいうと、リンカに相当すると思われます。 -語源はlabel-stackです。 -前バージョンのlbstk01やlbstk02と比較すると、内部仕様が変更され、より使いやすい方向に進化しました。 --仕様が変わったので互換性はありません。 //-C言語の標準ライブラリだけで書いた場合は210行くらいの非常に簡単なものです。できれば将来OSECPUアプリとして移植したいと思っています。 -できれば将来OSECPUアプリとして移植したいと思っています。 -最初のバージョンはosecpu022aにバンドルされています。 ** きっかけ -OSECPUでは関数を呼ぶときに関数呼び出しの命令があるわけではなく、ただ目的の関数へJMPしています。しかしそれでは当然戻ってこられません。ということで、JMPの直前に、P1Eレジスタに「終わったらここへJMPしてください」というアドレスを格納する命令を置きます。 PLIMM(P1E, 4); JMP(12); LB0(4); --この例では、LB0(12);の関数を呼んでいます。 -もしこの関数を連続で2度呼ぶとしたら、こうなります。 PLIMM(P1E, 4); JMP(12); LB0(4); PLIMM(P1E, 5); JMP(12); LB0(5); -つまり関数呼び出しのたびにラベルを作る必要があって、しかもその番号は重複してはいけないのです。このラベル番号の管理はプログラムが長くなってくると非常に面倒になってきます。 -このような仕様なのには理由があります。OSECPUはラベルのあるところ以外には絶対に分岐できないようになっています。どこでも好きなところに分岐できてしまう普通のCPUとは違います。好きなところに分岐できてしまうことはセキュリティ的に危険ですし(だからx86にはコールゲートなどの仕組みを使って、分岐先を制限する仕組みを持っているわけです)、プログラム上のどこで他から処理が合流するか事前に分かるこの仕様はJITコンパイラにとっては有利です。 -それにこのような仕様だからこそ、OSECPUでは分岐命令はJMP命令(=P00への代入)だけで済んでいて、JITコンパイラがシンプルになっています。 -それならosecpu.exeがもっとがんばってうまく処理すればいいではないかという指摘もあるかと思います(CALLの直後に自動でラベルを発行するとか)。しかしそれはosecpu.exeが複雑になってしまいます。osecpu.exeは移植しやすい規模を維持するべきです。・・・とまあそんなわけで、この問題を解決するためのツールをosecpu.exeの外に作ることになりました。 ** 仕組み -上記の関数呼び出しを次のように書くことにしました。 lbstk2(0,1); PLIMM(P1E, lbstk1(0,0)); JMP(12); LB0(lbstk1(0,0)); lbstk3(0); -これは次のような意味を持ちます。 --lbstk2(j, sz); : 新規にラベル用の連続した番号をsz個発行し、その番号のうち一番小さいものをスタックにつみます。使用するスタックはj番目のスタックです(lbstk03ではスタックを4本持っていて、0~3を指定できます)。 ---上記例でj=0としたのは、関数コール用のスタックとしてj=0を使っているからです。 --この命令自身は、ラベルの発行を促す以上の意味を持たないので、出力ソースには現れません(消滅します)。 --lbstk1(j, ofs) : スタック[j]から一番上のラベル番号を取得します。popはしません。peekです。その数値にofsを加えラベル番号とし、lbstk1(j, ofs)の記述と置換して出力します。 --lbstl3(j); : スタック[j]から一番上のラベル番号をpopし、値を読み捨てます。この命令もスタック状態を制御する以上の意味を持たないので、出力ソースには現れません(消滅します)。 -このような機構により、以下のように完全に同一の記述を何度書いても問題なくなりました。~ lbstk2(0,1); PLIMM(P1E, lbstk1(0,0)); JMP(12); LB0(lbstk1(0,0)); lbstk3(0); lbstk2(0,1); PLIMM(P1E, lbstk1(0,0)); JMP(12); LB0(lbstk1(0,0)); lbstk3(0); -ということで、これはマクロ化されて、 CALL(12); とだけ書くことになっています。 #define CALL(label) lbstk2(0,1); PLIMM(P1E, lbstk1(0,0)); JMP(label); LB0(lbstk1(0,0)); lbstk3(0) -このスタック操作は、ソースの書き換えの際にラベル番号を求めるために仮想的に行うものであって、アプリの実行時に行うわけではありません。 ** 応用 -osecpu_asm.hには以下のような記述があります。 #define LOOP() lbstk2(0,2); LB0(lbstk1(0,0)) #define CONTINUE lbstk1(0,0) #define BREAK lbstk1(0,1) #define ENDLOOP0() lbstk3(0) /* BREAKを使わない場合用 */ #define ENDLOOP1() LB0(lbstk1(0,1)); lbstk3(0) /* BREAKを使う場合用 */ -これがあると以下のような表記が可能になります。 #define sum R00 #define i R01 LIMM(sum, 0); LIMM(i, 0); LOOP(); ADD2(sum, i); ADDI(i, i, 1); CMPIJNE(i, 10001, CONTINUE); ENDLOOP0(); /* BREAKを使わない場合用 */ -このようにループを書く際にラベル番号を気にしないで済みます。またこのループは入れ子にしていても問題なく機能します。 -なおこのマクロによるループは、ENDLOOPしても次のループを開始しません(そのままループから抜け出てしまいます)。繰り返しを意図するときは、JMP(CONTINUE);をENDLOOPの直前に入れてください。 ** 発展 -他にlbstk0(n);とlbstk4(n);とlbstk5(i)という表記をサポートしています。これは関数内でネストしないローカルなラベルにうまくラベル番号を振るためのものです。 -まずlbstk0(n); はlbstkが発行するラベル番号の開始番号を指定するためのものです。この番号よりも小さな数字でグローバルラベルを定義します。グローバルラベルというのは、関数の外からも参照可能なラベル番号のことです(publicな関数の呼び出しポイントなど)。 -lbstk4(n);は関数の先頭で宣言されるべきもので、関数内でいくつのローカルラベルを使うかを規定します。このローカルラベルには、先のlbstk2(j, sz);で発行する分を含めません。その分についてはlbstkが自動で数えてうまくやってくれます。 -lbstk5(i)はi番目のローカルラベル番号を返します。iはlbstk5(n);で指定したnよりも小さくなければいけません。0から(n-1)が有効です。 -これらについてはosecpu_asm.hで以下のように整備されています。 #define GLOBALLABELS(n) lbstk0(n) #define LOCALLABELS(n) lbstk4(n) #define LOCAL(i) lbstk5(i) ** こめんと欄 -このページにこめんと欄はありません。このページの内容にコメントしたいときは[[impressions]]にお願いします。
テキスト整形のルールを表示する