学研の4ビットマイコンGMC-4の命令の実行速度が気になったので調べてみた。
ついでに互換機やシミュレータについても調べてみた。
測定対象
今回は、以下の5種類について実験を行った。
- FX-マイコン (学研電子ブロックFX-SYSTEM FX-マイコンR-165)
- GMC-4 (大人の科学マガジン Vol.24 のふろく)
- ORANGE-4
- FX-マイコン シミュレータ
- GMC-4 シミュレータ
シミュレータの実行環境は以下である。
Windows 10 Home 21H2 (64ビット)
Intel(R) Core(TM) i7-9750H CPU @2.60GHz 2.59GHz
RAM 16.0GB
測定方法
以下のプログラムにより測定を行った。
なお、このプログラムはMikeAssemblerによるアセンブルが可能である。
target gmc4
TIA 1
TIY 3
INIT_ONE_LOOP:
AM
AIY -1
JUMP INIT_ONE_LOOP
INPUT_WAIT:
KA
JUMP INPUT_WAIT
CY
TIA 0
JUMP INIT_START
INIT_LOOP:
AM
INIT_START:
AIY -1
JUMP INIT_LOOP
CAL SHTS
MAIN_LOOP:
; 実行時間を計る命令を追加する場合、ここに入れる
; ループのカウントを行う
TIY 0
MA
AIA -1
AM
CIA 0
JUMP MAIN_LOOP
TIY 1
MA
AIA -1
AM
CIA 0
JUMP MAIN_LOOP
TIY 2
MA
AIA -1
AM
CIA 0
JUMP MAIN_LOOP
TIY 3
MA
AIA -1
AM
CIA 0
JUMP MAIN_LOOP
CAL SHTS
END:
JUMP END
以下がこのプログラムの機械語表現である。
| 0 1 2 3 4 5 6 7 8 9 A B C D E F
--+-----------------------------------
0 | 8 1 A 3 4 B F F 0 4 0 F 0 A 3 8
1 | 0 F 1 5 4 B F F 1 4 E 9 A 0 5 9
2 | F 4 C 0 F 1 C A 1 5 9 F 4 C 0 F
3 | 1 C A 2 5 9 F 4 C 0 F 1 C A 3 5
4 | 9 F 4 C 0 F 1 C E 9 F 4 A
まず、負荷量の設定を行う。
今回のプログラムでは、最大4重のループを用いる。
ループ回数を決めるカウンタをとりあえず全て1 (1回実行する) に初期化し、
キー入力された個数のカウンタを0 (16回実行する) に書き換える。
入力は0~4が有効である。
キー入力を行うと、ループ処理が実行される。
各ループは以下のブロックで表現され、同じ構造のブロックが4個連なっている。
TIY (0-3) ; ループカウンタを選択する
MA ; ループカウンタをAレジスタに読み出す
AIA -1 ; ループカウンタをデクリメントする
AM ; ループカウンタを保存する
CIA 0 ; ループカウンタが0かをチェックする
JUMP MAIN_LOOP ; ループカウンタが0でなければ、ループを続行する
今回はこのブロックを何回実行するかを計算し、それに基づいて1秒あたりの命令実行数を計算することにした。
1命令の実行時間は命令の種類や実行結果(ジャンプするかどうかなど)によって変わることが予想されるが、簡単のため今回は無視することにした。
さらに、ループ処理の前後で CAL SHTS
命令により音を鳴らすようにした。
これらの音を録音し、最初の音が鳴り始めてから2番目の音が鳴り始めるまでの時間を調べることにより、命令の実行時間を計測することにした。
この時間には、ループ処理にかかる時間に加え、CAL SHTS
命令1回分の実行時間も含まれる。
そこで、ループの回数を変えて時間を測定し、連立方程式を解くことで、CAL SHTS
命令の実行時間とループ処理の実行時間に分けることにした。
- 1種類目におけるブロックの実行回数を $n_1$
- 1種類目の実行時間を $t_1$
- 2種類目におけるブロックの実行回数を $n_2$
- 2種類目の実行時間を $t_2$
-
CAL SHTS
命令の実行時間を $s$ - ブロック1回あたりの実行時間を $b$
とおくと $s + n_1 b = t_1, s + n_2 b = t_2$ と表せるので、これを解けば $s, b$ の値が求まる。
ブロックの実行回数
負荷設定0
各ブロックを1回ずつ実行するので、実行回数は4回である。
負荷設定1
- 最初のブロックを16回実行する
- 2~4番目のブロックを1回ずつ実行する
よって、実行回数は19回である。
負荷設定2
- 2番目のブロックのループにより、以下を16回実行する
- 最初のブロックを16回実行する
- 2番目のブロックを1回実行する
- 3番目・4番目のブロックを1回ずつ実行する
よって、実行回数は$(16+1)\times 16 + 1 + 1 = 274$回である。
負荷設定3
- 3番目のブロックのループにより、以下を16回実行する
- 2番目のブロックのループにより、以下を16回実行する
- 最初のブロックを16回実行する
- 2番目のブロックを1回実行する
- 3番目のブロックを1回実行する
- 2番目のブロックのループにより、以下を16回実行する
- 4番目のブロックを1回実行する
よって、実行回数は$((16+1)\times 16 + 1)\times 16 + 1 = 4369$回である。
負荷設定4
- 4番目のブロックのループにより、以下を16回実行する
- 3番目のブロックのループにより、以下を16回実行する
- 2番目のブロックのループにより、以下を16回実行する
- 最初のブロックを16回実行する
- 2番目のブロックを1回実行する
- 3番目のブロックを1回実行する
- 2番目のブロックのループにより、以下を16回実行する
- 4番目のブロックを1回実行する
- 3番目のブロックのループにより、以下を16回実行する
よって、実行回数は$(((16+1)\times 16 + 1)\times 16 + 1)\times 16 = 69904$回である。
測定結果
実行時間の測定結果は、以下のようになった。
なお、本来は複数回測定して平均を取るべきだろうが、今回は簡単のため1回のみ測定した。
実行環境 | 負荷設定0 | 負荷設定1 | 負荷設定2 | 負荷設定3 | 負荷設定4 |
---|---|---|---|---|---|
FX-マイコン | - | 0.492秒 | 2.826秒 | - | - |
GMC-4 | - | - | 0.615秒 | 5.236秒 | - |
ORANGE-4 | - | - | - | 0.514秒 | 2.970秒 |
FX-マイコン シミュレータ | - | 2.315秒 | 27.822秒 | - | - |
GMC-4 シミュレータ | - | - | - | 0.320秒 | 0.340秒 |
この測定結果から実行時間を求め、1秒あたりの命令実行数に換算すると、以下のようになった。
1ブロックが6命令からなることを利用している。
実行環境 |
CAL SHTS 命令の実行時間 |
1ブロックあたりの実行時間 | 1秒あたりの命令実行数 |
---|---|---|---|
FX-マイコン | 0.318秒 | 0.00915秒 | 656命令 |
GMC-4 | 0.306秒 | 0.00113秒 | 5317命令 |
ORANGE-4 | 0.350秒 | 0.0000375秒 | 160102命令 |
FX-マイコン シミュレータ | 0.414秒 | 0.100秒 | 60命令 |
GMC-4 シミュレータ | 0.319秒 | 0.000000305秒 | 19660500命令 |
すなわち、
- GMC-4は1秒あたり約5k命令実行できる
- FX-マイコンはGMC-4の約8分の1の実行速度
- ORANGE-4はGMC-4の約30倍速い
- GMC-4 シミュレータはGMC-4の約3700倍速い
- FX-マイコン シミュレータはGMC-4の約90分の1の実行速度
という結果になった。
7セグメントLEDを点灯させての測定
FX-マイコンは7セグメントLEDを点灯させると実行速度が落ちるようだったので、
先程のプログラムの最初の TIA 1
の次に AO
を挿入し、
7セグメントLEDを点灯させるようにしたプログラムで再度測定を行ってみた。
以下がこの変更を行ったプログラムの機械語表現である。
| 0 1 2 3 4 5 6 7 8 9 A B C D E F
--+-----------------------------------
0 | 8 1 1 A 3 4 B F F 0 5 0 F 0 B 3
1 | 8 0 F 1 6 4 B F F 1 5 E 9 A 0 5
2 | 9 F 4 C 0 F 1 D A 1 5 9 F 4 C 0
3 | F 1 D A 2 5 9 F 4 C 0 F 1 D A 3
4 | 5 9 F 4 C 0 F 1 D E 9 F 4 B
同様に1回ずつ測定を行った結果、以下の測定結果が得られた。
実行環境 | 負荷設定0 | 負荷設定1 | 負荷設定2 | 負荷設定3 | 負荷設定4 |
---|---|---|---|---|---|
FX-マイコン | - | 0.565秒 | 3.845秒 | - | - |
GMC-4 | - | - | 0.614秒 | 5.237秒 | - |
ORANGE-4 | - | - | - | 0.471秒 | 3.080秒 |
FX-マイコン シミュレータ | - | 2.306秒 | 27.908秒 | - | - |
GMC-4 シミュレータ | - | - | - | 0.329秒 | 0.350秒 |
この測定結果から実行時間を求め、1秒あたりの命令実行数に換算すると、以下のようになった。
1ブロックが6命令からなることを利用している。
実行環境 |
CAL SHTS 命令の実行時間 |
1ブロックあたりの実行時間 | 1秒あたりの命令実行数 | 実行速度(消灯時比) |
---|---|---|---|---|
FX-マイコン | 0.321秒 | 0.0129秒 | 466命令 | 71.2% |
GMC-4 | 0.305秒 | 0.00113秒 | 5315命令 | 100.0% |
ORANGE-4 | 0.297秒 | 0.0000398秒 | 150713命令 | 94.1% |
FX-マイコン シミュレータ | 0.398秒 | 0.100秒 | 60命令 | 99.6% |
GMC-4 シミュレータ | 0.328秒 | 0.000000320秒 | 18724286命令 | 95.2% |
- FX-マイコンでは、約30%という顕著な速度の低下がみられた。
- GMC-4では、速度はほとんど変わらなかった。
- ORANGE-4では、5%程度の速度の低下がみられた。
- FX-マイコン シミュレータでは、速度はほとんど変わらなかった。
- 「動作をできるだけ忠実に再現しました」と主張しているが、ここは再現できなかったようだ。(そもそも遅いし)
- GMC-4 シミュレータでは、5%程度の速度の低下がみられた。
- 測定された時間が短いため、実行時の他のタスクの違いなど誤差の可能性も考えられる。
ORANGE-4における7セグメントLEDの点灯による実行速度の低下を確かめるため、
以下のプログラムでPORT1へ0/1の出力を繰り返し、オシロスコープ FNIRSI-1013D で周波数を測定した。
target orange4
ldyi 1
ldi 0
ioctrl
loop:
ldi 1
out
ldi 0
out
jmpf loop
以下がこのプログラムの機械語表現である。
| 0 1 2 3 4 5 6 7 8 9 A B C D E F
--+-----------------------------------
0 | A 1 8 0 F 7 0 8 1 F 7 1 8 0 F 7
1 | 1 F 0 7
以下が測定結果である。
さらに、最初の ldi 0
の次に outn
命令を追加し、
7セグメントLEDを点灯させる以下のプログラム(機械語表現)について、同様に測定した。
| 0 1 2 3 4 5 6 7 8 9 A B C D E F
--+-----------------------------------
0 | A 1 8 0 1 F 7 0 8 1 F 7 1 8 0 F
1 | 7 1 F 0 8
以下が測定結果である。
7セグメントLED消灯時は28.3kHzであるのに対し、7セグメントLED点灯時は27.1kHzとなっており、95.8%の実行速度となっている。
ORANGE-4では7セグメントLEDを点灯させると約5%速度が低下することを、別の形でも確かめることができた。
GMC-4 シミュレータの追加検証
GMC-4 シミュレータは他と比べて非常に高速で動作し、負荷設定4でも1秒未満で実行できた。
そこで、プログラムの入力部分を削ることで容量を確保し、負荷設定5および負荷設定6相当で検証を行った。
以下が検証用のプログラムである。(GMC-4 シミュレータ上で直接アセンブルできる)
; 7セグメントLEDを点灯させる際、コメントアウトを解除する
;AO
CAL SHTS
MAIN_LOOP:
; ループのカウントを行う
TIY 0
MA
AIA 0xF
AM
CIA 0
JUMP MAIN_LOOP
TIY 1
MA
AIA 0xF
AM
CIA 0
JUMP MAIN_LOOP
TIY 2
MA
AIA 0xF
AM
CIA 0
JUMP MAIN_LOOP
TIY 3
MA
AIA 0xF
AM
CIA 0
JUMP MAIN_LOOP
TIY 4
MA
AIA 0xF
AM
CIA 0
JUMP MAIN_LOOP
; 負荷設定6にする際、コメントアウトを解除する
;TIY 5
;MA
;AIA 0xF
;AM
;CIA 0
;JUMP MAIN_LOOP
CAL SHTS
END:
JUMP END
ORG 0x50
DN 0, 0, 0, 0, 0, 0, 0, 0
1回ずつ測定を行った結果、以下の測定結果が得られた。
実行環境 | 負荷設定5 | 負荷設定6 |
---|---|---|
GMC-4 シミュレータ (7セグメントLED消灯) | 0.680秒 | 6.180秒 |
GMC-4 シミュレータ (7セグメントLED点灯) | 0.690秒 | 6.180秒 |
また、負荷設定5の実行回数は、
「負荷設定4の処理と最後のブロック」を16回実行するので $(69904 + 1) \times 16 = 1118480$ 回
負荷設定6の実行回数は、
「負荷設定5の処理と最後のブロック」を16回実行するので $(1118480 + 1) \times 16 = 17895696$ 回
となる。
この測定結果から実行時間を求め、1秒あたりの命令実行数に換算すると、以下のようになった。
1ブロックが6命令からなることを利用している。
実行環境 |
CAL SHTS 命令の実行時間 |
1ブロックあたりの実行時間 | 1秒あたりの命令実行数 |
---|---|---|---|
GMC-4 シミュレータ (7セグメントLED消灯) |
0.313秒 | 0.000000328秒 | 18302417命令 |
GMC-4 シミュレータ (7セグメントLED点灯) |
0.324秒 | 0.000000327秒 | 18335755命令 |
7セグメントLED点灯時の実行速度は7セグメントLED消灯時の100.2%となり、ほとんど差がないという結果になった。
負荷設定4までの実験と比べてある程度の実行時間を確保できており、より信頼できると考えられる。
結論
今回の実験では、各実行環境の実行速度は以下のようになった。
なお、実行にかかる時間は命令や条件によって変わる可能性がある。
実行環境 | 実行速度 (7セグメントLED消灯時) |
7セグメントLED点灯による 実行速度の低下 |
---|---|---|
FX-マイコン | 656命令/s | 約30% |
GMC-4 | 5.31k命令/s | 見られず |
ORANGE-4 | 160k命令/s | 約5% |
FX-マイコン シミュレータ | 60.0命令/s | 見られず |
GMC-4 シミュレータ | 18.3M命令/s | 見られず |
参考になれば幸いである。