| // Copyright lowRISC contributors. | 
 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 |  | 
 | /** | 
 |  * CRT library | 
 |  * | 
 |  * Utility functions written in assembly that can be used before the C | 
 |  * runtime has been initialized. These functions should not be used once | 
 |  * the C runtime has been initialized. | 
 |  * | 
 |  * The name of this library is historical. In many toolchains, a file called | 
 |  * "crt0.o" is linked into each executable, which does something similar to | 
 |  * what these functions  | 
 |  */ | 
 |  | 
 |   // NOTE: The "ax" flag below is necessary to ensure that this section | 
 |   // is allocated space in ROM by the linker. | 
 |   .section .crt, "ax", @progbits | 
 |  | 
 |   /** | 
 |    * Write zeros into the section bounded by the start and end pointers. | 
 |    * The section must be word (4 byte) aligned. It is valid for the section | 
 |    * to have a length of 0 (i.e. the start and end pointers may be equal). | 
 |    * | 
 |    * This function follows the standard ILP32 calling convention for arguments | 
 |    * but does not require a valid stack pointer, thread pointer or global | 
 |    * pointer. | 
 |    * | 
 |    * Clobbers a0 and t0. | 
 |    * | 
 |    * @param a0 pointer to start of section to clear (inclusive). | 
 |    * @param a1 pointer to end of section to clear (exclusive). | 
 |    */ | 
 |   .balign 4 | 
 |   .global crt_section_clear | 
 |   .type crt_section_clear, @function | 
 | crt_section_clear: | 
 |  | 
 |   // Check that start is before end. | 
 |   bgeu a0, a1, .L_clear_nothing | 
 |  | 
 |   // Check that start and end are word aligned. | 
 |   or   t0, a0, a1 | 
 |   andi t0, t0, 0x3 | 
 |   bnez t0, .L_clear_error | 
 |  | 
 | .L_clear_loop: | 
 |   // Write zero into section memory word-by-word. | 
 |   // TODO: unroll | 
 |   sw   zero, 0(a0) | 
 |   addi a0, a0, 4 | 
 |   bltu a0, a1, .L_clear_loop | 
 |   ret | 
 |  | 
 | .L_clear_nothing: | 
 |   // If section length is 0 just return. Otherwise end is before start | 
 |   // which is invalid so trigger an error. | 
 |   bne a0, a1, .L_clear_error | 
 |   ret | 
 |  | 
 | .L_clear_error: | 
 |   unimp | 
 |  | 
 |   // Set function size to allow disassembly. | 
 |   .size crt_section_clear, .-crt_section_clear | 
 |  | 
 | // ----------------------------------------------------------------------------- | 
 |  | 
 |   /** | 
 |    * Copy data from the given source into the section bounded by the start and | 
 |    * end pointers. Both the section and the source must be word (4 byte) aligned. | 
 |    * It is valid for the section to have a length of 0 (i.e. the start and end | 
 |    * pointers may be equal). The source is assumed to have the same length as the | 
 |    * target section. | 
 |    * | 
 |    * The destination section and the source must not overlap. | 
 |    * | 
 |    * This function follows the standard ILP32 calling convention for arguments | 
 |    * but does not require a valid stack pointer, thread pointer or global | 
 |    * pointer. | 
 |    * | 
 |    * Clobbers a0, a2, t0 and t1. | 
 |    * | 
 |    * @param a0 pointer to start of destination section (inclusive). | 
 |    * @param a1 pointer to end of destination section (exclusive). | 
 |    * @param a2 pointer to source data (inclusive). | 
 |    */ | 
 |   .balign 4 | 
 |   .global crt_section_copy | 
 |   .type crt_section_copy, @function | 
 | crt_section_copy: | 
 |  | 
 |   // Check that start is before end. | 
 |   bgeu a0, a1, .L_copy_nothing | 
 |  | 
 |   // Check that start, end and src are word aligned. | 
 |   or   t0, a0, a1 | 
 |   or   t0, t0, a2 | 
 |   andi t0, t0, 0x3 | 
 |   bnez t0, .L_copy_error | 
 |  | 
 |   // Check that source does not destructively overlap destination | 
 |   // (assuming a forwards copy). | 
 |   // | 
 |   // src  start          end | 
 |   //  |     |             | | 
 |   //  +-------------+     | | 
 |   //  |   source    |     | | 
 |   //  +-------------+     | | 
 |   //        +-------------+ | 
 |   //        | destination | | 
 |   //        +-------------+ | 
 |   //        |             | | 
 |   //      start          end | 
 |   // | 
 |   // TODO: disallow all overlap since it indicates API misuse? | 
 |   sub  t0, a0, a2           // (start - src) mod 2**32 | 
 |   sub  t1, a1, a0           // end - start | 
 |   bltu t0, t1, .L_copy_error | 
 |  | 
 | .L_copy_loop: | 
 |   // Copy data from src into section word-by-word. | 
 |   // TODO: unroll | 
 |   lw   t0, 0(a2) | 
 |   addi a2, a2, 4 | 
 |   sw   t0, 0(a0) | 
 |   addi a0, a0, 4 | 
 |   bltu a0, a1, .L_copy_loop | 
 |   ret | 
 |  | 
 | .L_copy_nothing: | 
 |   // If section length is 0 just return. Otherwise end is before start | 
 |   // which is invalid so trigger an error. | 
 |   bne a0, a1, .L_copy_error | 
 |   ret | 
 |  | 
 | .L_copy_error: | 
 |   unimp | 
 |   .size crt_section_copy, .-crt_section_copy |