1919 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2020*/
2121
22- #include < stdint.h >
23- #include < string.h >
22+ #include < cstdint >
23+ #include < cstring >
2424
2525// register names
2626#include " esp8266_peri.h"
@@ -43,35 +43,76 @@ namespace experimental {
4343 * Kept in a separate function to aid with precaching
4444 * PRECACHE_* saves having to make the function IRAM_ATTR.
4545 *
46- * spiIfNum needs to be volatile to keep the optimiser from
47- * deciding it can be treated as a constant (due to this being a
48- * static function only called with spiIfNum set to 0)
49- *
5046 * Note: if porting to ESP32 mosi/miso bits are set in 2 registers, not 1.
5147 */
48+
49+ #define PRELOAD_DST (DST,SRC )\
50+ __asm__ __volatile__ (\
51+ " mov %0, %1\n\t " \
52+ : " =r" (DST)\
53+ : "r"(SRC)\
54+ : "memory")
55+
56+ #define PRELOAD_IMMEDIATE (DST,SRC )\
57+ uint32_t DST;\
58+ __asm__ __volatile__ (\
59+ " movi %0, %1\n\t " \
60+ : " =r" (DST)\
61+ : "i"(SRC)\
62+ : "memory")
63+
64+ #define PRELOAD_VAR (DST,SRC )\
65+ decltype (SRC) DST;\
66+ PRELOAD_DST (DST,SRC)
67+
68+ #define PRELOAD_FUNC (DST,SRC )\
69+ decltype (&SRC) DST;\
70+ PRELOAD_DST (DST,SRC)
71+
5272static SpiOpResult PRECACHE_ATTR
53- _SPICommand (volatile uint32_t spiIfNum,
54- uint32_t spic,uint32_t spiu,uint32_t spiu1,uint32_t spiu2,
55- uint32_t *data,uint32_t writeWords,uint32_t readWords, uint32_t pre_cmd )
73+ _SPICommand (uint32_t spiIfNum,
74+ uint32_t spic, uint32_t spiu, uint32_t spiu1, uint32_t spiu2,
75+ uint32_t *data, uint32_t writeWords, uint32_t readWords, uint32_t _pre_cmd )
5676{
5777 if (spiIfNum>1 )
5878 return SPI_RESULT_ERR;
5979
60- // force SPI register access via base+offset.
61- // Prevents loading individual address constants from flash.
62- uint32_t *spibase = (uint32_t *)(spiIfNum ? &(SPI1CMD) : &(SPI0CMD));
63- #define SPIREG (reg ) (*((volatile uint32_t *)(spibase+(&(reg) - &(SPI0CMD)))))
80+ // force SPI register access via base+offset by deconstructing SPI# access macros
81+ // note that the function below only ever calls this one w/ spiIfNum==0
82+ // in case it is *really* necessary, preload spiIfNum as well
83+ #define VOLATILE_PTR (X ) reinterpret_cast <volatile uint32_t *>(X)
84+ #define SPIADDR (X ) const_cast <uint32_t *>(&(X))
85+
86+ // preload all required constants and functions into variables.
87+ // when modifying code below, always double-check the asm output
88+
89+ PRELOAD_IMMEDIATE (spi0cmd_addr, SPIADDR (SPI0CMD));
90+ PRELOAD_IMMEDIATE (spi1cmd_addr, SPIADDR (SPI1CMD));
91+ uint32_t *spibase = spiIfNum
92+ ? reinterpret_cast <uint32_t *>(spi1cmd_addr)
93+ : reinterpret_cast <uint32_t *>(spi0cmd_addr);
94+ #define SPIREG (reg ) \
95+ (*VOLATILE_PTR (spibase + (SPIADDR (reg) - SPIADDR (SPI0CMD))))
96+
97+ PRELOAD_FUNC (SPI_write_enablep, SPI_write_enable);
98+ PRELOAD_FUNC (Wait_SPI_Idlep, Wait_SPI_Idle);
99+
100+ PRELOAD_VAR (fchip, flashchip);
101+
102+ PRELOAD_IMMEDIATE (spicmdusr, SPICMDUSR);
103+ PRELOAD_IMMEDIATE (saved_ps, 0 );
104+
105+ // also force 'pre_cmd' & 'spiu' mask constant to be loaded right now
106+ // (TODO write all of the preamble in asm directly?)
107+ PRELOAD_VAR (pre_cmd, _pre_cmd);
64108
65- // preload any constants and functions we need into variables
66- // Everything defined here must be volatile or the optimizer can
67- // treat them as constants, resulting in the flash reads we're
68- // trying to avoid
69- SpiFlashOpResult (* volatile SPI_write_enablep)(SpiFlashChip *) = SPI_write_enable;
70- uint32_t (* volatile Wait_SPI_Idlep)(SpiFlashChip *) = Wait_SPI_Idle;
71- volatile SpiFlashChip *fchip=flashchip;
72- volatile uint32_t spicmdusr=SPICMDUSR;
109+ PRELOAD_IMMEDIATE (pre_cmd_spiu_mask, ~(SPIUMOSI | SPIUMISO));
110+ uint32_t _pre_cmd_spiu = spiu & pre_cmd_spiu_mask;
111+ PRELOAD_VAR (pre_cmd_spiu, _pre_cmd_spiu);
73112
74- uint32_t saved_ps=0 ;
113+ PRELOAD_IMMEDIATE (pre_cmd_spiu2_mask, ~0xFFFFu );
114+ uint32_t _pre_cmd_spiu2 = (spiu2 & pre_cmd_spiu2_mask) | pre_cmd;
115+ PRELOAD_VAR (pre_cmd_spiu2, _pre_cmd_spiu2);
75116
76117 if (!spiIfNum) {
77118 // Only need to disable interrupts and precache when using SPI0
@@ -91,12 +132,11 @@ _SPICommand(volatile uint32_t spiIfNum,
91132 if (SPI_FLASH_CMD_WREN == pre_cmd) {
92133 // See SPI_write_enable comments in esp8266_undocumented.h
93134 SPI_write_enablep ((SpiFlashChip *)fchip);
94- } else
95- if (pre_cmd) {
135+ } else if (pre_cmd) {
96136 // Send prefix cmd w/o data - sends 8 bits. eg. Volatile SR Write Enable, 0x50
97- SPIREG (SPI0U) = (spiu & ~(SPIUMOSI|SPIUMISO)) ;
137+ SPIREG (SPI0U) = pre_cmd_spiu ;
98138 SPIREG (SPI0U1) = 0 ;
99- SPIREG (SPI0U2) = (spiu2 & ~ 0xFFFFu ) | pre_cmd ;
139+ SPIREG (SPI0U2) = pre_cmd_spiu2 ;
100140
101141 SPIREG (SPI0CMD) = spicmdusr; // Send cmd
102142 while ((SPIREG (SPI0CMD) & spicmdusr));
0 commit comments