Instrução AVR SEI

13

A instrução AVR SEI ( http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_SEI.html ) aguarda a conclusão da próxima instrução antes de ativar as interrupções.

Se eu usar outra instrução para definir o sinalizador I no SREG, isso também esperará 1 instrução?

Em outras palavras: a espera é um recurso da instrução SEI ou do registro de status?

Se é um recurso da instrução SEI, em que momento o sinalizador é realmente configurado, no ciclo que executa o SEI ou com a próxima instrução?

Jay Jay
fonte
Essa é uma ótima pergunta, mas não deve ser muito difícil de testar e ter certeza.
Vorac
1
@Vorac Você pode me dar um exemplo de como isso pode ser testado? Essa seria a minha resposta aceita, com certeza.
Jayjay
1
Pode ser um recurso de uma implementação da arquitetura do AVR e onde as interrupções podem ser tratadas. IIRC, a arquitetura AVR usou um pipeline de 3 estágios. Portanto, a próxima instrução já deve estar 'em voo' (ou seja, no estágio 1 do pipeline ou mais) antes que a alteração da bandeira I possa ser usada para verificar se há interrupções. Não olho há muito tempo, mas não acho que os projetistas da arquitetura do AVR teriam se restringido demais. Portanto, testar a interrupção para obter uma instrução no estágio 1 do pipeline, e não antes da próxima instrução (no estágio 2), oferece flexibilidade.
gbulmer

Respostas:

8

Resultados empíricos!

Enquanto as outras respostas são bem pensadas e bem fundamentadas, são todas incompletas ou apenas conjecturas. Onde a documentação é ambígua, devemos experimentar e testar todos os casos.

Esta pergunta merece uma resposta conclusiva, então vamos retirar um AVR e começar a definir alguns bits!

Procedimento

Para testar, fiz um pequeno programa do Arduino (ATMEGA328P) que ...

  1. configurar um ISR que nunca retornaria ( while (1))
  2. atribuiu o ISR a uma fonte que eu poderia acionar em software ( INT0diminuindo)
  3. interrupções desabilitadas
  4. ativado e acionou a interrupção para que estivesse pendente

Eu usei um banco de testes que acenderia um LED na instrução única após as interrupções serem ativadas. Ao tentar diferentes maneiras de ativar interrupções no banco de testes e verificar o LED, eu poderia dizer se a instrução após a instrução de ativação foi executada ou não.

Se o LED não acender, sei que o ISR foi executado (e bloqueado) imediatamente após a ativação das interrupções.

Se o LED acender, sei que a próxima instrução foi executada antes da chamada do ISR.

Resultados

SEI instrução (caso base)

Código:

sei

Resultado: LED aceso. Seguindo a instrução executada.

OUT instrução

Código:

in  r16,0x3f   // Get SREG
ori r16,128    // Set I bit 
out 0x3f,r16   // Save back to SREG

Resultado:

LED aceso. Seguindo a instrução executada.

ST instrução

Código:

   clr r29        // Clear Y high byte
   ldi r28,0x5f   // Set Y low byte to point to SREG
   ld r16, Y      // Get SREG
   ori r16,128    // Set I bit 
   st Y,r16       // Put SREG

Resultado:

LED aceso. Seguindo a instrução executada.

Conclusão!

P: A espera é um recurso da instrução SEI ou do registro de status?

R: Parece que alterar o Ibit in SREGde a 0para a 1permitirá que a seguinte instrução seja executada a seguir, mesmo que haja uma interrupção pendente, independentemente da instrução usada para definir o bit.

Notas

Isso realmente se transformou em uma pergunta muito interessante, com muitas complicações. Se você estiver interessado nos detalhes, confira ...

http://wp.josh.com/2016/01/05/different-ways-to-set-i-bit-in-avr-sreg-besides-sei/

bigjosh
fonte
2
Quando a especificação é ambígua, há um problema com "Resultados empíricos". Simplesmente porque a peça específica de hardware que você testou funciona de uma maneira específica, não significa que outras partes funcionem dessa maneira. A Atmel tem a liberdade de alterar a implementação, desde que não altere a especificação. Portanto, "Onde a documentação é ambígua ...", permanece exatamente o que, após experimentos e testes, ainda é ambíguo.
gbulmer
@gbulmer Concordo 100%. Quem usa recursos não documentados na produção está fadado a ficar triste. Ainda é uma pergunta empírica interessante (e resposta), e provavelmente ok para depender de um projeto pessoal único.
bigjosh
Sim, você fez uma investigação fascinante.
gbulmer
4

Entendo, a partir da documentação, que executar a seiinstrução não é diferente de escrever diretamente um 1 no bit I do SREG. A vantagem da instrução é que você não precisa carregar primeiro um valor 1<<Iem um registro de trabalho para alterar o SREG, economizando tempo.

Para elaborar, usando sei:

sei ; One cycle

Definir o bit usando sbi(só funcionaria se o SREG estivesse nos 32 bytes inferiores do mapa de registro, mas parece que na maioria, se não todos, não está).

sbi SREG,7 ; Two cycles

Escrevendo para bit diretamente no SREG:

in  r24,SREG ;
ori r24,0x80 ;
out SREG,r24 ; Three cycles

O Ibit deve ser definido em SREG assim que a seiinstrução ( sbiouout ) for concluída. No entanto, quaisquer interrupções pendentes não serão tratadas até que a próxima instrução seja concluída - o bit será definido, mas é necessário um ciclo extra para que as interrupções sejam ativadas. Como uma interrupção não pode ser manipulada no meio da instrução e algumas instruções levam mais de um ciclo para serem executadas, elas especificam o tempo necessário para serem ativadas como uma instrução. Este deve ser o caso de todas as versões do código - ou seja, cada uma das opções acima causará o atraso de uma instrução.


Depois de um pouco de pesquisa, achei esse tópico no fórum do Arduino, no qual vários testes diferentes foram realizados para verificar o comportamento. Parece concordar com o que eu disse acima.

Além disso, de acordo com esse encadeamento, se o Isinalizador já estiver definido, não haverá resposta atrasada de uma interrupção causada, o seique implica que a resposta atrasada é causada não pela própria instrução, mas pelo hardware interno controlado pelo Isinalizador - portanto, qualquer operação que muda a bandeira em SREG, seja seiou outou ststerá exatamente o mesmo comportamento.

Tom Carpenter
fonte
Portanto, não há nenhum aspecto de atrasar a operação, específico para SEI, mas não OUT, que permita a conclusão das seguintes instruções?
Brian Drummond
No caso do seu segundo exemplo, quando é tratada uma interrupção pendente? Existe um atraso de ciclo como no primeiro?
Jayjay
@jayjay ver minha atualização.
Tom Carpenter
1
Observe que SBInão pode ser usado para definir o Ibit; SREGportanto, qualquer código que faça isso provavelmente não foi realmente testado na vida real porque ele nem será montado. SBIsó pode funcionar com as mais baixas 32 registros e SREG é a ranhura 63.
bigjosh
@bigjosh o exemplo do SBI foi um que pensei mais tarde - outera o que eu estava usando originalmente. Eu pensei em encontrar um AVR (pode ser um ATTiny) que tem o SREG nos 32 registros mais baixos, mas eu posso estar imaginando.
Tom Carpenter
1

O IMHO que escreve para o SREG ainda atrasa 1 instrução pode ser testada assim (pseudocódigo):

ISR() { PORTA = 0; while(1); }
main() 
{
    cli();
    DDRA = 0xff;
    configure_isr_for_level_interrupt_that_will_trigger_immediately();
    SREG = 0xff;
    cli();
    PORTA = 0xff;
    while(1);
}

Infelizmente, não tenho tempo para fazê-lo :(

Vorac
fonte
0

Não é isso que diz. As documentações dizem

A instrução a seguir à SEI será executada antes de qualquer interrupção pendente.

não que aguarde a próxima instrução. Eu li isso como o sinalizador é definido imediatamente, mas, embora habilitado, nenhuma interrupção será tratada até que a próxima instrução seja executada.

patthoyts
fonte
Tudo isso é verdade, mas minha pergunta é: esse comportamento é específico ao SEI?
jayjay
@jayjay Eu suspeito que isso é devido ao comprimento gasoduto instrução
crasic