3

私はATmega128マイクロコントローラーを使用しており、おそらく2つの16ビット数を追加する必要があります。私はAVRStudioを使用していますが、これは私がこれまでに得たものです。

.include "m128def.inc";

.equ    ramstart = 0x100
.def    temp = r16

.dseg
.org ramstart
number1: .byte 2
number2: .byte 2

.cseg
.org 0

rjmp start

start:
    ; number1 := 0x7856
    ldi temp, low(number1)
    sts number1, temp
    ldi temp, high(number1)
    sts number1+1, temp

    ; number2 := 0x34B2
    lds temp, number1
    sts number2, temp
    lds temp, number1+1
    sts number2+1, temp

slutt:
    rjmp slutt

初めてアセンブリを使用するのはそう遠くないです。何か間違ったことをしていることはわかっていますが、何が起こっているのか理解できないようです。キャリーフラグがありませんか?

4

4 に答える 4

9

鉛筆と紙で小学校に戻ります。1234と5678を追加したい場合

  1234
+ 5678
======

4+8は2キャリー1

    1
  1234
+ 5678
======
     2    

等々

 00110 <-- carry bits
  1234 <-- first operand
+ 5678 <-- second operand
======
  6912

1列の上のキャリービットは重要であり、キャリーインと呼ばれ、左端の列を離れるキャリービットが実行されます。

一度に2列追加するのに十分な幅の用紙しかない場合はどうなりますか?

 110 
  34 
+ 78 
======
  12

下の2桁のセットから始め、キャリーインとしてゼロが必要です。キャリーアウトで結果12が得られます。

今、私はその実行を取り、次の2桁の持ち込みとして使用します。この加算器は、前の加算からキャリーを取得して、この加算のキャリーインとして使用できる必要があります。

 001
  12
+ 56
====
  69

すべてを言い終えると、69と12が得られます。これらを組み合わせると、6912が得られますが、そこに到達するために4桁の全加算器は必要ありませんでした。これを永久に繰り返すことも、メモリ、レジスタ、またはクロックサイクルがなくなるまで繰り返すこともできます。

avrには問題を解決する他の方法があるかもしれませんが、ほとんどのプロセッサーには少なくとも2つの形式の加算と2つの形式の減算があるため、加算器を必要な幅にカスケードできます。avrの命令セットを調べてください。上で起こっていることがあなたに飛び出すはずです。

編集:

ACの例が役立つかもしれません...(16進数への切り替え)

unsigned int a,b,c,d,cin,cout,x,y;

a=0x12; b=0x34;
c=0x56; d=0x78;

x=b+d; //dont want a carry in or assume it is zero
cout=x&0x100; 
if(cout) cin=1; else cin=0;
y=a+c+cin; //need the carry out on the prior add as the carry in here

x&=0xFF;
y&=0xFF;

printf("0x%02X%02X\n",y,x);

EDIT2:

これが宿題ではないことを願っています...

ldi r20,0x12
ldi r21,0x34
ldi r22,0x56
ldi r23,0x78
add r21,r23
adc r20,r22

結果はr20上位バイト、r21下位バイトになります

RAMから読み取る必要がある場合、多くの方法があります。これは、16ビットの数値がリトルエンディアンであると想定しています。

lds r0,0x100
lds r1,0x101
lds r2,0x102
lds r3,0x103
add r0,r2
adc r1,r3

結果のr0下半分、r1上半分。

または、x、y、またはzポインタレジスタの1つを使用します

;put 0x0100 in Z
ldi r30,0x00
ldi r31,0x01
ld r0,z+
ld r1,z+
ld r2,z+
ld r3,z+
add r0,r2
adc r1,r3
于 2012-02-09T21:26:56.917 に答える
1

ええと、あなたは実際には追加命令を出していません。私は決してAVRプログラマーではありませんが、ATmega128の命令セットを一目見ただけで、このようなものの方がはるかに正しいようです。アセンブラがIntel構文を使用し、数値がリトルエンディアンとして格納されていることを前提としています。

lds r16, number1 ; low byte of number1
lds r17, number2 ; low byte of number2
add r16, r17 ; number1 += number2

lds r17, number1+1 ; high byte of number1
lds r18, number2+1 ; high byte of number2
adc r17, r18 ; add the high bytes including the carry flag generated by the "add" instruction above

したがって、結果はに格納されr17:r16ます。たとえば、の上位バイトr17との下位バイトに格納されr16ます。

于 2012-02-09T21:06:54.197 に答える
1

データシートには、addこのリンクがあります。私が上で推測したように、おそらくあなたはあなたの数を得るためにプログラムメモリロード、ldmを使う必要があります。adc

基本的に:



ldi r0, number1 ; get low address of number 1 in a register.
ldm r16, r0+    ; low-byte of number 1 - inc pointer after each read with r0+
ldm r17, r0+    ; high-byte of number 1
ldm r18, r0+    ; low-byte of number 2
ldm r19, r0+    ; high-byte of number 2

add r16, r18    ; add low bytes
adc r17, r19    ; add hi-bytes with carry

; r16/r17 now holds the sum of the number1 and number2 as a 16-bit number.  
; Store to RAM or whatever you want with them.
;  Note, you may have to push/pop registers depending on your system requirements...

上記のコードは機能せず、機能する例があります...

post-increment ldmコマンドでコンテキストを正しく理解していて、すべてのレジスタが8ビットである場合。

于 2012-02-09T21:39:05.700 に答える
0
ldi temp, low(number1)
sts number1, temp
ldi temp, high(number1)

記号「number1」には、そのアドレスの内容ではなく、アドレスの値があります。.ORG RAMSTARTに「number1」を配置したため(おそらく0100 Hex)、low(number1)は00に等しく、high(number1)は01に等しくなります。

アドレス「number1」の内容が必要な場合は、最初にアドレスを16ビットアドレスレジスタに入れる必要があります。たとえば、次のようにしてZレジスタ=(R30、R31)になります。

LDI R30、HIGH(番号1)LDI R31、LOW(番号1)

これで、Zレジスタを使用して、アドレス「number1」のVALUEを次のようにアドレス指定できます。

LD R16、Z + LD R17.Z

これで、R16、R17に16ビット値があります。「number2」についても同じことを行う必要があります。

LDI R30、HIGH(番号2)LDI R31、LOW(番号2)LD R18、Z + LD R19.Z

これで、R18の2番目の16ビット番号R19ができました。

次に、LSBからMSBへのキャリーとともにそれらを追加します

ADD R19、R17;LSBの最初のADCR18、R16を追加します;次にキャリービットでMSBを追加します

答えは今R18、R19にあります

結論:AVRには、非常に粗雑で非効率的な命令セットがあります。ただし、8051に比べて1つの利点があります。つまり、スタックはRAM内のどこにでも配置できるため、それぞれが独自のスタックを持つ複数のプロセスを実行できます。しかし、一般的に、すべてのハーバードアーキテクチャプロセッサは、フォンノイマンアーキテクチャと比較してSUCKです。神にお願いします。誰かが8085またはZ80をベースに、オンチップRAMとFLASHを備えたマイクロコントローラーを作成し、すべてのピンをI/Oポートとして使用できるようにしました。

于 2012-12-07T06:53:43.880 に答える