1 /******************************************************************************
\r
3 * Copyright 2013 Altera Corporation. All Rights Reserved.
\r
5 * Redistribution and use in source and binary forms, with or without
\r
6 * modification, are permitted provided that the following conditions are met:
\r
8 * 1. Redistributions of source code must retain the above copyright notice,
\r
9 * this list of conditions and the following disclaimer.
\r
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
\r
12 * this list of conditions and the following disclaimer in the documentation
\r
13 * and/or other materials provided with the distribution.
\r
15 * 3. The name of the author may not be used to endorse or promote products
\r
16 * derived from this software without specific prior written permission.
\r
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
\r
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO
\r
21 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
\r
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
\r
23 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
\r
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
\r
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
\r
26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
\r
29 ******************************************************************************/
\r
31 #include "alt_dma_program.h"
\r
32 #include "alt_cache.h"
\r
37 // NOTE: To enable debugging output, delete the next line and uncomment the
\r
39 #define dprintf(...)
\r
40 // #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
\r
45 // The following section describes how the bits are used in the "flag" field:
\r
48 // [17:16] Which loop registers (LOOP0, LOOP1) are currently being used by a
\r
49 // partially assembled program. LOOP0 is always used before LOOP1. LOOP1 is
\r
50 // always ended before LOOP0.
\r
51 #define ALT_DMA_PROGRAM_FLAG_LOOP0 (1UL << 16)
\r
52 #define ALT_DMA_PROGRAM_FLAG_LOOP1 (1UL << 17)
\r
53 #define ALT_DMA_PROGRAM_FLAG_LOOP_ALL (ALT_DMA_PROGRAM_FLAG_LOOP0 | ALT_DMA_PROGRAM_FLAG_LOOP1)
\r
55 // [18] Flag that marks LOOP0 as a forever loop. Said another way, LOOP0 is
\r
56 // being used to execute the DMALPFE directive.
\r
57 #define ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE (1UL << 18)
\r
58 // [19] Flag that marks LOOP1 as a forever loop. Said another way, LOOP1 is
\r
59 // being used to execute the DMALPFE directive.
\r
60 #define ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE (1UL << 19)
\r
62 // [24] Flag that the first SAR has been programmed. The SAR field is valid and
\r
63 // is the offset from the start of the buffer where SAR is located.
\r
64 #define ALT_DMA_PROGRAM_FLAG_SAR (1UL << 24)
\r
65 // [25] Flag that the first DAR has been programmed. The DAR field is valid and
\r
66 // is the offset from the start of the buffer where DAR is located.
\r
67 #define ALT_DMA_PROGRAM_FLAG_DAR (1UL << 25)
\r
69 // [31] Flag that marks the last assembled instruction as DMAEND.
\r
70 #define ALT_DMA_PROGRAM_FLAG_ENDED (1UL << 31)
\r
74 ALT_STATUS_CODE alt_dma_program_init(ALT_DMA_PROGRAM_t * pgm)
\r
76 // Clear the variables that matter.
\r
80 // Calculate the cache aligned start location of the buffer.
\r
81 size_t buffer = (size_t)pgm->program;
\r
82 size_t offset = ((buffer + ALT_DMA_PROGRAM_CACHE_LINE_SIZE - 1) & ~(ALT_DMA_PROGRAM_CACHE_LINE_SIZE - 1)) - buffer;
\r
84 // It is safe to cast to uint16_t because the extra offset can only be up to
\r
85 // (ALT_DMA_PROGRAM_CACHE_LINE_SIZE - 1) or 31, which is within range of the
\r
87 pgm->buffer_start = (uint16_t)offset;
\r
89 return ALT_E_SUCCESS;
\r
92 ALT_STATUS_CODE alt_dma_program_uninit(ALT_DMA_PROGRAM_t * pgm)
\r
94 return ALT_E_SUCCESS;
\r
97 ALT_STATUS_CODE alt_dma_program_clear(ALT_DMA_PROGRAM_t * pgm)
\r
99 // Clear the variables that matter
\r
101 pgm->code_size = 0;
\r
103 return ALT_E_SUCCESS;
\r
106 __attribute__((weak)) ALT_STATUS_CODE alt_cache_system_clean(void * address, size_t length)
\r
108 return ALT_E_SUCCESS;
\r
111 ALT_STATUS_CODE alt_dma_program_validate(const ALT_DMA_PROGRAM_t * pgm)
\r
113 // Verify that at least one instruction is in the buffer
\r
114 if (pgm->code_size == 0)
\r
116 return ALT_E_ERROR;
\r
119 // Verify all loops are completed.
\r
120 if (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)
\r
122 return ALT_E_ERROR;
\r
125 // Verify last item is DMAEND
\r
126 if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_ENDED))
\r
128 return ALT_E_ERROR;
\r
131 // Sync the DMA program to RAM.
\r
132 void * vaddr = (void *)((uintptr_t)(pgm->program + pgm->buffer_start) & ~(ALT_CACHE_LINE_SIZE - 1));
\r
133 size_t length = (pgm->code_size + ALT_CACHE_LINE_SIZE) & ~(ALT_CACHE_LINE_SIZE - 1);
\r
135 dprintf("DEBUG[DMAP]: Program (real) @ %p, length = 0x%x.\n", pgm->program + pgm->buffer_start, pgm->code_size);
\r
136 dprintf("DEBUG[DMAP]: Clean: addr = %p, length = 0x%x.\n", vaddr, length);
\r
138 return alt_cache_system_clean(vaddr, length);
\r
141 ALT_STATUS_CODE alt_dma_program_progress_reg(ALT_DMA_PROGRAM_t * pgm,
\r
142 ALT_DMA_PROGRAM_REG_t reg,
\r
143 uint32_t current, uint32_t * progress)
\r
145 // Pointer to where the register is initialized in the program buffer.
\r
146 uint8_t * buffer = NULL;
\r
150 case ALT_DMA_PROGRAM_REG_SAR:
\r
151 if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_SAR))
\r
153 return ALT_E_BAD_ARG;
\r
155 buffer = pgm->program + pgm->buffer_start + pgm->sar;
\r
158 case ALT_DMA_PROGRAM_REG_DAR:
\r
159 if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_DAR))
\r
161 return ALT_E_BAD_ARG;
\r
163 buffer = pgm->program + pgm->buffer_start + pgm->dar;
\r
167 return ALT_E_BAD_ARG;
\r
171 (buffer[3] << 24) |
\r
172 (buffer[2] << 16) |
\r
176 *progress = current - initial;
\r
178 return ALT_E_SUCCESS;
\r
181 ALT_STATUS_CODE alt_dma_program_update_reg(ALT_DMA_PROGRAM_t * pgm,
\r
182 ALT_DMA_PROGRAM_REG_t reg, uint32_t val)
\r
184 uint8_t * buffer = NULL;
\r
188 case ALT_DMA_PROGRAM_REG_SAR:
\r
189 if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_SAR))
\r
191 return ALT_E_BAD_ARG;
\r
193 buffer = pgm->program + pgm->buffer_start + pgm->sar;
\r
196 case ALT_DMA_PROGRAM_REG_DAR:
\r
197 if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_DAR))
\r
199 return ALT_E_BAD_ARG;
\r
201 buffer = pgm->program + pgm->buffer_start + pgm->dar;
\r
205 return ALT_E_BAD_ARG;
\r
208 buffer[0] = (uint8_t)((val >> 0) & 0xff);
\r
209 buffer[1] = (uint8_t)((val >> 8) & 0xff);
\r
210 buffer[2] = (uint8_t)((val >> 16) & 0xff);
\r
211 buffer[3] = (uint8_t)((val >> 24) & 0xff);
\r
213 return ALT_E_SUCCESS;
\r
216 ALT_STATUS_CODE alt_dma_program_DMAADDH(ALT_DMA_PROGRAM_t * pgm,
\r
217 ALT_DMA_PROGRAM_REG_t addr_reg, uint16_t val)
\r
219 // For information on DMAADDH, see PL330, section 4.3.1.
\r
221 // Check for sufficient space in buffer
\r
222 if ((pgm->code_size + 3) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
224 return ALT_E_BUF_OVF;
\r
227 // Verify valid register; construct instruction modifier.
\r
228 uint8_t ra_mask = 0;
\r
231 case ALT_DMA_PROGRAM_REG_SAR:
\r
234 case ALT_DMA_PROGRAM_REG_DAR:
\r
238 return ALT_E_BAD_ARG;
\r
241 // Buffer of where to assemble the instruction.
\r
242 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
244 // Assemble DMAADDH
\r
245 buffer[0] = 0x54 | ra_mask;
\r
246 buffer[1] = (uint8_t)(val & 0xff);
\r
247 buffer[2] = (uint8_t)(val >> 8);
\r
249 // Update the code size.
\r
250 pgm->code_size += 3;
\r
252 return ALT_E_SUCCESS;
\r
255 ALT_STATUS_CODE alt_dma_program_DMAADNH(ALT_DMA_PROGRAM_t * pgm,
\r
256 ALT_DMA_PROGRAM_REG_t addr_reg, uint16_t val)
\r
258 // For information on DMAADNH, see PL330, section 4.3.2.
\r
260 // Check for sufficient space in buffer
\r
261 if ((pgm->code_size + 3) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
263 return ALT_E_BUF_OVF;
\r
266 // Verify valid register; construct instruction modifier.
\r
267 uint8_t ra_mask = 0;
\r
270 case ALT_DMA_PROGRAM_REG_SAR:
\r
273 case ALT_DMA_PROGRAM_REG_DAR:
\r
277 return ALT_E_BAD_ARG;
\r
280 // Buffer of where to assemble the instruction.
\r
281 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
283 // Assemble DMAADNH
\r
284 buffer[0] = 0x5c | ra_mask;
\r
285 buffer[1] = (uint8_t)(val & 0xff);
\r
286 buffer[2] = (uint8_t)(val >> 8);
\r
288 // Update the code size.
\r
289 pgm->code_size += 3;
\r
291 return ALT_E_SUCCESS;
\r
294 ALT_STATUS_CODE alt_dma_program_DMAEND(ALT_DMA_PROGRAM_t * pgm)
\r
296 // For information on DMAEND, see PL330, section 4.3.3.
\r
298 // Check for sufficient space in buffer
\r
299 if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
301 return ALT_E_BUF_OVF;
\r
304 // Buffer of where to assemble the instruction.
\r
305 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
310 // Update the code size.
\r
311 pgm->code_size += 1;
\r
313 // Mark program as ended.
\r
314 pgm->flag |= ALT_DMA_PROGRAM_FLAG_ENDED;
\r
316 return ALT_E_SUCCESS;
\r
319 ALT_STATUS_CODE alt_dma_program_DMAFLUSHP(ALT_DMA_PROGRAM_t * pgm,
\r
320 ALT_DMA_PERIPH_t periph)
\r
322 // For information on DMAFLUSHP, see PL330, section 4.3.4.
\r
324 // Check for sufficient space in buffer
\r
325 if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
327 return ALT_E_BUF_OVF;
\r
330 // Verify valid peripheral identifier.
\r
331 if (periph > ((1 << 5) - 1))
\r
333 return ALT_E_BAD_ARG;
\r
336 // Buffer of where to assemble the instruction.
\r
337 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
339 // Assemble DMAFLUSHP
\r
341 buffer[1] = (uint8_t)(periph) << 3;
\r
343 // Update the code size.
\r
344 pgm->code_size += 2;
\r
346 return ALT_E_SUCCESS;
\r
349 ALT_STATUS_CODE alt_dma_program_DMAGO(ALT_DMA_PROGRAM_t * pgm,
\r
350 ALT_DMA_CHANNEL_t channel, uint32_t val,
\r
351 ALT_DMA_SECURITY_t sec)
\r
353 // For information on DMAGO, see PL330, section 4.3.5.
\r
355 // Check for sufficient space in buffer
\r
356 if ((pgm->code_size + 6) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
358 return ALT_E_BUF_OVF;
\r
364 case ALT_DMA_CHANNEL_0:
\r
365 case ALT_DMA_CHANNEL_1:
\r
366 case ALT_DMA_CHANNEL_2:
\r
367 case ALT_DMA_CHANNEL_3:
\r
368 case ALT_DMA_CHANNEL_4:
\r
369 case ALT_DMA_CHANNEL_5:
\r
370 case ALT_DMA_CHANNEL_6:
\r
371 case ALT_DMA_CHANNEL_7:
\r
374 return ALT_E_BAD_ARG;
\r
377 // Verify security; construct ns mask value
\r
378 uint8_t ns_mask = 0;
\r
381 case ALT_DMA_SECURITY_DEFAULT:
\r
382 case ALT_DMA_SECURITY_SECURE:
\r
385 case ALT_DMA_SECURITY_NONSECURE:
\r
389 return ALT_E_BAD_ARG;
\r
392 // Buffer of where to assemble the instruction.
\r
393 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
396 buffer[0] = 0xa0 | ns_mask;
\r
397 buffer[1] = (uint8_t)channel;
\r
398 buffer[2] = (uint8_t)((val >> 0) & 0xff);
\r
399 buffer[3] = (uint8_t)((val >> 8) & 0xff);
\r
400 buffer[4] = (uint8_t)((val >> 16) & 0xff);
\r
401 buffer[5] = (uint8_t)((val >> 24) & 0xff);
\r
403 // Update the code size.
\r
404 pgm->code_size += 6;
\r
406 return ALT_E_SUCCESS;
\r
409 ALT_STATUS_CODE alt_dma_program_DMAKILL(ALT_DMA_PROGRAM_t * pgm)
\r
411 // For information on DMAKILL, see PL330, section 4.3.6.
\r
413 // Check for sufficient space in buffer
\r
414 if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
416 return ALT_E_BUF_OVF;
\r
419 // Buffer of where to assemble the instruction.
\r
420 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
422 // Assemble DMAKILL
\r
425 // Update the code size.
\r
426 pgm->code_size += 1;
\r
428 return ALT_E_SUCCESS;
\r
431 ALT_STATUS_CODE alt_dma_program_DMALD(ALT_DMA_PROGRAM_t * pgm,
\r
432 ALT_DMA_PROGRAM_INST_MOD_t mod)
\r
434 // For information on DMALD, see PL330, section 4.3.7.
\r
436 // Check for sufficient space in buffer
\r
437 if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
439 return ALT_E_BUF_OVF;
\r
442 // Verify instruction modifier; construct bs, x mask value.
\r
443 uint8_t bsx_mask = 0;
\r
446 case ALT_DMA_PROGRAM_INST_MOD_NONE:
\r
449 case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
\r
452 case ALT_DMA_PROGRAM_INST_MOD_BURST:
\r
456 return ALT_E_BAD_ARG;
\r
459 // Buffer of where to assemble the instruction.
\r
460 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
463 buffer[0] = 0x04 | bsx_mask;
\r
465 // Update the code size.
\r
466 pgm->code_size += 1;
\r
468 return ALT_E_SUCCESS;
\r
471 ALT_STATUS_CODE alt_dma_program_DMALDP(ALT_DMA_PROGRAM_t * pgm,
\r
472 ALT_DMA_PROGRAM_INST_MOD_t mod, ALT_DMA_PERIPH_t periph)
\r
474 // For information on DMALDP, see PL330, section 4.3.8.
\r
476 // Check for sufficient space in buffer
\r
477 if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
479 return ALT_E_BUF_OVF;
\r
482 // Verify instruction modifier; construct bs mask value.
\r
483 uint8_t bs_mask = 0;
\r
486 case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
\r
489 case ALT_DMA_PROGRAM_INST_MOD_BURST:
\r
493 return ALT_E_BAD_ARG;
\r
496 // Verify valid peripheral identifier.
\r
497 if (periph > ((1 << 5) - 1))
\r
499 return ALT_E_BAD_ARG;
\r
502 // Buffer of where to assemble the instruction.
\r
503 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
506 buffer[0] = 0x25 | bs_mask;
\r
507 buffer[1] = (uint8_t)(periph) << 3;
\r
509 // Update the code size.
\r
510 pgm->code_size += 2;
\r
512 return ALT_E_SUCCESS;
\r
515 ALT_STATUS_CODE alt_dma_program_DMALP(ALT_DMA_PROGRAM_t * pgm,
\r
516 uint32_t iterations)
\r
518 // For information on DMALP, see PL330, section 4.3.9.
\r
520 // Check for sufficient space in buffer
\r
521 if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
523 return ALT_E_BUF_OVF;
\r
526 // Verify iterations in range
\r
527 if ((iterations == 0) || (iterations > 256))
\r
529 return ALT_E_BAD_ARG;
\r
532 // Find suitable LOOPx register to use; construct lc mask value.
\r
533 uint8_t lc_mask = 0;
\r
534 switch (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)
\r
536 case 0: // No LOOPx in use. Use LOOP0.
\r
537 pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP0;
\r
538 pgm->loop0 = pgm->code_size + 2; // This is the first instruction after the DMALP
\r
542 case ALT_DMA_PROGRAM_FLAG_LOOP0: // LOOP0 in use. Use LOOP1.
\r
543 pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP1;
\r
544 pgm->loop1 = pgm->code_size + 2; // This is the first instruction after the DMALP
\r
548 case ALT_DMA_PROGRAM_FLAG_LOOP_ALL: // All LOOPx in use. Report error.
\r
549 return ALT_E_BAD_OPERATION;
\r
551 default: // Catastrophic error !!!
\r
552 return ALT_E_ERROR;
\r
555 // Buffer of where to assemble the instruction.
\r
556 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
559 buffer[0] = 0x20 | lc_mask;
\r
560 buffer[1] = (uint8_t)(iterations - 1);
\r
562 // Update the code size.
\r
563 pgm->code_size += 2;
\r
565 return ALT_E_SUCCESS;
\r
568 ALT_STATUS_CODE alt_dma_program_DMALPEND(ALT_DMA_PROGRAM_t * pgm,
\r
569 ALT_DMA_PROGRAM_INST_MOD_t mod)
\r
571 // For information on DMALPEND, see PL330, section 4.3.10.
\r
573 // Check for sufficient space in buffer
\r
574 if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
576 return ALT_E_BUF_OVF;
\r
579 // Verify instruction modifier; construct bs, x mask value.
\r
580 uint8_t bsx_mask = 0;
\r
583 case ALT_DMA_PROGRAM_INST_MOD_NONE:
\r
586 case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
\r
589 case ALT_DMA_PROGRAM_INST_MOD_BURST:
\r
593 return ALT_E_BAD_ARG;
\r
596 // Determine the loop to end, if it is a forever loop; construct lc mask, nf mask, and backwards jump value.
\r
597 uint8_t lc_mask = 0;
\r
598 uint8_t nf_mask = 0;
\r
599 uint16_t backwards_jump = 0;
\r
600 switch (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)
\r
602 case ALT_DMA_PROGRAM_FLAG_LOOP0: // LOOP0 in use. End LOOP0.
\r
604 backwards_jump = pgm->code_size - pgm->loop0;
\r
606 pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP0;
\r
611 if (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE)
\r
613 pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE;
\r
621 case ALT_DMA_PROGRAM_FLAG_LOOP_ALL: // All LOOPx in use. End LOOP1.
\r
623 backwards_jump = pgm->code_size - pgm->loop1;
\r
625 pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP1;
\r
630 if (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE)
\r
632 pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE;
\r
640 case 0: // No LOOPx in use. Report error!
\r
641 return ALT_E_BAD_OPERATION;
\r
643 default: // Catastrophic error !!!
\r
644 return ALT_E_ERROR;
\r
647 // Verify that the jump size is suitable
\r
648 if (backwards_jump > 255)
\r
650 return ALT_E_ARG_RANGE;
\r
653 // Buffer of where to assemble the instruction.
\r
654 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
656 // Assemble DMALPEND
\r
657 buffer[0] = 0x28 | nf_mask | lc_mask | bsx_mask;
\r
658 buffer[1] = (uint8_t)(backwards_jump);
\r
660 // Update the code size.
\r
661 pgm->code_size += 2;
\r
663 return ALT_E_SUCCESS;
\r
666 ALT_STATUS_CODE alt_dma_program_DMALPFE(ALT_DMA_PROGRAM_t * pgm)
\r
668 // For information on DMALPFE, see PL330, section 4.3.11.
\r
670 // Find suitable LOOPx register to use;
\r
671 switch (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)
\r
673 case 0: // No LOOPx in use. Use LOOP0.
\r
674 pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP0;
\r
675 pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE;
\r
676 pgm->loop0 = pgm->code_size;
\r
679 case ALT_DMA_PROGRAM_FLAG_LOOP0: // LOOP0 in use. Use LOOP1.
\r
680 pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP1;
\r
681 pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE;
\r
682 pgm->loop1 = pgm->code_size;
\r
685 case ALT_DMA_PROGRAM_FLAG_LOOP_ALL: // All LOOPx in use. Report error.
\r
686 return ALT_E_BAD_OPERATION;
\r
688 default: // Catastrophic error !!!
\r
689 return ALT_E_ERROR;
\r
692 // Nothing to assemble.
\r
694 return ALT_E_SUCCESS;
\r
697 ALT_STATUS_CODE alt_dma_program_DMAMOV(ALT_DMA_PROGRAM_t * pgm,
\r
698 ALT_DMA_PROGRAM_REG_t chan_reg, uint32_t val)
\r
700 // For information on DMAMOV, see PL330, section 4.3.12.
\r
702 // Check for sufficient space in buffer
\r
703 if ((pgm->code_size + 6) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
705 return ALT_E_BUF_OVF;
\r
708 // Verify channel register; construct rd mask value
\r
709 uint8_t rd_mask = 0;
\r
712 case ALT_DMA_PROGRAM_REG_SAR:
\r
714 // If SAR has not been set before, mark the location of where SAR is in the buffer.
\r
715 if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_SAR))
\r
717 pgm->flag |= ALT_DMA_PROGRAM_FLAG_SAR;
\r
718 pgm->sar = pgm->code_size + 2;
\r
722 case ALT_DMA_PROGRAM_REG_CCR:
\r
726 case ALT_DMA_PROGRAM_REG_DAR:
\r
728 // If DAR has not been set before, mark the location of where DAR is in the buffer.
\r
729 if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_DAR))
\r
731 pgm->flag |= ALT_DMA_PROGRAM_FLAG_DAR;
\r
732 pgm->dar = pgm->code_size + 2;
\r
737 return ALT_E_BAD_ARG;
\r
740 // Buffer of where to assemble the instruction.
\r
741 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
745 buffer[1] = rd_mask;
\r
746 buffer[2] = (uint8_t)((val >> 0) & 0xff);
\r
747 buffer[3] = (uint8_t)((val >> 8) & 0xff);
\r
748 buffer[4] = (uint8_t)((val >> 16) & 0xff);
\r
749 buffer[5] = (uint8_t)((val >> 24) & 0xff);
\r
751 // Update the code size.
\r
752 pgm->code_size += 6;
\r
754 return ALT_E_SUCCESS;
\r
758 ALT_STATUS_CODE alt_dma_program_DMANOP(ALT_DMA_PROGRAM_t * pgm)
\r
760 // For information on DMANOP, see PL330, section 4.3.13.
\r
762 // Check for sufficient space in buffer
\r
763 if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
765 return ALT_E_BUF_OVF;
\r
768 // Buffer of where to assemble the instruction.
\r
769 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
774 // Update the code size.
\r
775 pgm->code_size += 1;
\r
777 return ALT_E_SUCCESS;
\r
780 ALT_STATUS_CODE alt_dma_program_DMARMB(ALT_DMA_PROGRAM_t * pgm)
\r
782 // For information on DMARMB, see PL330, section 4.3.14.
\r
784 // Check for sufficient space in buffer
\r
785 if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
787 return ALT_E_BUF_OVF;
\r
790 // Buffer of where to assemble the instruction.
\r
791 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
796 // Update the code size.
\r
797 pgm->code_size += 1;
\r
799 return ALT_E_SUCCESS;
\r
802 ALT_STATUS_CODE alt_dma_program_DMASEV(ALT_DMA_PROGRAM_t * pgm,
\r
803 ALT_DMA_EVENT_t evt)
\r
805 // For information on DMA, see PL330, section 4.3.15.
\r
807 // Check for sufficient space in buffer
\r
808 if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
810 return ALT_E_BUF_OVF;
\r
813 // Validate evt selection
\r
816 case ALT_DMA_EVENT_0:
\r
817 case ALT_DMA_EVENT_1:
\r
818 case ALT_DMA_EVENT_2:
\r
819 case ALT_DMA_EVENT_3:
\r
820 case ALT_DMA_EVENT_4:
\r
821 case ALT_DMA_EVENT_5:
\r
822 case ALT_DMA_EVENT_6:
\r
823 case ALT_DMA_EVENT_7:
\r
824 case ALT_DMA_EVENT_ABORT:
\r
827 return ALT_E_BAD_ARG;
\r
830 // Buffer of where to assemble the instruction.
\r
831 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
835 buffer[1] = (uint8_t)(evt) << 3;
\r
837 // Update the code size.
\r
838 pgm->code_size += 2;
\r
840 return ALT_E_SUCCESS;
\r
843 ALT_STATUS_CODE alt_dma_program_DMAST(ALT_DMA_PROGRAM_t * pgm,
\r
844 ALT_DMA_PROGRAM_INST_MOD_t mod)
\r
846 // For information on DMAST, see PL330, section 4.3.16.
\r
848 // Check for sufficient space in buffer
\r
849 if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
851 return ALT_E_BUF_OVF;
\r
854 // Verify instruction modifier; construct bs, x mask value.
\r
855 uint8_t bsx_mask = 0;
\r
858 case ALT_DMA_PROGRAM_INST_MOD_NONE:
\r
861 case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
\r
864 case ALT_DMA_PROGRAM_INST_MOD_BURST:
\r
868 return ALT_E_BAD_ARG;
\r
871 // Buffer of where to assemble the instruction.
\r
872 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
875 buffer[0] = 0x08 | bsx_mask;
\r
877 // Update the code size.
\r
878 pgm->code_size += 1;
\r
880 return ALT_E_SUCCESS;
\r
883 ALT_STATUS_CODE alt_dma_program_DMASTP(ALT_DMA_PROGRAM_t * pgm,
\r
884 ALT_DMA_PROGRAM_INST_MOD_t mod, ALT_DMA_PERIPH_t periph)
\r
886 // For information on DMASTP, see PL330, section 4.3.17.
\r
888 // Check for sufficient space in buffer
\r
889 if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
891 return ALT_E_BUF_OVF;
\r
894 // Verify instruction modifier; construct bs mask value.
\r
895 uint8_t bs_mask = 0;
\r
898 case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
\r
901 case ALT_DMA_PROGRAM_INST_MOD_BURST:
\r
905 return ALT_E_BAD_ARG;
\r
908 // Verify valid peripheral identifier.
\r
909 if (periph > ((1 << 5) - 1))
\r
911 return ALT_E_BAD_ARG;
\r
914 // Buffer of where to assemble the instruction.
\r
915 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
918 buffer[0] = 0x29 | bs_mask;
\r
919 buffer[1] = (uint8_t)(periph) << 3;
\r
921 // Update the code size.
\r
922 pgm->code_size += 2;
\r
924 return ALT_E_SUCCESS;
\r
927 ALT_STATUS_CODE alt_dma_program_DMASTZ(ALT_DMA_PROGRAM_t * pgm)
\r
929 // For information on DMASTZ, see PL330, section 4.3.18.
\r
931 // Check for sufficient space in buffer
\r
932 if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
934 return ALT_E_BUF_OVF;
\r
937 // Buffer of where to assemble the instruction.
\r
938 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
943 // Update the code size.
\r
944 pgm->code_size += 1;
\r
946 return ALT_E_SUCCESS;
\r
949 ALT_STATUS_CODE alt_dma_program_DMAWFE(ALT_DMA_PROGRAM_t * pgm,
\r
950 ALT_DMA_EVENT_t evt, bool invalid)
\r
952 // For information on DMAWFE, see PL330, section 4.3.19.
\r
954 // Check for sufficient space in buffer
\r
955 if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
957 return ALT_E_BUF_OVF;
\r
960 // Validate evt selection
\r
963 case ALT_DMA_EVENT_0:
\r
964 case ALT_DMA_EVENT_1:
\r
965 case ALT_DMA_EVENT_2:
\r
966 case ALT_DMA_EVENT_3:
\r
967 case ALT_DMA_EVENT_4:
\r
968 case ALT_DMA_EVENT_5:
\r
969 case ALT_DMA_EVENT_6:
\r
970 case ALT_DMA_EVENT_7:
\r
971 case ALT_DMA_EVENT_ABORT:
\r
974 return ALT_E_BAD_ARG;
\r
977 // Construct i mask value
\r
978 uint8_t i_mask = 0;
\r
984 // Buffer of where to assemble the instruction.
\r
985 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
989 buffer[1] = ((uint8_t)(evt) << 3) | i_mask;
\r
991 // Update the code size.
\r
992 pgm->code_size += 2;
\r
994 return ALT_E_SUCCESS;
\r
997 ALT_STATUS_CODE alt_dma_program_DMAWFP(ALT_DMA_PROGRAM_t * pgm,
\r
998 ALT_DMA_PERIPH_t periph, ALT_DMA_PROGRAM_INST_MOD_t mod)
\r
1000 // For information on DMAWFP, see PL330, section 4.3.20.
\r
1002 // Check for sufficient space in buffer
\r
1003 if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
1005 return ALT_E_BUF_OVF;
\r
1008 // Verify valid peripheral identifier.
\r
1009 if (periph > ((1 << 5) - 1))
\r
1011 return ALT_E_BAD_ARG;
\r
1014 // Verify instruction modifier; construct bs, p mask value.
\r
1015 uint8_t bsp_mask = 0;
\r
1018 case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
\r
1021 case ALT_DMA_PROGRAM_INST_MOD_BURST:
\r
1024 case ALT_DMA_PROGRAM_INST_MOD_PERIPH:
\r
1028 return ALT_E_BAD_ARG;
\r
1031 // Buffer of where to assemble the instruction.
\r
1032 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
1034 // Assemble DMAWFP
\r
1035 buffer[0] = 0x30 | bsp_mask;
\r
1036 buffer[1] = (uint8_t)(periph) << 3;
\r
1038 // Update the code size.
\r
1039 pgm->code_size += 2;
\r
1041 return ALT_E_SUCCESS;
\r
1044 ALT_STATUS_CODE alt_dma_program_DMAWMB(ALT_DMA_PROGRAM_t * pgm)
\r
1046 // For information on DMAWMB, see PL330, section 4.3.21.
\r
1048 // Check for sufficient space in buffer
\r
1049 if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
\r
1051 return ALT_E_BUF_OVF;
\r
1054 // Buffer of where to assemble the instruction.
\r
1055 uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
\r
1057 // Assemble DMAWMB
\r
1060 // Update the code size.
\r
1061 pgm->code_size += 1;
\r
1063 return ALT_E_SUCCESS;
\r