diff --git a/Makefile.am b/Makefile.am index 11bcb571..0166e282 100644 --- a/Makefile.am +++ b/Makefile.am @@ -78,6 +78,7 @@ nobase_include_HEADERS += \ metal/io.h \ metal/itim.h \ metal/led.h \ + metal/lim.h \ metal/lock.h \ metal/memory.h \ metal/pmp.h \ diff --git a/Makefile.in b/Makefile.in index 551e82f0..8bba3983 100644 --- a/Makefile.in +++ b/Makefile.in @@ -480,10 +480,10 @@ nobase_include_HEADERS = metal/machine.h metal/machine/inline.h \ metal/cache.h metal/clock.h metal/compiler.h metal/cpu.h \ metal/csr.h metal/gpio.h metal/hpm.h metal/i2c.h metal/init.h \ metal/interrupt.h metal/io.h metal/itim.h metal/led.h \ - metal/lock.h metal/memory.h metal/pmp.h metal/privilege.h \ - metal/pwm.h metal/rtc.h metal/shutdown.h metal/scrub.h \ - metal/spi.h metal/switch.h metal/timer.h metal/time.h \ - metal/tty.h metal/uart.h metal/watchdog.h + metal/lim.h metal/lock.h metal/memory.h metal/pmp.h \ + metal/privilege.h metal/pwm.h metal/rtc.h metal/shutdown.h \ + metal/scrub.h metal/spi.h metal/switch.h metal/timer.h \ + metal/time.h metal/tty.h metal/uart.h metal/watchdog.h # This will generate these sources before the compilation step BUILT_SOURCES = \ diff --git a/gloss/crt0.S b/gloss/crt0.S index e023e093..20afcc0c 100644 --- a/gloss/crt0.S +++ b/gloss/crt0.S @@ -108,6 +108,36 @@ _start: complete */ fence.i +2: + + /* Copy the LIM section */ + la t0, metal_segment_lim_source_start + la t1, metal_segment_lim_target_start + la t2, metal_segment_lim_target_end + + beq t0, t1, 2f + bge t1, t2, 2f + +1: +#if __riscv_xlen == 32 + lw a0, 0(t0) + addi t0, t0, 4 + sw a0, 0(t1) + addi t1, t1, 4 + blt t1, t2, 1b +#else + ld a0, 0(t0) + addi t0, t0, 8 + sd a0, 0(t1) + addi t1, t1, 8 + blt t1, t2, 1b +#endif +2: + + /* Fence all subsequent instruction fetches until after the LIM writes + complete */ + fence.i + /* Zero the BSS segment. */ la t1, metal_segment_bss_target_start la t2, metal_segment_bss_target_end diff --git a/metal/drivers/sifive_ccache0.h b/metal/drivers/sifive_ccache0.h index 9af1cb3f..13a47c0b 100644 --- a/metal/drivers/sifive_ccache0.h +++ b/metal/drivers/sifive_ccache0.h @@ -29,6 +29,7 @@ typedef enum { /*! @brief Initialize cache controller, enables all available * cache-ways. + * Note: If LIM is in use, corresponding cache ways are not enabled. * @param None. * @return 0 If no error.*/ int sifive_ccache0_init(void); diff --git a/metal/lim.h b/metal/lim.h new file mode 100644 index 00000000..1e573cad --- /dev/null +++ b/metal/lim.h @@ -0,0 +1,20 @@ +/* Copyright 2020 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#ifndef METAL__LIM_H +#define METAL__LIM_H + +/*! @file lim.h + * + * API for manipulating LIM allocation + */ + +/*! @def METAL_PLACE_IN_LIM + * @brief Link a function into the LIM + * + * Link a function into the LIM (Loosely Integrated + * Memory) if the LIM is present on the target device. + */ +#define METAL_PLACE_IN_LIM __attribute__((section(".lim"))) + +#endif diff --git a/src/drivers/sifive_ccache0.c b/src/drivers/sifive_ccache0.c index 29b46ee4..76aeb25c 100644 --- a/src/drivers/sifive_ccache0.c +++ b/src/drivers/sifive_ccache0.c @@ -21,19 +21,16 @@ #define REG_SHIFT_16 16 #define REG_SHIFT_24 24 -/* Masks to get cache configuration data */ -#define SIFIVE_CCACHE0_CONFIG_BANKS_MASK 0x000000FFUL -#define SIFIVE_CCACHE0_CONFIG_WAYS_MASK 0x0000FF00UL -#define SIFIVE_CCACHE0_CONFIG_SETS_MASK 0x00FF0000UL -#define SIFIVE_CCACHE0_CONFIG_BLOCKS_MASK 0xFF000000UL - -#define SIFIVE_CCACHE0_WAY_ENABLE_MASK 0x000000FFUL +#define SIFIVE_CCACHE0_BYTE_MASK 0xFFUL static int sifive_ccache0_interrupts[] = METAL_SIFIVE_CCACHE0_INTERRUPTS; /* Initialize cache at start-up via metal constructors */ METAL_CONSTRUCTOR(_sifive_ccache0_init) { sifive_ccache0_init(); } +/* Linker symbols to calculate LIM allocated size */ +extern char metal_segment_lim_target_start, metal_segment_lim_target_end; + int sifive_ccache0_init(void) { int ret; @@ -42,6 +39,17 @@ int sifive_ccache0_init(void) { /* Get cache configuration data */ sifive_ccache0_get_config(&config); + int lim_size = + &metal_segment_lim_target_end - &metal_segment_lim_target_start; + + if (lim_size) { /* Do not enable cache ways, corresponding to LIM area in + use. */ + while (lim_size > 0) { + lim_size -= (config.block_size * config.num_sets * config.num_bank); + config.num_ways--; + } + } + /* Enable ways */ ret = sifive_ccache0_set_enabled_ways(config.num_ways); @@ -56,13 +64,12 @@ void sifive_ccache0_get_config(sifive_ccache0_config *config) { val = REGW(METAL_SIFIVE_CCACHE0_CONFIG); /* Populate cache configuration data */ - config->num_bank = (val & SIFIVE_CCACHE0_CONFIG_BANKS_MASK); - config->num_ways = - (val & SIFIVE_CCACHE0_CONFIG_WAYS_MASK) >> REG_SHIFT_8; + config->num_bank = (val & SIFIVE_CCACHE0_BYTE_MASK); + config->num_ways = ((val >> REG_SHIFT_8) & SIFIVE_CCACHE0_BYTE_MASK); config->num_sets = - 2 ^ ((val & SIFIVE_CCACHE0_CONFIG_SETS_MASK) >> REG_SHIFT_16); + 2 << (((val >> REG_SHIFT_16) & SIFIVE_CCACHE0_BYTE_MASK) - 1); config->block_size = - 2 ^ ((val & SIFIVE_CCACHE0_CONFIG_BLOCKS_MASK) >> REG_SHIFT_24); + 2 << (((val >> REG_SHIFT_24) & SIFIVE_CCACHE0_BYTE_MASK) - 1); } } @@ -70,7 +77,7 @@ uint32_t sifive_ccache0_get_enabled_ways(void) { uint32_t val = 0; - val = SIFIVE_CCACHE0_WAY_ENABLE_MASK & REGW(METAL_SIFIVE_CCACHE0_WAYENABLE); + val = SIFIVE_CCACHE0_BYTE_MASK & REGW(METAL_SIFIVE_CCACHE0_WAYENABLE); /* The stored number is the way index, so increment by 1 */ val++;