ulp.h 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  1. // Copyright 2016-2018 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #pragma once
  15. #include <stdint.h>
  16. #include <stddef.h>
  17. #include <stdlib.h>
  18. #include "esp_err.h"
  19. #include "soc/soc.h"
  20. #include "ulp_common.h"
  21. #ifdef __cplusplus
  22. extern "C" {
  23. #endif
  24. #define ULP_FSM_PREPARE_SLEEP_CYCLES 2 /*!< Cycles spent by FSM preparing ULP for sleep */
  25. #define ULP_FSM_WAKEUP_SLEEP_CYCLES 2 /*!< Cycles spent by FSM waking up ULP from sleep */
  26. /**
  27. * @defgroup ulp_registers ULP coprocessor registers
  28. * @{
  29. */
  30. #define R0 0 /*!< general purpose register 0 */
  31. #define R1 1 /*!< general purpose register 1 */
  32. #define R2 2 /*!< general purpose register 2 */
  33. #define R3 3 /*!< general purpose register 3 */
  34. /**@}*/
  35. /** @defgroup ulp_opcodes ULP coprocessor opcodes, sub opcodes, and various modifiers/flags
  36. *
  37. * These definitions are not intended to be used directly.
  38. * They are used in definitions of instructions later on.
  39. *
  40. * @{
  41. */
  42. #define OPCODE_WR_REG 1 /*!< Instruction: write peripheral register (RTC_CNTL/RTC_IO/SARADC) */
  43. #define OPCODE_RD_REG 2 /*!< Instruction: read peripheral register (RTC_CNTL/RTC_IO/SARADC) */
  44. #define RD_REG_PERIPH_RTC_CNTL 0 /*!< Identifier of RTC_CNTL peripheral for RD_REG and WR_REG instructions */
  45. #define RD_REG_PERIPH_RTC_IO 1 /*!< Identifier of RTC_IO peripheral for RD_REG and WR_REG instructions */
  46. #define RD_REG_PERIPH_SENS 2 /*!< Identifier of SARADC peripheral for RD_REG and WR_REG instructions */
  47. #define RD_REG_PERIPH_RTC_I2C 3 /*!< Identifier of RTC_I2C peripheral for RD_REG and WR_REG instructions */
  48. #define OPCODE_I2C 3 /*!< Instruction: read/write I2C */
  49. #define SUB_OPCODE_I2C_RD 0 /*!< I2C read */
  50. #define SUB_OPCODE_I2C_WR 1 /*!< I2C write */
  51. #define OPCODE_DELAY 4 /*!< Instruction: delay (nop) for a given number of cycles */
  52. #define OPCODE_ADC 5 /*!< Instruction: SAR ADC measurement */
  53. #define OPCODE_ST 6 /*!< Instruction: store indirect to RTC memory */
  54. #define SUB_OPCODE_ST 4 /*!< Store 32 bits, 16 MSBs contain PC, 16 LSBs contain value from source register */
  55. #define OPCODE_ALU 7 /*!< Arithmetic instructions */
  56. #define SUB_OPCODE_ALU_REG 0 /*!< Arithmetic instruction, both source values are in register */
  57. #define SUB_OPCODE_ALU_IMM 1 /*!< Arithmetic instruction, one source value is an immediate */
  58. #define SUB_OPCODE_ALU_CNT 2 /*!< Arithmetic instruction, stage counter and an immediate */
  59. #define ALU_SEL_ADD 0 /*!< Addition */
  60. #define ALU_SEL_SUB 1 /*!< Subtraction */
  61. #define ALU_SEL_AND 2 /*!< Logical AND */
  62. #define ALU_SEL_OR 3 /*!< Logical OR */
  63. #define ALU_SEL_MOV 4 /*!< Copy value (immediate to destination register or source register to destination register */
  64. #define ALU_SEL_LSH 5 /*!< Shift left by given number of bits */
  65. #define ALU_SEL_RSH 6 /*!< Shift right by given number of bits */
  66. #define ALU_SEL_SINC 0 /*!< Increment the stage counter */
  67. #define ALU_SEL_SDEC 1 /*!< Decrement the stage counter */
  68. #define ALU_SEL_SRST 2 /*!< Reset the stage counter */
  69. #define OPCODE_BRANCH 8 /*!< Branch instructions */
  70. #define SUB_OPCODE_BX 0 /*!< Branch to absolute PC (immediate or in register) */
  71. #define SUB_OPCODE_BR 1 /*!< Branch to relative PC, conditional on R0 */
  72. #define SUB_OPCODE_BS 2 /*!< Branch to relative PC, conditional on the stage counter */
  73. #define BX_JUMP_TYPE_DIRECT 0 /*!< Unconditional jump */
  74. #define BX_JUMP_TYPE_ZERO 1 /*!< Branch if last ALU result is zero */
  75. #define BX_JUMP_TYPE_OVF 2 /*!< Branch if last ALU operation caused and overflow */
  76. #define SUB_OPCODE_B 1 /*!< Branch to a relative offset */
  77. #define B_CMP_L 0 /*!< Branch if R0 is less than an immediate */
  78. #define B_CMP_GE 1 /*!< Branch if R0 is greater than or equal to an immediate */
  79. #define JUMPS_LT 0 /*!< Branch if the stage counter < */
  80. #define JUMPS_GE 1 /*!< Branch if the stage counter >= */
  81. #define JUMPS_LE 2 /*!< Branch if the stage counter <= */
  82. #define OPCODE_END 9 /*!< Stop executing the program */
  83. #define SUB_OPCODE_END 0 /*!< Stop executing the program and optionally wake up the chip */
  84. #define SUB_OPCODE_SLEEP 1 /*!< Stop executing the program and run it again after selected interval */
  85. #define OPCODE_TSENS 10 /*!< Instruction: temperature sensor measurement */
  86. #define OPCODE_HALT 11 /*!< Halt the coprocessor */
  87. #define OPCODE_LD 13 /*!< Indirect load lower 16 bits from RTC memory */
  88. #define OPCODE_MACRO 15 /*!< Not a real opcode. Used to identify labels and branches in the program */
  89. #define SUB_OPCODE_MACRO_LABEL 0 /*!< Label macro */
  90. #define SUB_OPCODE_MACRO_BRANCH 1 /*!< Branch macro */
  91. #define SUB_OPCODE_MACRO_LABELPC 2 /*!< Label pointer macro */
  92. /**@}*/
  93. /**
  94. * @brief Instruction format structure
  95. *
  96. * All ULP instructions are 32 bit long.
  97. * This union contains field layouts used by all of the supported instructions.
  98. * This union also includes a special "macro" instruction layout.
  99. * This is not a real instruction which can be executed by the CPU. It acts
  100. * as a token which is removed from the program by the
  101. * ulp_process_macros_and_load function.
  102. *
  103. * These structures are not intended to be used directly.
  104. * Preprocessor definitions provided below fill the fields of these structure with
  105. * the right arguments.
  106. */
  107. union ulp_insn {
  108. struct {
  109. uint32_t cycles : 16; /*!< Number of cycles to sleep */
  110. uint32_t unused : 12; /*!< Unused */
  111. uint32_t opcode : 4; /*!< Opcode (OPCODE_DELAY) */
  112. } delay; /*!< Format of DELAY instruction */
  113. struct {
  114. uint32_t dreg : 2; /*!< Register which contains data to store */
  115. uint32_t sreg : 2; /*!< Register which contains address in RTC memory (expressed in words) */
  116. uint32_t unused1 : 6; /*!< Unused */
  117. uint32_t offset : 11; /*!< Offset to add to sreg */
  118. uint32_t unused2 : 4; /*!< Unused */
  119. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_ST) */
  120. uint32_t opcode : 4; /*!< Opcode (OPCODE_ST) */
  121. } st; /*!< Format of ST instruction */
  122. struct {
  123. uint32_t dreg : 2; /*!< Register where the data should be loaded to */
  124. uint32_t sreg : 2; /*!< Register which contains address in RTC memory (expressed in words) */
  125. uint32_t unused1 : 6; /*!< Unused */
  126. uint32_t offset : 11; /*!< Offset to add to sreg */
  127. uint32_t unused2 : 7; /*!< Unused */
  128. uint32_t opcode : 4; /*!< Opcode (OPCODE_LD) */
  129. } ld; /*!< Format of LD instruction */
  130. struct {
  131. uint32_t unused : 28; /*!< Unused */
  132. uint32_t opcode : 4; /*!< Opcode (OPCODE_HALT) */
  133. } halt; /*!< Format of HALT instruction */
  134. struct {
  135. uint32_t dreg : 2; /*!< Register which contains target PC, expressed in words (used if .reg == 1) */
  136. uint32_t addr : 11; /*!< Target PC, expressed in words (used if .reg == 0) */
  137. uint32_t unused : 8; /*!< Unused */
  138. uint32_t reg : 1; /*!< Target PC in register (1) or immediate (0) */
  139. uint32_t type : 3; /*!< Jump condition (BX_JUMP_TYPE_xxx) */
  140. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_BX) */
  141. uint32_t opcode : 4; /*!< Opcode (OPCODE_BRANCH) */
  142. } bx; /*!< Format of BRANCH instruction (absolute address) */
  143. struct {
  144. uint32_t imm : 16; /*!< Immediate value to compare against */
  145. uint32_t cmp : 1; /*!< Comparison to perform: B_CMP_L or B_CMP_GE */
  146. uint32_t offset : 7; /*!< Absolute value of target PC offset w.r.t. current PC, expressed in words */
  147. uint32_t sign : 1; /*!< Sign of target PC offset: 0: positive, 1: negative */
  148. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_B) */
  149. uint32_t opcode : 4; /*!< Opcode (OPCODE_BRANCH) */
  150. } b; /*!< Format of BRANCH instruction (relative address, conditional on R0) */
  151. struct {
  152. uint32_t imm : 8; /*!< Immediate value to compare against */
  153. uint32_t unused : 7; /*!< Unused */
  154. uint32_t cmp : 2; /*!< Comparison to perform: JUMPS_LT, JUMPS_GE or JUMPS_LE */
  155. uint32_t offset : 7; /*!< Absolute value of target PC offset w.r.t. current PC, expressed in words */
  156. uint32_t sign : 1; /*!< Sign of target PC offset: 0: positive, 1: negative */
  157. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_BS) */
  158. uint32_t opcode : 4; /*!< Opcode (OPCODE_BRANCH) */
  159. } bs; /*!< Format of BRANCH instruction (relative address, conditional on the stage counter) */
  160. struct {
  161. uint32_t dreg : 2; /*!< Destination register */
  162. uint32_t sreg : 2; /*!< Register with operand A */
  163. uint32_t treg : 2; /*!< Register with operand B */
  164. uint32_t unused : 15; /*!< Unused */
  165. uint32_t sel : 4; /*!< Operation to perform, one of ALU_SEL_xxx */
  166. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_ALU_REG) */
  167. uint32_t opcode : 4; /*!< Opcode (OPCODE_ALU) */
  168. } alu_reg; /*!< Format of ALU instruction (both sources are registers) */
  169. struct {
  170. uint32_t unused1 : 4; /*!< Unused */
  171. uint32_t imm : 8; /*!< Immediate value of operand */
  172. uint32_t unused2 : 9; /*!< Unused */
  173. uint32_t sel : 4; /*!< Operation to perform, one of ALU_SEL_Sxxx */
  174. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_ALU_CNT) */
  175. uint32_t opcode : 4; /*!< Opcode (OPCODE_ALU) */
  176. } alu_reg_s; /*!< Format of ALU instruction (stage counter and an immediate) */
  177. struct {
  178. uint32_t dreg : 2; /*!< Destination register */
  179. uint32_t sreg : 2; /*!< Register with operand A */
  180. uint32_t imm : 16; /*!< Immediate value of operand B */
  181. uint32_t unused : 1; /*!< Unused */
  182. uint32_t sel : 4; /*!< Operation to perform, one of ALU_SEL_xxx */
  183. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_ALU_IMM) */
  184. uint32_t opcode : 4; /*!< Opcode (OPCODE_ALU) */
  185. } alu_imm; /*!< Format of ALU instruction (one source is an immediate) */
  186. struct {
  187. uint32_t addr : 8; /*!< Address within either RTC_CNTL, RTC_IO, or SARADC */
  188. uint32_t periph_sel : 2; /*!< Select peripheral: RTC_CNTL (0), RTC_IO(1), SARADC(2) */
  189. uint32_t data : 8; /*!< 8 bits of data to write */
  190. uint32_t low : 5; /*!< Low bit */
  191. uint32_t high : 5; /*!< High bit */
  192. uint32_t opcode : 4; /*!< Opcode (OPCODE_WR_REG) */
  193. } wr_reg; /*!< Format of WR_REG instruction */
  194. struct {
  195. uint32_t addr : 8; /*!< Address within either RTC_CNTL, RTC_IO, or SARADC */
  196. uint32_t periph_sel : 2; /*!< Select peripheral: RTC_CNTL (0), RTC_IO(1), SARADC(2) */
  197. uint32_t unused : 8; /*!< Unused */
  198. uint32_t low : 5; /*!< Low bit */
  199. uint32_t high : 5; /*!< High bit */
  200. uint32_t opcode : 4; /*!< Opcode (OPCODE_RD_REG) */
  201. } rd_reg; /*!< Format of RD_REG instruction */
  202. struct {
  203. uint32_t dreg : 2; /*!< Register where to store ADC result */
  204. uint32_t mux : 4; /*!< Select SARADC pad (mux + 1) */
  205. uint32_t sar_sel : 1; /*!< Select SARADC0 (0) or SARADC1 (1) */
  206. uint32_t unused1 : 1; /*!< Unused */
  207. uint32_t cycles : 16; /*!< TBD, cycles used for measurement */
  208. uint32_t unused2 : 4; /*!< Unused */
  209. uint32_t opcode: 4; /*!< Opcode (OPCODE_ADC) */
  210. } adc; /*!< Format of ADC instruction */
  211. struct {
  212. uint32_t dreg : 2; /*!< Register where to store temperature measurement result */
  213. uint32_t wait_delay: 14; /*!< Cycles to wait after measurement is done */
  214. uint32_t reserved: 12; /*!< Reserved, set to 0 */
  215. uint32_t opcode: 4; /*!< Opcode (OPCODE_TSENS) */
  216. } tsens; /*!< Format of TSENS instruction */
  217. struct {
  218. uint32_t i2c_addr : 8; /*!< I2C slave address */
  219. uint32_t data : 8; /*!< 8 bits of data for write operation */
  220. uint32_t low_bits : 3; /*!< low bit of range for write operation (lower bits are masked) */
  221. uint32_t high_bits : 3; /*!< high bit of range for write operation (higher bits are masked) */
  222. uint32_t i2c_sel : 4; /*!< index of slave address register [7:0] */
  223. uint32_t unused : 1; /*!< Unused */
  224. uint32_t rw : 1; /*!< Write (1) or read (0) */
  225. uint32_t opcode : 4; /*!< Opcode (OPCODE_I2C) */
  226. } i2c; /*!< Format of I2C instruction */
  227. struct {
  228. uint32_t wakeup : 1; /*!< Set to 1 to wake up chip */
  229. uint32_t unused : 24; /*!< Unused */
  230. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_WAKEUP) */
  231. uint32_t opcode : 4; /*!< Opcode (OPCODE_END) */
  232. } end; /*!< Format of END instruction with wakeup */
  233. struct {
  234. uint32_t cycle_sel : 4; /*!< Select which one of SARADC_ULP_CP_SLEEP_CYCx_REG to get the sleep duration from */
  235. uint32_t unused : 21; /*!< Unused */
  236. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_SLEEP) */
  237. uint32_t opcode : 4; /*!< Opcode (OPCODE_END) */
  238. } sleep; /*!< Format of END instruction with sleep */
  239. struct {
  240. uint32_t dreg : 2; /*!< Destination register (for SUB_OPCODE_MACRO_LABELPC) > */
  241. uint32_t label : 16; /*!< Label number */
  242. uint32_t unused : 6; /*!< Unused */
  243. uint32_t sub_opcode : 4; /*!< SUB_OPCODE_MACRO_LABEL or SUB_OPCODE_MACRO_BRANCH or SUB_OPCODE_MACRO_LABELPC */
  244. uint32_t opcode: 4; /*!< Opcode (OPCODE_MACRO) */
  245. } macro; /*!< Format of tokens used by MACROs */
  246. uint32_t instruction; /*!< Encoded instruction for ULP coprocessor */
  247. };
  248. typedef union ulp_insn ulp_insn_t;
  249. _Static_assert(sizeof(ulp_insn_t) == 4, "ULP coprocessor instruction size should be 4 bytes");
  250. /**
  251. * Delay (nop) for a given number of cycles
  252. */
  253. #define I_DELAY(cycles_) { .delay = {\
  254. .cycles = cycles_, \
  255. .unused = 0, \
  256. .opcode = OPCODE_DELAY } }
  257. /**
  258. * Halt the coprocessor.
  259. *
  260. * This instruction halts the coprocessor, but keeps ULP timer active.
  261. * As such, ULP program will be restarted again by timer.
  262. * To stop the program and prevent the timer from restarting the program,
  263. * use I_END(0) instruction.
  264. */
  265. #define I_HALT() { .halt = {\
  266. .unused = 0, \
  267. .opcode = OPCODE_HALT } }
  268. /**
  269. * Map SoC peripheral register to periph_sel field of RD_REG and WR_REG
  270. * instructions.
  271. *
  272. * @param reg peripheral register in RTC_CNTL_, RTC_IO_, SENS_, RTC_I2C peripherals.
  273. * @return periph_sel value for the peripheral to which this register belongs.
  274. */
  275. static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
  276. uint32_t ret = 3;
  277. if (reg < DR_REG_RTCCNTL_BASE) {
  278. assert(0 && "invalid register base");
  279. } else if (reg < DR_REG_RTCIO_BASE) {
  280. ret = RD_REG_PERIPH_RTC_CNTL;
  281. } else if (reg < DR_REG_SENS_BASE) {
  282. ret = RD_REG_PERIPH_RTC_IO;
  283. } else if (reg < DR_REG_RTC_I2C_BASE){
  284. ret = RD_REG_PERIPH_SENS;
  285. } else if (reg < DR_REG_IO_MUX_BASE){
  286. ret = RD_REG_PERIPH_RTC_I2C;
  287. } else {
  288. assert(0 && "invalid register base");
  289. }
  290. return ret;
  291. }
  292. /**
  293. * Write literal value to a peripheral register
  294. *
  295. * reg[high_bit : low_bit] = val
  296. * This instruction can access RTC_CNTL_, RTC_IO_, SENS_, and RTC_I2C peripheral registers.
  297. */
  298. #define I_WR_REG(reg, low_bit, high_bit, val) {.wr_reg = {\
  299. .addr = (reg & 0xff) / sizeof(uint32_t), \
  300. .periph_sel = SOC_REG_TO_ULP_PERIPH_SEL(reg), \
  301. .data = val, \
  302. .low = low_bit, \
  303. .high = high_bit, \
  304. .opcode = OPCODE_WR_REG } }
  305. /**
  306. * Read from peripheral register into R0
  307. *
  308. * R0 = reg[high_bit : low_bit]
  309. * This instruction can access RTC_CNTL_, RTC_IO_, SENS_, and RTC_I2C peripheral registers.
  310. */
  311. #define I_RD_REG(reg, low_bit, high_bit) {.rd_reg = {\
  312. .addr = (reg & 0xff) / sizeof(uint32_t), \
  313. .periph_sel = SOC_REG_TO_ULP_PERIPH_SEL(reg), \
  314. .unused = 0, \
  315. .low = low_bit, \
  316. .high = high_bit, \
  317. .opcode = OPCODE_RD_REG } }
  318. /**
  319. * Set or clear a bit in the peripheral register.
  320. *
  321. * Sets bit (1 << shift) of register reg to value val.
  322. * This instruction can access RTC_CNTL_, RTC_IO_, SENS_, and RTC_I2C peripheral registers.
  323. */
  324. #define I_WR_REG_BIT(reg, shift, val) I_WR_REG(reg, shift, shift, val)
  325. /**
  326. * Wake the SoC from deep sleep.
  327. *
  328. * This instruction initiates wake up from deep sleep.
  329. * Use esp_deep_sleep_enable_ulp_wakeup to enable deep sleep wakeup
  330. * triggered by the ULP before going into deep sleep.
  331. * Note that ULP program will still keep running until the I_HALT
  332. * instruction, and it will still be restarted by timer at regular
  333. * intervals, even when the SoC is woken up.
  334. *
  335. * To stop the ULP program, use I_HALT instruction.
  336. *
  337. * To disable the timer which start ULP program, use I_END()
  338. * instruction. I_END instruction clears the
  339. * RTC_CNTL_ULP_CP_SLP_TIMER_EN_S bit of RTC_CNTL_STATE0_REG
  340. * register, which controls the ULP timer.
  341. */
  342. #define I_WAKE() { .end = { \
  343. .wakeup = 1, \
  344. .unused = 0, \
  345. .sub_opcode = SUB_OPCODE_END, \
  346. .opcode = OPCODE_END } }
  347. /**
  348. * Stop ULP program timer.
  349. *
  350. * This is a convenience macro which disables the ULP program timer.
  351. * Once this instruction is used, ULP program will not be restarted
  352. * anymore until ulp_run function is called.
  353. *
  354. * ULP program will continue running after this instruction. To stop
  355. * the currently running program, use I_HALT().
  356. */
  357. #define I_END() \
  358. I_WR_REG_BIT(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN_S, 0)
  359. /**
  360. * Select the time interval used to run ULP program.
  361. *
  362. * This instructions selects which of the SENS_SLEEP_CYCLES_Sx
  363. * registers' value is used by the ULP program timer.
  364. * When the ULP program stops at I_HALT instruction, ULP program
  365. * timer start counting. When the counter reaches the value of
  366. * the selected SENS_SLEEP_CYCLES_Sx register, ULP program
  367. * start running again from the start address (passed to the ulp_run
  368. * function).
  369. * There are 5 SENS_SLEEP_CYCLES_Sx registers, so 0 <= timer_idx < 5.
  370. *
  371. * By default, SENS_SLEEP_CYCLES_S0 register is used by the ULP
  372. * program timer.
  373. */
  374. #define I_SLEEP_CYCLE_SEL(timer_idx) { .sleep = { \
  375. .cycle_sel = timer_idx, \
  376. .unused = 0, \
  377. .sub_opcode = SUB_OPCODE_SLEEP, \
  378. .opcode = OPCODE_END } }
  379. /**
  380. * Perform temperature sensor measurement and store it into reg_dest.
  381. *
  382. * Delay can be set between 1 and ((1 << 14) - 1). Higher values give
  383. * higher measurement resolution.
  384. */
  385. #define I_TSENS(reg_dest, delay) { .tsens = { \
  386. .dreg = reg_dest, \
  387. .wait_delay = delay, \
  388. .reserved = 0, \
  389. .opcode = OPCODE_TSENS } }
  390. /**
  391. * Perform ADC measurement and store result in reg_dest.
  392. *
  393. * adc_idx selects ADC (0 or 1).
  394. * pad_idx selects ADC pad (0 - 7).
  395. */
  396. #define I_ADC(reg_dest, adc_idx, pad_idx) { .adc = {\
  397. .dreg = reg_dest, \
  398. .mux = pad_idx + 1, \
  399. .sar_sel = adc_idx, \
  400. .unused1 = 0, \
  401. .cycles = 0, \
  402. .unused2 = 0, \
  403. .opcode = OPCODE_ADC } }
  404. /**
  405. * Store value from register reg_val into RTC memory.
  406. *
  407. * The value is written to an offset calculated by adding value of
  408. * reg_addr register and offset_ field (this offset is expressed in 32-bit words).
  409. * 32 bits written to RTC memory are built as follows:
  410. * - bits [31:21] hold the PC of current instruction, expressed in 32-bit words
  411. * - bits [20:16] = 5'b1
  412. * - bits [15:0] are assigned the contents of reg_val
  413. *
  414. * RTC_SLOW_MEM[addr + offset_] = { 5'b0, insn_PC[10:0], val[15:0] }
  415. */
  416. #define I_ST(reg_val, reg_addr, offset_) { .st = { \
  417. .dreg = reg_val, \
  418. .sreg = reg_addr, \
  419. .unused1 = 0, \
  420. .offset = offset_, \
  421. .unused2 = 0, \
  422. .sub_opcode = SUB_OPCODE_ST, \
  423. .opcode = OPCODE_ST } }
  424. /**
  425. * Load value from RTC memory into reg_dest register.
  426. *
  427. * Loads 16 LSBs from RTC memory word given by the sum of value in reg_addr and
  428. * value of offset_.
  429. */
  430. #define I_LD(reg_dest, reg_addr, offset_) { .ld = { \
  431. .dreg = reg_dest, \
  432. .sreg = reg_addr, \
  433. .unused1 = 0, \
  434. .offset = offset_, \
  435. .unused2 = 0, \
  436. .opcode = OPCODE_LD } }
  437. /**
  438. * Branch relative if R0 less than immediate value.
  439. *
  440. * pc_offset is expressed in words, and can be from -127 to 127
  441. * imm_value is a 16-bit value to compare R0 against
  442. */
  443. #define I_BL(pc_offset, imm_value) { .b = { \
  444. .imm = imm_value, \
  445. .cmp = B_CMP_L, \
  446. .offset = abs(pc_offset), \
  447. .sign = (pc_offset >= 0) ? 0 : 1, \
  448. .sub_opcode = SUB_OPCODE_B, \
  449. .opcode = OPCODE_BRANCH } }
  450. /**
  451. * Branch relative if R0 greater or equal than immediate value.
  452. *
  453. * pc_offset is expressed in words, and can be from -127 to 127
  454. * imm_value is a 16-bit value to compare R0 against
  455. */
  456. #define I_BGE(pc_offset, imm_value) { .b = { \
  457. .imm = imm_value, \
  458. .cmp = B_CMP_GE, \
  459. .offset = abs(pc_offset), \
  460. .sign = (pc_offset >= 0) ? 0 : 1, \
  461. .sub_opcode = SUB_OPCODE_B, \
  462. .opcode = OPCODE_BRANCH } }
  463. /**
  464. * Unconditional branch to absolute PC, address in register.
  465. *
  466. * reg_pc is the register which contains address to jump to.
  467. * Address is expressed in 32-bit words.
  468. */
  469. #define I_BXR(reg_pc) { .bx = { \
  470. .dreg = reg_pc, \
  471. .addr = 0, \
  472. .unused = 0, \
  473. .reg = 1, \
  474. .type = BX_JUMP_TYPE_DIRECT, \
  475. .sub_opcode = SUB_OPCODE_BX, \
  476. .opcode = OPCODE_BRANCH } }
  477. /**
  478. * Unconditional branch to absolute PC, immediate address.
  479. *
  480. * Address imm_pc is expressed in 32-bit words.
  481. */
  482. #define I_BXI(imm_pc) { .bx = { \
  483. .dreg = 0, \
  484. .addr = imm_pc, \
  485. .unused = 0, \
  486. .reg = 0, \
  487. .type = BX_JUMP_TYPE_DIRECT, \
  488. .sub_opcode = SUB_OPCODE_BX, \
  489. .opcode = OPCODE_BRANCH } }
  490. /**
  491. * Branch to absolute PC if ALU result is zero, address in register.
  492. *
  493. * reg_pc is the register which contains address to jump to.
  494. * Address is expressed in 32-bit words.
  495. */
  496. #define I_BXZR(reg_pc) { .bx = { \
  497. .dreg = reg_pc, \
  498. .addr = 0, \
  499. .unused = 0, \
  500. .reg = 1, \
  501. .type = BX_JUMP_TYPE_ZERO, \
  502. .sub_opcode = SUB_OPCODE_BX, \
  503. .opcode = OPCODE_BRANCH } }
  504. /**
  505. * Branch to absolute PC if ALU result is zero, immediate address.
  506. *
  507. * Address imm_pc is expressed in 32-bit words.
  508. */
  509. #define I_BXZI(imm_pc) { .bx = { \
  510. .dreg = 0, \
  511. .addr = imm_pc, \
  512. .unused = 0, \
  513. .reg = 0, \
  514. .type = BX_JUMP_TYPE_ZERO, \
  515. .sub_opcode = SUB_OPCODE_BX, \
  516. .opcode = OPCODE_BRANCH } }
  517. /**
  518. * Branch to absolute PC if ALU overflow, address in register
  519. *
  520. * reg_pc is the register which contains address to jump to.
  521. * Address is expressed in 32-bit words.
  522. */
  523. #define I_BXFR(reg_pc) { .bx = { \
  524. .dreg = reg_pc, \
  525. .addr = 0, \
  526. .unused = 0, \
  527. .reg = 1, \
  528. .type = BX_JUMP_TYPE_OVF, \
  529. .sub_opcode = SUB_OPCODE_BX, \
  530. .opcode = OPCODE_BRANCH } }
  531. /**
  532. * Branch to absolute PC if ALU overflow, immediate address
  533. *
  534. * Address imm_pc is expressed in 32-bit words.
  535. */
  536. #define I_BXFI(imm_pc) { .bx = { \
  537. .dreg = 0, \
  538. .addr = imm_pc, \
  539. .unused = 0, \
  540. .reg = 0, \
  541. .type = BX_JUMP_TYPE_OVF, \
  542. .sub_opcode = SUB_OPCODE_BX, \
  543. .opcode = OPCODE_BRANCH } }
  544. /**
  545. * Addition: dest = src1 + src2
  546. */
  547. #define I_ADDR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  548. .dreg = reg_dest, \
  549. .sreg = reg_src1, \
  550. .treg = reg_src2, \
  551. .unused = 0, \
  552. .sel = ALU_SEL_ADD, \
  553. .sub_opcode = SUB_OPCODE_ALU_REG, \
  554. .opcode = OPCODE_ALU } }
  555. /**
  556. * Subtraction: dest = src1 - src2
  557. */
  558. #define I_SUBR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  559. .dreg = reg_dest, \
  560. .sreg = reg_src1, \
  561. .treg = reg_src2, \
  562. .unused = 0, \
  563. .sel = ALU_SEL_SUB, \
  564. .sub_opcode = SUB_OPCODE_ALU_REG, \
  565. .opcode = OPCODE_ALU } }
  566. /**
  567. * Logical AND: dest = src1 & src2
  568. */
  569. #define I_ANDR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  570. .dreg = reg_dest, \
  571. .sreg = reg_src1, \
  572. .treg = reg_src2, \
  573. .unused = 0, \
  574. .sel = ALU_SEL_AND, \
  575. .sub_opcode = SUB_OPCODE_ALU_REG, \
  576. .opcode = OPCODE_ALU } }
  577. /**
  578. * Logical OR: dest = src1 | src2
  579. */
  580. #define I_ORR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  581. .dreg = reg_dest, \
  582. .sreg = reg_src1, \
  583. .treg = reg_src2, \
  584. .unused = 0, \
  585. .sel = ALU_SEL_OR, \
  586. .sub_opcode = SUB_OPCODE_ALU_REG, \
  587. .opcode = OPCODE_ALU } }
  588. /**
  589. * Copy: dest = src
  590. */
  591. #define I_MOVR(reg_dest, reg_src) { .alu_reg = { \
  592. .dreg = reg_dest, \
  593. .sreg = reg_src, \
  594. .treg = 0, \
  595. .unused = 0, \
  596. .sel = ALU_SEL_MOV, \
  597. .sub_opcode = SUB_OPCODE_ALU_REG, \
  598. .opcode = OPCODE_ALU } }
  599. /**
  600. * Logical shift left: dest = src << shift
  601. */
  602. #define I_LSHR(reg_dest, reg_src, reg_shift) { .alu_reg = { \
  603. .dreg = reg_dest, \
  604. .sreg = reg_src, \
  605. .treg = reg_shift, \
  606. .unused = 0, \
  607. .sel = ALU_SEL_LSH, \
  608. .sub_opcode = SUB_OPCODE_ALU_REG, \
  609. .opcode = OPCODE_ALU } }
  610. /**
  611. * Logical shift right: dest = src >> shift
  612. */
  613. #define I_RSHR(reg_dest, reg_src, reg_shift) { .alu_reg = { \
  614. .dreg = reg_dest, \
  615. .sreg = reg_src, \
  616. .treg = reg_shift, \
  617. .unused = 0, \
  618. .sel = ALU_SEL_RSH, \
  619. .sub_opcode = SUB_OPCODE_ALU_REG, \
  620. .opcode = OPCODE_ALU } }
  621. /**
  622. * Add register and an immediate value: dest = src1 + imm
  623. */
  624. #define I_ADDI(reg_dest, reg_src, imm_) { .alu_imm = { \
  625. .dreg = reg_dest, \
  626. .sreg = reg_src, \
  627. .imm = imm_, \
  628. .unused = 0, \
  629. .sel = ALU_SEL_ADD, \
  630. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  631. .opcode = OPCODE_ALU } }
  632. /**
  633. * Subtract register and an immediate value: dest = src - imm
  634. */
  635. #define I_SUBI(reg_dest, reg_src, imm_) { .alu_imm = { \
  636. .dreg = reg_dest, \
  637. .sreg = reg_src, \
  638. .imm = imm_, \
  639. .unused = 0, \
  640. .sel = ALU_SEL_SUB, \
  641. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  642. .opcode = OPCODE_ALU } }
  643. /**
  644. * Logical AND register and an immediate value: dest = src & imm
  645. */
  646. #define I_ANDI(reg_dest, reg_src, imm_) { .alu_imm = { \
  647. .dreg = reg_dest, \
  648. .sreg = reg_src, \
  649. .imm = imm_, \
  650. .unused = 0, \
  651. .sel = ALU_SEL_AND, \
  652. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  653. .opcode = OPCODE_ALU } }
  654. /**
  655. * Logical OR register and an immediate value: dest = src | imm
  656. */
  657. #define I_ORI(reg_dest, reg_src, imm_) { .alu_imm = { \
  658. .dreg = reg_dest, \
  659. .sreg = reg_src, \
  660. .imm = imm_, \
  661. .unused = 0, \
  662. .sel = ALU_SEL_OR, \
  663. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  664. .opcode = OPCODE_ALU } }
  665. /**
  666. * Copy an immediate value into register: dest = imm
  667. */
  668. #define I_MOVI(reg_dest, imm_) { .alu_imm = { \
  669. .dreg = reg_dest, \
  670. .sreg = 0, \
  671. .imm = imm_, \
  672. .unused = 0, \
  673. .sel = ALU_SEL_MOV, \
  674. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  675. .opcode = OPCODE_ALU } }
  676. /**
  677. * Logical shift left register value by an immediate: dest = src << imm
  678. */
  679. #define I_LSHI(reg_dest, reg_src, imm_) { .alu_imm = { \
  680. .dreg = reg_dest, \
  681. .sreg = reg_src, \
  682. .imm = imm_, \
  683. .unused = 0, \
  684. .sel = ALU_SEL_LSH, \
  685. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  686. .opcode = OPCODE_ALU } }
  687. /**
  688. * Logical shift right register value by an immediate: dest = val >> imm
  689. */
  690. #define I_RSHI(reg_dest, reg_src, imm_) { .alu_imm = { \
  691. .dreg = reg_dest, \
  692. .sreg = reg_src, \
  693. .imm = imm_, \
  694. .unused = 0, \
  695. .sel = ALU_SEL_RSH, \
  696. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  697. .opcode = OPCODE_ALU } }
  698. /**
  699. * Define a label with number label_num.
  700. *
  701. * This is a macro which doesn't generate a real instruction.
  702. * The token generated by this macro is removed by ulp_process_macros_and_load
  703. * function. Label defined using this macro can be used in branch macros defined
  704. * below.
  705. */
  706. #define M_LABEL(label_num) { .macro = { \
  707. .dreg = 0, \
  708. .label = label_num, \
  709. .unused = 0, \
  710. .sub_opcode = SUB_OPCODE_MACRO_LABEL, \
  711. .opcode = OPCODE_MACRO } }
  712. /**
  713. * Token macro used by M_B and M_BX macros. Not to be used directly.
  714. */
  715. #define M_BRANCH(label_num) { .macro = { \
  716. .dreg = 0, \
  717. .label = label_num, \
  718. .unused = 0, \
  719. .sub_opcode = SUB_OPCODE_MACRO_BRANCH, \
  720. .opcode = OPCODE_MACRO } }
  721. /**
  722. * Token macro used by M_MOVL macro. Not to be used directly.
  723. */
  724. #define M_LABELPC(label_num) { .macro = { \
  725. .dreg = 0, \
  726. .label = label_num, \
  727. .unused = 0, \
  728. .sub_opcode = SUB_OPCODE_MACRO_LABELPC, \
  729. .opcode = OPCODE_MACRO } }
  730. /**
  731. * Macro: Move the program counter at the given label into the register.
  732. * This address can then be used with I_BXR, I_BXZR, I_BXFR, etc.
  733. *
  734. * This macro generates two ulp_insn_t values separated by a comma, and should
  735. * be used when defining contents of ulp_insn_t arrays. First value is not a
  736. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  737. * function.
  738. */
  739. #define M_MOVL(reg_dest, label_num) \
  740. M_LABELPC(label_num), \
  741. I_MOVI(reg_dest, 0)
  742. /**
  743. * Macro: branch to label label_num if R0 is less than immediate value.
  744. *
  745. * This macro generates two ulp_insn_t values separated by a comma, and should
  746. * be used when defining contents of ulp_insn_t arrays. First value is not a
  747. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  748. * function.
  749. */
  750. #define M_BL(label_num, imm_value) \
  751. M_BRANCH(label_num), \
  752. I_BL(0, imm_value)
  753. /**
  754. * Macro: branch to label label_num if R0 is greater or equal than immediate value
  755. *
  756. * This macro generates two ulp_insn_t values separated by a comma, and should
  757. * be used when defining contents of ulp_insn_t arrays. First value is not a
  758. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  759. * function.
  760. */
  761. #define M_BGE(label_num, imm_value) \
  762. M_BRANCH(label_num), \
  763. I_BGE(0, imm_value)
  764. /**
  765. * Macro: unconditional branch to label
  766. *
  767. * This macro generates two ulp_insn_t values separated by a comma, and should
  768. * be used when defining contents of ulp_insn_t arrays. First value is not a
  769. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  770. * function.
  771. */
  772. #define M_BX(label_num) \
  773. M_BRANCH(label_num), \
  774. I_BXI(0)
  775. /**
  776. * Macro: branch to label if ALU result is zero
  777. *
  778. * This macro generates two ulp_insn_t values separated by a comma, and should
  779. * be used when defining contents of ulp_insn_t arrays. First value is not a
  780. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  781. * function.
  782. */
  783. #define M_BXZ(label_num) \
  784. M_BRANCH(label_num), \
  785. I_BXZI(0)
  786. /**
  787. * Macro: branch to label if ALU overflow
  788. *
  789. * This macro generates two ulp_insn_t values separated by a comma, and should
  790. * be used when defining contents of ulp_insn_t arrays. First value is not a
  791. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  792. * function.
  793. */
  794. #define M_BXF(label_num) \
  795. M_BRANCH(label_num), \
  796. I_BXFI(0)
  797. /**
  798. * Increment the stage counter by immediate value
  799. */
  800. #define I_STAGE_INC(imm_) { .alu_reg_s = { \
  801. .unused1 = 0, \
  802. .imm = imm_, \
  803. .unused2 = 0, \
  804. .sel = ALU_SEL_SINC, \
  805. .sub_opcode = SUB_OPCODE_ALU_CNT, \
  806. .opcode = OPCODE_ALU } }
  807. /**
  808. * Decrement the stage counter by immediate value
  809. */
  810. #define I_STAGE_DEC(imm_) { .alu_reg_s = { \
  811. .unused1 = 0, \
  812. .imm = imm_, \
  813. .unused2 = 0, \
  814. .sel = ALU_SEL_SDEC, \
  815. .sub_opcode = SUB_OPCODE_ALU_CNT, \
  816. .opcode = OPCODE_ALU } }
  817. /**
  818. * Reset the stage counter
  819. */
  820. #define I_STAGE_RST() { .alu_reg_s = { \
  821. .unused1 = 0, \
  822. .imm = 0, \
  823. .unused2 = 0, \
  824. .sel = ALU_SEL_SRST, \
  825. .sub_opcode = SUB_OPCODE_ALU_CNT, \
  826. .opcode = OPCODE_ALU } }
  827. /**
  828. * Macro: branch to label if the stage counter is less than immediate value
  829. *
  830. * This macro generates two ulp_insn_t values separated by a comma, and should
  831. * be used when defining contents of ulp_insn_t arrays. First value is not a
  832. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  833. * function.
  834. */
  835. #define M_BSLT(label_num, imm_value) \
  836. M_BRANCH(label_num), \
  837. I_JUMPS(0, imm_value, JUMPS_LT)
  838. /**
  839. * Macro: branch to label if the stage counter is greater than or equal to immediate value
  840. *
  841. * This macro generates two ulp_insn_t values separated by a comma, and should
  842. * be used when defining contents of ulp_insn_t arrays. First value is not a
  843. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  844. * function.
  845. */
  846. #define M_BSGE(label_num, imm_value) \
  847. M_BRANCH(label_num), \
  848. I_JUMPS(0, imm_value, JUMPS_GE)
  849. /**
  850. * Macro: branch to label if the stage counter is less than or equal to immediate value
  851. *
  852. * This macro generates two ulp_insn_t values separated by a comma, and should
  853. * be used when defining contents of ulp_insn_t arrays. First value is not a
  854. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  855. * function.
  856. */
  857. #define M_BSLE(label_num, imm_value) \
  858. M_BRANCH(label_num), \
  859. I_JUMPS(0, imm_value, JUMPS_LE)
  860. /**
  861. * Macro: branch to label if the stage counter is equal to immediate value.
  862. * Implemented using two JUMPS instructions:
  863. * JUMPS next, imm_value, LT
  864. * JUMPS label_num, imm_value, LE
  865. *
  866. * This macro generates three ulp_insn_t values separated by commas, and should
  867. * be used when defining contents of ulp_insn_t arrays. Second value is not a
  868. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  869. * function.
  870. */
  871. #define M_BSEQ(label_num, imm_value) \
  872. I_JUMPS(2, imm_value, JUMPS_LT), \
  873. M_BRANCH(label_num), \
  874. I_JUMPS(0, imm_value, JUMPS_LE)
  875. /**
  876. * Macro: branch to label if the stage counter is greater than immediate value.
  877. * Implemented using two instructions:
  878. * JUMPS next, imm_value, LE
  879. * JUMPS label_num, imm_value, GE
  880. *
  881. * This macro generates three ulp_insn_t values separated by commas, and should
  882. * be used when defining contents of ulp_insn_t arrays. Second value is not a
  883. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  884. * function.
  885. */
  886. #define M_BSGT(label_num, imm_value) \
  887. I_JUMPS(2, imm_value, JUMPS_LE), \
  888. M_BRANCH(label_num), \
  889. I_JUMPS(0, imm_value, JUMPS_GE)
  890. /**
  891. * Branch relative if (stage counter [comp_type] [imm_value]) evaluates to true.
  892. *
  893. * pc_offset is expressed in words, and can be from -127 to 127
  894. * imm_value is an 8-bit value to compare the stage counter against
  895. * comp_type is the type of comparison to perform: JUMPS_LT (<), JUMPS_GE (>=) or JUMPS_LE (<=)
  896. */
  897. #define I_JUMPS(pc_offset, imm_value, comp_type) { .bs = { \
  898. .imm = imm_value, \
  899. .unused = 0, \
  900. .cmp = comp_type, \
  901. .offset = abs(pc_offset), \
  902. .sign = (pc_offset >= 0) ? 0 : 1, \
  903. .sub_opcode = SUB_OPCODE_BS, \
  904. .opcode = OPCODE_BRANCH } }
  905. /**
  906. * Perform an I2C transaction with a slave device.
  907. * I_I2C_READ and I_I2C_WRITE are provided for convenience, instead of using this directly.
  908. *
  909. * Slave address (in 7-bit format) has to be set in advance into SENS_I2C_SLAVE_ADDRx register field, where x == slave_sel.
  910. * For read operations, 8 bits of read result is stored into R0 register.
  911. * For write operations, val will be written to sub_addr at [high_bit:low_bit]. Bits outside of this range are masked.
  912. */
  913. #define I_I2C_RW(sub_addr, val, low_bit, high_bit, slave_sel, rw_bit) { .i2c = {\
  914. .i2c_addr = sub_addr, \
  915. .data = val, \
  916. .low_bits = low_bit, \
  917. .high_bits = high_bit, \
  918. .i2c_sel = slave_sel, \
  919. .unused = 0, \
  920. .rw = rw_bit, \
  921. .opcode = OPCODE_I2C } }
  922. /**
  923. * Read a byte from the sub address of an I2C slave, and store the result in R0.
  924. *
  925. * Slave address (in 7-bit format) has to be set in advance into SENS_I2C_SLAVE_ADDRx register field, where x == slave_sel.
  926. */
  927. #define I_I2C_READ(slave_sel, sub_addr) I_I2C_RW(sub_addr, 0, 0, 0, slave_sel, SUB_OPCODE_I2C_RD)
  928. /**
  929. * Write a byte to the sub address of an I2C slave.
  930. *
  931. * Slave address (in 7-bit format) has to be set in advance into SENS_I2C_SLAVE_ADDRx register field, where x == slave_sel.
  932. */
  933. #define I_I2C_WRITE(slave_sel, sub_addr, val) I_I2C_RW(sub_addr, val, 0, 7, slave_sel, SUB_OPCODE_I2C_WR)
  934. #define RTC_SLOW_MEM ((uint32_t*) 0x50000000) /*!< RTC slow memory, 8k size */
  935. #ifdef __cplusplus
  936. }
  937. #endif