diff --git a/hw/application_fpga/fw/testapp/Makefile b/hw/application_fpga/fw/testapp/Makefile new file mode 100644 index 0000000..5509877 --- /dev/null +++ b/hw/application_fpga/fw/testapp/Makefile @@ -0,0 +1,68 @@ +P := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) +OBJCOPY ?= llvm-objcopy +CC = clang +CFLAGS = \ + -target riscv32-unknown-none-elf \ + -march=rv32iczmmul \ + -mabi=ilp32 \ + -mcmodel=medany \ + -static \ + -std=gnu99 \ + -O2 \ + -ffast-math \ + -fno-common \ + -fno-builtin-printf \ + -fno-builtin-putchar \ + -fno-builtin-memcpy \ + -nostdlib \ + -mno-relax \ + -Wall \ + -Wpedantic \ + -Wno-language-extension-token \ + -Werror \ + -flto \ + -g + +AS = clang + +ASFLAGS = \ + -target riscv32-unknown-none-elf \ + -march=rv32iczmmul \ + -mabi=ilp32 \ + -mno-relax + +LDFLAGS=-T $(P)/app.lds + +.PHONY: all +all: testapp.bin + +# Turn elf into bin for device +%.bin: %.elf + $(OBJCOPY) --input-target=elf32-littleriscv --output-target=binary $^ $@ + chmod a-x $@ + +TESTAPP_FMTFILES = \ + $(P)/main.c \ + +TESTAPP_OBJS = \ + $(P)/main.o \ + $(P)/crt0.o \ + $(P)/../tk1/led.o \ + $(P)/../tk1/lib.o \ + $(P)/../tk1/proto.o + +testapp.elf: $(TESTAPP_OBJS) + $(CC) $(CFLAGS) $(TESTAPP_OBJS) $(LDFLAGS) -o $@ + +.PHONY: fmt +fmt: + clang-format --dry-run --ferror-limit=0 $(TESTAPP_FMTFILES) + clang-format --verbose -i $(TESTAPP_FMTFILES) + +.PHONY: checkfmt +checkfmt: + clang-format --dry-run --ferror-limit=0 --Werror $(TESTAPP_FMTFILES) + +.PHONY: clean +clean: + rm -f testapp.bin testapp.elf $(TESTAPP_OBJS) diff --git a/hw/application_fpga/fw/testapp/app.lds b/hw/application_fpga/fw/testapp/app.lds new file mode 100644 index 0000000..421122c --- /dev/null +++ b/hw/application_fpga/fw/testapp/app.lds @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2022 Tillitis AB + * SPDX-License-Identifier: BSD-2-Clause + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + RAM (rwx) : ORIGIN = 0x40000000, LENGTH = 0x20000 /* 128 KB */ +} + +SECTIONS +{ + .text.init : + { + *(.text.init) + } >RAM + + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + *(.srodata) /* .rodata sections (constants, strings, etc.) */ + *(.srodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + _etext = .; + _sidata = _etext; + } >RAM + + .data : AT (_etext) + { + . = ALIGN(4); + _sdata = .; + . = ALIGN(4); + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + *(.sdata) /* .sdata sections */ + *(.sdata*) /* .sdata* sections */ + . = ALIGN(4); + _edata = .; + } >RAM + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss) + *(.bss*) + *(.sbss) + *(.sbss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; + } >RAM + + /* libcrt0/crt0.S inits stack to start just below end of RAM */ +} diff --git a/hw/application_fpga/fw/testapp/crt0.S b/hw/application_fpga/fw/testapp/crt0.S new file mode 100644 index 0000000..f484b7d --- /dev/null +++ b/hw/application_fpga/fw/testapp/crt0.S @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2022 Tillitis AB +// SPDX-License-Identifier: BSD-2-Clause + + .section ".text.init" + .global _start +_start: + li x1, 0 + li x2, 0 + li x3, 0 + li x4, 0 + li x5, 0 + li x6, 0 + li x7, 0 + li x8, 0 + li x9, 0 + li x10,0 + li x11,0 + li x12,0 + li x13,0 + li x14,0 + li x15,0 + li x16,0 + li x17,0 + li x18,0 + li x19,0 + li x20,0 + li x21,0 + li x22,0 + li x23,0 + li x24,0 + li x25,0 + li x26,0 + li x27,0 + li x28,0 + li x29,0 + li x30,0 + li x31,0 + + /* init stack below 0x40020000 (TK1_RAM_BASE+TK1_RAM_SIZE) */ + li sp, 0x4001fff0 + + /* zero-init bss section */ + la a0, _sbss + la a1, _ebss + bge a0, a1, end_init_bss + +loop_init_bss: + sw zero, 0(a0) + addi a0, a0, 4 + blt a0, a1, loop_init_bss + +end_init_bss: + call main diff --git a/hw/application_fpga/fw/testapp/main.c b/hw/application_fpga/fw/testapp/main.c new file mode 100644 index 0000000..ab16f80 --- /dev/null +++ b/hw/application_fpga/fw/testapp/main.c @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2022, 2023 - Tillitis AB + * SPDX-License-Identifier: GPL-2.0-only + */ + +#include "../tk1/led.h" +#include "../tk1/lib.h" +#include "../tk1/proto.h" +#include "../tk1/types.h" +#include "../tk1_mem.h" + +// clang-format off +volatile uint32_t *tk1name0 = (volatile uint32_t *)TK1_MMIO_TK1_NAME0; +volatile uint32_t *tk1name1 = (volatile uint32_t *)TK1_MMIO_TK1_NAME1; +volatile uint32_t *uds = (volatile uint32_t *)TK1_MMIO_UDS_FIRST; +volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST; +volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST; +volatile uint32_t *system_mode_ctrl = (volatile uint32_t *)TK1_MMIO_TK1_SYSTEM_MODE_CTRL; +volatile uint8_t *fw_ram = (volatile uint8_t *)TK1_MMIO_FW_RAM_BASE; +volatile uint32_t *timer = (volatile uint32_t *)TK1_MMIO_TIMER_TIMER; +volatile uint32_t *timer_prescaler = (volatile uint32_t *)TK1_MMIO_TIMER_PRESCALER; +volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER_STATUS; +volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL; +volatile uint32_t *trng_status = (volatile uint32_t *)TK1_MMIO_TRNG_STATUS; +volatile uint32_t *trng_entropy = (volatile uint32_t *)TK1_MMIO_TRNG_ENTROPY; +// clang-format on + +#define UDS_WORDS 8 +#define UDI_WORDS 2 +#define CDI_WORDS 8 + +void *memcpy(void *dest, const void *src, size_t n) +{ + uint8_t *src_byte = (uint8_t *)src; + uint8_t *dest_byte = (uint8_t *)dest; + + for (int i = 0; i < n; i++) { + dest_byte[i] = src_byte[i]; + } + + return dest; +} + +void puts(char *reason) +{ + for (char *c = reason; *c != '\0'; c++) { + writebyte(*c); + } +} + +void putsn(char *p, int n) +{ + for (int i = 0; i < n; i++) { + writebyte(p[i]); + } +} + +void puthex(uint8_t c) +{ + unsigned int upper = (c >> 4) & 0xf; + unsigned int lower = c & 0xf; + writebyte(upper < 10 ? '0' + upper : 'a' - 10 + upper); + writebyte(lower < 10 ? '0' + lower : 'a' - 10 + lower); +} + +void puthexn(uint8_t *p, int n) +{ + for (int i = 0; i < n; i++) { + puthex(p[i]); + } +} + +void hexdump(void *buf, int len) +{ + uint8_t *byte_buf = (uint8_t *)buf; + + for (int i = 0; i < len; i++) { + puthex(byte_buf[i]); + if (i % 2 == 1) { + writebyte(' '); + } + + if (i != 1 && i % 16 == 1) { + puts("\r\n"); + } + } + + puts("\r\n"); +} + +void reverseword(uint32_t *wordp) +{ + *wordp = ((*wordp & 0xff000000) >> 24) | ((*wordp & 0x00ff0000) >> 8) | + ((*wordp & 0x0000ff00) << 8) | ((*wordp & 0x000000ff) << 24); +} + +uint32_t wait_timer_tick(uint32_t last_timer) +{ + uint32_t newtimer; + for (;;) { + newtimer = *timer; + if (newtimer != last_timer) { + return newtimer; + } + } +} + +void zero_fwram(void) +{ + for (int i = 0; i < TK1_MMIO_FW_RAM_SIZE; i++) { + fw_ram[i] = 0x00; + } +} + +int check_fwram_zero_except(unsigned int offset, uint8_t expected_val) +{ + int failed = 0; + for (unsigned int i = 0; i < TK1_MMIO_FW_RAM_SIZE; i++) { + uint32_t addr = TK1_MMIO_FW_RAM_BASE + i; + uint8_t *p = (uint8_t *)addr; + uint8_t val = *(volatile uint8_t *)p; + int failed_now = 0; + if (i == offset) { + if (val != expected_val) { + failed_now = 1; + puts(" wrong value at: "); + } + } else { + if (val != 0) { + failed_now = 1; + puts(" not zero at: "); + } + } + if (failed_now) { + failed = 1; + reverseword(&addr); + puthexn((uint8_t *)&addr, 4); + puts("\r\n"); + } + } + return failed; +} + +void failmsg(char *s) +{ + puts("FAIL: "); + puts(s); + puts("\r\n"); +} + +int main(void) +{ + uint8_t in; + + set_led(LED_BLUE); + + // Wait for terminal program and a character to be typed + in = readbyte(); + + puts("\r\nI'm testapp on:"); + // Output the TK1 core's NAME0 and NAME1 + uint32_t name; + wordcpy_s(&name, 1, (void *)tk1name0, 1); + reverseword(&name); + putsn((char *)&name, 4); + puts(" "); + wordcpy_s(&name, 1, (void *)tk1name1, 1); + reverseword(&name); + putsn((char *)&name, 4); + puts("\r\n"); + + uint32_t zeros[8]; + memset(zeros, 0, 8 * 4); + + int anyfailed = 0; + + uint32_t uds_local[UDS_WORDS]; + uint32_t udi_local[UDI_WORDS]; + + uint32_t sw = *system_mode_ctrl; + if (sw != 0xffffffff) { + failmsg("system_mode_ctrl is not 0xffffffff"); + anyfailed = 1; + } + + // Should NOT be able to read from UDS in app-mode. + wordcpy_s(uds_local, UDS_WORDS, (void *)uds, UDS_WORDS); + if (!memeq(uds_local, zeros, UDS_WORDS * 4)) { + failmsg("Read from UDS in app-mode"); + anyfailed = 1; + } + + // Should NOT be able to read from UDI in app-mode. + wordcpy_s(udi_local, UDI_WORDS, (void *)udi, UDI_WORDS); + if (!memeq(udi_local, zeros, UDI_WORDS * 4)) { + failmsg("Read from UDI in app-mode"); + anyfailed = 1; + } + + uint32_t cdi_local[CDI_WORDS]; + uint32_t cdi_local2[CDI_WORDS]; + wordcpy_s(cdi_local, CDI_WORDS, (void *)cdi, CDI_WORDS); + + // Write to CDI should NOT have any effect in app mode. + wordcpy_s((void *)cdi, CDI_WORDS, zeros, CDI_WORDS); + wordcpy_s(cdi_local2, CDI_WORDS, (void *)cdi, CDI_WORDS); + if (!memeq(cdi_local, cdi_local2, CDI_WORDS * 4)) { + failmsg("Write to CDI in app-mode"); + anyfailed = 1; + } + + // Test FW_RAM. + *fw_ram = 0x21; + if (*fw_ram == 0x21) { + failmsg("Write and read FW RAM in app-mode"); + anyfailed = 1; + } + + puts("\r\nTesting timer... 3"); + // Matching clock at 21 MHz, giving us timer in seconds + *timer_prescaler = 21 * 1000000; + + // Test timer expiration after 1s + *timer = 1; + // Start the timer + *timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_START_BIT); + while (*timer_status & (1 << TK1_MMIO_TIMER_STATUS_RUNNING_BIT)) { + } + // Now timer has expired and is ready to run again + puts(" 2"); + + // Test to interrupt a timer - and reads from timer register + // Starting 10s timer and interrupting it in 3s... + *timer = 10; + *timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_START_BIT); + uint32_t last_timer = 10; + for (int i = 0; i < 3; i++) { + last_timer = wait_timer_tick(last_timer); + } + + // Stop the timer + *timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_STOP_BIT); + puts(" 1. done.\r\n"); + + if (*timer_status & (1 << TK1_MMIO_TIMER_STATUS_RUNNING_BIT)) { + failmsg("Timer didn't stop"); + anyfailed = 1; + } + + if (*timer != 10) { + failmsg("Timer didn't reset to 10"); + anyfailed = 1; + } + + // Check and display test results. + puts("\r\n--> "); + if (anyfailed) { + puts("Some test FAILED!\r\n"); + } else { + puts("All tests passed.\r\n"); + } + + puts("\r\nHere are 256 bytes from the TRNG:\r\n"); + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) { + while ((*trng_status & + (1 << TK1_MMIO_TRNG_STATUS_READY_BIT)) == 0) { + } + uint32_t rnd = *trng_entropy; + puthexn((uint8_t *)&rnd, 4); + puts(" "); + } + puts("\r\n"); + } + puts("\r\n"); + + puts("Now echoing what you type...\r\n"); + for (;;) { + in = readbyte(); // blocks + writebyte(in); + } +} diff --git a/hw/application_fpga/fw/testfw/main.c b/hw/application_fpga/fw/testfw/main.c index eaaf268..0ec2a6a 100644 --- a/hw/application_fpga/fw/testfw/main.c +++ b/hw/application_fpga/fw/testfw/main.c @@ -256,50 +256,6 @@ int main(void) anyfailed = 1; } - // Turn on application mode. - // ------------------------- - - *system_mode_ctrl = 1; - - sw = *system_mode_ctrl; - if (sw != 0xffffffff) { - failmsg("system_mode_ctrl is not 0xffffffff in app mode"); - anyfailed = 1; - } - - // Should NOT be able to read from UDS in app-mode. - wordcpy_s(uds_local, UDS_WORDS, (void *)uds, UDS_WORDS); - if (!memeq(uds_local, zeros, UDS_WORDS * 4)) { - failmsg("Read from UDS in app-mode"); - anyfailed = 1; - } - - // Should NOT be able to read from UDI in app-mode. - wordcpy_s(udi_local, UDI_WORDS, (void *)udi, UDI_WORDS); - if (!memeq(udi_local, zeros, UDI_WORDS * 4)) { - failmsg("Read from UDI in app-mode"); - anyfailed = 1; - } - - uint32_t cdi_local[CDI_WORDS]; - uint32_t cdi_local2[CDI_WORDS]; - wordcpy_s(cdi_local, CDI_WORDS, (void *)cdi, CDI_WORDS); - - // Write to CDI should NOT have any effect in app mode. - wordcpy_s((void *)cdi, CDI_WORDS, zeros, CDI_WORDS); - wordcpy_s(cdi_local2, CDI_WORDS, (void *)cdi, CDI_WORDS); - if (!memeq(cdi_local, cdi_local2, CDI_WORDS * 4)) { - failmsg("Write to CDI in app-mode"); - anyfailed = 1; - } - - // Test FW_RAM. - *fw_ram = 0x21; - if (*fw_ram == 0x21) { - failmsg("Write and read FW RAM in app-mode"); - anyfailed = 1; - } - puts("\r\nTesting timer... 3"); // Matching clock at 18 MHz, giving us timer in seconds *timer_prescaler = 18 * 1000000;