AVR Assembly Code Mystery

Go To Last Post
30 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm using Atmel Studio 7 and the code outlined below refuses to recognise the Global Interrupts Enable bit being set in the SREG.

I must be stupid not to see the problem, anyone have any ideas?

 

/*
 * AssemblerApplication2.asm
 *
 *  Created: 30/12/2016 13:58:12
 *   Author: Steve
 */

.include "m328pdef.inc"

.cseg
.org 0x00
  jmp  reset

.org 0x40

reset:
  cli
  
 ; Initialize Stack Pointer.
  ldi  r16, LOW(RAMEND)
  out  SPL, r16
  ldi  r16, HIGH(RAMEND)
  out  SPH, r16

  sei

 MAIN_LOOP:
  brie global_Ints_enabled
  brid global_Ints_disabled
  rjmp MAIN_LOOP

global_Ints_enabled:
  rjmp global_Ints_enabled

global_Ints_disabled:
  rjmp global_Ints_disabled

.exit

This topic has a solution.

varistha

Last Edited: Fri. Dec 30, 2016 - 07:27 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How are you testing?  If with a simulator, could it be a simulator artifact?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your code works for me (in the simulator, loops at global_Ints_enabled).

How are you observing that it does not work?

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah-ha.   I had never heard of the BRIE instruction.   So I built your AS7 project.

 

Sure enough.    Whatever the state of the I bit,   you always end up at global_Ints_disabled !!

 

At least that is what the Smulator produced.

 

David.

 

Edit.   I see that it worked for frog_jr.    I have always assumed that the Simulator should be 100% correct.

Last Edited: Fri. Dec 30, 2016 - 03:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, this is interesting.

I used AS7.0.1006 (haven't upgraded this computer as I am in the middle of a project) and the code appears to work in the simulator.

 

@David, what simulator are you using that branches to global_Ints_disabled?

 

Edit: What happens if you add a couple of NOPs after the sei?

David (aka frog_jr)

Last Edited: Fri. Dec 30, 2016 - 03:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

frog_jr wrote:
Edit: What happens if you add a couple of NOPs after the sei?
I thought of that race as well...

 

If [exactly] a one cycle delay, then the BRIE will be false as I bit is not yet set.  But by the time it gets to the BRID, it is set so that branch is taken.

 

Now, isn't one instruction done after an SEI?  That's how we do bulletproof SEI-SLEEP, right?  So maybe indeed SEI doesn't "take" for one cycle after being set.

https://www.avrfreaks.net/comment...

https://www.avrfreaks.net/comment...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Fri. Dec 30, 2016 - 04:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the response.

Yes I'm using the built-in simulator.

 

Adding a few 'NOPS' does not change the result.

I don't know if it is a simulator configuration issue!

varistha

Last Edited: Fri. Dec 30, 2016 - 04:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just changed it so I could run on an ATmega328pb Xplained Mini and the original code appears to function by branching immediately to global_Ints_enabled on the hardware.

 

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

 

I substituted the brie & brid instructions for brbc & brbs, and set the flags either in code or manually during stepping through in the simulator.

 

brbc 7, xxxx {equivalent to CLI being executed}

brbs 7, xxxx {equivalent to SEI being executed}

The code always fails.

 

brbc 6, xxxx {equivalent to CLT being executed}

brbs 6, xxxx {equivalent to SET being executed}

The code always works.

 

/*
 * AssemblerApplication2.asm
 *
 *  Created: 30/12/2016 13:58:12
 *   Author: Steve
 */

.include "m328pdef.inc"

.cseg
.org 0x00

  jmp  reset

 

.org 0x40

 

reset:
  cli  ; clear Global Interrupts Enable flag.
  
 ; Initialize Stack Pointer.
  ldi  r16, LOW(RAMEND)
  out  SPL, r16
  ldi  r16, HIGH(RAMEND)
  out  SPH, r16

  sei  ; Set Global Interrupts Enable flag.

 

 MAIN_LOOP:
  nop
  nop
  nop
  brbs 7, bit_set
  brbc 7, bit_clear

;  brie global_Ints_enabled
;  brid global_Ints_disabled

  rjmp MAIN_LOOP

 

global_Ints_enabled:
  rjmp global_Ints_enabled

 

global_Ints_disabled:
  rjmp global_Ints_disabled

 

bit_set:
  rjmp bit_set

 

bit_clear:
  rjmp bit_clear

 

.exit

 

 

varistha

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The first instruction after a "sei" will be executed with interrupts disabled.

(This way you can do a "sei; sleep" atomically.)

 

This means the code will branch before the interrupts are enabled.

So after initializing the SP try "sei; nop" or "sei; mov r0,r0".

Last Edited: Fri. Dec 30, 2016 - 05:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The main reason for the one instruction (it's a copy from 8051), is that you can single step "main" from a interrupt (that always is triggered).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

djboni wrote:
So after initializing the SP try "sei; nop" or "sei; mov r0,r0".
Varistha wrote:
Adding a few 'NOPS' does not change the result.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The solution to this 'MYSTERY' appears to be a possible bug in ATMEL STUDIO 7 ( and also version 6 ).

Installed ATMEL STUDIO 5.1 and the code works as expected.

 

If this is a real bug I'm surprised it has not been picked up before.

 

I appreciate everyone's efforts.

Thanks.

varistha

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Varistha wrote:
The solution to this 'MYSTERY' appears to be a possible bug in ATMEL STUDIO 7 ( and also version 6 ).

Interesting.  We recently learned:

https://www.avrfreaks.net/comment...

je_ruud wrote:
The simulator models are made with the exact same RTL code that the chips are made with. We take all the synthesizable code, replace the necessary non-synthesizable parts with synthesizable behaviour-correct modules and compile it with http://www.veripool.org/wiki/ver.... That's why you can trust the simulator. The only thing that can prove it wrong is the real device. The simulator in AVR Studio 4 was a C++ implementation based on the datasheets, but we figured it was too much work and too error prone. With the introduction of Simulator2 in AVR Studio 4 we started with simulator models based on the RTL code. In all Studios after AVR Studio 4 there has been only one simulator, which is the same as Simulator2.

So now someone needs to test on a real device.  A couple of LEDs for the poor man...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Fri. Dec 30, 2016 - 08:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But no one really cares about ASM programmers.....so don't hold your breath for a quick fix it it's a Studio bug. surprise

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
But no one really cares about ASM programmers.....so don't hold your breath for a quick fix it it's a Studio bug.

C'mon -- what does that have to do with assembler?  Or do assembler programmers have super-double-secret-probation op codes that mere mortals cannot use?  The simulator has to handle op codes no matter what the source language is, right?

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Varistha wrote:

The solution to this 'MYSTERY' appears to be a possible bug in ATMEL STUDIO 7 ( and also version 6 ).

Installed ATMEL STUDIO 5.1 and the code works as expected.

 

frog_jr (post #3) wrote:

Your code works for me (in the simulator, loops at global_Ints_enabled).

 

frog_jr wrote:

I used AS7.0.1006 ... and the code appears to work in the simulator.

 

Varistha, which version of Studio 7 did you test?  Why did the simulator work for frog_jr?

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Or do assembler programmers have super-double-secret-probation op codes that mere mortals cannot use?

Well if I told you then I would have to kill you to protect the secret. wink

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fails here, using 7.0.1188

Processor Status window clearly shows I bit set, BTW...

 

Do we think that BRIE *ever* branches?  I'm not sure what other conditions to try...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was using Studio Version 7.0.1188

 

The problem was highlighted when running some assembled code for PWM using Timers 0 & 2.

Even though the required Int flag was being set correctly along with INT MASK ENB set, the interrupt routine was not being called.

So I targeted the Global Interrupt Enable flag recognition accordingly.

 

Using Studio Version 5.1.208 and all code testing Global Interrupt Enable flag recognition and the original PWM Timers works perfectly.

I thought I was just being dumb somehow but believe Studio 7 is the culprit in this case.

varistha

Last Edited: Sat. Dec 31, 2016 - 12:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just tried it as well (in AS 7.0.1188), and I can replicate BOTH situations laugh

If I start the simulator and let it run (F5), and then break the execution, the code ends up looping in global_Ints_enabled.

But if I singlestep through the code (with F11), it ends up in global_Ints_disabled.

 

Next step: Trying it on real hardware.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I had this nagging feeling that I've been in a similar situation before, and indeed that was the case:

https://www.avrfreaks.net/comment/1834511#comment-1834511

I just verified that the solution also applies to this problem, and it does. By disabling "Mask interrupts while stepping", the simulator consistently ends up in the global_Ints_enabled loop, single stepping or not.

 

And the rationale for this option, and its default value, is here:

https://www.avrfreaks.net/comment/1277931#comment-1277931

 

Last Edited: Sat. Dec 31, 2016 - 10:26 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have tested the code both ways, single stepping or free running to a breakpoint.

Running to a breakpoint in the destination loop it does work, single stepping it does not.

 

Clearly a 'dependable' simulator should produce the same results, regardless of single stepping or free running to a breakpoint.

 

I cannot think of any good reason you would want it to do otherwise!

varistha

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Varistha wrote:
I cannot think of any good reason you would want it to do otherwise!
Svuppe wrote:
And the rationale for this option, and its default value, is here: https://www.avrfreaks.net/comment...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Varistha wrote:

...

The problem was highlighted when running some assembled code for PWM using Timers 0 & 2.

...

...Global Interrupt Enable flag recognition...

 

 

 

I checked several of my larger AVR8 apps (written in C/CodeVision), and none have used BRIE/BRIC opcodes.  (Is that why we seldom BRICk an AVR8?)

 

And I couldn't think of a situation where I might use it.

 

But then I thought of the "save SREG-turn off interrupts-do my thing-restore SREG" dance, and that's where I'd use the op codes if I hadn't learned the SREG trick.

 

IIRC I was puzzled by the dance the first time I saw it performed by the natives.  Then I realized (or was pointed out to me) that the dance used fewer code words and fewer cycles and a deterministic cycle count.

 

OP, is there another need for BRIE that I can't think of?

 

(besides a fruitcake alternative...)

Brie6

http://www.purewow.com/food/Best...

Baked Brie with Figs, Walnuts and Pistachios

So much better than a fruitcake.

Example of the dance, sans BRIE/BRIC:

 

 

004636 99f9      	SBIC EECR,EEWE
004637 cffe      	RJMP __EEPROMRDB
004638 93ff      	PUSH R31
004639 b7ff      	IN   R31,SREG
00463a 94f8      	CLI
00463b bda1      	OUT  EEARL,R26
00463c bdb2      	OUT  EEARH,R27
00463d 9af8      	SBI  EECR,EERE
00463e b5e0      	IN   R30,EEDR
00463f bfff      	OUT  SREG,R31
004640 91ff      	POP  R31
004641 9508      	RET

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Sat. Dec 31, 2016 - 03:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Svuppe wrote:
If I start the simulator and let it run (F5), and then break the execution, the code ends up looping in global_Ints_enabled.

And in my testing of the code (post #3 and #8), I just set breakpoints and did a run (F5).

So the single stepping with "Mask interrupts while stepping" seems to be the difference...

 

theusch wrote:
Baked Brie with Figs, Walnuts and Pistachios So much better than a fruitcake.

Although that does sound very good, my family absolutely loves the family recipe fruitcake.. (hic), excuse me! wink

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

frog_jr wrote:
Although that does sound very good, my family absolutely loves the family recipe fruitcake..

I also like our fruitcake recipe.  The above was the quoted caption from the Web link.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
The above was the quoted caption from the Web link.
My apologies ...

Now back to BRIC-a-BRAC ..., er, that is brie and brid

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I had the opportunity to try Stinking Bishop, Britain's smelliest cheese this Christmas.

https://en.wikipedia.org/wiki/Stinking_Bishop_cheese

https://www.theguardian.com/lifeandstyle/wordofmouth/2009/may/28/smelliest-cheese-world-stinking-bishop

I became "nose blind" after a while but did notice people keeping their distance after I'd had a good helping.

 

Back on topic however, Are we testing whether the simulator honours the "Always execute one instruction after SEI before servicing any IRQ" rule ?

Well with this test code I can vouch that it does.

 

.include "m328pdef.inc"

.cseg
.org 0x00
    jmp	reset
.org 19*2
    jmp	USART_UDRE_vect     ; USART, Data Register Empty

reset:
    cli
    
; Enable receiver and transmitter and IRQ
    ldi	r16, (1<<UDRIE0)|(1<<RXEN0)|(1<<TXEN0)
    sts	UCSR0B, r16
    nop
    sei

MAIN_LOOP:
    brie global_Ints_enabled
    brid global_Ints_disabled
    rjmp MAIN_LOOP

global_Ints_enabled:
    rjmp global_Ints_enabled

global_Ints_disabled:
    rjmp global_Ints_disabled


USART_UDRE_vect   :  /* USART, Data Register Empty */
    nop
    reti

Here I've lined up a UART interrupt request which is ready to pounce as soon as SEI allows it.

 

Putting a breakpoint in the ISR and running by pressing F5 (not single-step) halts the program in the ISR as expected.

Single stepping out of the ISR takes the Program Counter to the global_Ints_enabled forever loop indicating that the BRIE has been swallowed before the ISR ran.

 

My faith in the simulator has been restored.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I will just add that I have used BRID in some old code.

 

The reason was that the ISR played sounds so it could not be disabled at any time, and I had to be able make some atomic updates

to the variables used by the ISR.

My solution was to set a flag in "main" and wait until the ISR cleared it, now I knew that it would take a while 

before next ISR so I could safely make my updates.

But that wait will hang forever if the I flag is cleared! so a BRID solved the problem