source: rtems/c/src/lib/libbsp/arm/altera-cyclone-v/hwlib/src/hwmgr/alt_dma_program.c @ 76386c1

4.115
Last change on this file since 76386c1 was 76386c1, checked in by Sebastian Huber <sebastian.huber@…>, on Aug 26, 2014 at 2:00:44 PM

bsp/altera-cyclone-v: Add DMA support hwlib files

  • Property mode set to 100644
File size: 28.7 KB
Line 
1/******************************************************************************
2 *
3 * Copyright 2013 Altera Corporation. All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO
21 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
23 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
27 * OF SUCH DAMAGE.
28 *
29 ******************************************************************************/
30
31#include "alt_dma_program.h"
32#include "alt_cache.h"
33#include <stdio.h>
34
35/////
36
37// NOTE: To enable debugging output, delete the next line and uncomment the
38//   line after.
39#define dprintf(...)
40// #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
41
42/////
43
44//
45// The following section describes how the bits are used in the "flag" field:
46//
47
48// [17:16] Which loop registers (LOOP0, LOOP1) are currently being used by a
49//   partially assembled program. LOOP0 is always used before LOOP1. LOOP1 is
50//   always ended before LOOP0.
51#define ALT_DMA_PROGRAM_FLAG_LOOP0 (1UL << 16)
52#define ALT_DMA_PROGRAM_FLAG_LOOP1 (1UL << 17)
53#define ALT_DMA_PROGRAM_FLAG_LOOP_ALL (ALT_DMA_PROGRAM_FLAG_LOOP0 | ALT_DMA_PROGRAM_FLAG_LOOP1)
54
55// [18] Flag that marks LOOP0 as a forever loop. Said another way, LOOP0 is
56//   being used to execute the DMALPFE directive.
57#define ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE (1UL << 18)
58// [19] Flag that marks LOOP1 as a forever loop. Said another way, LOOP1 is
59//   being used to execute the DMALPFE directive.
60#define ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE (1UL << 19)
61
62// [24] Flag that the first SAR has been programmed. The SAR field is valid and
63//    is the offset from the start of the buffer where SAR is located.
64#define ALT_DMA_PROGRAM_FLAG_SAR (1UL << 24)
65// [25] Flag that the first DAR has been programmed. The DAR field is valid and
66//    is the offset from the start of the buffer where DAR is located.
67#define ALT_DMA_PROGRAM_FLAG_DAR (1UL << 25)
68
69// [31] Flag that marks the last assembled instruction as DMAEND.
70#define ALT_DMA_PROGRAM_FLAG_ENDED (1UL << 31)
71
72/////
73
74ALT_STATUS_CODE alt_dma_program_init(ALT_DMA_PROGRAM_t * pgm)
75{
76    // Clear the variables that matter.
77    pgm->flag      = 0;
78    pgm->code_size = 0;
79
80    // Calculate the cache aligned start location of the buffer.
81    size_t buffer = (size_t)pgm->program;
82    size_t offset = ((buffer + ALT_DMA_PROGRAM_CACHE_LINE_SIZE - 1) & ~(ALT_DMA_PROGRAM_CACHE_LINE_SIZE - 1)) - buffer;
83
84    // It is safe to cast to uint16_t because the extra offset can only be up to
85    // (ALT_DMA_PROGRAM_CACHE_LINE_SIZE - 1) or 31, which is within range of the
86    // uint16_t.
87    pgm->buffer_start = (uint16_t)offset;
88
89    return ALT_E_SUCCESS;
90}
91
92ALT_STATUS_CODE alt_dma_program_uninit(ALT_DMA_PROGRAM_t * pgm)
93{
94    return ALT_E_SUCCESS;
95}
96
97ALT_STATUS_CODE alt_dma_program_clear(ALT_DMA_PROGRAM_t * pgm)
98{
99    // Clear the variables that matter
100    pgm->flag      = 0;
101    pgm->code_size = 0;
102
103    return ALT_E_SUCCESS;
104}
105
106__attribute__((weak)) ALT_STATUS_CODE alt_cache_system_clean(void * address, size_t length)
107{
108    return ALT_E_SUCCESS;
109}
110
111ALT_STATUS_CODE alt_dma_program_validate(const ALT_DMA_PROGRAM_t * pgm)
112{
113    // Verify that at least one instruction is in the buffer
114    if (pgm->code_size == 0)
115    {
116        return ALT_E_ERROR;
117    }
118
119    // Verify all loops are completed.
120    if (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)
121    {
122        return ALT_E_ERROR;
123    }
124
125    // Verify last item is DMAEND
126    if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_ENDED))
127    {
128        return ALT_E_ERROR;
129    }
130
131    // Sync the DMA program to RAM.
132    void * vaddr  = (void *)((uintptr_t)(pgm->program + pgm->buffer_start) & ~(ALT_CACHE_LINE_SIZE - 1));
133    size_t length = (pgm->code_size + ALT_CACHE_LINE_SIZE) & ~(ALT_CACHE_LINE_SIZE - 1);
134
135    dprintf("DEBUG[DMAP]: Program (real) @ %p, length = 0x%x.\n", pgm->program + pgm->buffer_start, pgm->code_size);
136    dprintf("DEBUG[DMAP]: Clean: addr = %p, length = 0x%x.\n", vaddr, length);
137
138    return alt_cache_system_clean(vaddr, length);
139}
140
141ALT_STATUS_CODE alt_dma_program_progress_reg(ALT_DMA_PROGRAM_t * pgm,
142                                             ALT_DMA_PROGRAM_REG_t reg,
143                                             uint32_t current, uint32_t * progress)
144{
145    // Pointer to where the register is initialized in the program buffer.
146    uint8_t * buffer = NULL;
147
148    switch (reg)
149    {
150    case ALT_DMA_PROGRAM_REG_SAR:
151        if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_SAR))
152        {
153            return ALT_E_BAD_ARG;
154        }
155        buffer = pgm->program + pgm->buffer_start + pgm->sar;
156        break;
157
158    case ALT_DMA_PROGRAM_REG_DAR:
159        if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_DAR))
160        {
161            return ALT_E_BAD_ARG;
162        }
163        buffer = pgm->program + pgm->buffer_start + pgm->dar;
164        break;
165
166    default:
167        return ALT_E_BAD_ARG;
168    }
169
170    uint32_t initial =
171        (buffer[3] << 24) |
172        (buffer[2] << 16) |
173        (buffer[1] <<  8) |
174        (buffer[0] <<  0);
175
176    *progress = current - initial;
177
178    return ALT_E_SUCCESS;
179}
180
181ALT_STATUS_CODE alt_dma_program_update_reg(ALT_DMA_PROGRAM_t * pgm,
182                                           ALT_DMA_PROGRAM_REG_t reg, uint32_t val)
183{
184    uint8_t * buffer = NULL;
185
186    switch (reg)
187    {
188    case ALT_DMA_PROGRAM_REG_SAR:
189        if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_SAR))
190        {
191            return ALT_E_BAD_ARG;
192        }
193        buffer = pgm->program + pgm->buffer_start + pgm->sar;
194        break;
195
196    case ALT_DMA_PROGRAM_REG_DAR:
197        if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_DAR))
198        {
199            return ALT_E_BAD_ARG;
200        }
201        buffer = pgm->program + pgm->buffer_start + pgm->dar;
202        break;
203
204    default:
205        return ALT_E_BAD_ARG;
206    }
207
208    buffer[0] = (uint8_t)((val >>  0) & 0xff);
209    buffer[1] = (uint8_t)((val >>  8) & 0xff);
210    buffer[2] = (uint8_t)((val >> 16) & 0xff);
211    buffer[3] = (uint8_t)((val >> 24) & 0xff);
212
213    return ALT_E_SUCCESS;
214}
215
216ALT_STATUS_CODE alt_dma_program_DMAADDH(ALT_DMA_PROGRAM_t * pgm,
217                                        ALT_DMA_PROGRAM_REG_t addr_reg, uint16_t val)
218{
219    // For information on DMAADDH, see PL330, section 4.3.1.
220
221    // Check for sufficient space in buffer
222    if ((pgm->code_size + 3) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
223    {
224        return ALT_E_BUF_OVF;
225    }
226
227    // Verify valid register; construct instruction modifier.
228    uint8_t ra_mask = 0;
229    switch (addr_reg)
230    {
231    case ALT_DMA_PROGRAM_REG_SAR:
232        ra_mask = 0x0;
233        break;
234    case ALT_DMA_PROGRAM_REG_DAR:
235        ra_mask = 0x2;
236        break;
237    default:
238        return ALT_E_BAD_ARG;
239    }
240
241    // Buffer of where to assemble the instruction.
242    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
243
244    // Assemble DMAADDH
245    buffer[0] = 0x54 | ra_mask;
246    buffer[1] = (uint8_t)(val & 0xff);
247    buffer[2] = (uint8_t)(val >> 8);
248
249    // Update the code size.
250    pgm->code_size += 3;
251
252    return ALT_E_SUCCESS;
253}
254
255ALT_STATUS_CODE alt_dma_program_DMAADNH(ALT_DMA_PROGRAM_t * pgm,
256                                        ALT_DMA_PROGRAM_REG_t addr_reg, uint16_t val)
257{
258    // For information on DMAADNH, see PL330, section 4.3.2.
259
260    // Check for sufficient space in buffer
261    if ((pgm->code_size + 3) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
262    {
263        return ALT_E_BUF_OVF;
264    }
265
266    // Verify valid register; construct instruction modifier.
267    uint8_t ra_mask = 0;
268    switch (addr_reg)
269    {
270    case ALT_DMA_PROGRAM_REG_SAR:
271        ra_mask = 0x0;
272        break;
273    case ALT_DMA_PROGRAM_REG_DAR:
274        ra_mask = 0x2;
275        break;
276    default:
277        return ALT_E_BAD_ARG;
278    }
279
280    // Buffer of where to assemble the instruction.
281    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
282
283    // Assemble DMAADNH
284    buffer[0] = 0x5c | ra_mask;
285    buffer[1] = (uint8_t)(val & 0xff);
286    buffer[2] = (uint8_t)(val >> 8);
287
288    // Update the code size.
289    pgm->code_size += 3;
290
291    return ALT_E_SUCCESS;
292}
293
294ALT_STATUS_CODE alt_dma_program_DMAEND(ALT_DMA_PROGRAM_t * pgm)
295{
296    // For information on DMAEND, see PL330, section 4.3.3.
297
298    // Check for sufficient space in buffer
299    if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
300    {
301        return ALT_E_BUF_OVF;
302    }
303
304    // Buffer of where to assemble the instruction.
305    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
306
307    // Assemble DMAEND
308    buffer[0] = 0x00;
309
310    // Update the code size.
311    pgm->code_size += 1;
312
313    // Mark program as ended.
314    pgm->flag |= ALT_DMA_PROGRAM_FLAG_ENDED;
315
316    return ALT_E_SUCCESS;
317}
318
319ALT_STATUS_CODE alt_dma_program_DMAFLUSHP(ALT_DMA_PROGRAM_t * pgm,
320                                          ALT_DMA_PERIPH_t periph)
321{
322    // For information on DMAFLUSHP, see PL330, section 4.3.4.
323
324    // Check for sufficient space in buffer
325    if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
326    {
327        return ALT_E_BUF_OVF;
328    }
329
330    // Verify valid peripheral identifier.
331    if (periph > ((1 << 5) - 1))
332    {
333        return ALT_E_BAD_ARG;
334    }
335
336    // Buffer of where to assemble the instruction.
337    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
338
339    // Assemble DMAFLUSHP
340    buffer[0] = 0x35;
341    buffer[1] = (uint8_t)(periph) << 3;
342
343    // Update the code size.
344    pgm->code_size += 2;
345
346    return ALT_E_SUCCESS;
347}
348
349ALT_STATUS_CODE alt_dma_program_DMAGO(ALT_DMA_PROGRAM_t * pgm,
350                                      ALT_DMA_CHANNEL_t channel, uint32_t val,
351                                      ALT_DMA_SECURITY_t sec)
352{
353    // For information on DMAGO, see PL330, section 4.3.5.
354
355    // Check for sufficient space in buffer
356    if ((pgm->code_size + 6) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
357    {
358        return ALT_E_BUF_OVF;
359    }
360
361    // Verify channel
362    switch (channel)
363    {
364    case ALT_DMA_CHANNEL_0:
365    case ALT_DMA_CHANNEL_1:
366    case ALT_DMA_CHANNEL_2:
367    case ALT_DMA_CHANNEL_3:
368    case ALT_DMA_CHANNEL_4:
369    case ALT_DMA_CHANNEL_5:
370    case ALT_DMA_CHANNEL_6:
371    case ALT_DMA_CHANNEL_7:
372        break;
373    default:
374        return ALT_E_BAD_ARG;
375    }
376
377    // Verify security; construct ns mask value
378    uint8_t ns_mask = 0;
379    switch (sec)
380    {
381    case ALT_DMA_SECURITY_DEFAULT:
382    case ALT_DMA_SECURITY_SECURE:
383        ns_mask = 0x0;
384        break;
385    case ALT_DMA_SECURITY_NONSECURE:
386        ns_mask = 0x2;
387        break;
388    default:
389        return ALT_E_BAD_ARG;
390    }
391
392    // Buffer of where to assemble the instruction.
393    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
394
395    // Assemble DMAGO
396    buffer[0] = 0xa0 | ns_mask;
397    buffer[1] = (uint8_t)channel;
398    buffer[2] = (uint8_t)((val >>  0) & 0xff);
399    buffer[3] = (uint8_t)((val >>  8) & 0xff);
400    buffer[4] = (uint8_t)((val >> 16) & 0xff);
401    buffer[5] = (uint8_t)((val >> 24) & 0xff);
402
403    // Update the code size.
404    pgm->code_size += 6;
405
406    return ALT_E_SUCCESS;
407}
408
409ALT_STATUS_CODE alt_dma_program_DMAKILL(ALT_DMA_PROGRAM_t * pgm)
410{
411    // For information on DMAKILL, see PL330, section 4.3.6.
412
413    // Check for sufficient space in buffer
414    if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
415    {
416        return ALT_E_BUF_OVF;
417    }
418
419    // Buffer of where to assemble the instruction.
420    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
421
422    // Assemble DMAKILL
423    buffer[0] = 0x01;
424
425    // Update the code size.
426    pgm->code_size += 1;
427
428    return ALT_E_SUCCESS;
429}
430
431ALT_STATUS_CODE alt_dma_program_DMALD(ALT_DMA_PROGRAM_t * pgm,
432                                      ALT_DMA_PROGRAM_INST_MOD_t mod)
433{
434    // For information on DMALD, see PL330, section 4.3.7.
435
436    // Check for sufficient space in buffer
437    if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
438    {
439        return ALT_E_BUF_OVF;
440    }
441
442    // Verify instruction modifier; construct bs, x mask value.
443    uint8_t bsx_mask = 0;
444    switch (mod)
445    {
446    case ALT_DMA_PROGRAM_INST_MOD_NONE:
447        bsx_mask = 0x0;
448        break;
449    case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
450        bsx_mask = 0x1;
451        break;
452    case ALT_DMA_PROGRAM_INST_MOD_BURST:
453        bsx_mask = 0x3;
454        break;
455    default:
456        return ALT_E_BAD_ARG;
457    }
458
459    // Buffer of where to assemble the instruction.
460    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
461
462    // Assemble DMALD
463    buffer[0] = 0x04 | bsx_mask;
464
465    // Update the code size.
466    pgm->code_size += 1;
467
468    return ALT_E_SUCCESS;
469}
470
471ALT_STATUS_CODE alt_dma_program_DMALDP(ALT_DMA_PROGRAM_t * pgm,
472                                       ALT_DMA_PROGRAM_INST_MOD_t mod, ALT_DMA_PERIPH_t periph)
473{
474    // For information on DMALDP, see PL330, section 4.3.8.
475
476    // Check for sufficient space in buffer
477    if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
478    {
479        return ALT_E_BUF_OVF;
480    }
481
482    // Verify instruction modifier; construct bs mask value.
483    uint8_t bs_mask = 0;
484    switch (mod)
485    {
486    case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
487        bs_mask = 0x0;
488        break;
489    case ALT_DMA_PROGRAM_INST_MOD_BURST:
490        bs_mask = 0x2;
491        break;
492    default:
493        return ALT_E_BAD_ARG;
494    }
495
496    // Verify valid peripheral identifier.
497    if (periph > ((1 << 5) - 1))
498    {
499        return ALT_E_BAD_ARG;
500    }
501
502    // Buffer of where to assemble the instruction.
503    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
504
505    // Assemble DMALDP
506    buffer[0] = 0x25 | bs_mask;
507    buffer[1] = (uint8_t)(periph) << 3;
508
509    // Update the code size.
510    pgm->code_size += 2;
511
512    return ALT_E_SUCCESS;
513}
514
515ALT_STATUS_CODE alt_dma_program_DMALP(ALT_DMA_PROGRAM_t * pgm,
516                                      uint32_t iterations)
517{
518    // For information on DMALP, see PL330, section 4.3.9.
519
520    // Check for sufficient space in buffer
521    if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
522    {
523        return ALT_E_BUF_OVF;
524    }
525
526    // Verify iterations in range
527    if ((iterations == 0) || (iterations > 256))
528    {
529        return ALT_E_BAD_ARG;
530    }
531
532    // Find suitable LOOPx register to use; construct lc mask value.
533    uint8_t lc_mask = 0;
534    switch (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)
535    {
536    case 0:                              // No LOOPx in use. Use LOOP0.
537        pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP0;
538        pgm->loop0 = pgm->code_size + 2; // This is the first instruction after the DMALP
539        lc_mask = 0x0;
540        break;
541
542    case ALT_DMA_PROGRAM_FLAG_LOOP0:     // LOOP0 in use. Use LOOP1.
543        pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP1;
544        pgm->loop1 = pgm->code_size + 2; // This is the first instruction after the DMALP
545        lc_mask = 0x2;
546        break;
547
548    case ALT_DMA_PROGRAM_FLAG_LOOP_ALL: // All LOOPx in use. Report error.
549        return ALT_E_BAD_OPERATION;
550
551    default:                            // Catastrophic error !!!
552        return ALT_E_ERROR;
553    }
554
555    // Buffer of where to assemble the instruction.
556    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
557
558    // Assemble DMALP
559    buffer[0] = 0x20 | lc_mask;
560    buffer[1] = (uint8_t)(iterations - 1);
561
562    // Update the code size.
563    pgm->code_size += 2;
564
565    return ALT_E_SUCCESS;
566}
567
568ALT_STATUS_CODE alt_dma_program_DMALPEND(ALT_DMA_PROGRAM_t * pgm,
569                                         ALT_DMA_PROGRAM_INST_MOD_t mod)
570{
571    // For information on DMALPEND, see PL330, section 4.3.10.
572
573    // Check for sufficient space in buffer
574    if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
575    {
576        return ALT_E_BUF_OVF;
577    }
578
579    // Verify instruction modifier; construct bs, x mask value.
580    uint8_t bsx_mask = 0;
581    switch (mod)
582    {
583    case ALT_DMA_PROGRAM_INST_MOD_NONE:
584        bsx_mask = 0x0;
585        break;
586    case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
587        bsx_mask = 0x1;
588        break;
589    case ALT_DMA_PROGRAM_INST_MOD_BURST:
590        bsx_mask = 0x3;
591        break;
592    default:
593        return ALT_E_BAD_ARG;
594    }
595
596    // Determine the loop to end, if it is a forever loop; construct lc mask, nf mask, and backwards jump value.
597    uint8_t lc_mask = 0;
598    uint8_t nf_mask = 0;
599    uint16_t backwards_jump = 0;
600    switch (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)
601    {
602    case ALT_DMA_PROGRAM_FLAG_LOOP0:    // LOOP0 in use. End LOOP0.
603
604        backwards_jump = pgm->code_size - pgm->loop0;
605
606        pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP0;
607        pgm->loop0 = 0;
608
609        lc_mask = 0x0;
610
611        if (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE)
612        {
613            pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE;
614        }
615        else
616        {
617            nf_mask = 0x10;
618        }
619        break;
620
621    case ALT_DMA_PROGRAM_FLAG_LOOP_ALL: // All LOOPx in use. End LOOP1.
622
623        backwards_jump = pgm->code_size - pgm->loop1;
624
625        pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP1;
626        pgm->loop1 = 0;
627
628        lc_mask = 0x4;
629
630        if (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE)
631        {
632            pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE;
633        }
634        else
635        {
636            nf_mask = 0x10;
637        }
638        break;
639
640    case 0:                             // No LOOPx in use. Report error!
641        return ALT_E_BAD_OPERATION;
642
643    default:                            // Catastrophic error !!!
644        return ALT_E_ERROR;
645    }
646
647    // Verify that the jump size is suitable
648    if (backwards_jump > 255)
649    {
650        return ALT_E_ARG_RANGE;
651    }
652
653    // Buffer of where to assemble the instruction.
654    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
655
656    // Assemble DMALPEND
657    buffer[0] = 0x28 | nf_mask | lc_mask | bsx_mask;
658    buffer[1] = (uint8_t)(backwards_jump);
659
660    // Update the code size.
661    pgm->code_size += 2;
662
663    return ALT_E_SUCCESS;
664}
665
666ALT_STATUS_CODE alt_dma_program_DMALPFE(ALT_DMA_PROGRAM_t * pgm)
667{
668    // For information on DMALPFE, see PL330, section 4.3.11.
669
670    // Find suitable LOOPx register to use;
671    switch (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)
672    {
673    case 0:                             // No LOOPx in use. Use LOOP0.
674        pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP0;
675        pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE;
676        pgm->loop0 = pgm->code_size;
677        break;
678
679    case ALT_DMA_PROGRAM_FLAG_LOOP0:    // LOOP0 in use. Use LOOP1.
680        pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP1;
681        pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE;
682        pgm->loop1 = pgm->code_size;
683        break;
684
685    case ALT_DMA_PROGRAM_FLAG_LOOP_ALL: // All LOOPx in use. Report error.
686        return ALT_E_BAD_OPERATION;
687
688    default:                            // Catastrophic error !!!
689        return ALT_E_ERROR;
690    }
691
692    // Nothing to assemble.
693
694    return ALT_E_SUCCESS;
695}
696
697ALT_STATUS_CODE alt_dma_program_DMAMOV(ALT_DMA_PROGRAM_t * pgm,
698                                       ALT_DMA_PROGRAM_REG_t chan_reg, uint32_t val)
699{
700    // For information on DMAMOV, see PL330, section 4.3.12.
701
702    // Check for sufficient space in buffer
703    if ((pgm->code_size + 6) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
704    {
705        return ALT_E_BUF_OVF;
706    }
707
708    // Verify channel register; construct rd mask value
709    uint8_t rd_mask = 0;
710    switch (chan_reg)
711    {
712    case ALT_DMA_PROGRAM_REG_SAR:
713        rd_mask = 0;
714        // If SAR has not been set before, mark the location of where SAR is in the buffer.
715        if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_SAR))
716        {
717            pgm->flag |= ALT_DMA_PROGRAM_FLAG_SAR;
718            pgm->sar = pgm->code_size + 2;
719        }
720        break;
721
722    case ALT_DMA_PROGRAM_REG_CCR:
723        rd_mask = 1;
724        break;
725
726    case ALT_DMA_PROGRAM_REG_DAR:
727        rd_mask = 2;
728        // If DAR has not been set before, mark the location of where DAR is in the buffer.
729        if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_DAR))
730        {
731            pgm->flag |= ALT_DMA_PROGRAM_FLAG_DAR;
732            pgm->dar = pgm->code_size + 2;
733        }
734        break;
735
736    default:
737        return ALT_E_BAD_ARG;
738    }
739
740    // Buffer of where to assemble the instruction.
741    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
742
743    // Assemble DMAMOV
744    buffer[0] = 0xbc;;
745    buffer[1] = rd_mask;
746    buffer[2] = (uint8_t)((val >>  0) & 0xff);
747    buffer[3] = (uint8_t)((val >>  8) & 0xff);
748    buffer[4] = (uint8_t)((val >> 16) & 0xff);
749    buffer[5] = (uint8_t)((val >> 24) & 0xff);
750
751    // Update the code size.
752    pgm->code_size += 6;
753
754    return ALT_E_SUCCESS;
755
756}
757
758ALT_STATUS_CODE alt_dma_program_DMANOP(ALT_DMA_PROGRAM_t * pgm)
759{
760    // For information on DMANOP, see PL330, section 4.3.13.
761
762    // Check for sufficient space in buffer
763    if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
764    {
765        return ALT_E_BUF_OVF;
766    }
767
768    // Buffer of where to assemble the instruction.
769    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
770
771    // Assemble DMANOP
772    buffer[0] = 0x18;
773
774    // Update the code size.
775    pgm->code_size += 1;
776
777    return ALT_E_SUCCESS;
778}
779
780ALT_STATUS_CODE alt_dma_program_DMARMB(ALT_DMA_PROGRAM_t * pgm)
781{
782    // For information on DMARMB, see PL330, section 4.3.14.
783
784    // Check for sufficient space in buffer
785    if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
786    {
787        return ALT_E_BUF_OVF;
788    }
789
790    // Buffer of where to assemble the instruction.
791    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
792
793    // Assemble DMARMB
794    buffer[0] = 0x12;
795
796    // Update the code size.
797    pgm->code_size += 1;
798
799    return ALT_E_SUCCESS;
800}
801
802ALT_STATUS_CODE alt_dma_program_DMASEV(ALT_DMA_PROGRAM_t * pgm,
803                                       ALT_DMA_EVENT_t evt)
804{
805    // For information on DMA, see PL330, section 4.3.15.
806
807    // Check for sufficient space in buffer
808    if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
809    {
810        return ALT_E_BUF_OVF;
811    }
812
813    // Validate evt selection
814    switch (evt)
815    {
816    case ALT_DMA_EVENT_0:
817    case ALT_DMA_EVENT_1:
818    case ALT_DMA_EVENT_2:
819    case ALT_DMA_EVENT_3:
820    case ALT_DMA_EVENT_4:
821    case ALT_DMA_EVENT_5:
822    case ALT_DMA_EVENT_6:
823    case ALT_DMA_EVENT_7:
824    case ALT_DMA_EVENT_ABORT:
825        break;
826    default:
827        return ALT_E_BAD_ARG;
828    }
829
830    // Buffer of where to assemble the instruction.
831    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
832
833    // Assemble DMASEV
834    buffer[0] = 0x34;
835    buffer[1] = (uint8_t)(evt) << 3;
836
837    // Update the code size.
838    pgm->code_size += 2;
839
840    return ALT_E_SUCCESS;
841}
842
843ALT_STATUS_CODE alt_dma_program_DMAST(ALT_DMA_PROGRAM_t * pgm,
844                                      ALT_DMA_PROGRAM_INST_MOD_t mod)
845{
846    // For information on DMAST, see PL330, section 4.3.16.
847
848    // Check for sufficient space in buffer
849    if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
850    {
851        return ALT_E_BUF_OVF;
852    }
853
854    // Verify instruction modifier; construct bs, x mask value.
855    uint8_t bsx_mask = 0;
856    switch (mod)
857    {
858    case ALT_DMA_PROGRAM_INST_MOD_NONE:
859        bsx_mask = 0x0;
860        break;
861    case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
862        bsx_mask = 0x1;
863        break;
864    case ALT_DMA_PROGRAM_INST_MOD_BURST:
865        bsx_mask = 0x3;
866        break;
867    default:
868        return ALT_E_BAD_ARG;
869    }
870
871    // Buffer of where to assemble the instruction.
872    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
873
874    // Assemble DMAST
875    buffer[0] = 0x08 | bsx_mask;
876
877    // Update the code size.
878    pgm->code_size += 1;
879
880    return ALT_E_SUCCESS;
881}
882
883ALT_STATUS_CODE alt_dma_program_DMASTP(ALT_DMA_PROGRAM_t * pgm,
884                                       ALT_DMA_PROGRAM_INST_MOD_t mod, ALT_DMA_PERIPH_t periph)
885{
886    // For information on DMASTP, see PL330, section 4.3.17.
887
888    // Check for sufficient space in buffer
889    if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
890    {
891        return ALT_E_BUF_OVF;
892    }
893
894    // Verify instruction modifier; construct bs mask value.
895    uint8_t bs_mask = 0;
896    switch (mod)
897    {
898    case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
899        bs_mask = 0x0;
900        break;
901    case ALT_DMA_PROGRAM_INST_MOD_BURST:
902        bs_mask = 0x2;
903        break;
904    default:
905        return ALT_E_BAD_ARG;
906    }
907
908    // Verify valid peripheral identifier.
909    if (periph > ((1 << 5) - 1))
910    {
911        return ALT_E_BAD_ARG;
912    }
913
914    // Buffer of where to assemble the instruction.
915    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
916
917    // Assemble DMASTP
918    buffer[0] = 0x29 | bs_mask;
919    buffer[1] = (uint8_t)(periph) << 3;
920
921    // Update the code size.
922    pgm->code_size += 2;
923
924    return ALT_E_SUCCESS;
925}
926
927ALT_STATUS_CODE alt_dma_program_DMASTZ(ALT_DMA_PROGRAM_t * pgm)
928{
929    // For information on DMASTZ, see PL330, section 4.3.18.
930
931    // Check for sufficient space in buffer
932    if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
933    {
934        return ALT_E_BUF_OVF;
935    }
936
937    // Buffer of where to assemble the instruction.
938    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
939
940    // Assemble DMASTZ
941    buffer[0] = 0x0c;
942
943    // Update the code size.
944    pgm->code_size += 1;
945
946    return ALT_E_SUCCESS;
947}
948
949ALT_STATUS_CODE alt_dma_program_DMAWFE(ALT_DMA_PROGRAM_t * pgm,
950                                       ALT_DMA_EVENT_t evt, bool invalid)
951{
952    // For information on DMAWFE, see PL330, section 4.3.19.
953
954    // Check for sufficient space in buffer
955    if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
956    {
957        return ALT_E_BUF_OVF;
958    }
959
960    // Validate evt selection
961    switch (evt)
962    {
963    case ALT_DMA_EVENT_0:
964    case ALT_DMA_EVENT_1:
965    case ALT_DMA_EVENT_2:
966    case ALT_DMA_EVENT_3:
967    case ALT_DMA_EVENT_4:
968    case ALT_DMA_EVENT_5:
969    case ALT_DMA_EVENT_6:
970    case ALT_DMA_EVENT_7:
971    case ALT_DMA_EVENT_ABORT:
972        break;
973    default:
974        return ALT_E_BAD_ARG;
975    }
976
977    // Construct i mask value
978    uint8_t i_mask = 0;
979    if (invalid)
980    {
981        i_mask = 0x2;
982    }
983
984    // Buffer of where to assemble the instruction.
985    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
986
987    // Assemble DMAWFE
988    buffer[0] = 0x36;
989    buffer[1] = ((uint8_t)(evt) << 3) | i_mask;
990
991    // Update the code size.
992    pgm->code_size += 2;
993
994    return ALT_E_SUCCESS;
995}
996
997ALT_STATUS_CODE alt_dma_program_DMAWFP(ALT_DMA_PROGRAM_t * pgm,
998                                       ALT_DMA_PERIPH_t periph, ALT_DMA_PROGRAM_INST_MOD_t mod)
999{
1000    // For information on DMAWFP, see PL330, section 4.3.20.
1001
1002    // Check for sufficient space in buffer
1003    if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
1004    {
1005        return ALT_E_BUF_OVF;
1006    }
1007
1008    // Verify valid peripheral identifier.
1009    if (periph > ((1 << 5) - 1))
1010    {
1011        return ALT_E_BAD_ARG;
1012    }
1013
1014    // Verify instruction modifier; construct bs, p mask value.
1015    uint8_t bsp_mask = 0;
1016    switch (mod)
1017    {
1018    case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
1019        bsp_mask = 0x0;
1020        break;
1021    case ALT_DMA_PROGRAM_INST_MOD_BURST:
1022        bsp_mask = 0x2;
1023        break;
1024    case ALT_DMA_PROGRAM_INST_MOD_PERIPH:
1025        bsp_mask = 0x1;
1026        break;
1027    default:
1028        return ALT_E_BAD_ARG;
1029    }
1030
1031    // Buffer of where to assemble the instruction.
1032    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
1033
1034    // Assemble DMAWFP
1035    buffer[0] = 0x30 | bsp_mask;
1036    buffer[1] = (uint8_t)(periph) << 3;
1037
1038    // Update the code size.
1039    pgm->code_size += 2;
1040
1041    return ALT_E_SUCCESS;
1042}
1043
1044ALT_STATUS_CODE alt_dma_program_DMAWMB(ALT_DMA_PROGRAM_t * pgm)
1045{
1046    // For information on DMAWMB, see PL330, section 4.3.21.
1047
1048    // Check for sufficient space in buffer
1049    if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
1050    {
1051        return ALT_E_BUF_OVF;
1052    }
1053
1054    // Buffer of where to assemble the instruction.
1055    uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
1056
1057    // Assemble DMAWMB
1058    buffer[0] = 0x13;
1059
1060    // Update the code size.
1061    pgm->code_size += 1;
1062
1063    return ALT_E_SUCCESS;
1064}
Note: See TracBrowser for help on using the repository browser.