2012-02-09 3 views
3

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

.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 

Это не далеко не в первый раз я использую любой тип сборки, я знаю, что я делаю что-то неправильно, но может Кажется, что-то выяснить. Я пропускаю флаг переноса?

+0

Это домашнее задание? Если это так, пометьте его как таковой. да, сначала вам нужно загрузить некоторые регистры, тогда вам нужно добавить их все или вычесть. Вы можете всегда возвращаться к добавлению/adc или sub/sbc для выполнения большого количества бит/байтов добавлений или вычитаний. –

+0

Если я использую add или adc, как правильно сохранить результат? –

ответ

8

Назад к gradeschool с карандашом и бумагой. Если я хочу, чтобы добавить 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, и то, что происходит выше, должно выскочить на вас.

EDIT:

A C пример может помочь ... (переключение проклясть)

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.

или использовать один из х, у, или г регистров указателей

;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 
+0

Спасибо за это сообщение. Обертывание вокруг меня только сейчас. –

1

Ну, вы действительно не выпускаете никаких инструкций по добавлению. Я вообще не программист 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

Хм, не работал. Я только закончил с 0xFF в трех регистрах. Как будто это максимизировано или что-то в этом роде? –

+0

Спецификация инструкции LDS говорит, что она работает правильно только с регистрами с 16 по 31. Я отредактировал свое сообщение соответственно. –

+0

Вместо использования lds, а как насчет ldm? Не уверен, где в RAM RAM запускается выделение, но оно может быть в «программной памяти», учитывая, что вы размещаете свои номера и код в одной области. Я думаю, именно поэтому вы получаете 0xFF - SRAM не инициализируется или не существует. –

1

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

В основном:



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

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

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

+0

Хмм .. где вы загружаете номер2? И ldm, я полагаю, вы имеете в виду ldi? –

+0

Загрузите адрес немедленно в r0. Загрузить программный режим с r0 на r16, r17, r18, r19. Поэтому я имел в виду инструкцию ldm. Я смущен, как получить значения из ОЗУ, но через регистры, поскольку они всего лишь 8 бит. –

+0

А, X/Y/Z регистрирует ala Z80 дней. Виноват. –

0
ldi temp, low(number1) 
sts number1, temp 
ldi temp, high(number1) 

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

Если вы хотите, содержимое адреса "номер1", вы должны сначала получить адрес в 16-битного адресного регистра, например, Z регистр = (R30, R31) по следующему

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

Теперь регистр Z может использоваться для адресации VALUE по адресу «номер1»:

LD R16, Z + LD R17.Z

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

LDI R30, HIGH (number2) LDI R31, LOW (number2) LD R18, Z + LD R19.Z

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

Теперь вы сложите их вместе с переносом от LSB к MSB

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

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

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

Смежные вопросы