ulp.h 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. // Copyright 2016 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #pragma once
  15. #include <stdint.h>
  16. #include <stddef.h>
  17. #include <stdlib.h>
  18. #include "esp_err.h"
  19. #ifdef __cplusplus
  20. extern "C" {
  21. #endif
  22. /**
  23. * @defgroup ulp_registers ULP coprocessor registers
  24. * @{
  25. */
  26. #define R0 0 /*!< general purpose register 0 */
  27. #define R1 1 /*!< general purpose register 1 */
  28. #define R2 2 /*!< general purpose register 2 */
  29. #define R3 3 /*!< general purpose register 3 */
  30. /**@}*/
  31. /** @defgroup ulp_opcodes ULP coprocessor opcodes, sub opcodes, and various modifiers/flags
  32. *
  33. * These definitions are not intended to be used directly.
  34. * They are used in definitions of instructions later on.
  35. *
  36. * @{
  37. */
  38. #define OPCODE_WR_REG 1 /*!< Instruction: write peripheral register (RTC_CNTL/RTC_IO/SARADC) (not implemented yet) */
  39. #define OPCODE_RD_REG 2 /*!< Instruction: read peripheral register (RTC_CNTL/RTC_IO/SARADC) (not implemented yet) */
  40. #define OPCODE_I2C 3 /*!< Instruction: read/write I2C (not implemented yet) */
  41. #define OPCODE_DELAY 4 /*!< Instruction: delay (nop) for a given number of cycles */
  42. #define OPCODE_ADC 5 /*!< Instruction: SAR ADC measurement (not implemented yet) */
  43. #define OPCODE_ST 6 /*!< Instruction: store indirect to RTC memory */
  44. #define SUB_OPCODE_ST 4 /*!< Store 32 bits, 16 MSBs contain PC, 16 LSBs contain value from source register */
  45. #define OPCODE_ALU 7 /*!< Arithmetic instructions */
  46. #define SUB_OPCODE_ALU_REG 0 /*!< Arithmetic instruction, both source values are in register */
  47. #define SUB_OPCODE_ALU_IMM 1 /*!< Arithmetic instruction, one source value is an immediate */
  48. #define SUB_OPCODE_ALU_CNT 2 /*!< Arithmetic instruction between counter register and an immediate (not implemented yet)*/
  49. #define ALU_SEL_ADD 0 /*!< Addition */
  50. #define ALU_SEL_SUB 1 /*!< Subtraction */
  51. #define ALU_SEL_AND 2 /*!< Logical AND */
  52. #define ALU_SEL_OR 3 /*!< Logical OR */
  53. #define ALU_SEL_MOV 4 /*!< Copy value (immediate to destination register or source register to destination register */
  54. #define ALU_SEL_LSH 5 /*!< Shift left by given number of bits */
  55. #define ALU_SEL_RSH 6 /*!< Shift right by given number of bits */
  56. #define OPCODE_BRANCH 8 /*!< Branch instructions */
  57. #define SUB_OPCODE_BX 0 /*!< Branch to absolute PC (immediate or in register) */
  58. #define BX_JUMP_TYPE_DIRECT 0 /*!< Unconditional jump */
  59. #define BX_JUMP_TYPE_ZERO 1 /*!< Branch if last ALU result is zero */
  60. #define BX_JUMP_TYPE_OVF 2 /*!< Branch if last ALU operation caused and overflow */
  61. #define SUB_OPCODE_B 1 /*!< Branch to a relative offset */
  62. #define B_CMP_L 0 /*!< Branch if R0 is less than an immediate */
  63. #define B_CMP_GE 1 /*!< Branch if R0 is greater than or equal to an immediate */
  64. #define OPCODE_END 9 /*!< Stop executing the program (not implemented yet) */
  65. #define SUB_OPCODE_END 0 /*!< Stop executing the program and optionally wake up the chip */
  66. #define SUB_OPCODE_SLEEP 1 /*!< Stop executing the program and run it again after selected interval */
  67. #define OPCODE_TSENS 10 /*!< Instruction: temperature sensor measurement (not implemented yet) */
  68. #define OPCODE_HALT 11 /*!< Halt the coprocessor */
  69. #define OPCODE_LD 13 /*!< Indirect load lower 16 bits from RTC memory */
  70. #define OPCODE_MACRO 15 /*!< Not a real opcode. Used to identify labels and branches in the program */
  71. #define SUB_OPCODE_MACRO_LABEL 0 /*!< Label macro */
  72. #define SUB_OPCODE_MACRO_BRANCH 1 /*!< Branch macro */
  73. /**@}*/
  74. /**@{*/
  75. #define ESP_ERR_ULP_BASE 0x1200 /*!< Offset for ULP-related error codes */
  76. #define ESP_ERR_ULP_SIZE_TOO_BIG (ESP_ERR_ULP_BASE + 1) /*!< Program doesn't fit into RTC memory reserved for the ULP */
  77. #define ESP_ERR_ULP_INVALID_LOAD_ADDR (ESP_ERR_ULP_BASE + 2) /*!< Load address is outside of RTC memory reserved for the ULP */
  78. #define ESP_ERR_ULP_DUPLICATE_LABEL (ESP_ERR_ULP_BASE + 3) /*!< More than one label with the same number was defined */
  79. #define ESP_ERR_ULP_UNDEFINED_LABEL (ESP_ERR_ULP_BASE + 4) /*!< Branch instructions references an undefined label */
  80. #define ESP_ERR_ULP_BRANCH_OUT_OF_RANGE (ESP_ERR_ULP_BASE + 5) /*!< Branch target is out of range of B instruction (try replacing with BX) */
  81. /**@}*/
  82. /**
  83. * @brief Instruction format structure
  84. *
  85. * All ULP instructions are 32 bit long.
  86. * This union contains field layouts used by all of the supported instructions.
  87. * This union also includes a special "macro" instruction layout.
  88. * This is not a real instruction which can be executed by the CPU. It acts
  89. * as a token which is removed from the program by the
  90. * ulp_process_macros_and_load function.
  91. *
  92. * These structures are not intended to be used directly.
  93. * Preprocessor definitions provided below fill the fields of these structure with
  94. * the right arguments.
  95. */
  96. typedef union {
  97. struct {
  98. uint32_t cycles : 16; /*!< Number of cycles to sleep */
  99. uint32_t unused : 12; /*!< Unused */
  100. uint32_t opcode : 4; /*!< Opcode (OPCODE_DELAY) */
  101. } delay; /*!< Format of DELAY instruction */
  102. struct {
  103. uint32_t dreg : 2; /*!< Register which contains data to store */
  104. uint32_t sreg : 2; /*!< Register which contains address in RTC memory (expressed in words) */
  105. uint32_t unused1 : 6; /*!< Unused */
  106. uint32_t offset : 11; /*!< Offset to add to sreg */
  107. uint32_t unused2 : 4; /*!< Unused */
  108. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_ST) */
  109. uint32_t opcode : 4; /*!< Opcode (OPCODE_ST) */
  110. } st; /*!< Format of ST instruction */
  111. struct {
  112. uint32_t dreg : 2; /*!< Register where the data should be loaded to */
  113. uint32_t sreg : 2; /*!< Register which contains address in RTC memory (expressed in words) */
  114. uint32_t unused1 : 6; /*!< Unused */
  115. uint32_t offset : 11; /*!< Offset to add to sreg */
  116. uint32_t unused2 : 7; /*!< Unused */
  117. uint32_t opcode : 4; /*!< Opcode (OPCODE_LD) */
  118. } ld; /*!< Format of LD instruction */
  119. struct {
  120. uint32_t unused : 28; /*!< Unused */
  121. uint32_t opcode : 4; /*!< Opcode (OPCODE_HALT) */
  122. } halt; /*!< Format of HALT instruction */
  123. struct {
  124. uint32_t dreg : 2; /*!< Register which contains target PC, expressed in words (used if .reg == 1) */
  125. uint32_t addr : 11; /*!< Target PC, expressed in words (used if .reg == 0) */
  126. uint32_t unused : 8; /*!< Unused */
  127. uint32_t reg : 1; /*!< Target PC in register (1) or immediate (0) */
  128. uint32_t type : 3; /*!< Jump condition (BX_JUMP_TYPE_xxx) */
  129. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_BX) */
  130. uint32_t opcode : 4; /*!< Opcode (OPCODE_BRANCH) */
  131. } bx; /*!< Format of BRANCH instruction (absolute address) */
  132. struct {
  133. uint32_t imm : 16; /*!< Immediate value to compare against */
  134. uint32_t cmp : 1; /*!< Comparison to perform: B_CMP_L or B_CMP_GE */
  135. uint32_t offset : 7; /*!< Absolute value of target PC offset w.r.t. current PC, expressed in words */
  136. uint32_t sign : 1; /*!< Sign of target PC offset: 0: positive, 1: negative */
  137. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_B) */
  138. uint32_t opcode : 4; /*!< Opcode (OPCODE_BRANCH) */
  139. } b; /*!< Format of BRANCH instruction (relative address) */
  140. struct {
  141. uint32_t dreg : 2; /*!< Destination register */
  142. uint32_t sreg : 2; /*!< Register with operand A */
  143. uint32_t treg : 2; /*!< Register with operand B */
  144. uint32_t unused : 15; /*!< Unused */
  145. uint32_t sel : 4; /*!< Operation to perform, one of ALU_SEL_xxx */
  146. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_ALU_REG) */
  147. uint32_t opcode : 4; /*!< Opcode (OPCODE_ALU) */
  148. } alu_reg; /*!< Format of ALU instruction (both sources are registers) */
  149. struct {
  150. uint32_t dreg : 2; /*!< Destination register */
  151. uint32_t sreg : 2; /*!< Register with operand A */
  152. uint32_t imm : 16; /*!< Immediate value of operand B */
  153. uint32_t unused : 1; /*!< Unused */
  154. uint32_t sel : 4; /*!< Operation to perform, one of ALU_SEL_xxx */
  155. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_ALU_IMM) */
  156. uint32_t opcode : 4; /*!< Opcode (OPCODE_ALU) */
  157. } alu_imm; /*!< Format of ALU instruction (one source is an immediate) */
  158. struct {
  159. uint32_t addr : 8; /*!< Address within either RTC_CNTL, RTC_IO, or SARADC */
  160. uint32_t periph_sel : 2; /*!< Select peripheral: RTC_CNTL (0), RTC_IO(1), SARADC(2) */
  161. uint32_t data : 8; /*!< 8 bits of data to write */
  162. uint32_t high : 5; /*!< High bit */
  163. uint32_t low : 5; /*!< Low bit */
  164. uint32_t opcode : 4; /*!< Opcode (OPCODE_WR_REG) */
  165. } wr_reg; /*!< Format of WR_REG instruction */
  166. struct {
  167. uint32_t addr : 8; /*!< Address within either RTC_CNTL, RTC_IO, or SARADC */
  168. uint32_t periph_sel : 2; /*!< Select peripheral: RTC_CNTL (0), RTC_IO(1), SARADC(2) */
  169. uint32_t unused : 8; /*!< Unused */
  170. uint32_t high : 5; /*!< High bit */
  171. uint32_t low : 5; /*!< Low bit */
  172. uint32_t opcode : 4; /*!< Opcode (OPCODE_WR_REG) */
  173. } rd_reg; /*!< Format of WR_REG instruction */
  174. struct {
  175. uint32_t dreg : 2; /*!< Register where to store ADC result */
  176. uint32_t mux : 4; /*!< Select SARADC pad (mux + 1) */
  177. uint32_t sar_sel : 1; /*!< Select SARADC0 (0) or SARADC1 (1) */
  178. uint32_t unused1 : 1; /*!< Unused */
  179. uint32_t cycles : 16; /*!< TBD, cycles used for measurement */
  180. uint32_t unused2 : 4; /*!< Unused */
  181. uint32_t opcode: 4; /*!< Opcode (OPCODE_ADC) */
  182. } adc; /*!< Format of ADC instruction */
  183. struct {
  184. uint32_t dreg : 2; /*!< Register where to store temperature measurement result */
  185. uint32_t wait_delay: 14; /*!< Cycles to wait after measurement is done */
  186. uint32_t cycles: 12; /*!< Cycles used to perform measurement */
  187. uint32_t opcode: 4; /*!< Opcode (OPCODE_TSENS) */
  188. } tsens; /*!< Format of TSENS instruction */
  189. struct {
  190. uint32_t i2c_addr : 8; /*!< I2C slave address */
  191. uint32_t data : 8; /*!< Data to read or write */
  192. uint32_t low_bits : 3; /*!< TBD */
  193. uint32_t high_bits : 3; /*!< TBD */
  194. uint32_t i2c_sel : 4; /*!< TBD, select reg_i2c_slave_address[7:0] */
  195. uint32_t unused : 1; /*!< Unused */
  196. uint32_t rw : 1; /*!< Write (1) or read (0) */
  197. uint32_t opcode : 4; /*!< Opcode (OPCODE_I2C) */
  198. } i2c; /*!< Format of I2C instruction */
  199. struct {
  200. uint32_t wakeup : 1; /*!< Set to 1 to wake up chip */
  201. uint32_t unused : 24; /*!< Unused */
  202. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_WAKEUP) */
  203. uint32_t opcode : 4; /*!< Opcode (OPCODE_END) */
  204. } end; /*!< Format of END instruction with wakeup */
  205. struct {
  206. uint32_t cycle_sel : 4; /*!< Select which one of SARADC_ULP_CP_SLEEP_CYCx_REG to get the sleep duration from */
  207. uint32_t unused : 21; /*!< Unused */
  208. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_SLEEP) */
  209. uint32_t opcode : 4; /*!< Opcode (OPCODE_END) */
  210. } sleep; /*!< Format of END instruction with sleep */
  211. struct {
  212. uint32_t label : 16; /*!< Label number */
  213. uint32_t unused : 8; /*!< Unused */
  214. uint32_t sub_opcode : 4; /*!< SUB_OPCODE_MACRO_LABEL or SUB_OPCODE_MACRO_BRANCH */
  215. uint32_t opcode: 4; /*!< Opcode (OPCODE_MACRO) */
  216. } macro; /*!< Format of tokens used by LABEL and BRANCH macros */
  217. } ulp_insn_t;
  218. /**
  219. * Delay (nop) for a given number of cycles
  220. */
  221. #define I_DELAY(cycles_) { .delay = {\
  222. .opcode = OPCODE_DELAY, \
  223. .unused = 0, \
  224. .cycles = cycles_ } }
  225. /**
  226. * Halt the coprocessor
  227. */
  228. #define I_HALT() { .halt = {\
  229. .unused = 0, \
  230. .opcode = OPCODE_HALT } }
  231. /**
  232. * Store value from register reg_val into RTC memory.
  233. *
  234. * The value is written to an offset calculated by adding value of
  235. * reg_addr register and offset_ field (this offset is expressed in 32-bit words).
  236. * 32 bits written to RTC memory are built as follows:
  237. * - 5 MSBs are zero
  238. * - next 11 bits hold the PC of current instruction, expressed in 32-bit words
  239. * - next 16 bits hold the actual value to be written
  240. *
  241. * RTC_SLOW_MEM[addr + offset_] = { 5'b0, insn_PC[10:0], val[15:0] }
  242. */
  243. #define I_ST(reg_val, reg_addr, offset_) { .st = { \
  244. .dreg = reg_val, \
  245. .sreg = reg_addr, \
  246. .unused1 = 0, \
  247. .offset = offset_, \
  248. .unused2 = 0, \
  249. .sub_opcode = SUB_OPCODE_ST, \
  250. .opcode = OPCODE_ST } }
  251. /**
  252. * Load value from RTC memory into reg_dest register.
  253. *
  254. * Loads 16 LSBs from RTC memory word given by the sum of value in reg_addr and
  255. * value of offset_.
  256. */
  257. #define I_LD(reg_dest, reg_addr, offset_) { .ld = { \
  258. .dreg = reg_dest, \
  259. .sreg = reg_addr, \
  260. .unused1 = 0, \
  261. .offset = offset_, \
  262. .unused2 = 0, \
  263. .opcode = OPCODE_LD } }
  264. /**
  265. * Branch relative if R0 less than immediate value.
  266. *
  267. * pc_offset is expressed in words, and can be from -127 to 127
  268. * imm_value is a 16-bit value to compare R0 against
  269. */
  270. #define I_BL(pc_offset, imm_value) { .b = { \
  271. .imm = imm_value, \
  272. .cmp = B_CMP_L, \
  273. .offset = abs(pc_offset), \
  274. .sign = (pc_offset >= 0) ? 0 : 1, \
  275. .sub_opcode = SUB_OPCODE_B, \
  276. .opcode = OPCODE_BRANCH } }
  277. /**
  278. * Branch relative if R0 greater or equal than immediate value.
  279. *
  280. * pc_offset is expressed in words, and can be from -127 to 127
  281. * imm_value is a 16-bit value to compare R0 against
  282. */
  283. #define I_BGE(pc_offset, imm_value) { .b = { \
  284. .imm = imm_value, \
  285. .cmp = B_CMP_GE, \
  286. .offset = abs(pc_offset), \
  287. .sign = (pc_offset >= 0) ? 0 : 1, \
  288. .sub_opcode = SUB_OPCODE_B, \
  289. .opcode = OPCODE_BRANCH } }
  290. /**
  291. * Unconditional branch to absolute PC, address in register.
  292. *
  293. * reg_pc is the register which contains address to jump to.
  294. * Address is expressed in 32-bit words.
  295. */
  296. #define I_BXR(reg_pc) { .bx = { \
  297. .dreg = reg_pc, \
  298. .addr = 0, \
  299. .unused = 0, \
  300. .reg = 1, \
  301. .type = BX_JUMP_TYPE_DIRECT, \
  302. .sub_opcode = SUB_OPCODE_BX, \
  303. .opcode = OPCODE_BRANCH } }
  304. /**
  305. * Unconditional branch to absolute PC, immediate address.
  306. *
  307. * Address imm_pc is expressed in 32-bit words.
  308. */
  309. #define I_BXI(imm_pc) { .bx = { \
  310. .dreg = 0, \
  311. .addr = imm_pc, \
  312. .unused = 0, \
  313. .reg = 0, \
  314. .type = BX_JUMP_TYPE_DIRECT, \
  315. .sub_opcode = SUB_OPCODE_BX, \
  316. .opcode = OPCODE_BRANCH } }
  317. /**
  318. * Branch to absolute PC if ALU result is zero, address in register.
  319. *
  320. * reg_pc is the register which contains address to jump to.
  321. * Address is expressed in 32-bit words.
  322. */
  323. #define I_BXZR(reg_pc) { .bx = { \
  324. .dreg = reg_pc, \
  325. .addr = 0, \
  326. .unused = 0, \
  327. .reg = 1, \
  328. .type = BX_JUMP_TYPE_ZERO, \
  329. .sub_opcode = SUB_OPCODE_BX, \
  330. .opcode = OPCODE_BRANCH } }
  331. /**
  332. * Branch to absolute PC if ALU result is zero, immediate address.
  333. *
  334. * Address imm_pc is expressed in 32-bit words.
  335. */
  336. #define I_BXZI(imm_pc) { .bx = { \
  337. .dreg = 0, \
  338. .addr = imm_pc, \
  339. .unused = 0, \
  340. .reg = 0, \
  341. .type = BX_JUMP_TYPE_ZERO, \
  342. .sub_opcode = SUB_OPCODE_BX, \
  343. .opcode = OPCODE_BRANCH } }
  344. /**
  345. * Branch to absolute PC if ALU overflow, address in register
  346. *
  347. * reg_pc is the register which contains address to jump to.
  348. * Address is expressed in 32-bit words.
  349. */
  350. #define I_BXFR(reg_pc) { .bx = { \
  351. .dreg = reg_pc, \
  352. .addr = 0, \
  353. .unused = 0, \
  354. .reg = 1, \
  355. .type = BX_JUMP_TYPE_OVF, \
  356. .sub_opcode = SUB_OPCODE_BX, \
  357. .opcode = OPCODE_BRANCH } }
  358. /**
  359. * Branch to absolute PC if ALU overflow, immediate address
  360. *
  361. * Address imm_pc is expressed in 32-bit words.
  362. */
  363. #define I_BXFI(imm_pc) { .bx = { \
  364. .dreg = 0, \
  365. .addr = imm_pc, \
  366. .unused = 0, \
  367. .reg = 0, \
  368. .type = BX_JUMP_TYPE_OVF, \
  369. .sub_opcode = SUB_OPCODE_BX, \
  370. .opcode = OPCODE_BRANCH } }
  371. /**
  372. * Addition: dest = src1 + src2
  373. */
  374. #define I_ADDR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  375. .dreg = reg_dest, \
  376. .sreg = reg_src1, \
  377. .treg = reg_src2, \
  378. .unused = 0, \
  379. .sel = ALU_SEL_ADD, \
  380. .sub_opcode = SUB_OPCODE_ALU_REG, \
  381. .opcode = OPCODE_ALU } }
  382. /**
  383. * Subtraction: dest = src1 - src2
  384. */
  385. #define I_SUBR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  386. .dreg = reg_dest, \
  387. .sreg = reg_src1, \
  388. .treg = reg_src2, \
  389. .unused = 0, \
  390. .sel = ALU_SEL_SUB, \
  391. .sub_opcode = SUB_OPCODE_ALU_REG, \
  392. .opcode = OPCODE_ALU } }
  393. /**
  394. * Logical AND: dest = src1 & src2
  395. */
  396. #define I_ANDR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  397. .dreg = reg_dest, \
  398. .sreg = reg_src1, \
  399. .treg = reg_src2, \
  400. .unused = 0, \
  401. .sel = ALU_SEL_AND, \
  402. .sub_opcode = SUB_OPCODE_ALU_REG, \
  403. .opcode = OPCODE_ALU } }
  404. /**
  405. * Logical OR: dest = src1 | src2
  406. */
  407. #define I_ORR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  408. .dreg = reg_dest, \
  409. .sreg = reg_src1, \
  410. .treg = reg_src2, \
  411. .unused = 0, \
  412. .sel = ALU_SEL_OR, \
  413. .sub_opcode = SUB_OPCODE_ALU_REG, \
  414. .opcode = OPCODE_ALU } }
  415. /**
  416. * Copy: dest = src
  417. */
  418. #define I_MOVR(reg_dest, reg_src) { .alu_reg = { \
  419. .dreg = reg_dest, \
  420. .sreg = reg_src, \
  421. .treg = 0, \
  422. .unused = 0, \
  423. .sel = ALU_SEL_MOV, \
  424. .sub_opcode = SUB_OPCODE_ALU_REG, \
  425. .opcode = OPCODE_ALU } }
  426. /**
  427. * Logical shift left: dest = src << shift
  428. */
  429. #define I_LSHR(reg_dest, reg_src, reg_shift) { .alu_reg = { \
  430. .dreg = reg_dest, \
  431. .sreg = reg_src, \
  432. .treg = reg_shift, \
  433. .unused = 0, \
  434. .sel = ALU_SEL_LSH, \
  435. .sub_opcode = SUB_OPCODE_ALU_REG, \
  436. .opcode = OPCODE_ALU } }
  437. /**
  438. * Logical shift right: dest = src >> shift
  439. */
  440. #define I_RSHR(reg_dest, reg_src, reg_shift) { .alu_reg = { \
  441. .dreg = reg_dest, \
  442. .sreg = reg_src, \
  443. .treg = reg_shift, \
  444. .unused = 0, \
  445. .sel = ALU_SEL_RSH, \
  446. .sub_opcode = SUB_OPCODE_ALU_REG, \
  447. .opcode = OPCODE_ALU } }
  448. /**
  449. * Add register and an immediate value: dest = src1 + imm
  450. */
  451. #define I_ADDI(reg_dest, reg_src, imm_) { .alu_imm = { \
  452. .dreg = reg_dest, \
  453. .sreg = reg_src, \
  454. .imm = imm_, \
  455. .unused = 0, \
  456. .sel = ALU_SEL_ADD, \
  457. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  458. .opcode = OPCODE_ALU } }
  459. /**
  460. * Subtract register and an immediate value: dest = src - imm
  461. */
  462. #define I_SUBI(reg_dest, reg_src, imm_) { .alu_imm = { \
  463. .dreg = reg_dest, \
  464. .sreg = reg_src, \
  465. .imm = imm_, \
  466. .unused = 0, \
  467. .sel = ALU_SEL_SUB, \
  468. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  469. .opcode = OPCODE_ALU } }
  470. /**
  471. * Logical AND register and an immediate value: dest = src & imm
  472. */
  473. #define I_ANDI(reg_dest, reg_src, imm_) { .alu_imm = { \
  474. .dreg = reg_dest, \
  475. .sreg = reg_src, \
  476. .imm = reg_imm_, \
  477. .unused = 0, \
  478. .sel = ALU_SEL_AND, \
  479. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  480. .opcode = OPCODE_ALU } }
  481. /**
  482. * Logical OR register and an immediate value: dest = src | imm
  483. */
  484. #define I_ORI(reg_dest, reg_src, imm_) { .alu_imm = { \
  485. .dreg = reg_dest, \
  486. .sreg = reg_src, \
  487. .imm = imm_, \
  488. .unused = 0, \
  489. .sel = ALU_SEL_OR, \
  490. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  491. .opcode = OPCODE_ALU } }
  492. /**
  493. * Copy an immediate value into register: dest = imm
  494. */
  495. #define I_MOVI(reg_dest, imm_) { .alu_imm = { \
  496. .dreg = reg_dest, \
  497. .sreg = 0, \
  498. .imm = imm_, \
  499. .unused = 0, \
  500. .sel = ALU_SEL_MOV, \
  501. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  502. .opcode = OPCODE_ALU } }
  503. /**
  504. * Logical shift left register value by an immediate: dest = src << imm
  505. */
  506. #define I_LSHI(reg_dest, reg_src, imm_) { .alu_imm = { \
  507. .dreg = reg_dest, \
  508. .sreg = reg_src, \
  509. .imm = imm_, \
  510. .unused = 0, \
  511. .sel = ALU_SEL_LSH, \
  512. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  513. .opcode = OPCODE_ALU } }
  514. /**
  515. * Logical shift right register value by an immediate: dest = val >> imm
  516. */
  517. #define I_RSHI(reg_dest, reg_src, imm_) { .alu_imm = { \
  518. .dreg = reg_dest, \
  519. .sreg = reg_src, \
  520. .imm = imm_, \
  521. .unused = 0, \
  522. .sel = ALU_SEL_RSH, \
  523. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  524. .opcode = OPCODE_ALU } }
  525. /**
  526. * Define a label with number label_num.
  527. *
  528. * This is a macro which doesn't generate a real instruction.
  529. * The token generated by this macro is removed by ulp_process_macros_and_load
  530. * function. Label defined using this macro can be used in branch macros defined
  531. * below.
  532. */
  533. #define M_LABEL(label_num) { .macro = { \
  534. .label = label_num, \
  535. .unused = 0, \
  536. .sub_opcode = SUB_OPCODE_MACRO_LABEL, \
  537. .opcode = OPCODE_MACRO } }
  538. /**
  539. * Token macro used by M_B and M_BX macros. Not to be used directly.
  540. */
  541. #define M_BRANCH(label_num) { .macro = { \
  542. .label = label_num, \
  543. .unused = 0, \
  544. .sub_opcode = SUB_OPCODE_MACRO_BRANCH, \
  545. .opcode = OPCODE_MACRO } }
  546. /**
  547. * Macro: branch to label label_num if R0 is less than immediate value.
  548. *
  549. * This macro generates two ulp_insn_t values separated by a comma, and should
  550. * be used when defining contents of ulp_insn_t arrays. First value is not a
  551. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  552. * function.
  553. */
  554. #define M_BL(label_num, imm_value) \
  555. M_BRANCH(label_num), \
  556. I_BL(0, imm_value)
  557. /**
  558. * Macro: branch to label label_num if R0 is greater or equal than immediate value
  559. *
  560. * This macro generates two ulp_insn_t values separated by a comma, and should
  561. * be used when defining contents of ulp_insn_t arrays. First value is not a
  562. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  563. * function.
  564. */
  565. #define M_BGE(label_num, imm_value) \
  566. M_BRANCH(label_num), \
  567. I_BGE(0, imm_value)
  568. /**
  569. * Macro: unconditional branch to label
  570. *
  571. * This macro generates two ulp_insn_t values separated by a comma, and should
  572. * be used when defining contents of ulp_insn_t arrays. First value is not a
  573. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  574. * function.
  575. */
  576. #define M_BX(label_num) \
  577. M_BRANCH(label_num), \
  578. I_BXI(0)
  579. /**
  580. * Macro: branch to label if ALU result is zero
  581. *
  582. * This macro generates two ulp_insn_t values separated by a comma, and should
  583. * be used when defining contents of ulp_insn_t arrays. First value is not a
  584. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  585. * function.
  586. */
  587. #define M_BXZ(label_num) \
  588. M_BRANCH(label_num), \
  589. I_BXZI(0)
  590. /**
  591. * Macro: branch to label if ALU overflow
  592. *
  593. * This macro generates two ulp_insn_t values separated by a comma, and should
  594. * be used when defining contents of ulp_insn_t arrays. First value is not a
  595. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  596. * function.
  597. */
  598. #define M_BXF(label_num) \
  599. M_BRANCH(label_num), \
  600. I_BXFI(0)
  601. #define RTC_SLOW_MEM ((uint32_t*) 0x50000000) /*!< RTC slow memory, 8k size */
  602. /**
  603. * @brief Resolve all macro references in a program and load it into RTC memory
  604. * @param load_addr address where the program should be loaded, expressed in 32-bit words
  605. * @param program ulp_insn_t array with the program
  606. * @param psize size of the program, expressed in 32-bit words
  607. * @return
  608. * - ESP_OK on success
  609. * - ESP_ERR_NO_MEM if auxiliary temporary structure can not be allocated
  610. * - one of ESP_ERR_ULP_xxx if program is not valid or can not be loaded
  611. */
  612. esp_err_t ulp_process_macros_and_load(uint32_t load_addr, const ulp_insn_t* program, size_t* psize);
  613. /**
  614. * @brief Run the program loaded into RTC memory
  615. * @param entry_point entry point, expressed in 32-bit words
  616. * @return ESP_OK on success
  617. */
  618. esp_err_t ulp_run(uint32_t entry_point);
  619. #ifdef __cplusplus
  620. }
  621. #endif