19
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
20
*/
21
21
22
- #include < stdint.h >
23
- #include < string.h >
22
+ #include < cstdint >
23
+ #include < cstring >
24
24
25
25
// register names
26
26
#include " esp8266_peri.h"
@@ -43,35 +43,76 @@ namespace experimental {
43
43
* Kept in a separate function to aid with precaching
44
44
* PRECACHE_* saves having to make the function IRAM_ATTR.
45
45
*
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
- *
50
46
* Note: if porting to ESP32 mosi/miso bits are set in 2 registers, not 1.
51
47
*/
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
+
52
72
static 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 )
56
76
{
57
77
if (spiIfNum>1 )
58
78
return SPI_RESULT_ERR;
59
79
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);
64
108
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);
73
112
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);
75
116
76
117
if (!spiIfNum) {
77
118
// Only need to disable interrupts and precache when using SPI0
@@ -91,12 +132,11 @@ _SPICommand(volatile uint32_t spiIfNum,
91
132
if (SPI_FLASH_CMD_WREN == pre_cmd) {
92
133
// See SPI_write_enable comments in esp8266_undocumented.h
93
134
SPI_write_enablep ((SpiFlashChip *)fchip);
94
- } else
95
- if (pre_cmd) {
135
+ } else if (pre_cmd) {
96
136
// 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 ;
98
138
SPIREG (SPI0U1) = 0 ;
99
- SPIREG (SPI0U2) = (spiu2 & ~ 0xFFFFu ) | pre_cmd ;
139
+ SPIREG (SPI0U2) = pre_cmd_spiu2 ;
100
140
101
141
SPIREG (SPI0CMD) = spicmdusr; // Send cmd
102
142
while ((SPIREG (SPI0CMD) & spicmdusr));
0 commit comments