diff --git a/README.md b/README.md index eb5b303..988aff6 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Although based on a fully fledged CPU emulator, uvm32 is intended for executing * [host-arduino](host-arduino) vm host as Arduino sketch (tested on Arduino Uno ATmega328P, uses 9950 bytes of flash/1254 bytes RAM) * [apps/helloworld](apps/helloworld) C hello world program * [apps/conio](apps/conio) C console IO demo + * [apps/lissajous](apps/lissajour) C console lissajous curve (showing softfp, floating point) * [apps/hello-asm](apps/hello-asm) Minimal hello world assembly * [apps/fib](apps/fib) C fibonacci series program (iterative and recursive) * [apps/sketch](apps/sketch) C Arduino/Wiring/Processing type program in `setup()` and `loop()` style diff --git a/apps/Makefile b/apps/Makefile index 133cabb..abe6621 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -4,6 +4,7 @@ all: docker build -t ${DOCKER_IMAGE} . (cd sketch && make) (cd helloworld && make) + (cd lissajous && make) (cd conio && make) (cd zig-mandel && make) (cd zigtris && make) @@ -13,6 +14,7 @@ all: clean: (cd sketch && make clean) (cd helloworld && make clean) + (cd lissajous && make clean) (cd conio && make clean) (cd zig-mandel && make clean) (cd zigtris && make clean) diff --git a/apps/lissajous/Makefile b/apps/lissajous/Makefile new file mode 100644 index 0000000..7843727 --- /dev/null +++ b/apps/lissajous/Makefile @@ -0,0 +1,27 @@ +PROJECT:=lissajous + +DOCKER_IMAGE=riscv-dev +DOCKER_CMD:=docker run --rm -v ${PWD}../../../:/data -w /data/apps/${PROJECT} ${DOCKER_IMAGE} +PREFIX:=${DOCKER_CMD} riscv64-unknown-elf- +CFLAGS+=-I../../common +CFLAGS+=-fno-stack-protector +CFLAGS+=-static-libgcc -fdata-sections -ffunction-sections +CFLAGS+=-g -Os -march=rv32ima_zicsr -mabi=ilp32 -static +LDFLAGS:= -T ../linker.ld -nostdlib -Wl,--gc-sections +LIBS:= -lgcc # needed for softfp + +SRCS=${PROJECT}.c ../crt0.S + +all: + ${PREFIX}gcc -o ${PROJECT}.elf ${CFLAGS} ${LDFLAGS} ${SRCS} ${LIBS} + $(PREFIX)objcopy ${PROJECT}.elf -O binary ${PROJECT}.bin + +disasm: all + $(PREFIX)objdump -S -d -f ${PROJECT}.elf + +test: all + ../../host/host ${PWD}/${PROJECT}.bin + +clean: + rm -f ${PROJECT}.o ${PROJECT}.elf ${PROJECT}.bin + diff --git a/apps/lissajous/lissajous.c b/apps/lissajous/lissajous.c new file mode 100644 index 0000000..92da9ab --- /dev/null +++ b/apps/lissajous/lissajous.c @@ -0,0 +1,118 @@ +#define USE_MAIN +#include "uvm32_target.h" + +// https://github.com/shastro/CodeGolf-Lissajous/blob/master/lissa.c +// https://github.com/nicbk/donut-embedded/blob/ad8061ece9a2c156694c39af12f109ea6778da52/donut.c#L57 + +#define PI 3.14159265358979323846 // First 21 digits of pi + +void movecursor(int x, int y) { + print("\033["); + printdec(y); + print(";"); + printdec(x); + print("f"); +} + +void sleep(uint32_t ms) { + uint32_t start = millis(); + while (millis() < start + ms) { + yield(); + } +} + +// Absolute value function for doubles +double abs_c(double x) { + if (x < 0) { + return -x; + } else { + return x; + } +} + +// Recursive factorial capable of calculating a max of approximately 10^18 in size +unsigned long long fac(unsigned char x) { + if (x == 0) { + return 1; + } else { + return x * fac(x - 1); + } +} + +// Exponential function +// Ignores edge cases such as indeterminate forms for simplicity +double pow_c(double x, unsigned char n) { + if (n == 0) { + return 1; + } else { + double product = x; + + for (int i = 1; i < n; ++i) { + product *= x; + } + + return product; + } +} + +// MacLaurin series approximation of sin(x) from -PI/2 to PI/2 +// with eight terms, and extended to the domain of all +// real numbers with modular arithmetic. +double sin(double x) { + double translation = 0; + if (x > -PI / 2) { + translation = (int)((x + PI / 2) / PI); + } else { + translation = (int)((x - PI / 2) / PI); + } + + x -= PI * translation; + if ((int)abs_c(translation) % 2 == 1) { + x = -x; + } + + double sum = 0; + + for (int i = 0; i < 9; ++i) { + sum += pow_c(-1, i) * pow_c(x, 2 * i + 1) / fac(2 * i + 1); + } + + return sum; +} + +// cos(x) function derived from sin(x) +double cos(double x) { + return sin(PI / 2 - x); +} + +void main(void) { + int freq1 = 45; + int freq2 = 90; + + for (int i = 0; i < 300; i++) { + putc('\n'); + } + print("\033[H"); // Cursor at Corner of Screen + + float x = 0; + float y = 0; + float angle = 0; + float beta = 0.0; + + while (1) { + uint32_t framestart = millis(); + for (angle = 0; angle < 2 * PI; angle += 0.15) { + movecursor(x, y); + x = 40 * cos(freq1 * angle + beta) + 60; + y = 20 * sin(freq2 * angle) + 30; + print("#"); + } + // wait for next frame + while (millis() < framestart + 20) { + yield(); + } + beta += 0.05; + + print("\033[2J"); + } +} diff --git a/precompiled/lissajous.bin b/precompiled/lissajous.bin new file mode 100755 index 0000000..6381bb0 Binary files /dev/null and b/precompiled/lissajous.bin differ