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