ulp.h 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153
  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. typedef union ulp_insn ulp_insn_t;
  231. _Static_assert(sizeof(ulp_insn_t) == 4, "ULP coprocessor instruction size should be 4 bytes");
  232. /**
  233. * Delay (nop) for a given number of cycles
  234. */
  235. #define I_DELAY(cycles_) { .delay = {\
  236. .cycles = cycles_, \
  237. .unused = 0, \
  238. .opcode = OPCODE_DELAY } }
  239. /**
  240. * Halt the coprocessor.
  241. *
  242. * This instruction halts the coprocessor, but keeps ULP timer active.
  243. * As such, ULP program will be restarted again by timer.
  244. * To stop the program and prevent the timer from restarting the program,
  245. * use I_END(0) instruction.
  246. */
  247. #define I_HALT() { .halt = {\
  248. .unused = 0, \
  249. .opcode = OPCODE_HALT } }
  250. /**
  251. * Map SoC peripheral register to periph_sel field of RD_REG and WR_REG
  252. * instructions.
  253. *
  254. * @param reg peripheral register in RTC_CNTL_, RTC_IO_, SENS_, RTC_I2C peripherals.
  255. * @return periph_sel value for the peripheral to which this register belongs.
  256. */
  257. static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg)
  258. {
  259. uint32_t ret = 3;
  260. if (reg < DR_REG_RTCCNTL_BASE) {
  261. assert(0 && "invalid register base");
  262. } else if (reg < DR_REG_RTCIO_BASE) {
  263. ret = RD_REG_PERIPH_RTC_CNTL;
  264. } else if (reg < DR_REG_SENS_BASE) {
  265. ret = RD_REG_PERIPH_RTC_IO;
  266. } else if (reg < DR_REG_RTC_I2C_BASE) {
  267. ret = RD_REG_PERIPH_SENS;
  268. } else if (reg < DR_REG_IO_MUX_BASE) {
  269. ret = RD_REG_PERIPH_RTC_I2C;
  270. } else {
  271. assert(0 && "invalid register base");
  272. }
  273. return ret;
  274. }
  275. /**
  276. * Write literal value to a peripheral register
  277. *
  278. * reg[high_bit : low_bit] = val
  279. * This instruction can access RTC_CNTL_, RTC_IO_, SENS_, and RTC_I2C peripheral registers.
  280. */
  281. #define I_WR_REG(reg, low_bit, high_bit, val) {.wr_reg = {\
  282. .addr = (reg & 0xff) / sizeof(uint32_t), \
  283. .periph_sel = SOC_REG_TO_ULP_PERIPH_SEL(reg), \
  284. .data = val, \
  285. .low = low_bit, \
  286. .high = high_bit, \
  287. .opcode = OPCODE_WR_REG } }
  288. /**
  289. * Read from peripheral register into R0
  290. *
  291. * R0 = reg[high_bit : low_bit]
  292. * This instruction can access RTC_CNTL_, RTC_IO_, SENS_, and RTC_I2C peripheral registers.
  293. */
  294. #define I_RD_REG(reg, low_bit, high_bit) {.rd_reg = {\
  295. .addr = (reg & 0xff) / sizeof(uint32_t), \
  296. .periph_sel = SOC_REG_TO_ULP_PERIPH_SEL(reg), \
  297. .unused = 0, \
  298. .low = low_bit, \
  299. .high = high_bit, \
  300. .opcode = OPCODE_RD_REG } }
  301. /**
  302. * Set or clear a bit in the peripheral register.
  303. *
  304. * Sets bit (1 << shift) of register reg to value val.
  305. * This instruction can access RTC_CNTL_, RTC_IO_, SENS_, and RTC_I2C peripheral registers.
  306. */
  307. #define I_WR_REG_BIT(reg, shift, val) I_WR_REG(reg, shift, shift, val)
  308. /**
  309. * Wake the SoC from deep sleep.
  310. *
  311. * This instruction initiates wake up from deep sleep.
  312. * Use esp_deep_sleep_enable_ulp_wakeup to enable deep sleep wakeup
  313. * triggered by the ULP before going into deep sleep.
  314. * Note that ULP program will still keep running until the I_HALT
  315. * instruction, and it will still be restarted by timer at regular
  316. * intervals, even when the SoC is woken up.
  317. *
  318. * To stop the ULP program, use I_HALT instruction.
  319. *
  320. * To disable the timer which start ULP program, use I_END()
  321. * instruction. I_END instruction clears the
  322. * RTC_CNTL_ULP_CP_SLP_TIMER_EN_S bit of RTC_CNTL_ULP_CP_TIMER_REG
  323. * register, which controls the ULP timer.
  324. */
  325. #define I_WAKE() { .end = { \
  326. .wakeup = 1, \
  327. .unused = 0, \
  328. .sub_opcode = SUB_OPCODE_END, \
  329. .opcode = OPCODE_END } }
  330. /**
  331. * Stop ULP program timer.
  332. *
  333. * This is a convenience macro which disables the ULP program timer.
  334. * Once this instruction is used, ULP program will not be restarted
  335. * anymore until ulp_run function is called.
  336. *
  337. * ULP program will continue running after this instruction. To stop
  338. * the currently running program, use I_HALT().
  339. */
  340. #define I_END() \
  341. I_WR_REG_BIT(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN_S, 0)
  342. /**
  343. * Perform temperature sensor measurement and store it into reg_dest.
  344. *
  345. * Delay can be set between 1 and ((1 << 14) - 1). Higher values give
  346. * higher measurement resolution.
  347. */
  348. #define I_TSENS(reg_dest, delay) { .tsens = { \
  349. .dreg = reg_dest, \
  350. .wait_delay = delay, \
  351. .reserved = 0, \
  352. .opcode = OPCODE_TSENS } }
  353. /**
  354. * Perform ADC measurement and store result in reg_dest.
  355. *
  356. * adc_idx selects ADC (0 or 1).
  357. * pad_idx selects ADC pad (0 - 7).
  358. */
  359. #define I_ADC(reg_dest, adc_idx, pad_idx) { .adc = {\
  360. .dreg = reg_dest, \
  361. .mux = pad_idx + 1, \
  362. .sar_sel = adc_idx, \
  363. .unused1 = 0, \
  364. .cycles = 0, \
  365. .unused2 = 0, \
  366. .opcode = OPCODE_ADC } }
  367. /**
  368. * Store lower half-word, upper half-word or full-word data from register reg_val into RTC memory address.
  369. *
  370. * This instruction can be used to write data to discontinuous addresses in the RTC_SLOW_MEM.
  371. * The value is written to an offset calculated by adding the value of
  372. * reg_addr register and offset_ field (this offset is expressed in 32-bit words).
  373. * The storage method is dictated by the wr_way and upper field settings as summarized in the following table:
  374. *
  375. * @verbatim
  376. * |--------|-------|----------------------------------------------------------------------------------------|----------------------------|
  377. * | wr_way | upper | data | operation |
  378. * |--------|-------|----------------------------------------------------------------------------------------|----------------------------|
  379. * | | | | Write full-word, including |
  380. * | 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 |
  381. * |--------|-------|----------------------------------------------------------------------------------------|----------------------------|
  382. * | | | | Store the data with label |
  383. * | 1 | 0 | RTC_SLOW_MEM[addr + offset_]{15:0} = {label_[1:0], reg_val[13:0]} | in the low half-word |
  384. * |--------|-------|----------------------------------------------------------------------------------------|----------------------------|
  385. * | | | | Store the data with label |
  386. * | 1 | 1 | RTC_SLOW_MEM[addr + offset_]{31:16} = {label_[1:0], reg_val[13:0]} | in the high half-word |
  387. * |--------|-------|----------------------------------------------------------------------------------------|----------------------------|
  388. * | | | | Store the data without |
  389. * | 3 | 0 | RTC_SLOW_MEM[addr + offset_]{15:0} = reg_val[15:0] | label in the low half-word |
  390. * |--------|-------|----------------------------------------------------------------------------------------|----------------------------|
  391. * | | | | Store the data without |
  392. * | 3 | 1 | RTC_SLOW_MEM[addr + offset_]{31:16} = reg_val[15:0] | label in the high half-word|
  393. * |--------|-------|----------------------------------------------------------------------------------------|----------------------------|
  394. * @endverbatim
  395. *
  396. * SUB_OPCODE_ST = manual_en:1, offset_set:0, wr_auto:0
  397. */
  398. #define I_ST_MANUAL(reg_val, reg_addr, offset_, label_, upper_, wr_way_) { .st = { \
  399. .dreg = reg_val, \
  400. .sreg = reg_addr, \
  401. .label = label_, \
  402. .upper = upper_, \
  403. .wr_way = wr_way_, \
  404. .unused1 = 0, \
  405. .offset = offset_, \
  406. .unused2 = 0, \
  407. .sub_opcode = SUB_OPCODE_ST, \
  408. .opcode = OPCODE_ST } }
  409. /**
  410. * Store value from register reg_val into RTC memory.
  411. *
  412. * I_ST() instruction provides backward compatibility for code written for esp32 to be run on esp32s2.
  413. * This instruction is equivalent to calling I_ST_MANUAL() instruction with label = 0, upper = 0 and wr_way = 3.
  414. */
  415. #define I_ST(reg_val, reg_addr, offset_) I_ST_MANUAL(reg_val, reg_addr, offset_, 0, 0, 3)
  416. /**
  417. * Store value from register reg_val to lower 16 bits of the RTC memory address.
  418. *
  419. * This instruction is equivalent to calling I_ST_MANUAL() instruction with label = 0, upper = 0 and wr_way = 3.
  420. */
  421. #define I_STL(reg_val, reg_addr, offset_) I_ST_MANUAL(reg_val, reg_addr, offset_, 0, 0, 3)
  422. /**
  423. * Store value from register reg_val to upper 16 bits of the RTC memory address.
  424. *
  425. * This instruction is equivalent to calling I_ST_MANUAL() instruction with label = 0, upper = 1 and wr_way = 3.
  426. */
  427. #define I_STH(reg_val, reg_addr, offset_) I_ST_MANUAL(reg_val, reg_addr, offset_, 0, 1, 3)
  428. /**
  429. * Store value from register reg_val to full 32 bit word of the RTC memory address.
  430. *
  431. * This instruction is equivalent to calling I_ST_MANUAL() instruction with wr_way = 0.
  432. */
  433. #define I_ST32(reg_val, reg_addr, offset_, label_) I_ST_MANUAL(reg_val, reg_addr, offset_, label_, 0, 0)
  434. /**
  435. * Store value from register reg_val with label to lower 16 bits of RTC memory address.
  436. *
  437. * This instruction is equivalent to calling I_ST_MANUAL() instruction with label = label_, upper = 0 and wr_way = 1.
  438. */
  439. #define I_STL_LABEL(reg_val, reg_addr, offset_, label_) I_ST_MANUAL(reg_val, reg_addr, offset_, label_, 0, 1)
  440. /**
  441. * Store value from register reg_val with label to upper 16 bits of RTC memory address.
  442. *
  443. * This instruction is equivalent to calling I_ST_MANUAL() instruction with label = label_, upper = 1 and wr_way = 1.
  444. */
  445. #define I_STH_LABEL(reg_val, reg_addr, offset_, label_) I_ST_MANUAL(reg_val, reg_addr, offset_, label_, 1, 1)
  446. /**
  447. * 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.
  448. *
  449. * This instruction can be used to write data to continuous addresses in the RTC_SLOW_MEM.
  450. * The initial address must be set using the SUB_OPCODE_ST_OFFSET instruction before the auto store instruction is called.
  451. * 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
  452. * 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.
  453. * write_cnt indicates the later. The following table summarizes the storage method:
  454. *
  455. * @verbatim
  456. * |--------|-----------|----------------------------------------------------------------------------------------|----------------------------|
  457. * | wr_way | write_cnt | data | operation |
  458. * |--------|-----------|----------------------------------------------------------------------------------------|----------------------------|
  459. * | | | | Write full-word, including |
  460. * | 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 |
  461. * |--------|-----------|----------------------------------------------------------------------------------------|----------------------------|
  462. * | | | | Store the data with label |
  463. * | 1 | odd | RTC_SLOW_MEM[addr + offset_]{15:0} = {label_[1:0], reg_val[13:0]} | in the low half-word |
  464. * |--------|-----------|----------------------------------------------------------------------------------------|----------------------------|
  465. * | | | | Store the data with label |
  466. * | 1 | even | RTC_SLOW_MEM[addr + offset_]{31:16} = {label_[1:0], reg_val[13:0]} | in the high half-word |
  467. * |--------|-----------|----------------------------------------------------------------------------------------|----------------------------|
  468. * | | | | Store the data without |
  469. * | 3 | odd | RTC_SLOW_MEM[addr + offset_]{15:0} = reg_val[15:0] | label in the low half-word |
  470. * |--------|-----------|----------------------------------------------------------------------------------------|----------------------------|
  471. * | | | | Store the data without |
  472. * | 3 | even | RTC_SLOW_MEM[addr + offset_]{31:16} = reg_val[15:0] | label in the high half-word|
  473. * |--------|-----------|----------------------------------------------------------------------------------------|----------------------------|
  474. * @endverbatim
  475. *
  476. * The initial address offset is incremented after each store operation as follows:
  477. * - When a full-word is written, the offset is automatically incremented by 1 after each SUB_OPCODE_ST_AUTO operation.
  478. * - When a half-word is written (lower half-word first), the offset is automatically incremented by 1 after two
  479. * SUB_OPCODE_ST_AUTO operations.
  480. *
  481. * SUB_OPCODE_ST_AUTO = manual_en:0, offset_set:0, wr_auto:1
  482. */
  483. #define I_ST_AUTO(reg_val, reg_addr, label_, wr_way_) { .st = { \
  484. .dreg = reg_addr, \
  485. .sreg = reg_val, \
  486. .label = label_, \
  487. .upper = 0, \
  488. .wr_way = wr_way_, \
  489. .unused1 = 0, \
  490. .offset = 0, \
  491. .unused2 = 0, \
  492. .sub_opcode = SUB_OPCODE_ST_AUTO, \
  493. .opcode = OPCODE_ST } }
  494. /**
  495. * Set the initial address offset for auto-store operation
  496. *
  497. * This instruction sets the initial address of the RTC_SLOW_MEM to be used by the auto-store operation.
  498. * The offset is incremented automatically.
  499. * Refer I_ST_AUTO() for detailed explaination.
  500. *
  501. * SUB_OPCODE_ST_OFFSET = manual_en:0, offset_set:1, wr_auto:1
  502. */
  503. #define I_STO(offset_) { .st = { \
  504. .dreg = 0, \
  505. .sreg = 0, \
  506. .label = 0, \
  507. .upper = 0, \
  508. .wr_way = 0, \
  509. .unused1 = 0, \
  510. .offset = offset_, \
  511. .unused2 = 0, \
  512. .sub_opcode = SUB_OPCODE_ST_OFFSET, \
  513. .opcode = OPCODE_ST } }
  514. /**
  515. * Store value from register reg_val to 32 bit word of the RTC memory address.
  516. *
  517. * This instruction is equivalent to calling I_ST_AUTO() instruction with label = 0 and wr_way = 3.
  518. * The data in reg_val will be either written to the lower half-word or the upper half-word of the RTC memory address
  519. * depending on the count of the number of times the I_STI() instruction is called.
  520. * The initial offset is automatically incremented with I_STI() is called twice.
  521. * Refer I_ST_AUTO() for detailed explaination.
  522. */
  523. #define I_STI(reg_val, reg_addr) I_ST_AUTO(reg_val, reg_addr, 0, 3)
  524. /**
  525. * Store value from register reg_val with label to 32 bit word of the RTC memory address.
  526. *
  527. * This instruction is equivalent to calling I_ST_AUTO() instruction with label = label_ and wr_way = 1.
  528. * The data in reg_val will be either written to the lower half-word or the upper half-word of the RTC memory address
  529. * depending on the count of the number of times the I_STI_LABEL() instruction is called.
  530. * The initial offset is automatically incremented with I_STI_LABEL() is called twice.
  531. * Refer I_ST_AUTO() for detailed explaination.
  532. */
  533. #define I_STI_LABEL(reg_val, reg_addr, label_) I_ST_AUTO(reg_val, reg_addr, label_, 1)
  534. /**
  535. * Store value from register reg_val to full 32 bit word of the RTC memory address.
  536. *
  537. * This instruction is equivalent to calling I_ST_AUTO() instruction with label = label_ and wr_way = 0.
  538. * The data in reg_val will be written to the RTC memory address along with the label and the PC.
  539. * The initial offset is automatically incremented each time the I_STI32() instruction is called.
  540. * Refer I_ST_AUTO() for detailed explaination.
  541. */
  542. #define I_STI32(reg_val, reg_addr, label_) I_ST_AUTO(reg_val, reg_addr, label_, 0)
  543. /**
  544. * Load lower half-word, upper half-word or full-word data from RTC memory address into the register reg_dest.
  545. *
  546. * This instruction reads the lower half-word or upper half-word of the RTC memory address depending on the value
  547. * of rd_upper_. The following table summarizes the loading method:
  548. *
  549. * @verbatim
  550. * |----------|------------------------------------------------------|-------------------------|
  551. * | rd_upper | data | operation |
  552. * |----------|------------------------------------------------------|-------------------------|
  553. * | | | Read lower half-word of |
  554. * | 0 | reg_dest{15:0} = RTC_SLOW_MEM[addr + offset_]{31:16} | the memory |
  555. * |----------|------------------------------------------------------|-------------------------|
  556. * | | | Read upper half-word of |
  557. * | 1 | reg_dest{15:0} = RTC_SLOW_MEM[addr + offset_]{15:0} | the memory |
  558. * |----------|------------------------------------------------------|-------------------------|
  559. * @endverbatim
  560. *
  561. */
  562. #define I_LD_MANUAL(reg_dest, reg_addr, offset_, rd_upper_) { .ld = { \
  563. .dreg = reg_dest, \
  564. .sreg = reg_addr, \
  565. .unused1 = 0, \
  566. .offset = offset_, \
  567. .unused2 = 0, \
  568. .rd_upper = rd_upper_, \
  569. .opcode = OPCODE_LD } }
  570. /**
  571. * Load lower 16 bits value from RTC memory into reg_dest register.
  572. *
  573. * Loads 16 LSBs (rd_upper = 1) from RTC memory word given by the sum of value in reg_addr and
  574. * value of offset_.
  575. * I_LD() instruction provides backward compatibility for code written for esp32 to be run on esp32s2.
  576. */
  577. #define I_LD(reg_dest, reg_addr, offset_) I_LD_MANUAL(reg_dest, reg_addr, offset_, 0)
  578. /**
  579. * Load lower 16 bits value from RTC memory into reg_dest register.
  580. *
  581. * I_LDL() instruction and I_LD() instruction can be used interchangably.
  582. */
  583. #define I_LDL(reg_dest, reg_addr, offset_) I_LD(reg_dest, reg_addr, offset_)
  584. /**
  585. * Load upper 16 bits value from RTC memory into reg_dest register.
  586. *
  587. * Loads 16 MSBs (rd_upper = 0) from RTC memory word given by the sum of value in reg_addr and
  588. * value of offset_.
  589. */
  590. #define I_LDH(reg_dest, reg_addr, offset_) I_LD_MANUAL(reg_dest, reg_addr, offset_, 1)
  591. /**
  592. * Branch relative if R0 register less than the immediate value.
  593. *
  594. * pc_offset is expressed in words, and can be from -127 to 127
  595. * imm_value is a 16-bit value to compare R0 against
  596. */
  597. #define I_BL(pc_offset, imm_value) { .b = { \
  598. .imm = imm_value, \
  599. .cmp = B_CMP_L, \
  600. .offset = abs(pc_offset), \
  601. .sign = (pc_offset >= 0) ? 0 : 1, \
  602. .sub_opcode = SUB_OPCODE_B, \
  603. .opcode = OPCODE_BRANCH } }
  604. /**
  605. * Branch relative if R0 register greater than the immediate value.
  606. *
  607. * pc_offset is expressed in words, and can be from -127 to 127
  608. * imm_value is a 16-bit value to compare R0 against
  609. */
  610. #define I_BG(pc_offset, imm_value) { .b = { \
  611. .imm = imm_value, \
  612. .cmp = B_CMP_G, \
  613. .offset = abs(pc_offset), \
  614. .sign = (pc_offset >= 0) ? 0 : 1, \
  615. .sub_opcode = SUB_OPCODE_B, \
  616. .opcode = OPCODE_BRANCH } }
  617. /**
  618. * Branch relative if R0 register is equal to the immediate value.
  619. *
  620. * pc_offset is expressed in words, and can be from -127 to 127
  621. * imm_value is a 16-bit value to compare R0 against
  622. */
  623. #define I_BE(pc_offset, imm_value) { .b = { \
  624. .imm = imm_value, \
  625. .cmp = B_CMP_E, \
  626. .offset = abs(pc_offset), \
  627. .sign = (pc_offset >= 0) ? 0 : 1, \
  628. .sub_opcode = SUB_OPCODE_B, \
  629. .opcode = OPCODE_BRANCH } }
  630. /**
  631. * Unconditional branch to absolute PC, address in register.
  632. *
  633. * reg_pc is the register which contains address to jump to.
  634. * Address is expressed in 32-bit words.
  635. */
  636. #define I_BXR(reg_pc) { .bx = { \
  637. .dreg = reg_pc, \
  638. .addr = 0, \
  639. .unused1 = 0, \
  640. .reg = 1, \
  641. .type = BX_JUMP_TYPE_DIRECT, \
  642. .unused2 = 0, \
  643. .sub_opcode = SUB_OPCODE_BX, \
  644. .opcode = OPCODE_BRANCH } }
  645. /**
  646. * Unconditional branch to absolute PC, immediate address.
  647. *
  648. * Address imm_pc is expressed in 32-bit words.
  649. */
  650. #define I_BXI(imm_pc) { .bx = { \
  651. .dreg = 0, \
  652. .addr = imm_pc, \
  653. .unused1 = 0, \
  654. .reg = 0, \
  655. .type = BX_JUMP_TYPE_DIRECT, \
  656. .unused2 = 0, \
  657. .sub_opcode = SUB_OPCODE_BX, \
  658. .opcode = OPCODE_BRANCH } }
  659. /**
  660. * Branch to absolute PC if ALU result is zero, address in register.
  661. *
  662. * reg_pc is the register which contains address to jump to.
  663. * Address is expressed in 32-bit words.
  664. */
  665. #define I_BXZR(reg_pc) { .bx = { \
  666. .dreg = reg_pc, \
  667. .addr = 0, \
  668. .unused1 = 0, \
  669. .reg = 1, \
  670. .type = BX_JUMP_TYPE_ZERO, \
  671. .unused2 = 0, \
  672. .sub_opcode = SUB_OPCODE_BX, \
  673. .opcode = OPCODE_BRANCH } }
  674. /**
  675. * Branch to absolute PC if ALU result is zero, immediate address.
  676. *
  677. * Address imm_pc is expressed in 32-bit words.
  678. */
  679. #define I_BXZI(imm_pc) { .bx = { \
  680. .dreg = 0, \
  681. .addr = imm_pc, \
  682. .unused1 = 0, \
  683. .reg = 0, \
  684. .type = BX_JUMP_TYPE_ZERO, \
  685. .unused2 = 0, \
  686. .sub_opcode = SUB_OPCODE_BX, \
  687. .opcode = OPCODE_BRANCH } }
  688. /**
  689. * Branch to absolute PC if ALU overflow, address in register
  690. *
  691. * reg_pc is the register which contains address to jump to.
  692. * Address is expressed in 32-bit words.
  693. */
  694. #define I_BXFR(reg_pc) { .bx = { \
  695. .dreg = reg_pc, \
  696. .addr = 0, \
  697. .unused1 = 0, \
  698. .reg = 1, \
  699. .type = BX_JUMP_TYPE_OVF, \
  700. .unused2 = 0, \
  701. .sub_opcode = SUB_OPCODE_BX, \
  702. .opcode = OPCODE_BRANCH } }
  703. /**
  704. * Branch to absolute PC if ALU overflow, immediate address
  705. *
  706. * Address imm_pc is expressed in 32-bit words.
  707. */
  708. #define I_BXFI(imm_pc) { .bx = { \
  709. .dreg = 0, \
  710. .addr = imm_pc, \
  711. .unused1 = 0, \
  712. .reg = 0, \
  713. .type = BX_JUMP_TYPE_OVF, \
  714. .unused2 = 0, \
  715. .sub_opcode = SUB_OPCODE_BX, \
  716. .opcode = OPCODE_BRANCH } }
  717. /**
  718. * Branch relative if stage_cnt is less than or equal to the immediate value.
  719. *
  720. * pc_offset is expressed in words, and can be from -127 to 127
  721. * imm_value is a 16-bit value to compare R0 against
  722. */
  723. #define I_BSLE(pc_offset, imm_value) { .b = { \
  724. .imm = imm_value, \
  725. .cmp = BS_CMP_LE, \
  726. .offset = abs(pc_offset), \
  727. .sign = (pc_offset >= 0) ? 0 : 1, \
  728. .sub_opcode = SUB_OPCODE_BS, \
  729. .opcode = OPCODE_BRANCH } }
  730. /**
  731. * Branch relative if stage_cnt register is greater than or equal to the immediate value.
  732. *
  733. * pc_offset is expressed in words, and can be from -127 to 127
  734. * imm_value is a 16-bit value to compare R0 against
  735. */
  736. #define I_BSGE(pc_offset, imm_value) { .b = { \
  737. .imm = imm_value, \
  738. .cmp = BS_CMP_GE, \
  739. .offset = abs(pc_offset), \
  740. .sign = (pc_offset >= 0) ? 0 : 1, \
  741. .sub_opcode = SUB_OPCODE_BS, \
  742. .opcode = OPCODE_BRANCH } }
  743. /**
  744. * Branch relative if stage_cnt register is less than the immediate value.
  745. *
  746. * pc_offset is expressed in words, and can be from -127 to 127
  747. * imm_value is a 16-bit value to compare R0 against
  748. */
  749. #define I_BSL(pc_offset, imm_value) { .b = { \
  750. .imm = imm_value, \
  751. .cmp = BS_CMP_L, \
  752. .offset = abs(pc_offset), \
  753. .sign = (pc_offset >= 0) ? 0 : 1, \
  754. .sub_opcode = SUB_OPCODE_BS, \
  755. .opcode = OPCODE_BRANCH } }
  756. /**
  757. * Addition: dest = src1 + src2
  758. */
  759. #define I_ADDR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  760. .dreg = reg_dest, \
  761. .sreg = reg_src1, \
  762. .treg = reg_src2, \
  763. .unused1 = 0, \
  764. .sel = ALU_SEL_ADD, \
  765. .unused2 = 0, \
  766. .sub_opcode = SUB_OPCODE_ALU_REG, \
  767. .opcode = OPCODE_ALU } }
  768. /**
  769. * Subtraction: dest = src1 - src2
  770. */
  771. #define I_SUBR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  772. .dreg = reg_dest, \
  773. .sreg = reg_src1, \
  774. .treg = reg_src2, \
  775. .unused1 = 0, \
  776. .sel = ALU_SEL_SUB, \
  777. .unused2 = 0, \
  778. .sub_opcode = SUB_OPCODE_ALU_REG, \
  779. .opcode = OPCODE_ALU } }
  780. /**
  781. * Logical AND: dest = src1 & src2
  782. */
  783. #define I_ANDR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  784. .dreg = reg_dest, \
  785. .sreg = reg_src1, \
  786. .treg = reg_src2, \
  787. .unused1 = 0, \
  788. .sel = ALU_SEL_AND, \
  789. .unused2 = 0, \
  790. .sub_opcode = SUB_OPCODE_ALU_REG, \
  791. .opcode = OPCODE_ALU } }
  792. /**
  793. * Logical OR: dest = src1 | src2
  794. */
  795. #define I_ORR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  796. .dreg = reg_dest, \
  797. .sreg = reg_src1, \
  798. .treg = reg_src2, \
  799. .unused1 = 0, \
  800. .sel = ALU_SEL_OR, \
  801. .unused2 = 0, \
  802. .sub_opcode = SUB_OPCODE_ALU_REG, \
  803. .opcode = OPCODE_ALU } }
  804. /**
  805. * Copy: dest = src
  806. */
  807. #define I_MOVR(reg_dest, reg_src) { .alu_reg = { \
  808. .dreg = reg_dest, \
  809. .sreg = reg_src, \
  810. .treg = 0, \
  811. .unused1 = 0, \
  812. .sel = ALU_SEL_MOV, \
  813. .unused2 = 0, \
  814. .sub_opcode = SUB_OPCODE_ALU_REG, \
  815. .opcode = OPCODE_ALU } }
  816. /**
  817. * Logical shift left: dest = src << shift
  818. */
  819. #define I_LSHR(reg_dest, reg_src, reg_shift) { .alu_reg = { \
  820. .dreg = reg_dest, \
  821. .sreg = reg_src, \
  822. .treg = reg_shift, \
  823. .unused1 = 0, \
  824. .sel = ALU_SEL_LSH, \
  825. .unused2 = 0, \
  826. .sub_opcode = SUB_OPCODE_ALU_REG, \
  827. .opcode = OPCODE_ALU } }
  828. /**
  829. * Logical shift right: dest = src >> shift
  830. */
  831. #define I_RSHR(reg_dest, reg_src, reg_shift) { .alu_reg = { \
  832. .dreg = reg_dest, \
  833. .sreg = reg_src, \
  834. .treg = reg_shift, \
  835. .unused1 = 0, \
  836. .sel = ALU_SEL_RSH, \
  837. .unused2 = 0, \
  838. .sub_opcode = SUB_OPCODE_ALU_REG, \
  839. .opcode = OPCODE_ALU } }
  840. /**
  841. * Add register and an immediate value: dest = src1 + imm
  842. */
  843. #define I_ADDI(reg_dest, reg_src, imm_) { .alu_imm = { \
  844. .dreg = reg_dest, \
  845. .sreg = reg_src, \
  846. .imm = imm_, \
  847. .unused1 = 0, \
  848. .sel = ALU_SEL_ADD, \
  849. .unused2 = 0, \
  850. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  851. .opcode = OPCODE_ALU } }
  852. /**
  853. * Subtract register and an immediate value: dest = src - imm
  854. */
  855. #define I_SUBI(reg_dest, reg_src, imm_) { .alu_imm = { \
  856. .dreg = reg_dest, \
  857. .sreg = reg_src, \
  858. .imm = imm_, \
  859. .unused1 = 0, \
  860. .sel = ALU_SEL_SUB, \
  861. .unused2 = 0, \
  862. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  863. .opcode = OPCODE_ALU } }
  864. /**
  865. * Logical AND register and an immediate value: dest = src & imm
  866. */
  867. #define I_ANDI(reg_dest, reg_src, imm_) { .alu_imm = { \
  868. .dreg = reg_dest, \
  869. .sreg = reg_src, \
  870. .imm = imm_, \
  871. .unused1 = 0, \
  872. .sel = ALU_SEL_AND, \
  873. .unused2 = 0, \
  874. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  875. .opcode = OPCODE_ALU } }
  876. /**
  877. * Logical OR register and an immediate value: dest = src | imm
  878. */
  879. #define I_ORI(reg_dest, reg_src, imm_) { .alu_imm = { \
  880. .dreg = reg_dest, \
  881. .sreg = reg_src, \
  882. .imm = imm_, \
  883. .unused1 = 0, \
  884. .sel = ALU_SEL_OR, \
  885. .unused2 = 0, \
  886. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  887. .opcode = OPCODE_ALU } }
  888. /**
  889. * Copy an immediate value into register: dest = imm
  890. */
  891. #define I_MOVI(reg_dest, imm_) { .alu_imm = { \
  892. .dreg = reg_dest, \
  893. .sreg = 0, \
  894. .imm = imm_, \
  895. .unused1 = 0, \
  896. .sel = ALU_SEL_MOV, \
  897. .unused2 = 0, \
  898. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  899. .opcode = OPCODE_ALU } }
  900. /**
  901. * Logical shift left register value by an immediate: dest = src << imm
  902. */
  903. #define I_LSHI(reg_dest, reg_src, imm_) { .alu_imm = { \
  904. .dreg = reg_dest, \
  905. .sreg = reg_src, \
  906. .imm = imm_, \
  907. .unused1 = 0, \
  908. .sel = ALU_SEL_LSH, \
  909. .unused2 = 0, \
  910. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  911. .opcode = OPCODE_ALU } }
  912. /**
  913. * Logical shift right register value by an immediate: dest = val >> imm
  914. */
  915. #define I_RSHI(reg_dest, reg_src, imm_) { .alu_imm = { \
  916. .dreg = reg_dest, \
  917. .sreg = reg_src, \
  918. .imm = imm_, \
  919. .unused1 = 0, \
  920. .sel = ALU_SEL_RSH, \
  921. .unused2 = 0, \
  922. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  923. .opcode = OPCODE_ALU } }
  924. /**
  925. * Increment stage_cnt register by an immediate: stage_cnt = stage_cnt + imm
  926. */
  927. #define I_STAGE_INC(reg_dest, reg_src, imm_) { .alu_cnt = { \
  928. .unused1 = 0, \
  929. .imm = imm_, \
  930. .unused2 = 0, \
  931. .sel = ALU_SEL_STAGE_INC, \
  932. .unused3 = 0, \
  933. .sub_opcode = SUB_OPCODE_ALU_CNT, \
  934. .opcode = OPCODE_ALU } }
  935. /**
  936. * Decrement stage_cnt register by an immediate: stage_cnt = stage_cnt - imm
  937. */
  938. #define I_STAGE_DEC(reg_dest, reg_src, imm_) { .alu_cnt = { \
  939. .unused1 = 0, \
  940. .imm = imm_, \
  941. .unused2 = 0, \
  942. .sel = ALU_SEL_STAGE_DEC, \
  943. .unused3 = 0, \
  944. .sub_opcode = SUB_OPCODE_ALU_CNT, \
  945. .opcode = OPCODE_ALU } }
  946. /**
  947. * Reset stage_cnt register by an immediate: stage_cnt = 0
  948. */
  949. #define I_STAGE_RST(reg_dest, reg_src, imm_) { .alu_cnt = { \
  950. .unused1 = 0, \
  951. .imm = imm_, \
  952. .unused2 = 0, \
  953. .sel = ALU_SEL_STAGE_RST, \
  954. .unused3 = 0, \
  955. .sub_opcode = SUB_OPCODE_ALU_CNT, \
  956. .opcode = OPCODE_ALU } }
  957. /**
  958. * Define a label with number label_num.
  959. *
  960. * This is a macro which doesn't generate a real instruction.
  961. * The token generated by this macro is removed by ulp_process_macros_and_load
  962. * function. Label defined using this macro can be used in branch macros defined
  963. * below.
  964. */
  965. #define M_LABEL(label_num) { .macro = { \
  966. .label = label_num, \
  967. .unused = 0, \
  968. .sub_opcode = SUB_OPCODE_MACRO_LABEL, \
  969. .opcode = OPCODE_MACRO } }
  970. /**
  971. * Token macro used by M_B and M_BX macros. Not to be used directly.
  972. */
  973. #define M_BRANCH(label_num) { .macro = { \
  974. .label = label_num, \
  975. .unused = 0, \
  976. .sub_opcode = SUB_OPCODE_MACRO_BRANCH, \
  977. .opcode = OPCODE_MACRO } }
  978. /**
  979. * Macro: branch to label label_num if R0 is less than immediate value.
  980. *
  981. * This macro generates two ulp_insn_t values separated by a comma, and should
  982. * be used when defining contents of ulp_insn_t arrays. First value is not a
  983. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  984. * function.
  985. */
  986. #define M_BL(label_num, imm_value) \
  987. M_BRANCH(label_num), \
  988. I_BL(0, imm_value)
  989. /**
  990. * Macro: branch to label label_num if R0 is greater than immediate value
  991. *
  992. * This macro generates two ulp_insn_t values separated by a comma, and should
  993. * be used when defining contents of ulp_insn_t arrays. First value is not a
  994. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  995. * function.
  996. */
  997. #define M_BG(label_num, imm_value) \
  998. M_BRANCH(label_num), \
  999. I_BG(0, imm_value)
  1000. /**
  1001. * Macro: branch to label label_num if R0 equal to the immediate value
  1002. *
  1003. * This macro generates two ulp_insn_t values separated by a comma, and should
  1004. * be used when defining contents of ulp_insn_t arrays. First value is not a
  1005. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  1006. * function.
  1007. */
  1008. #define M_BE(label_num, imm_value) \
  1009. M_BRANCH(label_num), \
  1010. I_BE(0, imm_value)
  1011. /**
  1012. * Macro: unconditional branch to label
  1013. *
  1014. * This macro generates two ulp_insn_t values separated by a comma, and should
  1015. * be used when defining contents of ulp_insn_t arrays. First value is not a
  1016. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  1017. * function.
  1018. */
  1019. #define M_BX(label_num) \
  1020. M_BRANCH(label_num), \
  1021. I_BXI(0)
  1022. /**
  1023. * Macro: branch to label if ALU result is zero
  1024. *
  1025. * This macro generates two ulp_insn_t values separated by a comma, and should
  1026. * be used when defining contents of ulp_insn_t arrays. First value is not a
  1027. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  1028. * function.
  1029. */
  1030. #define M_BXZ(label_num) \
  1031. M_BRANCH(label_num), \
  1032. I_BXZI(0)
  1033. /**
  1034. * Macro: branch to label if ALU overflow
  1035. *
  1036. * This macro generates two ulp_insn_t values separated by a comma, and should
  1037. * be used when defining contents of ulp_insn_t arrays. First value is not a
  1038. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  1039. * function.
  1040. */
  1041. #define M_BXF(label_num) \
  1042. M_BRANCH(label_num), \
  1043. I_BXFI(0)
  1044. #ifdef __cplusplus
  1045. }
  1046. #endif