]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A9_Cyclone_V_SoC_DK/Altera_Code/HardwareLibrary/alt_dma_program.c
Added project for Altera Cyclone V SoC, currently running from internal RAM.
[freertos] / FreeRTOS / Demo / CORTEX_A9_Cyclone_V_SoC_DK / Altera_Code / HardwareLibrary / alt_dma_program.c
1 /******************************************************************************\r
2  *\r
3  * Copyright 2013 Altera Corporation. All Rights Reserved.\r
4  *\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
7  *\r
8  * 1. Redistributions of source code must retain the above copyright notice,\r
9  * this list of conditions and the following disclaimer.\r
10  *\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
14  *\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
17  *\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
27  * OF SUCH DAMAGE.\r
28  *\r
29  ******************************************************************************/\r
30 \r
31 #include "alt_dma_program.h"\r
32 #include "alt_cache.h"\r
33 #include <stdio.h>\r
34 \r
35 /////\r
36 \r
37 // NOTE: To enable debugging output, delete the next line and uncomment the\r
38 //   line after.\r
39 #define dprintf(...)\r
40 // #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)\r
41 \r
42 /////\r
43 \r
44 //\r
45 // The following section describes how the bits are used in the "flag" field:\r
46 //\r
47 \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
54 \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
61 \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
68 \r
69 // [31] Flag that marks the last assembled instruction as DMAEND.\r
70 #define ALT_DMA_PROGRAM_FLAG_ENDED (1UL << 31)\r
71 \r
72 /////\r
73 \r
74 ALT_STATUS_CODE alt_dma_program_init(ALT_DMA_PROGRAM_t * pgm)\r
75 {\r
76     // Clear the variables that matter.\r
77     pgm->flag      = 0;\r
78     pgm->code_size = 0;\r
79 \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
83 \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
86     // uint16_t.\r
87     pgm->buffer_start = (uint16_t)offset;\r
88 \r
89     return ALT_E_SUCCESS;\r
90 }\r
91 \r
92 ALT_STATUS_CODE alt_dma_program_uninit(ALT_DMA_PROGRAM_t * pgm)\r
93 {\r
94     return ALT_E_SUCCESS;\r
95 }\r
96 \r
97 ALT_STATUS_CODE alt_dma_program_clear(ALT_DMA_PROGRAM_t * pgm)\r
98 {\r
99     // Clear the variables that matter\r
100     pgm->flag      = 0;\r
101     pgm->code_size = 0;\r
102 \r
103     return ALT_E_SUCCESS;\r
104 }\r
105 \r
106 __attribute__((weak)) ALT_STATUS_CODE alt_cache_system_clean(void * address, size_t length)\r
107 {\r
108     return ALT_E_SUCCESS;\r
109 }\r
110 \r
111 ALT_STATUS_CODE alt_dma_program_validate(const ALT_DMA_PROGRAM_t * pgm)\r
112 {\r
113     // Verify that at least one instruction is in the buffer\r
114     if (pgm->code_size == 0)\r
115     {\r
116         return ALT_E_ERROR;\r
117     }\r
118 \r
119     // Verify all loops are completed.\r
120     if (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)\r
121     {\r
122         return ALT_E_ERROR;\r
123     }\r
124 \r
125     // Verify last item is DMAEND\r
126     if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_ENDED))\r
127     {\r
128         return ALT_E_ERROR;\r
129     }\r
130 \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
134 \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
137 \r
138     return alt_cache_system_clean(vaddr, length);\r
139 }\r
140 \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
144 {\r
145     // Pointer to where the register is initialized in the program buffer.\r
146     uint8_t * buffer = NULL;\r
147 \r
148     switch (reg)\r
149     {\r
150     case ALT_DMA_PROGRAM_REG_SAR:\r
151         if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_SAR))\r
152         {\r
153             return ALT_E_BAD_ARG;\r
154         }\r
155         buffer = pgm->program + pgm->buffer_start + pgm->sar;\r
156         break;\r
157 \r
158     case ALT_DMA_PROGRAM_REG_DAR:\r
159         if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_DAR))\r
160         {\r
161             return ALT_E_BAD_ARG;\r
162         }\r
163         buffer = pgm->program + pgm->buffer_start + pgm->dar;\r
164         break;\r
165 \r
166     default:\r
167         return ALT_E_BAD_ARG;\r
168     }\r
169 \r
170     uint32_t initial =\r
171         (buffer[3] << 24) |\r
172         (buffer[2] << 16) |\r
173         (buffer[1] <<  8) |\r
174         (buffer[0] <<  0);\r
175 \r
176     *progress = current - initial;\r
177 \r
178     return ALT_E_SUCCESS;\r
179 }\r
180 \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
183 {\r
184     uint8_t * buffer = NULL;\r
185 \r
186     switch (reg)\r
187     {\r
188     case ALT_DMA_PROGRAM_REG_SAR:\r
189         if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_SAR))\r
190         {\r
191             return ALT_E_BAD_ARG;\r
192         }\r
193         buffer = pgm->program + pgm->buffer_start + pgm->sar;\r
194         break;\r
195 \r
196     case ALT_DMA_PROGRAM_REG_DAR:\r
197         if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_DAR))\r
198         {\r
199             return ALT_E_BAD_ARG;\r
200         }\r
201         buffer = pgm->program + pgm->buffer_start + pgm->dar;\r
202         break;\r
203 \r
204     default:\r
205         return ALT_E_BAD_ARG;\r
206     }\r
207 \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
212 \r
213     return ALT_E_SUCCESS;\r
214 }\r
215 \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
218 {\r
219     // For information on DMAADDH, see PL330, section 4.3.1.\r
220 \r
221     // Check for sufficient space in buffer\r
222     if ((pgm->code_size + 3) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
223     {\r
224         return ALT_E_BUF_OVF;\r
225     }\r
226 \r
227     // Verify valid register; construct instruction modifier.\r
228     uint8_t ra_mask = 0;\r
229     switch (addr_reg)\r
230     {\r
231     case ALT_DMA_PROGRAM_REG_SAR:\r
232         ra_mask = 0x0;\r
233         break;\r
234     case ALT_DMA_PROGRAM_REG_DAR:\r
235         ra_mask = 0x2;\r
236         break;\r
237     default:\r
238         return ALT_E_BAD_ARG;\r
239     }\r
240 \r
241     // Buffer of where to assemble the instruction.\r
242     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
243 \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
248 \r
249     // Update the code size.\r
250     pgm->code_size += 3;\r
251 \r
252     return ALT_E_SUCCESS;\r
253 }\r
254 \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
257 {\r
258     // For information on DMAADNH, see PL330, section 4.3.2.\r
259 \r
260     // Check for sufficient space in buffer\r
261     if ((pgm->code_size + 3) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
262     {\r
263         return ALT_E_BUF_OVF;\r
264     }\r
265 \r
266     // Verify valid register; construct instruction modifier.\r
267     uint8_t ra_mask = 0;\r
268     switch (addr_reg)\r
269     {\r
270     case ALT_DMA_PROGRAM_REG_SAR:\r
271         ra_mask = 0x0;\r
272         break;\r
273     case ALT_DMA_PROGRAM_REG_DAR:\r
274         ra_mask = 0x2;\r
275         break;\r
276     default:\r
277         return ALT_E_BAD_ARG;\r
278     }\r
279 \r
280     // Buffer of where to assemble the instruction.\r
281     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
282 \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
287 \r
288     // Update the code size.\r
289     pgm->code_size += 3;\r
290 \r
291     return ALT_E_SUCCESS;\r
292 }\r
293 \r
294 ALT_STATUS_CODE alt_dma_program_DMAEND(ALT_DMA_PROGRAM_t * pgm)\r
295 {\r
296     // For information on DMAEND, see PL330, section 4.3.3.\r
297 \r
298     // Check for sufficient space in buffer\r
299     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
300     {\r
301         return ALT_E_BUF_OVF;\r
302     }\r
303 \r
304     // Buffer of where to assemble the instruction.\r
305     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
306 \r
307     // Assemble DMAEND\r
308     buffer[0] = 0x00;\r
309 \r
310     // Update the code size.\r
311     pgm->code_size += 1;\r
312 \r
313     // Mark program as ended.\r
314     pgm->flag |= ALT_DMA_PROGRAM_FLAG_ENDED;\r
315 \r
316     return ALT_E_SUCCESS;\r
317 }\r
318 \r
319 ALT_STATUS_CODE alt_dma_program_DMAFLUSHP(ALT_DMA_PROGRAM_t * pgm,\r
320                                           ALT_DMA_PERIPH_t periph)\r
321 {\r
322     // For information on DMAFLUSHP, see PL330, section 4.3.4.\r
323 \r
324     // Check for sufficient space in buffer\r
325     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
326     {\r
327         return ALT_E_BUF_OVF;\r
328     }\r
329 \r
330     // Verify valid peripheral identifier.\r
331     if (periph > ((1 << 5) - 1))\r
332     {\r
333         return ALT_E_BAD_ARG;\r
334     }\r
335 \r
336     // Buffer of where to assemble the instruction.\r
337     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
338 \r
339     // Assemble DMAFLUSHP\r
340     buffer[0] = 0x35;\r
341     buffer[1] = (uint8_t)(periph) << 3;\r
342 \r
343     // Update the code size.\r
344     pgm->code_size += 2;\r
345 \r
346     return ALT_E_SUCCESS;\r
347 }\r
348 \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
352 {\r
353     // For information on DMAGO, see PL330, section 4.3.5.\r
354 \r
355     // Check for sufficient space in buffer\r
356     if ((pgm->code_size + 6) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
357     {\r
358         return ALT_E_BUF_OVF;\r
359     }\r
360 \r
361     // Verify channel\r
362     switch (channel)\r
363     {\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
372         break;\r
373     default:\r
374         return ALT_E_BAD_ARG;\r
375     }\r
376 \r
377     // Verify security; construct ns mask value\r
378     uint8_t ns_mask = 0;\r
379     switch (sec)\r
380     {\r
381     case ALT_DMA_SECURITY_DEFAULT:\r
382     case ALT_DMA_SECURITY_SECURE:\r
383         ns_mask = 0x0;\r
384         break;\r
385     case ALT_DMA_SECURITY_NONSECURE:\r
386         ns_mask = 0x2;\r
387         break;\r
388     default:\r
389         return ALT_E_BAD_ARG;\r
390     }\r
391 \r
392     // Buffer of where to assemble the instruction.\r
393     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
394 \r
395     // Assemble DMAGO\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
402 \r
403     // Update the code size.\r
404     pgm->code_size += 6;\r
405 \r
406     return ALT_E_SUCCESS;\r
407 }\r
408 \r
409 ALT_STATUS_CODE alt_dma_program_DMAKILL(ALT_DMA_PROGRAM_t * pgm)\r
410 {\r
411     // For information on DMAKILL, see PL330, section 4.3.6.\r
412 \r
413     // Check for sufficient space in buffer\r
414     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
415     {\r
416         return ALT_E_BUF_OVF;\r
417     }\r
418 \r
419     // Buffer of where to assemble the instruction.\r
420     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
421 \r
422     // Assemble DMAKILL\r
423     buffer[0] = 0x01;\r
424 \r
425     // Update the code size.\r
426     pgm->code_size += 1;\r
427 \r
428     return ALT_E_SUCCESS;\r
429 }\r
430 \r
431 ALT_STATUS_CODE alt_dma_program_DMALD(ALT_DMA_PROGRAM_t * pgm,\r
432                                       ALT_DMA_PROGRAM_INST_MOD_t mod)\r
433 {\r
434     // For information on DMALD, see PL330, section 4.3.7.\r
435 \r
436     // Check for sufficient space in buffer\r
437     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
438     {\r
439         return ALT_E_BUF_OVF;\r
440     }\r
441 \r
442     // Verify instruction modifier; construct bs, x mask value.\r
443     uint8_t bsx_mask = 0;\r
444     switch (mod)\r
445     {\r
446     case ALT_DMA_PROGRAM_INST_MOD_NONE:\r
447         bsx_mask = 0x0;\r
448         break;\r
449     case ALT_DMA_PROGRAM_INST_MOD_SINGLE:\r
450         bsx_mask = 0x1;\r
451         break;\r
452     case ALT_DMA_PROGRAM_INST_MOD_BURST:\r
453         bsx_mask = 0x3;\r
454         break;\r
455     default:\r
456         return ALT_E_BAD_ARG;\r
457     }\r
458 \r
459     // Buffer of where to assemble the instruction.\r
460     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
461 \r
462     // Assemble DMALD\r
463     buffer[0] = 0x04 | bsx_mask;\r
464 \r
465     // Update the code size.\r
466     pgm->code_size += 1;\r
467 \r
468     return ALT_E_SUCCESS;\r
469 }\r
470 \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
473 {\r
474     // For information on DMALDP, see PL330, section 4.3.8.\r
475 \r
476     // Check for sufficient space in buffer\r
477     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
478     {\r
479         return ALT_E_BUF_OVF;\r
480     }\r
481 \r
482     // Verify instruction modifier; construct bs mask value.\r
483     uint8_t bs_mask = 0;\r
484     switch (mod)\r
485     {\r
486     case ALT_DMA_PROGRAM_INST_MOD_SINGLE:\r
487         bs_mask = 0x0;\r
488         break;\r
489     case ALT_DMA_PROGRAM_INST_MOD_BURST:\r
490         bs_mask = 0x2;\r
491         break;\r
492     default:\r
493         return ALT_E_BAD_ARG;\r
494     }\r
495 \r
496     // Verify valid peripheral identifier.\r
497     if (periph > ((1 << 5) - 1))\r
498     {\r
499         return ALT_E_BAD_ARG;\r
500     }\r
501 \r
502     // Buffer of where to assemble the instruction.\r
503     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
504 \r
505     // Assemble DMALDP\r
506     buffer[0] = 0x25 | bs_mask;\r
507     buffer[1] = (uint8_t)(periph) << 3;\r
508 \r
509     // Update the code size.\r
510     pgm->code_size += 2;\r
511 \r
512     return ALT_E_SUCCESS;\r
513 }\r
514 \r
515 ALT_STATUS_CODE alt_dma_program_DMALP(ALT_DMA_PROGRAM_t * pgm,\r
516                                       uint32_t iterations)\r
517 {\r
518     // For information on DMALP, see PL330, section 4.3.9.\r
519 \r
520     // Check for sufficient space in buffer\r
521     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
522     {\r
523         return ALT_E_BUF_OVF;\r
524     }\r
525 \r
526     // Verify iterations in range\r
527     if ((iterations == 0) || (iterations > 256))\r
528     {\r
529         return ALT_E_BAD_ARG;\r
530     }\r
531 \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
535     {\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
539         lc_mask = 0x0;\r
540         break;\r
541 \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
545         lc_mask = 0x2;\r
546         break;\r
547 \r
548     case ALT_DMA_PROGRAM_FLAG_LOOP_ALL: // All LOOPx in use. Report error.\r
549         return ALT_E_BAD_OPERATION;\r
550 \r
551     default:                            // Catastrophic error !!!\r
552         return ALT_E_ERROR;\r
553     }\r
554 \r
555     // Buffer of where to assemble the instruction.\r
556     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
557 \r
558     // Assemble DMALP\r
559     buffer[0] = 0x20 | lc_mask;\r
560     buffer[1] = (uint8_t)(iterations - 1);\r
561 \r
562     // Update the code size.\r
563     pgm->code_size += 2;\r
564 \r
565     return ALT_E_SUCCESS;\r
566 }\r
567 \r
568 ALT_STATUS_CODE alt_dma_program_DMALPEND(ALT_DMA_PROGRAM_t * pgm,\r
569                                          ALT_DMA_PROGRAM_INST_MOD_t mod)\r
570 {\r
571     // For information on DMALPEND, see PL330, section 4.3.10.\r
572 \r
573     // Check for sufficient space in buffer\r
574     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
575     {\r
576         return ALT_E_BUF_OVF;\r
577     }\r
578 \r
579     // Verify instruction modifier; construct bs, x mask value.\r
580     uint8_t bsx_mask = 0;\r
581     switch (mod)\r
582     {\r
583     case ALT_DMA_PROGRAM_INST_MOD_NONE:\r
584         bsx_mask = 0x0;\r
585         break;\r
586     case ALT_DMA_PROGRAM_INST_MOD_SINGLE:\r
587         bsx_mask = 0x1;\r
588         break;\r
589     case ALT_DMA_PROGRAM_INST_MOD_BURST:\r
590         bsx_mask = 0x3;\r
591         break;\r
592     default:\r
593         return ALT_E_BAD_ARG;\r
594     }\r
595 \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
601     {\r
602     case ALT_DMA_PROGRAM_FLAG_LOOP0:    // LOOP0 in use. End LOOP0.\r
603 \r
604         backwards_jump = pgm->code_size - pgm->loop0;\r
605 \r
606         pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP0;\r
607         pgm->loop0 = 0;\r
608 \r
609         lc_mask = 0x0;\r
610 \r
611         if (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE)\r
612         {\r
613             pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE;\r
614         }\r
615         else\r
616         {\r
617             nf_mask = 0x10;\r
618         }\r
619         break;\r
620 \r
621     case ALT_DMA_PROGRAM_FLAG_LOOP_ALL: // All LOOPx in use. End LOOP1.\r
622 \r
623         backwards_jump = pgm->code_size - pgm->loop1;\r
624 \r
625         pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP1;\r
626         pgm->loop1 = 0;\r
627 \r
628         lc_mask = 0x4;\r
629 \r
630         if (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE)\r
631         {\r
632             pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE;\r
633         }\r
634         else\r
635         {\r
636             nf_mask = 0x10;\r
637         }\r
638         break;\r
639 \r
640     case 0:                             // No LOOPx in use. Report error!\r
641         return ALT_E_BAD_OPERATION;\r
642 \r
643     default:                            // Catastrophic error !!!\r
644         return ALT_E_ERROR;\r
645     }\r
646 \r
647     // Verify that the jump size is suitable\r
648     if (backwards_jump > 255)\r
649     {\r
650         return ALT_E_ARG_RANGE;\r
651     }\r
652 \r
653     // Buffer of where to assemble the instruction.\r
654     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
655 \r
656     // Assemble DMALPEND\r
657     buffer[0] = 0x28 | nf_mask | lc_mask | bsx_mask;\r
658     buffer[1] = (uint8_t)(backwards_jump);\r
659 \r
660     // Update the code size.\r
661     pgm->code_size += 2;\r
662 \r
663     return ALT_E_SUCCESS;\r
664 }\r
665 \r
666 ALT_STATUS_CODE alt_dma_program_DMALPFE(ALT_DMA_PROGRAM_t * pgm)\r
667 {\r
668     // For information on DMALPFE, see PL330, section 4.3.11.\r
669 \r
670     // Find suitable LOOPx register to use;\r
671     switch (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)\r
672     {\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
677         break;\r
678 \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
683         break;\r
684 \r
685     case ALT_DMA_PROGRAM_FLAG_LOOP_ALL: // All LOOPx in use. Report error.\r
686         return ALT_E_BAD_OPERATION;\r
687 \r
688     default:                            // Catastrophic error !!!\r
689         return ALT_E_ERROR;\r
690     }\r
691 \r
692     // Nothing to assemble.\r
693 \r
694     return ALT_E_SUCCESS;\r
695 }\r
696 \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
699 {\r
700     // For information on DMAMOV, see PL330, section 4.3.12.\r
701 \r
702     // Check for sufficient space in buffer\r
703     if ((pgm->code_size + 6) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
704     {\r
705         return ALT_E_BUF_OVF;\r
706     }\r
707 \r
708     // Verify channel register; construct rd mask value\r
709     uint8_t rd_mask = 0;\r
710     switch (chan_reg)\r
711     {\r
712     case ALT_DMA_PROGRAM_REG_SAR:\r
713         rd_mask = 0;\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
716         {\r
717             pgm->flag |= ALT_DMA_PROGRAM_FLAG_SAR;\r
718             pgm->sar = pgm->code_size + 2;\r
719         }\r
720         break;\r
721 \r
722     case ALT_DMA_PROGRAM_REG_CCR:\r
723         rd_mask = 1;\r
724         break;\r
725 \r
726     case ALT_DMA_PROGRAM_REG_DAR:\r
727         rd_mask = 2;\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
730         {\r
731             pgm->flag |= ALT_DMA_PROGRAM_FLAG_DAR;\r
732             pgm->dar = pgm->code_size + 2;\r
733         }\r
734         break;\r
735 \r
736     default:\r
737         return ALT_E_BAD_ARG;\r
738     }\r
739 \r
740     // Buffer of where to assemble the instruction.\r
741     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
742 \r
743     // Assemble DMAMOV\r
744     buffer[0] = 0xbc;;\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
750 \r
751     // Update the code size.\r
752     pgm->code_size += 6;\r
753 \r
754     return ALT_E_SUCCESS;\r
755 \r
756 }\r
757 \r
758 ALT_STATUS_CODE alt_dma_program_DMANOP(ALT_DMA_PROGRAM_t * pgm)\r
759 {\r
760     // For information on DMANOP, see PL330, section 4.3.13.\r
761 \r
762     // Check for sufficient space in buffer\r
763     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
764     {\r
765         return ALT_E_BUF_OVF;\r
766     }\r
767 \r
768     // Buffer of where to assemble the instruction.\r
769     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
770 \r
771     // Assemble DMANOP\r
772     buffer[0] = 0x18;\r
773 \r
774     // Update the code size.\r
775     pgm->code_size += 1;\r
776 \r
777     return ALT_E_SUCCESS;\r
778 }\r
779 \r
780 ALT_STATUS_CODE alt_dma_program_DMARMB(ALT_DMA_PROGRAM_t * pgm)\r
781 {\r
782     // For information on DMARMB, see PL330, section 4.3.14.\r
783 \r
784     // Check for sufficient space in buffer\r
785     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
786     {\r
787         return ALT_E_BUF_OVF;\r
788     }\r
789 \r
790     // Buffer of where to assemble the instruction.\r
791     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
792 \r
793     // Assemble DMARMB\r
794     buffer[0] = 0x12;\r
795 \r
796     // Update the code size.\r
797     pgm->code_size += 1;\r
798 \r
799     return ALT_E_SUCCESS;\r
800 }\r
801 \r
802 ALT_STATUS_CODE alt_dma_program_DMASEV(ALT_DMA_PROGRAM_t * pgm,\r
803                                        ALT_DMA_EVENT_t evt)\r
804 {\r
805     // For information on DMA, see PL330, section 4.3.15.\r
806 \r
807     // Check for sufficient space in buffer\r
808     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
809     {\r
810         return ALT_E_BUF_OVF;\r
811     }\r
812 \r
813     // Validate evt selection\r
814     switch (evt)\r
815     {\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
825         break;\r
826     default:\r
827         return ALT_E_BAD_ARG;\r
828     }\r
829 \r
830     // Buffer of where to assemble the instruction.\r
831     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
832 \r
833     // Assemble DMASEV\r
834     buffer[0] = 0x34;\r
835     buffer[1] = (uint8_t)(evt) << 3;\r
836 \r
837     // Update the code size.\r
838     pgm->code_size += 2;\r
839 \r
840     return ALT_E_SUCCESS;\r
841 }\r
842 \r
843 ALT_STATUS_CODE alt_dma_program_DMAST(ALT_DMA_PROGRAM_t * pgm,\r
844                                       ALT_DMA_PROGRAM_INST_MOD_t mod)\r
845 {\r
846     // For information on DMAST, see PL330, section 4.3.16.\r
847 \r
848     // Check for sufficient space in buffer\r
849     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
850     {\r
851         return ALT_E_BUF_OVF;\r
852     }\r
853 \r
854     // Verify instruction modifier; construct bs, x mask value.\r
855     uint8_t bsx_mask = 0;\r
856     switch (mod)\r
857     {\r
858     case ALT_DMA_PROGRAM_INST_MOD_NONE:\r
859         bsx_mask = 0x0;\r
860         break;\r
861     case ALT_DMA_PROGRAM_INST_MOD_SINGLE:\r
862         bsx_mask = 0x1;\r
863         break;\r
864     case ALT_DMA_PROGRAM_INST_MOD_BURST:\r
865         bsx_mask = 0x3;\r
866         break;\r
867     default:\r
868         return ALT_E_BAD_ARG;\r
869     }\r
870 \r
871     // Buffer of where to assemble the instruction.\r
872     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
873 \r
874     // Assemble DMAST\r
875     buffer[0] = 0x08 | bsx_mask;\r
876 \r
877     // Update the code size.\r
878     pgm->code_size += 1;\r
879 \r
880     return ALT_E_SUCCESS;\r
881 }\r
882 \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
885 {\r
886     // For information on DMASTP, see PL330, section 4.3.17.\r
887 \r
888     // Check for sufficient space in buffer\r
889     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
890     {\r
891         return ALT_E_BUF_OVF;\r
892     }\r
893 \r
894     // Verify instruction modifier; construct bs mask value.\r
895     uint8_t bs_mask = 0;\r
896     switch (mod)\r
897     {\r
898     case ALT_DMA_PROGRAM_INST_MOD_SINGLE:\r
899         bs_mask = 0x0;\r
900         break;\r
901     case ALT_DMA_PROGRAM_INST_MOD_BURST:\r
902         bs_mask = 0x2;\r
903         break;\r
904     default:\r
905         return ALT_E_BAD_ARG;\r
906     }\r
907 \r
908     // Verify valid peripheral identifier.\r
909     if (periph > ((1 << 5) - 1))\r
910     {\r
911         return ALT_E_BAD_ARG;\r
912     }\r
913 \r
914     // Buffer of where to assemble the instruction.\r
915     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
916 \r
917     // Assemble DMASTP\r
918     buffer[0] = 0x29 | bs_mask;\r
919     buffer[1] = (uint8_t)(periph) << 3;\r
920 \r
921     // Update the code size.\r
922     pgm->code_size += 2;\r
923 \r
924     return ALT_E_SUCCESS;\r
925 }\r
926 \r
927 ALT_STATUS_CODE alt_dma_program_DMASTZ(ALT_DMA_PROGRAM_t * pgm)\r
928 {\r
929     // For information on DMASTZ, see PL330, section 4.3.18.\r
930 \r
931     // Check for sufficient space in buffer\r
932     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
933     {\r
934         return ALT_E_BUF_OVF;\r
935     }\r
936 \r
937     // Buffer of where to assemble the instruction.\r
938     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
939 \r
940     // Assemble DMASTZ\r
941     buffer[0] = 0x0c;\r
942 \r
943     // Update the code size.\r
944     pgm->code_size += 1;\r
945 \r
946     return ALT_E_SUCCESS;\r
947 }\r
948 \r
949 ALT_STATUS_CODE alt_dma_program_DMAWFE(ALT_DMA_PROGRAM_t * pgm,\r
950                                        ALT_DMA_EVENT_t evt, bool invalid)\r
951 {\r
952     // For information on DMAWFE, see PL330, section 4.3.19.\r
953 \r
954     // Check for sufficient space in buffer\r
955     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
956     {\r
957         return ALT_E_BUF_OVF;\r
958     }\r
959 \r
960     // Validate evt selection\r
961     switch (evt)\r
962     {\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
972         break;\r
973     default:\r
974         return ALT_E_BAD_ARG;\r
975     }\r
976 \r
977     // Construct i mask value\r
978     uint8_t i_mask = 0;\r
979     if (invalid)\r
980     {\r
981         i_mask = 0x2;\r
982     }\r
983 \r
984     // Buffer of where to assemble the instruction.\r
985     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
986 \r
987     // Assemble DMAWFE\r
988     buffer[0] = 0x36;\r
989     buffer[1] = ((uint8_t)(evt) << 3) | i_mask;\r
990 \r
991     // Update the code size.\r
992     pgm->code_size += 2;\r
993 \r
994     return ALT_E_SUCCESS;\r
995 }\r
996 \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
999 {\r
1000     // For information on DMAWFP, see PL330, section 4.3.20.\r
1001 \r
1002     // Check for sufficient space in buffer\r
1003     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
1004     {\r
1005         return ALT_E_BUF_OVF;\r
1006     }\r
1007 \r
1008     // Verify valid peripheral identifier.\r
1009     if (periph > ((1 << 5) - 1))\r
1010     {\r
1011         return ALT_E_BAD_ARG;\r
1012     }\r
1013 \r
1014     // Verify instruction modifier; construct bs, p mask value.\r
1015     uint8_t bsp_mask = 0;\r
1016     switch (mod)\r
1017     {\r
1018     case ALT_DMA_PROGRAM_INST_MOD_SINGLE:\r
1019         bsp_mask = 0x0;\r
1020         break;\r
1021     case ALT_DMA_PROGRAM_INST_MOD_BURST:\r
1022         bsp_mask = 0x2;\r
1023         break;\r
1024     case ALT_DMA_PROGRAM_INST_MOD_PERIPH:\r
1025         bsp_mask = 0x1;\r
1026         break;\r
1027     default:\r
1028         return ALT_E_BAD_ARG;\r
1029     }\r
1030 \r
1031     // Buffer of where to assemble the instruction.\r
1032     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
1033 \r
1034     // Assemble DMAWFP\r
1035     buffer[0] = 0x30 | bsp_mask;\r
1036     buffer[1] = (uint8_t)(periph) << 3;\r
1037 \r
1038     // Update the code size.\r
1039     pgm->code_size += 2;\r
1040 \r
1041     return ALT_E_SUCCESS;\r
1042 }\r
1043 \r
1044 ALT_STATUS_CODE alt_dma_program_DMAWMB(ALT_DMA_PROGRAM_t * pgm)\r
1045 {\r
1046     // For information on DMAWMB, see PL330, section 4.3.21.\r
1047 \r
1048     // Check for sufficient space in buffer\r
1049     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)\r
1050     {\r
1051         return ALT_E_BUF_OVF;\r
1052     }\r
1053 \r
1054     // Buffer of where to assemble the instruction.\r
1055     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;\r
1056 \r
1057     // Assemble DMAWMB\r
1058     buffer[0] = 0x13;\r
1059 \r
1060     // Update the code size.\r
1061     pgm->code_size += 1;\r
1062 \r
1063     return ALT_E_SUCCESS;\r
1064 }\r