あなたCPUなんか創ってどうするのかしら?! 第4章 第8節

~あんたCPUなんか創ってどうするのよ?! Vol.4~

2018/10/8
技術書典5 け39

第4章 第8節 二桁電卓

  CALC2:   ; 2桁電卓
200:6F MOVA0xF; AC
201:A1 MOV[1]A; 最後のキー
202:A2 MOV[2]A; 直前のキー
203:A3 MOV[3]A; 現在の演算
204:60 MOVA0
205:A4 MOV[4]A; X
206:A5 MOV[5]A
207:A6 MOV[6]A
208:A7 MOV[7]A; Y
209:A8 MOV[8]A
20A:A9 MOV[9]A
  CALC2A:
20B:44 MOVA[4]; X表示
20C:AE MOV[0xE]A
20D:70 MOVB0
20E:BF MOV[0xF]B
20F:6F MOVA0xF; 10の位消灯
210:55 MOVB[5]; 0か?
211:3F SUBB1
212:E5 JNCCALC2B
213:21
214:45 MOVA[5]
  CALC2B:
215:AE MOV[0xE]A
216:71 MOVB1
217:BF MOV[0xF]B
218:46 MOVA[6]; 符号
219:AE MOV[0xE]A
21A:72 MOVB2
21B:BF MOV[0xF]B
  CALC2C:
21C:41 MOVA[1]; 最後キー
21D:A2 MOV[2]A
21E:63 MOVA3; CALC2D
21F:A0 MOV[0]A
220:F0 JMPKBDIN ; キー入力
221:08
  CALC2D:
222:A1 MOV[1]A; 最後のキー
223:26 SUBA0xA; 数値X分岐
224:EE JNCCALC2E
225:22
226:2C SUBA4; +-×÷か?
227:E0 JNCCALC2G
228:24
229:2F SUBA1; =か?
22A:EF JNCCALC2H
22B:24
22C:F0 JMPCALC2 ; AC処理
22D:20
  CALC2E:   ; X入力
22E:70 MOVB0; 10の位
22F:B5 MOV[5]B
230:69 MOVA9; 2桁か?
231:82 SUBA[2]
232:E6 JNCCALC2F
233:23
234:44 MOVA[4]; 桁シフト
235:A5 MOV[5]A
  CALC2F:
236:41 MOVA[1]; Xに格納
237:A4 MOV[4]A
238:42 MOVA[2]; =直後か?
239:22 SUBA0xE
23A:EB JNCCALC2A
23B:20
23C:6F MOVA0xF; 演算クリア
23D:A3 MOV[3]A; +-×÷
23E:FB JMPCALC2A
23F:20
  CALC2G:   ; +-×÷キー
240:43 MOVA[3]; 演算確認
241:2C SUBA4
242:E5 JNCCALC2I ; 演算実行
243:25
244:44 MOVA[4]; 演算未入力
245:A7 MOV[7]A; X→Y移動
246:45 MOVA[5]
247:A8 MOV[8]A
248:46 MOVA[6]
249:A9 MOV[9]A
24A:41 MOVA[1]; 演算確定
24B:26 SUBA0xA
24C:A3 MOV[3]A
24D:FC JMPCALC2C ; X入力
24E:21
  CALC2H:   ; =キー処理
24F:43 MOVA[3]; 演算確認
250:2C SUBA4
251:E9 JNCCALC2J ; 演算実行
252:25
253:FC JMPCALC2C ; X入力
254:21
  CALC2I:   ; 演算入力済
255:6D MOVA0xD; =か?
256:82 SUBA[2]
257:EA JNCCALC2K ; =の直後
258:26
  CALC2J:   ; 演算判定
259:56 MOVB[6]; Xの符号
25A:43 MOVA[3]; +-×÷
25B:2F SUBA1
25C:EF JNCCALC2L ; 加減算
25D:26
25E:38 ADDB8; X符号反転
25F:2F SUBA1
260:EF JNCCALC2L ; 加減算
261:26
262:2F SUBA1
263:E0 JNCMUL2 ; 乗算
264:31
265:2F SUBA1
266:E0 JNCDIV2 ; 除算
267:36
268:F0 JMPCALC2 ; エラー
269:20
  CALC2K:  ; =直後
26A:41 MOVA[1]; 演算確定
26B:26 SUBA0xA
26C:A3 MOV[3]A
26D:FC JMPCALC2C ; 戻る
26E:21
  CALC2L:  ; 加減算
26F:19 ADDB[9]; Yの符号
270:64 MOVA4; CALC2M
271:A0 MOV[0]A
272:38 ADDB8; 符号確認
273:E0 JNCADD2 ; 加算へ
274:28
275:F0 JMPSUB2 ; 減算へ
276:2B
   ADD2:  ; 無符号加算
280:47 MOVA[7]; 1の位
281:04 ADDA[4]
282:A7 MOV[7]A
283:70 MOVB0; 繰り上げ無
284:E7 JNC ADD2A
285:28
286:71 MOVB1; 繰り上げ有
   ADD2A:
287:26 ADDA6; 10進補正
288:EB JNC ADD2B
289:28
28A:71 MOVB1; 繰り上げ有
   ADD2B:
28B:3F SUBB1
28C:E2 JNCADD2C ; 補正不要
28D:29
28E:A7 MOV[7]A; 補正済
28F:58 MOVB[8]; 繰り上げ
290:31 ADDB1
291:B8 MOV[8]B
   ADD2C:
292:58 MOVB[8]; 10の位
293:15 ADDB[5]
294:B8 MOV[8]B
295:60 MOVA0; 繰り上げ無
296:E9 JNC ADD2D
297:29
298:61 MOVA1; 繰り上げ有
   ADD2D:
299:36 ADDB6; 10進補正
29A:ED JNC ADD2E
29B:29
29C:61 MOVA1; 繰り上げ有
  ADD2E:
29D:2F SUBA1
29E:E4 JNCADD2F ; 補正不要
29F:2A
2A0:B8 MOV[8]B; 補正済
2A1:49 MOVA[9]; 符号
2A2:21 ADDA1
2A3:A9 MOV[9]A
  ADD2F:
2A4:FC JMPRET ; RETURN
2A5:0F
  SUB2:  ; 無符号減算
2B0:47 MOVA[7]; 1の位
2B1:84 SUBA[4]
2B2:A7 MOV[7]A
2B3:E7 JNCSUB2A ; マイナス
2B4:2B
2B5:FE JMPSUB2B ; 10の位へ
2B6:2B
  SUB2A:  ; 繰下げ処理
2B7:2A ADDA10; 10進補正
2B8:A7 MOV[7]A
2B9:58 MOVB[8]; 借り
2BA:3F SUBB1
2BB:B8 MOV[8]B
2BC:E5 JNCSUB2C ; マイナス
2BD:2C
  SUB2B:
2BE:58 MOVB[8]; 10の位
2BF:95 SUBB[5]
2C0:B8 MOV[8]B
2C1:E8 JNCSUB2D ; マイナス
2C2:2C
2C3:FC JMPRET ; RETURN
2C4:0F
  SUB2C:
2C5:58 MOVB[8]; 10の位
2C6:95 SUBB[5]
2C7:B8 MOV[8]B
  SUB2D:  ; 補正
2C8:6A MOVA10
2C9:87 SUBA[7]
2CA:A7 MOV[7]A
2CB:7F MOVB0xF
2CC:26 SUBA10
2CD:E1 JNCSUB2E
2CE:2D
2CF:70 MOVB0
2D0:B7 MOV[7]B
  SUB2E:
2D1:98 SUBB[8]
2D2:B8 MOV[8]B
2D3:49 MOVA[9]; 符号反転
2D4:28 ADDA8
2D5:A9 MOV[9]A
2D6:FC JMPRET ; RETURN
2D7:0F
  CALC2M:   ; 結果表示
2E0:47 MOVA[7]; Y表示
2E1:AE MOV[0xE]A
2E2:70 MOVB0
2E3:BF MOV[0xF]B
2E4:6F MOVA0xF
2E5:59 MOVB[9]; 10の位消灯
2E6:19 ADDB[9]
2E7:18 ADDB[8]
2E8:3F SUBB1
2E9:EC JNCCALC2N
2EA:2E
2EB:48 MOVA[8]
  CALC2N:
2EC:AE MOV[0xE]A
2ED:71 MOVB1
2EE:BF MOV[0xF]B
2EF:49 MOVA[9]
2F0:AE MOV[0xE]A
2F1:72 MOVB2
2F2:BF MOV[0xF]B
2F3:09 ADDA[9]; エラーか?
2F4:2E ADDA0xE
2F5:E0 JNCCALC2P ; 正常
2F6:30
  CALC2O:   ; エラー
2F7:6B MOVA0xB; AC待機
2F8:AE MOV[0xE]A
2F9:4E MOVA[0xE]
2FA:22 ADDA0x2
2FB:2F ADDA0xF
2FC:EC JNCCALC2C ; AC処理へ
2FD:21
2FE:F7 JMPCALC2O
2FF:2F
  CALC2P:
300:6D MOVA0xD; 演算確定
301:81 SUBA[1]
302:EC JNCCALC2C ; =キーか?
303:21
304:41 MOVA[1]; 演算確定
305:26 SUBA0xA
306:EC JNCCALC2C ; 数字キー
307:21
308:A3 MOV[3]A; 演算確定
309:FC JMPCALC2C ; 入力に戻る
30A:21    ; 終了

本プロジェクトの本命である2桁電卓です。整数2桁による四則演算が可能です。

入力はテンキー、出力は7セグメントLEDです。

1 + 2 + 3 = という具合に連続して計算を行うことができます。

1 + 1 = = = のように = キーを連打して同じ計算を繰り返し実行することもできます。

2桁の整数である点を除けば普通の電卓です。

プログラムの中身は1桁電卓とほぼ同じですが、腰を据えてじっくり作りましたので分かり易いと思います。少なくともスパゲティ状態にはなっていません。

以下、注意点。

イミディエイトデータによる減算命令を使っていますが、これは2の補数による加算に置き換えて考えてください。

逆に、イミディエイトデータを先にアキュムレーターに読み込んでから減算をしている箇所がありますが、これは条件分岐命令がJNCしかない不便さを回避するための苦肉の策です。

JNC命令はキャリーが発生しない場合に分岐しますが、シチュエーションによってはキャリーが発生した場合に分岐したい場合もあります。そのような時は減算対象を入れ替えることでキャリー発生条件を逆転させている訳です。

プログラム内にはADD2とSUB2という2つの疑似サブルーチンがあります。KBDINと同様に、これらもRAMの0番地に戻り先番号を格納してから呼び出します。KBDINの末尾にある疑似RETURN命令を利用しているため、戻り先番号は全ての疑似サブルーチンで共通です。

 

この電卓プログラムは10進数で計算を行っていますので、それぞれの桁毎に計算結果が10以上になったかどうかを確認し、もし10以上ならば繰り上がり補正を行う必要があります。

一般的なCPUの場合、この処理は専用の命令によって行うのが普通です。これは4004の開発者の一人である嶋正利氏によって発明されたと言われている由緒正しい命令なのですが、残念ながらTD4EX4にはありません。

仕方ないので本プログラムでは、演算結果に6を加算し、キャリーが発生したら補正する、という強引な方法を使っています。