Skip to content

Commit

Permalink
spellcheck and tidy directportmanipulation docs
Browse files Browse the repository at this point in the history
  • Loading branch information
SpenceKonde committed Sep 27, 2023
1 parent b252907 commit 44e561b
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 36 deletions.
2 changes: 1 addition & 1 deletion megaavr/cores/megatinycore/Arduino.h
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ See Ref_Analog.md for more information of the representations of "analog pins".

#if defined(HYPERRATIONAL_PIN_NUMBERS) /* Pins numbered starting from PA0, and PB6 and PB7 (14, 15) skipped on 20-pin */
#define _digitalPinToCanon(pin) (((pin) < NUM_TOTAL_PINS) ? (pin) : NOT_A_PIN)
#elif defined(RATIONALPLUS_PIN_NUMBERS) /* Pins numbered starting from PA1 = 0, so pin + 1 = cannonical pin number */
#elif defined(RATIONALPLUS_PIN_NUMBERS) /* Pins numbered starting from PA1 = 0, so pin + 1 = canonical pin number */
#define _digitalPinToCanon(pin) (((pin) < NUM_TOTAL_PINS) ? (((pin) == NUM_TOTAL_PINS - 1) ? 0 :((pin) + 1 )) : NOT_A_PIN)
#elif defined(SPECIAL_PIN_NUMBERS)
#define _digitalPinToCanon(pin) (((pin) < NUM_TOTAL_PINS) ? ((digital_pin_to_port[pin] << 3) + digital_pin_to_bit_position[pin] ) : NOT_A_PIN)
Expand Down
2 changes: 1 addition & 1 deletion megaavr/extras/Errata.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ Currently, this is only in the tinyAVR 1-series w/under 8k flash errata sheet. H

Though some will think this bug to be mighty and dreadful, it is not so.

This is nowhere near as bad as it sounds in reality for the simple reason that this is a very uncommon access pattern: It requires an ST/STD directed at very low addresses (notice that STS is not impacted, probably because the write happens 1 clock later because it has to read the next instruction word to know where to write to). The compiler will *not emit code like that unless you force it to* (ie, use a compile time unknown pointer to access the I/O space - if it's known constant, it will be emitted as an OUT instruction if it's in the I/O space (at worst, this is the same speed, and it's sometimes faster; the compiler is likely weighted to treat it as faster in all cases) or an STS if it's not - the STS is favorable unless the pointer or a pointer less than 64 lower than it is already in one of the pointer register pairs and this fact is known at compile time and the optimization permitted - a bar almost never met), and you have to do that in the cycle immediately after a ST/STS to somewhere else to manifest the bug. Accessing the I/O space by pointer is weird. You generally know the address at compile time, and so the compiler will generate OUT instructions instead of ST/STD instructions. And for SLPCTRL.CTRLA, since you're never going to access the sleep controller with a pointer (you'd be insane to - it's strictly worse, and there's no incentive to use a pointer since there is only one register in the SLPCTRL, so the address is known at compile time and will be accessed using STS. That only SLPCTRL is listed, while RSTCTRL is at a lower address is interesting, but not implausible. I think most likely RSTCTRL would be impacted just the same, except that RSTFR is a "flag" register and may be handled differently, while the SWRR register must use a protected write sequence, which precludes this access pattern, by dictating that the instruction immediately preceeding the key write is an OUT instruction writing to the CCP register in the high I/O space). Using a pointer to access an isolated variable or register of 1 byte in size is at least 1 clock slower but could be as much as 7 clocks slower (and the conditions required for this bug make the +4 and +7 clock options more likely, namely, likely having two pointers loaded at the same time. (the other possibilities are that an STS was followed immediately by a write to a pre-staged pointer to a low address. There are two other theoretical ways, but they're extreme contrivances involving writes to the page write buffer aimed at the last page that then either displace or postincrement to roll over the address. Writing to the page buffer and then the VPORTs like that does not maintain reasonable doubt - the only reason to do that is in order to manifest this bug.
This is nowhere near as bad as it sounds in reality for the simple reason that this is a very uncommon access pattern: It requires an ST/STD directed at very low addresses (notice that STS is not impacted, probably because the write happens 1 clock later because it has to read the next instruction word to know where to write to). The compiler will *not emit code like that unless you force it to* (ie, use a compile time unknown pointer to access the I/O space - if it's known constant, it will be emitted as an OUT instruction if it's in the I/O space (at worst, this is the same speed, and it's sometimes faster; the compiler is likely weighted to treat it as faster in all cases) or an STS if it's not - the STS is favorable unless the pointer or a pointer less than 64 lower than it is already in one of the pointer register pairs and this fact is known at compile time and the optimization permitted - a bar almost never met), and you have to do that in the cycle immediately after a ST/STS to somewhere else to manifest the bug. Accessing the I/O space by pointer is weird. You generally know the address at compile time, and so the compiler will generate OUT instructions instead of ST/STD instructions. And for SLPCTRL.CTRLA, since you're never going to access the sleep controller with a pointer (you'd be insane to - it's strictly worse, and there's no incentive to use a pointer since there is only one register in the SLPCTRL, so the address is known at compile time and will be accessed using STS. That only SLPCTRL is listed, while RSTCTRL is at a lower address is interesting, but not implausible. I think most likely RSTCTRL would be impacted just the same, except that RSTFR is a "flag" register and may be handled differently, while the SWRR register must use a protected write sequence, which precludes this access pattern, by dictating that the instruction immediately preceding the key write is an OUT instruction writing to the CCP register in the high I/O space). Using a pointer to access an isolated variable or register of 1 byte in size is at least 1 clock slower but could be as much as 7 clocks slower (and the conditions required for this bug make the +4 and +7 clock options more likely, namely, likely having two pointers loaded at the same time. (the other possibilities are that an STS was followed immediately by a write to a pre-staged pointer to a low address. There are two other theoretical ways, but they're extreme contrivances involving writes to the page write buffer aimed at the last page that then either displace or postincrement to roll over the address. Writing to the page buffer and then the VPORTs like that does not maintain reasonable doubt - the only reason to do that is in order to manifest this bug.

I can think of two ways that real code could encounter these, and neither of them demonstrate good coding practices:
1. If you are trying to get clever about converting some sort of pin identifier scheme, where you associate a number with each pin wherein the three low bits are the bit position, and you end up with the port number in bits 5-7 (so you would mov the pin identifier to the low byte of the Y or Z register, ANDI with 0xE0. That's your PORTx base register, and it's easy to trick yourself into thinking that swapping the nybbles, left shifting once, and ANDI'ing with 0x1F is a fast and efficient way to access the pins via the VPORTS. It's actually not favored if you already have the pointer to the PORT struct assembled - in fact, it's not favored period, ever - unless you're doing it toget rid of the lookup tables. The key problem is that OUT and CBI/SBI only work when the IO register, and bit or working register, are compile time known - which they're not if you've got some identifier scheme that you're decoding!), and you would specifically have to set the PORTx registers (likely PORTx.PINnCTRL) before the VPORT register in order to manifest this bug. But once you have that PORTx base pointer, it's faster to so you shouldn't be doing this! Generally you don't want to use the VPORT registers like this.
Expand Down
2 changes: 1 addition & 1 deletion megaavr/extras/Ref_Differences.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Differences between megaTinyCore and stock core
We generally try to honor the Arduino API. Occasionally that is impractical. In some cases we are just explicitly stating what was true of the Arduino stock cores, but never acknowledged.

## Intended cases where behavior differes from official cores:
## Intended cases where behavior differs from official cores:
While we generally make an effort to emulate the official Arduino core, there are a few cases where the decision was made to have different behavior to avoid compromising the overall functionality; the official core is disappointing on many levels. The following is a (hopefully nearly complete) list of these cases.

### I2C **Requires** External Pullup Resistors
Expand Down
Loading

0 comments on commit 44e561b

Please sign in to comment.