ulp.h 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  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 "soc/reg_base.h"
  13. #ifdef __cplusplus
  14. extern "C" {
  15. #endif
  16. #define ULP_FSM_PREPARE_SLEEP_CYCLES 2 /*!< Cycles spent by FSM preparing ULP for sleep */
  17. #define ULP_FSM_WAKEUP_SLEEP_CYCLES 2 /*!< Cycles spent by FSM waking up ULP from sleep */
  18. /**
  19. * @defgroup ulp_registers ULP coprocessor registers
  20. * @{
  21. */
  22. #define R0 0 /*!< general purpose register 0 */
  23. #define R1 1 /*!< general purpose register 1 */
  24. #define R2 2 /*!< general purpose register 2 */
  25. #define R3 3 /*!< general purpose register 3 */
  26. /**@}*/
  27. /** @defgroup ulp_opcodes ULP coprocessor opcodes, sub opcodes, and various modifiers/flags
  28. *
  29. * These definitions are not intended to be used directly.
  30. * They are used in definitions of instructions later on.
  31. *
  32. * @{
  33. */
  34. #define OPCODE_WR_REG 1 /*!< Instruction: write peripheral register (RTC_CNTL/RTC_IO/SARADC) (not implemented yet) */
  35. #define OPCODE_RD_REG 2 /*!< Instruction: read peripheral register (RTC_CNTL/RTC_IO/SARADC) (not implemented yet) */
  36. #define RD_REG_PERIPH_RTC_CNTL 0 /*!< Identifier of RTC_CNTL peripheral for RD_REG and WR_REG instructions */
  37. #define RD_REG_PERIPH_RTC_IO 1 /*!< Identifier of RTC_IO peripheral for RD_REG and WR_REG instructions */
  38. #define RD_REG_PERIPH_SENS 2 /*!< Identifier of SARADC peripheral for RD_REG and WR_REG instructions */
  39. #define RD_REG_PERIPH_RTC_I2C 3 /*!< Identifier of RTC_I2C peripheral for RD_REG and WR_REG instructions */
  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 */
  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. * @brief Instruction format structure
  76. *
  77. * All ULP instructions are 32 bit long.
  78. * This union contains field layouts used by all of the supported instructions.
  79. * This union also includes a special "macro" instruction layout.
  80. * This is not a real instruction which can be executed by the CPU. It acts
  81. * as a token which is removed from the program by the
  82. * ulp_process_macros_and_load function.
  83. *
  84. * These structures are not intended to be used directly.
  85. * Preprocessor definitions provided below fill the fields of these structure with
  86. * the right arguments.
  87. */
  88. union ulp_insn {
  89. struct {
  90. uint32_t cycles : 16; /*!< Number of cycles to sleep */
  91. uint32_t unused : 12; /*!< Unused */
  92. uint32_t opcode : 4; /*!< Opcode (OPCODE_DELAY) */
  93. } delay; /*!< Format of DELAY instruction */
  94. struct {
  95. uint32_t dreg : 2; /*!< Register which contains data to store */
  96. uint32_t sreg : 2; /*!< Register which contains address in RTC memory (expressed in words) */
  97. uint32_t unused1 : 6; /*!< Unused */
  98. uint32_t offset : 11; /*!< Offset to add to sreg */
  99. uint32_t unused2 : 4; /*!< Unused */
  100. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_ST) */
  101. uint32_t opcode : 4; /*!< Opcode (OPCODE_ST) */
  102. } st; /*!< Format of ST instruction */
  103. struct {
  104. uint32_t dreg : 2; /*!< Register where the data should be loaded to */
  105. uint32_t sreg : 2; /*!< Register which contains address in RTC memory (expressed in words) */
  106. uint32_t unused1 : 6; /*!< Unused */
  107. uint32_t offset : 11; /*!< Offset to add to sreg */
  108. uint32_t unused2 : 7; /*!< Unused */
  109. uint32_t opcode : 4; /*!< Opcode (OPCODE_LD) */
  110. } ld; /*!< Format of LD instruction */
  111. struct {
  112. uint32_t unused : 28; /*!< Unused */
  113. uint32_t opcode : 4; /*!< Opcode (OPCODE_HALT) */
  114. } halt; /*!< Format of HALT instruction */
  115. struct {
  116. uint32_t dreg : 2; /*!< Register which contains target PC, expressed in words (used if .reg == 1) */
  117. uint32_t addr : 11; /*!< Target PC, expressed in words (used if .reg == 0) */
  118. uint32_t unused : 8; /*!< Unused */
  119. uint32_t reg : 1; /*!< Target PC in register (1) or immediate (0) */
  120. uint32_t type : 3; /*!< Jump condition (BX_JUMP_TYPE_xxx) */
  121. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_BX) */
  122. uint32_t opcode : 4; /*!< Opcode (OPCODE_BRANCH) */
  123. } bx; /*!< Format of BRANCH instruction (absolute address) */
  124. struct {
  125. uint32_t imm : 16; /*!< Immediate value to compare against */
  126. uint32_t cmp : 1; /*!< Comparison to perform: B_CMP_L or B_CMP_GE */
  127. uint32_t offset : 7; /*!< Absolute value of target PC offset w.r.t. current PC, expressed in words */
  128. uint32_t sign : 1; /*!< Sign of target PC offset: 0: positive, 1: negative */
  129. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_B) */
  130. uint32_t opcode : 4; /*!< Opcode (OPCODE_BRANCH) */
  131. } b; /*!< Format of BRANCH instruction (relative address) */
  132. struct {
  133. uint32_t dreg : 2; /*!< Destination register */
  134. uint32_t sreg : 2; /*!< Register with operand A */
  135. uint32_t treg : 2; /*!< Register with operand B */
  136. uint32_t unused : 15; /*!< Unused */
  137. uint32_t sel : 4; /*!< Operation to perform, one of ALU_SEL_xxx */
  138. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_ALU_REG) */
  139. uint32_t opcode : 4; /*!< Opcode (OPCODE_ALU) */
  140. } alu_reg; /*!< Format of ALU instruction (both sources are registers) */
  141. struct {
  142. uint32_t dreg : 2; /*!< Destination register */
  143. uint32_t sreg : 2; /*!< Register with operand A */
  144. uint32_t imm : 16; /*!< Immediate value of operand B */
  145. uint32_t unused : 1; /*!< Unused */
  146. uint32_t sel : 4; /*!< Operation to perform, one of ALU_SEL_xxx */
  147. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_ALU_IMM) */
  148. uint32_t opcode : 4; /*!< Opcode (OPCODE_ALU) */
  149. } alu_imm; /*!< Format of ALU instruction (one source is an immediate) */
  150. struct {
  151. uint32_t addr : 8; /*!< Address within either RTC_CNTL, RTC_IO, or SARADC */
  152. uint32_t periph_sel : 2; /*!< Select peripheral: RTC_CNTL (0), RTC_IO(1), SARADC(2) */
  153. uint32_t data : 8; /*!< 8 bits of data to write */
  154. uint32_t low : 5; /*!< Low bit */
  155. uint32_t high : 5; /*!< High bit */
  156. uint32_t opcode : 4; /*!< Opcode (OPCODE_WR_REG) */
  157. } wr_reg; /*!< Format of WR_REG instruction */
  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 unused : 8; /*!< Unused */
  162. uint32_t low : 5; /*!< Low bit */
  163. uint32_t high : 5; /*!< High bit */
  164. uint32_t opcode : 4; /*!< Opcode (OPCODE_RD_REG) */
  165. } rd_reg; /*!< Format of RD_REG instruction */
  166. struct {
  167. uint32_t dreg : 2; /*!< Register where to store ADC result */
  168. uint32_t mux : 4; /*!< Select SARADC pad (mux + 1) */
  169. uint32_t sar_sel : 1; /*!< Select SARADC0 (0) or SARADC1 (1) */
  170. uint32_t unused1 : 1; /*!< Unused */
  171. uint32_t cycles : 16; /*!< TBD, cycles used for measurement */
  172. uint32_t unused2 : 4; /*!< Unused */
  173. uint32_t opcode: 4; /*!< Opcode (OPCODE_ADC) */
  174. } adc; /*!< Format of ADC instruction */
  175. struct {
  176. uint32_t dreg : 2; /*!< Register where to store temperature measurement result */
  177. uint32_t wait_delay: 14; /*!< Cycles to wait after measurement is done */
  178. uint32_t reserved: 12; /*!< Reserved, set to 0 */
  179. uint32_t opcode: 4; /*!< Opcode (OPCODE_TSENS) */
  180. } tsens; /*!< Format of TSENS instruction */
  181. struct {
  182. uint32_t i2c_addr : 8; /*!< I2C slave address */
  183. uint32_t data : 8; /*!< Data to read or write */
  184. uint32_t low_bits : 3; /*!< TBD */
  185. uint32_t high_bits : 3; /*!< TBD */
  186. uint32_t i2c_sel : 4; /*!< TBD, select reg_i2c_slave_address[7:0] */
  187. uint32_t unused : 1; /*!< Unused */
  188. uint32_t rw : 1; /*!< Write (1) or read (0) */
  189. uint32_t opcode : 4; /*!< Opcode (OPCODE_I2C) */
  190. } i2c; /*!< Format of I2C instruction */
  191. struct {
  192. uint32_t wakeup : 1; /*!< Set to 1 to wake up chip */
  193. uint32_t unused : 24; /*!< Unused */
  194. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_WAKEUP) */
  195. uint32_t opcode : 4; /*!< Opcode (OPCODE_END) */
  196. } end; /*!< Format of END instruction with wakeup */
  197. struct {
  198. uint32_t cycle_sel : 4; /*!< Select which one of SARADC_ULP_CP_SLEEP_CYCx_REG to get the sleep duration from */
  199. uint32_t unused : 21; /*!< Unused */
  200. uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_SLEEP) */
  201. uint32_t opcode : 4; /*!< Opcode (OPCODE_END) */
  202. } sleep; /*!< Format of END instruction with sleep */
  203. struct {
  204. uint32_t label : 16; /*!< Label number */
  205. uint32_t unused : 8; /*!< Unused */
  206. uint32_t sub_opcode : 4; /*!< SUB_OPCODE_MACRO_LABEL or SUB_OPCODE_MACRO_BRANCH */
  207. uint32_t opcode: 4; /*!< Opcode (OPCODE_MACRO) */
  208. } macro; /*!< Format of tokens used by LABEL and BRANCH macros */
  209. };
  210. typedef union ulp_insn ulp_insn_t;
  211. _Static_assert(sizeof(ulp_insn_t) == 4, "ULP coprocessor instruction size should be 4 bytes");
  212. /**
  213. * Delay (nop) for a given number of cycles
  214. */
  215. #define I_DELAY(cycles_) { .delay = {\
  216. .cycles = cycles_, \
  217. .unused = 0, \
  218. .opcode = OPCODE_DELAY } }
  219. /**
  220. * Halt the coprocessor.
  221. *
  222. * This instruction halts the coprocessor, but keeps ULP timer active.
  223. * As such, ULP program will be restarted again by timer.
  224. * To stop the program and prevent the timer from restarting the program,
  225. * use I_END(0) instruction.
  226. */
  227. #define I_HALT() { .halt = {\
  228. .unused = 0, \
  229. .opcode = OPCODE_HALT } }
  230. /**
  231. * Map SoC peripheral register to periph_sel field of RD_REG and WR_REG
  232. * instructions.
  233. *
  234. * @param reg peripheral register in RTC_CNTL_, RTC_IO_, SENS_, RTC_I2C peripherals.
  235. * @return periph_sel value for the peripheral to which this register belongs.
  236. */
  237. static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
  238. uint32_t ret = 3;
  239. if (reg < DR_REG_RTCCNTL_BASE) {
  240. assert(0 && "invalid register base");
  241. } else if (reg < DR_REG_RTCIO_BASE) {
  242. ret = RD_REG_PERIPH_RTC_CNTL;
  243. } else if (reg < DR_REG_SENS_BASE) {
  244. ret = RD_REG_PERIPH_RTC_IO;
  245. } else if (reg < DR_REG_RTC_I2C_BASE){
  246. ret = RD_REG_PERIPH_SENS;
  247. } else if (reg < DR_REG_IO_MUX_BASE){
  248. ret = RD_REG_PERIPH_RTC_I2C;
  249. } else {
  250. assert(0 && "invalid register base");
  251. }
  252. return ret;
  253. }
  254. /**
  255. * Write literal value to a peripheral register
  256. *
  257. * reg[high_bit : low_bit] = val
  258. * This instruction can access RTC_CNTL_, RTC_IO_, SENS_, and RTC_I2C peripheral registers.
  259. */
  260. #define I_WR_REG(reg, low_bit, high_bit, val) {.wr_reg = {\
  261. .addr = (reg & 0xff) / sizeof(uint32_t), \
  262. .periph_sel = SOC_REG_TO_ULP_PERIPH_SEL(reg), \
  263. .data = val, \
  264. .low = low_bit, \
  265. .high = high_bit, \
  266. .opcode = OPCODE_WR_REG } }
  267. /**
  268. * Read from peripheral register into R0
  269. *
  270. * R0 = reg[high_bit : low_bit]
  271. * This instruction can access RTC_CNTL_, RTC_IO_, SENS_, and RTC_I2C peripheral registers.
  272. */
  273. #define I_RD_REG(reg, low_bit, high_bit) {.rd_reg = {\
  274. .addr = (reg & 0xff) / sizeof(uint32_t), \
  275. .periph_sel = SOC_REG_TO_ULP_PERIPH_SEL(reg), \
  276. .unused = 0, \
  277. .low = low_bit, \
  278. .high = high_bit, \
  279. .opcode = OPCODE_RD_REG } }
  280. /**
  281. * Set or clear a bit in the peripheral register.
  282. *
  283. * Sets bit (1 << shift) of register reg to value val.
  284. * This instruction can access RTC_CNTL_, RTC_IO_, SENS_, and RTC_I2C peripheral registers.
  285. */
  286. #define I_WR_REG_BIT(reg, shift, val) I_WR_REG(reg, shift, shift, val)
  287. /**
  288. * Wake the SoC from deep sleep.
  289. *
  290. * This instruction initiates wake up from deep sleep.
  291. * Use esp_deep_sleep_enable_ulp_wakeup to enable deep sleep wakeup
  292. * triggered by the ULP before going into deep sleep.
  293. * Note that ULP program will still keep running until the I_HALT
  294. * instruction, and it will still be restarted by timer at regular
  295. * intervals, even when the SoC is woken up.
  296. *
  297. * To stop the ULP program, use I_HALT instruction.
  298. *
  299. * To disable the timer which start ULP program, use I_END()
  300. * instruction. I_END instruction clears the
  301. * RTC_CNTL_ULP_CP_SLP_TIMER_EN_S bit of RTC_CNTL_STATE0_REG
  302. * register, which controls the ULP timer.
  303. */
  304. #define I_WAKE() { .end = { \
  305. .wakeup = 1, \
  306. .unused = 0, \
  307. .sub_opcode = SUB_OPCODE_END, \
  308. .opcode = OPCODE_END } }
  309. /**
  310. * Stop ULP program timer.
  311. *
  312. * This is a convenience macro which disables the ULP program timer.
  313. * Once this instruction is used, ULP program will not be restarted
  314. * anymore until ulp_run function is called.
  315. *
  316. * ULP program will continue running after this instruction. To stop
  317. * the currently running program, use I_HALT().
  318. */
  319. #define I_END() \
  320. I_WR_REG_BIT(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN_S, 0)
  321. /**
  322. * Select the time interval used to run ULP program.
  323. *
  324. * This instructions selects which of the SENS_SLEEP_CYCLES_Sx
  325. * registers' value is used by the ULP program timer.
  326. * When the ULP program stops at I_HALT instruction, ULP program
  327. * timer start counting. When the counter reaches the value of
  328. * the selected SENS_SLEEP_CYCLES_Sx register, ULP program
  329. * start running again from the start address (passed to the ulp_run
  330. * function).
  331. * There are 5 SENS_SLEEP_CYCLES_Sx registers, so 0 <= timer_idx < 5.
  332. *
  333. * By default, SENS_SLEEP_CYCLES_S0 register is used by the ULP
  334. * program timer.
  335. */
  336. #define I_SLEEP_CYCLE_SEL(timer_idx) { .sleep = { \
  337. .cycle_sel = timer_idx, \
  338. .unused = 0, \
  339. .sub_opcode = SUB_OPCODE_SLEEP, \
  340. .opcode = OPCODE_END } }
  341. /**
  342. * Perform temperature sensor measurement and store it into reg_dest.
  343. *
  344. * Delay can be set between 1 and ((1 << 14) - 1). Higher values give
  345. * higher measurement resolution.
  346. */
  347. #define I_TSENS(reg_dest, delay) { .tsens = { \
  348. .dreg = reg_dest, \
  349. .wait_delay = delay, \
  350. .reserved = 0, \
  351. .opcode = OPCODE_TSENS } }
  352. /**
  353. * Perform ADC measurement and store result in reg_dest.
  354. *
  355. * adc_idx selects ADC (0 or 1).
  356. * pad_idx selects ADC pad (0 - 7).
  357. */
  358. #define I_ADC(reg_dest, adc_idx, pad_idx) { .adc = {\
  359. .dreg = reg_dest, \
  360. .mux = pad_idx + 1, \
  361. .sar_sel = adc_idx, \
  362. .unused1 = 0, \
  363. .cycles = 0, \
  364. .unused2 = 0, \
  365. .opcode = OPCODE_ADC } }
  366. /**
  367. * Store value from register reg_val into RTC memory.
  368. *
  369. * The value is written to an offset calculated by adding value of
  370. * reg_addr register and offset_ field (this offset is expressed in 32-bit words).
  371. * 32 bits written to RTC memory are built as follows:
  372. * - bits [31:21] hold the PC of current instruction, expressed in 32-bit words
  373. * - bits [20:18] = 3'b0
  374. * - bits [17:16] reg_addr (0..3)
  375. * - bits [15:0] are assigned the contents of reg_val
  376. *
  377. * RTC_SLOW_MEM[addr + offset_] = { insn_PC[10:0], 3'b0, reg_addr, reg_val[15:0] }
  378. */
  379. #define I_ST(reg_val, reg_addr, offset_) { .st = { \
  380. .dreg = reg_val, \
  381. .sreg = reg_addr, \
  382. .unused1 = 0, \
  383. .offset = offset_, \
  384. .unused2 = 0, \
  385. .sub_opcode = SUB_OPCODE_ST, \
  386. .opcode = OPCODE_ST } }
  387. /**
  388. * Load value from RTC memory into reg_dest register.
  389. *
  390. * Loads 16 LSBs from RTC memory word given by the sum of value in reg_addr and
  391. * value of offset_.
  392. */
  393. #define I_LD(reg_dest, reg_addr, offset_) { .ld = { \
  394. .dreg = reg_dest, \
  395. .sreg = reg_addr, \
  396. .unused1 = 0, \
  397. .offset = offset_, \
  398. .unused2 = 0, \
  399. .opcode = OPCODE_LD } }
  400. /**
  401. * Branch relative if R0 less than immediate value.
  402. *
  403. * pc_offset is expressed in words, and can be from -127 to 127
  404. * imm_value is a 16-bit value to compare R0 against
  405. */
  406. #define I_BL(pc_offset, imm_value) { .b = { \
  407. .imm = imm_value, \
  408. .cmp = B_CMP_L, \
  409. .offset = abs(pc_offset), \
  410. .sign = (pc_offset >= 0) ? 0 : 1, \
  411. .sub_opcode = SUB_OPCODE_B, \
  412. .opcode = OPCODE_BRANCH } }
  413. /**
  414. * Branch relative if R0 greater or equal than immediate value.
  415. *
  416. * pc_offset is expressed in words, and can be from -127 to 127
  417. * imm_value is a 16-bit value to compare R0 against
  418. */
  419. #define I_BGE(pc_offset, imm_value) { .b = { \
  420. .imm = imm_value, \
  421. .cmp = B_CMP_GE, \
  422. .offset = abs(pc_offset), \
  423. .sign = (pc_offset >= 0) ? 0 : 1, \
  424. .sub_opcode = SUB_OPCODE_B, \
  425. .opcode = OPCODE_BRANCH } }
  426. /**
  427. * Unconditional branch to absolute PC, address in register.
  428. *
  429. * reg_pc is the register which contains address to jump to.
  430. * Address is expressed in 32-bit words.
  431. */
  432. #define I_BXR(reg_pc) { .bx = { \
  433. .dreg = reg_pc, \
  434. .addr = 0, \
  435. .unused = 0, \
  436. .reg = 1, \
  437. .type = BX_JUMP_TYPE_DIRECT, \
  438. .sub_opcode = SUB_OPCODE_BX, \
  439. .opcode = OPCODE_BRANCH } }
  440. /**
  441. * Unconditional branch to absolute PC, immediate address.
  442. *
  443. * Address imm_pc is expressed in 32-bit words.
  444. */
  445. #define I_BXI(imm_pc) { .bx = { \
  446. .dreg = 0, \
  447. .addr = imm_pc, \
  448. .unused = 0, \
  449. .reg = 0, \
  450. .type = BX_JUMP_TYPE_DIRECT, \
  451. .sub_opcode = SUB_OPCODE_BX, \
  452. .opcode = OPCODE_BRANCH } }
  453. /**
  454. * Branch to absolute PC if ALU result is zero, address in register.
  455. *
  456. * reg_pc is the register which contains address to jump to.
  457. * Address is expressed in 32-bit words.
  458. */
  459. #define I_BXZR(reg_pc) { .bx = { \
  460. .dreg = reg_pc, \
  461. .addr = 0, \
  462. .unused = 0, \
  463. .reg = 1, \
  464. .type = BX_JUMP_TYPE_ZERO, \
  465. .sub_opcode = SUB_OPCODE_BX, \
  466. .opcode = OPCODE_BRANCH } }
  467. /**
  468. * Branch to absolute PC if ALU result is zero, immediate address.
  469. *
  470. * Address imm_pc is expressed in 32-bit words.
  471. */
  472. #define I_BXZI(imm_pc) { .bx = { \
  473. .dreg = 0, \
  474. .addr = imm_pc, \
  475. .unused = 0, \
  476. .reg = 0, \
  477. .type = BX_JUMP_TYPE_ZERO, \
  478. .sub_opcode = SUB_OPCODE_BX, \
  479. .opcode = OPCODE_BRANCH } }
  480. /**
  481. * Branch to absolute PC if ALU overflow, address in register
  482. *
  483. * reg_pc is the register which contains address to jump to.
  484. * Address is expressed in 32-bit words.
  485. */
  486. #define I_BXFR(reg_pc) { .bx = { \
  487. .dreg = reg_pc, \
  488. .addr = 0, \
  489. .unused = 0, \
  490. .reg = 1, \
  491. .type = BX_JUMP_TYPE_OVF, \
  492. .sub_opcode = SUB_OPCODE_BX, \
  493. .opcode = OPCODE_BRANCH } }
  494. /**
  495. * Branch to absolute PC if ALU overflow, immediate address
  496. *
  497. * Address imm_pc is expressed in 32-bit words.
  498. */
  499. #define I_BXFI(imm_pc) { .bx = { \
  500. .dreg = 0, \
  501. .addr = imm_pc, \
  502. .unused = 0, \
  503. .reg = 0, \
  504. .type = BX_JUMP_TYPE_OVF, \
  505. .sub_opcode = SUB_OPCODE_BX, \
  506. .opcode = OPCODE_BRANCH } }
  507. /**
  508. * Addition: dest = src1 + src2
  509. */
  510. #define I_ADDR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  511. .dreg = reg_dest, \
  512. .sreg = reg_src1, \
  513. .treg = reg_src2, \
  514. .unused = 0, \
  515. .sel = ALU_SEL_ADD, \
  516. .sub_opcode = SUB_OPCODE_ALU_REG, \
  517. .opcode = OPCODE_ALU } }
  518. /**
  519. * Subtraction: dest = src1 - src2
  520. */
  521. #define I_SUBR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  522. .dreg = reg_dest, \
  523. .sreg = reg_src1, \
  524. .treg = reg_src2, \
  525. .unused = 0, \
  526. .sel = ALU_SEL_SUB, \
  527. .sub_opcode = SUB_OPCODE_ALU_REG, \
  528. .opcode = OPCODE_ALU } }
  529. /**
  530. * Logical AND: dest = src1 & src2
  531. */
  532. #define I_ANDR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  533. .dreg = reg_dest, \
  534. .sreg = reg_src1, \
  535. .treg = reg_src2, \
  536. .unused = 0, \
  537. .sel = ALU_SEL_AND, \
  538. .sub_opcode = SUB_OPCODE_ALU_REG, \
  539. .opcode = OPCODE_ALU } }
  540. /**
  541. * Logical OR: dest = src1 | src2
  542. */
  543. #define I_ORR(reg_dest, reg_src1, reg_src2) { .alu_reg = { \
  544. .dreg = reg_dest, \
  545. .sreg = reg_src1, \
  546. .treg = reg_src2, \
  547. .unused = 0, \
  548. .sel = ALU_SEL_OR, \
  549. .sub_opcode = SUB_OPCODE_ALU_REG, \
  550. .opcode = OPCODE_ALU } }
  551. /**
  552. * Copy: dest = src
  553. */
  554. #define I_MOVR(reg_dest, reg_src) { .alu_reg = { \
  555. .dreg = reg_dest, \
  556. .sreg = reg_src, \
  557. .treg = 0, \
  558. .unused = 0, \
  559. .sel = ALU_SEL_MOV, \
  560. .sub_opcode = SUB_OPCODE_ALU_REG, \
  561. .opcode = OPCODE_ALU } }
  562. /**
  563. * Logical shift left: dest = src << shift
  564. */
  565. #define I_LSHR(reg_dest, reg_src, reg_shift) { .alu_reg = { \
  566. .dreg = reg_dest, \
  567. .sreg = reg_src, \
  568. .treg = reg_shift, \
  569. .unused = 0, \
  570. .sel = ALU_SEL_LSH, \
  571. .sub_opcode = SUB_OPCODE_ALU_REG, \
  572. .opcode = OPCODE_ALU } }
  573. /**
  574. * Logical shift right: dest = src >> shift
  575. */
  576. #define I_RSHR(reg_dest, reg_src, reg_shift) { .alu_reg = { \
  577. .dreg = reg_dest, \
  578. .sreg = reg_src, \
  579. .treg = reg_shift, \
  580. .unused = 0, \
  581. .sel = ALU_SEL_RSH, \
  582. .sub_opcode = SUB_OPCODE_ALU_REG, \
  583. .opcode = OPCODE_ALU } }
  584. /**
  585. * Add register and an immediate value: dest = src1 + imm
  586. */
  587. #define I_ADDI(reg_dest, reg_src, imm_) { .alu_imm = { \
  588. .dreg = reg_dest, \
  589. .sreg = reg_src, \
  590. .imm = imm_, \
  591. .unused = 0, \
  592. .sel = ALU_SEL_ADD, \
  593. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  594. .opcode = OPCODE_ALU } }
  595. /**
  596. * Subtract register and an immediate value: dest = src - imm
  597. */
  598. #define I_SUBI(reg_dest, reg_src, imm_) { .alu_imm = { \
  599. .dreg = reg_dest, \
  600. .sreg = reg_src, \
  601. .imm = imm_, \
  602. .unused = 0, \
  603. .sel = ALU_SEL_SUB, \
  604. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  605. .opcode = OPCODE_ALU } }
  606. /**
  607. * Logical AND register and an immediate value: dest = src & imm
  608. */
  609. #define I_ANDI(reg_dest, reg_src, imm_) { .alu_imm = { \
  610. .dreg = reg_dest, \
  611. .sreg = reg_src, \
  612. .imm = imm_, \
  613. .unused = 0, \
  614. .sel = ALU_SEL_AND, \
  615. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  616. .opcode = OPCODE_ALU } }
  617. /**
  618. * Logical OR register and an immediate value: dest = src | imm
  619. */
  620. #define I_ORI(reg_dest, reg_src, imm_) { .alu_imm = { \
  621. .dreg = reg_dest, \
  622. .sreg = reg_src, \
  623. .imm = imm_, \
  624. .unused = 0, \
  625. .sel = ALU_SEL_OR, \
  626. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  627. .opcode = OPCODE_ALU } }
  628. /**
  629. * Copy an immediate value into register: dest = imm
  630. */
  631. #define I_MOVI(reg_dest, imm_) { .alu_imm = { \
  632. .dreg = reg_dest, \
  633. .sreg = 0, \
  634. .imm = imm_, \
  635. .unused = 0, \
  636. .sel = ALU_SEL_MOV, \
  637. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  638. .opcode = OPCODE_ALU } }
  639. /**
  640. * Logical shift left register value by an immediate: dest = src << imm
  641. */
  642. #define I_LSHI(reg_dest, reg_src, imm_) { .alu_imm = { \
  643. .dreg = reg_dest, \
  644. .sreg = reg_src, \
  645. .imm = imm_, \
  646. .unused = 0, \
  647. .sel = ALU_SEL_LSH, \
  648. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  649. .opcode = OPCODE_ALU } }
  650. /**
  651. * Logical shift right register value by an immediate: dest = val >> imm
  652. */
  653. #define I_RSHI(reg_dest, reg_src, imm_) { .alu_imm = { \
  654. .dreg = reg_dest, \
  655. .sreg = reg_src, \
  656. .imm = imm_, \
  657. .unused = 0, \
  658. .sel = ALU_SEL_RSH, \
  659. .sub_opcode = SUB_OPCODE_ALU_IMM, \
  660. .opcode = OPCODE_ALU } }
  661. /**
  662. * Define a label with number label_num.
  663. *
  664. * This is a macro which doesn't generate a real instruction.
  665. * The token generated by this macro is removed by ulp_process_macros_and_load
  666. * function. Label defined using this macro can be used in branch macros defined
  667. * below.
  668. */
  669. #define M_LABEL(label_num) { .macro = { \
  670. .label = label_num, \
  671. .unused = 0, \
  672. .sub_opcode = SUB_OPCODE_MACRO_LABEL, \
  673. .opcode = OPCODE_MACRO } }
  674. /**
  675. * Token macro used by M_B and M_BX macros. Not to be used directly.
  676. */
  677. #define M_BRANCH(label_num) { .macro = { \
  678. .label = label_num, \
  679. .unused = 0, \
  680. .sub_opcode = SUB_OPCODE_MACRO_BRANCH, \
  681. .opcode = OPCODE_MACRO } }
  682. /**
  683. * Macro: branch to label label_num if R0 is less than immediate value.
  684. *
  685. * This macro generates two ulp_insn_t values separated by a comma, and should
  686. * be used when defining contents of ulp_insn_t arrays. First value is not a
  687. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  688. * function.
  689. */
  690. #define M_BL(label_num, imm_value) \
  691. M_BRANCH(label_num), \
  692. I_BL(0, imm_value)
  693. /**
  694. * Macro: branch to label label_num if R0 is greater or equal than immediate value
  695. *
  696. * This macro generates two ulp_insn_t values separated by a comma, and should
  697. * be used when defining contents of ulp_insn_t arrays. First value is not a
  698. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  699. * function.
  700. */
  701. #define M_BGE(label_num, imm_value) \
  702. M_BRANCH(label_num), \
  703. I_BGE(0, imm_value)
  704. /**
  705. * Macro: unconditional branch to label
  706. *
  707. * This macro generates two ulp_insn_t values separated by a comma, and should
  708. * be used when defining contents of ulp_insn_t arrays. First value is not a
  709. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  710. * function.
  711. */
  712. #define M_BX(label_num) \
  713. M_BRANCH(label_num), \
  714. I_BXI(0)
  715. /**
  716. * Macro: branch to label if ALU result is zero
  717. *
  718. * This macro generates two ulp_insn_t values separated by a comma, and should
  719. * be used when defining contents of ulp_insn_t arrays. First value is not a
  720. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  721. * function.
  722. */
  723. #define M_BXZ(label_num) \
  724. M_BRANCH(label_num), \
  725. I_BXZI(0)
  726. /**
  727. * Macro: branch to label if ALU overflow
  728. *
  729. * This macro generates two ulp_insn_t values separated by a comma, and should
  730. * be used when defining contents of ulp_insn_t arrays. First value is not a
  731. * real instruction; it is a token which is removed by ulp_process_macros_and_load
  732. * function.
  733. */
  734. #define M_BXF(label_num) \
  735. M_BRANCH(label_num), \
  736. I_BXFI(0)
  737. #define RTC_SLOW_MEM ((uint32_t*) 0x50000000) /*!< RTC slow memory, 8k size */
  738. #ifdef __cplusplus
  739. }
  740. #endif