1

Assume the following code in C:

long int a = 262143;

which in binary will be 111111111111111111 (18 bits). If an atmega328p register can hold 8 bits, how is the above represented in the register?

Compiled Assembly:

    .file   "a.c"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__tmp_reg__ = 0
__zero_reg__ = 1
    .text
.global main
    .type   main, @function
main:
    push r28
    push r29
    rcall .
    rcall .
    in r28,__SP_L__
    in r29,__SP_H__
/* prologue: function */
/* frame size = 4 */
/* stack size = 6 */
.L__stack_usage = 6
    ldi r24,lo8(-1)
    ldi r25,lo8(-1)
    ldi r26,lo8(3)
    ldi r27,0
    std Y+1,r24
    std Y+2,r25
    std Y+3,r26
    std Y+4,r27
    ldi r24,0
    ldi r25,0
/* epilogue start */
    pop __tmp_reg__
    pop __tmp_reg__
    pop __tmp_reg__
    pop __tmp_reg__
    pop r29
    pop r28
    ret
    .size   main, .-main
    .ident  "GCC: (GNU) 8.2.0"
Josh l
  • 11
  • 2

1 Answers1

2

It isn't. It's split into four 8-bit values, each representing a quarter of the bits. Each value is stored in a separate register or memory location (depending on what is being done with it).

Software then combines them together to act as a single 32-bit value.

Majenko
  • 105,095
  • 5
  • 79
  • 137
  • Then how would a single instruction look like? isn't an instruction supposed to be 8 bits in length in this case? – Josh l Sep 15 '18 at 17:58
  • 1
    There is no "single instruction". You should compile some code and look at the resultant assembly language - you'll find it's many instructions long. This is why 32-bit CPUs are more efficient than 8 bit. – Majenko Sep 15 '18 at 17:59
  • I added the assembly code above, so I guess ldi r24,lo8(-1) ldi r25,lo8(-1) are doing that – Josh l Sep 15 '18 at 18:01
  • and ldi r26,lo8(3) since you're working with 18 bits not 16. 0xFF is -1 in two's complement, so you have 0x03 ff ff which is 0b111111111111111111. – Majenko Sep 15 '18 at 18:02
  • one last question, what does the above code do exactly? it populates 3 registers with 2 lower 8 bit of -1 = 111111 and 1 lower 8 bit of 3 = 000011 ? – Josh l Sep 15 '18 at 18:04
  • Yes. "ldi" is "LoaD Immediate". You end up with r24 = 0xFF, r25 = 0xFF and r26 = 0x03. – Majenko Sep 15 '18 at 18:05
  • One more off topic question (hope I can ask it properly). instructions are stored in RAM right, in this case an 8 bit instruction is somewhere in RAM and CPU loads it. How does CPU know where the instruction ends given a RAM address? how does it know the different between an instruction and a small integer length which has lower bit counts? Basically how doesn't it keep reading the RAM and knows where to stop – Josh l Sep 15 '18 at 18:12
  • Fun fact: the compiler supports int64_t and uint64_t on a arduino uno. That is a variable of 64 bits (8 bytes) on a 8 bit microcontroller. – Jot Sep 15 '18 at 18:13
  • 2
    @Joshl No - instructions are in flash, not RAM, and flash is 16 bits wide. Each instruction either fits in one 16 bit word or two 16 bit words depending on the instruction. The CPU knows how "long" each instruction is by the fact that the instruction itself will contain information about what needs to be fetched from where. – Majenko Sep 15 '18 at 18:18
  • It's actually 4 registers (r27:r24), and 4 bytes of stack: (SP+1 to SP+4). Not sure why the stack is used. Maybe the variable was volatile, or the code was compiled at -O0... – Edgar Bonet Sep 15 '18 at 19:23
  • @EdgarBonet The stack is used because r24-r27 are in the "call clobbered" category. They're just used temporarily to place the values into memory since you can't LDI direct into memory. Registers 18-27, 30 and 31 can only be used for temporary storage since any function called is allowed to change the value and not restore it. 2 to 17, 28 and 29 are "call saved" - any function must restore them after use. Whether the compiler decides to use memory or "call saved" registers for its variables depends on what it's being used for and what else is going on. – Majenko Sep 15 '18 at 22:56
  • https://gcc.gnu.org/wiki/avr-gcc#Call-Used_Registers – Majenko Sep 15 '18 at 22:57
  • I am aware of the call saved / call clobbered distinction. My point is: if you don't make a volatile, then it is optimized away by the compiler at any optimization level other than -O0. – Edgar Bonet Sep 16 '18 at 07:54
  • @EdgarBonet no it isn't. It can be, but whether or not it is depends entirely on both what a is being used for, and what other variables are around. There's limited registers that can be used. If a is considered less important it won't waste a dedicated group of registers on it You cannot second guess what the optimizer will do just on the strength of a single variable. – Majenko Sep 16 '18 at 10:47
  • I can. I have read the compiler's generated assembly. – Edgar Bonet Sep 16 '18 at 12:00
  • It probably was compiled with no optimization anyway. That assembly can't have been produced from Arduino code, so has no validity on this site anyway. So it's very much down to whatever the OP typed on the command line, and so is outside the scope of this site. – Majenko Sep 16 '18 at 12:22