- 締切済み
アセンブラの初歩
独習アセンブラという本で1+5をするコードが最初のほうに載っています。http://d.hatena.ne.jp/mir/searchdiary?word=*%5BAssembler%5D (ブログにコードを載せている方がいるので、貼ります↑) ブログを書いている方もおっしゃっていますが、これはASCIIコードの演算なので、例えば、5+9+6+3とかいう演算をしようとしても正しい結果が表示されません。5+9+6+3をやって画面に表示させたい場合どういったコードを書けばいいのでしょうか?サンプルを示してもらえるとありがたいです。
- みんなの回答 (6)
- 専門家の回答
みんなの回答
- haruh3
- ベストアンサー率65% (31/47)
サンプルを書いているうちに他の方からも沢山コメントがついていますね。 でも折角書いたので載せておきます。 基本的に数値計算のプログラムを作成する場合、 1. バイナリ(2進数)で計算をして結果を得る. 2. 得られた結果を10進数で表示する. と、計算と表示とを順次分けて処理します。 理解を容易にするために、冗長なプログラムです。 また書いただけでアセンブルしていないのでもしかすると間違いがないとは言えません。(^^;) --- ; 数値計算して dxレジスタに格納 mov dx,5 ; dx=5 add dx,9 ; dx=dx+9 add dx,6 ; dx=dx+6 add dx,3 ; dx=dx+3 ; dxレジスタにある数値を10進数で表示 mov ax,dx mov dx,0 ; dx:axの上位16bitを初期化 mov bx,10000 ; 10000で割る div bx ; ax=商,dx=剰余 call disp_char ; alの値を文字で表示 mov ax,dx mov dx,0 ; dx:axの上位16bitを初期化 mov bx,1000 ; 1000で割る div bx ; ax=商,dx=剰余 call disp_char ; alの値を文字で表示 mov ax,dx mov dx,0 ; dx:axの上位16bitを初期化 mov bx,100 ; 100で割る div bx ; ax=商,dx=剰余 call disp_char ; alの値を文字で表示 mov ax,dx mov dx,0 ; dx:axの上位16bitを初期化 mov bx,10 ; 10で割る div bx ; ax=商,dx=剰余 call disp_char ; alの値を文字で表示 mov al,dl ; 1の位 call disp_char ; alの値を文字で表示 mov ah, 4Ch ; プログラム終了 mov al, 0 int 21h ; DOS call ; alの値を文字で表示するためのサブルーチン disp_char: push ax push dx mov dl,al ; 0-9までの数値 add dl,30h ; + '0' mov ah,02h ; 1文字表示 int 21h ; DOS call pop dx pop ax ret --- このプログラムは例えば100という数値を"00100"と表示します。 これを"100"と表示できるように改造してみてください。 初めて商が0でなくなるまで表示をskipするとできますよ。
- R32C
- ベストアンサー率39% (115/290)
例示しろということですので、とりあえず、マイコンが違ってもそうたいした問題 じゃないと思っていますのでM16Cで例示しますと以下のとおりです。 stdio.h のprintfを使っていますが、全部アセンブラじゃないと気がすまないという のでしたら、HEWのCのソースもあるので、 -S でコンパイルして、アセンブリ言語にすればよいかと思います。 また、printf相当のC言語のソースで比較的見やすいものとして、 TOPPERS/JSPのjsp\liblary\log_output.c というものがあり、 これを参考にされてもよいかと思います。 ソース (mainプログラム Cで書いて コンパイラ出力を手で直したもの) ------------------------------------------------------------------------------ ;src,distがINTELのものとは右左逆です。 ; .GLB __SB__ .SB __SB__ .FB 0 ;## # FUNCTION addsub .SECTION program,CODE,align .align .glb $addsub $addsub: ADD.W R1,R0 RTS ;## # FUNCTION main .align .glb _main _main: ; enter #02H ;## # C_SRC : value = addsub(5,9); mov.w #0009H,R0 mov.w #0005H,R1 jsr $addsub mov.w R0,R2 ;## # C_SRC : value = addsub(value,6); mov.w #0006H,R0 mov.w R2,R1 ; value jsr $addsub mov.w R0,R2 ; value ;## # C_SRC : value = addsub(value,3); mov.w #0003H,R0 mov.w R2,R1 ; value jsr $addsub mov.w R0,R2 ; value ;## # C_SRC : printf("5+9+6+3 = %d\n",value); push.w R2 ; value push.w #___T0>>16 push.w #(___T0&0FFFFH) jsr _printf add.b #06H,SP ;## # C_SRC : } ; exitd RTS E2: .glb __iob .glb _getc .glb _getchar .glb $putc .glb $putchar .glb _feof .glb _ferror .glb _fgetc .glb $fgets .glb $fputc .glb _fputs .glb _fread .glb _fwrite .glb _gets .glb _puts .glb $ungetc .glb _printf .glb _fprintf .glb _sprintf .glb $vprintf .glb _vfprintf .glb _vsprintf .glb _fscanf .glb _scanf .glb _sscanf .glb _fflush .glb _clearerr .glb _perror .glb $init_dev .glb $speed .glb _init_prn .glb __sget .glb $_sput .glb $_pput .glb __print ;## # Common Objects --- begin --- ;## # Common Objects --- end --- .SECTION rom_FO,ROMDATA ___T0: .byte 35H ; '5' .byte 2bH ; '+' .byte 39H ; '9' .byte 2bH ; '+' .byte 36H ; '6' .byte 2bH ; '+' .byte 33H ; '3' .byte 20H ; ' ' .byte 3dH ; '=' .byte 20H ; ' ' .byte 25H ; '%' .byte 64H ; 'd' .byte 0aH .byte 00H .END ;## Compile End Time Sun Jul 23 18:10:28 2006 出力ログ (HEWシミュレータ出力) ----------------------------------------------------------------------------- 5+9+6+3 = 23
お礼
回答ありがとうございます。 -Sは試してみたんです・・・が出てきたものが分けが分からなくて、 ここで質問させてもらいました。 まだまだ分からない事だらけです・・・
- shiojiri
- ベストアンサー率43% (84/192)
レジスタALに入っている16進数の値を10進数にして、 100の桁をCLレジスタ、 10の桁をAHレジスタ、 1の桁をALレジスタ、に代入する。 MOV AL,DL //計算結果をALへ MOV CL,00H //CLをクリア LP1: CMP AL,100 JB JP1 //ALが100より小さいとJP1へジャンプ SUB AL,100 INC CL //ALから100引けなくなるまで引いたカウント JMP LP1 JP1: MOV AH,00H //CLをクリア LP2: CMP AL,10 JB JP2 //ALが10より小さいとJP2へジャンプ SUB AL,10 INC AH //ALから100引けなくなるまで引いたカウント JMP LP2 JP2: PUSH AL //INT21Hを実行してレジスタの値が破壊される為スタックへ退避 PUSH AH MOV DL,CL //100の位を表示 ADD DL.30H MOV AH,02H INT 21H POP DL //10の位を表示 ADD DL.30H MOV AH,02H INT 21H POP DL //1の位を表示 ADD DL.30H MOV AH,02H INT 21H この場合答えが23なら”023”と表示されます。
お礼
回答ありがとうございます。 具体例を示してもらえてうれしいです。 ここまでコードが長くなるんですね。 じっくり勉強します。
- zap35
- ベストアンサー率44% (1383/3079)
5+9+6+3の答えは10進数なら23ですが、レジスタ上は16進数なので0x17になります。 画面表示は23という10進数で表示したいのであれば、条件判定文などと組み合わせて、0x17から10の位の2と1の位の3を別々のレジスタに取り出す必要があります。そして0x30を加えて0x32、0x33とすればはじめて「23」という文字として表示されることになります。 アセンブリ言語の仕様やシステムルーチンの有無が分からないので、そのサンプルまでは書くことはできないですね。すみません。
お礼
回答ありがとうございます。 大変、参考になりました。 まだまだアセンブリ言語について分からないので、質問の仕方も曖昧になってすみません。
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
1+5 は、そのまま計算すればいいです。 一桁の数字を1桁の文字にするために0x30を足します。 1+0x35 をしているのは、それをまとめてやっていることに相当します。 5+9+6+3の場合は、そのまま計算をして、 10進数に変換して、それぞれの桁を0x30して表示していくことになると思います。
お礼
回答ありがとうございます。 考え方を示してもらえて助かります。 ただ、それをやるには、まだまだ勉強が 必要だと感じました・・・
- ymmasayan
- ベストアンサー率30% (2593/8599)
> ブログを書いている方もおっしゃっていますが、これはASCIIコードの演算なので、 move dl,1 add dl,5 ここまでは2進数の計算です。 次の add dl,0X30 で2進数をASCIIに変換しています。 このやり方は結果が9までしか通用しません。 5+9+6+3なら move dl,5 add dl,9 add dl,6 add dl,3 のあと(結果の23を)2桁に分けて2と3をとりだし それぞれをadd 0X30でASCIIに変換することになります。 結構面倒くさいですよ。
お礼
回答ありがとうございます。 そうなんです。9までしか通用しないので悩んでいました。 やはり、桁を分けて表示という事ですか。 難しいですね・・・
お礼
具体例、本当にありがとうございます。 大変助かりました。 じっくりと、読んでいきます。