diff --git a/evalsoc/zcmt_jumptable/Makefile b/evalsoc/zcmt_jumptable/Makefile new file mode 100644 index 0000000..d940dfd --- /dev/null +++ b/evalsoc/zcmt_jumptable/Makefile @@ -0,0 +1,15 @@ +TARGET = jmp + +NUCLEI_SDK_ROOT = ../../.. + +CORE ?= n300 + +ARCH_EXT ?= _zca_zcb_zcmp_zcmt + +SRCDIRS = . + +INCDIRS = . + +COMMON_FLAGS := -O3 + +include $(NUCLEI_SDK_ROOT)/Build/Makefile.base diff --git a/evalsoc/zcmt_jumptable/README.md b/evalsoc/zcmt_jumptable/README.md new file mode 100644 index 0000000..2c7999c --- /dev/null +++ b/evalsoc/zcmt_jumptable/README.md @@ -0,0 +1,27 @@ +# RISC-V Zcmt Jump Table Example For Nuclei SDK + +This example is used to demostrate how to use Zcmt extension to implement +runtime jump function replacement, so you can do hotfix for certain functions. + +## Run in command line + +You need to download Nuclei SDK >= 0.5.0 version. + +~~~shell +cd /path/to/nuclei-sdk +cd nuclei-board-labs/evalsoc/zcmt_jumptable +# build it +# Assume environment is already setup, see https://doc.nucleisys.com/nuclei_sdk/quickstart.html +# Require Nuclei Studio 2023.10 +make all +# run on qemu +make run_qemu +# run on hw +# require N300 with Zc extension bitstream +make upload +~~~ + +## Run in Nuclei Studio + +> Nuclei Studio >= 2023.10 is required + diff --git a/evalsoc/zcmt_jumptable/main.c b/evalsoc/zcmt_jumptable/main.c new file mode 100644 index 0000000..d63f1be --- /dev/null +++ b/evalsoc/zcmt_jumptable/main.c @@ -0,0 +1,91 @@ +#include "nuclei_sdk_hal.h" +#include + +// used for jump table index < 32, cm.jt +// https://github.com/riscv/riscv-code-size-reduction/blob/main/Zc-specification/cm_jt.adoc +void __attribute__ ((naked)) zcmt_cmjt(void) +{ + asm volatile("cm.jt 0 \n"); +} + +// used for jump table index >= 32, cm.jalt +// https://github.com/riscv/riscv-code-size-reduction/blob/main/Zc-specification/cm_jalt.adoc +void __attribute__ ((naked)) zcmt_cmjalt(void) +{ +#if __riscv_xlen == 32 + asm volatile( + "add sp,sp,-4\n" + "sw ra,0(sp) \n" + "cm.jalt 255 \n" + "lw ra,0(sp) \n" + "add sp,sp,4\n" + "ret"); +#else + asm volatile( + "add sp,sp,-8\n" + "sd ra,0(sp) \n" + "cm.jalt 255 \n" + "ld ra,0(sp) \n" + "add sp,sp,8\n" + "ret"); +#endif +} + +// Test func 1 +void abc() +{ + printf("hello from abc\n"); +} + +// Test func 2 +void cdf() +{ + printf("hello from cdf\n"); +} + +// Need to align at 64bytes, required by jvt csr +// The value in the BASE field must always be aligned on a 64-byte boundary. see https://github.com/riscv/riscv-code-size-reduction/blob/main/Zc-specification/jvt_csr.adoc +// For this encoding to decode as cm.jalt, index>=32, otherwise it decodes as cm.jt +// max entries are 0-255, total 256 entries +// TODO jump table need to place in a ram where cpu instruction fetch unit and data acess unit can both access it +static unsigned long jptbl[256] __ALIGNED(64) = {}; + +unsigned long update_jump_table(unsigned long index, unsigned long funptr) +{ + unsigned long *tbptr = (unsigned long *)__RV_CSR_READ(CSR_JVT); + + if (tbptr != jptbl) { + printf("jump table not match!\n"); + return 1; + } + tbptr[index] = funptr; + // fence.i is required to flush cache if cache present + __FENCE_I(); +} + +// NOTE: About Zcmt table jump, see https://github.com/riscv/riscv-code-size-reduction/blob/main/Zc-specification/tablejump.adoc +void main(void) +{ + __RV_CSR_WRITE(CSR_JVT, jptbl); + + printf("Jump table located in 0x%x\n", __RV_CSR_READ(CSR_JVT)); + + printf("--> Test cm.jt instruction!\n"); + // let cm.jt jump to abc + update_jump_table(0, (unsigned long)abc); + // before execute this function the jump table must be initialized + zcmt_cmjt(); + + // let cm.jt jump to cdf + update_jump_table(0, (unsigned long)cdf); + zcmt_cmjt(); + + printf("--> Test cm.jalt instruction!\n"); + // let cm.jalt jump to abc + update_jump_table(255, (unsigned long)abc); + zcmt_cmjalt(); + + // let cm.jalt jump to cdf + update_jump_table(255, (unsigned long)cdf); + zcmt_cmjalt(); +} diff --git a/evalsoc/zcmt_jumptable/npk.yml b/evalsoc/zcmt_jumptable/npk.yml new file mode 100644 index 0000000..9cb6163 --- /dev/null +++ b/evalsoc/zcmt_jumptable/npk.yml @@ -0,0 +1,58 @@ +## Package Base Information +name: app_evalsoc_zcmt_jumptable +owner: nuclei +version: 1.0.0 +description: Nuclei Zcmt Jump Table Demo +type: app +keywords: + - nuclei board labs + - baremetal + - jump table +category: Board Labs +license: Apache-2.0 +homepage: https://github.com/Nuclei-Software/nuclei-board-labs/tree/master/evalsoc/zcmt_jumptable + +## Package Dependency +dependencies: + - name: ssp-nsdk_evalsoc + owner: nuclei + version: + +## Package Configurations +configuration: + app_commonflags: + value: -O3 + type: text + description: Application Compile Flags + +setconfig: + - config: nuclei_core + value: n300 + - config: nuclei_archext + value: _zca_zcb_zcmp_zcmt + +## Source Code Management +codemanage: + copyfiles: + - path: ["*.c", "*.h", "*.S", "*.s", "*.C"] + incdirs: + - path: ["./"] + libdirs: + ldlibs: + - libs: [""] + +## Build Configuration +buildconfig: + - type: common + common_flags: # flags need to be combined together across all packages + - flags: ${app_commonflags} + ldflags: + cflags: + asmflags: + cxxflags: + prebuild_steps: # could be override by app/bsp type + command: + description: + postbuild_steps: # could be override by app/bsp type + command: + description: