I am woking with Microsemi Polarfire Splashkit evaluation board (Microchip's Polarfire MPF300T FPGA on board). My project has Mi-V RV32 Softcore processor (RISC-V ISA) and I am writing firmware for it. I set 256kB TCM as a memory for exeсutable program.
When my programm's size is small it's all fine. Program compiled and executed in debug mode as expected. However if text + data sections of .elf exceed 64 kB then .elf builded but program doesn't work. Main program even doesn't loaded in debug mode. I realized that launched code has some odd arbitrary instructions in reset vector instead of boot code miv_rv32_entry.S from miv_rv32_hal. What's wrong?
On Libero SoC's side (Libero SoC v2021.1) I am using Mi-V RV32 3.0.100, IMC RISC-V extension. TCM is on, TCM APB slave (TAS) is off, TCM has address range 0x80000000 - 0x8003ffff. Reset vector is set to 0x80000000 also.
For making firmware I am using SoftConsole v2021.1. HAL is MIV_RV32 HAL version 3.0.109. In Properties->Target Processor pane Multiply and Compressed Extensions are on, align set to strict. -O0 optimization was choosen and "use newlib-nano" is off.
For Linker Script I took miv-rv32-ram.ld from miv_rv32_hal and changed it to:
OUTPUT_ARCH( "riscv" )
ENTRY(_start)
MEMORY
{
ram (rwx) : ORIGIN = 0x80000000, LENGTH = 256k
}
RAM_START_ADDRESS = 0x80000000; /* Must be the same value MEMORY region ram ORIGIN above. */
RAM_SIZE = 256k; /* Must be the same value MEMORY region ram LENGTH above. */
STACK_SIZE = 8k; /* needs to be calculated for your application */
HEAP_SIZE = 8k; /* needs to be calculated for your application */
SECTIONS
{
.entry : ALIGN(0x10)
{
KEEP (*(SORT_NONE(.entry)))
. = ALIGN(0x10);
} > ram
.text : ALIGN(0x10)
{
*(.text .text.* .gnu.linkonce.t.*)
*(.plt)
. = ALIGN(0x10);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.gcc_except_table)
*(.eh_frame_hdr)
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(0x10);
} > ram
/* short/global data section */
.sdata : ALIGN(0x10)
{
__sdata_load = LOADADDR(.sdata);
__sdata_start = .;
PROVIDE( __global_pointer$ = . + 0x800);
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2)
*(.srodata*)
*(.sdata .sdata.* .gnu.linkonce.s.*)
. = ALIGN(0x10);
__sdata_end = .;
} > ram
/* data section */
.data : ALIGN(0x10)
{
__data_load = LOADADDR(.data);
__data_start = .;
*(.got.plt) *(.got)
*(.shdata)
*(.data .data.* .gnu.linkonce.d.*)
. = ALIGN(0x10);
__data_end = .;
} > ram
/* sbss section */
.sbss : ALIGN(0x10)
{
__sbss_start = .;
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
. = ALIGN(0x10);
__sbss_end = .;
} > ram
/* sbss section */
.bss : ALIGN(0x10)
{
__bss_start = .;
*(.shbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(0x10);
__bss_end = .;
} > ram
/* End of uninitialized data segment */
_end = .;
.heap : ALIGN(0x10)
{
__heap_start = .;
. += HEAP_SIZE;
__heap_end = .;
. = ALIGN(0x10);
_heap_end = __heap_end;
} > ram
.stack : ALIGN(0x10)
{
__stack_bottom = .;
. += STACK_SIZE;
__stack_top = .;
} > ram
}
Remaining part of linker script was unchanged. .map and .lst files seem ok, boot code has right place according to it.
I discovered that content of TCM memory differs from builded .hex file using SmartDebug. So, I think that problem is not in linker-script (not only, at least). Then I tried to boot from external SPI-flash (may be problem that binary loaded in debug mode). But result is the same (although memory content differs in different way for that case). If firmware is small then .hex content and loaded in TCM data match. Very strange situation. Why could it be?