ulp.h 45 KB

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