From 29e926beba86eba0c6000a2f687f64dcfc34f191 Mon Sep 17 00:00:00 2001 From: Aadi Desai <21363892+supleed2@users.noreply.github.com> Date: Tue, 7 Mar 2023 19:05:21 +0000 Subject: [PATCH] Add demo software files and gitignore/build script --- .gitignore | 7 +- demo.sh | 6 ++ demo/Makefile | 57 +++++++++++++ demo/README.md | 104 +++++++++++++++++++++++ demo/demo.py | 37 ++++++++ demo/donut.c | 68 +++++++++++++++ demo/helloc.c | 6 ++ demo/hellocpp.cpp | 7 ++ demo/linker.ld | 66 +++++++++++++++ demo/main.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++ make.py | 15 ++-- 11 files changed, 574 insertions(+), 9 deletions(-) create mode 100755 demo.sh create mode 100644 demo/Makefile create mode 100644 demo/README.md create mode 100755 demo/demo.py create mode 100644 demo/donut.c create mode 100644 demo/helloc.c create mode 100644 demo/hellocpp.cpp create mode 100644 demo/linker.ld create mode 100644 demo/main.c diff --git a/.gitignore b/.gitignore index 3a45ef7..2849284 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ /.vscode/ /build/ -__pycache__/ \ No newline at end of file +__pycache__/ +demo/*.o +demo/*.d +demo/demo.bin +demo/demo.elf +demo/demo.elf.map diff --git a/demo.sh b/demo.sh new file mode 100755 index 0000000..5166656 --- /dev/null +++ b/demo.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -e +rm -f demo/*.o demo/*.d demo/demo.bin demo/demo.elf demo/demo.elf.map +python3 demo/demo.py --build-path build/gsd_orangecrab/ --with-cxx +rm -f /mnt/c/Users/suple/Desktop/dfu-util-0.9-win64/gsd.bin && echo "Deleted old Win11 BIN" +mv demo.bin /mnt/c/Users/suple/Desktop/dfu-util-0.9-win64/gsd.bin && echo "Moved new BIN to Win11 Desktop" diff --git a/demo/Makefile b/demo/Makefile new file mode 100644 index 0000000..a30071a --- /dev/null +++ b/demo/Makefile @@ -0,0 +1,57 @@ +BUILD_DIR?=../build/ + +include $(BUILD_DIR)/software/include/generated/variables.mak +include $(SOC_DIRECTORY)/software/common.mak + +OBJECTS = donut.o helloc.o crt0.o main.o +ifdef WITH_CXX + OBJECTS += hellocpp.o + CFLAGS += -DWITH_CXX +endif + + +all: demo.bin + + +%.bin: %.elf + $(OBJCOPY) -O binary $< $@ +ifneq ($(OS),Windows_NT) + chmod -x $@ +endif + +vpath %.a $(PACKAGES:%=../%) + +demo.elf: $(OBJECTS) + $(CC) $(LDFLAGS) -T linker.ld -N -o $@ \ + $(OBJECTS) \ + $(PACKAGES:%=-L$(BUILD_DIR)/software/%) \ + -Wl,--whole-archive \ + -Wl,--gc-sections \ + -Wl,-Map,$@.map \ + $(LIBS:lib%=-l%) + +ifneq ($(OS),Windows_NT) + chmod -x $@ +endif + +# pull in dependency info for *existing* .o files +-include $(OBJECTS:.o=.d) + +donut.o: CFLAGS += -w + +VPATH = $(BIOS_DIRECTORY):$(BIOS_DIRECTORY)/cmds:$(CPU_DIRECTORY) + + +%.o: %.cpp + $(compilexx) + +%.o: %.c + $(compile) + +%.o: %.S + $(assemble) + +clean: + $(RM) $(OBJECTS) demo.elf demo.bin .*~ *~ + +.PHONY: all clean diff --git a/demo/README.md b/demo/README.md new file mode 100644 index 0000000..fe7310f --- /dev/null +++ b/demo/README.md @@ -0,0 +1,104 @@ +# Bare Metal Demo App + +This directory provides a minimal bare metal demo app that demonstrates how to easily create a bare metal C application and load it/run it on the CPU of a SoC. + +## Build and Load over LiteX-Term + +To build a LiteX SoC for the Arty board (available in LiteX-Boards) and build the demo app for it, execute the following commands: + +```bash +python3 -m litex_boards.targets.digilent_arty --build --load +litex_bare_metal_demo --build-path=build/digilent_arty +``` + +Where `--build-path` is the build path to the Arty build directory. The Arty board is used here but almost any another board supported in LiteX-Boards could be used. When no external RAM is provided directly by the board, `--integrated-main-ram-size` argument could be used to add some integrated RAM in the SoC and be able to execute the demo from it. (ex `--integrated-main-ram-size=0x8000` will add 32KB of integrated RAM). + +Loading the compiled demo app can be done in different ways as explain in LiteX's [wiki](https://github.com/enjoy-digital/litex/wiki/Load-Application-Code-To-CPU) + +Since our app is small and for simplicity we'll just load it over serial here: `$ litex_term /dev/ttyUSBX --kernel=demo.bin` + +You should see the minimal demo app running and should be able to interact with it: + +```shell +--============== Boot ==================-- +Booting from serial... +Press Q or ESC to abort boot completely. +sL5DdSMmkekro +[LITEX-TERM] Received firmware download request from the device. +[LITEX-TERM] Uploading demo.bin to 0x40000000 (9264 bytes)... +[LITEX-TERM] Upload complete (9.8KB/s). +[LITEX-TERM] Booting the device. +[LITEX-TERM] Done. +Executing booted program at 0x40000000 + +--============= Liftoff! ===============-- + +LiteX minimal demo app built Dec 10 2020 17:13:02 + +Available commands: +help - Show this command +reboot - Reboot CPU +led - Led demo +donut - Spinning Donut demo +litex-demo-app> led +Led demo... +Counter mode... +Shift mode... +Dance mode... +litex-demo-app> donut +Donut demo... + + $$$$$@@@@@ + $##########$$$$$$$$ + ###*!!!!!!!!!***##$$$$$$ + ***!!====;;;;===!!**###$$$$# + **!===;;;:::::;:===!!**####$## + !*!!==;;:~-,,.,-~::;;=!!**#######! + !!!!=;:~-,.......-~::==!!***#####* + !!!!==;~~-.........,-:;==!!***###**! + !**!!=;:~-... ..-:;=!!!********! + ;!*#####*!!;. ~:;==!!!******!!= + :!*###$$$$#*! :;==!!!!!****!!!=; + ~=!*#$$$@@@$$##!!!!!!!!!!!!****!!!!=; + ;=!*#$$$@@@@$$#*******!*!!*!!!!!==;~ + -;!*###$$$$$$$###******!!!!!!!===;~ + -;!!*####$#####******!!!!!!==;;:- + ,:=!!!!**#**#***!!!!!!!====;:~, + -:==!!!*!!*!!!!!!!===;;;:~- + .~:;;========;=;;:::~-, + .--~~::::~:~~--,. +litex-demo-app> +``` + +## Replace the LiteX BIOS with the Demo App + +In some cases, we'll just want to replace the LiteX BIOS with our custom app. This demo can be used as a basis to create a such custom app. + +The demo will be recompiled to target the ROM of the SoC: + +```bash +litex_bare_metal_demo --build-path=build/arty/ --mem=rom +``` + +The SoC can then be re-compiled to integrate the demo app in the ROM with: + +```bash +python3 -m litex_boards.targets.digilent_arty --integrated-rom-init=demo.bin --build --load +``` + +When loading the bitstream, you should then directly see the demo app executed: + +```shell +LiteX minimal demo app built Dec 10 2020 17:13:02 + +Available commands: +help - Show this command +reboot - Reboot CPU +led - Led demo +donut - Spinning Donut demo +litex-demo-app> +``` + +## Going further + +To create more complex apps, feel free to explore the source code of the BIOS or other open source projects build with LiteX on the [GitHub wiki](https://github.com/enjoy-digital/litex/wiki/Projects). diff --git a/demo/demo.py b/demo/demo.py new file mode 100755 index 0000000..1eaeb0f --- /dev/null +++ b/demo/demo.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX. +# +# Copyright (c) 2020-2022 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import os +import sys +import argparse + +from litex.build.tools import replace_in_file + +def main(): + parser = argparse.ArgumentParser(description="LiteX Bare Metal Demo App.") + parser.add_argument("--build-path", help="Target's build path (ex build/board_name).", required=True) + parser.add_argument("--with-cxx", action="store_true", help="Enable CXX support.") + parser.add_argument("--mem", default="main_ram", help="Memory Region where code will be loaded/executed.") + args = parser.parse_args() + + # Update memory region. + replace_in_file("demo/linker.ld", "main_ram", args.mem) + + # Compile demo + build_path = args.build_path if os.path.isabs(args.build_path) else os.path.join("..", args.build_path) + os.system(f"export BUILD_DIR={build_path} && {'export WITH_CXX=1 &&' if args.with_cxx else ''} cd demo && make") + + # Copy demo.bin + os.system("cp demo/demo.bin ./") + + # Prepare flash boot image. + # python3 = sys.executable or "python3" # Nix specific: Reuse current Python executable if available. + # os.system(f"{python3} -m litex.soc.software.crcfbigen demo.bin -o demo.fbi --fbi --little") # FIXME: Endianness. + +if __name__ == "__main__": + main() diff --git a/demo/donut.c b/demo/donut.c new file mode 100644 index 0000000..eab0905 --- /dev/null +++ b/demo/donut.c @@ -0,0 +1,68 @@ +// The donut code with fixed-point arithmetic; no sines, cosines, square roots, or anything. +// a1k0n 2020 +// Code from: https://gist.github.com/a1k0n/80f48aa8911fffd805316b8ba8f48e83 +// For more info: +// - https://www.a1k0n.net/2011/07/20/donut-math.html +// - https://www.youtube.com/watch?v=DEqXNfs_HhY + +#include +#include +#include + +#include + +#define R(mul,shift,x,y) \ + _=x; \ + x -= mul*y>>shift; \ + y += mul*_>>shift; \ + _ = 3145728-x*x-y*y>>11; \ + x = x*_>>10; \ + y = y*_>>10; + +signed char b[1760], z[1760]; + +void donut(void); +void donut(void) { + int sA=1024,cA=0,sB=1024,cB=0,_; + for (;;) { + memset(b, 32, 1760); // text buffer + memset(z, 127, 1760); // z buffer + int sj=0, cj=1024; + for (int j = 0; j < 90; j++) { + int si = 0, ci = 1024; // sine and cosine of angle i + for (int i = 0; i < 324; i++) { + int R1 = 1, R2 = 2048, K2 = 5120*1024; + + int x0 = R1*cj + R2, + x1 = ci*x0 >> 10, + x2 = cA*sj >> 10, + x3 = si*x0 >> 10, + x4 = R1*x2 - (sA*x3 >> 10), + x5 = sA*sj >> 10, + x6 = K2 + R1*1024*x5 + cA*x3, + x7 = cj*si >> 10, + x = 40 + 30*(cB*x1 - sB*x4)/x6, + y = 12 + 15*(cB*x4 + sB*x1)/x6, + N = (-cA*x7 - cB*((-sA*x7>>10) + x2) - ci*(cj*sB >> 10) >> 10) - x5 >> 7; + + int o = x + 80 * y; + signed char zz = (x6-K2)>>15; + if (22 > y && y > 0 && x > 0 && 80 > x && zz < z[o]) { + z[o] = zz; + b[o] = ".,-~:;=!*#$@"[N > 0 ? N : 0]; + } + R(5, 8, ci, si) // rotate i + } + R(9, 7, cj, sj) // rotate j + } + for (int k = 0; 1761 > k; k++) + putchar(k % 80 ? b[k] : 10); + R(5, 7, cA, sA); + R(5, 8, cB, sB); + if (readchar_nonblock()) { + getchar(); + break; + } + fputs("\x1b[23A", stdout); + } +} diff --git a/demo/helloc.c b/demo/helloc.c new file mode 100644 index 0000000..e8750cc --- /dev/null +++ b/demo/helloc.c @@ -0,0 +1,6 @@ +#include + +void helloc(void); +void helloc(void) { + printf("C: Hello, world!\n"); +} \ No newline at end of file diff --git a/demo/hellocpp.cpp b/demo/hellocpp.cpp new file mode 100644 index 0000000..fb9e3fe --- /dev/null +++ b/demo/hellocpp.cpp @@ -0,0 +1,7 @@ +#include + +extern "C" void hellocpp(void); +void hellocpp(void) +{ + printf("C++: Hello, world!\n"); +} \ No newline at end of file diff --git a/demo/linker.ld b/demo/linker.ld new file mode 100644 index 0000000..60c3936 --- /dev/null +++ b/demo/linker.ld @@ -0,0 +1,66 @@ +INCLUDE generated/output_format.ld +ENTRY(_start) + +__DYNAMIC = 0; + +INCLUDE generated/regions.ld + +SECTIONS +{ + .text : + { + _ftext = .; + /* Make sure crt0 files come first, and they, and the isr */ + /* don't get disposed of by greedy optimisation */ + *crt0*(.text) + KEEP(*crt0*(.text)) + KEEP(*(.text.isr)) + + *(.text .stub .text.* .gnu.linkonce.t.*) + _etext = .; + } > main_ram + + .rodata : + { + . = ALIGN(8); + _frodata = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.got .got.*) + *(.toc .toc.*) + . = ALIGN(8); + _erodata = .; + } > main_ram + + .data : + { + . = ALIGN(8); + _fdata = .; + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + _gp = ALIGN(16); + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(8); + _edata = .; + } > sram AT > main_ram + + .bss : + { + . = ALIGN(8); + _fbss = .; + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(8); + _ebss = .; + _end = .; + } > sram +} + +PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram)); + +PROVIDE(_fdata_rom = LOADADDR(.data)); +PROVIDE(_edata_rom = LOADADDR(.data) + SIZEOF(.data)); diff --git a/demo/main.c b/demo/main.c new file mode 100644 index 0000000..38c451f --- /dev/null +++ b/demo/main.c @@ -0,0 +1,210 @@ +// This file is Copyright (c) 2020 Florent Kermarrec +// License: BSD + +#include +#include +#include + +#include +#include +#include +#include + +/*-----------------------------------------------------------------------*/ +/* Uart */ +/*-----------------------------------------------------------------------*/ + +static char *readstr(void) +{ + char c[2]; + static char s[64]; + static int ptr = 0; + + if(readchar_nonblock()) { + c[0] = getchar(); + c[1] = 0; + switch(c[0]) { + case 0x7f: + case 0x08: + if(ptr > 0) { + ptr--; + fputs("\x08 \x08", stdout); + } + break; + case 0x07: + break; + case '\r': + case '\n': + s[ptr] = 0x00; + fputs("\n", stdout); + ptr = 0; + return s; + default: + if(ptr >= (sizeof(s) - 1)) + break; + fputs(c, stdout); + s[ptr] = c[0]; + ptr++; + break; + } + } + + return NULL; +} + +static char *get_token(char **str) +{ + char *c, *d; + + c = (char *)strchr(*str, ' '); + if(c == NULL) { + d = *str; + *str = *str+strlen(*str); + return d; + } + *c = 0; + d = *str; + *str = c+1; + return d; +} + +static void prompt(void) +{ + printf("\e[92;1mlitex-demo-app\e[0m> "); +} + +/*-----------------------------------------------------------------------*/ +/* Help */ +/*-----------------------------------------------------------------------*/ + +static void help(void) +{ + puts("\nLiteX minimal demo app built "__DATE__" "__TIME__"\n"); + puts("Available commands:"); + puts("help - Show this command"); + puts("reboot - Reboot CPU"); +#ifdef CSR_LEDS_BASE + puts("led - Led demo"); +#endif + puts("donut - Spinning Donut demo"); + puts("helloc - Hello C"); +#ifdef WITH_CXX + puts("hellocpp - Hello C++"); +#endif +} + +/*-----------------------------------------------------------------------*/ +/* Commands */ +/*-----------------------------------------------------------------------*/ + +static void reboot_cmd(void) +{ + ctrl_reset_write(1); +} + +#ifdef CSR_LEDS_BASE +static void led_cmd(void) +{ + int i; + printf("Led demo...\n"); + + printf("Counter mode...\n"); + for(i=0; i<32; i++) { + leds_out_write(i); + busy_wait(100); + } + + printf("Shift mode...\n"); + for(i=0; i<4; i++) { + leds_out_write(1<