<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/58395>58395</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [AVR] Microchip changed the semantics of 16 bit register writes on newer cores
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          G33KatWork
      </td>
    </tr>
</table>

<pre>
    When accessing 16 bit registers like counters on an 8 bit AVR core, these accesses have to be split into two 8 bit register writes. To do this, the peripherals have a TEMP register that the CPU automatically writes to on the first write and a write to the other half of the target register yields a write of this temporary register and the currently written value into the 16 bit target register in the same cycle.

On old cores like an ATmega8, the datasheet states that you need to write the high byte first and then the low byte. [See ATmega8 datasheet, page 78.](https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2486-8-bit-AVR-microcontroller-ATmega8_L_datasheet.pdf). LLVM takes care of this [here for writes](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp#L1262-L1269) and [here for reads](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp#L1230-L1238).

However, newer cores like the tinyAVR 1-series like an ATtiny817 require these writes to happen with the LOW byte first, followed by the high byte. [See ATtiny817 datasheet, page 55.](https://ww1.microchip.com/downloads/aemDocuments/documents/MCU08/ProductDocuments/DataSheets/ATtiny417-814-816-817-DataSheet-DS40002288A.pdf) I didn't check any other datasheets yet about which other cores might be affected by this change.

I just ran into this when trying to use Rust on an ATtiny817. Writing to the counter register with a `u16` seemingly caused the low byte to be ignored or otherwise wrong all the time. Once I converted my writes manually to two `u8` writes in the order specified by the datasheet, things started to work. Flipping them once more showed the same broken results as the single `u16` write.

I also confirmed the wrong order by disassembling the resulting Rust program and comparing it to an equivalent C program compiled by `avr-gcc`. The `avr-gcc` compiled program was equivalent except for the write order of the two register halves.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzFVsFy2zYQ_RrpghGHpESJOujgWnGbqT3xJE58zIDgikRMEiwAStXf9wEEJTntpb10JqFJYrn79u3bXRWqPO9ea-oYF4KMkV3FkjUrpGWaKmksacMa-UZMqKHzTwq2Hcu9zd23zzjQNEvvma3JUHBDhtX8SMwqVhAzfQNb2eHJnlT4dHLPTlpaMhF7UayEQS1N8MZ60rKvSfMmuOPs5cPT8_VTW3PrLe-fvzI-WNVyKwVvmnPw6gAArzM5SG3s-Br4S_ga7x0oHCtcNKI0B6YO_o3luqIbnGdJTWku33kriQjU9kpzfb5aOvfOgxi0ps4GNBYkH3kzUGACBoHpnyPJEbHhLXycRUPRLN7P4rvx-qljqik97aE0KMfdS0sVzyfmSm65qQlOjeWeB8fUWQ2sIypdziF52NayqllxthNFAf2IoVEnfxaxWfbLF6Ip0DWCC9nzitgmj2bZfpbmtbW9mS3vZukD_p1OSdRKoZWoZR8J1eJdqU5do3iJSj9Qh8uejlLQXgnc39mWmkW6yteLfAF6FhDZYvSgOqtV05BeBBjfH79fgER9eZil24g9Pn57AqdvSFtwfa0UMkCNkaaaRPdPeCtp66EIQJvmOP1Z9Fr9IIF8H4pGFfjTctnd2Ej37sWX0mXx7fN4_fBnD0afDQ2l-tgZayLR97N0-Zik63Thrlug9qzfAtTk6Pl_8S1jh2-ZO1ZvFfibOtGRtKt8RycI9kaLvnNkd3aTIVkYdPA7lbqjPNkgvT8GqSkMjWuz1rzvIb0TkvSuHj-93mjTRTxAAIhf4vV7-d5IdIryd5Fm2X8SKacW4hxadLPxR9f7p_uvMRh6eNaqHIS9Ndsj_BcX3j2MqFbJZpEnK_yHunF_MVnsv6ziOE7TPL8LSmYfWSlLlHBjmahJvIHCcxhUl8wMO6PLeaEGDLdaijoYjCVpQY51I5gfDtDGxBqaQdS8q94Plo_sx4D-1yhUmFCwO_lJoM9uMeDdgGp9dlbjFrhQHbFX1DAY-dk3roubMe9KytlsHQ_JGldmiFp8gOkoONyW7-ZN2Byy6pBHydAQPq2T9GpRiIMpH8TWovSfOkHgCxMCwnR5tpcV0PJu8CshrB-HIHcAwnmYtkqXQGl6EvIgr_J6JyEw0lXGzVQfw41Rpd8ihubqe598TS2oAZYWuJmpvVIvw7zQ6g10ojJDg8pxMx45FuiGGQ_sp9JgByqXHvqgDS5HHkbcQFtKw7F526IJSEIc9-RLhgFRad76UQOJ91y7I7d_lKul60jsJ2iX3V9snZ1sRjoAjR_1ohICd9jXNb1_dTWevj4hwxu39Keg3vrxNuL3e9Tjn3Yu6nNRDJbxET8M5rRL1utsm8WbPJuXu2W5XW753Erb0A4t7yZZtmdPU_sGaQfaCeXHbwLjIvz0w2YSAKR8M8bmg252_3rkSmMGcm2e5cttNq93oqBlwrNVsT1s4nJ5wINIsmSZi0NZlPlm3vCCGuMSAPq53KXo_SRO1mkcr9MsSsQqy9LNuihEWRTYEasYqcgmcoEjpau53nkMxVAZHDbSje7LIZSA3iGa_OPHUa307tfl8nduXyHauUe883D_Arr1bJ0">