Trying to understand assembly code

I'm very new to using assembly code and having some trouble understanding what this code is doing and how it works. I sort of understand the first few lines of code but I have no clue what the "brne delay" is doing, if someone could give a run down of what this code is doing it would be much appreciated!

void setup() {
  // put your setup code here, to run once:
asm("sbi 0x04, 5");
}

void loop() {
  // put your main code here, to run repeatedly:
asm("start:");
asm("sbi 0x05, 5");
asm("ldi r16,40 \n\t rcall delay");
asm("cbi 0x05, 5");
asm("ldi r16,40 \n\t rcall delay");
asm("rjmp start");

asm("delay:");
asm("dec r8");
asm("brne delay");
asm("dec r9");
asm("brne delay");
asm("dec r16");
asm("brne delay");
asm("ret");
}

dec decrements the values held in those registers. It sets the zero flag if the result is 0.
brne is a conditional branch that is taken only if the zero flag is not set - and if it is, they go back to the delay label. decrementing the register that was previously 0 makes it roll over. First part of the delay happens 256 times for each time that the second part does, and the second part happens 256 times per

So it's a delay based on the contents of r16... (which gets set to 0x40), working out to 4.2 million passes through the delay, and hence like... a second or so?

Ranch if not equal

If the Z flag is not zero, jump to delay

KeithRB:
Ranch if not equal

If the Z flag is not zero, jump to delay

The text of the instruction description: Tests the Zero flag (Z) and branches relatively to PC if Z is cleared. Meaning, the result of a previous instruction was Not Equal to zero.

The BREQ - branch (relative) if equal - Tests the Zero flag (Z) and branches relatively to PC if Z is set. Meaning the result of a previous instruction was EQual to zero.

It can be read as: If the result of an operation which affects the status register was zero, then set the Z flag. There's also a pair of instructions which do nothing but set/clear the zero flag (SEZ).

Sorry, yes, bad editing on my part. The docs I linked to should be correct, though. 8^)

It's the Blink example in assembler.

void setup() {
  // put your setup code here, to run once:
  // asm("sbi 0x04, 5");
  pinMode(13, OUTPUT);  // DDRB |= 0x20;
}

void loop() {
  // put your main code here, to run repeatedly:
  // asm("start:");
  while (true) {
    //asm("sbi 0x05, 5");
    digitalWrite(13, HIGH);  // PORTB |= 0x20;

    //asm("ldi r16,40 \n\t rcall delay");
    mydelay(40);

    //asm("cbi 0x05, 5");
    digitalWrite(13, LOW);  // PORTB &= ~0x20;

    //asm("ldi r16,40 \n\t rcall delay");
    mydelay(40);

    //asm("rjmp start");
  }
}

void mydelay(int count) {
  byte register8 = 0;
  byte register9 = 0;

  //asm("delay:");
  while (true) {
    //asm("dec r8");
    register8--;

    //asm("brne delay");
    if (register8 != 0)
      continue;

    //asm("dec r9");
    register9--;  // Counts down one for every 256 counts of register8

    //asm("brne delay");
    if (register9 != 0)
      continue;

    //asm("dec r16");
    count--;  // Counts down one for every 65536 times through the loop

    //asm("brne delay");
    if (count != 0)
      continue;

    //asm("ret");
  }
}

Thank you Johnwasser, that actually helped a lot, I'm still a little fuzzy on why registers 8 and 9 are used though.

Walks:
Thank you Johnwasser, that actually helped a lot, I'm still a little fuzzy on why registers 8 and 9 are used though.

All those registers are 8-bit registers, so if you need to delay for longer than 255 iterations of the loop (which you do), you need to use more than 1 register to store the count-down.

Walks:
I'm still a little fuzzy on why registers 8 and 9 are used though.

Excellent question. Anything from R18–R27, R30, R31 is a better choice...

https://gcc.gnu.org/wiki/avr-gcc

In addition, failing to initialize them is a bug. On power-up there is no guarantee the registers will be zero.

Thanks every, I definitely have a lot to learn.... and last question, how would I go about finding the on off time in real time, I know i need to know the crystal frequency

Each datasheet has a section titled Instruction Set Summary. That section has timings for each instruction (usually 1 or 2 clock cycles). It helps to have a spreadsheet that does the instruction-to-timing lookups.

Each datasheet has a section titled Instruction Set Summary.

And the more complete description of what the instructions do is in Atmel-0856 AVR Instruction Set Manual