LusoRobótica - Robótica em Português
Software => Assembly => Tópico iniciado por: rglove em 04 de Abril de 2014, 16:41
-
Boas,
Há pouco tempo atrás comecei a aprender assembly. Tenho estado a ler o instruction set e a experimentar diversas instruções, mas as instruções de salto relativo não são executadas da forma como está escrito no instruction set. O microcontrolador que estou a programar é o atmega328p.
Se colocar a seguinte instrução:
RJMP 2
Era de esperar que PC <- PC + 1 + 2 segundo o que está no instruction set. O que acontece na realidade é que PC <- 2. Alguém me sabe explicar o porquê disto? Tentei procurar na datasheet algo relacionado com isto, mas não descobri... No instruction set também não descobri...
-
Já não programo em assembly há tempos, e acho que nunca programei AVR, mas para jumps é normal utilizar-se labels ("LABEL:"- o nome com dois pontos no fim), o assemblador sabe interpretá-las. Utilizam-se para jumps e calls.
Senão tens de andar a fazer contas de quantos bytes ocupa cada instrução para que o salto acerte no destino.
Edit:
Como está no exemplo do instruction set do AVR (http://www.atmel.com/images/doc0856.pdf (http://www.atmel.com/images/doc0856.pdf))
Example:
cpi r16,$42 ; Compare r16 to $42
brne error ; Branch if r16 <> $42
rjmp ok ; Unconditional branch
error: add r16,r17 ; Add r17 to r16
inc r16 ; Increment r16
ok: nop ; Destination for rjmp (do nothing)
Edit 2:
O que deve estar a acontecer é o assemblador estar a considerar o "2" como um endereço absoluto (o comportamento que se pretende mais habitualmente), em vez do comprimento do salto. Vê o código em hexadecimal gerado para confirmar.
-
Não me punha a contar os ciclos das instruções (PC), isso dá uma dor de cabeça além de não ter grande utilidade.
Como o jm_araujo referiu este "2" seria um label tendo de ser colocado "2:" para assumir o salto, não creio que vá reconhecer como um endereço.
O rjmp é até 2k(words)=4kB e são 2 ciclos
O jmp é para maiores distâncias do programa e são 3 ciclos.
O código começo sempre por :
.include "m8def.inc"
;a memória de $60 até $FF é utilizada para variaveis
.def lpmreg = r00 ;leitura da memória flash
.def "Nomes associados aos registos de r4 a r25" exe:
.def Temp = r19
;X=R27,R26 Y=R29,R28 Z=R31,R30
.cseg
.org 0
Também não programo assembler faz tempo, porque será :P, os micro-controladores são baratos, rápidos e têm bastante memória, de qualquer forma tem o seu interesse, o último programa que fiz em assembler foi para um cubo de leds com o atmega8 e 814 linhas de código, é um pouco difícil de entender ao começar mas passado umas horas já estamos confortáveis; por isso ver um problema que surja agora é quase como começar do início, abusar nos comentários!!! ;)
-
http://www.avrbeginners.net/ (http://www.avrbeginners.net/)
Secção assembly, tens lá muita informação.
Dropes, mesmo assim não estás a tratar da stack, por acaso maior parte dos avr's mete o SP com o devido valor para o correcto funcionamento, mas não se deve esperar isso de todos os micros.
-
Bem visto,
costumo ligar a isso quanto é em programação de alto nível, em assembler também convém estar bem definido para que não ocorram atropelamentos na memória...
Existe no ficheiro "m8def.inc" essa informação mas por comodidade alterei os valores:
;Posição inferior da memória
ldi temp,$00
out sph,temp
ldi temp,$FF
out spl,temp
-
Obrigado pelas respostas.
jm_araujo, eu sei que é possível o uso das labels, mas para o salto de uma instrução ou duas repetidamente fica "feio" e um bocado confuso ter tantas labels, isto na minha opinião.
dropes, ainda estou muito fresquinho no que diz respeito a assembly. Ainda estou só a experimentar, daí ter surgido esta dúvida, porque o instruction set não está de acordo com o que acontece realmente. Contar o PC não é assim tão difícil, os casos em que pretendia usar isto eram simples e onde o PC incrementava só 1 por instrução... Vou experimentar ver a instrução guardada na memória flash para ver se está de acordo com o instruction set.
senso, obrigado pela partilha do link.
Consegui usar na mesma como pretendia, mas tive que usar da seguinte forma:
RJMP PC + 3
-
Tipicamente quando queres saltar uma instrução usas os branchs(a base dos if's).
-
Sim, é exatamente para situações dessas (if's) que não é prático as labels, é chato ter que colocar labels para cada branch ou jmp...
Mas apesar de achar estúpido o instruction set não fazer referência ao uso dessas operações desta forma, acho que já descobri o que está a acontecer...
No atmel simulator vi a instrução que era guardada na memória flash e cheguei à conclusão que o assembler faz os cálculos de forma a colocar na instrução o offset correto. Ou seja, interpreta RJMP (ou qqr jmp ou branch) k como se quisesse fazer um salto absoluto para PC = k e calcula o offset. Também dá para ver isso no tab "disassembly".
-
Até pode ficar feio usar labels, embora não tenham de ser declarados no início do programa trata-se apenas de uma posição da memória flash para onde vai saltar sem ter de se andar a contar, caso desejes colocar alguma instrução no meio o endereço adapta-se, coisa que não acontece com o PC e toca a calcular novamente... bugs
Realmente em assembler fazem-se coisas que são de se evitar em C ou outra do género, como "goto" "jump" "labels" , "ifs" dentro de "ifs" e tudo aquilo que vamos aprendendo a não fazer para que não se crie situações difíceis de interpretar, daí colocarem-se bastantes comentários, bastam minutos para nos esquecermos o motivo de algumas decisões.
Resume-se a branchs ao comparar registos e valores, ifs, como o Senso referiu.