FX-マイコンで同時押し対応CWキーヤー…を作ろうとしたら新しい仕様を発見した

FX-マイコンR-165付属のプログラム集には、「No.82 モールス, エレキー」がある。
しかし、これはキー入力を用いているので、同時押しができない。
そこで、`CAL INPT` 命令を用いて左右同時押しにより短点と長点を交互に鳴らす操作に対応したキーヤーを作成することにした。

# プログラム (失敗)

以下のプログラムは、[MikeAssembler](https://mikecat.github.io/mike_assembler/) でアセンブルできる。

```
target gmc4

; K1 : 短点 (左)
; K2 : 長点 (右)

	TIA 0
	AO
main_loop:
	DATAN 0xE, 0x3 ; CAL INPT
	AIA 0xE
	JUMP sound_long
	; K2が非導通だった
	AIA 1
	JUMP sound_short
	JUMP main_loop
sound_long:
	CAL LONS
	; K1が導通なら、K2の状態にかかわらず短点を鳴らす (短点 or 同時押し)
	DATAN 0xE, 0x3 ; CAL INPT
	CAL SIFT
	JUMP sound_long_after
sound_short:
	CAL SHTS
	; K2が導通なら、K1の状態にかかわらず長点を鳴らす (長点 or 同時押し)
	DATAN 0xE, 0x3 ; CAL INPT
	AIA 0xE
	JUMP sound_long
	; K2が非導通、K1が導通なら、短点を鳴らす
	AIA 1
	JUMP sound_short
	; K1もK2も非導通なので、待機
	JUMP main_loop
sound_long_after:
	; K1が非導通、K2が導通なら、長点を鳴らす
	AIA 0xF
	JUMP sound_long
	; K1もK2も非導通なので、待機
	JUMP main_loop
```

以下は、このプログラムの機械語表現である。

```
  | 0 1 2 3  4 5 6 7  8 9 A B  C D E F
--+-----------------------------------
0 | 8 0 1 E  3 9 E F  1 2 9 1  F 1 B F
1 | 0 3 E A  E 3 E 6  F 2 C E  9 E 3 9
2 | E F 1 2  9 1 F 1  B F 0 3  9 F F 1
3 | 2 F 0 3
```

# 実行結果 (失敗)

3.5mmステレオジャックのGNDにK1・K2に入力する信号、LにK1、RにK2を接続し、これを介して [CW-ONE](https://www.cqcqde.com/fs/cqohm/20026) を接続して実行した。
結果、パドルを押しっぱなしにするとなぜか音が鳴りっぱなしになってしまった。

<iframe width="560" height="315" src="https://www.youtube.com/embed/k5Zc5vrsq8g" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# 何がいけなかったのか

調査の結果、`CAL SHTS` や `CAL LONS` 命令は、7セグメントLEDが点灯した状態で `CAL INPT` 命令でAレジスタのビットを1にするような入力をすると、なぜか実行が停止することがわかった。
以下のプログラムは、2進LEDを点灯させて短い音を鳴らし、2進LEDを消灯させて0.5秒待つ、を繰り返すプログラムである。
このプログラムを実行し、パドルを操作すると、タイミングによって音が鳴りっぱなしになったり、止まりっぱなしになったりした。
しかし、2進LEDが消えたタイミングでパドルを操作しても、必ず2進LEDが点いてから実行が停止した。
すなわち、`CAL TIMR` 命令はK1やK2の影響を受けないようである。

```
機械語 アセンブリ言語
---------------------
A 0        TIY 0
1          AO
       loop:
E 1        CAL SETR
E 9        CAL SHTS
8 4        TIA 4
E 2        CAL RSTR
E C        CAL TIMR
F 0 3      JUMP loop
```

<iframe width="560" height="315" src="https://www.youtube.com/embed/hB_slBrDTXg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# プログラム (罠回避)

残念ながら `CAL INPT` 命令用の入力と `CAL SHTS` や `CAL LONS` 命令の併用は難しそうなので、かわりに2進LEDの最下位を用いてモールス信号を出力することにした。
この出力は、マイコンユニット右側の下から2番目の端子にも出ているため、外部に取り出し、連動して音を鳴らすなどの応用も可能だろう。
ただし、この端子は8V付近の電圧が出ることがあるので、接続する部品の最大入力電圧には注意したい。
([以前の記事](https://qiita.com/mikecat_mixc/items/cde539fe570dfebf18ea#led0led1led2)を参照)

```
target gmc4

; K1 : 短点 (左)
; K2 : 長点 (右)

	TIA 0
	TIY 0
	AO
main_loop:
	DATAN 0xE, 0x3 ; CAL INPT
	AIA 0xE
	JUMP sound_long
	; K2が非導通だった
	AIA 1
	JUMP sound_short
	JUMP main_loop
sound_long:
	CAL SETR
	TIA 2
	CAL TIMR
	CAL RSTR
	TIA 0
	CAL TIMR
	; K1が導通なら、K2の状態にかかわらず短点を鳴らす (短点 or 同時押し)
	DATAN 0xE, 0x3 ; CAL INPT
	CAL SIFT
	JUMP sound_long_after
sound_short:
	CAL SETR
	TIA 0
	CAL TIMR
	CAL RSTR
	CAL TIMR
	; K2が導通なら、K1の状態にかかわらず長点を鳴らす (長点 or 同時押し)
	DATAN 0xE, 0x3 ; CAL INPT
	AIA 0xE
	JUMP sound_long
	; K2が非導通、K1が導通なら、短点を鳴らす
	AIA 1
	JUMP sound_short
	; K1もK2も非導通なので、待機
	JUMP main_loop
sound_long_after:
	; K1が非導通、K2が導通なら、長点を鳴らす
	AIA 0xF
	JUMP sound_long
	; K1もK2も非導通なので、待機
	JUMP main_loop
```

以下は、このプログラムの機械語表現である。

```
  | 0 1 2 3  4 5 6 7  8 9 A B  C D E F
--+-----------------------------------
0 | 8 0 A 0  1 E 3 9  E F 1 4  9 1 F 2
1 | 7 F 0 5  E 1 8 2  E C E 2  8 0 E C
2 | E 3 E 6  F 4 0 E  1 8 0 E  C E 2 E
3 | C E 3 9  E F 1 4  9 1 F 2  7 F 0 5
4 | 9 F F 1  4 F 0 5
```

# 実行結果 (罠回避)

パドルの操作によってモールス信号を出力できている。

<iframe width="560" height="315" src="https://www.youtube.com/embed/u0mLZtRs3MM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>