BRIE also known as BRBS SREG_I Wanted

Go To Last Post
53 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

QA: Did anybody experienced:

    - BRIE or BRBS SERG_I aka "branch if "I" flag is set" - BRIC or BRBC SREG_I aka "branch if "I" flag is clear"
in any compiled HLL or asm code?

QB: Why is "I" flag placed inside of SREG register, when it is not a part of an unknown interrupted context? Only ISRs (and reset) can interrupt program flow, so what is the point of saving "I" when its value is known at compile time?

I will answer further questions of "Why do you need that" kind. I am just curious why did Atmel put it there, when it is completely useless as a part of a context. Useless like nop;mov x,x;rjmp pc+1; subi x,0 and a bunch of other op codes without meaning.

Which unimplemented context flag would you find the most useful (a parity flag like in '51)?

No RSTDISBL, no fun!

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

Surely it would have taken a whole extra register if it were to be held separate from the other flags in SREG at IO address 0x3F

You may be too young to remember but the original AVRs all had just 64 SFRs fitting nicely into the IN/OUT address range which is why some of them ended up doing double duty with UBRRH/URSRC as 65 registers were really required. I doubt they could have found room for another, separate register just to show the state of I though I guess it could have been made visible in something like MCUCSR.

Cliff

PS as for QA - I think you are right, those are probably very seldom used though I guess they could form part of some atomicity protection code perhaps?

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

You are right, the I flag inside SREG was definitively the most worst place. :cry:

E.g. the SREG should be ideally suited to solve complex state machines, since you can jump on every bit directly.
But unfortunately the unwanted changing of the interrupt enable flage forbid such easy usage.

So you can only use other registers with two instructions (skip and jump), which double the program size.

Peter

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

Quote:
so what is the point of saving "I" when its value is known at compile time?
But it is most certainly not known at compile time. The program can change its value at any time. Is it going to be used very often? Probably not. But it most certainly does need to be saved out in some circumstances (such as when a write or read of a multibyte variable needs to be made atomic). And I can't think of any other place that would be logical to put it.

Regards,
Steve A.

The Board helps those that help themselves.

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

I think it's BRID rather than BRIC, but that's a minor point.

I have seen one or both of the instructions used, although I don't remember where. Some bootloader, perhaps, or some of the security chips' or USB code I was having a look at. I have never used either myself.

As to putting it in the SREG, everybody has to be somewhere. By having it in the SREG it's available for the generic clear/set instruction encoding, although I see your point that some other flag could have used the real estate.

I would contend that nop is far from useless, and rjmp pc+1 is an artifact of the offset calculation (should it have a zero offset mean pc+2? Perhaps it's a common adding mechanism in the instruction decoder that needs to add 1 or 0 sometimes). I can see a possible use for subtracting an immediate 0 in setting flags or some such.

I'm sure that instruction set design is a huge undertaking, trying to optimize a thousand things and make a "best fit" of all the pieces. While hindsight may be 20/20 I feel like the boys did a pretty good job over all.

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

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

Quote:

I will answer further questions of "Why do you need that" kind.

Heck, no wonder PIC and ARM are popular. You have an AVR with 100+ instructions, and many aren't even used:

==========================================================================
ATmega1280 instruction use summary:
.lds  :   0 .lds.l:   0 .sts  :   0 .sts.l:   0 adc   : 179 add   : 215 
adiw  :1057 and   :  49 andi  : 207 asr   :   0 bclr  :   0 bld   :  73 
brbc  :   0 brbs  :   0 brcc  :   5 brcs  :   0 break :   0 breq  : 445 
brge  :  11 brhc  :   0 brhs  :   0 brid  :   0 brie  :   0 brlo  : 193 
brlt  :  17 brmi  :   4 brne  : 536 brpl  :   2 brsh  : 141 brtc  :   3 
brts  :   0 brvc  :   0 brvs  :   0 bset  :   0 bst   :   1 call  :2323 
cbi   :  17 cbr   :   1 clc   :   0 clh   :   0 cli   :   9 cln   :   0 
clr   : 282 cls   :   0 clt   :  12 clv   :   0 clz   :   0 com   :  34 
cp    : 165 cpc   : 137 cpi   : 892 cpse  :   0 dec   :  21 des   :   0 
elpm  :   0 eor   :   6 fmul  :   0 fmuls :   0 fmulsu:   0 icall :  10 
ijmp  :   0 in    :  54 inc   :  18 jmp   : 246 ld    : 489 ldd   :2046 
ldi   :3209 lds   :1649 lpm   :  76 lsl   :  69 lsr   :  27 mov   : 731 
movw  : 765 mul   : 166 muls  :   0 mulsu :   0 neg   :   3 nop   :   0 
or    :  79 ori   :  45 out   :  73 pop   :  98 push  :  98 rcall : 134 
ret   : 260 reti  :   7 rjmp  :1044 rol   :  73 ror   :  17 sbc   :  20 
sbci  : 324 sbi   :  24 sbic  :  12 sbis  :  16 sbiw  : 149 sbr   :   3 
sbrc  :  16 sbrs  : 140 sec   :   0 seh   :   0 sei   :   7 sen   :   0 
ser   :   1 ses   :   0 set   :  59 sev   :   0 sez   :   0 sleep :   0 
spm   :   0 st    :1842 std   : 555 sts   : 881 sub   :  18 subi  : 533 
swap  :  25 tst   :  22 wdr   :   7 
Instructions used: 75 out of 117 (64.1%)

ATmega1280 memory use summary [bytes]:
Segment   Begin    End      Code   Data   Used    Size   Use%
---------------------------------------------------------------
[.cseg] 0x000000 0x00fbc6  56490   7964  64454  131072  49.2%
...

...so a decent-sized app and only 2/3 of instructions used. (I haven't even heard of some of the instructions.)

I've never seen the H flag used. Perhaps only by those doing BCD arithmetic?

Parity might be nice. A couple of times I'd have liked to have it but have not found its lack critical.

Do you expect/desire Atmel to change the base AVR instruction set after decades and billions of units that apparently can get the job done with the instruction set as it is?

As a curiosity these discussions are somewhat interesting. But on the whole not as interesting as "what is the fastest/shortest instruction sequence to do xyz". That at least has a practical outcome, and assumes the given AVR instruction set.

If there was one perfect instruction set we'd all be using that micro. We don't all use the same micro. So I'm gonna call this a whine/troll, and am out.

If there is a critical area of the app code--e.g., graphics bit rendering, or FORTH kernel dispatch--where every cycle counts then pick the micro that gives you the shortest time.

Aside from a few selected ISRs, over the years very very few of my AVR apps ever run out of gas even at modest clock rates. Size? Our volumes don't justify total squeezing as Cliff's might, and chances are a new feature will be added to my app next year at customer request so flash space isn't 99+%. So what is the objective?

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

Quote:
I can see a possible use for subtracting an immediate 0 in setting flags or some such.
In fact, it could have been used for the TST opcode instead of AND Rd, Rd. The only difference is how the H bit is affected.
Quote:
...so a decent-sized app and only 2/3 of instructions used. (I haven't even heard of some of the instructions.)
I think that this analysis is somewhat bogus. According to this, lds and sts are never used in the program. This is highly unlikely for the vast majority of apps. It says that BRBS and BRBC are never used, but in fact they are (these are the generic branch opcodes that encompass all branch opcodes). Same with BSET and BCLR. There might be others that are aliases marked incorrectly.

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:

According to this, lds and sts are never used in the program.

???

lds   :1649
sts   : 881

[edit] I >>did<< say I'd never heard of some of the instructions. I now see the ".sts" etc. on the first line of the table; probably what caught your eye. I have no idea what that is. Long addresses in a '1280 perhaps? [end edit]

Remember that this table is the output of AVRASM2. I'd assume that it is just a "hit" count of whenever a mnemonic is actually assembled. So without doing detailed checking the instruction use will be chalked up to the mnemonic used. Also note that this is the output of a compiler. Hand-crafted .ASM source by any programmer will probably exhibit a different profile.

I thought the alias debate was another thread. ;) But pertinent to this, in the register use there are x, y, z as well as R26, ... .

[just to note that I edited some === into the table above so the layout doesn't wrap - hopefully more readable and the LDS use can be seen easily]

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

BTW would lds.l be those short opcodes added to the brain-dead Tiny10 and friends?

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

Brutte wrote:
I will answer further questions of "Why do you need that" kind. I am just curious why did Atmel put it there, when it is completely useless as a part of a context. Useless like nop;mov x,x;rjmp pc+1; subi x,0 and a bunch of other op codes without meaning.

Why would you have mov x,x?
Probably for the sake of instruction othogonality. The instruction decode hardware can directly accept the 6-bit op-code, 5-bit source register number, and 5-bit destination register number as fixed fields in the instruction, and it immediately knows exactly what to do.

I'd speculate that taking steps to explicitly filter out the mov x,x instruction, while leaving the remainder of mov x,y instructions intact, would result in increased complexity and transistor count, and hence increased power consumption and cost.

This is balanced against the debatable benefit of the recovery of 32 additional instructions which could be custom-crafted for other purposes. Such a benefit kinda goes against the principle of RISC which was apparently considered to be an important design goal when the AVR was first created.

Why would you have a RJMP PC+1 instruction?
Same reason as above.

Why would you have a NOP instruction?
There are timing benefits in having an instruction which is guaranteed to have no side-effects other than taking up a well known period of time. However, in my opinion, given the fact that other instructions already exist which exhibit the exact same properties as NOP in terms of timing, side-effects, etc, there really isn't any reason for a separate NOP instruction to exist. I think Atmel ought to have taken one of those mov x,x instructions, and made it an alias for NOP.

Last Edited: Wed. Jul 28, 2010 - 04:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Quote:
so what is the point of saving "I" when its value is known at compile time?
But it is most certainly not known at compile time.

The original statement was:
Quote:
Only ISRs (and reset) can interrupt program flow, so what is the point of saving "I" when its value is known at compile time?

The point is
- after reset, I is 0
- after enter ISR, the I is 0
- after RETI, the I is 1
so it is known, and doesn't make sense to save it together with other flags.

Also, when access double registers, I could sit in a different register as well.

George.

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

angelu wrote:
Quote:

Quote:
so what is the point of saving "I" when its value is known at compile time?
But it is most certainly not known at compile time.

The original statement was:
Quote:
Only ISRs (and reset) can interrupt program flow, so what is the point of saving "I" when its value is known at compile time?

The point is
- after reset, I is 0
- after enter ISR, the I is 0
- after RETI, the I is 1
so it is known, and doesn't make sense to save it together with other flags.

Not necessarily, if you consider the possibility of re-usable code (eg. functions) that may be called from an unknown context. Such functions would not necessarily know, at compile time, whether interrupts are disabled or enabled.

In fact, if a single function has been designed to be called at different times from both inside and outside an interrupt service routine, then that function is 100% guaranteed to only be able find out for certain whether or not interrupts are disabled by means of a run-time check.

Now, would it really be the end of the world if it needed to perform that runtime check on a general purpose I/O register rather than using up one of the bits in SREG? Maybe not.

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

Quote:
Not necessarily, if you consider the possibility of re-usable code (eg. functions) that may be called from an unknown context

Yes, I agree, but my question is (quoting with error)
Quote:
Did anybody experienced (...)

I can imagine such situation, but "I" is an implicit argument to that function then(it is a const argument, so it is still compile time known for caller and an auto for callee). Instead you can use it explicitly or even implicitly check where the call was made from.

The main disadvantage of such SREG construction to mee is the fact I cannot perform switch() statement effectively:

;temp contains switch argument
out SREG,temp
brbs 3,option_3
 brbc 2,exit
option_3:
 brbc 5,option_3_not_5
  brbs 7,option_3_5_7
  ...

It has only 5 bits effective length if you want to keep SREG_T(at least they have put it next to "I").

Quote:
I've never seen the H flag used. Perhaps only by those doing BCD arithmetic?

SREG_H flag is very useful. It is modified by only some arithmetical operators (great for passing args)and wonderful for nibble counters. You can keep two independent counters in one register. Set, clear, inc dec, ldi and many other combinations in a single clk. SREG_H is almost the same as SREG_C.

No RSTDISBL, no fun!

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

Quote:

I can imagine such situation, but "I" is an implicit argument to that function then(it is a const argument, so it is still compile time known for caller and an auto for callee). Instead you can use it explicitly or even implicitly check where the call was made from.

Now we have to start worrying about how much nesting we want to force the compiler to deal with -- what if the function in question is a callee of a function of a function of a function (...) before we get back to the point where the root function was called from either an interrupt or non-interrupt context? What if this involves passing from one compilation unit to another, so the ultimate target function is actually compiled independently from the root caller? What if the programmer plays some tricks to save Flash space by occasionally directly calling the body of an ISR from the mainline, so that the root entry point of the ISR can be considered to be simultaneously in both an interrupt and non-interrupt context?

My point is, it can sometimes be dangerous for compiler designers to make certain assumptions about what can be known at compile-time and what must be resolved at run-time. Some of these distinctions are best left up to the software designer herself, and therefore it is best for the tools to be made available to allow for runtime checking, if the situation calls for it.

The decision might have boiled down to preference: "other successful architectures (eg. CCR in 68HC11, FLAGS in x86, CPSR in ARM, etc) have made the decision to place the equivalent to the I bit in their equivalent to SREG in the past, so if it was a valid decision for them to make, why not do the same here?"

That being said, I'll grant that it was not absolutely necessary for SREG to be the specific tool that is used for this particular type of runtime checking -- several other mechanisms could have been pursued instead, such as placing the I bit in a different register.

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

Also bear in mind that the AVR was designed in collaboration with IAR as the perfect "C micro" (in part this presumably explains 32 registers?) so the architecture and opcodes are probably optimised for the way the IAR code generator behaves, not necessarily for the benefit of Asm programmers.

A lot of the opcodes that most of the C compilers seldom, if ever use may just be there as a result of orthogonality and minimal instruction decode (to save transistors/silicon) rather than a deliberate act.

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

Quote:
The main disadvantage of such SREG construction to mee is the fact I cannot perform switch() statement effectively:
But this is just a hack, isn't it? The status register bits are set or cleared by actions of the core. To set them to random values and then complain that it doesn't work the way you want it is just asinine. The AVR gives you instructions to check any single bit of any of the GP registers (sbrs, sbrc). Given your code above, the equivalent with sbrs, sbrc and rjmp is only 3 words longer and at most 3 clocks longer.

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:
But this is just a hack, isn't it?

Don't you "hack" SUBI instruction using it as a replacement for the missing "ANDI" one ? I am sure you do.
Quote:
The AVR gives you instructions to check any single bit of any of the GP registers (sbrs, sbrc). Given your code above, the equivalent with sbrs, sbrc and rjmp is only 3 words longer and at most 3 clocks longer.

Reading this thread, do you think the OP is not aware about the existence / usage of SBRS and SBRC ?

George.

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

Quote:
The status register bits are set or cleared by actions of the core

But you can set or clear them manually (sex, where x is ithvscz) or use them as a switch statement (if arg is 5 bits long). That is pretty useful. Of course you can use sbrx and rjmp but it will take twice the size(not including out SREG,temp).

Anyway, there are several propositions how to explain placing "I" inside SREG and save it with context..

Quote:
other successful architectures

Quote:
what if the function in question is a callee of a function of a function of a function

Quote:
As to putting it in the SREG, everybody has to be somewhere

Quote:
But it is most certainly not known at compile time

Quote:
Not necessarily, if you consider the possibility of re-usable code (eg. functions)

None of them is convincing, it seems that nobody have ever seen brie or brid and there is no practical reason to put this flag into SREG and branch on it or save it as a context.
Thank you all for interesting discussion and ideas. Of course further remarks are welcome. And maybe some examples from different architectures touching saving context/conditionals/flags?

No RSTDISBL, no fun!

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

Quote:
Don't you "hack" SUBI instruction using it as a replacement for the missing "ANDI" one ?
This is not a "hack", it is the way the designers of the chip want you to use the instruction.
Quote:
Reading this thread, do you think the OP is not aware about the existence / usage of SBRS and SBRC ?
No, I think that the OP is proud that he found a hack that saves trivial amounts of time and space.
Quote:
Of course you can use sbrx and rjmp but it will take twice the size(not including out SREG,temp).
But you have to include the out SREG, temp, or it won't work, making your point moot.

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:
But you have to include the out SREG, temp, or it won't work, making your point moot.

No, you do not need to do that - use 5/6 lower bits only. You just select appropriate switch statement with brbx instead of sbrx+rjmp. No need to restore if you did not modify SREG_I (known at compile time).

Quote:
No, I think that the OP is proud that he found a hack

I did not find anything - I simply regret "I" is a part of SREG, because switch and other conditional jumps could be much more useful without "I" in there. The discussion is about "Why I in SREG" so I gave the argument of waste of resource and oportunities to use it more eficiently that way. SREG and brbx is a wonderful thing but because of useless brix it is not that wonderful. I thought somebody ever seen brix..
BRIX WANTED!

No RSTDISBL, no fun!

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

Quote:

BRIX WANTED!

OK, now assess the likelihood that it will happen.. (A.k.a.: Pick your fights)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Quote:
No, you do not need to do that - use 5/6 lower bits only.
Huh??? If you don't put the values that you want to switch on into SREG, then you are going to be switching on random values. That doesn't sound very useful to me.
Quote:
The discussion is about "Why I in SREG" so I gave the argument of waste of resource and oportunities to use it more eficiently that way.
Then where would you put the I bit?

Regards,
Steve A.

The Board helps those that help themselves.

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

Koshchi wrote:
Quote:
The discussion is about "Why I in SREG" so I gave the argument of waste of resource and oportunities to use it more eficiently that way.
Then where would you put the I bit?

In all fairness, there is no reason I can fathom why you couldn't put the global I bit in any other I/O register. It doesn't absolutely *need* to be in SREG.

Quite frankly, the pseudo-instructions BRIE (I) and BRID (I) (along with all their ilk, BRCC (C), BRCS (C), BRLO (C), BRSH (C), BREQ (Z), BRNE (Z), BRGE (S), BRLT (S), BRHC (H), BRHS (H), BRMI (N), BRPL (N), BRTC (T), BRTS (T), BRVC (V), BRVS (V)) don't actually exist.

All that exist are BRBC and BRBS. The fact that the CPU associates special conditional flags with certain bits in SREG is an implementation detail. The ability to branch on the majority of those conditional flags (C, Z, S, H, N, V) is quite essential to proper program flow, so it makes sense to make them readily accessible in SREG at all times.

It could easily be argued, on the other hand, that the I bit could have been placed somewhere else -- anywhere else in the I/O register space -- without a significant detriment to writing code that is able to read the I bit's status (if necessary), but it would have opened up potential flexibility in what you could do with the BRBC and BRBS instructions elsewhere.

I'm not going to bother getting into a heated debate about the question of whether or not the interrupt-enable status of the CPU is always knowable at compile-time versus run-time. Honestly, it is irrelevant to this debate, because other options exist which would allow the I bit to be evaluated at run-time (if necessary) even if the I bit were placed in any other arbitrary I/O register.

(Mind you, there is an additional trade-off to consider: placing the I bit in an ordinary I/O register would have meant a minimum 2-cycle penalty to manually enable/disable interrupts (via the SBI and CBI instructions) versus the 1-cycle penalty that comes with the specialized set and clear instructions which are reserved for SREG...)

But the fact of the matter is, the I bit has been placed in SREG, and no amount of grumbling by us mere mortals is going to be able to change that.

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

I was brought up on the 6502 where you accessed the P register in a very convoluted manner. e.g. PHP, PLA, AND #$xx ...

In my experience, you seldom want or need to access SREG. The typical case being remember=SREG, CLI, ... , SREG = remember.
So you could argue that the I bit could be anywhere, just as long as you can read it somehow. The cpu would always push and pull its flags as part of its IRQ response.

However, the AVR has many instructions that do not alter the flags. Hence you do not always need to save the flags during an IRQ.

It is all fairly academic. IMHO, the AVR instruction set is pretty wisely chosen. So we will just have to put up with what we have got. I doubt that we will ever see any NEW 8-bit cores invented.

David.

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

Quote:

But the fact of the matter is, the I bit has been placed in SREG, and no amount of grumbling by us mere mortals is going to be able to change that.


Yah know, if this construct -- I bit in the status register -- is detrimental or harmful or less than optimal you'd think that the smart people at ARM would do it the right/better/best way. And as they are coming out with new and improved cores regularly, they have opportunities to make things better. Yet

Quote:
11.2.4.2 Status Registers
All other processor states are held in status registers. The current operating processor status is
in the Current Program Status Register (CPSR). The CPSR holds:
• four ALU flags (Negative, Zero, Carry, and Overflow)
• two interrupt disable bits (one for each type of interrupt)
• one bit to indicate ARM or Thumb execution
• five bits to encode the current processor mode
All five exception modes also have a Saved Program Status Register (SPSR) that holds the
CPSR of the task immediately preceding the exception.

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

Quote:
(Mind you, there is an additional trade-off to consider: placing the I bit in an ordinary I/O register would have meant a minimum 2-cycle penalty to manually enable/disable interrupts (via the SBI and CBI instructions) versus the 1-cycle penalty that comes with the specialized set and clear instructions which are reserved for SREG...)
But the whole point of the OP is that putting it somewhere else would be "more efficient", when in fact it would most likely makes thing less efficient. But the only example of "more efficient" that the OP could come up with is his hack, of which he laments because the designers of the chip decided to make the status register actually represent the current status of the chip.

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:

(Mind you, there is an additional trade-off to consider: placing the I bit in an ordinary I/O register would have meant a minimum 2-cycle penalty to manually enable/disable interrupts (via the SBI and CBI instructions) versus the 1-cycle penalty that comes with the specialized set and clear instructions which are reserved for SREG...)

Why couldn't the same SEI or CLI opcodes affect the same bit that has the same interrupt enabling/disabling function? All that changes is the ability to read it back? In fact if we're redesigning the core (it'll never happen!) then why not add a TSTI opcode to read it's state (and, ironically, set a flag in SREG!)?

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

clawson wrote:
Quote:

(Mind you, there is an additional trade-off to consider: placing the I bit in an ordinary I/O register would have meant a minimum 2-cycle penalty to manually enable/disable interrupts (via the SBI and CBI instructions) versus the 1-cycle penalty that comes with the specialized set and clear instructions which are reserved for SREG...)

Why couldn't the same SEI or CLI opcodes affect the same bit that has the same interrupt enabling/disabling function?

Because to do that, the OP would lose the ability to perform orthogonal single-bit set/clearing of some of his precious general-purpose SREG bits -- keep in mind that CLI, SEI, CLZ, SEZ, CLH, SEH, CLV, SEV, CLT, SET, CLC, SEC, CLN, SEN, CLS, and SES instructions basically just boil down to aliases for a single pair of undocumented "SBSREG x" (set bit x in SREG) and "CBSREG x" (clear bit x in SREG) instructions.

By the way, I am not advocating the OP's position. I am perfectly content with things the way they are. I've never been in a situation where I was inclined to use the OP's proposed switch statement "hack".

Certainly, Atmel has people with a lot more experience in silicon design than me (or most of the rest of us on this forum) so I trust that they had reasons for designing things the way they did.

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

Quote:

keep in mind that CLI, SEI, CLZ, SEZ, CLH, SEH, CLV, SEV, CLT, SET, CLC, SEC, CLN, SEN, CLS, and SES instructions basically just boil down to aliases for a single pair of undocumented "SBSREG x" (set bit x in SREG) and "CBSREG x" (clear bit x in SREG) instructions.

Ummm--undocumented? Aren't they the specific variants of BSET and BCLR?

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

Oops, I didn't notice those. Indeed.

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

Quote:

Because to do that, the OP would lose the ability to perform orthogonal single-bit set/clearing of some of his precious general-purpose SREG bits

No I was suggesting the same opcodes be maintained, but not necessarily the same underlying opcode bit pattern so it's not doing BSET/BLCR and has nothing to do with SREG any more. I guess it could even be the same bit pattern but it's fully decoded so does not interfere with BSET/BCLR operation

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

Wow, I did not know the discussion will find such audience!
I understand AVR's core will not be changed. Even this discussion is not going to change that!
I can see most of you like the current "I" position in SREG and you do not find it disturbing because of one reason - that is where Atmel has already put it. But nobody has ever used or even seen this brix instruction in action! Nobody has ever saved SREG_I as part of unknown "core context" (well, there was a theoretical example this could be done: f(f(f))..).

Quote:
would have meant a minimum 2-cycle penalty

That is the execution time of current core operation with IO addresses below 0x3F. I do not think that was the reasoning of the authors of the core to put "I" in SREG - you could link sex/clx commands with any other IO bits I suppose.
The usage of sex/clx with other SREG flags is also another misunderstanding since you can set/clear almost any combination of these flags with a single asm command (cpi or cp for example) - they are useless in my opinion and I was never forced to use a single one of them (except for SREG_I).
But this is a topic for another discussion.
Quote:
But the only example of "more efficient" that the OP could come up with is his hack

Anybody ever seen BRIX? That was the question. Why it exists, was it ever useful? I only gave the example that if "I" was somewhere else, bigger switch statement selection (specially those with bitfields) would have been easier (faster and smaller). I think much better than "I" there could be one of:
    - parity bit (which can be used only with transmission error recognition I suppose), - separate Carry and Borrow
    - RAMPZ
or any other flag which is a part of an unknown context, would be much more beneficial (in my opinion).

I liked the argument:

Quote:
would lose the ability to perform orthogonal single-bit set/clearing

because it is much easier to learn AVR assembler if number of its rules is small.
This is the only convincing reason of brix existence.

No RSTDISBL, no fun!

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

Quote:

But nobody has ever used or even seen this brix instruction in action!

My C compiler is not using the BRIX instruction. I am devastated..

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Brutte wrote:
Wow, I did not know the discussion will find such audience!
I understand AVR's core will not be changed. Even this discussion is not going to change that!
I can see most of you like the current "I" position in SREG and you do not find it disturbing because of one reason - that is where Atmel has already put it. But nobody has ever used or even seen this brix instruction in action! Nobody has ever saved SREG_I as part of unknown "core context"...

YES!!!

I do save SREG_I, then unconditionally clear it, then run some code, then transfer the saved state back into SREG_I. I do this on a regular basis as part of just about any critical section code. In fact, WinAVR's critical section API (ATOMIC_BLOCK()) regularly works this way, so I'll bet that most WInAVR users also do this.

I'll go further, and wager that the majority of other people who work with WinAVR do this on a fairly regular basis too, even if they don't explicitly use the critical section API, because of the code that is automatically generated by WinAVR whenever the compiler needs to atomically manipulate the stack frame in the prologue or epilogue of any regular function call.

Run-time manipulation of SREG_I in situations where the initial state of SREG_I is assumed to be unknown, is extremely common.

Albeit, these runtime evaluations of SREG_I do not involve the BRIE or BRID istructions -- they use whole-register transfers from SREG into and out of temporary holding variables.

Anyway, I think it's clear that the real root of the problem isn't, "why do the BIRE and BRID instructions exist?", but rather, "why is the I bit kept in SREG instead of some other register?".

I do not have a good answer to that question.

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

Quote:
Run-time manipulation of SREG_I in situations where the initial state of SREG_I is assumed to be unknown, is extremely common.

Yes, it is saved and restored to provide ISR-free critical sections. But is it a part of unknown context?
Critical section must be in something interruptable (in 99.9% times it will be main, 0.1% in interruptable ISRs), there is no point of using it when interrupts are disabled (I think). So you are saying you have a function in main() which (for example) modifies some 16-bit register (which must be also used in some enabled ISR to protect against something) and the compiler is not sure if interrupts are set or cleared when accessing that function?

It seems to me this is a known case:

Quote:
what if the function in question is a callee of a function of a function of a function

"I" is an implicit argument of that function then.
It is reasonable only if mentioned function is called at least twice, with "I" and without "I" set, which is rather pecular, but also mentioned in this post.

I know that "C" language does not support "bit" type, but "I" is still nothing else. Its place can be anywhere, including a register or another IO(like RAMPZ or MCUSR bits), but SREG is the worst place for "I" (IMHO). SREG ought to hold an unknown context state which is saved when program flow is unexpectedly interrupted and it should be used as a tool for branching. But to hold there static variables which are regular arguments to some functions of main()?

No RSTDISBL, no fun!

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

You're right that in many cases, it is "knowable".

However, it's also a fact that for most C programmers, it's just more convenient to allow SREG_I's state to be explicitly saved/restored at run-time, rather than go through the trouble of taking special measures to ensure SREG_I's state is implicitly tracked compile-time. The (very) slight performance benefits that would come from taking such compile-time measures just don't often justify the extra effort involved.

Especially in terms of the code that is automatically generated by avr-gcc (without the influence of any explicit source code whatsoever) when it manipulates the stack frame in the prologue and epilogue of functions, the extra effort required of the programmer to avoid such instances of explicit save/modify/do-work/restore of SREG_I is, indeed, significant.

Quote:

It is reasonable only if mentioned function is called at least twice, with "I" and without "I" set, which is rather pecular, but also mentioned in this post.

As a matter of fact, calling the same function twice, once with "I" set and once with "I" cleared, happens all the time in the code I write.

For example, it may happen when I write one piece of atomic critical section utility code, which is intended to be safe to invoke directly from the mainline (hence SREG_I is initially '1'), but which is also occasionally invoked from within another piece of code that's already in a critical section (hence SREG_I is initially '0').

I could write two different versions of the same function, one of which is intended to be called directly from the mainline and the other of which is intended to be called from within existing critical sections. But that introduces maintenance nightmares when I discover a bug in the function, and fix it in one version but forget to fix it in the other.

To avoid that pitfall, I could make the 'SREG_I initially 1' version into a wrapper around the "SREG_I initially 0' version, whose only job is to clear SREG_I manually before starting, and then set SREG_I again after completion. But that comes with its own set of inconveniences related to having to mentally keep track of which version of the function is appropriate to use in any given context. It's much more convenient to have a single entry point which is guaranteed to be safe to use in any context.

In any event, both of these alternatives are virtually guaranteed to result in a larger overall code size than a single version which always saves/restores SREG -- if only due to the extra layer of CALLing involved in the wrapper alternative.

I don't find this strategy to be peculiar at all. I consider it a good common sense solution, balancing code efficiency with convenience. And I think you'll find others who agree with me.

But I have already stated the following, and I will state it again: This entire discussion of whether or not SREG_I is always knowable at compile time, truly is an irrelevant sidebar to the real question at hand, specifically, "Why can't SREG_I be stored in some other register outside of SREG"?

And as I have conceded in the past, I cannot think of any compelling answer to that question.

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

Quote:
I could write two different versions of the same function

That is what the arguments to functions are for.

Anyway, this was a very theoretical thread. As always, I was thinking there is some beneficial reason of placing "I" in SREG and that here on AVR Forum some guru will give a reasonable example so that I could say: "Oh, now I understand, "I" could not be in a better place than SREG".

Unfortunately this did not happen.

No RSTDISBL, no fun!

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

Brutte wrote:
Quote:
I could write two different versions of the same function

That is what the arguments to functions are for.

Adding extra arguments means that the stack frame being fed into the function needs to grow, so there is an objective detriment to such a technique, especially in limited RAM environments such as most AVRs.

Even if it can be done in such a way that there isn't any difference in size or speed, why would a firmware writer ever choose the inconvenience of needing to keep track of more arguments than necessary?

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

You can put arguments to functions in any register bit, byte, IO or even SREG flag. I can also imagine it could be passed in one of the hidden states. Not a problem with that. If you want to keep it in IO register, you can use any of them, not necessearily SREG, which is (could be) wonderful for conditional branches. I understand "I" has to be somewhere (one of the arguments) but why SREG?

Quote:
Adding extra arguments means that the stack frame being fed into the function

I am not sure about it for 100%, but did anybody experience SREG to be an explicit (unlike implicit SREG_I which is an exception) argument to the function in C? I do not think so, because, as I wrote earlier,
    neither switch() statement is useful then because of hardware implementation, nor "bit" type is supported in "C/C++".

So there is no point discussing about other arguments of bit type, as there is only one SREG_I flag - nothing can be done in a better way, flag will be passed within some byte in this or other way. It is static (and volatile, as all IO registers), so it does not involve stack overhead. Speaking other words, it is global. The only situation SREG is saved is at the beginning of some ISRs, but then SREG_I is const (as I wrote before) and it does not make sense to save a const on the stack.

No RSTDISBL, no fun!

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

Quote:
You can put arguments to functions in any register bit, byte, IO or even SREG flag.
And gee, look, the very thing that you want to pass is already there, in SREG, ready for you to use, yet your whole argument is that it is a bad idea that it is there in the first place.

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:
And gee, look, the very thing that you want to pass is already there, in SREG, ready for you to use, yet your whole argument is that it is a bad idea that it is there in the first place

Quote:
I am not sure about it for 100%, but did anybody experience any SREG flag to be an explicit (unlike implicit SREG_I which is an exception) argument to the function in C?

No RSTDISBL, no fun!

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

Quote:

You can put arguments to functions in any register bit, byte, IO or even SREG flag.

Fine. If you place the "I" bit in any other register, then you're free to call it an implicit argument to every function, if that name makes you happy.

Personally, I wouldn't call it a function argument. I'd call it either a "global variable" or a "piece of global state information".

The CPU is already responsible for keeping track of whether interrupts are enabled or disabled, in order to decide whether or not code is interruptible at any given point in time; therefore, the label "CPU State Information" seems the most appropriate.

Given the fact that I have described scenarios where it is beneficial to be able to write a single function that is able to behave differently at run time depending on whether or not interrupts were enabled at the moment the function started, and given the fact that the hardware is already keeping track of whether or not interrupts are enabled at every point in time, it seems reasonable to me that the hardware would provide a mechanism to allow the software to directly read hardware's "I" bit, rather than requiring the software to needlessly duplicate this information separately.

You're absolutely correct, the "I" bit could have been placed in any other I/O register, and the benefits of the scenario above could still have been met. The "I" bit does not need to be in SREG. I'm now on the third round of repeating myself on that point and you still don't seem to comprehend the meaning of my words.

If anybody else (other than Brutte, who already seems to have made his opinion clear) doesn't agree with my position, please chime in to correct me.

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

Quote:
Personally, I wouldn't call it a function argument. I'd call it either a "global variable" or a "piece of global state information".

I was also thinking about the definition of "argument of a function". We all agree argument does not need to change program flow, but the effect of execution must depend on it some way. Not like SREG content when entering ISR - its execution must not depend on it at all. And an argument does not need to be explicitly listed on a function's argument list - globals are not. Same with return values. There is one explicit (as only one is allowed in C/C++) and the rest must be passed implicitly through globals.

Quote:
if you consider the possibility of re-usable code (eg. functions) that may be called from an unknown context
and f(f(f()))..

It does not change the fact functions we were talking about treat it as argument. As you mentioned you do not need to write two separate sets of functions, but one only - the "I" argument controls an if(SREG_I) statement (you use it for critical section) to select one or the other alternative. The problem is nobody ever seen brix, because implementation always assumes "I" is const - save/restore does the job better than if("I") in 100% cases.

No RSTDISBL, no fun!

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

What compiler setting gives me this ? Thanks.

==========================================================================
ATmega1280 instruction use summary:
.lds  :   0 .lds.l:   0 .sts  :   0 .sts.l:   0 adc   : 179 add   : 215
adiw  :1057 and   :  49 andi  : 207 asr   :   0 bclr  :   0 bld   :  73
brbc  :   0 brbs  :   0 brcc  :   5 brcs  :   0 break :   0 breq  : 445
brge  :  11 brhc  :   0 brhs  :   0 brid  :   0 brie  :   0 brlo  : 193
brlt  :  17 brmi  :   4 brne  : 536 brpl  :   2 brsh  : 141 brtc  :   3
brts  :   0 brvc  :   0 brvs  :   0 bset  :   0 bst   :   1 call  :2323
cbi   :  17 cbr   :   1 clc   :   0 clh   :   0 cli   :   9 cln   :   0
clr   : 282 cls   :   0 clt   :  12 clv   :   0 clz   :   0 com   :  34
cp    : 165 cpc   : 137 cpi   : 892 cpse  :   0 dec   :  21 des   :   0
elpm  :   0 eor   :   6 fmul  :   0 fmuls :   0 fmulsu:   0 icall :  10
ijmp  :   0 in    :  54 inc   :  18 jmp   : 246 ld    : 489 ldd   :2046
ldi   :3209 lds   :1649 lpm   :  76 lsl   :  69 lsr   :  27 mov   : 731
movw  : 765 mul   : 166 muls  :   0 mulsu :   0 neg   :   3 nop   :   0
or    :  79 ori   :  45 out   :  73 pop   :  98 push  :  98 rcall : 134
ret   : 260 reti  :   7 rjmp  :1044 rol   :  73 ror   :  17 sbc   :  20
sbci  : 324 sbi   :  24 sbic  :  12 sbis  :  16 sbiw  : 149 sbr   :   3
sbrc  :  16 sbrs  : 140 sec   :   0 seh   :   0 sei   :   7 sen   :   0
ser   :   1 ses   :   0 set   :  59 sev   :   0 sez   :   0 sleep :   0
spm   :   0 st    :1842 std   : 555 sts   : 881 sub   :  18 subi  : 533
swap  :  25 tst   :  22 wdr   :   7
Instructions used: 75 out of 117 (64.1%)

ATmega1280 memory use summary [bytes]:
Segment   Begin    End      Code   Data   Used    Size   Use%
---------------------------------------------------------------
[.cseg] 0x000000 0x00fbc6  56490   7964  64454  131072  49.2%

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

indianajones11 wrote:
What compiler setting gives me this ? Thanks.
CodeVision.

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

In a simple application you can catch up an interrupt by polling the appropriate interrupt flag,execute the code and then clear the flag by writing one on the flag.SEI or BSET 7 does exactly this,when an interrupt flag is set jumps to interrupt vector and executes the interrupt.As long as interrupt is executed,I flag is cleared and set again by RETI clearing in the meantime the interrupt flag by writing one to this flag.The SREG is saved and restored to allow the program to continue without altering all the other flags.
Example:
CP r16,r5
----Here jumps to interrupt----
BREQ is_same;Tests Zero flag,Zero==1 when the two registers are equal
In the case when SREG is not saved,the two registed may appear to be equal,might not.Who knows,comparison has done and the result has lost.

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

Quote:

indianajones11 wrote:
What compiler setting gives me this ? Thanks.
CodeVision.

Not exactly. It is from the output of Atmel's AVRASM2, in the .LST file. CodeVision uses that assembler. Those using infinite-value toolchains may need another approach.

Lee

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

This post is a reply to the question asked by theusch in this topic:
https://www.avrfreaks.net/index.p...
I felt like it is a little off-topic actually to give answer in there, as that subject is more about efficient switch()case: method on an AVR architecture (SREG is involved, but not strictly SREG_I which is the subject of this one).

theusch wrote:
So, you said it before and repeated it now that the I bit state was known at
compile time.

Sorry for repeating, but after my posting there was a proposition of using SREG for switch() again.

What I meant is that SREG is an unfortunate place for SREG_I because it greatly complicates switch() and prevents efficient computations.

Quote:
Are you saing that any cli() or sei() in my code are not needed?

It seems you misunderstood "known at compile time" as

#define SREG_I 1
//#define SREG_I 0

?
That is not what I meant. Let me explain:

Lets call the example given by you a foo(). Our foo() is callable and can be called from main() and from ISR() (there is no point discussing about foo() when it is inlined).

A: From main() perspective:
If this function is called from main(), then obviously main() knows if SREG_I is set or is not set, as it is the main() that must set or clear SREG_I and call foo(). An ISR cannot enable SREG_I by itself as it would not be executed when SREG_I is cleared and it also cannot clear SREG_I as there is RETI at the end of each ISR.
In this case SREG_I is known at compile time because it is you (the main()) who set/clear it! It is not even volatile, but a global variable/flag which can also be used as an argument in some functions if you wish. Same as for example DDRB7 which (lets assume in our foo) is not modified at all or restored by an ISR whenever it is interested in toggling it for some reason.

B. From ISR() perspective:
If foo() is called from ISR() then the example is exactly the same - the compiler must call the foo() so it knows if SREG_I is or is not set. Well, initially SREG_I is obviously cleared but you can also make the ISRs interruptable - no problem. Still that does not change a thing - SREG_I is known at compile time (unlike rest of SREG while entering ISR).

It is not the cli or sei that is bad or not needed, but the place SREG_I is located is unfortunate IMHO.

There is another possibility - that I do not understand Atmel's ingenuity!

No RSTDISBL, no fun!

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

Quote:

it greatly complicates switch()

I must be dim - what does I have to do with switch()? Surely switch just uses BRNE's or similar? Where does I come into that?

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

Danni wrote:
E.g. the SREG should be ideally suited to solve complex state machines, since you can jump on every bit directly.
But unfortunately the unwanted changing of the interrupt enable flage forbid such easy usage.

Brutte wrote:

The main disadvantage of such SREG construction to mee is the fact I cannot perform switch() statement effectively:

;temp contains switch argument
out SREG,temp
brbs 3,option_3
 brbc 2,exit
option_3:
 brbc 5,option_3_not_5
  brbs 7,option_3_5_7
  ...

It has only 5 bits effective length if you want to keep SREG_T(at least they have put it next to "I").

No RSTDISBL, no fun!

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

Quote:
If this function is called from main(), then obviously main() knows if SREG_I is set or is not set, as it is the main() that must set or clear SREG_I and call foo().
Bull. The compiler will do no such thing, a function call does not touch SREG.
Quote:
I must be dim - what does I have to do with switch()?
He is still complaining that his trick can only do 6 cases instead of 7 (which of course is inconsequential when your switch statement has 32 cases).

Regards,
Steve A.

The Board helps those that help themselves.

Pages