Problem with SBRK not returning from call on bare metal risk

Damien Towning <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <CANJyiQUbAPaPoWHxbCSdAb6JBWfJWfVVnu50U0k+rat2CBPnvg@mail.gmail.com>
So a bit of a background. I have the bonfire Risc-V 32 core running on a
T-35 FPGA board. The metal part of this is working great. The processor
runs. I've got it to turn around the segment display on the board. I've
also implemented my own _sbrk and got that to work I think consistently
with malloc. Now in my Risc-v 32 toolchain I have the newlib and I have
brought that in and with my own wrapped _sbrk I am able to use the system
defined malloc. But I am not entirely happy with this because I don't want
to be wrapping every function I encounter. So for example today I found
myself wrapping srand and rand. So I am pretty sure the reason my
nano_newlib isn't working is something to do with either not having the
correct variable names in my firmware.ld or something to do with disabling
the re-entrant behaviour of newlib. I've included in this email my
firmware.ld,platform.h,c code example. What happens is I call the _sbrk(0)
and ( in the simulator I am also running this in ) I never see a bad opcode
generated. It just seems like the processor goes away and never comes back.
Does anybody have any suggestions as to what might cause this sort of
problem ? I'd like to use the sbrk and other funcitons within the newlib
itself if possible without rolling my own.

------------- firmware.ld
MEMORY
{

   RAM (rwx)    : ORIGIN = 0x0C000000, LENGTH = 512K
}

ENTRY(_start)

SECTIONS
{
    _rombase = 0x0C000000;

  . = 0x0;

  .text : {
    *(.init)
    *(.text.*)

  } > RAM

  .data  ALIGN(4) : {
    *(.rodata.*)
    *(.rodata)
    *(.eh_frame)
    *(.sdata)
    *(.data)
    *(.sbss)
    *(.sbss.*)
    *(.gnu.linkonce.sb.*)
    *(.bss)
    *(.bss.*)
    *(.gnu.linkonce.b.*)
    *(COMMON)

    end = .; _end = .; __end = .;

 } > RAM

 _heap_end = _end;
 _heap_prev_end = _end;

}

PROVIDE(__heap_end = _end);
PROVIDE(__prev_heap_end = _end);
PROVIDE(__heap_start = _end+128K);

PROVIDE(__stack_top   = ORIGIN(RAM) + LENGTH(RAM));
PROVIDE(__stack_start = ORIGIN(RAM) + LENGTH(RAM));

PROVIDE(__heap_size = 128K );
PROVIDE(__stack_size = 128K );



/*
0x0C000000 +-------------------+
           |                   |
           |     ROM / Flash   |
0x0C080000 +-------------------+
           |                   |
           |      .data        |
           |-------------------|
           |     .bss / .sbss  |
           |-------------------|
           |        _end       |
           |-------------------|
           |        Heap       |
           |-------------------|
           |        Stack      |
0xXXXXXXXX +-------------------+
*/
--------------------------------------------------------------------------------------

---------platform.h
----------------------------------------------------------------
#ifndef BASIC_PLATFORM_H
#define BASIC_PLATFORM_H

// New Defintions for new bonfire-soc-io core
#define IO_BASE 0x04000000
#define SOC_IO_OFFSET 0x10000 // Offset from one I/O Device to the next
(64K range)

#define UART0_BASE IO_BASE
#define SPIFLASH_BASE (IO_BASE+SOC_IO_OFFSET)
#define GPIO_BASE (IO_BASE+3*SOC_IO_OFFSET)
#define UART1_BASE (IO_BASE+2*SOC_IO_OFFSET)

#define UART_BASE UART0_BASE // Backwards compatiblity

#define MTIME_BASE 0x0FFFF0000

#define DRAM_BASE 0x0
#define DRAM_SIZE 0
#define DRAM_TOP  (DRAM_BASE+DRAM_SIZE-1)
#define SRAM_BASE 0x0C000000
#define SRAM_SIZE 524288
#define SRAM_TOP  (SRAM_BASE+SRAM_SIZE-1)

//#define SYSCLK 12000000
//#define SYSCLK   33333333
//#define   SYSCLK   24997500
//#define   SYSCLK   88786000
#define     EXT_SYSCLK   89015000

#define SYSCLK       24997500

//#define EXT_SYSCLK   92370000  /* For reasons not clear to me when any
change is made to the interface   */
  /* configuration in Efinity and a new synthesis is done a clock time will
*/
  /* be calculated so you must build your efinity project. Take that new
 */
  /* time value. Update it here. Rebuild your hex file. Then rebuild your
*/
  /* efinity project AGAIN
 */


#define TIME_UNIT 1e+9;  // A billion

#ifndef SIMULATOR
#define SCALAR 1      // Relative Scalar division for efinity build
#define BAUD_SCALAR 1 // Relative Scalar division for efinity build
#else
#define SCALAR 10000    // Relative Scalar division for simulator. Use for
any of your own timing since
#define BAUD_SCALAR 20 // simulator runs slower than real hardware
#endif

#define CLK_PERIOD (TIME_UNIT / EXT_SYSCLK)  // in ns...

//#define DCACHE_SIZE 0 // (2048*4)  // DCache Size in Bytes

// Parameters for SPI Flash

#define FLASHSIZE (8192*1024)
#define MAX_FLASH_IMAGESIZE (2024*1024) // Max 2MB of flash used for boot
image
#define FLASH_IMAGEBASE (1024*3072)  // Boot Image starts at 3MB in Flash

#define PLATFORM_BAUDRATE (115200*BAUD_SCALAR)

#define NO_RECURSION
#define NO_SYSCALL
#define NO_FLASH
#define NO_XMODEM
#define NO_DRAMTEST

//#define GPIO_TEST

#endif
---------------------------------------------------------------------------------------------

---- sim_hello.c
------------------------------------------------------------------------
// ==============================================
// T35 S100 Module Test Code
// Damien Towning - 2022
// ==============================================
#include <stdioSo a bit of a background. I have the bonfire Risc-V 32 core
running on a T-35 FPGA board. The metal part of this is working great. The
processor runs. I've got it to turn around the segment display on the
board. I've also implemented my own _sbrk and got that to work I think
consistently with malloc. Now in my Risc-v 32 toolchain I have the newlib
and I have brought that in and with my own wrapped _sbrk I am able to use
the system defined malloc. But I am not entirely happy with this because I
don't want to be wrapping every function I encounter. So for example today
I found myself wrapping srand and rand. So I am pretty sure the reason my
nano_newlib isn't working is something to do with either not having the
correct variable names in my firmware.ld or something to do with disabling
the re-entrant behaviour of newlib. I've included in this email my
firmware.ld,platform.h,c code example. What happens is I call the _sbrk(0)
and ( in the simulator I am also running this in ) I never see a bad opcode
generated. It just seems like the processor goes away and never comes back.
Does anybody have any suggestions as to what might cause this sort of
problem ? I'd like to use the sbrk and other funcitons within the newlib
itself if possible without rolling my own.

------------- firmware.ld
MEMORY
{

   RAM (rwx)    : ORIGIN = 0x0C000000, LENGTH = 512K
}

ENTRY(_start)

SECTIONS
{
    _rombase = 0x0C000000;

  . = 0x0;

  .text : {
    *(.init)
    *(.text.*)

  } > RAM

  .data  ALIGN(4) : {
    *(.rodata.*)
    *(.rodata)
    *(.eh_frame)
    *(.sdata)
    *(.data)
    *(.sbss)
    *(.sbss.*)
    *(.gnu.linkonce.sb.*)
    *(.bss)
    *(.bss.*)
    *(.gnu.linkonce.b.*)
    *(COMMON)

    end = .; _end = .; __end = .;

 } > RAM

 _heap_end = _end;
 _heap_prev_end = _end;

}

PROVIDE(__heap_end = _end);
PROVIDE(__prev_heap_end = _end);
PROVIDE(__heap_start = _end+128K);

PROVIDE(__stack_top   = ORIGIN(RAM) + LENGTH(RAM));
PROVIDE(__stack_start = ORIGIN(RAM) + LENGTH(RAM));

PROVIDE(__heap_size = 128K );
PROVIDE(__stack_size = 128K );



/*
0x0C000000 +-------------------+
           |                   |
           |     ROM / Flash   |
0x0C080000 +-------------------+
           |                   |
           |      .data        |
           |-------------------|
           |     .bss / .sbss  |
           |-------------------|
           |        _end       |
           |-------------------|
           |        Heap       |
           |-------------------|
           |        Stack      |
0xXXXXXXXX +-------------------+
*/
--------------------------------------------------------------------------------------

---------platform.h
----------------------------------------------------------------
#ifndef BASIC_PLATFORM_H
#define BASIC_PLATFORM_H

// New Defintions for new bonfire-soc-io core
#define IO_BASE 0x04000000
#define SOC_IO_OFFSET 0x10000 // Offset from one I/O Device to the next
(64K range)

#define UART0_BASE IO_BASE
#define SPIFLASH_BASE (IO_BASE+SOC_IO_OFFSET)
#define GPIO_BASE (IO_BASE+3*SOC_IO_OFFSET)
#define UART1_BASE (IO_BASE+2*SOC_IO_OFFSET)

#define UART_BASE UART0_BASE // Backwards compatiblity

#define MTIME_BASE 0x0FFFF0000

#define DRAM_BASE 0x0
#define DRAM_SIZE 0
#define DRAM_TOP  (DRAM_BASE+DRAM_SIZE-1)
#define SRAM_BASE 0x0C000000
#define SRAM_SIZE 524288
#define SRAM_TOP  (SRAM_BASE+SRAM_SIZE-1)

//#define SYSCLK 12000000
//#define SYSCLK   33333333
//#define   SYSCLK   24997500
//#define   SYSCLK   88786000
#define     EXT_SYSCLK   89015000

#define SYSCLK       24997500

//#define EXT_SYSCLK   92370000  /* For reasons not clear to me when any
change is made to the interface   */
  /* configuration in Efinity and a new synthesis is done a clock time will
*/
  /* be calculated so you must build your efinity project. Take that new
 */
  /* time value. Update it here. Rebuild your hex file. Then rebuild your
*/
  /* efinity project AGAIN
 */


#define TIME_UNIT 1e+9;  // A billion

#ifndef SIMULATOR
#define SCALAR 1      // Relative Scalar division for efinity build
#define BAUD_SCALAR 1 // Relative Scalar division for efinity build
#else
#define SCALAR 10000    // Relative Scalar division for simulator. Use for
any of your own timing since
#define BAUD_SCALAR 20 // simulator runs slower than real hardware
#endif

#define CLK_PERIOD (TIME_UNIT / EXT_SYSCLK)  // in ns...

//#define DCACHE_SIZE 0 // (2048*4)  // DCache Size in Bytes

// Parameters for SPI Flash

#define FLASHSIZE (8192*1024)
#define MAX_FLASH_IMAGESIZE (2024*1024) // Max 2MB of flash used for boot
image
#define FLASH_IMAGEBASE (1024*3072)  // Boot Image starts at 3MB in Flash

#define PLATFORM_BAUDRATE (115200*BAUD_SCALAR)

#define NO_RECURSION
#define NO_SYSCALL
#define NO_FLASH
#define NO_XMODEM
#define NO_DRAMTEST

//#define GPIO_TEST

#endif
---------------------------------------------------------------------------------------------

---- sim_hello.c
------------------------------------------------------------------------
// ==============================================
// T35 S100 Module Test Code
// Damien Towning - 2022
// ==============================================
#include <stdio.h>
#include <stdlib.h>

//#include <newlib.h>
//#include <nano_malloc.h>
#include <errno.h>
#include <sys/types.h>
#include <string.h>
#include "bonfire.h"
#include "uart.h"
#include "bonfire_gpio.h"
#include "mem_rw.h"
#include "console.h"

extern void* sbrk(incr);


// ========================================
// Main function
// ========================================
int main() {

  setBaudRate(PLATFORM_BAUDRATE);

  caddr_t *ptr = sbrk(0);
  // code never returns from sbrk
  if (ptr == (void *)-1) {
    printk("Failed to allocate memory\r\n");
  }
  else {
    printk("Allocated memory at : %p\r\n", (void *) &ptr);
  }
  return 0;
}
------------------------------------------------------------------------------------
--- Makefile
--------------------------------------------------------------------

.PHONY: all clean

ARCH ?= rv32ia
ABI=ilp32
PLATFORM ?= S100_T35

#TARGET_PREFIX ?= riscv32-unknown-linux-gnu
TARGET_PREFIX ?= riscv32-unknown-elf
TARGET_CC := $(TARGET_PREFIX)-gcc
TARGET_LD := $(TARGET_PREFIX)-gcc
TARGET_SIZE := $(TARGET_PREFIX)-size
TARGET_OBJCOPY := $(TARGET_PREFIX)-objcopy
HEXDUMP ?= hexdump
DATA2MEM = /opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/data2mem

#PROJROOT = ../../..
#TOPLEVEL = ~/riscv/ise/bonfire/papilio_pro_dram_toplevel.bit
PLATFORMDIR=../platform

LINKDEF?=$(PLATFORMDIR)/$(PLATFORM)/firmware.ld

TARGET_CFLAGS +=  -march=$(ARCH) -mabi=$(ABI) -Wall -Os -g
 -fomit-frame-pointer \
-ffreestanding -fno-builtin  \
-Wall -Werror=implicit-function-declaration \
-D$(PLATFORM)

ifeq ($(SIMULATOR), 1)
  TARGET_CFLAGS+=-DSIMULATOR
endif

TARGET_CFLAGS+=-I$(PLATFORMDIR) -I$(PLATFORMDIR)/$(PLATFORM) -I../riscv

# If we wish to build with no newlib
#TARGET_LDFLAGS += -march=$(ARCH) -mabi=$(ABI) -nostartfiles   \
-Wl,-m,elf32lriscv,--wrap=malloc,--wrap=sbrk --specs=nosys.specs
-Wl,-T$(LINKDEF) \
-Wl,--gc-sections

TARGET_LDFLAGS += -march=$(ARCH) -mabi=$(ABI) -nostartfiles   \
-Wl,-m,elf32lriscv,--wrap=_srand,--wrap=_rand  --specs=nano.specs
-Wl,-Map=output.map,-T$(LINKDEF) \
-Wl,--gc-sections

all: sim_hello.hex memtest.hex nanotest.hex

%.o : %.S
$(TARGET_CC) $(TARGET_CFLAGS)  -c $<

%.o : %.c
$(TARGET_CC) $(TARGET_CFLAGS) -c $<

%.hex : %.elf
$(TARGET_OBJCOPY) -S -O binary  $< $(basename $@).bin
$(HEXDUMP) -v -e '1/4 "%08x\n"' $(basename $@).bin >$@
$(TARGET_PREFIX)-objdump -S -d $< >$(basename $@).lst
#$(TARGET_PREFIX)-objdump -D $< >$(basename $@).S
$(TARGET_PREFIX)-objdump -s $< >$(basename $@).dmp
$(TARGET_PREFIX)-size  $<

#sbrk.o: libwrap/sbrk.c
# $(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c libwrap/sbrk.c

rand.o: libwrap/rand.c
$(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c libwrap/rand.c

uart.o: uart.c
$(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c uart.c

#sim_hello.o : sim_hello.c
# $(TARGET_CC) $(TARGET_CFLAGS) -DSIM  -c sim_hello.c

sim_hello.elf: start.o uart.o sim_hello.o snprintf.o console.o rand.o
$(TARGET_LD) -o $@ $(TARGET_LDFLAGS) start.o uart.o sim_hello.o snprintf.o
console.o rand.o

#memtest.elf: start.o uart.o memtest.o snprintf.o console.o mempattern.o
sbrk.o
# $(TARGET_LD) -o $@ $(TARGET_LDFLAGS) start.o uart.o memtest.o snprintf.o
console.o mempattern.o sbrk.o

#nanotest.elf: start.o uart.o nanotest.o snprintf.o console.o mempattern.o
sbrk.o
# $(TARGET_LD) -o $@ $(TARGET_LDFLAGS) start.o uart.o nanotest.o snprintf.o
console.o mempattern.o sbrk.o

#jump0.elf : jump0.S
# $(TARGET_LD) -o $@ -march=RV32IM -nostartfiles   -Wl,-T$(BOOTLINK) $<

clean:
rm -f *.o
---------------------------------------------------------------------------------------------.h>
#include <stdlib.h>

//#include <newlib.h>
//#include <nano_malloc.h>
#include <errno.h>
#include <sys/types.h>
#include <string.h>
#include "bonfire.h"
#include "uart.h"
#include "bonfire_gpio.h"
#include "mem_rw.h"
#include "console.h"

extern void* sbrk(incr);


// ========================================
// Main function
// ========================================
int main() {

  setBaudRate(PLATFORM_BAUDRATE);

  caddr_t *ptr = sbrk(0);
  // code never returns from sbrk
  if (ptr == (void *)-1) {
    printk("Failed to allocate memory\r\n");
  }
  else {
    printk("Allocated memory at : %p\r\n", (void *) &ptr);
  }
  return 0;
}
------------------------------------------------------------------------------------
--- Makefile
--------------------------------------------------------------------

.PHONY: all clean

ARCH ?= rv32ia
ABI=ilp32
PLATFORM ?= S100_T35

#TARGET_PREFIX ?= riscv32-unknown-linux-gnu
TARGET_PREFIX ?= riscv32-unknown-elf
TARGET_CC := $(TARGET_PREFIX)-gcc
TARGET_LD := $(TARGET_PREFIX)-gcc
TARGET_SIZE := $(TARGET_PREFIX)-size
TARGET_OBJCOPY := $(TARGET_PREFIX)-objcopy
HEXDUMP ?= hexdump
DATA2MEM = /opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/data2mem

#PROJROOT = ../../..
#TOPLEVEL = ~/riscv/ise/bonfire/papilio_pro_dram_toplevel.bit
PLATFORMDIR=../platform

LINKDEF?=$(PLATFORMDIR)/$(PLATFORM)/firmware.ld

TARGET_CFLAGS +=  -march=$(ARCH) -mabi=$(ABI) -Wall -Os -g
 -fomit-frame-pointer \
-ffreestanding -fno-builtin  \
-Wall -Werror=implicit-function-declaration \
-D$(PLATFORM)

ifeq ($(SIMULATOR), 1)
  TARGET_CFLAGS+=-DSIMULATOR
endif

TARGET_CFLAGS+=-I$(PLATFORMDIR) -I$(PLATFORMDIR)/$(PLATFORM) -I../riscv

# If we wish to build with no newlib
#TARGET_LDFLAGS += -march=$(ARCH) -mabi=$(ABI) -nostartfiles   \
-Wl,-m,elf32lriscv,--wrap=malloc,--wrap=sbrk --specs=nosys.specs
-Wl,-T$(LINKDEF) \
-Wl,--gc-sections

TARGET_LDFLAGS += -march=$(ARCH) -mabi=$(ABI) -nostartfiles   \
-Wl,-m,elf32lriscv,--wrap=_srand,--wrap=_rand  --specs=nano.specs
-Wl,-Map=output.map,-T$(LINKDEF) \
-Wl,--gc-sections

all: sim_hello.hex memtest.hex nanotest.hex

%.o : %.S
$(TARGET_CC) $(TARGET_CFLAGS)  -c $<

%.o : %.c
$(TARGET_CC) $(TARGET_CFLAGS) -c $<

%.hex : %.elf
$(TARGET_OBJCOPY) -S -O binary  $< $(basename $@).bin
$(HEXDUMP) -v -e '1/4 "%08x\n"' $(basename $@).bin >$@
$(TARGET_PREFIX)-objdump -S -d $< >$(basename $@).lst
#$(TARGET_PREFIX)-objdump -D $< >$(basename $@).S
$(TARGET_PREFIX)-objdump -s $< >$(basename $@).dmp
$(TARGET_PREFIX)-size  $<

#sbrk.o: libwrap/sbrk.c
# $(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c libwrap/sbrk.c

rand.o: libwrap/rand.c
$(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c libwrap/rand.c

uart.o: uart.c
$(TARGET_CC) $(TARGET_CFLAGS) -DSIM -c uart.c

#sim_hello.o : sim_hello.c
# $(TARGET_CC) $(TARGET_CFLAGS) -DSIM  -c sim_hello.c

sim_hello.elf: start.o uart.o sim_hello.o snprintf.o console.o rand.o
$(TARGET_LD) -o $@ $(TARGET_LDFLAGS) start.o uart.o sim_hello.o snprintf.o
console.o rand.o

#memtest.elf: start.o uart.o memtest.o snprintf.o console.o mempattern.o
sbrk.o
# $(TARGET_LD) -o $@ $(TARGET_LDFLAGS) start.o uart.o memtest.o snprintf.o
console.o mempattern.o sbrk.o

#nanotest.elf: start.o uart.o nanotest.o snprintf.o console.o mempattern.o
sbrk.o
# $(TARGET_LD) -o $@ $(TARGET_LDFLAGS) start.o uart.o nanotest.o snprintf.o
console.o mempattern.o sbrk.o

#jump0.elf : jump0.S
# $(TARGET_LD) -o $@ -march=RV32IM -nostartfiles   -Wl,-T$(BOOTLINK) $<

clean:
rm -f *.o
---------------------------------------------------------------------------------------------

-- 
Damien Towning
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.