Comments
Description
Transcript
ND8080 応用プログラム集(100ページ)
ND8080 応用プログラム集 (有)中日電工 目次 第1部 ゲームプログラム ⅰ)はじめに ⅱ)プログラムリストについて ⅲ)附属CDROMのプログラム、データの扱い方 プログラム№1 おはよー(OHAYO8.BTK) プログラム№2 CRAZY EIGHT(CRAZY88.BTK) プログラム№3 Hi-Lo(HILO8.BTK) プログラム№4 FLIPFLOP(FLIPFLP8.BTK) プログラム№5 SWAP(SWAP8.BTK) プログラム№6 CATCH(CATCH8.BTK) プログラム№7 もぐらたたき(MOGURA8.BTK) プログラム№8 神経衰弱(SINKSUI8.BTK) プログラム№9 WANTED(WANTED8.BTK) プログラム№10 すごろく迷路(SUGOROK8.BTK) プログラム№11 REVERSE(REVERSE8.BTK) プログラム№12 ROCK CLIMBING(ROCKCLM8.BTK) プログラム№13 WILD SEVEN(WILD78.BTK) プログラム№14 MOO(MOO8.BTK) プログラム№15 SWAP2(SWAP28.BTK) 第2部 電子オルゴール 1.電子オルゴールプログラム ⅰ)プログラムの使い方 ⅱ)曲データコード ⅲ)曲の速さ ⅳ)プログラムの説明 2.電子オルゴールデータ 1 1 2 2 3 6 12 17 21 26 33 39 44 50 57 64 70 76 83 89 89 89 89 90 90 95 〒463‐0067 名古屋市守山区守山2-8-14 パレス守山305 有限会社中日電工 ℡052‐791‐6254 Fax052‐791‐1391 E‐mail [email protected] Homepage http://www.tyunitidenko.x0.com/ 2016.4.29 Rev. 1.0 2 第1部 ゲームプログラム ⅰ)はじめに 本編はND8080のためのゲームプログラム集です。 2003年にND80K用の応用プログラム集として編集したものを、2010年にND80ZⅢのために書き直しました。 その後2012年にND80Z3.5用に、内容はそのまま語句のみND80ZⅢをND80Z3.5に書き換えました。 今回(2016年4月)、もとはZ80CPU用として作成したプログラムを8080CPU用に書き改めました。 数日間でZ80プログラムを8080用に書き直さなければならなかったため、Z80なればこそメリットがあったプログラム をそのまま8080用に書き直すというかなり強引なプログラムになってしまいました。 結果としてプロが作ったと自慢できるほどのプログラムではなくなってしまいました。 ま、その辺はお許しいただくとしまして、序文にありますように、なにはともあれ、レトロな世界をお楽しみください。 2016年4月 (有)中日電工代表者 菱田照久 記 以下は2003年にND80K用として編集した応用プログラムの序文です。 本編はND80Kのためのゲームプログラム集です。 ND80Kは20年前にNECのTK80とソフトコンパチブルとして発売したND80の後継機種です。 発売当初はTK80と同じくCPUは8080でしたが、その後Z80を採用し(NECは8085を使ったTK85を発売した)、 マイコンがパソコンになって、Windows全盛の今日まで、当時に近い機能のまま今日に至っています。 その間参考プログラム集の作成も検討はしてきたのですが、世の動きに合わせて私の関心も機械語からアセンブラへ 移り(8080アセンブラを自作し、ついでに逆アセンブラも作りこれは後にZ80アセンブラ、逆アセンブラに発展します)、 さらにはBASICへと展開していきました。当然のことながらBASICも整数型のBASICからNECのPC8001に刺激さ れて浮動小数点演算やカラーグラフィック機能をも搭載したBASICの製作とハードの製作という、およそ零細企業にあ るまじき狂気のふるまいの中に埋没してしまい、ND80のZ80版であるND80Zも改良を続けながら販売しては来たの ですがいつしか惰性に流され、ND80Z参考プログラム集の製作も着手しないまま今日まで来てしまいました。 ND80KはCPUをZ80から川崎製鉄のKL5C8012に強化するとともに、DOS/Vパソコンと接続してプログラム開 発ができる機能(オプション)をも付加して2000年に発売を開始しました。しかし過去からのいきさつからこのボードを作 ったものの、今更TK80コンパチでもあるまいし、ということで、勿論あらためて参考プログラムを作る気もありませんでし た。 ところがつい先日(2003年4月)、当社のホームページを見た方から電話をいただき、TK80のシミュレーションソフト が販売されていること、そしてそれを購入したけれども、やはりパソコン上での模擬体験ではなく実物がさわってみたい、 というお話しを聞きました。 さっそくネットで検索して、はじめてそういうものが売られていることを知りました(いかに自分がTK80から離れていた かの証左です)。 しかし!これはなんなのだ!ふつうシミュレーションとは実物が容易に体験できないものが対象であるはず(たとえば 航空機の操縦とか、電車でGOとか)。しかるにたかがワンボードマイコンをバーチャルで体験するとは何たる世の中で あるか!ここに実物が、ND80Kがあるではないか! もーぜんと闘志がわいてきました。 参考プログラム集も作ってやろーではないか!と怒りにまかせてゴールデンウィークを棒に振って作成したのが本書で す。 本書中のプログラムのほとんどは、当時出版されていた、岸田孝一著「マイコンゲーム21」(産報出版)からアイデアを 拝借しました。この本はいつか参考プログラム集を出すときに参考にしようと思い、本箱の隅に眠っていたものですが、 私自身はゲームには興味がなくまたそんなひまもなかったのでプログラムを打ち込んでみることもなくそのままになって いました。 参考プログラム集を作成しようと思い立ったとき真っ先に頭に浮かんだのが「マイコンゲーム21」でした。 TK80ソフトコンパチを売り物にしてきたとはいえ、ND80KはTK80とはクロックもメモリ容量も比較にならぬほど速く、 そして大容量です。「マイコンゲーム21」のニーモニックは8080(インテル)であるのに対して、ND80KではZ80(ザイ ログ)ニーモニックです。またZ80は8080に倍化する新しい命令が使えます。当然「マイコンゲーム21」のプログラムを そのまま使うというわけにはいきません。 またどうせ作るなら、「マイコンゲーム21」で作者が述べているように、こちらもプロのプログラマが作ったらこうなると いうところを見せようではないか、と思い至りました。そこでできるだけ「マイコンゲーム21」のゲームプログラムと同じ動 作をするプログラムを作ってみることにしました。しかしプロの意地でもあって、参考にしたのは各ゲームの説明部分の みでプログラムリストそのものは読んでいません(説明のみを読んでこの程度のプログラムがすぐに書けないようではプ ロにはなれません)。 この参考プログラム集は、そういうわけでプロの意地などという不純な動機でもって作成されたもので、良い教科書と なりうるものではないかもしれません。かなりアクの強いテクニックを随所で用いています。このようなテクニックはプログ ラマとして必ずしも必要なものではありませんから、敢えて学ぶ必要は無いとも思います。こういうクセは知らず知らずの 1 うちに身にしみついてきてしまいます。初心者にはわかりづらいところがあるかもしれません。そこは「意地」に免じてお 許しください。できるだけ説明を入れるようにしました。 もしも「マイコンゲーム21」をお持ちの方でしたら、両方のプログラムを比較することで、同じ動きをするプログラムでも 作者が違うこととCPUが8080に対してZ80であることで全く異なっている(多分そのはずです)ことに驚かれると思いま す。 「マイコンゲーム21」にはその名の通り21本のゲームが紹介されています。しかしこの参考プログラム集ではそのうち 何本かは割愛しました。当時と違いパソコンやTVゲームがあるのですから、8ケタのLEDだけで2次元的なゲームを表 現するのは余りに無理があるように感じたからです。 ND80Kは最近のWindowsパソコンから見たらまるで新幹線と自転車のようですが、しかしながらWindowsパソコン でC++やVisual Basicなどのプログラムを作るのは相当の知識を必要とするのに対し、かえってむずかしいはずの 機械語の方が簡単に扱えるように思えます。 なにはともあれ、レトロなマイコンの世界をじっくりお楽しみ下さい。 2003年5月 (有)中日電工代表者 菱田照久 記 ⅱ)プログラムリストについて プログラムはWindowsパソコンを使い、当社オリジナルの8080アセンブラ(ASM80)で作成しました。 ND8080は機械語で入力しますから、リストのうち必要なのは左端の4桁のアドレスとその次の機械語コードのみで す。 TK80は標準ではRAMが8200~83FFまでしか実装されていませんでした(たった512バイト!です)。そのためTK 80用に書かれたプログラムは大抵は8200番地から始っています。 ND8080は標準ではRAMとして32KB(キロバイト)の62256を実装していますから、TK80の64倍のメモリエリア があることになります。したがってTK80と同じように8200番地からプログラムを書くこともできますが、ND8080はプ ログラムの開始アドレスは8000番地からとなっているため、通常は8000番地から書くようにします。 プログラムによってはCPUレジスタだけでは不足することがあってRAM上にワークエリアを設けます。システムが使 わなくて、ユーザープログラムとも重ならないRAMアドレスならばどこでもよいのですが、このゲームプログラム集では8 200~に割り当てています。 実はこのゲーム集のプログラムは8080用に新規に作成したものではなくて、Z80用のソースプログラムを8080用に コンバートして、それに加筆訂正したものです。 そのため8080にはない命令には”?”がついていて、その前後にそれに代わる8080の命令文が書かれています。 ⅲ)附属CDROMのプログラム、データの扱い方 ND8080組立キットの附属CDROMにはこの応用プログラム集に記載したゲームプログラム、電子オルゴールプロ グラム、曲データが全て収録されています。 CDROM(nd8080フォルダ)にはプログラムがTK80形式のバイナリファイルで入っています(ソースプログラムはA SM80フォルダにあります)。 nd8080フォルダごとハードディスクにコピーしてください。 プログラムのロードはコマンドプロンプトで操作します。詳細についてはND8080操作説明書、USB接続説明書を参 照してください。 1)TK80モードでの操作を前提にしていますから、ND8080はTK80モニタモードで使ってください。 2)USBケーブルでND8080とWindowsパソコンを接続します。 3)ND8080のキーボードの[REG]キー(TK80モードでは[LOAD]キーとして働きます)を押してください。受信スタン バイになります。LED表示は変わりませんが[MON]キー([RESET]キー)以外は受け付けなくなります。 4)Windowsパソコンのコマンドプロンプト画面からHIDWR8コマンドを使って、ND8080で実行したいプログラム(拡 張子は.BTKです)を送信します。 >hidwr8 ohayo.btk[Enter] [注記]プログラムは8000番地からLOADされます。 2 プログラム№1 おはよー(OHAYO8.BTK) これはゲームではありません。「マイコンゲーム21」にもありません。雑誌だったのか、どういう本に載っていたのかも 思い出せません。実は私自身完全に忘れていました。覚えていたのはうちのカミさんでした。その昔に、私が何かの本を 見てこんな動作をするプログラムを入力して動かしてみせたのを覚えているというのです(げに世の女房族の記憶力に は恐怖すべきものがあります)。 カミさんの記憶を頼りに作ったのがこのプログラムです。ゲームではありませんが、オープニングの肩ならしにはちょう どよいと思います。 ではさっそくスタートです。 プログラムを入力して、[8][0][0][0][ADRSSET][RUN]とするとコンピュータが起きあがってのそりのそりと歩き 始めます(LEDに表示されるのは足跡のみ)。目をパチパチさせて、それからゆっくりと「おはよー」と声をかけます(言葉 は話せませんからLEDにそれもローマ字で表示します)。 このプログラムはこれでおしまいです。 プログラムの説明 (以下の説明文に出てくる命令やレジスタの機能などの基本的な内容や詳細は、ND8080に付属の8080命令説明 書を参照してください。またND8080のメモリアドレスやシステムサブルーチン、キーの操作などはND8080操作説明 書を参照してください) LEDに0~F以外のパターンを表示するとか、表示を全部クリアして(0を表示するのではなくて)ブランクにしたいとき などは、LED表示アドレス($83F8~$83FF)に直接書き込みます。各アドレスの8ビットのデータのうち1のビットに 対応するLEDのセグメントが点灯し0のビットに対応するセグメントは消灯します。以下のプログラムの中でLED1~LE D8に対してデータを書き込んでいるところは全部この目的で使われています。 ;EYE close/openやサブルーチンCLRがその例です。;ASIATO dispと;ohayo dispでは表示するデータを8 バイト分用意しておいて、全部の表示を順次置換えています。 サブルーチンCLRは$83F8~$83FFに00を書き込むことでLEDを全消灯しています。 ;ASIATO dispと;ohayo dispで使っているLDIは8080には無い命令なのでサブルーチンとしました。 本当は機械的にサブルーチン化するのではなくて、目的に合わせて適切なプログラムを書くべきなのですが、時間が 無い中での作業のため、安易な方法になってしまいました。 2016/4/20 END=8087 8000 CD5180 8003 217280 8006 11F883 8009 0E08 800B CD5E80 800E CD8280 8011 C20B80 8014 CD5E80 8017 CD5180 7:39 ohayo8.txt ; OHAYO for NDZ ; 03/04/28 5/9 ;10/6/1 for ND80Z3 ;16/4/17 for nd8080 ; ORG $8000 LED1=$83F8;$FFF8 LED4=$83FB;$FFFB START1=$0051;$080F TM5M=$02DD ; CALL CLR ;ASIATO disp LXI H,ASIDT LXI D,LED1 ; LXI B,$0008 MVI C,08 ASIDP2:CALL TM1S ;? LDI CALL LDI; ; JPE ASIDP2 JNZ ASIDP2 CALL TM1S CALL CLR 3 801A CD5E80 801D 801F 8022 8025 8028 0603 211C1C 113F3F 22FB83 CD6480 802B 802C 802F 8030 EB 22FB83 EB CD6180 8033 05 8034 C22580 8037 CD5180 803A 217A80 803D 11F883 8040 0E08 8042 CD6180 8045 CD8280 8048 C24280 804B CD5E80 804E C35100 8051 8054 8057 8058 21F883 010008 71 23 8059 05 805A C25780 805D C9 805E 8061 8064 8065 8067 8068 806B 806C 806D 8070 8071 CD6180 CD6480 D5 1E32 D5 CDDD02 D1 1D C26780 D1 C9 8072 8073 8074 8075 8076 8077 8078 8079 43 4C 43 4C 43 4C 43 4C CALL TM1S ;EYE close/open MVI B,03 LXI H,$1C1C LXI D,$3F3F EYE:SHLD LED4 CALL TM025 ;? LD (LED4),DE XCHG; SHLD LED4; XCHG; CALL TM05 ;? DJNZ *EYE DCR B JNZ EYE CALL CLR ;ohayo disp LXI H,OHAYODT LXI D,LED1 ; LXI B,$0008 MVI C,08; OHYDP2:CALL TM05 ;? LDI CALL LDI; ; JPE OHYDP2 JNZ OHYDP2; CALL TM1S JMP START1 ;LED clear CLR:LXI H,LED1 LXI B,$0800 CLR2:MOV M,C INX H ;? DJNZ *CLR2 DCR B; JNZ CLR2; RET ;1sec timer/0.5sec timer/0.25sec timer TM1S:CALL TM05 TM05:CALL TM025 TM025:PUSH D MVI E,32;=50 TM025_2:PUSH D CALL TM5M;4.684ms POP D DCR E JNZ TM025_2 POP D RET ;asiato data ASIDT:DB 43 DB 4C DB 43 DB 4C DB 43 DB 4C DB 43 DB 4C 4 807A 807B 807C 807D 807E 807F 8080 8081 3F 76 77 6E 3F 40 40 40 8082 8083 8084 8085 8086 8087 7E 12 23 13 0D C9 ASIDP2 CLR2 LED1 OHYDP2 TM025_2 TM5M ;"ohayo---" OHAYODT:DB 3F;O DB 76;H DB 77;A DB 6E;y DB 3F;O DB 40;DB,40;DB 40;; LDI:MOV A,M STAX D INX H INX D DCR C RET ; =800B ASIDT =8057 EYE =83F8 LED4 =8042 START1 =8067 TM05 =02DD =8072 =8025 =83FB =0051 =8061 CLR LDI OHAYODT TM025 TM1S =8051 =8082 =807A =8064 =805E 5 プログラム№2 CRAZY EIGHT(CRAZY88.BTK) ゲームの説明 8000番地からRUNするとスピーカからピーと音が出て、LEDが全部消え、キー入力待ちになります。 ゲームはLED1~LED8のどこをコンピュータが選ぶか予測してその番号をキー入力するものです。 1~8のいずれかのキーを押すとその数に対応するLEDに”8”の下半分が表示されます。次の瞬間にコンピュータが 選んだ位置に”8”の上半分が表示されます。もし位置が一致すれば”8”の字が完成しピッピッという断続音とともにそ の”8”が点滅したあと点灯して静止します。位置が異なれば下半分と上半分が離れて表示されるだけで何もおこりませ ん。続いて残った消灯しているLEDから同じようにコンピュータの選択を予測して、その位置の数をキー入力します。こ れを繰り返してブランクが全て無くなればゲーム終了です。約2秒後にLEDの右2桁に獲得した点数が表示されます。 点数は”8”ができるごとに加算されます。加算される点数はその”8”の表示直前のLEDが消灯している数になります。 ゲーム開始直後は全部消灯していますから、最初にうまくヒットして”8”ができれば8点ゲットです。失敗すると2ヶ所が 点灯しますから残りは6個で、6点が次の”8”完成によって加算される得点になります。 数を入力するときに間違えて1~8以外のキーを押したり、すでに表示済みのLEDを示す数を入力しても無視されま す。 点数表示状態でどこかキーを押すと最初にもどって再びゲームが開始されます。このとき得点もゼロクリアされます。 プログラムの説明 CPUのレジスタだけでは足りないのでメモリ上にワークエリアを設けます。キー入力位置を記憶するYRADRS(your addressのつもり。名前は自分がわかる適当な名前をつける。これはアセンブラに必要なもので機械語に直してしまえ ば、ただのアドレスになってしまう。この場合は8003)、LEDの残り消灯数を格納するREST、乱数の作業用にRNDD T、RNDDT2、獲得した点数をカウントするCNTRです。 CNTRは普通のRAMエリアではなくて、システムのデータエリアである83F7を指定しています。 このあたりが機械語プログラムを書くときにアクの強さが出てくるところです。83F7はLEDの表示用のデータエリアで、 このプログラムでは最後の点数表示以外では使用しないのではじめから表示用データエリアをカウンタとして使ってしま おうというわけです。なおこのカウンタは点数を加算し、それを10進で表示するため、バイナリではなくて10進で演算し ます。 さてキー入力ですが、1~8の入力のチェックにCPI 09はよいのですが、ORA A、JZとしないのはなぜでしょう? そうする代わりにDCR A、JMとしています。 こういうところにプログラマの性格が現れます。なんともせっかちな…。 じつはここで入力した数は、そのあとで対応するLEDアドレスを計算するのに使いますが、そこでは1~8ではなくて0 ~7でないと都合が悪いのです。どうせ後でDCRするなら、ここでDCRを実行して同時に0キー入力も除外してしまおう というささやかなアイデアです。 なおLEDアドレスの算出は本来は、 LXI H,LED1 MOV E,A MVI D,00 DAD D とするべきです。ここでは、ADD Lとしています。わかっていてするのはテクニックですが初心者は誤解してしまいま す(教科書としては不適切です)。こういうプログラムを書くと学校のテストなら×になるかもしれません。しかし私が先生 ならこの設定でこのプログラムは◎をあげます。 上で例示したプログラムはどんな場合でも通用するプログラムです。初心者はこう書けば間違いありません。しかし今 回はデータに一定範囲の条件があります。Aの値は0~7で、HL=83F8という条件です。この場合にはADD Lでも、 ORA Lでも構いません。 さてMYTURNでは乱数を使って、コンピュータ側の1~8を発生させています。実際には上と同じ理由で0~7を用い ています。乱数については後で説明します。 とにかくサブルーチンRND3をCALLすると、00~07の範囲のランダムな数が得られます。プレーヤーが入力した数 (YRADRS)と一致すれば”8”になりますが、それ以外ですでに点灯済みのLEDを選択するのは無効ですから、それを チェックして、点灯済みなら乱数発生からやりなおします。 結果が不一致の場合にはLEDの残りが2つ減りますから、(REST)に対して2回DECを実行します。その結果(RES T)=0になったらゲーム終了です。 結果が一致したらヒットです。HIT:でその処理をします。サウンドの出力と、”8”の点滅表示のあと、点数を加算します。 (CNTR)に(REST)を加算します。10進数(BCD)として扱うため10進補正命令、DAAを使っています。 ではなぜ10進数なのか?なぜ10進補正が必要なのか? それは(CNTR)の値を最後にLEDに表示させるためです。通常の2進演算の場合、09+01は0Aになります。これを (CNTR)に入れてLEDにそのまま表示させると、0Aと表示されてしまいます。09+01の加算後にDAAを実行するとA レジスタの値は、10になります。これをそのままLEDに表示すれば10進の計算結果として正しく点数が表示されること 6 になります。 結果が一致したときは、LEDの残りは1つしか減りません。(REST)に対してDCRを1回だけ実行します。その結果 (REST)が奇数の場合と偶数の場合が出てきます。その両方の場合でゲーム終了の判断が異なります。 END:がゲーム終了での処理です。ここでやっとCNTRとしてLEDの表示用データレジスタをそのまま使用したわけが 明らかになります(なんとずる賢い)。 データ表示ルーチン01C0をCALLすれば何もしなくても点数がLEDの右2桁に表示されます。残りの6桁には無関係 な値が表示されてしまいますからLEDレジスタに00を書き込んでLED1~LED6の表示を消してしまいます。 乱数について ゲームではよくサイコロを使います。ところがコンピュータでサイコロを作るのはなかなか大変なのです。本格的な乱数 発生の計算方法もいろいろ考案されているらしいのですが、たかがワンボードのゲームのために複雑な計算をするのは ちょっと考え物です。といっていいかげんではゲームになりません。一番よいのは乱数表をメモリに入れておくことなので すが、仮にそうしたとしても、そのどこを読むかが問題です。毎回同じアドレスを選択したり、その選択する順序が毎回同 じであったりすれば乱数にはなりません。 ここでは擬似的な乱数表として、ROMに書かれたプログラムの命令コードを利用しています。コードの並びはプログラ ムとしては意味がありますが、数としてみれば大小順序はばらばらで乱数的と言えます。しかし完全ではなくて、よく使 われる命令コードやアドレスは頻繁に現れます。 乱数発生サブルーチンRND3では連続して同じ数が出ないように工夫しています。また次のアドレスを算出するときも 毎回同じ流れにならないようにするため、キー入力のときにコールされるチャタリングタイマーに乱数用の初期値カウン タR(=FFD2)を組み込んで、タイマーがコールされるたびに+1されるようにして、それを利用しています。 RNDの実行結果はまあまあですが、ときとしてちょっとできの悪いサイコロになることもあります。とりあえずは簡単な ゲーム用ですから、こんなものでしょう。 2016/4/20 END=8136 8000 8003 8004 8005 8006 8007 8008 800B 800E 800F 8010 8011 C30880 00 00 00 00 00 3AD2FF 210580 77 23 77 CDD880 11:50 crazy88.txt ; CRAZY EIGHT for NDZ ; 03/05/07 5/9 ;10/6/1 for ND80Z3 ;16/4/16 for nd8080 ;4/18 sound,timer ;4/19 rnd ;4/20 ; ORG $8000 ; YRADRS=$E800 ; REST=$E801 ; RNDDT=$E810;$E811 CNTR=$83F7;$FFF7;=DP4 LED1=$83F8;$FFF8 R=$FFD2 ; DTDPS=$01C0;$05C0;DATA DISP KEYIN1=$0216;$0616 D1=$02DD;4.684msec ; ;data set JMP START YRADRS:NOP REST:NOP RNDDT:NOP NOP RNDDT2:NOP START:LDA R LXI H,RNDDT MOV M,A INX H MOV M,A CALL CLR 7 8014 8015 8018 801A AF 32F783 3E08 320480 801D 3E10 801F 060A 8021 CDE580 8024 8025 8028 802B 802D 8030 8031 05 C22180 CD1602 FE09 D22880 3D FA2880 8034 8037 803A 803B 803C 803D 803E 8041 320380 21F883 85 6F 7E B7 C22880 365C 8043 CDBA80 8046 8047 804A 804B 804E 804F 8052 8053 8054 8055 8056 8059 805C 805E 8061 8064 8066 8069 806A 806B 806E 57 3A0380 BA CA7180 7A 21F883 85 6F 7E B7 CA6480 3A0480 FE01 CA9F80 C34380 3663 210480 35 35 C22880 C39F80 8071 8074 8075 8076 8078 807A 807C 807E 21F883 85 6F 0E05 367F 3E17 0603 CDE580 XRA A STA CNTR;DECIMAL COUNTER clear MVI A,08 STA REST ;GAME START MVI A,10;puuuu MVI B,0A START1:CALL SOUND ;? DJNZ START1 DCR B; JNZ START1; KEY:CALL KEYIN1 CPI 09 JNC KEY DCR A JM KEY ;keyin position check STA YRADRS;position save LXI H,LED1 ADD L MOV L,A MOV A,M ORA A JNZ KEY;already used MVI M,5C;"low" disp ;my turn MYTURN:CALL RND3;0-7 select ; ANI 07 MOV D,A LDA YRADRS CMP D JZ HIT MOV A,D LXI H,LED1 ADD L MOV L,A MOV A,M ORA A JZ MYTN2;not used LDA REST CPI 01 JZ END;no rest JMP MYTURN MYTN2:MVI M,63;"high" disp LXI H,REST DCR M DCR M JNZ KEY JMP END ; HIT:LXI H,LED1 ADD L MOV L,A MVI C,05 HIT1:MVI M,7F;"8" disp MVI A,17;piii MVI B,03 HIT2:CALL SOUND 8 ;? 8081 8082 8085 8087 808A 808B 808E 8090 8093 8096 8097 8098 809B 809C 809F 80A1 05 C27E80 3600 CD2681 0D C27880 367F 210480 3AF783 86 27 32F783 35 C22880 0614 CD2981 80A4 80A5 80A8 80AB 80AE 80B0 80B1 80B4 80B7 05 C2A180 CDC001 21F883 0606 AF CDDE80 CD1602 C30880 80BA 80BB 80BC 80BF 80C0 80C1 80C3 80C4 80C7 80CA 80CB 80CC 80CE 80CF 80D2 80D5 80D6 80D7 E5 D5 2A0580 23 7C E603 67 220580 3A0780 57 7E E607 BA CABC80 320780 D1 E1 C9 80D8 80DB 80DC 80DE 80DF 21F883 AF 0608 77 23 80E0 05 80E1 C2DE80 80E4 C9 DJNZ HIT2 DCR B; JNZ HIT2; MVI M,00 CALL TM02S DCR C JNZ HIT1 MVI M,7F LXI H,REST LDA CNTR;point up ADD M DAA STA CNTR DCR M JNZ KEY END:MVI B,14;=20 ,2sec wait WAIT:CALL TM01S ;? DJNZ WAIT DCR B; JNZ WAIT; CALL DTDPS LXI H,LED1 MVI B,06 XRA A END2:CALL CLR1 CALL KEYIN1 JMP START ; ;ransu RND3:PUSH H PUSH D RND2:LHLD RNDDT INX H MOV A,H ANI 03 MOV H,A SHLD RNDDT LDA RNDDT2 MOV D,A MOV A,M ANI 07 CMP D JZ RND2 STA RNDDT2 POP D POP H RET ; ;LED all clear CLR:LXI H,LED1 XRA A MVI B,08 CLR1:MOV M,A INX H ;? DJNZ *CLR1 DCR B; JNZ CLR1; RET 9 80E5 80E6 80E7 80E8 80E9 80EC 80ED 80EE 80EF 80F1 80F2 80F4 80F6 80F7 80F8 80FB 80FC 80FE 8100 8101 8102 8105 8106 8109 810A 810B 810C 810D F5 E5 D5 C5 210E81 85 6F 46 1E1A 50 3EFF D398 7F 15 C2F680 50 3EDF D398 7F 15 C20081 1D C2F180 C1 D1 E1 F1 C9 810E 810F 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 811A 811B 811C 811D 811E 811F 8120 8121 8122 8123 8124 8125 7F 77 71 6A 5F 59 54 4F 47 43 3F 3B 35 32 2F 2C 25 27 2A 4B 38 64 23 21 8126 CD2981 ; ; SOUND:PUSH PSW PUSH H PUSH D PUSH B LXI H,SNDTBL ADD L MOV L,A MOV B,M MVI E,1A SNDS1:MOV D,B MVI A,FF;SP OUT=H OUT 98 SNDS2:MOV A,A;5--------DCR D;5 | 5+5+10=20 JNZ SNDS2;10---MOV D,B MVI A,DF;sp out=L OUT 98 SNDS3:MOV A,A;5--------DCR D;5 | 5+5+10=20 JNZ SNDS3;10---DCR E JNZ SNDS1 POP B POP D POP H POP PSW RET ; SOUND TABLE SNDTBL:DB 7F;so4 DB 77;so#4 DB 71;ra4 DB 6A;ra#4 DB 5F;do5 DB 59;do#5 DB 54;re5 DB 4F;re# DB 47;fA5 DB 43;fa#5 DB 3F;so5 DB 3B;so5# DB 35;ra#5 DB 32;si5 DB 2F;do6 DB 2C;do#6 DB 25;mi6 DB 27;re#6 DB 2A;re6 DB 4B;mi5 DB 38;ra5 DB 64;si4 DB 23;fa6 DB 21;fa#6 ; ;0.2sec timer TM02S:CALL TM01S 20/2=10microsec 20/2=10microsec 10 8129 812A 812C 812D 8130 8131 8132 8135 8136 D5 1E15 D5 CDDD02 D1 1D C22C81 D1 C9 CLR D1 END2 HIT2 LED1 R RND3 SNDS1 SNDTBL START1 TM02S ;0.1sec timer TM01S:PUSH D MVI E,15;=21 TM01S2:PUSH D CALL D1;4.684ms POP D DCR E JNZ TM01S2 POP D RET ; =80D8 CLR1 =02DD DTDPS =80B1 HIT =807E KEY =83F8 MYTN2 =FFD2 REST =80BA RNDDT =80F1 SNDS2 =810E SOUND =8021 TM01S =8126 WAIT =80DE =01C0 =8071 =8028 =8064 =8004 =8005 =80F6 =80E5 =8129 =80A1 CNTR END HIT1 KEYIN1 MYTURN RND2 RNDDT2 SNDS3 START TM01S2 YRADRS =83F7 =809F =8078 =0216 =8043 =80BC =8007 =8100 =8008 =812C =8003 11 プログラム№3 Hi-Lo(HILO8.BTK) ゲームの説明 8000番地からRUNするとLEDの左2桁に、--が表示され、右4桁に0000が表示されます。このときコンピュータ は乱数を利用して4桁の数0000~9999を算出して隠しています。それを当てるゲームです。 キーから適当な数、たとえば4567と入力してWRITE INCキーを押すと、コンピュータは入力された数と、自分が隠 している数とを比較して、入力された数が隠した数よりも大きければLEDの左2桁に、Hi と表示します。小さければ、L o と表示します。この表示を参考にして、なるべく少ない回数で正解を得るのが目的です。 キーからの数値の入力はWRITE INCキーを押さない限りは何回でも入れなおしができます。 正解が出ると、LEDの左2桁にそれまでの入力回数が表示され、LED全体が約2秒間点滅したあと、最初に戻って新 しい数が選択されてゲームが再開されます。 プログラムの説明 最初にRND4サブルーチンを4回CALLして4桁のBCD数を求めて、HIDNDTに格納します(hidden dataのつもり)。 試行回数をカウントするCNTRは先回のCRAZY EIGHTと同じ手ですが、今回はLEDの左2桁に結果を表示するため、 アドレスは83EFに割り当てています。先回は表示用データレジスタ(83F4~83F7)をカウンタに利用したのですが、 今回はアドレス、データレジスタ(83EC~83EF)を利用しています。今回のプログラムではキー入力された数値をデー タレジスタに一度格納してからそれを表示するので、カウンタもアドレスレジスタに置かなければなりません。キー入力さ れた数値はLED表示用データレジスタに置くこともできるのですが、そうするとHとLの位置が逆になるので、プログラム が少し面倒になります。 (参考) HLの数値をデータレジスタに入れる場合 SHLD DTRG HLの数値をLED表示用データレジスタに入れる場合 XCHG LXI H,DP3;DP3=$83F6 MOV M,D INX H MOV M,E ;compare DATA でデータの比較を行っています。HL、DEともにBCD数なので、SBC HL,DE(この命令は80 80にはないのでサブルーチンSBCHLDEをコール)を行っても正しい結果は得られません。しかしここでは差を計算す ることが目的ではなくて大小がわかればよいので、比較命令としてつかっているのでこれでよいのです。 ALBLNKサブルーチンではND8080のDMAによるLEDの表示機能を利用しています。 LEDの一部だけを点滅させる場合には、表示データを一定時間毎にブランクと入れ替えて表示します。 しかしここでは全部を点灯、消灯すればよいのですから、LED表示回路が行っているDMAによる表示を禁止したり、 許可したりすればよいことになります。LEDONはLED表示のDMA許可ルーチンでLEDOFFはDMA禁止ルーチンで す。 2016/4/20 END=8102 11:49 hilo8.txt ; Hi-Lo for NDZ ; 03/04/29 4/30 5/1 5/3 5/5 5/9 5/10 ;10/6/1 for ND80Z3 ;16/4/16 for ND8080 ;4/18 ;4/19 rnd ;4/20 ; ORG $8000 ; HIDNDT=$E800;$E801 ; RNDDT=$E810;$E811 DTRG=$83EC;$FFEC ADRG=$83EE;$FFEE CNTR=$83EF;$FFEF;=ADRGH LED1=$83F8;$FFF8 12 LED3=$83FA;$FFFA R=$FFD2 ; ADDPS=$01A1;$05A1 KEYIN1=$0216;$0616 D1=$02DD;4.684msec ; 8000 8003 8004 8005 8006 8007 C30880 00 00 00 00 00 8008 800B 800E 800F 8010 8011 8013 3AD2FF 210580 77 23 77 0604 CD8480 8016 8018 801B 801C 801D 801E 801F 8020 FE0A D21380 29 29 29 29 B5 6F 8021 8022 8025 8028 802B 802E 8031 8032 8035 8038 803B 05 C21380 220380 210000 22EE83 22EC83 E5 CDA101 21CF80 CDC580 E1 803C 803F 8041 8044 8046 8049 804A 804B 804C 804D 804E 804F CD1602 FE15 CA5280 FE0A D23C80 29 29 29 29 B5 6F C32E80 8052 3AEF83 JMP START HIDNDT:NOP NOP RNDDT:NOP NOP RNDDT2:NOP ;data(hidden) set START:LDA R LXI H,RNDDT MOV M,A INX H MOV M,A MVI B,04 DTST1:CALL RND4 ; ANI 0F CPI 0A JNC DTST1 DAD H DAD H DAD H DAD H ORA L MOV L,A ;? DJNZ *DTST1 DCR B; JNZ DTST1; SHLD HIDNDT LXI H,$0000 SHLD ADRG;DECIMAL COUNTER clear REENT:SHLD DTRG PUSH H CALL ADDPS LXI H,STDT REENT1:CALL H4DP POP H ;key entry(0000-9999) KEY:CALL KEYIN1 CPI 15;WRITE INC JZ COMP CPI 0A JNC KEY DAD H DAD H DAD H DAD H ORA L MOV L,A JMP REENT ;compare DATA COMP:LDA CNTR;DECIMAL COUNTER up 13 8055 8057 8058 805B C601 27 32EF83 B7 805C 805D 8060 8061 EB 2A0380 EB E5 8062 8065 8068 806B 806E 8071 8074 8075 8078 807B CDDB80 CA7480 21D780 DA3880 21D380 C33880 E1 CDA101 210000 22FA83 807E CDA280 8081 C30880 8084 8085 8086 8089 808A 808B 808D 808E 8091 8094 8095 8096 8098 8099 809C 809F 80A0 80A1 E5 D5 2A0580 23 7C E603 67 220580 3A0780 57 7E E60F BA CA8680 320780 D1 E1 C9 80A2 80A4 80A6 80A8 80AB 80AD 80AF 060A 3EEF D398 CDB780 3EFF D398 CDB780 80B2 05 80B3 C2A480 80B6 C9 ADI 01 DAA STA CNTR ORA A;clear CARRY ;? LD DE,(HIDNDT) XCHG; LHLD HIDNDT; XCHG; PUSH H ;? SBC HL,DE CALL SBCHLDE; JZ SAME LXI H,LODT JC REENT1 LXI H,HIDT JMP REENT1 SAME:POP H CALL ADDPS LXI H,$0000 SHLD LED3 ;OK! ALL LED blink CALL ALBLNK JMP START ; ;ransu RND4:PUSH H PUSH D RND2:LHLD RNDDT INX H MOV A,H ANI 03 MOV H,A SHLD RNDDT LDA RNDDT2 MOV D,A MOV A,M ANI 0F CMP D JZ RND2 STA RNDDT2 POP D POP H RET ; ;LED all blink ALBLNK:MVI B,0A;=10 ALBLNK1:MVI A,EF OUT 98;LED OFF CALL TM01S MVI A,FF OUT 98;LED ON CALL TM01S ;? DJNZ *ALBLNK1 DCR B; JNZ ALBLNK1; RET ; ;0.1sec timer 14 80B7 80B8 80BA 80BB 80BE 80BF 80C0 80C3 80C4 D5 1E15 D5 CDDD02 D1 1D C2BA80 D1 C9 80C5 11F883 80C8 010400 80CB CDF680 80CE C9 80CF 80D0 80D1 80D2 80D3 80D4 80D5 80D6 80D7 80D8 80D9 80DA 40 40 00 00 76 06 00 00 38 3F 00 00 80DB 80DC 80DD 80DE 80DF 80E0 80E1 80E2 80E3 80E6 80E9 80EA 80ED 80EE 80EF 80F0 80F2 80F3 80F4 80F5 C5 47 7D 9B 6F 7C 9A 67 DAED80 FAED80 B5 C2F080 78 C1 C9 3E01 B7 78 C1 C9 80F6 80F7 80F8 80F9 80FA 80FB 80FC F5 7E 12 23 13 0B 78 TM01S:PUSH D MVI E,15;=21 TM01S2:PUSH D CALL D1;4.684ms POP D DCR E JNZ TM01S2 POP D RET ; ;High 4 disp H4DP:LXI D,LED1 LXI B,$0004 ;? LDIR CALL LDIR; RET ; STDT:DB 40 DB 40 DB 00 DB 00 HIDT:DB 76;H DB 06;i DB 00 DB 00 LODT:DB 38;L DB 3F;O DB 00 DB 00 ; SBCHLDE:PUSH B MOV B,A MOV A,L SBB E MOV L,A MOV A,H SBB D MOV H,A JC SBCHLDE1 JM SBCHLDE1 ORA L JNZ SBCHLDE2 SBCHLDE1:MOV A,B POP B RET SBCHLDE2:MVI A,01 ORA A;clear sf MOV A,B POP B RET ; LDIR:PUSH PSW LDIR2:MOV A,M STAX D INX H INX D DCX B MOV A,B 15 80FD 80FE 8101 8102 B1 C2F780 F1 C9 ADDPS ALBLNK1 D1 H4DP KEY LDIR2 LODT REENT1 RNDDT SBCHLDE START TM01S2 ORA C JNZ LDIR2 POP PSW RET ; =01A1 =80A4 =02DD =80C5 =803C =80F7 =80D7 =8038 =8005 =80DB =8008 =80BA ADRG CNTR DTRG HIDNDT KEYIN1 LED1 R RND2 RNDDT2 SBCHLDE1 STDT =83EE =83EF =83EC =8003 =0216 =83F8 =FFD2 =8086 =8007 =80ED =80CF ALBLNK COMP DTST1 HIDT LDIR LED3 REENT RND4 SAME SBCHLDE2 TM01S =80A2 =8052 =8013 =80D3 =80F6 =83FA =802E =8084 =8074 =80F0 =80B7 16 プログラム№4 FLIPFLOP(FLIPFLOP8.BTK) ゲームの説明 8000番地からRUNするとLEDに”8”の上半分が8個表示されます。各桁を示す1~8の数をキーから入力すると、 その位置のLEDが点滅します。それでよければWRITE INCキーを押します。WRITE INCキーを押す前なら別の数 を入れなおして位置の指定を変更することができます。WRITE INCを押すと指定位置の今点滅しているLEDの表示 が上下反転します。上半分の表示は下半分の表示になり、下半分の表示は逆に上半分の表示になります。ゲーム開始 時点でコンピュータは乱数によって各LEDに別のLEDを結びつけています。そのため、指定位置のLEDが反転すると ともに関係つけられた別のLEDも一緒に反転してしまいます。関係つけのリンクは1本のみで、自分自身を指定してい るときもあります。この場合には他のLEDは反転しません。関係つけの方向は一方向のみです。たとえばLED1を指定 したときにLED3が同時に反転したとしても、次にLED3を指定したときにLED1も同時に反転するとは限りません。逆 にLED3はLED6からも関係つけられているかもしれません。その場合はLED1を指定しても、LED6を指定してもそれ ぞれ同時にLED3が反転することになります。 首尾良く全部の表示が下半分になると、全部の表示が点滅し2秒後に、それまでの試行回数が表示されます。さらに 2秒たつと最初からゲームが再スタートします。関係つけによってはエンドレスになってしまってゲームが終了しない場 合もあります。そんなときはリセットしてもう一度8000番地からRUNしてください。 プログラムの説明 このプログラムでは各LEDにリンクされているLEDの番号を格納する場所としてLINKBF(8バイト)を用意しています。 はじめに各LED位置毎にRND3サブルーチンによって1~8(実際には0~7)を求めて対応するLINKBF以降の8バイ トに順に数を割り当てて行きます。 KEY:ではLED表示静止の状態でキー入力を待つため、KEYIN1($0216)をCAllしていますが、BLNK0:以下の 部分では表示をブリンクさせながらキーの入力をチェックしなければならないため、KEYIN2($0223)をCALLしてい ます。 2016/4/20 END=8104 8000 8003 8004 8005 8006 8007 8008 8009 C30E80 00 00 00 00 00 00 00 11:51 flipflp8.txt ; FLIP-FLOP for NDZ ; 03/04/29 4/30 5/1 5/3 5/5 5/10 ;10/6/1 for ND80Z3 ;16/4/16 for ND8080 ;4/17 ;4/19 ;4/20 ; ORG $8000 ; LINKBF=$E800 ; RNDDT=$E810;$E811 LED1=$83F8;$FFF8 DP1=$83F4;$FFF4 DP3=$83F6;$FFF6 CNTR=$83F7;$FFF7;=DP4 R=$FFD2 ; DTDPS=$01C0;$05C0 KEYIN1=$0216;$0616 KEYIN2=$0223;$0623 D1=$02DD;4.684msec ; JMP START LINKBF:NOP NOP NOP NOP NOP NOP NOP 17 800A 800B 800C 800D 00 00 00 00 800E 8011 8014 8015 8016 8017 8019 801B 801E 801F 3AD2FF 210B80 77 23 77 3E63 0608 21F883 77 23 8020 8021 8024 8027 802A 05 C21E80 210000 22F683 22F483 802D 0608 802F 210380 8032 CDC480 8035 77 8036 23 8037 05 8038 C23280 803B 803E 8040 8043 8044 CD1602 FE09 D23B80 3D FA3B80 8047 804A 804B 804C 804D 804E 8050 8051 8054 8055 8056 8059 805A 805B 805D 8060 8061 8064 8065 8068 21F883 85 6F 56 42 0E00 71 CDF780 D5 C5 CD2302 C1 D1 FE09 D26880 3D FA6D80 72 C34780 FE15 NOP RNDDT:NOP NOP RNDDT2:NOP ;all"UP" disp START:LDA R LXI H,RNDDT MOV M,A INX H MOV M,A MVI A,63;"UP" MVI B,08 LXI H,LED1 UPDP1:MOV M,A INX H ;? DJNZ UPDP1 DCR B; JNZ UPDP1; LXI H,$0000 SHLD DP3;DECIMAL COUNTER clear SHLD DP1 ;LINK set MVI B,08 LXI H,LINKBF LNKST1:CALL RND3 ; ANI 07 MOV M,A INX H ;? DJNZ LNKST1 DCR B; JNZ LNKST1; ;key entry KEY:CALL KEYIN1 CPI 09 JNC KEY DCR A JM KEY ;LED blink and wait WINC in BLNK0:LXI H,LED1 ADD L MOV L,A MOV D,M;LED data save MOV B,D MVI C,00 BLNK1:MOV M,C CALL TM01S PUSH D PUSH B CALL KEYIN2 POP B POP D CPI 09 JNC BLNK2 DCR A JM BLNK3 MOV M,D JMP BLNK0 BLNK2:CPI 15;WRITE INC 18 806A 806D 806E 806F 8070 CA7380 79 48 47 C35080 8073 8074 8076 8077 807A 807C 72 3E63 BE C27C80 3E5C 77 807D 807E 8080 8081 8084 8085 8086 8087 8088 808B 808E 808F 8090 8092 8093 8096 8098 8099 809C 809E 809F 7D E607 57 210380 85 6F 7E BA CA9980 21F883 85 6F 3E63 BE C29880 3E5C 77 3AF783 C601 27 32F783 80A2 80A5 80A7 80A9 80AA 80AD 21F883 0608 3E5C BE C23B80 23 80AE 05 80AF C2A980 80B2 80B5 80B8 80BA CDE280 CDC001 0614 CDF780 80BD 05 80BE C2BA80 80C1 C30E80 80C4 E5 80C5 D5 80C6 2A0B80 JZ REVRS BLNK3:MOV A,C MOV C,B MOV B,A JMP BLNK1 ;LED reverse REVRS:MOV M,D MVI A,63;"UP" CMP M JNZ REVRS1 MVI A,5C;"DOWN" REVRS1:MOV M,A ;link LED reverse MOV A,L ANI 07 MOV D,A; No. save LXI H,LINKBF ADD L MOV L,A MOV A,M CMP D JZ REVRS3;same No.(no LINK) LXI H,LED1 ADD L MOV L,A MVI A,63;"UP" CMP M JNZ REVRS2 MVI A,5C;"DOWN" REVRS2:MOV M,A REVRS3:LDA CNTR;DECIMAL COUNTER up ADI 01 DAA STA CNTR ;check LXI H,LED1 MVI B,08 MVI A,5C;"DOWN" CK1:CMP M JNZ KEY;not success INX H ;? DJNZ *CK1 DCR B; JNZ CK1; ;OK! ALL LED blink and COUNTER disp CALL ALBLNK CALL DTDPS MVI B,14;=20 ,2sec wait WAIT:CALL TM01S ;? DJNZ WAIT DCR B; JNZ WAIT; JMP START ; ;ransu RND3:PUSH H PUSH D RND2:LHLD RNDDT 19 80C9 80CA 80CB 80CD 80CE 80D1 80D4 80D5 80D6 80D8 80D9 80DC 80DF 80E0 80E1 80E2 80E4 80E6 80E8 80EB 80ED 80EF 23 7C E603 67 220B80 3A0D80 57 7E E607 BA CAC680 320D80 D1 E1 C9 060A 3EEF D398 CDF780 3EFF D398 CDF780 80F2 05 80F3 C2E480 80F6 C9 80F7 D5 80F8 C5 80F9 0615 80FB CDDD02 80FE 05 80FF C2FB80 8102 C1 8103 D1 8104 C9 ALBLNK BLNK1 CK1 DP1 KEY LED1 R REVRS2 RND3 START UPDP1 INX H MOV A,H ANI 03 MOV H,A SHLD RNDDT LDA RNDDT2 MOV D,A MOV A,M ANI 07 CMP D JZ RND2 STA RNDDT2 POP D POP H RET ; ;LED all blink ALBLNK:MVI B,0A;=10 ALBLNK1:MVI A,EF;LED OFF OUT 98 CALL TM01S MVI A,FF;LED ON OUT 98 CALL TM01S ;? DJNZ *ALBLNK1 DCR B; JNZ ALBLNK1; RET ; ;0.1sec timer TM01S:PUSH D PUSH B MVI B,15;=21 TM01S2:;CALL TM1M CALL D1;4.684ms DCR B JNZ TM01S2 POP B POP D RET =80E2 ALBLNK1 =80E4 =8050 BLNK2 =8068 =80A9 CNTR =83F7 =83F4 DP3 =83F6 =803B KEYIN1 =0216 =83F8 LINKBF =8003 =FFD2 REVRS =8073 =8098 REVRS3 =8099 =80C4 RNDDT =800B =800E TM01S =80F7 =801E WAIT =80BA BLNK0 BLNK3 D1 DTDPS KEYIN2 LNKST1 REVRS1 RND2 RNDDT2 TM01S2 =8047 =806D =02DD =01C0 =0223 =8032 =807C =80C6 =800D =80FB 20 プログラム№5 SWAP(SWAP8.BTK) ゲームの説明 8000番地からRUNするとLEDの左3桁に”8”の下半分が表示されその右に1桁のブランクがあってさらに右3桁に は”8”の上半分が表示されます。右端の1桁はブランクでこの桁は使用しません。 ルールにしたがって表示を移動し、左3桁の表示と右3桁の表示を上下入れ替えるのがゲームの目的です。 ルールは次の通りです。 1)ブランクの隣の表示はブランクと位置を交代することができます。 2)隣に異なる表示があるとき、その表示をはさんでさらにその隣がブランクならば、間の表示を飛び越してブランクと表 示位置を交代することができます。たとえば表示が[下][上][ブランク]とならんでいる時、[下]のLED番号をKEY入力 すると、[ブランク][上][下]に表示が入れ替わります。ルールに合わない表示を指定しても無視されます。 入れ替えたいLED位置を示す数をKEY入力するとその位置のLEDが点滅します。それでよければWRITE INCキー を押します。WRITE INCキーを押す前なら別の数を入れなおして位置の指定を変更することができます。WRITE IN Cを押すとルールにしたがって表示とブランクが入れ替わります。ルールに合わない場合には点滅は続きますが入れ替 えは行われません。 うまく全部の入れ替えに成功すると2秒間表示が点滅し、さらに2秒間試行回数が表示されたあと、最初に戻って再び ゲームが開始されます。 プログラムの説明 このプログラムではシステムのワークエリア以外は使用しません。LED表示はLED表示用のアドレスをそのまま使用 しています。また乱数も使いません。その割りには結構ややこしいプログラムです。こういうプログラムが得意な人と不 得意な人がでてきます。いかにもコンピュータ的なプログラムです。ややこしいのは、場合分けが何通りもあるからです。 こういう作業が苦手なプログラマは何か別のうまい方法を考えようとします。それはそれでよいので、こう書かなければ ならないというきまりはありません。こういうところでプログラマの個性が出て来ます。 私はというと割りと得意というか、苦にならない方なので、こんな感じに書いてしまいます。 場合分けはまずキー入力されたLED位置の左の状態を確認して、それから右を確認します。右から見ていっても構い ません(たまたま私は左利きなのでどうしても左が先になってしまいます)。 順に確認します。CHECK:のルーチンです。 ①入力した番号のLEDは左端か?これはLEDアドレスの下位3ビットが0であることで確認できます(LED1=$FFF 8)。このときは右側のチェックに行きます。 ②1 つ左はブランクか?左のLEDアドレスのデータが00ならブランクです。置換えルーチンへ行きます。 ③1つ左は自分(KEY入力したLEDアドレス)と同じ表示データか?同じ場合は右側のチェックに行きます。 ④1つ左のLEDは左端か?これは①と同じ方法でチェックできます。この場合は右側のチェックに行きます。 ⑤もう 1 つ左はブランクか?この場合は置き換えルーチンへ行きます。ブランクでない場合は左側のチェックは終了です。 右側のチェックに行きます。 右側のチェックの説明は省略しますが、やっていることは同じことです。 2016/4/18 END=810D 8000 21F280 8003 11F883 14:8 swap8.txt ; SWAP for NDZ ; 03/04/29 4/30 5/2 5/3 5/5 5/10 ;10/6/2 for ND80Z3 ;16/4/18 for nd8080 ; ORG $8000 LED1=$83F8;$FFF8 DP1=$83F4;$FFF4 DP3=$83F6;$FFF6 CNTR=$83F7;$FFF7;=DP4 DTDPS=$01C0;$05C0 KEYIN1=$0216;$0616 KEYIN2=$0223;$0623 D1=$02DD;4.684sec ; ;start data disp START:LXI H,STDT LXI D,LED1 21 8006 010800 LXI B,$0008 LDIR CALL LDIR; LXI H,$0000 SHLD DP3;DECIMAL COUNTER clear SHLD DP1 ;key entry KEY:CALL KEYIN1S;1-7 input CPI 08 JNC KEY DCR A JM KEY ;LED blink and wait WINC in BLNK0:LXI H,LED1 ADD L MOV L,A MOV A,M ORA A JZ KEY;space position MOV D,A;LED data save MOV B,A MVI C,00 BLNK1:MOV M,C CALL TM01S CALL KEYIN2S;1-7,15 input CPI 08 JNC BLNK2 DCR A JM BLNK3 MOV M,D JMP BLNK0 BLNK2:CPI 15;WRITE INC JZ CHECK BLNK3:MOV A,C MOV C,B MOV B,A JMP BLNK1 ;check CHECK:MOV A,L PUSH H;save HL(current position) ANI 07 JZ CHECKR;position=LED1 DCX H MOV A,M ORA A JZ REP;left=space CMP D JZ CHECKR;left=same MOV A,L ANI 07 JZ CHECKR;left=LED1 DCX H MOV A,M ORA A JZ REP;left of left=space CHECKR:POP H PUSH H MOV A,L ;? 8009 800C 800F 8012 CD0181 210000 22F683 22F483 8015 8018 801A 801D 801E CDBF80 FE08 D21580 3D FA1580 8021 8024 8025 8026 8027 8028 802B 802C 802D 802F 8030 8033 8036 8038 803B 803C 803F 8040 8043 8045 8048 8049 804A 804B 21F883 85 6F 7E B7 CA1580 57 47 0E00 71 CDE480 CDC780 FE08 D24380 3D FA4880 72 C32180 FE15 CA4E80 79 48 47 C32F80 804E 804F 8050 8052 8055 8056 8057 8058 805B 805C 805F 8060 8062 8065 8066 8067 8068 806B 806C 806D 7D E5 E607 CA6B80 2B 7E B7 CA8980 BA CA6B80 7D E607 CA6B80 2B 7E B7 CA8980 E1 E5 7D 22 806E 8070 8073 8074 8075 8076 8079 807A 807D 807E 8080 8083 8084 8085 8086 FEFE CABB80 23 7E B7 CA8980 BA CABB80 7D FEFE CABB80 23 7E B7 C2BB80 8089 808A 808B 808D 8090 8092 8093 72 E1 3600 3AF783 C601 27 32F783 8096 8099 809C 809E 809F 80A0 80A3 80A4 21F883 11FA80 0607 1A BE C21580 23 13 80A5 05 80A6 C29E80 80A9 80AC 80AF 80B1 CDCF80 CDC001 0614 CDE480 80B4 05 80B5 C2B180 80B8 C30080 80BB E1 80BC C34880 80BF 80C0 80C1 80C4 80C5 80C6 80C7 80C8 80C9 C5 D5 CD1602 D1 C1 C9 C5 D5 CD2302 CPI FE JZ CANT;position=LED7,cannot replace INX H MOV A,M ORA A JZ REP;right=space CMP D JZ CANT;right=same,cannot replace MOV A,L CPI FE JZ CANT;right=LED7,cannot replace INX H MOV A,M ORA A JNZ CANT;right of right is not space,cannot replace ;replace REP:MOV M,D;set current DATA to space position POP H MVI M,00;set space to current position LDA CNTR;DECIMAL COUNTER up ADI 01 DAA STA CNTR ;all check LXI H,LED1 LXI D,ENDDT MVI B,07 ALCHK1:LDAX D CMP M JNZ KEY;not success INX H INX D ;? DJNZ *ALCHK1 DCR B; JNZ ALCHK1; ;OK! ALL LED blink and COUNTER disp CALL ALBLNK CALL DTDPS MVI B,14;=20 ,2sec wait WAIT:CALL TM01S ;? DJNZ WAIT DCR B; JNZ WAIT; JMP START ;cannot replace CANT:POP H JMP BLNK3 ; ;KEYIN with DE,BC save KEYIN1S:PUSH B PUSH D CALL KEYIN1 POP D POP B RET KEYIN2S:PUSH B PUSH D CALL KEYIN2 23 80CC D1 80CD C1 80CE C9 80CF 80D1 80D3 80D5 80D8 80DA 80DC 060A 3EEF D398 CDE480 3EFF D398 CDE480 80DF 05 80E0 C2D180 80E3 C9 80E4 80E5 80E7 80E8 80EB 80EC 80ED 80F0 80F1 D5 1E15 D5 CDDD02 D1 1D C2E780 D1 C9 80F2 80F3 80F4 80F5 80F6 80F7 80F8 80F9 5C 5C 5C 00 63 63 63 00 80FA 80FB 80FC 80FD 80FE 80FF 8100 63 63 63 00 5C 5C 5C 8101 8102 8103 8104 8105 8106 8107 8108 8109 810C 810D F5 7E 12 23 13 0B 78 B1 C20281 F1 C9 ALBLNK POP D POP B RET ; ;LED all blink ALBLNK:MVI B,0A;=10 ALBLNK1:MVI A,EF OUT 98 CALL TM01S MVI A,FF OUT 98 CALL TM01S ;? DJNZ *ALBLNK1 DCR B; JNZ ALBLNK1; RET ; ;0.1sec timer TM01S:PUSH D MVI E,15;=21 TM01S2:PUSH D CALL D1;4.684ms POP D DCR E JNZ TM01S2 POP D RET ; STDT:DB 5C DB 5C DB 5C DB 00 DB 63 DB 63 DB 63 DB 00 ; ENDDT:DB 63 DB 63 DB 63 DB 00 DB 5C DB 5C DB 5C ; LDIR:PUSH PSW LDIR2:MOV A,M STAX D INX H INX D DCX B MOV A,B ORA C JNZ LDIR2 POP PSW RET ; =80CF ALBLNK1 =80D1 ALCHK1 =809E 24 BLNK0 BLNK3 CHECKR DP1 ENDDT KEYIN1S LDIR REP TM01S =8021 =8048 =806B =83F4 =80FA =80BF =8101 =8089 =80E4 BLNK1 CANT CNTR DP3 KEY KEYIN2 LDIR2 START TM01S2 =802F =80BB =83F7 =83F6 =8015 =0223 =8102 =8000 =80E7 BLNK2 CHECK D1 DTDPS KEYIN1 KEYIN2S LED1 STDT WAIT =8043 =804E =02DD =01C0 =0216 =80C7 =83F8 =80F2 =80B1 25 プログラム№6 CATCH(CATCH8.BTK) ゲームの説明 これはコンピュータ相手の鬼ごっこ(正確には追いかけっこ)です。 8000番地からRUNするとLEDのどこかに上向きのマーク(CUP)と下向きのマーク(CAP)がそれぞれ1個表示され ます。CUPがプレーヤーでCAPがコンピュータです。最初の表示位置は乱数で決定します。CUPが点滅してKEY入力 待ちであることを示します。プレーヤーはCUPを右に動かすか、左に動かすかを決めてKEY入力します。左に移動する なら[0]を、右に移動するなら[WRITE INC]を押します。移動量はコンピュータが乱数で求めます。CUPが移動して、 CAPと同じ位置で止まれば、プレーヤーの勝ちです。ピーと音がしてCAPが消滅します。CAPと同じ位置で止まらなか ったときはCAPが移動する番です。コンピュータがCAPをどちらにいくつ移動するかを乱数で求めてそのとおりに移動し ます。移動の結果CUPと同じ位置で止まるとコンピュータの勝ちです。ブーと音がしてCUPが消滅します。どちらかが消 滅するとゲームは終りです。2秒たつと始めに戻って再びゲームが開始されます。 なおゲーム開始時にCUPとCAPが同じ位置に表示されることがあります。この場合プレーヤーはまずCAPから逃げ ることから開始することになります。またLEDの左端と右端はリング状につながっていることとしています。左端からさら に左に移動したマークは右端から出現します。逆に右端からさらに右に移動したマークは左端から現れます。 プログラムの説明 作業用のメモリとしてMYADRS(my address,コンピュータ側の表示位置を記憶)とYRADRS(your address,プ レーヤーの表示位置を記憶)の各1バイトとRNDDT、RNDDT2(乱数用)を使います。それだけで済むのですから簡単 かというと処理はかなり複雑です。動作のポイントはプレーヤーもコンピュータも左か右に指定しただけ移動することと、 移動後に相手の位置を確認して、キャッチできたかどうかを判定することです。 ここで、うーむと考えると、どうもコンピュータとプレーヤーは表示マークが違うだけで、同じプログラムで動かせるので はないか、という気がします。ここが一番重要なポイントです。 そう考えた結果2つのサブルーチンを作りました。DTSETとSTEPです。 DTSETはゲーム開始時のCUPとCAPの位置を乱数で選び、その位置情報をメモリに入れるとともに、それぞれのマ ークを表示します。Eレジスタに表示マークを、BCレジスタに位置情報を格納するメモリアドレスを入れてDTSETをCAL Lするようにできています。このようにすることで、サブルーチンは与えられた情報の内容に関係無くまさに「機械的」に 処理をすることで目的の動作をしてしまいます。 こういうサブルーチン(場合によってはプログラム全体がこういうつくりになっているものもある)の特徴はそのサブルー チンだけを見ると、何をやっているのかさっぱりわからないということにあります。CLRとDTSETを比べてみるとそのこと がよくわかると思います。ではDTSETは悪いプログラムなのかというと、むしろDTSETの方がよりコンピュータ的で、よ り望ましいプログラムなのだと言えます(まああまりこだわって無理にしなくても、基本的には好きなように書けばよいわ けですけれど)。 たとえば良く似た処理を10回個々にプログラムするよりは何とか工夫して同じサブルーチンをCALLするようにした方 がすっきりまとまります。これが100回となるとこれはもう絶対にそうすべきです。こうすることの最大のメリットはとにかく プログラムが短くまとまる(ということはプログラム自体がフローチャート風になって、分かりやすくなる)ことです。ことの ついでですが、プロは滅多にフローチャートは書きません(私だけか?!)。たいていはひとりで始めから終わりまでひと つのプログラムを書くことになるので、その場合、ここで紹介している程度のプログラムなら、フローチャートは必要あり ません。やるべきことを、たとえば上で説明したゲームのルールをざっと読んで、理解すると、あとは頭の中でああやっ てこうやってと自然にプログラムの流れが出来てきます。あとはいきなりパソコンに向かってアセンブラのニーモニックを 打ち込みはじめます(何と原始的な!)。 ちょっと長いプログラムなら使いたいワークエリアのアドレスとか名前をメモしたり、処理の概略チャートをメモ風にかく こともあります。しかし、教科書にのっているようなチャートを書いているよりも直接プログラムを書いた方が速いので す! プログラムに慣れてくると、少なくとも自分で書いたプログラムならば、チャートなどなくても、プログラムリストを見れば 何をやっているのか分かります。あとで分からなくなるかなあと思ったときは、必要と思われるコメントを書き込んでおけ ば十分です。 これはあくまで個人で仕事をする場合の話で、グループで作業をする場合には、チャートが必要なこともあると思いま す(何事もケースバイケースです)。ともあれ私個人としてはチャートは面倒ですから、書きません。このプログラム集の プログラムに書き込んでいるコメントも大半は読者向けのもので自分用には殆ど不要です(実際、たった少しのコメントを プログラム中に書きこむのさえ、怠惰なプログラマにとっては面倒なのです)。 さて余計なことを書きすぎました。もうひとつサブルーチン化のメリットがあります。それはチェックや修正が容易な点で す。プログラムは書いていきなり完成ということはまずありません。こんな短いプログラムでもそうです。ここで紹介したプ ログラムも一度では終っていません。リストの最初に日付が覚えとして書いてあります。何回も訂正していることが分か ります。こういうときにサブルーチンになっていると、そこだけ直せば済んでしまいます。同じような処理を何回もだらだら 書いたプログラムでは、バグ修正が大変です。 26 サブルーチン化にはデメリットもあります。はじめに書いたように、そこだけ読んでもなにをやっているのかよくわからな いという点です。この点についてはたとえばプリントアウトしたリストに処理されるデータの1つを実際に書きこむなどして、 ブログラムをあらためてながめてみると、流れが見えてきます。 と無理矢理納得していただいたところでもうひとつのサブルーチンSTEPについて説明します。こちらはちょっと複雑で す。サブルーチンに与えるべきデータ(これをパラメータとか引数とかといいます)がちょっと多くて分かりづらいかもしれ ません。 現在自分のマークが表示されているLEDアドレス(HLレジスタ)、右へ行くのか左へ行くのか(Cレジスタ)、移動後に 現在の表示を消すためのマスク(同じ場所に相手も表示している場合を考えて、自分だけを消すようにする。Dレジスタ)、 移動後に表示するマーク(Eレジスタ)、移動後の位置情報を格納するメモリアドレス(もとはIXレジスタを使っていたが8 080にはないためそれに代わるワークエリアとしてADRSWKを使う)、とこれだけのデータをサブルーチンに与えます。 データが沢山あってなんだかややこしそうですがこれらのデータをサブルーチンのリストの各レジスタのところにメモなど して、あらためてながめてみると、それほど複雑ではないことがわかると思います。 このサブルーチンで特にコメントしたいのがCレジスタの値です。これがテクニックです。左に行くか右に行くかをFFか0 1で示しています。どこがテクニックか? 左に行くということは現在表示しているLEDのアドレス(83F8~83FFのいずれか)から-1することです。右に行くの は逆にアドレスを+1することです。-1はDCR、+1はINRを普通は使います。あるいはSUI 01かADI 01を使いま す。ここから先はわからない人にはわかりません。 突然無関係のように登場したFFですが、FFを10進に直すと255です。これではわかりません。FFにはもうひとつの 意味があります。FFを符号付の数として10進に直すと-1なのです!これは約束事なのですがでたらめに決めたので はなくて計算上の根拠があっての話なのです。SUI 01の代わりにADI FFとしても不思議なことに結果は同じになっ てしまうのです(フラグは異なります)。どーしても納得ができない人は試してみてください。 このことを利用して本来加算と減算にしなければならないはずのところを同じADD Cで切りぬけているのです。もうひ とつ、加算後にORI F8としている部分です。これによって加算後に結果がオーバフロー(下位アドレスがF8~FFの範 囲を超えてしまう)してもリング状に左端と右端がつながったように結果が計算されます。これも納得できない人は試して みてください。 ことのついでにMYTURN:のところでRNDの結果から、右と左を示す01とFFをさらりと作り出しているところに注目し てください。自画自賛ですがこのようにきれいに決まるとヤッターという気になって心が踊ります。 2016/4/20 END=8169 8000 8003 8004 8005 8006 8007 8008 8009 C30A80 00 00 00 00 00 00 00 11:51 catch8.txt ; CATCH for NDZ ; 03/05/06 5/10 ;10/6/2 for ND80Z3 ;16/4/15 for ND8080 ;16/4/15 timer ;4/18 ;4/19 ;4/20 ; ORG $8000 ; MYADRS=$E800 ; YRADRS=$E801 ; RNDDT=$E810;$E811 LED1=$83F8;$FFF8 R=$FFD2 ; KEYIN2=$0223;$0623 D1=$02DD;4.684msec ; JMP START MYADRS:NOP YRADRS:NOP ADRSWK:NOP NOP RNDDT:NOP NOP RNDDT2:NOP 27 800A 800D 8010 8011 8012 8013 3AD2FF 210780 77 23 77 CDD080 8016 1E23 8018 010380 801B CDDD80 801E 1E1C 8020 03 8021 CDDD80 8024 8027 802A 802B 802C 802D 802E 3A0480 21F883 85 6F 56 42 0E00 8030 8031 8034 8037 8038 803B 803D 8040 8041 8042 8043 8046 8048 804B 804D 71 CD5C81 CD1081 B7 CA4680 FE15 CA4B80 59 48 43 C33080 0EFF C34D80 0E01 111CE3 8050 8051 8054 8057 8058 E5 210480 220580 E1 CDEA80 805B 805C 805F 8060 8063 8064 8065 E5 2A0580 2B 220580 BE E1 C27180 8068 7E ;data set START:LDA R LXI H,RNDDT MOV M,A INX H MOV M,A CALL CLR ;my position select MVI E,23;cap LXI B,MYADRS CALL DTSET ;your posision select MVI E,1C;cup INX B CALL DTSET ;GAME START ;your turn REENT:LDA YRADRS LXI H,LED1 ADD L MOV L,A MOV D,M;LED data save MOV B,D MVI C,00 ;blink and keyin KEY:MOV M,C CALL TM01S CALL KEYIN2S ORA A JZ LEFT CPI 15;W INC JZ RIGHT MOV E,C MOV C,B MOV B,E JMP KEY LEFT:MVI C,FF JMP RIGHT2 RIGHT:MVI C,01 RIGHT2:LXI D,$E31C;see STEP comment line ;? LD IX,YRADRS PUSH H; LXI H,YRADRS; SHLD ADRSWK; POP H; CALL STEP ;catch? ;? DEC IX;MYADRS ;? CP (IX+00) PUSH H; LHLD ADRSWK; DCX H; SHLD ADRSWK; CMP M; POP H; JNZ MYTURN ;catch! MOV A,M 28 8069 806B 806C 806E E6DC 77 3E17 C39D80 8071 8074 8076 8079 807A 807B 807E 807F 8082 8083 8084 8087 CDB280 E601 C27A80 3D 4F 2A0580 7E 21F883 85 6F 1123DC CDEA80 808A 808B 808E 808F 8092 8093 8094 E5 2A0580 23 220580 BE E1 C22480 8097 8098 809A 809B 809D 809F 7E E6E3 77 3E00 0605 CD1881 80A2 80A3 80A6 80A8 05 C29F80 0614 CD5C81 80AB 05 80AC C2A880 80AF C30A80 80B2 80B3 80B4 80B7 80B8 80B9 80BB 80BC 80BF 80C2 80C3 80C4 80C6 E5 D5 2A0780 23 7C E603 67 220780 3A0980 57 7E E607 BA ANI DC;cap clear MOV M,A MVI A,17;piiii JMP END ;my turn MYTURN:CALL RND3;LEFT(FF) or RIGHT(01) select ANI 01 JNZ MYTURN1;=01 DCR A;=FF MYTURN1:MOV C,A LHLD ADRSWK MOV A,M LXI H,LED1 ADD L MOV L,A LXI D,$DC23;see STEP comment line CALL STEP ;catch? ;? INC IX;YRADRS ;? CP (IX+00) PUSH H; LHLD ADRSWK; INX H; SHLD ADRSWK; CMP M; POP H; JNZ REENT ;catch! MOV A,M ANI E3;cup clear MOV M,A MVI A,00;buuuu END:MVI B,05 END1:CALL SOUND ;? DJNZ *END1 DCR B; JNZ END1; MVI B,14;=20 ,2sec wait WAIT:CALL TM01S ;? DJNZ WAIT DCR B JNZ WAIT JMP START ; ;ransu RND3:PUSH H PUSH D RND2:LHLD RNDDT INX H MOV A,H ANI 03 MOV H,A SHLD RNDDT LDA RNDDT2 MOV D,A MOV A,M ANI 07 CMP D 29 80C7 80CA 80CD 80CE 80CF 80D0 80D3 80D4 80D6 80D7 CAB480 320980 D1 E1 C9 21F883 AF 0608 77 23 80D8 05 80D9 C2D680 80DC C9 80DD CDB280 80E0 80E1 80E4 80E5 80E6 80E7 80E8 80E9 02 21F883 85 6F 7B B6 77 C9 80EA CDB280 80ED 80EE 80F0 80F3 80F4 80F7 80F8 80F9 80FA 80FB 80FC 80FE 80FF 8100 8101 3C FE07 D2EA80 47 CD5981 7E A2 77 7D 81 F6F8 6F 7E B3 77 8102 8103 8106 8107 05 C2F480 7D E607 8109 E5 810A 2A0580 JZ RND2 STA RNDDT2 POP D POP H RET ; ;LED all clear CLR:LXI H,LED1 XRA A MVI B,08 CLR1:MOV M,A INX H ;? DJNZ *CLR1 DCR B; JNZ CLR1; RET ; ;start data set;BC=MYADRS or YRADRS;E=disp data 23(cap) or 1C(cup) DTSET:CALL RND3 ; ANI 07 STAX B LXI H,LED1 ADD L MOV L,A MOV A,E ORA M MOV M,A;cap or cup or both disp RET ; ;step left or right C=FF(left) C=01(right),HL=current position ; D=clear mask DC(cap) or E3(cup) ; E=disp data 23(cap) or 1C(cup) ; IX=MYADRS or YRADRS STEP:CALL RND3 ; ANI 07 INR A CPI 07 JNC STEP MOV B,A STEP1:CALL TM02S MOV A,M ANA D;clear MOV M,A MOV A,L ADD C ORI F8 MOV L,A MOV A,M ORA E;disp MOV M,A ;? DJNZ STEP1 DCR B; JNZ STEP1; MOV A,L ANI 07 ; STA IX+00 PUSH H; LHLD ADRSWK; 30 810D 77 810E E1 810F C9 8110 8111 8112 8115 8116 8117 C5 D5 CD2302 D1 C1 C9 8118 8119 811A 811B 811C 811F 8120 8121 8122 8124 8125 8127 8129 812A 812B 812E 812F 8131 8133 8134 8135 8138 8139 813C 813D 813E 813F 8140 F5 E5 D5 C5 214181 85 6F 46 1E1A 50 3EFF D398 7F 15 C22981 50 3EDF D398 7F 15 C23381 1D C22481 C1 D1 E1 F1 C9 8141 8142 8143 8144 8145 8146 8147 8148 8149 814A 814B 814C 814D 814E 814F 8150 7F 77 71 6A 5F 59 54 4F 47 43 3F 3B 35 32 2F 2C MOV M,A; POP H; RET ; ;KEYIN with DE,BC save KEYIN2S:PUSH B PUSH D CALL KEYIN2 POP D POP B RET ; ; SOUND:PUSH PSW PUSH H PUSH D PUSH B LXI H,SNDTBL ADD L MOV L,A MOV B,M MVI E,1A SNDS1:MOV D,B MVI A,FF;SP OUT=H OUT 98 SNDS2:MOV A,A;5--------DCR D;5 | 5+5+10=20 JNZ SNDS2;10---MOV D,B MVI A,DF;sp out=L OUT 98 SNDS3:MOV A,A;5--------DCR D;5 | 5+5+10=20 JNZ SNDS3;10---DCR E JNZ SNDS1 POP B POP D POP H POP PSW RET ; SOUND TABLE SNDTBL:DB 7F;so4 DB 77;so#4 DB 71;ra4 DB 6A;ra#4 DB 5F;do5 DB 59;do#5 DB 54;re5 DB 4F;re# DB 47;fA5 DB 43;fa#5 DB 3F;so5 DB 3B;so5# DB 35;ra#5 DB 32;si5 DB 2F;do6 DB 2C;do#6 20/2=10microsec 20/2=10microsec 31 8151 8152 8153 8154 8155 8156 8157 8158 25 27 2A 4B 38 64 23 21 8159 CD5C81 815C 815D 815F 8160 8163 8164 8165 8168 8169 D5 1E15 D5 CDDD02 D1 1D C25F81 D1 C9 ADRSWK D1 END1 KEYIN2S MYADRS R RIGHT2 RNDDT SNDS2 SOUND STEP1 TM02S DB DB DB DB DB DB DB DB 25;mi6 27;re#6 2A;re6 4B;mi5 38;ra5 64;si4 23;fa6 21;fa#6 ; ;0.2sec timer TM02S:CALL TM01S ;0.1sec timer TM01S:PUSH D MVI E,15;=21 TM01S2:PUSH D CALL D1;4.684ms POP D DCR E JNZ TM01S2 POP D RET ; =8005 CLR =02DD DTSET =809F KEY =8110 LED1 =8003 MYTURN =FFD2 REENT =804D RND2 =8007 RNDDT2 =8129 SNDS3 =8118 START =80F4 TM01S =8159 WAIT =80D0 =80DD =8030 =83F8 =8071 =8024 =80B4 =8009 =8133 =800A =815C =80A8 CLR1 END KEYIN2 LEFT MYTURN1 RIGHT RND3 SNDS1 SNDTBL STEP TM01S2 YRADRS =80D6 =809D =0223 =8046 =807A =804B =80B2 =8124 =8141 =80EA =815F =8004 32 プログラム№7 もぐらたたき(MOGURA8.BTK) ゲームの説明 LEDにランダムに現れるもぐらをたたくゲームです。 8000番地からRUNするとLEDの全部の表示が”8”の一番下の”_”になります。2秒ごとにLEDのどこかの桁にモ グラ(下向きのコの字のパターン)が現れます。1秒たつとモグラは引っ込んでしまいます。その前にうまくモグラをたたく と(表示されているLED位置を示す1~8の数字キーを押すと)ピッと音がしてモグラがつぶれます。1~8のキーを押す と対応するLEDにハンマー(”8”の字の上のバー)が表示され、0.5秒後に下に落とされます。ヒットするのが遅れたり、 違う数を押したりすると失敗です。ブーという音がします。 モグラは一度に1匹だけ出て来ます。全部で20匹出るとゲームオーバーです。ヒットしたモグラの数がLEDに表示さ れ約2秒間点滅します。そのあと2秒間表示が静止したあとはじめに戻って再びゲームが開始されます。 プログラムの説明 作業用のメモリとしてRNDDT、RNDDT2(乱数用)の他は1バイトのMCOUNTのみを使います。最初20(14H)から 始って0になるまでモグラの表示回数をダウンカウントします。 はじめのMOGURA01:の処理は説明が必要です。KEYからの入力をチェックしていますが1~8が入力されると「ブ ー」音を出しています。じつはこの時点ではまだモグラは出現していないのです。ここは「お手つき」をチェックしているの です。 HAMMERサブルーチンはハンマーの表示とサウンド(ブーおよびピー)を行います。HAMMERサブルーチンで、AN I 14としているのはモグラをヒットしたとき、モグラがつぶれた形を表示するためです(下向きのコの字の上のバーが消 える)。そのあとのORI 08でハンマーが落ちたところを表示しています。このANDとORによってモグラをヒットしたとき でも、モグラがいない場所をたたいてしまったときでも同じサブルーチンが使えるようになります。そのあとのサウンド出 力も同様でCレジスタの値によって、同じサブルーチンでヒットしたときのピーと失敗したときのブーが出るようになりま す。 さて失敗したときもヒットしたときもモグラの数は-1されます。0になったらゲーム終了処理へ行き、そうでないときは 始めの部分に戻ってモグラの出現処理をくりかえします。失敗してもヒットしても同じ処理を行います。NOT1:の部分で す。ここはサブルーチンではありませんがサブルーチンのときと同じ考え方です。NOT:の後半部分になっていますがHI T:の処理のあともここにジャンプしてきます。このように同じ処理にできる部分はCALLかJMPでひとつにまとめるのが プログラムのコツです。 2016/4/20 END=816E 8000 8003 8004 8005 C30780 00 00 00 9:53 mogura8.txt ; MOGURATATAKI for NDZ (HIT'N BLOW) ; 03/5/2 5/5 5/11 5/12 ;10/6/2 for ND80Z3 ;7/21 9/17 ;16/4/16 for ND8080 ;4/18 ;4/19 ;4/20 ; ORG $8000 ; RNDDT=$E810;$E811 ; MCOUNT=$E812 LED1=$83F8;$FFF8 DP1=$83F4;$FFF4 DP3=$83F6;$FFF6 CNTR=$83F7;$FFF7;=DP4 R=$FFD2 ; DTDPS=$01C0;$05C0 KEYIN2=$0223;$0623 ; JMP START RNDDT:NOP NOP RNDDT2:NOP 33 8006 00 8007 800A 800D 800E 800F 8010 8013 8016 8019 801B 3AD2FF 210380 77 23 77 210000 22F683 22F483 3E14 320680 801E 8021 8024 8027 802A 802C 802F 8030 8033 8035 8038 803B 803C 803D 803E CDF280 01D007 CD1F81 CDFF80 FE09 D23B80 3D FA3B80 0E00 CDA080 C31E80 0B 78 B1 C22480 8041 CDBF80 8044 8045 8048 8049 804A 804C 804F 8052 8054 8057 8058 805B 805C 57 21F883 85 6F 3654 01E803 CDFF80 FE09 D26780 3D FA6780 BA CA7D80 805F 0E00 8061 CDA080 8064 C37080 8067 806A 806B 806C 806D 8070 8073 8074 8077 CD1F81 0B 78 B1 C24F80 3A0680 3D CA8E80 320680 MCOUNT:NOP ;start data disp START:LDA R LXI H,RNDDT MOV M,A INX H MOV M,A LXI H,$0000 SHLD DP3;DECIMAL COUNTER clear SHLD DP1 MVI A,14;=20 STA MCOUNT;mogura ;wait 2sec,if keyin then buuuu MOGURA:CALL STDTDP LXI B,$07D0;=2000 ,wait 2000msec MOGURA01:CALL TM1M CALL KEYIN2S CPI 09 JNC MOGURA02 DCR A JM MOGURA02 MVI C,00;sound buuuu CALL HAMMER JMP MOGURA MOGURA02:DCX B MOV A,B ORA C JNZ MOGURA01 ;"MOGURA" up MOGURA1:CALL RND3 ; ANI 07 MOV D,A;position save LXI H,LED1 ADD L MOV L,A MVI M,54;MOGURA disp LXI B,$03E8;=1000 ,wait 1000msec MOGURA2:CALL KEYIN2S CPI 09 JNC NOT DCR A JM NOT CMP D JZ HIT ;BUUUUU MVI C,00;sound buuuuu CALL HAMMER JMP NOT1 ;not keyin NOT:CALL TM1M DCX B MOV A,B ORA C JNZ MOGURA2 NOT1:LDA MCOUNT DCR A JZ END STA MCOUNT 34 807A C31E80 807D 807F 8082 8085 8087 8088 808B 0E17 CDA080 3AF783 C601 27 32F783 C37080 808E 8091 8094 8096 CDC001 CDDD80 0614 CD1381 8099 05 809A C29680 809D C30780 80A0 80A3 80A4 80A5 80A6 80A8 80A9 80AC 80AE 80B0 80B1 80B2 80B4 21F883 85 6F 7E F601 77 CD0781 E614 F608 77 79 0603 CD2E81 80B7 80B8 80BB 80BE 05 C2B480 CD0781 C9 80BF 80C0 80C1 80C4 80C5 80C6 80C8 80C9 80CC 80CF 80D0 80D1 80D3 80D4 80D7 80DA 80DB 80DC E5 D5 2A0380 23 7C E603 67 220380 3A0580 57 7E E607 BA CAC180 320580 D1 E1 C9 JMP MOGURA ;hit! HIT:MVI C,17;sound piiii CALL HAMMER LDA CNTR;DECIMAL COUNTER up ADI 01 DAA STA CNTR JMP NOT1 ;game over! COUNTER disp and ALL LED blink END:CALL DTDPS CALL ALBLNK MVI B,14;=20 ,2sec wait WAIT:CALL TM01S ;? DJNZ WAIT DCR B; JNZ WAIT; JMP START ; ;hammer disp HAMMER:LXI H,LED1 ADD L MOV L,A MOV A,M ORI 01;hammer up MOV M,A CALL TM05S ANI 14;hammer down ORI 08 MOV M,A MOV A,C MVI B,03 HAMMER1:CALL SOUND ;? DJNZ HAMMER1 DCR B; JNZ HAMMER1; CALL TM05S RET ; ;ransu RND3:PUSH H PUSH D RND2:LHLD RNDDT INX H MOV A,H ANI 03 MOV H,A SHLD RNDDT LDA RNDDT2 MOV D,A MOV A,M ANI 07 CMP D JZ RND2 STA RNDDT2 POP D POP H RET 35 80DD 80DF 80E1 80E3 80E6 80E8 80EA 060A 3EEF D398 CD1381 3EFF D398 CD1381 80ED 05 80EE C2DF80 80F1 C9 80F2 80F5 80F7 80F9 21F883 0608 3608 23 80FA 05 80FB C2F780 80FE C9 80FF 8100 8101 8104 8105 8106 C5 D5 CD2302 D1 C1 C9 8107 C5 8108 0605 810A CD1381 810D 810E 8111 8112 05 C20A81 C1 C9 8113 8114 8116 8119 811A 811D 811E D5 1E64 CD1F81 1D C21681 D1 C9 811F 8120 8122 8124 8125 8128 8129 D5 1607 1E12 1D C22481 15 C22281 ; ;LED all blink ALBLNK:MVI B,0A;=10 ALBLNK1:MVI A,EF OUT 98 CALL TM01S MVI A,FF OUT 98 CALL TM01S ;? DJNZ *ALBLNK1 DCR B; JNZ ALBLNK1; RET ; ;start data disp STDTDP:LXI H,LED1 MVI B,08 STDTDP1:MVI M,08 INX H ;? DJNZ STDTDP1 DCR B; JNZ STDTDP1; RET ; ;KEYIN with DE,BC save KEYIN2S:PUSH B PUSH D CALL KEYIN2 POP D POP B RET ; ;0.5sec timer TM05S:PUSH B MVI B,05 TM05S1:CALL TM01S ;? DJNZ TM05S1 DCR B; JNZ TM05S1; POP B RET ;0.1sec timer TM01S:PUSH D MVI E,64;=100 TM01S2:CALL TM1M DCR E JNZ TM01S2 POP D RET ; ;1msec timer TM1M:PUSH D;11 MVI D,07; ck=5 (11+7+292*7+10+10)/2.048=2082/2.048=1016 TM1M2:MVI E,12;=18 ck=7 7+15*18+15=292 TM1M3:DCR E;5 JNZ TM1M3;10 DCR D;5 JNZ TM1M2;10 36 812C D1 812D C9 812E 812F 8130 8131 8132 8135 8136 8137 8138 813A 813B 813D 813F 8140 8141 8144 8145 8147 8149 814A 814B 814E 814F 8152 8153 8154 8155 8156 F5 E5 D5 C5 215781 85 6F 46 1E1A 50 3EFF D398 7F 15 C23F81 50 3EDF D398 7F 15 C24981 1D C23A81 C1 D1 E1 F1 C9 8157 8158 8159 815A 815B 815C 815D 815E 815F 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 816A 816B 816C 816D 816E 7F 77 71 6A 5F 59 54 4F 47 43 3F 3B 35 32 2F 2C 25 27 2A 4B 38 64 23 21 ALBLNK POP D;10 RET;10 ; SOUND:PUSH PSW PUSH H PUSH D PUSH B LXI H,SNDTBL ADD L MOV L,A MOV B,M MVI E,1A SNDS1:MOV D,B MVI A,FF;SP OUT=H OUT 98 SNDS2:MOV A,A;5--------DCR D;5 | 5+5+10=20 20/2=10microsec JNZ SNDS2;10---MOV D,B MVI A,DF;sp out=L OUT 98 SNDS3:MOV A,A;5--------DCR D;5 | 5+5+10=20 20/2=10microsec JNZ SNDS3;10---DCR E JNZ SNDS1 POP B POP D POP H POP PSW RET ; SOUND TABLE SNDTBL:DB 7F;so4 DB 77;so#4 DB 71;ra4 DB 6A;ra#4 DB 5F;do5 DB 59;do#5 DB 54;re5 DB 4F;re# DB 47;fA5 DB 43;fa#5 DB 3F;so5 DB 3B;so5# DB 35;ra#5 DB 32;si5 DB 2F;do6 DB 2C;do#6 DB 25;mi6 DB 27;re#6 DB 2A;re6 DB 4B;mi5 DB 38;ra5 DB 64;si4 DB 23;fa6 DB 21;fa#6 ; =80DD ALBLNK1 =80DF CNTR =83F7 37 DP1 END HIT LED1 MOGURA01 MOGURA2 R RNDDT SNDS2 SOUND STDTDP1 TM05S TM1M2 =83F4 =808E =807D =83F8 =8024 =804F =FFD2 =8003 =813F =812E =80F7 =8107 =8122 DP3 HAMMER KEYIN2 MCOUNT MOGURA02 NOT RND2 RNDDT2 SNDS3 START TM01S TM05S1 TM1M3 =83F6 =80A0 =0223 =8006 =803B =8067 =80C1 =8005 =8149 =8007 =8113 =810A =8124 DTDPS HAMMER1 KEYIN2S MOGURA MOGURA1 NOT1 RND3 SNDS1 SNDTBL STDTDP TM01S2 TM1M WAIT =01C0 =80B4 =80FF =801E =8041 =8070 =80BF =813A =8157 =80F2 =8116 =811F =8096 38 プログラム№8 神経衰弱(SINKSUI8.BTK) ゲームの説明 神経衰弱ゲームです。 8000番地からRUNするとLEDが全部消えます。この時点でコンピータは乱数によって1~Fのうちから同じものを2 個ずつ4組選んでLEDにばらばらにセットしています。 プレーヤーが1~8のキーを押すとその数で示される位置のLEDに隠されていた数(1~Fのどれか)が表示されます。 続いてもう1ヶ所のLEDを選択してその場所を示す数のキーを押します。うまく正解して同じ数を当てたときは両方のLE Dは点灯したままになります。もし失敗して違う数だった場合には、今まで表示されていた全部が消えて始めに戻ってし まいます(数の配置は変わりませんから点灯している間に覚えておくようにします)。 またうっかりしてすでに点灯しているLEDを示す数を入力した場合も「お手つき」で表示は全部消えてしまいます。 このようにしてうまく8個のLEDを全部点灯させることができればゲーム終了です。2秒間LEDが点滅し、そのあと試 行回数が2秒間表示されます。そして始めに戻って再びゲームが開始されます。 プログラムの説明 LEDに割り当てた数をしまっておくメモリエリアとして8バイトエリア(DTBF)を用意します。はじめに乱数で4個の数を 選択して、それぞれ2回乱数によって格納する場所を選んで、DTBFにLED表示パターンを格納します。こういうプログ ラムではDTBFにキー入力された数値そのものを格納するように考えるのが普通なのでしょうが、今回は数値を計算に は利用しないので、どうせ表示するときには表示パターンに変換することを考えると、ここで先に表示パターンに変換し てしまってもよいわけです。 ところでこのとき乱数の発生がうまくいかなくて発生させる数値が片寄ってしまい、全部の表示データを算出できないこ とがあります。このときはアドレス表示が8000のままで表示がブランクになりません。一度リセット(MONキーを押す) してから8000から再スタートしてください。 このプログラムでもちょいとしたテクニックを使っています。DTDP:の部分です。ここではキー入力された1~8の数(こ れを0~7に変換している)をもとに、対応するLEDに割り当てられた数値パターンを表示させるのですが、そのときすで に表示済み(点灯している)LEDアドレスが指定されていないかをチェックして、もしチェックされていたらそのことをメイン ルーチンに知らせるためにサインフラグ(S-FLAG)をセットしてリターンします。そうではないときには、LEDに表示す るとともにそのデータエリア(DTBF)に表示済みのマークをつけます。 普通は表示済みマークをつけるためにデータエリア(ここではDTBFの8バイト)の他にマーク用に8バイトの場所を用 意するなどと考えます。するとそれをチェックするために余計なアドレス計算が必要になってしまいます。DTDP:ではそ このところをちょいとした工夫でパスしています。 DTBFに格納される表示パターンは1~Fですが、共通しているところが1ヶ所あります。 そうです。最上位ビットは常に0です。最上位ビットはLEDの右下のピリオドに割り当てられているので普通は表示しま せん。これを点灯マークに使うのです。点灯しているときはここを1にします。16進数の約束事で符号付の数として考え るときはその最上位ビットが1のとき、この数はマイナスとして扱います。今回のプログラムでは点灯していないデータは +で点灯しているデータは-になります。ORA A命令を使うとAの内容によってS-FLAG(サインフラグ)がON/OF Fするので、この情報をメインルーチンに持って帰ることができます。 もうひとつ、DTDP:のはじめの部分でキー入力された情報(00~07)をもとにしてDTBFの該当するアドレスを算出 する部分で今までのようにADD L、MOV L,Aとしないで、いきなりMOV L,Aを実行しています。こういうやり方は 危険なので注意しなければいけません。ここではDTBFの先頭は8200になっていて、下位8ビットはAレジスタの値と 一致するために、ADD Lを省いたのです。危険なのは将来プログラムを変更するとか、この部分を他のプログラムに 利用するとかといった場合に、もしDTBFに半端なアドレスを割り当ててしまうと、正しい結果が得られなくなってしまうこ とです。 2016/4/20 END=8135 10:1 sinksui8.txt ; SINKEISUIJAKU for NDZ (ODD COUPLES) ; 03/04/29 4/30 5/1 5/5 5/12 5/24 ;10/6/2 for ND80Z3 ;16/4/18 for nd8080 ;4/19 ;4/20 ; ORG $8000 DTBF=$8200;$E800 ; RNDDT=$E810;$E811 LED1=$83F8;$FFF8 39 DP1=$83F4;$FFF4 DP3=$83F6;$FFF6 CNTR=$83F7;$FFF7;=DP4 R=$FFD2 ; DTDPS=$01C0;$05C0 KEYIN1=$0216;$0616 ; 8000 8003 8004 8005 C30680 00 00 00 8006 8009 800C 800D 800E 800F 8010 8012 8015 8016 3AD2FF 210380 77 23 77 AF 0608 210082 77 23 8017 05 8018 C21580 801B 0E04 801D CD9A80 8020 8023 8024 8026 8027 8028 802B 802D 802E 8031 210381 5F 1600 19 7E 210082 0608 BE CA1D80 23 8032 05 8033 C22D80 8036 57 8037 8039 803C 803E 8041 8042 8043 8044 8045 8048 0602 CD9A80 E607 210082 85 6F 7E B7 C23980 72 8049 05 JMP START RNDDT:NOP NOP RNDDT2:NOP ; ;data set START:LDA R LXI H,RNDDT MOV M,A INX H MOV M,A XRA A MVI B,08 LXI H,DTBF DTST1:MOV M,A INX H ;? DJNZ *DTST1 DCR B; JNZ DTST1; MVI C,04 ;No. select DTST2:CALL RND4 ; ANI 0F LXI H,SEGDT MOV E,A MVI D,00 DAD D MOV A,M LXI H,DTBF MVI B,08 DTST3:CMP M JZ DTST2;already selected No. INX H ;? DJNZ *DTST3 DCR B; JNZ DTST3; MOV D,A;DATA save ;ADDRESS select and DATA set MVI B,02 ADST1:CALL RND4 ANI 07 LXI H,DTBF ADD L MOV L,A MOV A,M ORA A JNZ ADST1;already used MOV M,D;DATA set ;? DJNZ *ADST1 DCR B; 40 804A C23980 804D 0D 804E C21D80 8051 210000 8054 22F683 8057 22F483 805A 805D 8060 8061 8064 8066 8067 806A 806B 806E CDCD80 CDE280 F5 3AF783 C601 27 32F783 F1 FA5A80 47 806F CDE280 8072 FA5A80 8075 B8 8076 C25A80 8079 807C 807E 807F 8080 8083 210082 0608 7E B7 F25D80 23 8084 05 8085 C27E80 8088 808B 808E 8090 CDB880 CDC001 0614 CD1B81 8093 05 8094 C29080 8097 C30680 809A 809B 809C 809F 80A0 80A1 80A3 80A4 80A7 80AA 80AB 80AC 80AE E5 D5 2A0380 23 7C E603 67 220380 3A0580 57 7E E60F BA JNZ ADST1; DCR C JNZ DTST2 ;GAME START LXI H,$0000 SHLD DP3;DECIMAL COUNTER clear SHLD DP1 ;key entry(first one) REENT:CALL CLR KEY:CALL KEYDP PUSH PSW;DATA and S-FLAG save LDA CNTR;DECIMAL COUNTER up ADI 01 DAA STA CNTR POP PSW;DATA and S-FLAG JM REENT;otetuki MOV B,A;first DATA save ;key entry(second ONE) KEY2:CALL KEYDP JM REENT;otetuki ;DATA compere CMP B; B=first data JNZ REENT;not same ;check all open or not LXI H,DTBF MVI B,08 OPNCK1:MOV A,M ORA A JP KEY;not open data,continue GAME INX H ;? DJNZ OPNCK1 DCR B; JNZ OPNCK1; ;OK! ALL LED blink CALL ALBLNK CALL DTDPS;COUNTER disp MVI B,14;=20 ,2sec wait WAIT:CALL TM01S ;? DJNZ WAIT DCR B; JNZ WAIT; JMP START ; ;ransu RND4:PUSH H PUSH D RND2:LHLD RNDDT INX H MOV A,H ANI 03 MOV H,A SHLD RNDDT LDA RNDDT2 MOV D,A MOV A,M ANI 0F CMP D 41 80AF 80B2 80B5 80B6 80B7 80B8 80BA 80BC 80BE 80C1 80C3 80C5 CA9C80 320580 D1 E1 C9 060A 3EEF D398 CD1B81 3EFF D398 CD1B81 80C8 05 80C9 C2BA80 80CC C9 80CD 80D0 80D3 80D6 80D7 80D8 80DA 80DB 80DC 21F883 110082 010008 71 1A E67F 12 23 13 80DD 05 80DE C2D680 80E1 C9 80E2 80E5 80E7 80EA 80EB 80EE 80F1 80F2 80F3 80F4 80F5 80F7 80F8 80FA 80FD 80FF 8100 8101 8102 8103 8104 8105 8106 CD1381 FE09 D2E280 3D FAE280 210082 6F 7E B7 F8 F680 77 E67F 11F883 2600 19 77 B7 C9 5C 06 5B 4F JZ RND2 STA RNDDT2 POP D POP H RET ; ;LED all blink ALBLNK:MVI B,0A;=10 ALBLNK1:MVI A,EF OUT 98 CALL TM01S MVI A,FF OUT 98 CALL TM01S ;? DJNZ *ALBLNK1 DCR B; JNZ ALBLNK1; RET ; ;LED clear and open mark clear CLR:LXI H,LED1 LXI D,DTBF LXI B,$0800 CLR2:MOV M,C LDAX D ANI 7F STAX D INX H INX D ;? DJNZ *CLR2 DCR B; JNZ CLR2; RET ; ;KEYIN and DATA disp KEYDP:CALL KEYIN1S CPI 09 JNC KEYDP DCR A JM KEYDP DTDP:LXI H,DTBF MOV L,A MOV A,M ORA A RM;otetuki! ORI 80 MOV M,A;open mark set ANI 7F LXI D,LED1 MVI H,00 DAD D MOV M,A ORA A;clear Sign-flag RET SEGDT:DB 5C;0 DB 06;1 DB 5B;2 DB 4F;3 42 8107 8108 8109 810A 810B 810C 810D 810E 810F 8110 8111 8112 66 6D 7D 27 7F 6F 77 7C 39 5E 79 71 8113 8114 8115 8118 8119 811A C5 D5 CD1602 D1 C1 C9 811B 811C 811E 8121 8122 8125 8126 D5 1E64 CD2781 1D C21E81 D1 C9 8127 8128 812A 812C 812D 8130 8131 8134 8135 D5 1607 1E12 1D C22C81 15 C22A81 D1 C9 ADST1 CLR DP1 DTDP DTST2 KEY2 KEYIN1S R RND4 SEGDT TM01S2 TM1M3 DB DB DB DB DB DB DB DB DB DB DB DB 66;4 6D;5 7D;6 27;7 7F;8 6F;9 77;A 7C;b 39;C 5E;d 79;E 71;F ; ;KEYIN with DE,BC save KEYIN1S:PUSH B PUSH D CALL KEYIN1 POP D POP B RET ; ;0.1sec timer TM01S:PUSH D MVI E,64;=100 TM01S2:CALL TM1M DCR E JNZ TM01S2 POP D RET ; ;1msec timer TM1M:PUSH D;11 MVI D,07; ck=5 (11+7+292*7+10+10)/2.048=2082/2.048=1016 TM1M2:MVI E,12;=18 ck=7 7+15*18+15=292 TM1M3:DCR E;5 JNZ TM1M3;10 DCR D;5 JNZ TM1M2;10 POP D;10 RET;10 ; =8039 ALBLNK =80B8 ALBLNK1 =80BA =80CD CLR2 =80D6 CNTR =83F7 =83F4 DP3 =83F6 DTBF =8200 =80EE DTDPS =01C0 DTST1 =8015 =801D DTST3 =802D KEY =805D =806F KEYDP =80E2 KEYIN1 =0216 =8113 LED1 =83F8 OPNCK1 =807E =FFD2 REENT =805A RND2 =809C =809A RNDDT =8003 RNDDT2 =8005 =8103 START =8006 TM01S =811B =811E TM1M =8127 TM1M2 =812A =812C WAIT =8090 43 プログラム№9 WANTED(WANTED8.BTK) ゲームの説明 これはちょっと変わった数当てゲームです。 コンピュータはあらかじめ乱数によって4桁の数(0000~9999)を求めて隠しています。 プレーヤーにはこの数は知らされませんがヒントが示されるので、プレーヤーはヒントを参考にしてこの数を推測し、こ の数に4桁(1~3桁でもよい)の数を加算して最終的に加算した結果を9999にするとゲーム終了です。 8000番地からRUNするとピーと音がしてLEDの左1桁と3桁目が消灯し、残りは全部0になります。適当な数(たとえ ば1234)を入力してWRITE INCキーを押すとコンピュータは入力した数ともとの数を加算して加算結果を記憶します。 加算の結果9999になればゲーム終了です。加算結果が9999より大きくなったときはオーバーフローです。ブーという 音がしてLEDの左から2桁目と4桁目に”F”が表示されます。この場合には入力した数は加算されず無視されます。オ ーバーフローしなかった場合にはコンピュータは加算結果の数をチェックしてどこかの桁に”9”があればその9の数をL EDの左から2桁目に表示します。しかし何桁目が9であるかは知らせてくれません。もうひとつヒントを出します。残りの 9ではない数のうちどれか1つの数をLEDの左から4桁目に表示します。そして再びピーと音がして次の数の入力待ち になります。入力する数はWRITE INCを押すまで何回でも入れなおすことができます。 9999が完成するとピーという音がしてLEDの左4桁に9999が表示されます。 何かキーを押すとLEDの左4桁に最初に隠されていた数値が表示され、右4桁に試行回数が表示されます。 もう1回何かキーを押すと始めに戻って再びゲームが開始されます。 「マイコンゲーム21」ではゲームスタートでLEDが全部0になるようにしていますが、そうするとリセットがかかったよう な気がしてとまどってしまいますので、ここにあるようにLEDの左1桁と3桁目をブランクにしました。 プログラムの説明 特に説明しなくても、多分理解できると思います。 2016/4/20 END=818F 8000 8003 8004 8005 8006 8007 8008 C30B80 00 00 00 00 00 00 10:22 wanted8.txt ; WANTED for NDZ ; 03/05/06 5/12 ;10/6/3 for ND80Z3 ;7/21 9/17 ;16/4/19 for nd8080 ;4/20 ; ORG $8000 ; MYDT=$E800 ; ACC=$E802 ; CNTR=$E805 ; RNDDT=$E810;$E811 DTRG=$83EC;$FFEC ADRG=$83EE;$FFEE LED1=$83F8;$FFF8 LED3=$83FA;$FFFA DP1=$83F4;$FFF4 DP3=$83F6;$FFF6 R=$FFD2 ; ADDPS=$01A1;$05A1 KEYIN1=$0216;$0616 ; ;data set JMP START MYDT:NOP NOP ACC:NOP NOP CNTR:NOP RNDDT:NOP 44 8009 800A 800B 800E 8011 8012 8013 8014 8015 8018 8019 801A 801D 00 00 3AD2FF 210880 77 23 77 AF 320780 67 6F 22EC83 22EE83 8020 0604 8022 CD0E81 8025 8027 802A 802B 802C 802D 802E 802F FE0A D22280 29 29 29 29 B5 6F 8030 8031 8034 8037 05 C22280 220380 220580 803A 3E10 803C 060A 803E CD4F81 8041 8042 8045 8048 8049 804C 804F 8052 8055 8057 805A 805C 805F 8060 8061 8062 8063 8064 8065 8068 05 C23E80 CDA101 AF 32F883 32FA83 2AEC83 CD2C81 FE15 CA6B80 FE0A D25280 29 29 29 29 B5 6F 22EC83 C34580 806B 3A0780 806E C601 NOP RNDDT2:NOP START:LDA R LXI H,RNDDT MOV M,A INX H MOV M,A XRA A STA CNTR;COUNTER clear MOV H,A MOV L,A SHLD DTRG SHLD ADRG ;data set MVI B,04 DTST1:CALL RND4 ; ANI 0F CPI 0A JNC DTST1 DAD H DAD H DAD H DAD H ORA L MOV L,A ;? DJNZ *DTST1 DCR B JNZ DTST1 SHLD MYDT SHLD ACC ;GAME START START1:MVI A,10;puuuu MVI B,0A START2:CALL SOUND ;? DJNZ START2 DCR B JNZ START2 KEY:CALL ADDPS XRA A STA LED1 STA LED3 KEY1:LHLD DTRG KEY2:CALL KEYIN1S CPI 15;W INC JZ ADD CPI 0A JNC KEY2 DAD H DAD H DAD H DAD H ORA L MOV L,A SHLD DTRG JMP KEY ;DATA add and check ADD:LDA CNTR ADI 01;DECIMAL COUNTER up 45 8070 27 8071 320780 8074 8075 8078 8079 807A 807B 807C 807D 807E 807F 8080 8083 8084 EB 2A0580 EB 7B 85 27 6F 7A 8C 27 DACB80 67 220580 8087 8089 808B 808D 808E 1600 0E04 0604 29 17 808F 8090 8093 8095 8097 809A 809B 809C 809F 80A0 80A2 05 C28D80 E60F FE09 C29B80 14 0D C28B80 7A FE04 CADF80 80A5 80A8 80AB 80AD 80AE 80AF 80B1 80B2 2A0580 CD0E81 E603 3C 4F 0604 29 17 80B3 80B4 80B7 80B8 80BB 80BD 80BF 80C2 05 C2B180 0D C2AF80 E60F FE09 CAA580 5F 80C3 80C4 80C7 80C8 EB 22EE83 EB C33A80 DAA STA CNTR ;? LD DE,(ACC) XCHG; LHLD ACC; XCHG; MOV A,E ADD L DAA MOV L,A MOV A,D ADC H DAA JC OVER MOV H,A SHLD ACC ;check MVI D,00 MVI C,04 CK1:MVI B,04 CK2:DAD H RAL ;? DJNZ *CK2 DCR B; JNZ CK2; ANI 0F CPI 09 JNZ CK3 INR D;count "9" CK3:DCR C JNZ CK1 MOV A,D CPI 04 JZ OK ;one No.(except "9") select CK4:LHLD ACC CALL RND4 ANI 03 INR A MOV C,A CK5:MVI B,04 CK6:DAD H RAL ;? DJNZ *CK6 DCR B; JNZ CK6; DCR C JNZ CK5 ANI 0F CPI 09 JZ CK4 MOV E,A ;result disp ;? LD (ADRG),DE XCHG; SHLD ADRG; XCHG; JMP START1 46 80CB 3E00 80CD 0605 80CF CD4F81 80D2 80D3 80D6 80D9 80DC 05 C2CF80 21FFFF 22EE83 C34580 80DF 3E17 80E1 0605 80E3 CD4F81 80E6 80E7 80EA 80ED 80F0 80F3 80F6 80F9 80FC 80FF 8100 8102 8105 8108 810B 05 C2E380 2A0580 22EE83 CDA101 CD2C81 2A0380 22EE83 3A0780 6F 2600 22EC83 CDA101 CD2C81 C30B80 810E 810F 8110 8113 8114 8115 8117 8118 811B 811E 811F 8120 8122 8123 8126 8129 812A 812B E5 D5 2A0880 23 7C E603 67 220880 3A0A80 57 7E E60F BA CA1081 320A80 D1 E1 C9 812C 812D 812E 8131 8132 8133 C5 D5 CD1602 D1 C1 C9 OVER:MVI A,00;buuuu MVI B,05 OVER1:CALL SOUND ;? DJNZ OVER1 DCR B; JNZ OVER1; LXI H,$FFFF SHLD ADRG JMP KEY ; ;result="9999" OK:MVI A,17;piiii MVI B,05 OK1:CALL SOUND ;? DJNZ OK1 DCR B; JNZ OK1; LHLD ACC SHLD ADRG CALL ADDPS CALL KEYIN1S LHLD MYDT SHLD ADRG LDA CNTR MOV L,A MVI H,00 SHLD DTRG CALL ADDPS CALL KEYIN1S JMP START ; ;ransu RND4:PUSH H PUSH D RND2:LHLD RNDDT INX H MOV A,H ANI 03 MOV H,A SHLD RNDDT LDA RNDDT2 MOV D,A MOV A,M ANI 0F CMP D JZ RND2 STA RNDDT2 POP D POP H RET ; ;KEYIN with DE,BC save KEYIN1S:PUSH B PUSH D CALL KEYIN1 POP D POP B RET 47 8134 8135 8137 813A 813B 813E 813F D5 1E64 CD4081 1D C23781 D1 C9 8140 8141 8143 8145 8146 8149 814A 814D 814E D5 1607 1E12 1D C24581 15 C24381 D1 C9 814F 8150 8151 8152 8153 8156 8157 8158 8159 815B 815C 815E 8160 8161 8162 8165 8166 8168 816A 816B 816C 816F 8170 8173 8174 8175 8176 8177 F5 E5 D5 C5 217881 85 6F 46 1E1A 50 3EFF D398 7F 15 C26081 50 3EDF D398 7F 15 C26A81 1D C25B81 C1 D1 E1 F1 C9 8178 8179 817A 817B 817C 817D 817E 817F 7F 77 71 6A 5F 59 54 4F ; ;0.1sec timer TM01S:PUSH D MVI E,64;=100 TM01S2:CALL TM1M DCR E JNZ TM01S2 POP D RET ; ;1msec timer TM1M:PUSH D;11 MVI D,07; ck=5 (11+7+292*7+10+10)/2.048=2082/2.048=1016 TM1M2:MVI E,12;=18 ck=7 7+15*18+15=292 TM1M3:DCR E;5 JNZ TM1M3;10 DCR D;5 JNZ TM1M2;10 POP D;10 RET;10 ; SOUND:PUSH PSW PUSH H PUSH D PUSH B LXI H,SNDTBL ADD L MOV L,A MOV B,M MVI E,1A SNDS1:MOV D,B MVI A,FF;SP OUT=H OUT 98 SNDS2:MOV A,A;5--------DCR D;5 | 5+5+10=20 20/2=10microsec JNZ SNDS2;10---MOV D,B MVI A,DF;sp out=L OUT 98 SNDS3:MOV A,A;5--------DCR D;5 | 5+5+10=20 20/2=10microsec JNZ SNDS3;10---DCR E JNZ SNDS1 POP B POP D POP H POP PSW RET ; SOUND TABLE SNDTBL:DB 7F;so4 DB 77;so#4 DB 71;ra4 DB 6A;ra#4 DB 5F;do5 DB 59;do#5 DB 54;re5 DB 4F;re# 48 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 818A 818B 818C 818D 818E 818F 47 43 3F 3B 35 32 2F 2C 25 27 2A 4B 38 64 23 21 ACC ADRG CK3 CK6 DP3 KEY KEYIN1 LED3 OK1 R RNDDT SNDS2 SOUND START2 TM1M DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB ; ; =8005 =83EE =809B =80B1 =83F6 =8045 =0216 =83FA =80E3 =FFD2 =8008 =8160 =814F =803E =8140 47;fA5 43;fa#5 3F;so5 3B;so5# 35;ra#5 32;si5 2F;do6 2C;do#6 25;mi6 27;re#6 2A;re6 4B;mi5 38;ra5 64;si4 23;fa6 21;fa#6 ADD CK1 CK4 CNTR DTRG KEY1 KEYIN1S MYDT OVER RND2 RNDDT2 SNDS3 START TM01S TM1M2 =806B =808B =80A5 =8007 =83EC =804F =812C =8003 =80CB =8110 =800A =816A =800B =8134 =8143 ADDPS CK2 CK5 DP1 DTST1 KEY2 LED1 OK OVER1 RND4 SNDS1 SNDTBL START1 TM01S2 TM1M3 =01A1 =808D =80AF =83F4 =8022 =8052 =83F8 =80DF =80CF =810E =815B =8178 =803A =8137 =8145 49 プログラム№10 すごろく迷路(SUGOROK8.BTK) ゲームの説明 LED表示を利用したすごろくゲームです。 8個のLEDのさらに右側にゴールがあります(見えませんがあることにします)。LEDの左側にも1つダミーポジション があります(これも見えませんがあることにします)。 8000番地からRUNするとピーと音がしてLEDが消灯します。ゲーム開始です。各LEDにはコンピュータが乱数を使 って1~8の数を隠しています。そのうち1つは1回でゴールに到着できるようにセットされています。 プレーヤーはスタートポジションを選択するため1~8のどれかを押します。ピッと音がしてその数で示される桁位置の LEDが点灯します。表示される数は右または左に進むステップ数です。プレーヤーは右に進むか左に進むかをキー入 力で示します。右ならWRITE INCを、左なら0を押します。指定した方向にステップ数だけ移動すると、そこでまたピッ と音がして次のLEDが点灯します。うまくLEDの右に進んでちょうどゴールで止まればゲーム終了です。ゴールに来て もまだ進むステップが残っているときは残った数だけ左に戻ってしまいます。左に進んだときも同じで左端のLEDを超え てダミーポジションも超えてしまうと残ったステップ数だけ右へもどってしまいます。ダミーポジションで止まってしまわな いように計算されています。またゴールに直接行けるのは1ヶ所だけです。みごとゴールできるとプーと音がして、それま での試行回数が表示されて、2秒間点滅します。そのあと2秒静止してからまた始めに戻って再びゲームが開始されま す。 運が悪いと同じところをぐるぐる回るだけでゴールに行けないこともあります。リセットしてやり直してください。 プログラムの説明 まず最初に乱数によって1~8のうちのどれかを選びます。これが最後にゴールに到着するときのステップ数です。つ ぎにこの数をセットするLEDを計算で求めます。実際にはLED位置に対応するDTBFに数を格納します。最初にDTBF を全て00でクリアしています。その結果HLレジスタはDTBF8バイトの次のアドレス(8208)になっています。;last position selectのところです。RNDルーチンによって、たとえば1が選ばれたとすると、ゴールに1ステップで行けるのは 右端のLED(アドレスは83FF)です。ここに対応するDTBFのアドレスは8207です。つまり選択したステップ数をHL(8 208)からマイナスすると、その数を格納するDTBFアドレスが求められます。そこでLからEを引く計算をしているので す。 次の;data set では残った7つの場所にやはりRNDによって1~8のいずれかを選んでセットしていきます。最初にセッ トした最終ポジションはパスします(DTST2:)。ルールにより、ゴールに行けるのは1個所だけ、また左のダミーポジジョ ンで止まってしまうこともないようにするため、RNDで選んだステップ数とそれを格納するDTBFアドレス(下位アドレス はLED位置と同じ)とから、次のポジションを計算してみて、その結果が08(ゴール)のときとFF(ダミー)のときを除外し ます(DTST3:)。 さてKEYから0(左)かWRITE INC(右)かを入力すると、Dレジスタにある現在の位置情報(00~07)と、次の場所 へのステップ数(Eレジスタ)から、次のポジションを算出します。右へ進む場合と左へ進む場合とで処理が異なりま す。;step to right と;step to left です。 ここでは何だかよくわからない計算をしています。まず右の場合です。D+Eが次のポジションになること、それからそ の次のポジションが08ならゴール(右端のLEDのポジションが07なので)であることは納得できると思います。問題は 加算の結果が08より大きい場合です。この場合は08を超えた分だけ左に戻ります。ここはどうしているかというと、NE GそしてANI 07で次のポジションとしています(???)。 NEGは8080には無い命令です。その代わりとしてCMAとINR Aを使っています。NEGはネガティブで0-Aを結果 とします。たとえば08より1だけ多い09について考えてみます。この場合ゴールから1ステップだけ左に戻りますから、 次のポジションは07です。では09に対してNEG命令を実行すると結果はどうなるのでしょうか?0-9=-9ですからA レジスタの値はF7になります。どーして-9がF7になるの?という人はこの説明書を最初から順に読んでこなかった人 です。F7は10進に直すと247ですが、符号付の数として考えたときには-9なのです。 うーん。わからない?F7に09を加算してみてください。 11110111 (F7) 247 9 00001001 (09) 1 00000000 (0100) 256 結果は0100で16ビット(2バイト)の数として見れば10進に直して256となります。これは正しい。では2バイトではなく てオーバーフローを許して結果も1バイトだとするとどうなるでしょうか?あくまで結果も1バイトにするのですから0100 ではなくて00になります。ほら-9+9=0で結果は合っています。 どーもおかしい。だまされているみたいだ、と思うかもしれませんがそういうことだと覚えてしまってください。慣れてくる とだんだん納得できるようになります。 さてもとに戻って説明を続けます。NEG命令によってもとのAレジスタの値は09からF7に変わります。そこでANI 07 を実行するとあら不思議、行くべきポジションの07になります。 次は左の処理です。D-Eが次のポジションになることは分かると思います。ただし結果がプラスの場合に限ります。 50 減算結果がマイナス(Cフラグが立つ)の時はどうするか?またNEG命令を使っています。マイナスのマイナスでプラス になります(もー、余計にわからーん!)。右の処理で説明したことと考え方は同じです。左の処理ではNEGのあとでSU I 02を行っています。どーしてこれでよいのか各自確かめてみてそして考えてみてください。 2016/4/20 END=8173 8000 8003 8004 8005 C30680 00 00 00 8006 CDB480 8009 800A 800B 800D 800E 800F 8010 8012 3C 5F 3E08 93 6F 57 2682 73 8013 8016 8018 8019 801A 801D 210082 0608 7D BA CA3080 CDB480 8020 8021 8022 8023 8025 8028 8029 802A 802C 802F 8030 3C 4F 85 FE08 CA1D80 7D 91 FEFF CA1D80 71 23 14:26 sugorok8.txt ; SUGOROKU for NDZ (SKIP OUT) ; 03/05/01 5/2 5/5 5/12 5/13 ;10/6/3 for ND80Z3 ;7/21 9/17 ;16/4/20 for nd8080 ; ORG $8000 DTBF=$8200;$E800 ; RNDDT=$E810;$E811 LED1=$83F8;$FFF8 DP1=$83F4;$FFF4 DP3=$83F6;$FFF6 CNTR=$83F7;$FFF7;=DP4 ; DTDPS=$01C0;$05C0 KEYIN1=$0216;$0616 D1=$02DD;4.684ms ; JMP START RNDDT:NOP NOP RNDDT2:NOP ;last position select START:CALL RND3 ; ANI 07 INR A MOV E,A;distance from goal MVI A,08;goal position SUB E MOV L,A MOV D,A;last position save MVI H,82;high address of DTBF MOV M,E ;data set LXI H,DTBF MVI B,08 DTST2:MOV A,L CMP D JZ DTST4;skip last position DTST3:CALL RND3 ; ANI 07 INR A MOV C,A;DATA save ADD L;next position(right) CPI 08;goal position JZ DTST3 MOV A,L SUB C;next position(left) CPI FF;dummy position JZ DTST3 MOV M,C DTST4:INX H 51 ;? 8031 05 8032 C21880 8035 210000 8038 22F683 803B 22F483 803E 8041 8043 8045 CDD280 3E0A 0610 CD0A81 8048 8049 804C 804F 8051 8054 8055 8058 8059 805C 805E 805F 8062 05 C24580 CDF480 FE09 D24C80 3D FA4C80 57 3AF783 C601 27 32F783 CD4B81 8065 8068 8069 806C 806E CDF480 B7 CA8580 FE15 C26580 8071 8072 8073 8075 8078 7A 83 FE08 CA9180 DA7F80 807B 807C 807D 807F 8082 2F 3C E607 CDD280 C35880 8085 7A 8086 93 8087 D27F80 808A 808B 808C 808E 2F 3C D602 C37F80 8091 3E00 8093 0610 8095 CD0A81 DJNZ *DTST2 DCR B; JNZ DTST2; ;GAME START LXI H,$0000 SHLD DP3;DECIMAL COUNTER clear SHLD DP1 ;key entry(1-8) CALL CLR MVI A,0A MVI B,10 START1:CALL SOUND ;? DJNZ START1 DCR B; JNZ START1; KEY:CALL KEYIN1S;1-8 input CPI 09 JNC KEY DCR A JM KEY NEXT:MOV D,A;position save LDA CNTR;DECIMAL COUNTER up ADI 01 DAA STA CNTR CALL DTDP;data disp and save to E ;right or left in KEY1:CALL KEYIN1S ORA A JZ LEFT CPI 15;WRITE INC JNZ KEY1 ;step to right MOV A,D;current position(00-07) ADD E;E=step No. D+E=next position CPI 08 JZ GOAL JC RIGHT1; D+E<08 ;? NEG; 0-A CMA; INR A; ANI 07;next position RIGHT1:CALL CLR JMP NEXT ;step to left LEFT:MOV A,D;current position(00-07) SUB E;E=step No. JNC RIGHT1 ;? NEG CMA; INR A; SUI 02;next position JMP RIGHT1 ;goal GOAL:MVI A,00 MVI B,10 GOAL1:CALL SOUND ;? DJNZ GOAL1 52 8098 8099 809C 809F 80A2 80A5 80A8 80AA 05 C29580 CDD280 CDFC80 CDC001 CDDF80 0614 CDFC80 80AD 05 80AE C2AA80 80B1 C30680 80B4 80B5 80B6 80B9 80BA 80BB 80BD 80BE 80C1 80C4 80C5 80C6 80C8 80C9 80CC 80CF 80D0 80D1 E5 D5 2A0380 23 7C E603 67 220380 3A0580 57 7E E607 BA CAB680 320580 D1 E1 C9 80D2 80D5 80D8 80D9 21F883 010008 71 23 80DA 05 80DB C2D880 80DE C9 80DF 80E1 80E3 80E5 80E8 80EA 80EC 060A 3EEF D398 CDFC80 3EFF D398 CDFC80 80EF 05 80F0 C2E180 80F3 C9 80F4 C5 DCR B; JNZ GOAL1; CALL CLR CALL TM01S CALL DTDPS;COUNTER disp CALL ALBLNK MVI B,14;=20 2sec wait WAIT:CALL TM01S ;? DJNZ WAIT DCR B; JNZ WAIT; JMP START ; ;ransu RND3:PUSH H PUSH D RND2:LHLD RNDDT INX H MOV A,H ANI 03 MOV H,A SHLD RNDDT LDA RNDDT2 MOV D,A MOV A,M ANI 07 CMP D JZ RND2 STA RNDDT2 POP D POP H RET ; ;LED clear CLR:LXI H,LED1 LXI B,$0800 CLR2:MOV M,C INX H ;? DJNZ *CLR2 DCR B; JNZ CLR2; RET ; ;LED all blink ALBLNK:MVI B,0A;=10 ALBLNK1:MVI A,EF OUT 98 CALL TM01S MVI A,FF OUT 98 CALL TM01S ;? DJNZ *ALBLNK1 DCR B; JNZ ALBLNK1; RET ; ;KEYIN with DE,BC save KEYIN1S:PUSH B 53 80F5 80F6 80F9 80FA 80FB D5 CD1602 D1 C1 C9 80FC 80FD 80FF 8100 8103 8104 8105 8108 8109 D5 1E15 D5 CDDD02 D1 1D C2FF80 D1 C9 810A 810B 810C 810D 810E 8111 8112 8113 8114 8116 8117 8119 811B 811C 811D 8120 8121 8123 8125 8126 8127 812A 812B 812E 812F 8130 8131 8132 F5 E5 D5 C5 213381 85 6F 46 1E1A 50 3EFF D398 7F 15 C21B81 50 3EDF D398 7F 15 C22581 1D C21681 C1 D1 E1 F1 C9 8133 8134 8135 8136 8137 8138 8139 813A 813B 813C 813D 7F 77 71 6A 5F 59 54 4F 47 43 3F PUSH D CALL KEYIN1 POP D POP B RET ; ; ;0.1sec timer TM01S:PUSH D MVI E,15;=21 TM01S2:PUSH D CALL D1;4.684ms POP D DCR E JNZ TM01S2 POP D RET ; SOUND:PUSH PSW PUSH H PUSH D PUSH B LXI H,SNDTBL ADD L MOV L,A MOV B,M MVI E,1A SNDS1:MOV D,B MVI A,FF;SP OUT=H OUT 98 SNDS2:MOV A,A;5--------DCR D;5 | 5+5+10=20 JNZ SNDS2;10---MOV D,B MVI A,DF;sp out=L OUT 98 SNDS3:MOV A,A;5--------DCR D;5 | 5+5+10=20 JNZ SNDS3;10---DCR E JNZ SNDS1 POP B POP D POP H POP PSW RET ; SOUND TABLE SNDTBL:DB 7F;so4 DB 77;so#4 DB 71;ra4 DB 6A;ra#4 DB 5F;do5 DB 59;do#5 DB 54;re5 DB 4F;re# DB 47;fA5 DB 43;fa#5 DB 3F;so5 20/2=10microsec 20/2=10microsec 54 813E 813F 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 814A 3B 35 32 2F 2C 25 27 2A 4B 38 64 23 21 814B 814C 814F 8150 8151 8152 8153 8156 8157 8159 815A 815B 815C 815F 8160 8161 8162 8163 8165 8167 7A 210082 85 6F 7E 5F 216B81 4F 0600 09 7E 47 21F883 7A 85 6F 70 3E10 0603 CD0A81 816A 816B 816C 816D 816E 816F 8170 8171 8172 8173 C9 5C 06 5B 4F 66 6D 7D 27 7F ALBLNK CLR2 DP1 DTDP DTST2 GOAL KEY1 LED1 RIGHT1 RNDDT DB DB DB DB DB DB DB DB DB DB DB DB DB 3B;so5# 35;ra#5 32;si5 2F;do6 2C;do#6 25;mi6 27;re#6 2A;re6 4B;mi5 38;ra5 64;si4 23;fa6 21;fa#6 ; ; ;DATA disp and save to E DTDP:MOV A,D LXI H,DTBF ADD L MOV L,A MOV A,M MOV E,A;DATA save LXI H,SEGDT MOV C,A MVI B,00 DAD B MOV A,M MOV B,A;segment data LXI H,LED1 MOV A,D ADD L MOV L,A MOV M,B MVI A,10 MVI B,03 DTDP1:CALL SOUND ;? DJNZ *DTDP1 RET SEGDT:DB 5C;0 DB 06;1 DB 5B;2 DB 4F;3 DB 66;4 DB 6D;5 DB 7D;6 DB 27;7 DB 7F;8 ; =80DF ALBLNK1 =80E1 =80D8 CNTR =83F7 =83F4 DP3 =83F6 =814B DTDP1 =8167 =8018 DTST3 =801D =8091 GOAL1 =8095 =8065 KEYIN1 =0216 =83F8 LEFT =8085 =807F RND2 =80B6 =8003 RNDDT2 =8005 save CLR D1 DTBF DTDPS DTST4 KEY KEYIN1S NEXT RND3 SEGDT =80D2 =02DD =8200 =01C0 =8030 =804C =80F4 =8058 =80B4 =816B 55 SNDS1 SNDTBL START1 WAIT =8116 =8133 =8045 =80AA SNDS2 SOUND TM01S =811B =810A =80FC SNDS3 START TM01S2 =8125 =8006 =80FF 56 プログラム№11 REVERSE(REVERSE8.BTK) ゲームの説明 数字の並べ替えゲームです。 8000番地からRUNすると1~8の数がばらばらの順序で表示されます。これをルールにしたがって12345678に 並べ替えるとゲーム終了です。 1~8の数を入力すると左からその桁数分の表示が点滅します。WRITE INCを押すと入力が確定します。WRITE I NCを押すまでは入力をやり直すことができます。WRITE INCによって入力が確定すると点滅していた表示が左右反 転します。これを繰り返して12345678が完成すると全体が2秒間点滅します。次に試行回数が表示され2秒間静止し ます。そのあとまた始めに戻って再びゲームが開始されます。 プログラムの説明 まず最初にDTBF(8バイト)をクリアします。ここに1~8の数をランダムに選んで格納します。8桁の数ですし、LEDに 表示するわけですから、LED表示用のメモリエリア(83F4~83F7)を使うか、アドレスレジスタ及びデータレジスタ(83 EC~83EF)を使った方が結果の表示は簡単になります。そうすると8桁のBCD数として扱うことになります。しかし今 回のプログラムのように桁単位で数の入れ替えが必要な処理ではBCD数というのはなかなかに面倒なのです。1桁が 4ビットなのですが8080には4ビット単位でデータを扱う命令はありません。4ビット単位で扱うにはシフト命令で1ビット ずつ4回シフトして1桁ごとに分離するしかありません。そこでこのプログラムでは処理のたびにどうせ1桁ずつ分離しな ければならない(今のところ、多分)のならはじめから分離して1桁ずつの数にして(たとえば、56というBCD数ではなく て、05、06という数にして)8バイトのデータエリアに格納し、ここで1バイト単位で数の入れ替えをするように考えました。 1バイト単位ならいろんな命令が使えるので楽になりそうです。8バイトのデータバッファの内容を表示するには、4バイト のBCD数に直さなければいけませんが、これは結果を表示するときだけですから、変換するサブルーチンを作って処理 することにしました。 まずDTBFを0クリアします。DTST0:のところです。ここまでにも出てきてると思いますが、XRA AはMVI A,00の 代わりとしてよく使います。Aレジスタを00にするため以外の意図はありません。DTST1:以下のところで1~8の数を 乱数によりランダムに作り、それをDTBFに格納しています。なんだかややこしいことをしているようですが、これは1~8 を1度だけ選んで格納するための処理なのです。まずRNDにより1~8のうちの1つの数を選び、それをDTBFに格納 するのですが、そのときDTBFの先頭から順にメモリの内容を確認します(DTST2:)。ここでテクニックを使っています。 MOV A,Mとして、ORA Aなどとしたいところですが、AレジスタにはRNDで選んだ数がすでに入っています。PUSH PSWとするとか、MOV D,AとしたりしてまずAの中身を退避させておいて…などと考えるのは、教条主義です(懐かし い言葉。知らないだろうなー。今どき)。ここは遊んでいるCレジスタを使ってDCR Cとしてしまいます。メモリの内容が0 0ならDCR Cの結果はFFになって、前のプログラムで出てきたようにマイナスになるのでSフラグが立ちます。でJMと いくわけです。ついでですが、SUB命令などではマイナスになると同時にキャリー(Cフラグ)も立つので、よくJCを使い ますが、DCRとINRについてはCフラグのみ変化しないので注意してください。 さてDTBFを前から順に確認していって最初に00の場所をみつけたら、Aに入っている数を格納してしまいます(あ れ?同じ数を選んでしまったかどうかの確認はしなくてもよいのか?)。プログラムの流れでは逆になっているようで分か りにくいのですがちゃんとやっているのです(DTST3:)。RNDで新しい数を選んだら必ずDTBFの先頭から内容を確認 しています。もし00でなかったらDTRD3:で同じ数か異なる数かをチェックします。ですからこのチェックをパスしてきて、 もう比較するデータが無い(つまり次のDTBFの内容が00のとき)なら、新しく出てきた数になるのでDTBFに格納しても よいことになります。 RNDで乱数がうまく作り出せなくてアドレスが8000の表示のままでハングアップしてしまうことがあります。リセットし てもう一度8000から実行してみてください。 無事8桁の数が決まったらまずLEDに表示します。DTBFDPサブルーチンです。DTBFの8バイトの数をBCD4バイト に変換してDP1~に格納します。DTBFは8バイトですが内容は下位4ビットに1~8が入っているだけですから、最初 のバイトを読んでそれを左に4ビットシフトして、そこに次のバイトの下位4ビット(上位4ビットは常に0)をORで合わせれ ばBCD2桁が出来あがります。最後にLED表示ルーチンをCALLします。 キーの入力です。入力前にCレジスタに01を入れています。あとで出て来ますが、Cレジスタにはキー入力した1~8 の桁指定数が入るのです。普通はまず桁指定の数を入力して、次にWRITE INCの入力ですが、そのようにキー入力 ルーチンを2段階に並べても、WRITE INCの入力待ちのときに数値を入れなおす場合もでてきます。そうすると結構 複雑なプログラムになってしまいます。ここはこのプログラムのように数値でもWRITE INCでもその入力順序に関係無 く受けつけてしまうとよいのです。数値が入力されたらそれをCレジスタに保存しておけば、次にWRITE INCが押され たときにCレジスタの値をもって処理ルーチンへ行くことができます。しかし中にはまだ数値を入力していないのにWRIT E INCを押してしまうあわて者がいるかもしれません。最初にCレジスタに01を入れているのはこのあわて者対策です。 データを反転させる桁数で1を指定しても結果は変わりません。このあとで出てくる反転処理ルーチン(REV:)ではC= 01のときは何もしないでリターンします。 ではいよいよそのREV:の説明です。何をしているのかちょっと見にはよくわかりません。でもここはごく当たり前の処 理をしています。まずDTBFのトップ(LEDの左端に相当)アドレスをHLに、そしてCレジスタの値から、反転させる範囲 57 の右端のDTBFアドレスを算出してDEに入れます。CレジスタはC=01をチェックするためとDEへのアドレス計算のた めにDCRしたものをもとに戻すためINRしたあとSRLを実行します。SRLも8080には無い命令です(その代わりとして 複数の命令を使っています)。Cレジスタの値が1/2になります。もとの値が奇数の場合は1/2した結果できる端数は 切り捨てられます。 これで準備完了です。AレジスタとBレジスタを利用して両端のデータ、(HL)と(DE)を入れ替えます。このあとHLを+ 1、DEを-1します。つまり外側から内側に1バイトずつアドレスを寄せるのです。この処理をC=00になるまで繰り返 すとデータの前後が全部入れ替わります。対象が奇数桁の場合には中央の桁は動きません。アドレスをHLとDEで1ず つせばめるのでCを1/2にしているのですが、奇数桁の場合には最後に残った1バイトは中央にあって動きませんから Cを1/2したときに切り捨ててよいのです。むむ、我ながら、なんと巧妙な(自画自賛)。 この部分がもしBCD数であったとすると面倒な処理になります。 データを入れ替えたあと、結果をLEDに表示します(DTBFDP)。そのあと、数字が並んだかどうかチェックします (;compare DATA)。ここもBCD数だと面倒です(ただし今回は結果が12345678になったかどうかの比較をすればよ いので各桁の大小比較をするよりずっと楽ではあります)。このプログラムではDTBFを先頭から順に読み出して、大小 を比較するだけで済みますからいとも簡単です。 順序が逆になってしまいましたがBLNKCについて説明します。指定した桁の表示だけブリンクさせるものです。ブリン クする桁数をCレジスタに入れます。ブリンクする準備として対象になるLEDレジスタの内容をBLNKBFにコピーします。 準備ができたら0.1秒ごとにLEDレジスタの内容を読み出して、BLNKBFと比較します。ここは比較しなくても00かど うかを確認すればよいのですが、その次にBLNKBFの値をLEDレジスタにコピーする作業があるため、先にAレジスタ にBLNKBFの値を読み出すという、普通の考えとは逆のようなことをしています(CMP MはあるがCMP (DE)という 命令は無い)。こういうところがちょいとした工夫です。内容が一致したら、LEDレジスタに00を書き込み、不一致なら (つまりLEDレジスタの内容が00なら)BLNKBFにコピーしてあるもとの表示データをLEDレジスタに書き込みます。こ れを繰り返すと表示がブリンクします。このル-チンではブリンク中にキーからの入力も確認しています。キー入力があ るとブリンクを停止してBLNKBFの内容をもとのLEDレジスタに戻してリターンします。 2016/4/20 END=8182 8000 8003 8004 8005 8006 8007 8008 8009 800A 800B 800C C31780 00 00 00 00 00 00 00 00 00 00 10:30 reverse8.txt ; REVERSE for NDZ ; 03/04/29 4/30 5/1 5/2 5/5 5/13 5/15 ;10/6/3 for ND80Z3 ;16/4/19 for nd8080 ;4/20 ; ORG $8000 ; DTBF=$E800 ; BLNKBF=$E808 ; RNDDT=$E810;$E811 ; CNTR=$E812 LED1=$83F8;$FFF8 DP1=$83F4;$FFF4 DP3=$83F6;$FFF6 R=$FFD2 ; DTDPS=$01C0;$05C0 KEYIN1=$0216;$0616 KEYIN2=$0223;$0623 ; ;data set JMP START DTBF:NOP NOP NOP NOP NOP NOP NOP NOP BLNKBF:NOP NOP 58 800D 800E 800F 8010 8011 8012 8013 8014 8015 8016 00 00 00 00 00 00 00 00 00 00 8017 801A 801D 801E 801F 8020 8022 8025 8026 8027 3AD2FF 211380 77 23 77 0608 210380 AF 77 23 8028 05 8029 C22680 802C CDC480 802F 8030 8032 8035 8036 8037 803A 3C 0608 210380 4E 0D F24280 77 803B 803C 803F 8042 8043 8046 05 C22C80 C34B80 BE CA2C80 23 8047 8048 804B 804E 804F 05 C23580 CD3181 AF 321680 8052 8054 8057 8059 805C 805E 8061 8063 0E01 CD4B81 FE15 CA6D80 FE09 D25480 FE02 DA5480 8066 4F 8067 CDF780 NOP NOP NOP NOP NOP NOP RNDDT:NOP NOP RNDDT2:NOP CNTR:NOP ; START:LDA R LXI H,RNDDT MOV M,A INX H MOV M,A MVI B,08 LXI H,DTBF XRA A DTST0:MOV M,A INX H ;? DJNZ *DTST0 DCR B; JNZ DTST0; DTST1:CALL RND3 ; ANI 07 INR A MVI B,08 LXI H,DTBF DTST2:MOV C,M DCR C JP DTST3 MOV M,A ;? DJNZ *DTST1 DCR B; JNZ DTST1; JMP ENTRY DTST3:CMP M JZ DTST1 INX H ;? DJNZ *DTST2 DCR B; JNZ DTST2; ENTRY:CALL DTBFDP XRA A STA CNTR;DECIMAL COUNTER clear ;key entry(1-8) REENT:MVI C,01 KEY:CALL KEYIN1S KEY1:CPI 15;WRITE INC JZ REV CPI 09 JNC KEY CPI 02 JC KEY ;blink select data MOV C,A CALL BLNKC 59 806A C35780 806D 806E 8071 8074 8075 8076 8077 8078 0D CA5280 210380 54 79 85 5F 0C 8079 807A 807B 807C 807D 807E 807F 8080 8081 8082 8083 8084 8085 8086 8087 808A 808D 8090 8092 8093 F5 79 B7 1F 4F F1 1A 46 77 78 12 23 1B 0D C27F80 CD3181 3A1680 C601 27 321680 8096 8099 809B 809C 809D 809E 210380 0607 7E 23 BE D25280 80A1 05 80A2 C29B80 80A5 CDE280 80A8 80AB 80AE 80B1 80B2 80B5 80B8 80BA 210000 22F483 3A1680 67 22F683 CDC001 0614 CD5B81 80BD 05 80BE C2BA80 80C1 C31780 JMP KEY1 ;reverse REV:DCR C JZ REENT LXI H,DTBF MOV D,H MOV A,C ADD L MOV E,A INR C ;? SRL C PUSH PSW; MOV A,C; ORA A; RAR; MOV C,A; POP PSW; REV1:LDAX D MOV B,M MOV M,A MOV A,B STAX D INX H DCX D DCR C JNZ REV1 REV2:CALL DTBFDP LDA CNTR;DECIMAL COUNTER up ADI 01 DAA STA CNTR ;compare DATA LXI H,DTBF MVI B,07 COMP1:MOV A,M INX H CMP M JNC REENT;not yet ;? DJNZ *COMP1 DCR B; JNZ COMP1; ;OK! ALL LED blink CALL ALBLNK ;COUNTER disp LXI H,$0000 SHLD DP1 LDA CNTR MOV H,A SHLD DP3 CALL DTDPS MVI B,14;=20 ,2sec wait WAIT:CALL TM01S ;? DJNZ WAIT DCR B; JNZ WAIT; JMP START ; ;ransu 60 80C4 80C5 80C6 80C9 80CA 80CB 80CD 80CE 80D1 80D4 80D5 80D6 80D8 80D9 80DC 80DF 80E0 80E1 E5 D5 2A1380 23 7C E603 67 221380 3A1580 57 7E E607 BA CAC680 321580 D1 E1 C9 80E2 80E4 80E6 80E8 80EB 80ED 80EF 060A 3EEF D398 CD5B81 3EFF D398 CD5B81 80F2 05 80F3 C2E480 80F6 C9 80F7 80F8 80FB 80FE 79 21F883 110B80 0600 8100 8103 8104 8107 810A 810B 810C 810D 8110 8111 8112 8113 CD7681 4F 21F883 110B80 41 1A BE C21181 AF 77 23 13 8114 8115 8118 811B 811E 811F 8122 8123 05 C20B81 CD5B81 CD5381 3C CA0481 3D 210B80 RND3:PUSH H PUSH D RND2:LHLD RNDDT INX H MOV A,H ANI 03 MOV H,A SHLD RNDDT LDA RNDDT2 MOV D,A MOV A,M ANI 07 CMP D JZ RND2 STA RNDDT2 POP D POP H RET ; ;LED all blink ALBLNK:MVI B,0A;=10 ALBLNK1:MVI A,EF OUT 98 CALL TM01S MVI A,FF OUT 98 CALL TM01S ;? DJNZ *ALBLNK1 DCR B; JNZ ALBLNK1; RET ;LED blink BLNKC:MOV A,C;save C LXI H,LED1 LXI D,BLNKBF MVI B,00 ;? LDIR CALL LDIR MOV C,A BLNKC1:LXI H,LED1 LXI D,BLNKBF MOV B,C BLNKC2:LDAX D CMP M JNZ BLNKC3 XRA A BLNKC3:MOV M,A INX H INX D ;? DJNZ *BLNKC2 DCR B; JNZ BLNKC2; CALL TM01S CALL KEYIN2S INR A JZ BLNKC1;no key in DCR A;key data LXI H,BLNKBF 61 8126 11F883 8129 0600 812B C5 812C CD7681 812F C1 8130 C9 8131 8134 8137 8139 813A 813B 813C 813D 813E 813F 8140 8141 8142 210380 11F483 0604 7E 07 07 07 07 23 B6 12 23 13 8143 8144 8147 814A 05 C23981 CDC001 C9 814B 814C 814D 8150 8151 8152 8153 8154 8155 8158 8159 815A C5 D5 CD1602 D1 C1 C9 C5 D5 CD2302 D1 C1 C9 815B 815C 815E 8161 8162 8165 8166 D5 1E64 CD6781 1D C25E81 D1 C9 8167 8168 816A 816C 816D 8170 D5 1607 1E12 1D C26C81 15 LXI D,LED1 MVI B,00 PUSH B ;? LDIR CALL LDIR POP B RET ; ;DTBF data disp DTBFDP:LXI H,DTBF LXI D,DP1 MVI B,04 DTBFDP1:MOV A,M RLC RLC RLC RLC INX H ORA M STAX D INX H INX D ;? DJNZ *DTBFDP1 DCR B; JNZ DTBFDP1; CALL DTDPS RET ; ;KEYIN with DE,BC save KEYIN1S:PUSH B PUSH D CALL KEYIN1 POP D POP B RET KEYIN2S:PUSH B PUSH D CALL KEYIN2 POP D POP B RET ; ;0.1sec timer TM01S:PUSH D MVI E,64;=100 TM01S2:CALL TM1M DCR E JNZ TM01S2 POP D RET ; ;1msec timer TM1M:PUSH D;11 MVI D,07; ck=5 (11+7+292*7+10+10)/2.048=2082/2.048=1016 TM1M2:MVI E,12;=18 ck=7 7+15*18+15=292 TM1M3:DCR E;5 JNZ TM1M3;10 DCR D;5 62 8171 C26A81 8174 D1 8175 C9 8176 8177 8178 8179 817A 817B 817C 817D 817E 8181 8182 F5 7E 12 23 13 0B 78 B1 C27781 F1 C9 ALBLNK BLNKC BLNKC3 DP1 DTBFDP DTST0 DTST3 KEY1 KEYIN2 LDIR2 REENT REV2 RNDDT TM01S TM1M2 JNZ TM1M2;10 POP D;10 RET;10 ; LDIR:PUSH PSW LDIR2:MOV A,M STAX D INX H INX D DCX B MOV A,B ORA C JNZ LDIR2 POP PSW RET ; =80E2 ALBLNK1 =80F7 BLNKC1 =8111 CNTR =83F4 DP3 =8131 DTBFDP1 =8026 DTST1 =8042 ENTRY =8057 KEYIN1 =0223 KEYIN2S =8177 LED1 =8052 REV =808A RND2 =8013 RNDDT2 =815B TM01S2 =816A TM1M3 =80E4 =8104 =8016 =83F6 =8139 =802C =804B =0216 =8153 =83F8 =806D =80C6 =8015 =815E =816C BLNKBF BLNKC2 COMP1 DTBF DTDPS DTST2 KEY KEYIN1S LDIR R REV1 RND3 START TM1M WAIT =800B =810B =809B =8003 =01C0 =8035 =8054 =814B =8176 =FFD2 =807F =80C4 =8017 =8167 =80BA 63 プログラム№12 ROCK CLIMBING(ROCKCLM8.BTK) ゲームの説明 これは今までのゲームとは異なり、コンピュータ相手ではなく、二人で行う対戦ゲームです。お互いに0mからスタート し途中に足場を築きながら速く100mを登った方が勝ちというものです。運が悪かったりあまり先を急ぎすぎるとときどき 転落してしまいます。 8000番地からRUNするとLEDの左側と右側にそれぞれスタートの000が表示されます。プレイは交互に行います。 先攻は左側です。まず左のLEDが点滅してキー入力待ちになります。プレーヤーは上に登るかここで休憩して足場を築 くか選択することができます。上に登るならREAD INCを押します。休憩して足場を築くならREAD DECを押します。 登る場合にはLEDの1桁目(後攻は5桁目)に”8”の上側のセグメントのみ点灯表示されます。休憩なら”8”の下側のセ グメントが点灯表示されます。確定するにはWRITE INCを押します。WRITE INCの入力前なら登るか休憩するかの 選択を変更することができます。 上に登るを選択した場合、コンピュータは乱数を利用したサイコロを2回振って出た目の合計を上に登るm数として現 在のmに加算して表示します。ただしどちらのサイコロでも1の目が出ると前の足場まで転落してしまいます。もし足場を 築いていないときは0mまで転落してしまいます。転落したら攻守交代です。適当なところまで登ったら一旦休憩してそこ を足場にする方がよいようです。休憩したときも攻守交代になります。転落する確率は1/3ですからかなり高率です(ち ょっとサイコロに片寄りがあって続けて転落したり片方のプレーヤーだけやたら有利なときがあります)。 どちらかが先に100mに到達すると(100mを超えてもよい)全体が2秒間点滅します。そのあとまた始めに戻って再 びゲームが開始されます。 プログラムの説明 足場を記憶するために各1バイトのメモリエリアを使います。BCDデータで00~99を入れればよいので1バイトで足り ます。プレーヤー1の現在の位置を記憶するためにアドレスレジスタを、プレーヤー2のそれにはデータレジスタをその まま使います。BCD数として扱うのでこうすれば表示のための処理の手間が省けます。 今回はもっと大胆に(?)手間を省くため、プレーヤー1とプレーヤー2の処理を同じプログラムでやってしまいます。そ のためにHLレジスタだけでは足りないので、IXレジスタとIYレジスタを動員します(残念ながら8080にはIXレジスタもIY レジスタもありませんから代わりにワークエリアとしてIXWK、IYWKを使っています)。HLにはLEDの1桁目か5桁目の アドレスを入れます。登るか休むかのマークを表示するためです。IXWKには現在の位置データの格納アドレス(PLYR 1かPLYR2)を入れます。IYWKには足場データを記憶するアドレス(ASI1かASI2)を入れます。両者の処理の違いは これだけなので、その相違しているところを、HL、IXWK、IYWKに入れてしまうと、全く同じ処理で済んでしまいます。 それでは処理の内容を見ていきます。DTDPで両プレーヤーの現在位置をLEDに表示します。LED1とLED5はブラ ンクにします。次にLEDブリンクとキー入力を行います(BLNK)。このサブルーチンは №11 REVERSE のBLNK Cと同じ動作です。今回はブリンクする桁が3バイト固定なのでCレジスタの使い方は異なります。BLBKルーチンの中 でキー入力をチェックしますが、READ INC(14)かREAD DEC(13)以外は受け付けません。いずれかをAレジスタ に入れてリターンします。 USDISP:ではAレジスタの内容によりLEDに登りのマークか休憩のマークを表示します。ANI 03は入力されたコー ドの14と13を簡単に区別ためのものでそれ以外の意味はありません。この値は後の処理のためCレジスタにも保存さ れます。マーク表示後再びキー入力を待ちます(KEY:)。WRITE INCの入力を待つためです。このときまたREAD I NCかREAD DECが入力されたら、USDISP:へ戻ってマークを表示します。WRITE INCが押されたら、Cレジスタを 確認します。DCR CでSフラグが立てばREAD INCなのでサイコロを振る処理に行きます(C=00のときDCR Cを 実行すると結果はFFでマイナスになる)。そうでなければ休憩(足場の処理)に行きます。 SAI:ではサイコロを2回振って出た目を加算します。Cレジスタを0クリアしておいて、ここに加算します。サイコロは1 ~6ですが処理を簡単にするため、乱数で0~5を求め、これに1を加えます。ただし+1する前に0であれば、これは1 の目ですから、墜落の処理(DOWN)へ行きます。 サイコロの目を2回加算した結果はCレジスタとAレジスタに入ります。Cは2回加算を行うためのワークとして使っただ けなので、この後の処理では用済みです。Aレジスタを使います。Aレジスタと現在の高さデータ(IXWKにその格納メモ リアドレスがある)を加算します。加算した結果、キャリーが発生すればBCD2桁の加算でオーバーフローが発生したわ けですから、100mを超えたことになります。ゲーム終了です。そうでなければ同じプレーヤーで最初の表示ブリンクと キー入力待ちの処理に戻ります。 ASISET:では足場データの更新を行います。IXWKで示されるメモリアドレスに入っている現在の高さデータをIYWK で示される足場データの入っているメモリアドレスにCOPYします。そのあと選手交代の処理をします。現在がどちらの プレーヤーの番かはHLレジスタに入っているのが、LED1のアドレスかLED5のアドレスかを見ればわかります。そこで 選手交代して最初の処理に戻ります。 DOWN:ではIXWKに入っている現在の高さを格納するメモリアドレスにIYWKの情報で示される足場データをCOPY します。そのあと選手交代の処理をしてゲームを続けます。 2016/4/20 10:36 rockclm8.txt 64 END=817F 8000 8003 8004 8005 8006 8007 8008 8009 800A 800B 800C 800D 800E 800F 8012 8015 8016 8017 8018 801B 801E 8021 C30F80 00 00 00 00 00 00 00 00 00 00 00 00 3AD2FF 210880 77 23 77 210000 22EE83 22EC83 220380 8024 8027 802A 802D 8030 8033 8036 21EE83 220B80 210380 220D80 21F883 CDEA80 CD0C81 8039 E603 ; LOCK CLIMBING for NDZ ; 03/05/08 5/14 ;10/6/3 for ND80Z3 ;7/22 9/22 ;16/4/19 for nd8080 ;4/20 ; ORG $8000 ; ASI1=$E800 ; ASI2=$E801 ; BLNKBF=$E808 ; RNDDT=$E810;$E811 PLYR2=$83EC;$FFEC;=DTRG PLYR1=$83EE;$FFEE;=ADRG LED1=$83F8;$FFF8 LED5=$83FC;$FFFC R=$FFD2 ; ADDPS=$01A1;$05A1 KEYIN1=$0216;$0616 KEYIN2=$0223;$0623 ; JMP START ASI1:NOP ASI2:NOP BLNKBF:NOP NOP NOP RNDDT:NOP NOP RNDDT2:NOP IXWK:NOP NOP IYWK:NOP NOP START:LDA R LXI H,RNDDT MOV M,A INX H MOV M,A LXI H,$0000 SHLD PLYR1 SHLD PLYR2 SHLD ASI1 ;player1 REENT1:;LXI H,LED1 ;? LD IX,PLYR1 ;? LD IY,ASI1 LXI H,PLYR1; SHLD IXWK; LXI H,ASI1; SHLD IYWK; LXI H,LED1; REENT2:CALL DTDP CALL BLNK ;"UP" or "STAY" disp USDISP:ANI 03 65 803B 803C 803E 8041 8043 8044 8047 8049 804C 804E 8051 8053 8056 4F 3E01 CA4380 3E08 77 CD4881 FE15 CA5980 FE13 CA3980 FE14 C24480 C33980 8059 805A 805D 8060 0D F28280 010002 CDCC80 8063 8065 8068 8069 806C 806D 806E 806F FE06 D26080 B7 CAA680 3C 81 27 4F 8070 05 8071 C26080 8074 8075 8078 8079 E5 2A0B80 86 27 807A 807B 807C 807F 77 E1 DAB380 C33380 8082 8083 8086 8087 808A 808B E5 2A0B80 7E 2A0D80 77 E1 808C 808D 808F 8092 7D E607 C22480 21FC83 8095 E5 8096 21EC83 MOV C,A;00 or 03 save MVI A,01;"UP" JZ USDISP1 MVI A,08;"STAY" USDISP1:MOV M,A KEY:CALL KEYIN1S CPI 15;write inc JZ SAI CPI 13;read dec("STAY") JZ USDISP CPI 14;read inc("UP") JNZ KEY JMP USDISP ;saikoro SAI:DCR C JP ASISET;C=03(keyin=RD_DEC) LXI B,$0200 SAI1:CALL RND3 ; ANI 07 CPI 06 JNC SAI1 ORA A JZ DOWN INR A ADD C DAA MOV C,A ;? DJNZ SAI1 DCR B; JNZ SAI1; ;? ADD A,(IX+00) PUSH H; LHLD IXWK; ADD M; DAA ; STA IX+00 MOV M,A; POP H; JC WIN JMP REENT2 ;asiba set ASISET:;LDA IX+00 ; STA IY+00 PUSH H; LHLD IXWK; MOV A,M; LHLD IYWK; MOV M,A; POP H; ;change player ASISET1:MOV A,L ANI 07 JNZ REENT1;current HL=LED5 LXI H,LED5 ;? LD IX,PLYR2 ;? LD IY,ASI2 PUSH H; LXI H,PLYR2; 66 8099 809C 809F 80A2 80A3 220B80 210480 220D80 E1 C33380 80A6 80A7 80AA 80AB 80AE 80AF 80B0 E5 2A0D80 7E 2A0B80 77 E1 C38C80 80B3 80B4 80B7 80B9 80BA 80BD 80C0 80C2 E5 210B80 3601 E1 CDEA80 CDF780 0614 CD5881 80C5 05 80C6 C2C280 80C9 C30F80 80CC 80CD 80CE 80D1 80D2 80D3 80D5 80D6 80D9 80DC 80DD 80DE 80E0 80E1 80E4 80E7 80E8 80E9 E5 D5 2A0880 23 7C E603 67 220880 3A0A80 57 7E E607 BA CACE80 320A80 D1 E1 C9 80EA 80EB 80EE 80EF 80F0 80F3 80F6 E5 CDA101 E1 AF 32F883 32FC83 C9 SHLD IXWK; LXI H,ASI2; SHLD IYWK; POP H; JMP REENT2 DOWN:;LDA IY+00 ; STA IX+00 PUSH H; LHLD IYWK; MOV A,M LHLD IXWK; MOV M,A; POP H; JMP ASISET1 ;? WIN:LD (IX+01),01 WIN:PUSH H; LXI H,IXWK; MVI M,01; POP H; CALL DTDP CALL ALBLNK MVI B,14;=20 2sec wait WAIT:CALL TM01S ;? DJNZ WAIT DCR B; JNZ WAIT; JMP START ; ;ransu RND3:PUSH H PUSH D RND2:LHLD RNDDT INX H MOV A,H ANI 03 MOV H,A SHLD RNDDT LDA RNDDT2 MOV D,A MOV A,M ANI 07 CMP D JZ RND2 STA RNDDT2 POP D POP H RET ; ;data disp DTDP:PUSH H CALL ADDPS POP H XRA A STA LED1 STA LED5 RET ; ;LED all blink 67 80F7 80F9 80FB 80FD 8100 8102 8104 060A 3EEF D398 CD5881 3EFF D398 CD5881 8107 05 8108 C2F980 810B C9 810C 810D 810E 810F 8112 E5 23 E5 110580 010300 8115 8118 8119 811A 811D 811F 8120 8121 8124 8125 8126 8127 CD7381 E1 E5 110580 0603 1A BE C22581 AF 77 23 13 8128 8129 812C 812F 8132 8134 8137 8139 813C 813D 8140 05 C21F81 CD5881 CD5081 FE13 CA3C81 FE14 C21881 D1 210580 010300 8143 CD7381 8146 E1 8147 C9 8148 8149 814A 814D 814E 814F 8150 8151 8152 8155 C5 D5 CD1602 D1 C1 C9 C5 D5 CD2302 D1 ALBLNK:MVI B,0A;=10 ALBLNK1:MVI A,EF OUT 98 CALL TM01S MVI A,FF OUT 98 CALL TM01S ;? DJNZ *ALBLNK1 DCR B; JNZ ALBLNK1; RET ;LED blink and keyin HL=LED1 or LED5 BLNK:PUSH H;HL save INX H PUSH H LXI D,BLNKBF LXI B,$0003 ;? LDIR CALL LDIR; BLNK1:POP H PUSH H LXI D,BLNKBF MVI B,03 BLNK2:LDAX D CMP M JNZ BLNK3 XRA A BLNK3:MOV M,A INX H INX D ;? DJNZ *BLNK2 DCR B; JNZ BLNK2; CALL TM01S CALL KEYIN2S CPI 13;read dec JZ BLNK4 CPI 14;read inc JNZ BLNK1 BLNK4:POP D LXI H,BLNKBF LXI B,$0003 ;? LDIR CALL LDIR; POP H RET ; ;KEYIN with DE,BC save KEYIN1S:PUSH B PUSH D CALL KEYIN1 POP D POP B RET KEYIN2S:PUSH B PUSH D CALL KEYIN2 POP D 68 8156 C1 8157 C9 8158 8159 815B 815E 815F 8162 8163 D5 1E64 CD6481 1D C25B81 D1 C9 8164 8165 8167 8169 816A 816D 816E 8171 8172 D5 1607 1E12 1D C26981 15 C26781 D1 C9 8173 8174 8175 8176 8177 8178 8179 817A 817B 817E 817F F5 7E 12 23 13 0B 78 B1 C27481 F1 C9 ADDPS ASI1 ASISET1 BLNK2 BLNKBF IXWK KEYIN1 KEYIN2S LED1 PLYR2 REENT2 RNDDT SAI1 TM01S2 TM1M3 WAIT POP B RET ; ;0.1sec timer TM01S:PUSH D MVI E,64;=100 TM01S2:CALL TM1M DCR E JNZ TM01S2 POP D RET ; ;1msec timer TM1M:PUSH D;11 MVI D,07; ck=5 (11+7+292*7+10+10)/2.048=2082/2.048=1016 TM1M2:MVI E,12;=18 ck=7 7+15*18+15=292 TM1M3:DCR E;5 JNZ TM1M3;10 DCR D;5 JNZ TM1M2;10 POP D;10 RET;10 ; LDIR:PUSH PSW LDIR2:MOV A,M STAX D INX H INX D DCX B MOV A,B ORA C JNZ LDIR2 POP PSW RET ; =01A1 ALBLNK =80F7 ALBLNK1 =80F9 =8003 ASI2 =8004 ASISET =8082 =808C BLNK =810C BLNK1 =8118 =811F BLNK3 =8125 BLNK4 =813C =8005 DOWN =80A6 DTDP =80EA =800B IYWK =800D KEY =8044 =0216 KEYIN1S =8148 KEYIN2 =0223 =8150 LDIR =8173 LDIR2 =8174 =83F8 LED5 =83FC PLYR1 =83EE =83EC R =FFD2 REENT1 =8024 =8033 RND2 =80CE RND3 =80CC =8008 RNDDT2 =800A SAI =8059 =8060 START =800F TM01S =8158 =815B TM1M =8164 TM1M2 =8167 =8169 USDISP =8039 USDISP1 =8043 =80C2 WIN =80B3 69 プログラム№13 WILD SEVEN(WILD78.BTK) ゲームの説明 №5 SWAPと№11 REVERSEを組み合わせたようなゲームです。 8000番地からRUNするとLEDに1~7の数と1個のブランク(スペース)がばらばらにならんでいます。これをルール にしたがって並べ替えて、1234567□にしてください。 ルールは№5 SWAPとほぼ同じです。スペースの隣にある数はスペースと入れ替えることができます。またスペース の1つ飛んで隣にある数も間の数をジャンプしてスペースと入れ替えることができます。 移動したい数の指定は、表示されているLEDの位置を示す1~8の数を押すことで行われます。1~8の数を押すとそ のLED位置にある数が点滅します。 WRITE INCを押すことで入力が確定します。WRITE INCを押す前ならばLED位置の指定をやり直すことができま す。WRITE INCを押すと指定したLEDにスペースが移動し、スペースがあった所に指定した場所の数が移ります。ス ペースと入れ替えができない位置を指定した場合にはWRITE INCを押しても移動は行われません。 この作業を繰り返して、1234567□(右端がスペース)が完成すると全体が2秒間点滅します。そのあと試行した回 数が2秒間表示されてから、また始めに戻って再びゲームが開始されます。 プログラムの説明 プログラムは№5 SWAPと№11 REVERSEをミックスしたようなものなのでほとんど新たに説明するところはありま せん。REVERSEでは数値の表示を行うのにBCD数に直してLED表示データレジスタに入れて表示させていましたが 今回は1桁ずつセグメントデータに変換して直接LED表示レジスタに入れています。REVERSEの方法ではスペースが 0の表示になってしまうからです。 2016/4/20 END=816F 8000 8003 8004 8005 8006 C30780 00 00 00 00 8007 800A 800D 800E 800F 8010 8012 8014 8017 3AD2FF 210380 77 23 77 3EFF 0608 21F883 77 11:17 wild78.txt ; JUNNARABE for NDZ (WILD SEVEN) ; 03/05/02 5/5 5/14 5/23 5/24 ;10/6/4 for ND80Z3 ;9/17 9/18 ;16/4/20 for nd8080 ; ORG $8000 ; RNDDT=$E810;$E811 ; CNTR=$E812 LED1=$83F8;$FFF8 DP1=$83F4;$FFF4 DP3=$83F6;$FFF6 R=$FFD2 ; DTDPS=$01C0;$05C0 KEYIN1=$0216;$0616 KEYIN2=$0223;$0623 ; JMP START RNDDT:NOP NOP RNDDT2:NOP CNTR:NOP ;data buffer clear START:LDA R LXI H,RNDDT MOV M,A INX H MOV M,A MVI A,FF MVI B,08 LXI H,LED1 DTCLR:MOV M,A 70 8018 23 INX H DJNZ *DTCLR DCR B; JNZ DTCLR; ;space position select CALL RND3 ; ANI 07 LXI H,LED1 ADD L MOV L,A MVI M,00 ;data set MVI B,07 DTST1:CALL RND3 ; ANI 07 ORA A JZ DTST1 ;? LD IX,SEGDT LXI H,SEGDT; MVI D,00 MOV E,A ;? ADD IX,DE DAD D; ; LDA IX+00 MOV A,M; LXI H,LED1 DTST2:MOV C,M INR C JNZ DTST3 MOV M,A ;? DJNZ *DTST1 DCR B; JNZ DTST1; JMP ENTRY DTST3:CMP M JZ DTST1 INR L JNZ DTST2 JMP DTST1 ;GAME START ENTRY:XRA A STA CNTR;DECIMAL COUNTER clear ;key entry(1-8) KEY:CALL KEYIN1S CPI 09 JNC KEY DCR A JM KEY ;LED blink and wait WINC in BLNK0:LXI H,LED1 ADD L MOV L,A MOV A,M ORA A JZ KEY;space position MOV D,A;LED data save MOV B,A MVI C,00 ;? 8019 05 801A C21780 801D CD0A81 8020 8023 8024 8025 21F883 85 6F 3600 8027 0607 8029 CD0A81 802C B7 802D CA2980 8030 216881 8033 1600 8035 5F 8036 19 8037 8038 803B 803C 803D 8040 7E 21F883 4E 0C C24880 77 8041 8042 8045 8048 8049 804C 804D 8050 05 C22980 C35380 BE CA2980 2C C23B80 C32980 8053 AF 8054 320680 8057 805A 805C 805F 8060 CD3D81 FE09 D25780 3D FA5780 8063 8066 8067 8068 8069 806A 806D 806E 806F 21F883 85 6F 7E B7 CA5780 57 47 0E00 71 8071 8072 8075 8078 807A 807D 807E 8081 8082 8085 8087 808A 808B 808C 808D 71 CD4D81 CD4581 FE09 D28580 3D FA8A80 72 C36380 FE15 CA9080 79 48 47 C37180 8090 8091 8092 8094 8097 8098 8099 809A 809D 809E 80A0 80A3 80A4 80A5 80A6 80A9 80AA 80AB 80AC 80AE 80B0 80B3 80B4 80B5 80B6 80B9 80BA 80BC 80BE 80C1 80C2 80C3 80C4 E5 7D E607 CAA980 2B 7E B7 CAC780 7D E607 CAA980 2B 7E B7 CAC780 E1 E5 7D E607 FE07 CA0681 23 7E B7 CAC780 7D E607 FE07 CA0681 23 7E B7 C20681 80C7 80C8 80C9 80CB 80CE 80D0 80D1 72 E1 3600 3A0680 C601 27 320680 BLNK1:MOV M,C CALL TM01S CALL KEYIN2S CPI 09 JNC BLNK2 DCR A JM BLNK3 MOV M,D JMP BLNK0 BLNK2:CPI 15;WRITE INC JZ CHECK BLNK3:MOV A,C MOV C,B MOV B,A JMP BLNK1 ;check CHECK:PUSH H;save keyin position MOV A,L ANI 07 JZ CHECKR;position=LED1 DCX H MOV A,M ORA A JZ REP;left=space MOV A,L ANI 07 JZ CHECKR;left=LED1 DCX H MOV A,M ORA A JZ REP;left of left=space CHECKR:POP H PUSH H MOV A,L ANI 07 CPI 07 JZ CANT;position=LED8,cannot replace INX H MOV A,M ORA A JZ REP;right=space MOV A,L ANI 07 CPI 07 JZ CANT;right=LED8,cannot replace INX H MOV A,M ORA A JNZ CANT;right of right is not space,cannot replace ;replace REP:MOV M,D POP H MVI M,00 LDA CNTR;DECIMAL COUNTER up ADI 01 DAA STA CNTR ;all check 72 80D4 21F883 80D7 0607 80D9 116981 80DC 80DD 80DE 80E1 1A BE C25780 23 80E2 13 80E3 05 80E4 C2DC80 80E7 CD2881 80EA 80ED 80F0 80F3 80F4 80F7 80FA 80FC 210000 22F483 3A0680 67 22F683 CDC001 0614 CD4D81 80FF 05 8100 C2FC80 8103 C30780 8106 E1 8107 C38A80 810A 810B 810C 810F 8110 8111 8113 8114 8117 811A 811B 811C 811E 811F 8122 8125 8126 8127 E5 D5 2A0380 23 7C E603 67 220380 3A0580 57 7E E607 BA CA0C81 320580 D1 E1 C9 8128 812A 812C 812E 060A 3EEF D398 CD4D81 LXI H,LED1 MVI B,07 ;? LD IX,SEGDT1 LXI D,SEGDT1; ALCHK1:;LDA IX+00 LDAX D; CMP M JNZ KEY;not done INX H ;? INC IX INX D; ;? DJNZ *ALCHK1 DCR B; JNZ ALCHK1; ;OK! ALL LED blink CALL ALBLNK ;COUNTER disp LXI H,$0000 SHLD DP1 LDA CNTR MOV H,A SHLD DP3 CALL DTDPS MVI B,14;=20 ,2sec wait WAIT:CALL TM01S ;? DJNZ WAIT DCR B; JNZ WAIT; JMP START ;cannot replace CANT:POP H JMP BLNK3 ; ;ransu RND3:PUSH H PUSH D RND2:LHLD RNDDT INX H MOV A,H ANI 03 MOV H,A SHLD RNDDT LDA RNDDT2 MOV D,A MOV A,M ANI 07 CMP D JZ RND2 STA RNDDT2 POP D POP H RET ; ;LED all blink ALBLNK:MVI B,0A;=10 ALBLNK1:MVI A,EF OUT 98 CALL TM01S 73 8131 3EFF 8133 D398 8135 CD4D81 8138 05 8139 C22A81 813C C9 813D 813E 813F 8142 8143 8144 8145 8146 8147 814A 814B 814C C5 D5 CD1602 D1 C1 C9 C5 D5 CD2302 D1 C1 C9 814D 814E 8150 8153 8154 8157 8158 D5 1E64 CD5981 1D C25081 D1 C9 8159 815A 815C 815E 815F 8162 8163 8166 8167 D5 1607 1E12 1D C25E81 15 C25C81 D1 C9 8168 8169 816A 816B 816C 816D 816E 816F 00 06 5B 4F 66 6D 7D 27 ALBLNK BLNK0 BLNK3 CHECKR DP3 DTST1 ENTRY MVI A,FF OUT 98 CALL TM01S ;? DJNZ *ALBLNK1 DCR B; JNZ ALBLNK1; RET ; ;KEYIN with DE,BC save KEYIN1S:PUSH B PUSH D CALL KEYIN1 POP D POP B RET KEYIN2S:PUSH B PUSH D CALL KEYIN2 POP D POP B RET ; ;0.1sec timer TM01S:PUSH D MVI E,64;=100 TM01S2:CALL TM1M DCR E JNZ TM01S2 POP D RET ; ;1msec timer TM1M:PUSH D;11 MVI D,07; ck=5 (11+7+292*7+10+10)/2.048=2082/2.048=1016 TM1M2:MVI E,12;=18 ck=7 7+15*18+15=292 TM1M3:DCR E;5 JNZ TM1M3;10 DCR D;5 JNZ TM1M2;10 POP D;10 RET;10 ; SEGDT:DB 00;space SEGDT1:DB 06;1 DB 5B;2 DB 4F;3 DB 66;4 DB 6D;5 DB 7D;6 DB 27;7 ; =8128 ALBLNK1 =812A ALCHK1 =80DC =8063 BLNK1 =8071 BLNK2 =8085 =808A CANT =8106 CHECK =8090 =80A9 CNTR =8006 DP1 =83F4 =83F6 DTCLR =8017 DTDPS =01C0 =8029 DTST2 =803B DTST3 =8048 =8053 KEY =8057 KEYIN1 =0216 74 KEYIN1S LED1 RND2 RNDDT2 START TM1M WAIT =813D =83F8 =810C =8005 =8007 =8159 =80FC KEYIN2 R RND3 SEGDT TM01S TM1M2 =0223 =FFD2 =810A =8168 =814D =815C KEYIN2S REP RNDDT SEGDT1 TM01S2 TM1M3 =8145 =80C7 =8003 =8169 =8150 =815E 75 プログラム№14 MOO(MOO8.BTK) ゲームの説明 MOOというのは牛の鳴き声(モー)です。別名BULLS & COWSといって昔イギリスではやったゲームだそうです (「マイコンゲーム21」から。私は知りません)。 コンピュータが乱数を使って4桁の数を隠しています。4桁の数には同じ数は含まれません(5074や3491はありうる が2335などはない)。 8000番地からRUNするとブーと音がしてLEDが----0000という表示になります。ゲームスタートです。コンピ ュータが隠している数を想像して4ケタの数を入力します。WRITE INCを押すことで入力が確定します。WRITE INC を押す前ならば数を入れ直すことができます。 コンピュータは入力された数と隠している数を比較して、同じ数が同じ桁位置にある場合、それを1頭の牡牛(BULL)と 数えます。4桁とも一致したときは牡牛が4頭いることになります。位置は異なるけれど同じ数が含まれている場合、そ れを牝牛(COW)の数で示します。牡牛は”b”、牝牛は”C”の文字を使ってその頭数が、プーという音とともにLEDの左 4桁に表示されます。全く該当しなかった場合には表示はブランクになります。この表示をヒントにしてできるだけ少ない 回数で正解することを競うゲームです。 テクニックとしてわざと同じ数の並びを入力するなどの方法も考えられますが、ルール違反とした方がよいでしょう(プ ログラムでチェックはしていません)。 みごと正解するとピーという音がしてLEDの左4桁がbbbbになり、LED全部が2秒間点滅します。そのあと試行回数 が2秒間表示され、また始めに戻って再びゲームが開始されます。 途中でギブアップするときは”F”キーを押します。LEDの左4桁にコンピュータが隠していた数が表示されます。2秒た つとまた始めに戻って再びゲームが開始されます。 プログラムの説明 4桁の数はBCD数ではなく、4バイトのセグメントデータに変換してデータバッファに格納します。各桁ごとに比較が必 要なのでBCD数では処理に手間がかかります。№13 WILD SEVENと同様、表示にブランク桁が含まれる場合があ るため、表示する場合には直接セグメントに変換して表示する方が楽です。ちょっと意外な気がしますが、数の大小比較 や計算はしないので、最初からセグメントデータに変換しておいても支障はないのです。 変換はCNVTサブルーチンで 行います。 最初に4桁のデータを作成します(;data set)。1桁目に0が来ると4桁の数になりませんから、そのチェックを行ってい ます。Lに00を入れてスタートし、RNDで選んだデータが0のときに、Lをチェックしています。DTBFのトップアドレスの 下位アドレスが00であることを利用したテクニックです。DTST4:でデータを格納したあとINC Lをしていますが、本来 不要な処理です。これを追加することによって、L=00であるのはまだ最初の桁にデータがセットされていない(つまり1 桁目の処理)であることが分かります。 牡牛と牝牛のチェック(COMP:)はちょっと複雑です。牡牛からチェックするのがポイントです。先頭の桁から比較して いって、データが一致したら、LEDに”b”を表示します。このときDTBFのデータのbit7を1にします。次の牝牛のチェッ クで除外するためのマークです。bit7はLED表示ではピリオドになっていて、このプログラムでのデータでは使わないビ ットなのでマークとして利用できます。さらにビット7=1のときその数はマイナスの数として扱われるため、Sフラグの有 無で判別が可能です。Cレジスタを牡牛用のダウンカウンタに使います。C=04でスタートしデータが一致するごとに- 1します。C=00になれば4桁とも一致したことになりゲーム終了です。牡牛のチェックが終ったら、牝牛をチェックします。 牡牛の場合と似ていますが、桁の違いを考慮しないため、DTBFの各桁ごとに、LED5~8のデータと照合します。この ときbit7=1のデータは除外すると同時に、そのマークを取り除きます(bit7=0に戻す)。データが一致するごとにLED に”C”を表示することは牡牛の処理と同じです。 2016/4/20 END=81E0 12:26 moo8.txt ; MOO for NDZ ; 03/05/06 5/15 ;10/6/4 for ND80Z3 ;9/17 ;16/4/20 for nd8080 ; ORG $8000 ; DTBF=$E800 ; DTBF2=$E802 ; RNDDT=$E810;$E811 LED1=$83F8;$FFF8 LED3=$83FA;$FFFA 76 LED5=$83FC;$FFFC LED8=$83FF;$FFFF DP1=$83F4;$FFF4 DP3=$83F6;$FFF6 CNTR=$83F7;$FFF7;=DP4 R=$FFD2 ; DTDPS=$01C0;$05C0 KEYIN1=$0216;$0616 D1=$02DD;4.684msec ; 8000 8003 8004 8005 8006 8007 8008 8009 C30A80 00 00 00 00 00 00 00 800A 800D 8010 8011 8012 8013 8016 8019 3AD2FF 210780 77 23 77 21FFFF 220380 220580 801C 2E00 801E CD2281 8021 8023 8026 8027 802A 802B 802E 8031 8034 8036 8037 803A 803B 803C 803F FE0A D21E80 B7 C22E80 BD CA1E80 CD4081 210380 0604 BE CA1E80 4E 0C CA4480 23 8040 8041 8044 8045 05 C33680 77 2C 8046 05 8047 C21E80 804A 210000 804D 22F683 JMP START DTBF:NOP NOP DTBF2:NOP NOP RNDDT:NOP NOP RNDDT2:NOP ;data set START:LDA R LXI H,RNDDT MOV M,A INX H MOV M,A LXI H,$FFFF SHLD DTBF SHLD DTBF2 ;data set MVI L,00 DTST1:CALL RND4 ; ANI 0F CPI 0A JNC DTST1 ORA A JNZ DTST2 CMP L JZ DTST1;first No. is not "0" DTST2:CALL CNVT LXI H,DTBF MVI B,04 DTST3:CMP M JZ DTST1;already selected No. MOV C,M INR C JZ DTST4;(HL)=FF INX H ;? DJNZ *DTST3;B is never 0 DCR B; JMP DTST3; DTST4:MOV M,A INR L;for first No. check ;? DJNZ *DTST1 DCR B; JNZ DTST1; ;GAME START LXI H,$0000 SHLD DP3;DECIMAL COUNTER clear 77 8050 22F483 8053 8056 8058 805A CD5E81 3E00 0605 CD9381 805D 805E 8061 8064 8066 8069 806B 806E 8071 8074 8075 8076 8077 05 C25A80 CD7D81 FE15 CA8680 FE0F CAF480 D26180 11FC83 62 6B 23 010300 807A 807D 8080 8083 CDD481 CD4081 32FF83 C36180 8086 8089 808B 808C 808F 8092 8095 8098 809B 809C 809F 3AF783 C601 27 32F783 210000 22F883 22FA83 21F883 E3 210380 11FC83 80A2 80A5 80A6 80A7 010404 1A BE C2B880 80AA 80AB 80AD 80AE 80AF 80B2 80B4 E3 367C E3 0D CA0581 F680 77 80B5 80B6 80B7 80B8 80B9 E3 23 E3 23 13 SHLD DP1 ;key entry CALL STDP MVI A,00;buuuu MVI B,05 START1:CALL SOUND ;? DJNZ START1 DCR B; JNZ START1; KEY:CALL KEYIN1S CPI 15;WRITE INC JZ COMP CPI 0F;"F" JZ GIVUP JNC KEY LXI D,LED5 MOV H,D MOV L,E INX H LXI B,$0003 ;? LDIR CALL LDIR; CALL CNVT STA LED8 JMP KEY ;DATA compere ;BULL check COMP:LDA CNTR ADI 01;DECIMAL COUNTER up DAA STA CNTR LXI H,$0000 SHLD LED1 SHLD LED3 LXI H,LED1; XTHL; LXI H,DTBF LXI D,LED5 ;? LD IX,LED1 LXI B,$0404 COMP1:LDAX D CMP M JNZ COMP2 ;? LD (IX+00),7C;b XTHL; MVI M,7C;b XTHL; DCR C JZ OK ORI 80 MOV M,A;B "bull" mark set ;? INC IX XTHL; INX H; XTHL; COMP2:INX H INX D ;? DJNZ *COMP1 78 80BA 05 80BB C2A580 80BE 80C1 80C3 80C5 80C8 80C9 80CA 80CD 80CF 80D0 80D3 80D4 110380 0604 0E04 21FC83 1A B7 F2D380 E67F 12 C3E180 BE C2DC80 80D7 E3 80D8 3639 80DA 80DB 80DC 80DD 80DE 80E1 23 E3 23 0D C2D380 13 80E2 80E3 80E6 80E8 80EA 05 C2C380 3E0A 0605 CD9381 80ED 05 80EE C2EA80 80F1 C36180 80F4 210380 80F7 11F883 80FA 010400 80FD 8100 8102 8105 8107 8109 CDD481 0628 C31881 3E17 060A CD9381 810C 810D 8110 8113 8116 8118 05 C20981 CD4981 CDC001 0614 CD8581 811B 05 811C C21881 811F C30A80 DCR B; JNZ COMP1; ;COW check LXI D,DTBF MVI B,04 COMP3:MVI C,04 LXI H,LED5 LDAX D ORA A JP COMP4 ANI 7F STAX D;"bull" mark JMP COMP6 COMP4:CMP M JNZ COMP5 ;? LD (IX+00),39;C XTHL; MVI M,39;C ;? INC IX INX H; XTHL; COMP5:INX H DCR C JNZ COMP4 COMP6:INX D ;? DJNZ *COMP3 DCR B; JNZ COMP3; MVI A,0A MVI B,05 COMP8:CALL SOUND ;? DJNZ *COMP8 DCR B JNZ COMP8; JMP KEY ;give up GIVUP:LXI H,DTBF LXI D,LED1 LXI B,$0004 ;? LDIR CALL LDIR; MVI B,28;=40 ,4sec JMP WAIT OK:MVI A,17 MVI B,0A OK1:CALL SOUND ;? DJNZ OK1 DCR B; JNZ OK1; CALL ALBLNK CALL DTDPS;COUNTER MVI B,14;=20 ,2sec WAIT:CALL TM01S ;? DJNZ WAIT DCR B; JNZ WAIT; JMP START ; clear wait disp wait 79 8122 8123 8124 8127 8128 8129 812B 812C 812F 8132 8133 8134 8136 8137 813A 813D 813E 813F E5 D5 2A0780 23 7C E603 67 220780 3A0980 57 7E E60F BA CA2481 320980 D1 E1 C9 8140 8143 8144 8146 8147 8148 217381 5F 1600 19 7E C9 8149 814B 814D 814F 8152 8154 8156 060A 3EEF D398 CD8581 3EFF D398 CD8581 8159 05 815A C24B81 815D C9 815E 216B81 8161 11F883 8164 010800 8167 816A 816B 816C 816D 816E 816F 8170 8171 8172 CDD481 C9 40 40 40 40 5C 5C 5C 5C 8173 5C ;ransu RND4:PUSH H PUSH D RND2:LHLD RNDDT INX H MOV A,H ANI 03 MOV H,A SHLD RNDDT LDA RNDDT2 MOV D,A MOV A,M ANI 0F CMP D JZ RND2 STA RNDDT2 POP D POP H RET ; ;from key data to segment data convert CNVT:LXI H,SEGDT MOV E,A MVI D,00 DAD D MOV A,M RET ; ;LED all blink ALBLNK:MVI B,0A;=10 ALBLNK1:MVI A,EF OUT 98 CALL TM01S MVI A,FF OUT 98 CALL TM01S ;? DJNZ *ALBLNK1 DCR B; JNZ ALBLNK1; RET ; ;start data disp STDP:LXI H,STDT LXI D,LED1 LXI B,$0008 ;? LDIR CALL LDIR; RET STDT:DB 40 DB 40 DB 40 DB 40 DB 5C DB 5C DB 5C DB 5C ; SEGDT:DB 5C;0 80 8174 8175 8176 8177 8178 8179 817A 817B 817C 06 5B 4F 66 6D 7D 27 7F 6F 817D 817E 817F 8182 8183 8184 C5 D5 CD1602 D1 C1 C9 8185 8186 8188 8189 818C 818D 818E 8191 8192 D5 1E15 D5 CDDD02 D1 1D C28881 D1 C9 8193 8194 8195 8196 8197 819A 819B 819C 819D 819F 81A0 81A2 81A4 81A5 81A6 81A9 81AA 81AC 81AE 81AF 81B0 81B3 81B4 81B7 81B8 81B9 81BA 81BB F5 E5 D5 C5 21BC81 85 6F 46 1E1A 50 3EFF D398 7F 15 C2A481 50 3EDF D398 7F 15 C2AE81 1D C29F81 C1 D1 E1 F1 C9 DB DB DB DB DB DB DB DB DB 06;1 5B;2 4F;3 66;4 6D;5 7D;6 27;7 7F;8 6F;9 ; ;KEYIN with DE,BC save KEYIN1S:PUSH B PUSH D CALL KEYIN1 POP D POP B RET ; ;0.1sec timer TM01S:PUSH D MVI E,15;=21 TM01S2:PUSH D CALL D1;4.684ms POP D DCR E JNZ TM01S2 POP D RET ; ; SOUND:PUSH PSW PUSH H PUSH D PUSH B LXI H,SNDTBL ADD L MOV L,A MOV B,M MVI E,1A SNDS1:MOV D,B MVI A,FF;SP OUT=H OUT 98 SNDS2:MOV A,A;5--------DCR D;5 | 5+5+10=20 JNZ SNDS2;10---MOV D,B MVI A,DF;sp out=L OUT 98 SNDS3:MOV A,A;5--------DCR D;5 | 5+5+10=20 JNZ SNDS3;10---DCR E JNZ SNDS1 POP B POP D POP H POP PSW RET 20/2=10microsec 20/2=10microsec 81 81BC 81BD 81BE 81BF 81C0 81C1 81C2 81C3 81C4 81C5 81C6 81C7 81C8 81C9 81CA 81CB 81CC 81CD 81CE 81CF 81D0 81D1 81D2 81D3 7F 77 71 6A 5F 59 54 4F 47 43 3F 3B 35 32 2F 2C 25 27 2A 4B 38 64 23 21 81D4 81D5 81D6 81D7 81D8 81D9 81DA 81DB 81DC 81DF 81E0 F5 7E 12 23 13 0B 78 B1 C2D581 F1 C9 ALBLNK CNVT COMP2 COMP5 D1 DTBF DTST1 DTST4 KEYIN1 LDIR2 LED5 OK1 RND4 SEGDT SNDS3 START STDT WAIT ; SOUND TABLE SNDTBL:DB 7F;so4 DB 77;so#4 DB 71;ra4 DB 6A;ra#4 DB 5F;do5 DB 59;do#5 DB 54;re5 DB 4F;re# DB 47;fA5 DB 43;fa#5 DB 3F;so5 DB 3B;so5# DB 35;ra#5 DB 32;si5 DB 2F;do6 DB 2C;do#6 DB 25;mi6 DB 27;re#6 DB 2A;re6 DB 4B;mi5 DB 38;ra5 DB 64;si4 DB 23;fa6 DB 21;fa#6 ; LDIR:PUSH PSW LDIR2:MOV A,M STAX D INX H INX D DCX B MOV A,B ORA C JNZ LDIR2 POP PSW RET ; =8149 ALBLNK1 =8140 COMP =80B8 COMP3 =80DC COMP6 =02DD DP1 =8003 DTBF2 =801E DTST2 =8044 GIVUP =0216 KEYIN1S =81D5 LED1 =83FC LED8 =8109 R =8122 RNDDT =8173 SNDS1 =81AE SNDTBL =800A START1 =816B TM01S =8118 =814B =8086 =80C3 =80E1 =83F4 =8005 =802E =80F4 =817D =83F8 =83FF =FFD2 =8007 =819F =81BC =805A =8185 CNTR COMP1 COMP4 COMP8 DP3 DTDPS DTST3 KEY LDIR LED3 OK RND2 RNDDT2 SNDS2 SOUND STDP TM01S2 =83F7 =80A5 =80D3 =80EA =83F6 =01C0 =8036 =8061 =81D4 =83FA =8105 =8124 =8009 =81A4 =8193 =815E =8188 82 プログラム№15 SWAP2(SWAP28.BTK) ゲームの説明 №5 SWAPを発展させたものです。SWAPがちょっと単純なので新しく作りました。「マイコンゲーム21」にはありま せん。 SWAPと違ってLEDは8桁全部を使います。 8000番地からRUNするとLEDに”8”の下半分と”8”の上半分がランダムに並び(それぞれの数も毎回異なる)、そ れとともにどこかに1桁のブランクが表示されます。 ルールにしたがって表示を移動し、ブランクをはさんで左側に”8”の下半分を集め、右側に”8”の上半分を集めるとゲ ーム終了です。入れ替えに成功すると2秒間表示が点滅し、さらに2秒間試行回数が表示されたあと、最初に戻って再 びゲームが開始されます。 ルールはSWAPと同じです。ブランクの隣の表示はブランクと位置を交代することができます。また隣に異なる表示が あるとき、その表示をはさんでさらにその隣がブランクならば、間の表示を飛び越してブランクと表示位置を交代すること ができます。 入れ替えたいLED位置に対応する数をKEY入力するとその位置のLEDが点滅します。それでよければWRITE INC キーを押します。WRITE INCキーを押す前なら別の数を入れ直して位置の指定を変更することができます。WRITE I NCを押すとルールにしたがって表示とブランクが入れ替わります。ルールに合わない場合には点滅が続きますが入れ 替えは行われません。 プログラムの説明 特に説明しなくても理解できると思います。 2016/4/20 END=8173 8000 8003 8004 8005 C30680 00 00 00 8006 8009 800C 800D 800E 800F 8011 8013 8015 8017 3AD2FF 210380 77 23 77 3EEF D398 3EFF 0608 21F883 13:55 swap28.txt ; SWAP2 for NDZ ; 03/05/03 5/5 5/15 ;10/6/4 for ND80Z3 ;16/4/20 for nd8080 ; ORG $8000 ; RNDDT=$E810;$E811 LED1=$83F8;$FFF8 DP1=$83F4;$FFF4 DP3=$83F6;$FFF6 CNTR=$83F7;$FFF7;=DP4 R=$FFD2 ; DTDPS=$01C0;$05C0 KEYIN1=$0216;$0616 KEYIN2=$0223;$0623 D1=$02DD;4.684msec ; JMP START RNDDT:NOP NOP RNDDT2:NOP ;data buffer clear START:LDA R LXI H,RNDDT MOV M,A INX H MOV M,A MVI A,EF OUT 98 MVI A,FF MVI B,08 LXI H,LED1 83 801A 77 801B 23 801C 05 801D C21A80 8020 CD2381 8023 8026 8027 8028 21F883 85 6F 3600 802A CD2381 802D 802F 8032 8033 FE06 D22A80 3C 47 8034 CD2381 8037 803A 803B 803C 803D 803E 8041 8042 8045 21F883 85 6F 7E B7 CA3480 3C C23480 3663 8047 05 8048 C23480 804B 804E 8050 8051 8052 8055 8056 8059 805B 21F883 0608 7E B7 CA5B80 3C C25B80 365C 23 805C 05 805D C25080 8060 8063 8066 8069 806B 210000 22F683 22F483 3EFF D398 806D 8070 8072 8075 CD5681 FE09 D26D80 3D DTCLR:MOV M,A INX H ;? DJNZ *DTCLR DCR B; JNZ DTCLR; ;space position select CALL RND3 ; ANI 07 LXI H,LED1 ADD L MOV L,A MVI M,00 ;"UP" No. select DTST1:CALL RND3 ; ANI 07 CPI 06 JNC DTST1 INR A;from 1 to 6 select MOV B,A ;"UP" data position select DTST2:CALL RND3 ; ANI 07 LXI H,LED1 ADD L MOV L,A MOV A,M ORA A JZ DTST2;space position INR A JNZ DTST2;already used MVI M,63;"UP" ;? DJNZ *DTST2 DCR B; JNZ DTST2; ;"down" data set LXI H,LED1 MVI B,08 DTST3:MOV A,M ORA A JZ DTST4;space position INR A JNZ DTST4;alredy used MVI M,5C;"DOWN" DTST4:INX H ;? DJNZ *DTST3 DCR B; JNZ DTST3; ; LXI H,$0000 SHLD DP3;DECIMAL COUNTER clear SHLD DP1 MVI A,FF OUT 98 ;key entry KEY:CALL KEYIN1S;1-8 input CPI 09 JNC KEY DCR A 84 8076 FA6D80 8079 807C 807D 807E 807F 8080 8083 8084 8085 8087 8088 808B 808E 8090 8093 8094 8097 8098 809B 809D 80A0 80A1 80A2 80A3 21F883 85 6F 7E B7 CA6D80 57 47 0E00 71 CD6681 CD5E81 FE09 D29B80 3D FAA080 72 C37980 FE15 CAA680 79 48 47 C38780 80A6 80A7 80A8 80AA 80AD 80AE 80AF 80B0 80B3 80B4 80B7 80B8 80BA 80BD 80BE 80BF 80C0 80C3 80C4 80C5 80C6 80C7 80CA 80CB 80CC 80CD 80D0 80D1 80D4 80D5 80D6 7D E5 E607 CAC380 2B 7E B7 CADF80 BA CAC380 7D E607 CAC380 2B 7E B7 CADF80 E1 E5 7D 3C CA1F81 23 7E B7 CADF80 BA CA1F81 7D 3C CA1F81 JM KEY ;LED blink and wait WINC in BLNK0:LXI H,LED1 ADD L MOV L,A MOV A,M ORA A JZ KEY;space position MOV D,A;LED data save MOV B,A MVI C,00 BLNK1:MOV M,C CALL TM01S CALL KEYIN2S;1-8,15 input CPI 09 JNC BLNK2 DCR A JM BLNK3 MOV M,D JMP BLNK0 BLNK2:CPI 15;WRITE INC JZ CHECK BLNK3:MOV A,C MOV C,B MOV B,A JMP BLNK1 ;check CHECK:MOV A,L PUSH H;save HL(current position) ANI 07 JZ CHECKR;current position=LED1 DCX H MOV A,M ORA A JZ REP;left=space CMP D JZ CHECKR;left=same MOV A,L ANI 07 JZ CHECKR;left=LED1 DCX H MOV A,M ORA A JZ REP;left of left=space CHECKR:POP H PUSH H MOV A,L INR A JZ CANT;position=L8,cannot replace INX H MOV A,M ORA A JZ REP;right=space CMP D JZ CANT;right=same,cannot replace MOV A,L INR A JZ CANT;right=L8,cannot replace 85 80D9 80DA 80DB 80DC 23 7E B7 C21F81 80DF 80E0 80E1 80E3 80E6 80E8 80E9 72 E1 3600 3AF783 C601 27 32F783 80EC 80EF 80F1 80F2 80F4 80F7 21F883 0608 7E FE5C C2FC80 23 80F8 80F9 80FC 80FD 8100 8101 8102 8103 8105 8108 05 C2F180 B7 C26D80 23 05 7E FE63 C26D80 23 8109 05 810A C20281 810D 8110 8113 8115 CD4181 CDC001 0614 CD6681 8118 05 8119 C21581 811C C30680 811F E1 8120 C3A080 8123 8124 8125 8128 8129 812A 812C 812D 8130 8133 8134 E5 D5 2A0380 23 7C E603 67 220380 3A0580 57 7E INX H MOV A,M ORA A JNZ CANT;right of right is not space,cannot replace ;replace REP:MOV M,D POP H MVI M,00 LDA CNTR;DECIMAL COUNTER up ADI 01 DAA STA CNTR ;all check LXI H,LED1 MVI B,08 ALCHK1:MOV A,M CPI 5C;"DOWN" JNZ ALCHK2 INX H ;? DJNZ *ALCHK1 DCR B; JNZ ALCHK1; ALCHK2:ORA A JNZ KEY;not success INX H DCR B ALCHK3:MOV A,M CPI 63;"UP" JNZ KEY;not success INX H ;? DJNZ *ALCHK3 DCR B; JNZ ALCHK3; ;OK! ALL LED blink and COUNTER disp CALL ALBLNK CALL DTDPS MVI B,14;=20 ,2sec wait WAIT:CALL TM01S ;? DJNZ WAIT DCR B; JNZ WAIT; JMP START ;cannot replace CANT:POP H JMP BLNK3 ; ;ransu RND3:PUSH H PUSH D RND2:LHLD RNDDT INX H MOV A,H ANI 03 MOV H,A SHLD RNDDT LDA RNDDT2 MOV D,A MOV A,M 86 8135 8137 8138 813B 813E 813F 8140 8141 8143 8145 8147 814A 814C 814E E607 BA CA2581 320580 D1 E1 C9 060A 3EEF D398 CD6681 3EFF D398 CD6681 8151 05 8152 C24381 8155 C9 8156 8157 8158 815B 815C 815D C5 D5 CD1602 D1 C1 C9 815E 815F 8160 8163 8164 8165 C5 D5 CD2302 D1 C1 C9 8166 8167 8169 816A 816D 816E 816F 8172 8173 D5 1E15 D5 CDDD02 D1 1D C26981 D1 C9 ALBLNK ALCHK2 BLNK1 CANT CNTR DP3 DTST1 DTST4 KEYIN1S LED1 RND2 ANI 07 CMP D JZ RND2 STA RNDDT2 POP D POP H RET ; ;LED all blink ALBLNK:MVI B,0A;=10 ALBLNK1:MVI A,EF OUT 98 CALL TM01S MVI A,FF OUT 98 CALL TM01S ;? DJNZ *ALBLNK1 DCR B; JNZ ALBLNK1; RET ; ;KEYIN with DE,BC save KEYIN1S:PUSH B PUSH D CALL KEYIN1 POP D POP B RET ; KEYIN2S:PUSH B PUSH D CALL KEYIN2 POP D POP B RET ; ;0.1sec timer TM01S:PUSH D MVI E,15;=21 TM01S2:PUSH D CALL D1;4.684ms POP D DCR E JNZ TM01S2 POP D RET ; =8141 ALBLNK1 =8143 =80FC ALCHK3 =8102 =8087 BLNK2 =809B =811F CHECK =80A6 =83F7 D1 =02DD =83F6 DTCLR =801A =802A DTST2 =8034 =805B KEY =806D =8156 KEYIN2 =0223 =83F8 R =FFD2 =8125 RND3 =8123 ALCHK1 BLNK0 BLNK3 CHECKR DP1 DTDPS DTST3 KEYIN1 KEYIN2S REP RNDDT =80F1 =8079 =80A0 =80C3 =83F4 =01C0 =8050 =0216 =815E =80DF =8003 87 RNDDT2 TM01S2 =8005 =8169 START WAIT =8006 =8115 TM01S =8166 88 第2部 電子オルゴール 1. 電子オルゴールプログラム MUSIC8.BTKは自動演奏プログラムです。 電子オルガンプログラム SOUND8.BTKはキーを押すことでオルガンのように音を出すプログラムですが、MUSIC 8.BTKはオルゴールのように自動演奏をします。 ⅰ)プログラムの使い方 nd8080フォルダにあるMUSIC8.BTKを、ND8080(ND80Zモニタ)に、HIDWR8コマンドで送信してください。 プログラムは8000番地からスタートしますが、その前に演奏データが必要です。 サンプルとして、演奏データファイルが、nd8080フォルダに入っています。 一度に1曲しか送ることはできません。 下記のうちどれかをHIDWR8コマンドでND8080(TK80モニタモード)に送信してください。 KINJIRA.BTK(速さのパラメータ03) KOKYO.BTK(速さのパラメータ03) NEKO.BTK(速さのパラメータ03) SEIJA.BTK(速さのパラメータ02) SEIYA.BTK(速さのパラメータ04) YOROKOBI.BTK(速さのパラメータ03) SUZANNA.BTK(速さのパラメータ01) ELISE.BTK(速さのパラメータ03) 曲データファイルは8100番地からLOADされます。 8100番地に上書き送信することで、別の曲を演奏させることができます。 曲によっては速さのパラメータ(アドレス8003の値)を書き換える必要があります。プログラムをロードした直後は03 になっています。必要に応じて上の()の値に変更してから、プログラムを実行してください。 プログラムと曲ファイルをLOADしたら、[8][0][0][0][ADRSSET][RUN]と入力すると自動演奏がはじまります。 演奏が終了してもLED表示はアドレス8000を表示したままモニタプログラムに戻りますから、そこでまた[RUN]を押 せば、ふたたび自動演奏がはじまります。 演奏終了後かまたはリセット後に、別の曲ファイルをLOADすると、8100からのメモリエリアが新しい曲データで上書 きされ、別の曲を演奏させることができます。 8000番地からのMUSICプログラムを書き換えてしまわない限りは、自動演奏を繰り返し実行させることができます。 ⅱ)曲データコード 曲データサンプルに限らず、楽譜さえあれば任意の曲データを書いて演奏することができます。データは音の高さのコ ードと長さのコードで構成されます。最初のデータ(偶数アドレス)が音の高さのデータで、後のデータ(奇数アドレス)は 音の長さのデータです。 休符も高さコードの1種として扱います。コード00を使います。 8100番地から、楽譜を見ながら音符データを書き込んでいくことで、任意の曲を演奏させることができます。 曲の最後(偶数アドレス)にはFFを書きます。 [音の長さデータ] 音符 コード 16分音符 01 8分音符 02 付点8分音符 03 4分音符 04 付点4分音符 06 2分音符 08 付点2分音符 0C 全音符 10 休符は高さコードが00で、長さコードは上の音の長さデータ表と同じコードにします。 たとえば4分休符は、0004になります。 89 [音の高さデータ] オクターブ 6 6 6 6 6 6 6 6 6 6 6 6 5 5 5 5 5 5 5 5 5 5 5 5 4 4 4 4 4 音階 シ ラ# ラ ソ# ソ ファ# ファ ミ レ# レ ド# ド シ ラ# ラ ソ# ソ ファ# ファ ミ レ# レ ド# ド シ ラ# ラ ソ# ソ 休符 コード 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00 周波数(参考) 1760Hz 880Hz 440Hz ⅲ)曲の速さ プログラムを簡略にしたため、演奏速度は下の4段階しか選択できません。 4分音符/分 コード 375 01 188 02 94 03 47 04 MUSICプログラムのアドレス8003を書き換えることで、演奏速度を変えることができます。初期値はコード03になって います。 ⅳ)プログラムの説明 データは2バイトで1組です。前の1バイトが音の高さ、後ろの1バイトが音の長さです。高さのデータはSNDTBLを 参照することで、対応する音の高さの周波数データに変換されます。 長さのデータは40ms×8001番地の値を16分音符の長さとしたとき、その長さに対する各音符の長さ比になります。 たとえば8003番地の値が標準の03のとき、40ms×3=120msですから、このときの4分音符の長さは120ms×4 =480msです。これは1分間では60/0.48=125ですから、1分間に4分音符が125回演奏される速さということ になります。 SND1:では8100番地からの曲データを順に読みこみ、音の高さデータがFFなら終りの処理を、00なら休符の処理 を行います。その他の場合には音の出力処理を行いますが、その前にCレジスタと比較しています。Cレジスタには1つ 前の音の高さデータが入っています(初期値は?です。手抜きですが問題はありません)。同じ高さの音が続く場合に切 れ目(約5ms)を入れるためです。 90 音の高さデータはテープルを参照することで、周波数を決定するデータになり、Dレジスタに保持されます。 SNDS1:が音を出力する中心部分です。周波数データDはカウンタCに入れられ、スピーカーにHを出力したあとSN DS2:のループがCレジスタの値だけ繰り返されます。次にスピーカーにLを出力したあと、SNDS3:のループが同じ回 数分繰り返されます。 SNDS2:、SNDS3:のループは1回につき10μsecかかります。 たとえばオクターブ5のラの周波数データはプログラムリストのテーブルデータを見ると、38です。10進数に直すと56 ですから、スピーカーからはH=560μsec、L=560μsecのパルスが出力されることになります。 つまり周期は1120μsecになります。 オクターブ5のラの音の周波数は880Hzですから、その周期は1136μsecです。計算上の周期は本来の周期より 少し短いのですが、データは整数値なので20μsecきざみになることと、ループ以外の部分でも若干の実行時間がか かることから、本来の周期よりも短い値になるようにしているためです。 音階データテーブルも2バイトで構成され、周波数データと繰り返し回数データがペアになっています。 周波数データは1回の周期を決定し、それで音の高さが決まります。しかし1回の周期は音の高さによって異なり、音 が高ければ短く、低ければ長くなってしまいます。 このままでは音の長さが高さによって異なってきてしまいます。そこで周波数データとペアにした2番目のデータによっ て、音の高さが異なっていても、一定の期間、音が出力されるようにしてあります。 オクターブ5のラでは、そのデータは23になっています。10進数に直すと35です。このデータは、プログラムではアド レス8004(REPEAT)に保持され、Eレジスタに入れられてダウンカウントされます。 周期×Eレジスタを計算すると、(1120+10)×35=39550μsecです。 これをオクターブ6のラと比較してみます。 周波数データは1Bなので、10進数の27になります。ですから周期は540μsecです(オクターブ6のラの周波数は1 760Hzですから、本来の周期は568μsecです)。 2番目のデータは47ですから、10進数では71になります。 周期×Eレジスタは、(540+10)×71=39050μsecになります。 高さによって多少の差異はありますが概ね40msecで一定になるようにしてあります。 音符の長さデータは、この40msecの乗数です。Hレジスタに保持され、その値はBレジスタに入れられてダウンカウ ントされます。 たとえば4分音符の長さデータは04ですから、40×4=160msecの長さになります。 これは1分間では60/0.16=375回演奏される長さです。 実際の音の長さは、さらに速さのパラメータ(アドレス8001の値)が乗じられることで決まります。速さのパラメータはL レジスタに入れられてダウンカウントされます。 上で計算した音符の長さ時間は、速さのパラメータが01のときのものです。 速さのパラメータが、02、03、04のときの音符の長さ時間は、上で計算した長さの2倍、3倍、4倍になります。 2016/4/29 END=80D5 8000 8003 8004 8005 8006 8009 800C 800D 800E C30680 03 00 00 210081 3A0580 4F 7E FEFF 11:25 music8.txt ;;; music 09/10/9 10/10 10/12 10/15 ;;; ;16/4/20 for nd8080 ;4/29 ; ORG $8000 ; ; SPEED=$EFFF ; REPEAT=$EFFE ; MAE=$EFFD DATA=$8100 END=$0051;MONITOR START ; JMP START SPEED:DB 03 REPEAT:NOP MAE:NOP START:LXI H,DATA SND1:LDA MAE MOV C,A MOV A,M CPI FF 91 8010 8013 8014 8017 8019 801C 801D 801E 8021 8022 8023 8024 8025 8026 8029 802A 802B 802D 802E 802F 8030 8031 8034 8035 8036 8037 CA5100 B7 CA6380 FE1E D27C80 F5 B9 CC8180 23 46 23 F1 E5 219A80 87 5F 1600 19 56 23 5E 3A0380 6F 60 7B 320480 803A 803B 803D 803F 8040 8041 8044 8045 8047 8049 804A 804B 804E 804F 8052 8055 8056 8057 805A 805B 805C 805F 8060 4A 3EFF D398 7F 0D C23F80 4A 3EDF D398 7F 0D C24980 1D C23A80 3A0480 5F 05 C23A80 44 2D C23A80 E1 C30980 8063 8064 8065 8066 8067 806A 806B 23 46 23 E5 3A0380 6F 60 JZ END ORA A JZ YASUMI CPI 1E JNC ERROR PUSH PSW CMP C CZ T5MS INX H MOV B,M;NAGASA INX H POP PSW PUSH H LXI H,SNDTBL ADD A MOV E,A MVI D,00 DAD D MOV D,M;TAKASA INX H MOV E,M;KURIKAESI KAISU LDA SPEED MOV L,A MOV H,B MOV A,E STA REPEAT ; SNDS1:MOV C,D MVI A,FF;sp out H OUT 98 SNDS2:MOV A,A;5 DCR C;5 JNZ SNDS2;10 MOV C,D MVI A,DF;sp out L OUT 98 SNDS3:MOV A,A;5 DCR C;5 JNZ SNDS3;10 DCR E JNZ SNDS1 LDA REPEAT MOV E,A DCR B JNZ SNDS1 MOV B,H DCR L JNZ SNDS1 POP H JMP SND1 ;;; YASUMI:INX H MOV B,M;NAGASA INX H PUSH H LDA SPEED MOV L,A MOV H,B 92 806C 806F 8070 8073 8074 8075 8078 8079 CD8680 05 C26C80 44 2D C26C80 E1 C30980 807C 23 807D 23 807E C30980 8081 0E05 8083 C38880 8086 8088 808B 808C 808F 0E28 CD9080 0D C28880 C9 8090 8091 8093 8094 8095 8098 8099 F5 3E60 7F 3D C29380 F1 C9 809A 809B 809C 809D 809E 809F 80A0 80A1 80A2 80A3 80A4 80A5 80A6 80A7 80A8 80A9 80AA 80AB 80AC 80AD 80AE 80AF 80B0 80B1 80B2 80B3 80B4 00 00 7F 10 77 11 71 12 6A 13 64 14 5F 15 59 16 54 18 4F 19 4B 1A 47 1C 43 1E 3F YASUMI2:CALL T40MS DCR B JNZ YASUMI2 MOV B,H DCR L JNZ YASUMI2 POP H JMP SND1 ;;; ERROR:INX H INX H JMP SND1 ; T5MS:MVI C,05 JMP T40MS2 ; T40MS:MVI C,28;=40 T40MS2:CALL T1MS DCR C JNZ T40MS2 RET ; T1MS:PUSH PSW MVI A,60;=96 T1MS2:MOV A,A;5 DCR A;5 JNZ T1MS2;10 POP PSW RET ; ; SOUND TABLE SNDTBL:DB 00;DUMMY DB 00;DUMMY DB 7F;so4 DB 10 DB 77;so#4 DB 11 DB 71;ra4 DB 12 DB 6A;ra#4 DB 13 DB 64;si4 DB 14 DB 5F;do5 DB 15 DB 59;do#5 DB 16 DB 54;re5 DB 18 DB 4F;re#5 DB 19 DB 4B;mi5 DB 1A DB 47;fa5 DB 1C DB 43;fa#5 DB 1E DB 3F;so5 93 80B5 80B6 80B7 80B8 80B9 80BA 80BB 80BC 80BD 80BE 80BF 80C0 80C1 80C2 80C3 80C4 80C5 80C6 80C7 80C8 80C9 80CA 80CB 80CC 80CD 80CE 80CF 80D0 80D1 80D2 80D3 80D4 80D5 1F 3B 21 38 23 35 25 32 27 2F 2A 2C 2C 2A 2F 27 32 25 35 23 38 21 3B 1F 3F 1D 43 1B 47 1A 4A 18 50 DATA MAE SNDS1 SNDTBL T1MS T40MS2 YASUMI2 DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB DB ;END =8100 =8005 =803A =809A =8090 =8088 =806C 1F 3B;so#5 21 38;ra5 23 35;ra#5 25 32;si5 27 2F;do6 2A 2C;do#6 2C 2A;re6 2F 27;re#6 32 25;mi6 35 23;fa6 38 21;fa#6 3B 1F;so6 3F; 1D;so#6 43; 1B;ra6 47; 1A;ra#6 4A; 18;si6 50; END REPEAT SNDS2 SPEED T1MS2 T5MS =0051 =8004 =803F =8003 =8093 =8081 ERROR SND1 SNDS3 START T40MS YASUMI =807C =8009 =8049 =8006 =8086 =8063 94 2. 電子オルゴールデータ ①プログラムの8003番地を速度のパラメータの値に変更してください。 ②プログラムは8000番地から実行します。 禁じられた遊び(KINJIRA.BTK) 速度のパラメータ(8003番地の値)=03 8100 0F 04 0F 04 0F 04 0F 04 0D 04 0B 04 8110 08 04 08 04 0B 04 0F 04 14 04 14 04 8120 12 04 10 04 10 04 0F 04 0D 04 0D 04 8130 0F 04 10 04 0F 04 13 04 10 04 0F 04 8140 0B 04 0B 04 0A 04 08 04 0A 04 0A 04 8150 0B 04 0A 04 08 04 08 04 08 04 08 08 8160 0C 04 0C 04 0C 04 0A 04 08 04 08 04 8170 07 04 06 04 07 04 11 04 11 04 11 04 8180 11 04 11 04 0F 04 0F 04 0F 04 11 04 8190 14 04 14 04 14 04 13 04 12 04 11 04 81A0 11 04 0F 04 0D 04 0C 04 0C 04 0C 04 81B0 0A 04 08 10 FF 故郷の廃家(KOKYO.BTK) 速度のパラメータ(8003番地の値)=03 8100 0D 06 0F 02 0D 04 0A 04 12 06 8110 0D 04 0A 04 12 04 0A 04 08 0C 8120 0D 04 0A 04 12 06 14 02 12 04 8130 0A 06 08 02 06 0C 00 04 08 06 8140 0A 06 09 02 0A 04 0D 04 0F 04 8150 08 0C 00 04 0D 06 0F 02 0D 04 8160 12 04 0F 04 0D 04 0A 04 0A 02 8170 0D 06 09 02 0A 04 0D 0C 00 08 8180 0F 02 0D 08 00 08 0D 06 09 02 8190 12 04 0A 04 0A 02 08 06 06 0C 0B 14 0F 0F 0A 00 07 11 13 11 0C 04 04 04 04 04 04 04 04 04 04 04 0A 14 10 0D 0A 0C 07 13 14 11 0D 04 04 04 04 04 04 04 04 04 04 04 14 00 0F 07 0D 0A 08 0D 0A FF 02 04 04 02 04 04 06 04 04 02 12 0D 12 08 0B 12 06 08 0D 0F 04 06 04 04 04 06 0C 04 0C 02 0F 0F 0A 0B 0A 14 00 11 00 0D 04 02 04 04 04 02 04 06 08 02 ねこふんじゃった(NEKO.BTK) 速度のパラメータ(8003番地の値)=03 8100 0F 02 0D 02 06 02 00 02 12 02 00 8110 0F 02 0D 02 06 02 00 02 12 02 00 8120 0F 02 0D 02 06 02 00 02 12 02 00 8130 12 02 00 02 01 04 11 02 00 02 11 8140 0D 02 01 02 00 02 11 02 00 02 11 8150 0D 02 01 02 00 02 11 02 00 02 11 8160 0D 02 01 02 00 02 11 02 00 02 03 8170 00 02 06 02 00 02 12 02 00 02 12 8180 16 02 00 02 12 02 00 02 12 02 00 8190 16 02 00 02 12 02 00 02 12 02 00 81A0 16 02 00 02 12 02 00 02 19 02 00 81B0 1B 04 11 02 00 02 11 02 00 02 0F 81C0 00 02 11 02 00 02 11 02 00 02 0F 81D0 00 02 11 02 00 02 11 02 00 02 0F 81E0 00 02 11 02 00 02 19 02 00 02 11 81F0 12 02 00 02 12 02 00 02 0F 02 0D 8200 12 02 00 02 01 02 00 02 12 02 00 8210 12 02 00 02 01 02 00 02 12 02 00 8220 06 04 07 04 08 04 11 02 00 02 11 8230 0D 02 08 02 00 02 11 02 00 02 01 8240 00 02 08 02 00 02 11 02 00 02 01 8250 00 02 08 04 07 04 08 04 09 04 0A 02 02 02 02 02 02 02 04 02 02 02 02 02 02 02 02 02 02 02 02 02 04 12 12 03 00 00 00 00 0F 0F 0F 12 0D 0D 0D 00 06 06 06 00 00 00 16 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 04 02 02 02 02 00 00 00 0F 0F 0F 11 0D 0D 0D 00 1B 1B 1B 16 00 00 05 0F 11 11 00 02 02 02 02 02 02 02 02 02 02 02 02 02 02 04 02 02 04 02 02 02 02 95 8260 8270 8280 8290 82A0 82B0 82C0 82D0 82E0 82F0 16 12 12 03 00 00 00 00 0D FF 02 02 02 02 02 02 02 02 02 00 00 00 00 0F 0F 0F 11 0C 02 02 02 02 02 02 02 02 02 0F 0F 0F 12 0D 0D 0D 00 0D 02 02 02 02 02 02 02 02 02 0D 0D 0D 00 01 01 01 12 0E 02 02 02 02 02 02 02 02 02 06 06 06 01 00 00 00 00 0F 02 02 02 04 02 02 02 02 02 00 00 00 11 11 11 11 12 10 02 02 02 02 02 02 02 02 02 12 12 12 00 00 00 00 00 11 02 02 02 02 02 02 02 02 02 00 00 00 11 11 11 03 12 12 02 02 02 02 02 02 02 04 04 聖者の行進(SEIJA.BTK) 速度のパラメータ(8003番地の値)=02 8100 0B 04 0F 04 10 04 12 10 00 06 8110 12 10 00 06 0B 02 0F 04 10 04 8120 0F 08 0D 10 00 08 0F 04 0D 04 8130 12 04 12 04 12 04 10 0C 00 06 8140 12 08 0F 08 0B 08 0D 08 0B 10 0B 12 0B 0B FF 02 08 0C 02 0F 0F 0B 0F 04 08 04 04 10 0B 0F 10 04 08 08 04 聖夜(SEIYA.BTK) 速度のパラメータ(8003番地の値)=04 8100 0D 06 0F 02 0D 04 0A 0C 0D 06 8110 14 08 14 04 11 0C 12 08 12 04 8120 12 06 11 02 0F 04 0D 06 0F 02 8130 0F 04 12 06 11 02 0F 04 0D 06 8140 14 08 14 04 17 06 14 02 11 04 8150 0D 02 0A 04 0D 06 0B 02 08 04 0F 0D 0D 0F 12 06 02 0C 04 02 0C 0C 0D 0F 0A 0D 16 FF 04 08 0C 04 0C 0A 0F 0F 0A 12 0C 04 08 0C 06 04 08 04 04 04 04 04 12 14 10 12 12 14 10 04 04 04 04 04 08 04 08 18 08 04 0C 04 04 10 18 08 0A 06 06 08 08 0A 0A 0F 06 06 08 04 0C 04 04 08 08 08 04 0C よろこびのうた(YOROKOBI.BTK) 速度のパラメータ(8003番地の値)=03 8100 14 04 14 04 15 04 17 04 17 04 15 04 14 8110 10 04 10 04 12 04 14 04 14 06 12 02 12 8120 14 04 15 04 17 04 17 04 15 04 14 04 12 8130 10 04 12 04 14 04 12 06 10 02 10 08 12 8140 14 04 10 04 12 04 14 02 15 02 14 04 10 8150 14 02 15 02 14 04 12 04 10 04 12 04 0B 8160 14 04 15 04 17 04 17 04 15 04 14 04 12 8170 10 04 12 04 14 04 12 06 10 02 10 08 FF おおスザンナ(SUZANNA.BTK) 速度のパラメータ(8003番地の値)=01 8100 06 04 08 04 0A 08 0D 08 0D 08 0F 8110 06 0C 08 04 0A 08 0A 08 08 08 06 8120 08 04 0A 08 0D 08 0D 0C 0F 04 0D 8130 08 04 0A 08 0A 08 08 08 08 08 06 8140 0A 08 0D 08 0D 08 0F 08 0D 08 0A 8150 0A 08 0A 08 08 08 06 08 08 18 06 8160 0D 08 0D 08 0F 08 0D 08 0A 08 06 8170 0A 08 08 08 08 08 06 18 00 08 0B 8180 0F 10 0F 08 0D 08 0D 08 0A 08 06 8190 08 04 0A 08 0D 08 0D 08 0F 08 0D 81A0 08 04 0A 08 0A 08 08 08 08 08 06 08 08 08 18 08 04 0C 10 08 08 10 0D 08 0A 06 06 08 08 0B 08 0A FF エリーゼのために(ELISE.BTK) 速度のパラメータ(8003番地の値)=02 8100 16 04 15 04 16 04 15 04 16 04 11 04 14 04 12 04 8110 0F 08 00 04 06 04 0A 04 0F 04 11 08 00 04 0A 04 8120 0E 04 11 04 12 08 00 04 0A 04 16 04 15 04 16 04 96 8130 8140 8150 8160 8170 8180 8190 81A0 81B0 81C0 15 0A 00 14 11 14 00 15 00 11 04 04 04 0C 04 04 04 04 04 04 16 0F 11 0B 00 12 0A 16 06 7A 04 04 04 04 04 04 04 04 04 00 11 11 12 16 16 0F 0E 15 0A 0F 04 08 04 04 04 08 04 04 04 08 14 00 14 14 15 00 11 16 0F FF 04 04 04 04 04 04 04 04 04 12 0A 16 12 16 06 12 11 11 04 04 0C 0C 04 04 08 04 08 0F 12 0D 0A 15 0A 00 14 00 08 04 04 04 04 04 04 04 04 00 11 17 14 16 0F 0A 12 0A 04 04 04 04 04 04 04 04 04 06 0F 16 12 11 11 16 0F 12 97 04 08 04 04 04 08 04 08 04 [memo] 98