- 締切済み
ワンボードマイコン Z80
ワンボードマイコンMP-Z80のプログラムを勉強しているのですが、 次の二つの問題がわかりません。 1)8100(H)番地~813F(H)番地に格納されているデータを 8200(H)番地以降にコピーせよ。 2)8100(H)番地から810F(H)番地に格納されているデータを8ビットの 符号付絶対値表現とみなしたとき、各データを2の補数表現に変換し、 8200(H)番地から格納せよ。 1)は LD HL,8100 LD DE,8200 LD A,40H LD BC,A LDI LDIR HALT でいいのでしょうか。2)はまったくわかりません。 お願いします。
- みんなの回答 (8)
- 専門家の回答
みんなの回答
- dummyplug
- ベストアンサー率58% (134/230)
回答者の方は今までのやりとりでもうほとんど解を得ていると思うのですが、なんか楽しそうなので一言。 nda23さんのCPI命令の使い方はシブいですね。私もZ80は30年選手ですが初めて見たかも。 私ならここは LD HL,8100H LD DE,8200H LD B,16 LOOP: LD A,(HL) ; ここで符号付き絶対値から2の補数表現に変換(後述) LD (DE),A INC HL INC DE DJNZ LOOP HALT とします。INC HL, INC DEで(オリジナルZ80なら)6クロック×2、DJNZは14クロック(13かも)で合計26(25)クロック、CPIとJP PEの組み合わせだと16+10で同じく26クロックですがDJNZを使うのだとCレジスタが空きます。データ量が256バイト以内と少ないならこちらのほうが素直かと思いました。 符号付き絶対値から2の補数表現への変換ですけれど、これはTacosanさんのが良さそうですね。 あるいは、ちゃんと考えてないのでしくじっているかもしれませんがこんな方法ではどうですか。 符号付き絶対値というのは、ある値の2の補数表現をAとして A (A=0~127) 128-A (A=-0~-127) ですから、(HL)に符号付き絶対値が入っているとして LD A,(HL) RLCA SBC A,A ; (HL)が正だったとき0, 負だったとき255(0FFH)が入る LD C,A AND 7FH ; (HL)が正だったとき0、負だったとき127(7FH) ADD A,(HL) ; (HL)が正だったとき(HL)、負だったとき(HL)+127 XOR C ; (HL)が正だったとき(HL)、負だったとき255-((HL)+127) = 128-(HL) というコードはどうでしょう。オリジナルZ80で37クロック、8バイト、分岐なしです。レジスタを一個使いますし、速くもないからイマイチですか。 もう一ひねりできるとマシなコードになりそうですけれど。 (Tacosanさんのは値が正の時27クロックで済みますし、負の時でも37クロックで8バイトですね。LD A,(HL)のところから数えて。)
- nda23
- ベストアンサー率54% (777/1415)
>JP NZ,LOOP ;BC≠0ならLOOPへ分岐 >ではだめでしょうか ダメです。 CPIは INC HL、INC、DEC BC とすべきところを横着して、1命令で やっているのです。比較結果を云々するためではありません。 最後の DEC BC の結果、BC=0だとP/VがEvenになり、そうでなければOddになります。 それを条件に分岐するのです。命令(ニモニック)の意味が書かれている参考書をお持ちでしょ? そういうの無しで、プログラムできませんし、勉強にもなりませんよ。
- Tacosan
- ベストアンサー率23% (3656/15482)
A に符号付き絶対値表現が入っているとして, これを 2の補数に直すなら BIT 7, A JR Z, isPositive NEG XOR A, 80H isPositive: になる... のかな? フラグ変化が今一つわからん....
- nda23
- ベストアンサー率54% (777/1415)
(1)LDIRの動作は知っているんでしょ? だったら、正直にやればいいと思うんですけど。 LD HL,8100H ;HL←8100H 転送元データのアドレス LD DE,8200H ;DE←8200H 転送先データのアドレス LD BC,0040H ;BC←0040H 転送バイト数 LDIR ;(DE++)←(HL++)×BCが示す回数 (2)少しひねった問題だけど、同じでしょう。 LD HL,8100H LD DE,8200H LD BC,0010H LOOP: LD A,(HL) ;A←(HL) HLの示すアドレスからAに代入 NEG ;A←Aの「2の補数」 LD (DE),A ;(DE)←A DEの示すアドレスへAを格納 CPI ;HL++,DE++,BC-- JP PE,LOOP ;BC≠0ならLOOPへ分岐 間接アドレス指定が理解できないと苦労します。というか、ここが コンピュータプログラムのセンスなんですが、これは勉強しても なかなか身に着かない。(だから個人的センスなんですが…) もし、どうしようもなく理解できない時は、アドレス感覚の無い 言語(Java、Basic、COBOL等)を勉強すべきです。 私の30年以上の経験から言いますと、世にSEですと威張っている人で 間接アドレス指定の何たるかが分かっている人は3割くらいです。
- php504
- ベストアンサー率42% (926/2160)
(1) LD HL, 8100H LD DE, 8200H LD BC, 0040H LDIR (2) LD HL, 8100H ; src LD DE, 8200H ; dst LD B, 10H ; counter LD C, FFH ; ビット反転用 LOOP: LD A, (HL) ; srcから XOR C ; ビット反転して1加えると2の補数 INC A LD (DE), A ; dstへ INC HL INC DE DJNZ LOOP ; Bレジスタの数だけ繰り返し でいいと思います。 確認できる環境がないので未検証ですが。
お礼
回答ありがとうございます。
- Tacosan
- ベストアンサー率23% (3656/15482)
BC と (BC) では意味が全く違います. 今は「BC レジスタの内容」なので (BC) はますますダメです. で, なんですが.... BC に 40H を入れたいのに, A を使う必要があるんでしょうか?
お礼
BCに0040という16ビットの値を直接入れればいいのでしょうか?
2の補数というのは、例えばどんなときに使うかという一例をあげますと・・・ 引き算命令がないような小規模マイコン減算をするときや、マイコン無しで減算器を作ったりするときは・・・ 引く数を2の補数にして、引かれる数に加算する。 とか、します。 論理演算の否定論理とか分かりますか? 論理演算とか2の補数の解説は、電子技術の文部検定教科書なんかにも書いてあります。
- Tacosan
- ベストアンサー率23% (3656/15482)
1) LD BC, A なんてことはできません (レジスタの大きさが異なっているので). あと, LDI してから LDIR をする意味がわからん. 2) 「符号付き絶対値表現」とか「2の補数表現」でどのように数値を表すかは理解できてますか?
お礼
1)は LD HL,8100 LD DE,8200 LD A,40H LD (BC),A LDIR HALT でいいのですか?
お礼
回答ありがとうございます。 最後の JP PE,LOOP ;BC≠0ならLOOPへ分岐 は JP NZ,LOOP ;BC≠0ならLOOPへ分岐 ではだめでしょうか?