ATmega128: сложение и вычитание 16-битных чисел (сборка) - PullRequest
3 голосов
/ 10 февраля 2012

Я работаю с микроконтроллером ATmega128 и, возможно, мне нужно добавить два 16-битных числа.Я использую AVR Studio, и это то, что я получил до сих пор:

.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 ]

8 голосов
/ 10 февраля 2012

Вернуться в начальную школу с карандашом и бумагой.Если я хочу добавить 1234 и 5678

  1234
+ 5678
======

4 + 8 - это 2 переноса, то 1

    1
  1234
+ 5678
======
     2    

и так далее

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

бит переноса вышестолбец с единицами является значимым, он называется переносом, и бит переноса, который покидает крайний левый столбец, выполняется.

Что если бы у меня была только бумага, достаточная для добавления двух столбцов одновременно?

 110 
  34 
+ 78 
======
  12

Я начинаю с двух нижних наборов цифр, и мне требуется ноль в качестве переноса. Я получаю результат 12 с переносом.

Теперь я беру это выполнение,используйте его для переноса следующих двух цифр.Этот сумматор, я должен быть в состоянии взять вынос из предыдущего добавления и использовать его в качестве переноса для этого добавления.

 001
  12
+ 56
====
  69

Когда все сказано и сделано, я получаю 69 и 12, сложите их вместеЯ получил 6912, но мне не нужен был полный 4-значный сумматор, чтобы добраться туда.Вы можете повторять это вечно или до тех пор, пока не закончится память, регистры или тактовые циклы.

У avr могут быть другие способы решения проблемы, но большинство процессоров по крайней мере имеют две формы сложения и две формы вычитаниятак что вы можете каскадировать сумматор так, чтобы он был настолько широким, насколько вам нужно.Изучите набор инструкций для avr, и то, что происходит выше, должно выскочить у вас.

РЕДАКТИРОВАТЬ:

Пример переменного тока может помочь ... (переключение в шестнадцатеричный формат)

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

, есливам нужно читать из оперативной памяти, есть много способов, это предполагает, что 16-битные числа имеют младший порядок

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

r0 младшая половина результата, верхняя половина r1.

или используйте один изрегистры указателя x, y или z

;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
1 голос
/ 10 февраля 2012

Ваша таблица данных имеет add и adc с этой ссылкой. Как я уже догадался выше, возможно, вам нужно использовать загрузку памяти программ, ldm, чтобы получить ваши номера.

В основном:


<strike>
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...
</strike>

Выше код не будет работать, и есть рабочий пример ...

Если я правильно понимаю контекст с помощью команды ldm post-increment и все регистры 8-битные.

1 голос
/ 10 февраля 2012

Ну, вы на самом деле не выдаете никаких дополнительных инструкций. Я не программист AVR в любом случае, но после быстрого взгляда на набор инструкций ATmega128, что-то вроде этого кажется гораздо более правильным. Я предполагаю, что ваш ассемблер использует синтаксис Intel и числа хранятся как Little Endian.

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.

0 голосов
/ 07 декабря 2012
ldi temp, low(number1)
sts number1, temp
ldi temp, high(number1)

Символ «номер1» имеет значение адреса, а не содержимое этого адреса. Так как вы поместили «номер1» в .ORG RAMSTART, который, вероятно, является 0100 Hex, то low (число1) равно 00, а high (число1) равно 01

Если вы хотите СОДЕРЖАНИЕ адреса "номер1", вы должны сначала получить адрес в 16-битный адресный регистр, например Z-регистр = (R30, R31) следующим образом

LDI R30, ВЫСОКИЙ (номер1) LDI R31, LOW (число 1)

Теперь Z-регистр можно использовать для адресации ЗНАЧЕНИЯ в адресе «номер1»:

LD R16, Z + LD R17.Z

Теперь у вас есть 16-битное значение в R16, R17 Теперь вы должны сделать то же самое для "number2"

LDI R30, ВЫСОКИЙ (номер2) LDI R31, LOW (номер2) LD R18, Z + LD R19.Z

Теперь у вас есть второе 16-битное число в R18, R19

Теперь вы добавляете их вместе с переносом из LSB в MSB

ADD R19, R17; сначала добавьте LSB АЦП R18, R16, затем добавьте MSB с битом переноса

Ответ теперь в R18, R19

Вывод: AVR имеет действительно грубый, неэффективный набор команд. Однако у него есть одно преимущество перед 8051: стек может находиться в любом месте ОЗУ, что позволяет запускать несколько процессов, каждый из которых имеет свои собственные стеки. Но в целом все процессоры гарвардской архитектуры SUCK сравнимы с архитектурами фон Неймана. Если только, пожалуйста, Боже, я хочу, чтобы кто-то сделал микроконтроллер на базе 8085 или Z80, с встроенной памятью и флэш-памятью, оставив все контакты свободными для портов ввода / вывода!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...