Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:42

0001 /**
0002  * @file
0003  *
0004  * @ingroup RTEMSBSPsARMCycVContrib
0005  */
0006 
0007 /******************************************************************************
0008  *
0009  * Copyright 2013 Altera Corporation. All Rights Reserved.
0010  *
0011  * Redistribution and use in source and binary forms, with or without
0012  * modification, are permitted provided that the following conditions are met:
0013  *
0014  * 1. Redistributions of source code must retain the above copyright notice,
0015  * this list of conditions and the following disclaimer.
0016  *
0017  * 2. Redistributions in binary form must reproduce the above copyright notice,
0018  * this list of conditions and the following disclaimer in the documentation
0019  * and/or other materials provided with the distribution.
0020  *
0021  * 3. The name of the author may not be used to endorse or promote products
0022  * derived from this software without specific prior written permission.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
0025  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
0026  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO
0027  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0028  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
0029  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
0032  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
0033  * OF SUCH DAMAGE.
0034  *
0035  ******************************************************************************/
0036 
0037 #include <bsp/alt_dma_program.h>
0038 #include <bsp/alt_cache.h>
0039 #include <stdio.h>
0040 
0041 /////
0042 
0043 // NOTE: To enable debugging output, delete the next line and uncomment the
0044 //   line after.
0045 #define dprintf(...)
0046 // #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
0047 
0048 /////
0049 
0050 //
0051 // The following section describes how the bits are used in the "flag" field:
0052 //
0053 
0054 // [17:16] Which loop registers (LOOP0, LOOP1) are currently being used by a
0055 //   partially assembled program. LOOP0 is always used before LOOP1. LOOP1 is
0056 //   always ended before LOOP0.
0057 #define ALT_DMA_PROGRAM_FLAG_LOOP0 (1UL << 16)
0058 #define ALT_DMA_PROGRAM_FLAG_LOOP1 (1UL << 17)
0059 #define ALT_DMA_PROGRAM_FLAG_LOOP_ALL (ALT_DMA_PROGRAM_FLAG_LOOP0 | ALT_DMA_PROGRAM_FLAG_LOOP1)
0060 
0061 // [18] Flag that marks LOOP0 as a forever loop. Said another way, LOOP0 is
0062 //   being used to execute the DMALPFE directive.
0063 #define ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE (1UL << 18)
0064 // [19] Flag that marks LOOP1 as a forever loop. Said another way, LOOP1 is
0065 //   being used to execute the DMALPFE directive.
0066 #define ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE (1UL << 19)
0067 
0068 // [24] Flag that the first SAR has been programmed. The SAR field is valid and
0069 //    is the offset from the start of the buffer where SAR is located.
0070 #define ALT_DMA_PROGRAM_FLAG_SAR (1UL << 24)
0071 // [25] Flag that the first DAR has been programmed. The DAR field is valid and
0072 //    is the offset from the start of the buffer where DAR is located.
0073 #define ALT_DMA_PROGRAM_FLAG_DAR (1UL << 25)
0074 
0075 // [31] Flag that marks the last assembled instruction as DMAEND.
0076 #define ALT_DMA_PROGRAM_FLAG_ENDED (1UL << 31)
0077 
0078 /////
0079 
0080 ALT_STATUS_CODE alt_dma_program_init(ALT_DMA_PROGRAM_t * pgm)
0081 {
0082     // Clear the variables that matter.
0083     pgm->flag      = 0;
0084     pgm->code_size = 0;
0085 
0086     // Calculate the cache aligned start location of the buffer.
0087     size_t buffer = (size_t)pgm->program;
0088     size_t offset = ((buffer + ALT_DMA_PROGRAM_CACHE_LINE_SIZE - 1) & ~(ALT_DMA_PROGRAM_CACHE_LINE_SIZE - 1)) - buffer;
0089 
0090     // It is safe to cast to uint16_t because the extra offset can only be up to
0091     // (ALT_DMA_PROGRAM_CACHE_LINE_SIZE - 1) or 31, which is within range of the
0092     // uint16_t.
0093     pgm->buffer_start = (uint16_t)offset;
0094 
0095     return ALT_E_SUCCESS;
0096 }
0097 
0098 ALT_STATUS_CODE alt_dma_program_uninit(ALT_DMA_PROGRAM_t * pgm)
0099 {
0100     return ALT_E_SUCCESS;
0101 }
0102 
0103 ALT_STATUS_CODE alt_dma_program_clear(ALT_DMA_PROGRAM_t * pgm)
0104 {
0105     // Clear the variables that matter
0106     pgm->flag      = 0;
0107     pgm->code_size = 0;
0108 
0109     return ALT_E_SUCCESS;
0110 }
0111 
0112 __attribute__((weak)) ALT_STATUS_CODE alt_cache_system_clean(void * address, size_t length)
0113 {
0114     return ALT_E_SUCCESS;
0115 }
0116 
0117 ALT_STATUS_CODE alt_dma_program_validate(const ALT_DMA_PROGRAM_t * pgm)
0118 {
0119     // Verify that at least one instruction is in the buffer
0120     if (pgm->code_size == 0)
0121     {
0122         return ALT_E_ERROR;
0123     }
0124 
0125     // Verify all loops are completed.
0126     if (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)
0127     {
0128         return ALT_E_ERROR;
0129     }
0130 
0131     // Verify last item is DMAEND
0132     if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_ENDED))
0133     {
0134         return ALT_E_ERROR;
0135     }
0136 
0137     // Sync the DMA program to RAM.
0138     void * vaddr  = (void *)((uintptr_t)(pgm->program + pgm->buffer_start) & ~(ALT_CACHE_LINE_SIZE - 1));
0139     size_t length = (pgm->code_size + ALT_CACHE_LINE_SIZE) & ~(ALT_CACHE_LINE_SIZE - 1);
0140 
0141     dprintf("DEBUG[DMAP]: Program (real) @ %p, length = 0x%x.\n", pgm->program + pgm->buffer_start, pgm->code_size);
0142     dprintf("DEBUG[DMAP]: Clean: addr = %p, length = 0x%x.\n", vaddr, length);
0143 
0144     return alt_cache_system_clean(vaddr, length);
0145 }
0146 
0147 ALT_STATUS_CODE alt_dma_program_progress_reg(ALT_DMA_PROGRAM_t * pgm,
0148                                              ALT_DMA_PROGRAM_REG_t reg,
0149                                              uint32_t current, uint32_t * progress)
0150 {
0151     // Pointer to where the register is initialized in the program buffer.
0152     uint8_t * buffer = NULL;
0153 
0154     switch (reg)
0155     {
0156     case ALT_DMA_PROGRAM_REG_SAR:
0157         if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_SAR))
0158         {
0159             return ALT_E_BAD_ARG;
0160         }
0161         buffer = pgm->program + pgm->buffer_start + pgm->sar;
0162         break;
0163 
0164     case ALT_DMA_PROGRAM_REG_DAR:
0165         if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_DAR))
0166         {
0167             return ALT_E_BAD_ARG;
0168         }
0169         buffer = pgm->program + pgm->buffer_start + pgm->dar;
0170         break;
0171 
0172     default:
0173         return ALT_E_BAD_ARG;
0174     }
0175 
0176     uint32_t initial =
0177         (buffer[3] << 24) |
0178         (buffer[2] << 16) |
0179         (buffer[1] <<  8) |
0180         (buffer[0] <<  0);
0181 
0182     *progress = current - initial;
0183 
0184     return ALT_E_SUCCESS;
0185 }
0186 
0187 ALT_STATUS_CODE alt_dma_program_update_reg(ALT_DMA_PROGRAM_t * pgm,
0188                                            ALT_DMA_PROGRAM_REG_t reg, uint32_t val)
0189 {
0190     uint8_t * buffer = NULL;
0191 
0192     switch (reg)
0193     {
0194     case ALT_DMA_PROGRAM_REG_SAR:
0195         if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_SAR))
0196         {
0197             return ALT_E_BAD_ARG;
0198         }
0199         buffer = pgm->program + pgm->buffer_start + pgm->sar;
0200         break;
0201 
0202     case ALT_DMA_PROGRAM_REG_DAR:
0203         if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_DAR))
0204         {
0205             return ALT_E_BAD_ARG;
0206         }
0207         buffer = pgm->program + pgm->buffer_start + pgm->dar;
0208         break;
0209 
0210     default:
0211         return ALT_E_BAD_ARG;
0212     }
0213 
0214     buffer[0] = (uint8_t)((val >>  0) & 0xff);
0215     buffer[1] = (uint8_t)((val >>  8) & 0xff);
0216     buffer[2] = (uint8_t)((val >> 16) & 0xff);
0217     buffer[3] = (uint8_t)((val >> 24) & 0xff);
0218 
0219     return ALT_E_SUCCESS;
0220 }
0221 
0222 ALT_STATUS_CODE alt_dma_program_DMAADDH(ALT_DMA_PROGRAM_t * pgm,
0223                                         ALT_DMA_PROGRAM_REG_t addr_reg, uint16_t val)
0224 {
0225     // For information on DMAADDH, see PL330, section 4.3.1.
0226 
0227     // Check for sufficient space in buffer
0228     if ((pgm->code_size + 3) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0229     {
0230         return ALT_E_BUF_OVF;
0231     }
0232 
0233     // Verify valid register; construct instruction modifier.
0234     uint8_t ra_mask = 0;
0235     switch (addr_reg)
0236     {
0237     case ALT_DMA_PROGRAM_REG_SAR:
0238         ra_mask = 0x0;
0239         break;
0240     case ALT_DMA_PROGRAM_REG_DAR:
0241         ra_mask = 0x2;
0242         break;
0243     default:
0244         return ALT_E_BAD_ARG;
0245     }
0246 
0247     // Buffer of where to assemble the instruction.
0248     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0249 
0250     // Assemble DMAADDH
0251     buffer[0] = 0x54 | ra_mask;
0252     buffer[1] = (uint8_t)(val & 0xff);
0253     buffer[2] = (uint8_t)(val >> 8);
0254 
0255     // Update the code size.
0256     pgm->code_size += 3;
0257 
0258     return ALT_E_SUCCESS;
0259 }
0260 
0261 ALT_STATUS_CODE alt_dma_program_DMAADNH(ALT_DMA_PROGRAM_t * pgm,
0262                                         ALT_DMA_PROGRAM_REG_t addr_reg, uint16_t val)
0263 {
0264     // For information on DMAADNH, see PL330, section 4.3.2.
0265 
0266     // Check for sufficient space in buffer
0267     if ((pgm->code_size + 3) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0268     {
0269         return ALT_E_BUF_OVF;
0270     }
0271 
0272     // Verify valid register; construct instruction modifier.
0273     uint8_t ra_mask = 0;
0274     switch (addr_reg)
0275     {
0276     case ALT_DMA_PROGRAM_REG_SAR:
0277         ra_mask = 0x0;
0278         break;
0279     case ALT_DMA_PROGRAM_REG_DAR:
0280         ra_mask = 0x2;
0281         break;
0282     default:
0283         return ALT_E_BAD_ARG;
0284     }
0285 
0286     // Buffer of where to assemble the instruction.
0287     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0288 
0289     // Assemble DMAADNH
0290     buffer[0] = 0x5c | ra_mask;
0291     buffer[1] = (uint8_t)(val & 0xff);
0292     buffer[2] = (uint8_t)(val >> 8);
0293 
0294     // Update the code size.
0295     pgm->code_size += 3;
0296 
0297     return ALT_E_SUCCESS;
0298 }
0299 
0300 ALT_STATUS_CODE alt_dma_program_DMAEND(ALT_DMA_PROGRAM_t * pgm)
0301 {
0302     // For information on DMAEND, see PL330, section 4.3.3.
0303 
0304     // Check for sufficient space in buffer
0305     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0306     {
0307         return ALT_E_BUF_OVF;
0308     }
0309 
0310     // Buffer of where to assemble the instruction.
0311     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0312 
0313     // Assemble DMAEND
0314     buffer[0] = 0x00;
0315 
0316     // Update the code size.
0317     pgm->code_size += 1;
0318 
0319     // Mark program as ended.
0320     pgm->flag |= ALT_DMA_PROGRAM_FLAG_ENDED;
0321 
0322     return ALT_E_SUCCESS;
0323 }
0324 
0325 ALT_STATUS_CODE alt_dma_program_DMAFLUSHP(ALT_DMA_PROGRAM_t * pgm,
0326                                           ALT_DMA_PERIPH_t periph)
0327 {
0328     // For information on DMAFLUSHP, see PL330, section 4.3.4.
0329 
0330     // Check for sufficient space in buffer
0331     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0332     {
0333         return ALT_E_BUF_OVF;
0334     }
0335 
0336     // Verify valid peripheral identifier.
0337     if (periph > ((1 << 5) - 1))
0338     {
0339         return ALT_E_BAD_ARG;
0340     }
0341 
0342     // Buffer of where to assemble the instruction.
0343     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0344 
0345     // Assemble DMAFLUSHP
0346     buffer[0] = 0x35;
0347     buffer[1] = (uint8_t)(periph) << 3;
0348 
0349     // Update the code size.
0350     pgm->code_size += 2;
0351 
0352     return ALT_E_SUCCESS;
0353 }
0354 
0355 ALT_STATUS_CODE alt_dma_program_DMAGO(ALT_DMA_PROGRAM_t * pgm,
0356                                       ALT_DMA_CHANNEL_t channel, uint32_t val,
0357                                       ALT_DMA_SECURITY_t sec)
0358 {
0359     // For information on DMAGO, see PL330, section 4.3.5.
0360 
0361     // Check for sufficient space in buffer
0362     if ((pgm->code_size + 6) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0363     {
0364         return ALT_E_BUF_OVF;
0365     }
0366 
0367     // Verify channel
0368     switch (channel)
0369     {
0370     case ALT_DMA_CHANNEL_0:
0371     case ALT_DMA_CHANNEL_1:
0372     case ALT_DMA_CHANNEL_2:
0373     case ALT_DMA_CHANNEL_3:
0374     case ALT_DMA_CHANNEL_4:
0375     case ALT_DMA_CHANNEL_5:
0376     case ALT_DMA_CHANNEL_6:
0377     case ALT_DMA_CHANNEL_7:
0378         break;
0379     default:
0380         return ALT_E_BAD_ARG;
0381     }
0382 
0383     // Verify security; construct ns mask value
0384     uint8_t ns_mask = 0;
0385     switch (sec)
0386     {
0387     case ALT_DMA_SECURITY_DEFAULT:
0388     case ALT_DMA_SECURITY_SECURE:
0389         ns_mask = 0x0;
0390         break;
0391     case ALT_DMA_SECURITY_NONSECURE:
0392         ns_mask = 0x2;
0393         break;
0394     default:
0395         return ALT_E_BAD_ARG;
0396     }
0397 
0398     // Buffer of where to assemble the instruction.
0399     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0400 
0401     // Assemble DMAGO
0402     buffer[0] = 0xa0 | ns_mask;
0403     buffer[1] = (uint8_t)channel;
0404     buffer[2] = (uint8_t)((val >>  0) & 0xff);
0405     buffer[3] = (uint8_t)((val >>  8) & 0xff);
0406     buffer[4] = (uint8_t)((val >> 16) & 0xff);
0407     buffer[5] = (uint8_t)((val >> 24) & 0xff);
0408 
0409     // Update the code size.
0410     pgm->code_size += 6;
0411 
0412     return ALT_E_SUCCESS;
0413 }
0414 
0415 ALT_STATUS_CODE alt_dma_program_DMAKILL(ALT_DMA_PROGRAM_t * pgm)
0416 {
0417     // For information on DMAKILL, see PL330, section 4.3.6.
0418 
0419     // Check for sufficient space in buffer
0420     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0421     {
0422         return ALT_E_BUF_OVF;
0423     }
0424 
0425     // Buffer of where to assemble the instruction.
0426     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0427 
0428     // Assemble DMAKILL
0429     buffer[0] = 0x01;
0430 
0431     // Update the code size.
0432     pgm->code_size += 1;
0433 
0434     return ALT_E_SUCCESS;
0435 }
0436 
0437 ALT_STATUS_CODE alt_dma_program_DMALD(ALT_DMA_PROGRAM_t * pgm,
0438                                       ALT_DMA_PROGRAM_INST_MOD_t mod)
0439 {
0440     // For information on DMALD, see PL330, section 4.3.7.
0441 
0442     // Check for sufficient space in buffer
0443     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0444     {
0445         return ALT_E_BUF_OVF;
0446     }
0447 
0448     // Verify instruction modifier; construct bs, x mask value.
0449     uint8_t bsx_mask = 0;
0450     switch (mod)
0451     {
0452     case ALT_DMA_PROGRAM_INST_MOD_NONE:
0453         bsx_mask = 0x0;
0454         break;
0455     case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
0456         bsx_mask = 0x1;
0457         break;
0458     case ALT_DMA_PROGRAM_INST_MOD_BURST:
0459         bsx_mask = 0x3;
0460         break;
0461     default:
0462         return ALT_E_BAD_ARG;
0463     }
0464 
0465     // Buffer of where to assemble the instruction.
0466     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0467 
0468     // Assemble DMALD
0469     buffer[0] = 0x04 | bsx_mask;
0470 
0471     // Update the code size.
0472     pgm->code_size += 1;
0473 
0474     return ALT_E_SUCCESS;
0475 }
0476 
0477 ALT_STATUS_CODE alt_dma_program_DMALDP(ALT_DMA_PROGRAM_t * pgm,
0478                                        ALT_DMA_PROGRAM_INST_MOD_t mod, ALT_DMA_PERIPH_t periph)
0479 {
0480     // For information on DMALDP, see PL330, section 4.3.8.
0481 
0482     // Check for sufficient space in buffer
0483     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0484     {
0485         return ALT_E_BUF_OVF;
0486     }
0487 
0488     // Verify instruction modifier; construct bs mask value.
0489     uint8_t bs_mask = 0;
0490     switch (mod)
0491     {
0492     case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
0493         bs_mask = 0x0;
0494         break;
0495     case ALT_DMA_PROGRAM_INST_MOD_BURST:
0496         bs_mask = 0x2;
0497         break;
0498     default:
0499         return ALT_E_BAD_ARG;
0500     }
0501 
0502     // Verify valid peripheral identifier.
0503     if (periph > ((1 << 5) - 1))
0504     {
0505         return ALT_E_BAD_ARG;
0506     }
0507 
0508     // Buffer of where to assemble the instruction.
0509     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0510 
0511     // Assemble DMALDP
0512     buffer[0] = 0x25 | bs_mask;
0513     buffer[1] = (uint8_t)(periph) << 3;
0514 
0515     // Update the code size.
0516     pgm->code_size += 2;
0517 
0518     return ALT_E_SUCCESS;
0519 }
0520 
0521 ALT_STATUS_CODE alt_dma_program_DMALP(ALT_DMA_PROGRAM_t * pgm,
0522                                       uint32_t iterations)
0523 {
0524     // For information on DMALP, see PL330, section 4.3.9.
0525 
0526     // Check for sufficient space in buffer
0527     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0528     {
0529         return ALT_E_BUF_OVF;
0530     }
0531 
0532     // Verify iterations in range
0533     if ((iterations == 0) || (iterations > 256))
0534     {
0535         return ALT_E_BAD_ARG;
0536     }
0537 
0538     // Find suitable LOOPx register to use; construct lc mask value.
0539     uint8_t lc_mask = 0;
0540     switch (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)
0541     {
0542     case 0:                              // No LOOPx in use. Use LOOP0.
0543         pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP0;
0544         pgm->loop0 = pgm->code_size + 2; // This is the first instruction after the DMALP
0545         lc_mask = 0x0;
0546         break;
0547 
0548     case ALT_DMA_PROGRAM_FLAG_LOOP0:     // LOOP0 in use. Use LOOP1.
0549         pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP1;
0550         pgm->loop1 = pgm->code_size + 2; // This is the first instruction after the DMALP
0551         lc_mask = 0x2;
0552         break;
0553 
0554     case ALT_DMA_PROGRAM_FLAG_LOOP_ALL: // All LOOPx in use. Report error.
0555         return ALT_E_BAD_OPERATION;
0556 
0557     default:                            // Catastrophic error !!!
0558         return ALT_E_ERROR;
0559     }
0560 
0561     // Buffer of where to assemble the instruction.
0562     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0563 
0564     // Assemble DMALP
0565     buffer[0] = 0x20 | lc_mask;
0566     buffer[1] = (uint8_t)(iterations - 1);
0567 
0568     // Update the code size.
0569     pgm->code_size += 2;
0570 
0571     return ALT_E_SUCCESS;
0572 }
0573 
0574 ALT_STATUS_CODE alt_dma_program_DMALPEND(ALT_DMA_PROGRAM_t * pgm,
0575                                          ALT_DMA_PROGRAM_INST_MOD_t mod)
0576 {
0577     // For information on DMALPEND, see PL330, section 4.3.10.
0578 
0579     // Check for sufficient space in buffer
0580     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0581     {
0582         return ALT_E_BUF_OVF;
0583     }
0584 
0585     // Verify instruction modifier; construct bs, x mask value.
0586     uint8_t bsx_mask = 0;
0587     switch (mod)
0588     {
0589     case ALT_DMA_PROGRAM_INST_MOD_NONE:
0590         bsx_mask = 0x0;
0591         break;
0592     case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
0593         bsx_mask = 0x1;
0594         break;
0595     case ALT_DMA_PROGRAM_INST_MOD_BURST:
0596         bsx_mask = 0x3;
0597         break;
0598     default:
0599         return ALT_E_BAD_ARG;
0600     }
0601 
0602     // Determine the loop to end, if it is a forever loop; construct lc mask, nf mask, and backwards jump value.
0603     uint8_t lc_mask = 0;
0604     uint8_t nf_mask = 0;
0605     uint16_t backwards_jump = 0;
0606     switch (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)
0607     {
0608     case ALT_DMA_PROGRAM_FLAG_LOOP0:    // LOOP0 in use. End LOOP0.
0609 
0610         backwards_jump = pgm->code_size - pgm->loop0;
0611 
0612         pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP0;
0613         pgm->loop0 = 0;
0614 
0615         lc_mask = 0x0;
0616 
0617         if (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE)
0618         {
0619             pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE;
0620         }
0621         else
0622         {
0623             nf_mask = 0x10;
0624         }
0625         break;
0626 
0627     case ALT_DMA_PROGRAM_FLAG_LOOP_ALL: // All LOOPx in use. End LOOP1.
0628 
0629         backwards_jump = pgm->code_size - pgm->loop1;
0630 
0631         pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP1;
0632         pgm->loop1 = 0;
0633 
0634         lc_mask = 0x4;
0635 
0636         if (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE)
0637         {
0638             pgm->flag &= ~ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE;
0639         }
0640         else
0641         {
0642             nf_mask = 0x10;
0643         }
0644         break;
0645 
0646     case 0:                             // No LOOPx in use. Report error!
0647         return ALT_E_BAD_OPERATION;
0648 
0649     default:                            // Catastrophic error !!!
0650         return ALT_E_ERROR;
0651     }
0652 
0653     // Verify that the jump size is suitable
0654     if (backwards_jump > 255)
0655     {
0656         return ALT_E_ARG_RANGE;
0657     }
0658 
0659     // Buffer of where to assemble the instruction.
0660     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0661 
0662     // Assemble DMALPEND
0663     buffer[0] = 0x28 | nf_mask | lc_mask | bsx_mask;
0664     buffer[1] = (uint8_t)(backwards_jump);
0665 
0666     // Update the code size.
0667     pgm->code_size += 2;
0668 
0669     return ALT_E_SUCCESS;
0670 }
0671 
0672 ALT_STATUS_CODE alt_dma_program_DMALPFE(ALT_DMA_PROGRAM_t * pgm)
0673 {
0674     // For information on DMALPFE, see PL330, section 4.3.11.
0675 
0676     // Find suitable LOOPx register to use;
0677     switch (pgm->flag & ALT_DMA_PROGRAM_FLAG_LOOP_ALL)
0678     {
0679     case 0:                             // No LOOPx in use. Use LOOP0.
0680         pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP0;
0681         pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP0_IS_FE;
0682         pgm->loop0 = pgm->code_size;
0683         break;
0684 
0685     case ALT_DMA_PROGRAM_FLAG_LOOP0:    // LOOP0 in use. Use LOOP1.
0686         pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP1;
0687         pgm->flag |= ALT_DMA_PROGRAM_FLAG_LOOP1_IS_FE;
0688         pgm->loop1 = pgm->code_size;
0689         break;
0690 
0691     case ALT_DMA_PROGRAM_FLAG_LOOP_ALL: // All LOOPx in use. Report error.
0692         return ALT_E_BAD_OPERATION;
0693 
0694     default:                            // Catastrophic error !!!
0695         return ALT_E_ERROR;
0696     }
0697 
0698     // Nothing to assemble.
0699 
0700     return ALT_E_SUCCESS;
0701 }
0702 
0703 ALT_STATUS_CODE alt_dma_program_DMAMOV(ALT_DMA_PROGRAM_t * pgm,
0704                                        ALT_DMA_PROGRAM_REG_t chan_reg, uint32_t val)
0705 {
0706     // For information on DMAMOV, see PL330, section 4.3.12.
0707 
0708     // Check for sufficient space in buffer
0709     if ((pgm->code_size + 6) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0710     {
0711         return ALT_E_BUF_OVF;
0712     }
0713 
0714     // Verify channel register; construct rd mask value
0715     uint8_t rd_mask = 0;
0716     switch (chan_reg)
0717     {
0718     case ALT_DMA_PROGRAM_REG_SAR:
0719         rd_mask = 0;
0720         // If SAR has not been set before, mark the location of where SAR is in the buffer.
0721         if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_SAR))
0722         {
0723             pgm->flag |= ALT_DMA_PROGRAM_FLAG_SAR;
0724             pgm->sar = pgm->code_size + 2;
0725         }
0726         break;
0727 
0728     case ALT_DMA_PROGRAM_REG_CCR:
0729         rd_mask = 1;
0730         break;
0731 
0732     case ALT_DMA_PROGRAM_REG_DAR:
0733         rd_mask = 2;
0734         // If DAR has not been set before, mark the location of where DAR is in the buffer.
0735         if (!(pgm->flag & ALT_DMA_PROGRAM_FLAG_DAR))
0736         {
0737             pgm->flag |= ALT_DMA_PROGRAM_FLAG_DAR;
0738             pgm->dar = pgm->code_size + 2;
0739         }
0740         break;
0741 
0742     default:
0743         return ALT_E_BAD_ARG;
0744     }
0745 
0746     // Buffer of where to assemble the instruction.
0747     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0748 
0749     // Assemble DMAMOV
0750     buffer[0] = 0xbc;;
0751     buffer[1] = rd_mask;
0752     buffer[2] = (uint8_t)((val >>  0) & 0xff);
0753     buffer[3] = (uint8_t)((val >>  8) & 0xff);
0754     buffer[4] = (uint8_t)((val >> 16) & 0xff);
0755     buffer[5] = (uint8_t)((val >> 24) & 0xff);
0756 
0757     // Update the code size.
0758     pgm->code_size += 6;
0759 
0760     return ALT_E_SUCCESS;
0761 
0762 }
0763 
0764 ALT_STATUS_CODE alt_dma_program_DMANOP(ALT_DMA_PROGRAM_t * pgm)
0765 {
0766     // For information on DMANOP, see PL330, section 4.3.13.
0767 
0768     // Check for sufficient space in buffer
0769     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0770     {
0771         return ALT_E_BUF_OVF;
0772     }
0773 
0774     // Buffer of where to assemble the instruction.
0775     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0776 
0777     // Assemble DMANOP
0778     buffer[0] = 0x18;
0779 
0780     // Update the code size.
0781     pgm->code_size += 1;
0782 
0783     return ALT_E_SUCCESS;
0784 }
0785 
0786 ALT_STATUS_CODE alt_dma_program_DMARMB(ALT_DMA_PROGRAM_t * pgm)
0787 {
0788     // For information on DMARMB, see PL330, section 4.3.14.
0789 
0790     // Check for sufficient space in buffer
0791     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0792     {
0793         return ALT_E_BUF_OVF;
0794     }
0795 
0796     // Buffer of where to assemble the instruction.
0797     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0798 
0799     // Assemble DMARMB
0800     buffer[0] = 0x12;
0801 
0802     // Update the code size.
0803     pgm->code_size += 1;
0804 
0805     return ALT_E_SUCCESS;
0806 }
0807 
0808 ALT_STATUS_CODE alt_dma_program_DMASEV(ALT_DMA_PROGRAM_t * pgm,
0809                                        ALT_DMA_EVENT_t evt)
0810 {
0811     // For information on DMA, see PL330, section 4.3.15.
0812 
0813     // Check for sufficient space in buffer
0814     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0815     {
0816         return ALT_E_BUF_OVF;
0817     }
0818 
0819     // Validate evt selection
0820     switch (evt)
0821     {
0822     case ALT_DMA_EVENT_0:
0823     case ALT_DMA_EVENT_1:
0824     case ALT_DMA_EVENT_2:
0825     case ALT_DMA_EVENT_3:
0826     case ALT_DMA_EVENT_4:
0827     case ALT_DMA_EVENT_5:
0828     case ALT_DMA_EVENT_6:
0829     case ALT_DMA_EVENT_7:
0830     case ALT_DMA_EVENT_ABORT:
0831         break;
0832     default:
0833         return ALT_E_BAD_ARG;
0834     }
0835 
0836     // Buffer of where to assemble the instruction.
0837     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0838 
0839     // Assemble DMASEV
0840     buffer[0] = 0x34;
0841     buffer[1] = (uint8_t)(evt) << 3;
0842 
0843     // Update the code size.
0844     pgm->code_size += 2;
0845 
0846     return ALT_E_SUCCESS;
0847 }
0848 
0849 ALT_STATUS_CODE alt_dma_program_DMAST(ALT_DMA_PROGRAM_t * pgm,
0850                                       ALT_DMA_PROGRAM_INST_MOD_t mod)
0851 {
0852     // For information on DMAST, see PL330, section 4.3.16.
0853 
0854     // Check for sufficient space in buffer
0855     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0856     {
0857         return ALT_E_BUF_OVF;
0858     }
0859 
0860     // Verify instruction modifier; construct bs, x mask value.
0861     uint8_t bsx_mask = 0;
0862     switch (mod)
0863     {
0864     case ALT_DMA_PROGRAM_INST_MOD_NONE:
0865         bsx_mask = 0x0;
0866         break;
0867     case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
0868         bsx_mask = 0x1;
0869         break;
0870     case ALT_DMA_PROGRAM_INST_MOD_BURST:
0871         bsx_mask = 0x3;
0872         break;
0873     default:
0874         return ALT_E_BAD_ARG;
0875     }
0876 
0877     // Buffer of where to assemble the instruction.
0878     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0879 
0880     // Assemble DMAST
0881     buffer[0] = 0x08 | bsx_mask;
0882 
0883     // Update the code size.
0884     pgm->code_size += 1;
0885 
0886     return ALT_E_SUCCESS;
0887 }
0888 
0889 ALT_STATUS_CODE alt_dma_program_DMASTP(ALT_DMA_PROGRAM_t * pgm,
0890                                        ALT_DMA_PROGRAM_INST_MOD_t mod, ALT_DMA_PERIPH_t periph)
0891 {
0892     // For information on DMASTP, see PL330, section 4.3.17.
0893 
0894     // Check for sufficient space in buffer
0895     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0896     {
0897         return ALT_E_BUF_OVF;
0898     }
0899 
0900     // Verify instruction modifier; construct bs mask value.
0901     uint8_t bs_mask = 0;
0902     switch (mod)
0903     {
0904     case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
0905         bs_mask = 0x0;
0906         break;
0907     case ALT_DMA_PROGRAM_INST_MOD_BURST:
0908         bs_mask = 0x2;
0909         break;
0910     default:
0911         return ALT_E_BAD_ARG;
0912     }
0913 
0914     // Verify valid peripheral identifier.
0915     if (periph > ((1 << 5) - 1))
0916     {
0917         return ALT_E_BAD_ARG;
0918     }
0919 
0920     // Buffer of where to assemble the instruction.
0921     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0922 
0923     // Assemble DMASTP
0924     buffer[0] = 0x29 | bs_mask;
0925     buffer[1] = (uint8_t)(periph) << 3;
0926 
0927     // Update the code size.
0928     pgm->code_size += 2;
0929 
0930     return ALT_E_SUCCESS;
0931 }
0932 
0933 ALT_STATUS_CODE alt_dma_program_DMASTZ(ALT_DMA_PROGRAM_t * pgm)
0934 {
0935     // For information on DMASTZ, see PL330, section 4.3.18.
0936 
0937     // Check for sufficient space in buffer
0938     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0939     {
0940         return ALT_E_BUF_OVF;
0941     }
0942 
0943     // Buffer of where to assemble the instruction.
0944     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0945 
0946     // Assemble DMASTZ
0947     buffer[0] = 0x0c;
0948 
0949     // Update the code size.
0950     pgm->code_size += 1;
0951 
0952     return ALT_E_SUCCESS;
0953 }
0954 
0955 ALT_STATUS_CODE alt_dma_program_DMAWFE(ALT_DMA_PROGRAM_t * pgm,
0956                                        ALT_DMA_EVENT_t evt, bool invalid)
0957 {
0958     // For information on DMAWFE, see PL330, section 4.3.19.
0959 
0960     // Check for sufficient space in buffer
0961     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
0962     {
0963         return ALT_E_BUF_OVF;
0964     }
0965 
0966     // Validate evt selection
0967     switch (evt)
0968     {
0969     case ALT_DMA_EVENT_0:
0970     case ALT_DMA_EVENT_1:
0971     case ALT_DMA_EVENT_2:
0972     case ALT_DMA_EVENT_3:
0973     case ALT_DMA_EVENT_4:
0974     case ALT_DMA_EVENT_5:
0975     case ALT_DMA_EVENT_6:
0976     case ALT_DMA_EVENT_7:
0977     case ALT_DMA_EVENT_ABORT:
0978         break;
0979     default:
0980         return ALT_E_BAD_ARG;
0981     }
0982 
0983     // Construct i mask value
0984     uint8_t i_mask = 0;
0985     if (invalid)
0986     {
0987         i_mask = 0x2;
0988     }
0989 
0990     // Buffer of where to assemble the instruction.
0991     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
0992 
0993     // Assemble DMAWFE
0994     buffer[0] = 0x36;
0995     buffer[1] = ((uint8_t)(evt) << 3) | i_mask;
0996 
0997     // Update the code size.
0998     pgm->code_size += 2;
0999 
1000     return ALT_E_SUCCESS;
1001 }
1002 
1003 ALT_STATUS_CODE alt_dma_program_DMAWFP(ALT_DMA_PROGRAM_t * pgm,
1004                                        ALT_DMA_PERIPH_t periph, ALT_DMA_PROGRAM_INST_MOD_t mod)
1005 {
1006     // For information on DMAWFP, see PL330, section 4.3.20.
1007 
1008     // Check for sufficient space in buffer
1009     if ((pgm->code_size + 2) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
1010     {
1011         return ALT_E_BUF_OVF;
1012     }
1013 
1014     // Verify valid peripheral identifier.
1015     if (periph > ((1 << 5) - 1))
1016     {
1017         return ALT_E_BAD_ARG;
1018     }
1019 
1020     // Verify instruction modifier; construct bs, p mask value.
1021     uint8_t bsp_mask = 0;
1022     switch (mod)
1023     {
1024     case ALT_DMA_PROGRAM_INST_MOD_SINGLE:
1025         bsp_mask = 0x0;
1026         break;
1027     case ALT_DMA_PROGRAM_INST_MOD_BURST:
1028         bsp_mask = 0x2;
1029         break;
1030     case ALT_DMA_PROGRAM_INST_MOD_PERIPH:
1031         bsp_mask = 0x1;
1032         break;
1033     default:
1034         return ALT_E_BAD_ARG;
1035     }
1036 
1037     // Buffer of where to assemble the instruction.
1038     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
1039 
1040     // Assemble DMAWFP
1041     buffer[0] = 0x30 | bsp_mask;
1042     buffer[1] = (uint8_t)(periph) << 3;
1043 
1044     // Update the code size.
1045     pgm->code_size += 2;
1046 
1047     return ALT_E_SUCCESS;
1048 }
1049 
1050 ALT_STATUS_CODE alt_dma_program_DMAWMB(ALT_DMA_PROGRAM_t * pgm)
1051 {
1052     // For information on DMAWMB, see PL330, section 4.3.21.
1053 
1054     // Check for sufficient space in buffer
1055     if ((pgm->code_size + 1) > ALT_DMA_PROGRAM_PROVISION_BUFFER_SIZE)
1056     {
1057         return ALT_E_BUF_OVF;
1058     }
1059 
1060     // Buffer of where to assemble the instruction.
1061     uint8_t * buffer = pgm->program + pgm->buffer_start + pgm->code_size;
1062 
1063     // Assemble DMAWMB
1064     buffer[0] = 0x13;
1065 
1066     // Update the code size.
1067     pgm->code_size += 1;
1068 
1069     return ALT_E_SUCCESS;
1070 }