summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--c/bfhello/Makefile20
-rw-r--r--c/bfhello/bfhello.b1
-rw-r--r--c/bfhello/bfhello.c91
-rwxr-xr-xc/bfhello/bfhello.elfbin0 -> 6508 bytes
-rw-r--r--c/bfhello/bfhello.hex27
-rw-r--r--c/bfhello/bfhello.obin0 -> 1856 bytes
-rw-r--r--c/bfhello/rvcontroller.ld45
-rw-r--r--c/bigfib/Makefile20
-rw-r--r--c/bigfib/bigfib.c23
-rwxr-xr-xc/bigfib/bigfib.elfbin0 -> 6552 bytes
-rw-r--r--c/bigfib/bigfib.hex19
-rw-r--r--c/bigfib/bigfib.obin0 -> 2184 bytes
-rw-r--r--c/bigfib/rvcontroller.ld45
-rw-r--r--c/drawercalc/Makefile20
-rw-r--r--c/drawercalc/drawercalc.c129
-rwxr-xr-xc/drawercalc/drawercalc.elfbin0 -> 7028 bytes
-rw-r--r--c/drawercalc/drawercalc.hex56
-rw-r--r--c/drawercalc/drawercalc.obin0 -> 5512 bytes
-rw-r--r--c/drawercalc/rvcontroller.ld45
-rw-r--r--c/elevator/Makefile20
-rw-r--r--c/elevator/elevator.c230
-rwxr-xr-xc/elevator/elevator.elfbin0 -> 8748 bytes
-rw-r--r--c/elevator/elevator.hex135
-rw-r--r--c/elevator/elevator.obin0 -> 12580 bytes
-rw-r--r--c/elevator/rvcontroller.ld45
-rw-r--r--c/elevator/states.h14
-rw-r--r--c/gol/Makefile20
-rw-r--r--c/gol/gol.c89
-rwxr-xr-xc/gol/gol.elfbin0 -> 13812 bytes
-rw-r--r--c/gol/gol.hex463
-rw-r--r--c/gol/gol.obin0 -> 13396 bytes
-rw-r--r--c/gol/rvcontroller.ld45
-rw-r--r--c/menu/Makefile44
-rw-r--r--c/menu/calculator.c95
-rw-r--r--c/menu/calculator.h6
-rw-r--r--c/menu/calculator.obin0 -> 6432 bytes
-rw-r--r--c/menu/digilines.c66
-rw-r--r--c/menu/digilines.h6
-rw-r--r--c/menu/digilines.obin0 -> 3800 bytes
-rw-r--r--c/menu/games.c121
-rw-r--r--c/menu/games.h6
-rw-r--r--c/menu/games.obin0 -> 7412 bytes
-rw-r--r--c/menu/menu.c74
-rwxr-xr-xc/menu/menu.elfbin0 -> 13056 bytes
-rw-r--r--c/menu/menu.hex377
-rw-r--r--c/menu/menu.obin0 -> 4704 bytes
-rw-r--r--c/menu/rvcontroller.ld45
-rw-r--r--c/menu/screensaver.c137
-rw-r--r--c/menu/screensaver.h6
-rw-r--r--c/menu/screensaver.obin0 -> 7492 bytes
-rw-r--r--c/rrxing/Makefile20
-rw-r--r--c/rrxing/rrxing.c86
-rwxr-xr-xc/rrxing/rrxing.elfbin0 -> 7292 bytes
-rw-r--r--c/rrxing/rrxing.hex70
-rw-r--r--c/rrxing/rrxing.obin0 -> 7340 bytes
-rw-r--r--c/rrxing/rvcontroller.ld45
-rw-r--r--c/rvcontroller-libraries/Makefile10
-rw-r--r--c/rvcontroller-libraries/rvcontroller-ecalls.S108
-rw-r--r--c/rvcontroller-libraries/rvcontroller-ecalls.h108
-rw-r--r--c/rvcontroller-libraries/rvcontroller-ecalls.obin0 -> 1292 bytes
-rw-r--r--c/rvcontroller-libraries/rvcontroller-init.S26
-rw-r--r--c/rvcontroller-libraries/rvcontroller-init.obin0 -> 916 bytes
-rw-r--r--c/squares/Makefile20
-rw-r--r--c/squares/rvcontroller.ld45
-rw-r--r--c/squares/squares.b8
-rw-r--r--c/squares/squares.c169
-rwxr-xr-xc/squares/squares.elfbin0 -> 6752 bytes
-rw-r--r--c/squares/squares.hex42
-rw-r--r--c/squares/squares.obin0 -> 2336 bytes
-rw-r--r--cross-links3
-rwxr-xr-xcross-toolchain/activate.sh6
-rw-r--r--fib.S29
-rw-r--r--guessnum-random.S126
-rw-r--r--guessnum.S119
-rw-r--r--hello.S6
-rw-r--r--loader.lua83
-rw-r--r--misa.S112
-rw-r--r--rrxing.S198
-rw-r--r--rvcontroller.ld45
-rw-r--r--rvcontroller.lua2604
81 files changed, 6676 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bedf027
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+cross-toolchain/build/*
+cross-toolchain/source/*
+cross-toolchain/install/*
diff --git a/c/bfhello/Makefile b/c/bfhello/Makefile
new file mode 100644
index 0000000..fa163ed
--- /dev/null
+++ b/c/bfhello/Makefile
@@ -0,0 +1,20 @@
+all: bfhello.hex
+
+bfhello.o: bfhello.c
+ clang -target riscv32-none-elf -I../rvcontroller-libraries -march=rv32imacb_zicntr_zicond_zicsr_zifencei_zihintpause_zilsd_zclsd_zabha_zacas_zbkb_zbkx_zcb_zcmp_zcmt -ffreestanding -O3 -c -o bfhello.o bfhello.c
+
+bfhello.elf: ../rvcontroller-libraries/rvcontroller-init.o ../rvcontroller-libraries/rvcontroller-ecalls.o bfhello.o
+ riscv32-none-elf-ld -T rvcontroller.ld --no-warn-rwx-segments -o bfhello.elf ../rvcontroller-libraries/rvcontroller-init.o bfhello.o ../rvcontroller-libraries/rvcontroller-ecalls.o
+
+dump: bfhello.elf
+ riscv32-none-elf-objdump -d bfhello.elf
+
+bfhello.hex: bfhello.elf
+ riscv32-none-elf-objcopy -O ihex bfhello.elf bfhello.hex
+
+load: bfhello.hex
+ bash -c "wl-copy < bfhello.hex"
+
+clean:
+ rm -f bfhello.bin bfhello.elf bfhello.o init.o
+
diff --git a/c/bfhello/bfhello.b b/c/bfhello/bfhello.b
new file mode 100644
index 0000000..8e5e5a6
--- /dev/null
+++ b/c/bfhello/bfhello.b
@@ -0,0 +1 @@
+++++++++[>+++++++++<-]>.+++++++++++++++++++++++++++++.+++++++..+++.>++++[>++++++++<-]>.>+++++[<+++++++++++>-]<.>++++[<++++++>-]<.+++.------.--------.>+++[>+++++++++++<-]>.>++++++++++.
diff --git a/c/bfhello/bfhello.c b/c/bfhello/bfhello.c
new file mode 100644
index 0000000..95d2209
--- /dev/null
+++ b/c/bfhello/bfhello.c
@@ -0,0 +1,91 @@
+/* This is a translation of bfhello.b, generated by bftoc.py (by Paul Kaefer)
+ * It was generated on Sunday, May 17, 2026 at 12:17AM
+ */
+
+#include "rvcontroller-ecalls.h"
+
+void main(void)
+{
+ int size = 1000;
+ int tape[size];
+ int i = 0;
+
+ /* Clearing the tape (array) */
+ for (i=0; i<size; i++)
+ tape[i] = 0;
+
+ int ptr = 0;
+
+ tape[ptr] += 8;
+ while (tape[ptr] != 0)
+ {
+ ptr += 1;
+ tape[ptr] += 9;
+ ptr -= 1;
+ tape[ptr] -= 1;
+ }
+ ptr += 1;
+ printchar(tape[ptr]);
+ tape[ptr] += 29;
+ printchar(tape[ptr]);
+ tape[ptr] += 7;
+ printchar(tape[ptr]);
+ printchar(tape[ptr]);
+ tape[ptr] += 3;
+ printchar(tape[ptr]);
+ ptr += 1;
+ tape[ptr] += 4;
+ while (tape[ptr] != 0)
+ {
+ ptr += 1;
+ tape[ptr] += 8;
+ ptr -= 1;
+ tape[ptr] -= 1;
+ }
+ ptr += 1;
+ printchar(tape[ptr]);
+ ptr += 1;
+ tape[ptr] += 5;
+ while (tape[ptr] != 0)
+ {
+ ptr -= 1;
+ tape[ptr] += 11;
+ ptr += 1;
+ tape[ptr] -= 1;
+ }
+ ptr -= 1;
+ printchar(tape[ptr]);
+ ptr += 1;
+ tape[ptr] += 4;
+ while (tape[ptr] != 0)
+ {
+ ptr -= 1;
+ tape[ptr] += 6;
+ ptr += 1;
+ tape[ptr] -= 1;
+ }
+ ptr -= 1;
+ printchar(tape[ptr]);
+ tape[ptr] += 3;
+ printchar(tape[ptr]);
+ tape[ptr] -= 6;
+ printchar(tape[ptr]);
+ tape[ptr] -= 8;
+ printchar(tape[ptr]);
+ ptr += 1;
+ tape[ptr] += 3;
+ while (tape[ptr] != 0)
+ {
+ ptr += 1;
+ tape[ptr] += 11;
+ ptr -= 1;
+ tape[ptr] -= 1;
+ }
+ ptr += 1;
+ printchar(tape[ptr]);
+ ptr += 1;
+ tape[ptr] += 10;
+ printchar(tape[ptr]);
+ return;
+}
+
diff --git a/c/bfhello/bfhello.elf b/c/bfhello/bfhello.elf
new file mode 100755
index 0000000..fea2048
--- /dev/null
+++ b/c/bfhello/bfhello.elf
Binary files differ
diff --git a/c/bfhello/bfhello.hex b/c/bfhello/bfhello.hex
new file mode 100644
index 0000000..c21b4ac
--- /dev/null
+++ b/c/bfhello/bfhello.hex
@@ -0,0 +1,27 @@
+:10000000370101002920A9487300000082804EB802
+:10001000130101801301018805650A95233485FACF
+:1000200028009305F57F9385157A23200500110597
+:10003000E31DB5FE2245B245130685003365A520B4
+:100040002E9513058504B3F5C50E3355C50EB3E4DF
+:10005000A50013F5F40FC1201385D401619D652817
+:1000600013844402619C22857D2022856D201385A6
+:100070007402619D4D204245D2451306450033650B
+:10008000B52013050502B3F5C50E3355C50E33E48F
+:10009000A5001375F40F41206245930555003346C2
+:1000A000A5203325A6202295130575033376B40EBB
+:1000B0003355B50E3364A6001375F40FA928130544
+:1000C0008401619D89281305B401619DA920130550
+:1000D0005401619D89201305D400619D2D2803459D
+:1000E000C10113051502619D3D200345010229054B
+:1000F000619D85658A9503B485FA1301017F13011B
+:1001000001794EBA09A885487300000082809148A1
+:10011000730000008280AD48730000008280930865
+:1001200010087300000082809308500873000000DC
+:10013000828093087008730000008280732510C0CD
+:100140008280732500C082809308600873000000DD
+:1001500082800589F322008093920248B3E2A200D4
+:10016000739002808280954873000000828093081B
+:100170000008730000008280A148730000008280A4
+:1001800093083008730000008280930840087300D1
+:040190000000828069
+:00000001FF
diff --git a/c/bfhello/bfhello.o b/c/bfhello/bfhello.o
new file mode 100644
index 0000000..c206039
--- /dev/null
+++ b/c/bfhello/bfhello.o
Binary files differ
diff --git a/c/bfhello/rvcontroller.ld b/c/bfhello/rvcontroller.ld
new file mode 100644
index 0000000..985892b
--- /dev/null
+++ b/c/bfhello/rvcontroller.ld
@@ -0,0 +1,45 @@
+/* Thanks https://github.com/darklife/darkriscv */
+ __heap_size = 0x200; /* required amount of heap */
+ __stack_size = 0x800; /* required amount of stack */
+ ENTRY(_start);
+ MEMORY
+ {
+ RAM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x10000
+ }
+ SECTIONS
+ {
+ .text :
+ {
+ *(.text.startup)
+ *(.text)
+ *(.text)
+ *(.rodata*)
+ } > RAM
+ .data :
+ {
+ *(.sbss)
+ *(.data)
+ *(.bss)
+ *(.rela*)
+ *(COMMON)
+ } > RAM
+
+ .heap :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ _sheap = .;
+ . = . + __heap_size;
+ . = ALIGN(4);
+ _eheap = .;
+ } >RAM
+
+ .stack :
+ {
+ . = ALIGN(4);
+ _estack = .;
+ . = . + __stack_size;
+ . = ALIGN(4);
+ _sstack = .;
+ } >RAM
+ }
diff --git a/c/bigfib/Makefile b/c/bigfib/Makefile
new file mode 100644
index 0000000..6eb4ffc
--- /dev/null
+++ b/c/bigfib/Makefile
@@ -0,0 +1,20 @@
+all: bigfib.hex
+
+bigfib.o: bigfib.c
+ clang -target riscv32-none-elf -I../rvcontroller-libraries -march=rv32imacb_zicntr_zicond_zicsr_zifencei_zihintpause_zilsd_zclsd_zabha_zacas_zbkb_zbkx_zcb_zcmp_zcmt -ffreestanding -O3 -c -o bigfib.o bigfib.c
+
+bigfib.elf: ../rvcontroller-libraries/rvcontroller-init.o ../rvcontroller-libraries/rvcontroller-ecalls.o bigfib.o
+ riscv32-none-elf-ld -T rvcontroller.ld --no-warn-rwx-segments -o bigfib.elf ../rvcontroller-libraries/rvcontroller-init.o bigfib.o ../rvcontroller-libraries/rvcontroller-ecalls.o
+
+dump: bigfib.elf
+ riscv32-none-elf-objdump -d bigfib.elf
+
+bigfib.hex: bigfib.elf
+ riscv32-none-elf-objcopy -O ihex bigfib.elf bigfib.hex
+
+load: bigfib.hex
+ bash -c "wl-copy < bigfib.hex"
+
+clean:
+ rm -f bigfib.bin bigfib.elf bigfib.o init.o
+
diff --git a/c/bigfib/bigfib.c b/c/bigfib/bigfib.c
new file mode 100644
index 0000000..063c27e
--- /dev/null
+++ b/c/bigfib/bigfib.c
@@ -0,0 +1,23 @@
+/* Fibonacci Sequence for RVController
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+#include <stdint.h>
+#include "rvcontroller-ecalls.h"
+
+uint64_t prev = 0;
+uint64_t oldprev = 0;
+uint64_t curr = 1;
+
+void main(void) {
+ while ((curr & 0x800000000000000) == 0 ) {
+ printstr("\nH ");
+ printint(curr/(1LL << 32));
+ printstr("\nL ");
+ printint(curr%(1LL << 32));
+ oldprev = prev;
+ prev = curr;
+ curr = prev + oldprev;
+ }
+}
diff --git a/c/bigfib/bigfib.elf b/c/bigfib/bigfib.elf
new file mode 100755
index 0000000..2fcdf75
--- /dev/null
+++ b/c/bigfib/bigfib.elf
Binary files differ
diff --git a/c/bigfib/bigfib.hex b/c/bigfib/bigfib.hex
new file mode 100644
index 0000000..b13c263
--- /dev/null
+++ b/c/bigfib/bigfib.hex
@@ -0,0 +1,19 @@
+:10000000370101002920A94873000000828096B8BA
+:1000100022E44AE003457010218939E1B70900085C
+:100020001309400F130A800F930480104A85812022
+:10003000032540100D2852851D280325001025207A
+:1000400003350010906088E090E4B6952A96333529
+:10005000A600B386A50033F536012330C01079D54C
+:100060002264026996BE8548730000008280914830
+:10007000730000008280AD48730000008280930806
+:10008000100873000000828093085008730000007D
+:10009000828093087008730000008280732510C06E
+:1000A0008280732500C0828093086008730000007E
+:1000B00082800589F322008093920248B3E2A20075
+:1000C00073900280828095487300000082809308BC
+:1000D0000008730000008280A14873000000828045
+:1000E0009308300873000000828093084008730072
+:0C00F000000082800A4820000A4C20001A
+:1001000001000000000000000000000000000000EE
+:080110000000000000000000E7
+:00000001FF
diff --git a/c/bigfib/bigfib.o b/c/bigfib/bigfib.o
new file mode 100644
index 0000000..32d9e29
--- /dev/null
+++ b/c/bigfib/bigfib.o
Binary files differ
diff --git a/c/bigfib/rvcontroller.ld b/c/bigfib/rvcontroller.ld
new file mode 100644
index 0000000..985892b
--- /dev/null
+++ b/c/bigfib/rvcontroller.ld
@@ -0,0 +1,45 @@
+/* Thanks https://github.com/darklife/darkriscv */
+ __heap_size = 0x200; /* required amount of heap */
+ __stack_size = 0x800; /* required amount of stack */
+ ENTRY(_start);
+ MEMORY
+ {
+ RAM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x10000
+ }
+ SECTIONS
+ {
+ .text :
+ {
+ *(.text.startup)
+ *(.text)
+ *(.text)
+ *(.rodata*)
+ } > RAM
+ .data :
+ {
+ *(.sbss)
+ *(.data)
+ *(.bss)
+ *(.rela*)
+ *(COMMON)
+ } > RAM
+
+ .heap :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ _sheap = .;
+ . = . + __heap_size;
+ . = ALIGN(4);
+ _eheap = .;
+ } >RAM
+
+ .stack :
+ {
+ . = ALIGN(4);
+ _estack = .;
+ . = . + __stack_size;
+ . = ALIGN(4);
+ _sstack = .;
+ } >RAM
+ }
diff --git a/c/drawercalc/Makefile b/c/drawercalc/Makefile
new file mode 100644
index 0000000..52f47d1
--- /dev/null
+++ b/c/drawercalc/Makefile
@@ -0,0 +1,20 @@
+all: drawercalc.hex
+
+drawercalc.o: drawercalc.c
+ clang -target riscv32-none-elf -I../rvcontroller-libraries -march=rv32imacb_zicntr_zicond_zicsr_zifencei_zihintpause_zilsd_zclsd_zabha_zacas_zbkb_zbkx_zcb_zcmp_zcmt -ffreestanding -O3 -c -o drawercalc.o drawercalc.c
+
+drawercalc.elf: ../rvcontroller-libraries/rvcontroller-init.o ../rvcontroller-libraries/rvcontroller-ecalls.o drawercalc.o
+ riscv32-none-elf-ld -T rvcontroller.ld --no-warn-rwx-segments -o drawercalc.elf ../rvcontroller-libraries/rvcontroller-init.o drawercalc.o ../rvcontroller-libraries/rvcontroller-ecalls.o
+
+dump: drawercalc.elf
+ riscv32-none-elf-objdump -d drawercalc.elf
+
+drawercalc.hex: drawercalc.elf
+ riscv32-none-elf-objcopy -O ihex drawercalc.elf drawercalc.hex
+
+load: drawercalc.hex
+ bash -c "wl-copy < drawercalc.hex"
+
+clean:
+ rm -f drawercalc.bin drawercalc.elf drawercalc.o init.o
+
diff --git a/c/drawercalc/drawercalc.c b/c/drawercalc/drawercalc.c
new file mode 100644
index 0000000..1d2de03
--- /dev/null
+++ b/c/drawercalc/drawercalc.c
@@ -0,0 +1,129 @@
+/* Drawer Capacity Calculator for RVController
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "rvcontroller-ecalls.h"
+
+#define BASE_SLOTS 32
+#define STACK_MAX 99
+#define STEEL_UPGRADE_MULT 1
+#define GOLD_UPGRADE_MULT 2
+#define OBSIDIAN_UPGRADE_MULT 3
+#define DIAMOND_UPGRADE_MULT 7
+#define MITHRIL_UPGRADE_MULT 12
+
+bool checkUpgradeCount(int32_t count,int32_t maxcount) {
+ return (count >= 0 && count <= maxcount);
+}
+
+void main(void) {
+ while (true) {
+ int32_t capacity = BASE_SLOTS * STACK_MAX;
+ uint8_t upgrades_used = 0;
+ printstr("\n\n\nSettings:\n");
+ printstr("Base Stack Count: ");
+ printint(BASE_SLOTS);
+ printstr("\nMax Stack Size: ");
+ printint(STACK_MAX);
+ printchar('\n');
+
+ int32_t upgcount = 0;
+ while (true) {
+ printstr("\nSteel Upgrades?\n[0-5] > ");
+ upgcount = readint();
+ printint(upgcount);
+ printchar('\n');
+ if (checkUpgradeCount(upgcount,5)) {
+ break;
+ } else {
+ printstr("Invalid entry");
+ }
+ }
+ upgrades_used += upgcount;
+ capacity += BASE_SLOTS * STACK_MAX * STEEL_UPGRADE_MULT * upgcount;
+
+ if (upgrades_used < 5) {
+ while (true) {
+ printstr("\nGold Upgrades?\n[0-");
+ printint(5-upgrades_used);
+ printstr("] > ");
+ upgcount = readint();
+ printint(upgcount);
+ printchar('\n');
+ if (checkUpgradeCount(upgcount,5-upgrades_used)) {
+ break;
+ } else {
+ printstr("Invalid entry");
+ }
+ }
+ upgrades_used += upgcount;
+ capacity += BASE_SLOTS * STACK_MAX * GOLD_UPGRADE_MULT * upgcount;
+ }
+
+ if (upgrades_used < 5) {
+ while (true) {
+ printstr("\nObsidian Upgrades?\n[0-");
+ printint(5-upgrades_used);
+ printstr("] > ");
+ upgcount = readint();
+ printint(upgcount);
+ printchar('\n');
+ if (checkUpgradeCount(upgcount,5-upgrades_used)) {
+ break;
+ } else {
+ printstr("Invalid entry");
+ }
+ }
+ upgrades_used += upgcount;
+ capacity += BASE_SLOTS * STACK_MAX * OBSIDIAN_UPGRADE_MULT * upgcount;
+ }
+
+ if (upgrades_used < 5) {
+ while (true) {
+ printstr("\nDiamond Upgrades?\n[0-");
+ printint(5-upgrades_used);
+ printstr("] > ");
+ upgcount = readint();
+ printint(upgcount);
+ printchar('\n');
+ if (checkUpgradeCount(upgcount,5-upgrades_used)) {
+ break;
+ } else {
+ printstr("Invalid entry");
+ }
+ }
+ upgrades_used += upgcount;
+ capacity += BASE_SLOTS * STACK_MAX * DIAMOND_UPGRADE_MULT * upgcount;
+ }
+
+ if (upgrades_used < 5) {
+ while (true) {
+ printstr("\nMithril Upgrades?\n[0-");
+ printint(5-upgrades_used);
+ printstr("] > ");
+ upgcount = readint();
+ printint(upgcount);
+ printchar('\n');
+ if (checkUpgradeCount(upgcount,5-upgrades_used)) {
+ break;
+ } else {
+ printstr("Invalid entry");
+ }
+ }
+ upgrades_used += upgcount;
+ capacity += BASE_SLOTS * STACK_MAX * MITHRIL_UPGRADE_MULT * upgcount;
+ }
+
+ printstr("\n1 slot: ");
+ printint(capacity);
+ printstr("\n2 slots: ");
+ printint(capacity/2);
+ printstr("\n4 slots: ");
+ printint(capacity/4);
+ printstr("\nPress 0 to run again\n");
+ upgcount = readint();
+ }
+}
diff --git a/c/drawercalc/drawercalc.elf b/c/drawercalc/drawercalc.elf
new file mode 100755
index 0000000..be34b55
--- /dev/null
+++ b/c/drawercalc/drawercalc.elf
Binary files differ
diff --git a/c/drawercalc/drawercalc.hex b/c/drawercalc/drawercalc.hex
new file mode 100644
index 0000000..b66fc63
--- /dev/null
+++ b/c/drawercalc/drawercalc.hex
@@ -0,0 +1,56 @@
+:10000000370101002928A948730000008280135697
+:10001000F50133A5A500518D1345150082804EB81A
+:100020000111A2E4CAE052FC5AF862F46AF00565D4
+:100030001309C0279304A0281304D029930BF02A96
+:10004000194B9549930C702D130D402C130C902CCB
+:100050008965930DB02E1566A566130505C62ACED3
+:100060001385058C2ACC138505522ACA1305066A06
+:100070002AC8138506482AC63DA83245419D2A9ABA
+:100080005A899304A0281304D029194B130510335F
+:100090009D225285A92A1305B033B12A13551A009F
+:1000A000B92213056034812A13552A0089221305C9
+:1000B00010359122692A4A853D2A26852D2A130565
+:1000C000000235222285052A130530060D22294516
+:1000D0003D225E850D22A52AAA8A112A29450522DC
+:1000E00063ED6A016285012A5E8531228D22AA8A2A
+:1000F000FD2829452922E3E759FF7245338AAA02E0
+:100100002A9AE3853AF96685FD20338B59415A8551
+:10011000F9286A85CD20252AAA84D1282945C52019
+:1001200063779B006285C1286685F120CDB7A69ACA
+:100130006245459D2A9A1145E36555F54A8B6E85C2
+:100140005D28B384594126855D206A856D20012292
+:100150002A847128294565201309303063F184020F
+:10016000628551286E854128268551206A85612047
+:10017000F9282A84AD2829455920E3E384FEA29A70
+:100180005245419D2A9A1145E36C55EF4A85A520B9
+:10019000B38459412685A1286A85B1284D282A842F
+:1001A000B9202945A92863F784006285A9204A85DA
+:1001B0009920CDB7A29A4245419D2A9A1145E36103
+:1001C00055ED1309A0314A853D20B3845941268558
+:1001D00039286A850D20A5282A841128294505205B
+:1001E000E3FD84E8628501284A853120CDB7854842
+:1001F0007300000082809148730000008280AD4847
+:100200007300000082809308100873000000828051
+:1002100093085008730000008280930870087300F0
+:1002200000008280732510C08280732500C0828008
+:10023000930860087300000082800589F322008023
+:1002400093920248B3E2A2007390028082809548A4
+:100250007300000082809308000873000000828011
+:10026000A1487300000082809308300873000000EA
+:100270008280930840087300000082800A0A0A53B3
+:10028000657474696E67733A0A004261736520533E
+:100290007461636B20436F756E743A20000A4D6180
+:1002A0007820537461636B2053697A653A20000AA1
+:1002B000537465656C2055706772616465733F0A9D
+:1002C0005B302D355D203E2000496E76616C69649F
+:1002D00020656E747279000A476F6C6420557067F0
+:1002E00072616465733F0A5B302D000A4F62736967
+:1002F0006469616E2055706772616465733F0A5B63
+:10030000302D000A4469616D6F6E6420557067720C
+:10031000616465733F0A5B302D000A4D6974687231
+:10032000696C2055706772616465733F0A5B302D9C
+:10033000000A3120736C6F743A20000A3220736C0B
+:100340006F74733A20000A3420736C6F74733A2010
+:10035000000A5072657373203020746F2072756EBE
+:0803600020616761696E0A006B
+:00000001FF
diff --git a/c/drawercalc/drawercalc.o b/c/drawercalc/drawercalc.o
new file mode 100644
index 0000000..fac534a
--- /dev/null
+++ b/c/drawercalc/drawercalc.o
Binary files differ
diff --git a/c/drawercalc/rvcontroller.ld b/c/drawercalc/rvcontroller.ld
new file mode 100644
index 0000000..985892b
--- /dev/null
+++ b/c/drawercalc/rvcontroller.ld
@@ -0,0 +1,45 @@
+/* Thanks https://github.com/darklife/darkriscv */
+ __heap_size = 0x200; /* required amount of heap */
+ __stack_size = 0x800; /* required amount of stack */
+ ENTRY(_start);
+ MEMORY
+ {
+ RAM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x10000
+ }
+ SECTIONS
+ {
+ .text :
+ {
+ *(.text.startup)
+ *(.text)
+ *(.text)
+ *(.rodata*)
+ } > RAM
+ .data :
+ {
+ *(.sbss)
+ *(.data)
+ *(.bss)
+ *(.rela*)
+ *(COMMON)
+ } > RAM
+
+ .heap :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ _sheap = .;
+ . = . + __heap_size;
+ . = ALIGN(4);
+ _eheap = .;
+ } >RAM
+
+ .stack :
+ {
+ . = ALIGN(4);
+ _estack = .;
+ . = . + __stack_size;
+ . = ALIGN(4);
+ _sstack = .;
+ } >RAM
+ }
diff --git a/c/elevator/Makefile b/c/elevator/Makefile
new file mode 100644
index 0000000..875cd3b
--- /dev/null
+++ b/c/elevator/Makefile
@@ -0,0 +1,20 @@
+all: elevator.hex
+
+elevator.o: elevator.c
+ clang -target riscv32-none-elf -I../rvcontroller-libraries -march=rv32imacb_zicntr_zicond_zicsr_zifencei_zihintpause_zilsd_zclsd_zabha_zacas_zbkb_zbkx_zcb_zcmp_zcmt -ffreestanding -O3 -c -o elevator.o elevator.c
+
+elevator.elf: ../rvcontroller-libraries/rvcontroller-init.o ../rvcontroller-libraries/rvcontroller-ecalls.o elevator.o
+ riscv32-none-elf-ld -T rvcontroller.ld --no-warn-rwx-segments -o elevator.elf ../rvcontroller-libraries/rvcontroller-init.o elevator.o ../rvcontroller-libraries/rvcontroller-ecalls.o
+
+dump: elevator.elf
+ riscv32-none-elf-objdump -d elevator.elf
+
+elevator.hex: elevator.elf
+ riscv32-none-elf-objcopy -O ihex elevator.elf elevator.hex
+
+load: elevator.hex
+ bash -c "wl-copy < elevator.hex"
+
+clean:
+ rm -f elevator.bin elevator.elf elevator.o init.o
+
diff --git a/c/elevator/elevator.c b/c/elevator/elevator.c
new file mode 100644
index 0000000..845a57e
--- /dev/null
+++ b/c/elevator/elevator.c
@@ -0,0 +1,230 @@
+/* Conway's Game of Life for RVController
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "rvcontroller-ecalls.h"
+#include "states.h"
+
+int state = STATE_INIT;
+bool sensor1state = false;
+bool sensor2state = false;
+bool sensor3state = false;
+bool call1state = false;
+bool call2state = false;
+bool call3state = false;
+int direction = DIRECTION_UP;
+int timer;
+
+char channelbuf[16];
+char msgbuf[64];
+
+bool streq(char *a, char *b) {
+ for (int i=0;a[i] != 0 || b[i] != 0;i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void sleep(uint32_t delay) {
+ //This will start having problems after about 130 years
+ //of uptime, but that's probably acceptable
+ uint32_t endtime = rdtime() + delay;
+ while (rdtime() < endtime) {}
+ return;
+}
+
+void sendSensorGetMessages(void) {
+ digiline_send("sensor1","GET");
+ digiline_send("sensor2","GET");
+ digiline_send("sensor3","GET");
+}
+
+void processDigilinesMessages(void) {
+ while (digiline_bufferlevel() > 0) {
+ digiline_receive(channelbuf,16,msgbuf,64);
+ if (streq(channelbuf,"sensor1")) {
+ sensor1state = (streq(msgbuf,"mesecons_movestones:movestone_vertical"));
+ } else if (streq(channelbuf,"sensor2")) {
+ sensor2state = (streq(msgbuf,"mesecons_movestones:movestone_vertical"));
+ } else if (streq(channelbuf,"sensor3")) {
+ sensor3state = (streq(msgbuf,"mesecons_movestones:movestone_vertical"));
+ } else if (streq(channelbuf,"button1") && (state != STATE_TIMING_1) && (state != STATE_IDLE_1)) {
+ call1state = true;
+ digiline_send("button1","light_on");
+ } else if (streq(channelbuf,"button2") && (state != STATE_TIMING_2) && (state != STATE_IDLE_2)) {
+ call2state = true;
+ digiline_send("button2","light_on");
+ } else if (streq(channelbuf,"button3") && (state != STATE_TIMING_3) && (state != STATE_IDLE_3)) {
+ call3state = true;
+ digiline_send("button3","light_on");
+ }
+ }
+}
+
+void main(void) {
+ while (true) {
+ sendSensorGetMessages();
+ processDigilinesMessages();
+ switch (state) {
+ case STATE_INIT:
+ printstr("\nElevator Controller\nfor RVController\nInitializing");
+ digiline_send("door1","extend");
+ digiline_send("door2","extend");
+ digiline_send("door3","extend");
+ digiline_send("sel","extend");
+ digiline_send("down","extend");
+ digiline_send("up","retract_sticky");
+ digiline_send("button1","light_off");
+ digiline_send("button2","light_off");
+ digiline_send("button3","light_off");
+ printstr("\nBottom Floor Demand");
+ state = STATE_BOTTOM_FLOOR_DEMAND;
+ break;
+ case STATE_BOTTOM_FLOOR_DEMAND:
+ if (sensor1state) {
+ printstr("\nBFD Complete");
+ digiline_send("down","retract_sticky");
+ digiline_send("door1","retract_sticky");
+ state = STATE_TIMING_1;
+ timer = 5;
+ }
+ break;
+ case STATE_TIMING_1:
+ timer--;
+ if (timer <= 0) {
+ printstr("\nIdle at 1");
+ state = STATE_IDLE_1;
+ }
+ break;
+ case STATE_TIMING_2:
+ timer--;
+ if (timer <= 0) {
+ printstr("\nIdle at 2");
+ state = STATE_IDLE_2;
+ }
+ break;
+ case STATE_TIMING_3:
+ timer--;
+ if (timer <= 0) {
+ printstr("\nIdle at 3");
+ state = STATE_IDLE_3;
+ }
+ break;
+ case STATE_IDLE_1:
+ if (call2state) {
+ direction = DIRECTION_UP;
+ printstr("\nMoving to 2");
+ state = STATE_MOVING_2;
+ digiline_send("door1","extend");
+ digiline_send("sel","retract_sticky");
+ digiline_send("up","extend");
+ } else if (call3state) {
+ direction = DIRECTION_UP;
+ printstr("\nMoving to 3");
+ state = STATE_MOVING_3;
+ digiline_send("door1","extend");
+ digiline_send("sel","extend");
+ digiline_send("up","extend");
+ }
+ break;
+ case STATE_IDLE_2:
+ if (direction == DIRECTION_UP) {
+ if (call3state) {
+ direction = DIRECTION_UP;
+ printstr("\nMoving to 3");
+ state = STATE_MOVING_3;
+ digiline_send("door2","extend");
+ digiline_send("sel","extend");
+ digiline_send("up","extend");
+ } else if (call1state) {
+ direction = DIRECTION_DOWN;
+ printstr("\nMoving to 1");
+ state = STATE_MOVING_1;
+ digiline_send("door2","extend");
+ digiline_send("sel","extend");
+ digiline_send("down","extend");
+ }
+ } else {
+ if (call1state) {
+ direction = DIRECTION_DOWN;
+ printstr("\nMoving to 1");
+ state = STATE_MOVING_1;
+ digiline_send("door2","extend");
+ digiline_send("sel","extend");
+ digiline_send("down","extend");
+ } else if (call3state) {
+ direction = DIRECTION_UP;
+ printstr("\nMoving to 3");
+ state = STATE_MOVING_3;
+ digiline_send("door2","extend");
+ digiline_send("sel","extend");
+ digiline_send("up","extend");
+ }
+ }
+ break;
+ case STATE_IDLE_3:
+ if (call2state) {
+ direction = DIRECTION_DOWN;
+ printstr("\nMoving to 2");
+ state = STATE_MOVING_2;
+ digiline_send("door3","extend");
+ digiline_send("sel","retract_sticky");
+ digiline_send("down","extend");
+ } else if (call1state) {
+ direction = DIRECTION_DOWN;
+ printstr("\nMoving to 1");
+ state = STATE_MOVING_1;
+ digiline_send("door3","extend");
+ digiline_send("sel","extend");
+ digiline_send("down","extend");
+ }
+ break;
+ case STATE_MOVING_1:
+ if (sensor1state) {
+ printstr("\nArrived at 1");
+ digiline_send("button1","light_off");
+ direction = DIRECTION_UP;
+ digiline_send("down","retract_sticky");
+ digiline_send("door1","retract_sticky");
+ timer = 5;
+ state = STATE_TIMING_1;
+ call1state = false;
+ }
+ break;
+ case STATE_MOVING_2:
+ if (sensor2state) {
+ printstr("\nArrived at 2");
+ digiline_send("button2","light_off");
+ digiline_send("up","retract_sticky");
+ digiline_send("down","retract_sticky");
+ digiline_send("door2","retract_sticky");
+ timer = 5;
+ state = STATE_TIMING_2;
+ call2state = false;
+ }
+ break;
+ case STATE_MOVING_3:
+ if (sensor3state) {
+ printstr("\nArrived at 3");
+ digiline_send("button3","light_off");
+ direction = DIRECTION_DOWN;
+ digiline_send("up","retract_sticky");
+ digiline_send("door3","retract_sticky");
+ timer = 5;
+ state = STATE_TIMING_3;
+ call3state = false;
+ }
+ break;
+ }
+ if ((state == STATE_IDLE_1) || (state == STATE_IDLE_2) || (state == STATE_IDLE_3)) {
+ lightweight_mode(1);
+ sleep(1);
+ lightweight_mode(0);
+ }
+ }
+}
diff --git a/c/elevator/elevator.elf b/c/elevator/elevator.elf
new file mode 100755
index 0000000..9b5cafc
--- /dev/null
+++ b/c/elevator/elevator.elf
Binary files differ
diff --git a/c/elevator/elevator.hex b/c/elevator/elevator.hex
new file mode 100644
index 0000000..2da4185
--- /dev/null
+++ b/c/elevator/elevator.hex
@@ -0,0 +1,135 @@
+:10000000370101008124A948730000008280148117
+:10001000988133E6E60009C685050505E389E6FE15
+:1000200013351600828052B82A84C92B2A94F923EA
+:10003000E36F85FE52BE46B822E422E00145130577
+:100040000068014413048068A285512B0145130503
+:10005000C068A2856923014513054069A285226411
+:10006000026446BAADAB4EB822F44AF052EC5AE8FC
+:1000700062E46AE0952B6300051C014B130BC07E04
+:10008000814B930B0068014C130CC069814C014DEE
+:10009000130DC068814D930D4069814A930A306CFD
+:1000A0000949014A130A406D81499309C06D9304BF
+:1000B0004B0113044B0201A813B516002306A07EC2
+:1000C0002523630A0516C14593060004268522866A
+:1000D0000D23FEAC1D4614813367D6003DC39881C5
+:1000E0007D1685050505E388E6FE1D45A6856A861D
+:1000F00094813367D5002DC718827D1505068505C7
+:10010000E388E6FE13054B019D456E86148133E7B7
+:10011000D50035CB1882FD1505060505E388E6FEFA
+:1001200013054B019D455686148133E7D50041C325
+:100130001882FD1505060505E388E6FE03258B00FC
+:10014000B5A813056002A28562869881B366E500B2
+:10015000A5D61C827D1505068505E308F7FEA9BF17
+:1001600013056002A28562869881B366E50099C690
+:100170001C827D1505068505E308F7FE13B51600FC
+:10018000A306A07E35BF13054B029305600262866D
+:100190001881B3E6E50099C61C82FD150506050524
+:1001A000E308F7FE13B516002307A07E11BF032551
+:1001B0008B006305250195456311B50693054B0139
+:1001C0001D46D2869881B367E60081CB9C827D165E
+:1001D00085068505E308F7FE39A099456305B50056
+:1001E0008D456311B50493054B011D46CE8698815C
+:1001F000B367E60081CB9C827D1685068505E30802
+:10020000F7FE7DBD9145E30DB5EA9D45E30AB5EAEC
+:100210000545A302AB004E8511A80545A307A07EA6
+:10022000568529A005452302AB00528581459305DB
+:10023000B06C752671B522740279626A426B226CC9
+:10024000026D4EBE4EB822F44AF052EC5AE862E417
+:100250006AE0014913090068814493048068814978
+:100260009309C068814C930C4069014C130CC07E0B
+:10027000A94A894D0544014D130D4065014B130BEF
+:10028000D071014A130AC07366AD912EE6AD812E7E
+:100290006685A685A926C13B03258C0063E5AA30A7
+:1002A0003345A5210841028501451305406E052609
+:1002B000014513057071DA851D260145130540724D
+:1002C000DA85312E01451305A072DA85092E014524
+:1002D00013050073DA852126014513054073DA857D
+:1002E000FD2C014513059073D285D52C01451305CE
+:1002F000306C01441304B074A285D5240145130564
+:10030000406DA285E92C01451305C06DA285054409
+:10031000F9240145130550755D2C23248C0061A43C
+:1003200003250C019305F5FF2328BC00634DA4268B
+:1003300001451305E078612C1D452324AC00A5A4DC
+:1003400001450345D07E6300052601451305E07C89
+:10035000BD2C01451305406D81459305B0744124C2
+:10036000014513059073D2859D2C014513054073FB
+:10037000D285B524014513054072D2858D24230210
+:100380000C000D4535A203250C019305F5FF23282C
+:10039000BC00634AA4200145130580770D2C154548
+:1003A0002324AC0009A403250C019305F5FF2328A1
+:1003B000BC00634AA41E014513053078092C194579
+:1003C0002324AC00CDA203454C000589630A051225
+:1003D00023268C00014513059079D52A2545232431
+:1003E000AC0001451305A072DA85D52A0145130535
+:1003F0000073D2855DA201450345C07E0589630473
+:10040000051A01451305A076D9220145130540734D
+:10041000D285F122014513057071D285C922D9A870
+:1004200003454C000589630E050E23260C0001458B
+:1004300013059079692A25452324AC00014513054D
+:100440007071DA85692A014513050073D28519AAEE
+:100450000325CC006306050E01450345F07E631CB1
+:10046000051003455C006300051423260C00E1A879
+:1004700001450345E07E0589630705120145130523
+:10048000C07DB12201451305C06D81459305B0744F
+:10049000B92223268C00014513059073D285812251
+:1004A00001451305A072D2851D2AA3020C00114537
+:1004B0002324AC0091A001450345C07E0589630457
+:1004C000050E01451305007C192201451305306C0A
+:1004D00081459305B074212223260C0001451305A4
+:1004E0004073D285ED28014513057071D285C5286A
+:1004F000A3010C002324BC0115452328AC0065A0F2
+:1005000001450345F07E45C123268C0001451305B6
+:10051000307B752821452324AC0001451305A072CA
+:10052000BDA003455C0041C123260C000145130515
+:10053000607A712823245C0101451305707129A894
+:1005400003455C000DC501451305607A492023244D
+:100550005C01014513054072DA8551200145130500
+:100560000073DA85AD280145130590731DA8014578
+:100570000345F07E0DC923268C0001451305307B11
+:10058000B92021452324AC00014513054072DA85CA
+:10059000B920014513050073DA8591200145130543
+:1005A0004073DA852D2803258C006D15E3EEADCC64
+:1005B00005458520A120930B15008920E36F75FF69
+:1005C00001458128D1B1854873000000828091489F
+:1005D000730000008280AD487300000082809308A1
+:1005E0001008730000008280930850087300000018
+:1005F000828093087008730000008280732510C009
+:100600008280732500C08280930860087300000018
+:1006100082800589F322008093920248B3E2A2000F
+:100620007390028082809548730000008280930856
+:100630000008730000008280A148730000008280DF
+:10064000930830087300000082809308400873000C
+:1006500000008280A8020000F6030000860300006C
+:10066000A603000020030000200400005004000046
+:10067000C6030000B6040000400300007004000040
+:1006800073656E736F7231004745540073656E7306
+:100690006F72320073656E736F7233006D657365D0
+:1006A000636F6E735F6D6F766573746F6E65733AAB
+:1006B0006D6F766573746F6E655F7665727469636E
+:1006C000616C00627574746F6E31006C6967687478
+:1006D0005F6F6E00627574746F6E32006275747451
+:1006E0006F6E33000A456C657661746F7220436FDC
+:1006F0006E74726F6C6C65720A666F72205256432C
+:100700006F6E74726F6C6C65720A496E69746961A0
+:100710006C697A696E6700646F6F72310065787416
+:10072000656E6400646F6F723200646F6F723300C5
+:1007300073656C00646F776E00757000726574721B
+:100740006163745F737469636B79006C6967687463
+:100750005F6F6666000A426F74746F6D20466C6F3F
+:100760006F722044656D616E64000A424644204306
+:100770006F6D706C657465000A49646C6520617406
+:100780002031000A49646C652061742032000A49F6
+:10079000646C652061742033000A4D6F76696E6762
+:1007A00020746F2032000A4D6F76696E6720746F77
+:1007B0002033000A4D6F76696E6720746F20310018
+:1007C0000A417272697665642061742031000A41C1
+:1007D0007272697665642061742032000A41727217
+:0A07E000697665642061742033001F
+:1007EC0000000000000000000000000000000000FD
+:1007FC0000000000000000000000000000000000ED
+:10080C0000000000000000000000000000000000DC
+:10081C0000000000000000000000000000000000CC
+:10082C0000000000000000000000000000000000BC
+:10083C0000000000000000000000000000000000AC
+:04084C0000000000A8
+:00000001FF
diff --git a/c/elevator/elevator.o b/c/elevator/elevator.o
new file mode 100644
index 0000000..834800b
--- /dev/null
+++ b/c/elevator/elevator.o
Binary files differ
diff --git a/c/elevator/rvcontroller.ld b/c/elevator/rvcontroller.ld
new file mode 100644
index 0000000..985892b
--- /dev/null
+++ b/c/elevator/rvcontroller.ld
@@ -0,0 +1,45 @@
+/* Thanks https://github.com/darklife/darkriscv */
+ __heap_size = 0x200; /* required amount of heap */
+ __stack_size = 0x800; /* required amount of stack */
+ ENTRY(_start);
+ MEMORY
+ {
+ RAM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x10000
+ }
+ SECTIONS
+ {
+ .text :
+ {
+ *(.text.startup)
+ *(.text)
+ *(.text)
+ *(.rodata*)
+ } > RAM
+ .data :
+ {
+ *(.sbss)
+ *(.data)
+ *(.bss)
+ *(.rela*)
+ *(COMMON)
+ } > RAM
+
+ .heap :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ _sheap = .;
+ . = . + __heap_size;
+ . = ALIGN(4);
+ _eheap = .;
+ } >RAM
+
+ .stack :
+ {
+ . = ALIGN(4);
+ _estack = .;
+ . = . + __stack_size;
+ . = ALIGN(4);
+ _sstack = .;
+ } >RAM
+ }
diff --git a/c/elevator/states.h b/c/elevator/states.h
new file mode 100644
index 0000000..27fb4d2
--- /dev/null
+++ b/c/elevator/states.h
@@ -0,0 +1,14 @@
+#define STATE_INIT 0
+#define STATE_BOTTOM_FLOOR_DEMAND 1
+#define STATE_TIMING_1 2
+#define STATE_TIMING_2 3
+#define STATE_TIMING_3 4
+#define STATE_IDLE_1 5
+#define STATE_IDLE_2 6
+#define STATE_IDLE_3 7
+#define STATE_MOVING_1 8
+#define STATE_MOVING_2 9
+#define STATE_MOVING_3 10
+
+#define DIRECTION_UP 0
+#define DIRECTION_DOWN 1
diff --git a/c/gol/Makefile b/c/gol/Makefile
new file mode 100644
index 0000000..54e4d4a
--- /dev/null
+++ b/c/gol/Makefile
@@ -0,0 +1,20 @@
+all: gol.hex
+
+gol.o: gol.c
+ clang -target riscv32-none-elf -I../rvcontroller-libraries -march=rv32imacb_zicntr_zicond_zicsr_zifencei_zihintpause_zilsd_zclsd_zabha_zacas_zbkb_zbkx_zcb_zcmp_zcmt -ffreestanding -O3 -c -o gol.o gol.c
+
+gol.elf: ../rvcontroller-libraries/rvcontroller-init.o ../rvcontroller-libraries/rvcontroller-ecalls.o gol.o
+ riscv32-none-elf-ld -T rvcontroller.ld --no-warn-rwx-segments -o gol.elf ../rvcontroller-libraries/rvcontroller-init.o gol.o ../rvcontroller-libraries/rvcontroller-ecalls.o
+
+dump: gol.elf
+ riscv32-none-elf-objdump -d gol.elf
+
+gol.hex: gol.elf
+ riscv32-none-elf-objcopy -O ihex gol.elf gol.hex
+
+load: gol.hex
+ bash -c "wl-copy < gol.hex"
+
+clean:
+ rm -f gol.bin gol.elf gol.o init.o
+
diff --git a/c/gol/gol.c b/c/gol/gol.c
new file mode 100644
index 0000000..1ccb4c4
--- /dev/null
+++ b/c/gol/gol.c
@@ -0,0 +1,89 @@
+/* Conway's Game of Life for RVController
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "rvcontroller-ecalls.h"
+
+bool field[176] = {false}; // 22*8, extra pixel on each edge will just always be false, makes generation logic easier
+bool field2[176] = {false};
+char screenbuf[121] = {'x'}; //20*6 + terminator
+
+void randomFill(void) {
+ for (int y=1;y<=6;y++) {
+ for (int x=1;x<=20;x++) {
+ int cell = (y*22)+x;
+ field[cell] = (randomint(0,1) == 1);
+ }
+ }
+}
+
+void draw(void) {
+ char channelbuf[3] = {0};
+ for (int y=1;y<=6;y++) {
+ channelbuf[1] = 0x30+y;
+ for (int x=1;x<=20;x++) {
+ channelbuf[0] = 0x40+x;
+ int cell = (y*22)+x;
+ int outpos = ((y-1)*20)+x-1;
+ if (field[cell]) {
+ screenbuf[outpos] = '*';
+ digiline_send(channelbuf,"ffaa55");
+ } else {
+ screenbuf[outpos] = ' ';
+ digiline_send(channelbuf,"552200");
+ }
+ }
+ }
+ screenbuf[120] = 0;
+ printstr(screenbuf);
+}
+
+int countLivingCells(int cell) {
+ int count = 0;
+ if (field[cell-23]) { count += 1; } //Up-left
+ if (field[cell-22]) { count += 1; } //Up
+ if (field[cell-21]) { count += 1; } //Up-right
+ if (field[cell-1]) { count += 1; } //Left
+ if (field[cell+1]) { count += 1; } //Right
+ if (field[cell+21]) { count += 1; } //Down-left
+ if (field[cell+22]) { count += 1; } //Down
+ if (field[cell+23]) { count += 1; } //Down-right
+ return count;
+}
+
+void calculateNewGeneration(void) {
+ for (int y=1;y<=6;y++) {
+ for (int x=1;x<=20;x++) {
+ int cell = (y*22)+x;
+ int living = countLivingCells(cell);
+ if (field[cell]) {
+ //Currently alive, stay if 2 or 3
+ field2[cell] = (living == 2 || living == 3);
+ } else {
+ //Not currently alive, spawn if 3
+ field2[cell] = (living == 3);
+ }
+ }
+ }
+}
+
+void copyNewGeneration(void) {
+ for (int y=1;y<=6;y++) {
+ for (int x=1;x<=20;x++) {
+ int cell = (y*22)+x;
+ field[cell] = field2[cell];
+ }
+ }
+}
+
+void main(void) {
+ randomFill();
+ while (true) {
+ draw();
+ calculateNewGeneration();
+ copyNewGeneration();
+ }
+}
diff --git a/c/gol/gol.elf b/c/gol/gol.elf
new file mode 100755
index 0000000..157bcc0
--- /dev/null
+++ b/c/gol/gol.elf
Binary files differ
diff --git a/c/gol/gol.hex b/c/gol/gol.hex
new file mode 100644
index 0000000..0623260
--- /dev/null
+++ b/c/gol/gol.hex
@@ -0,0 +1,463 @@
+:1000000037010100EF107019A948730000008280C9
+:1000100046B822E40965130535B71304A502930415
+:10002000E50A85450145EF10102A7D1513351500A9
+:10003000A306A4FE85450145EF10F0287D15133574
+:1000400015002307A4FE85450145EF10D0277D1537
+:1000500013351500A307A4FE85450145EF10B02612
+:100060007D15133515002308A4FE85450145EF10C5
+:1000700090257D1513351500A308A4FE854501457F
+:10008000EF1070247D15133515002309A4FE854556
+:100090000145EF1050237D1513351500A309A4FE6B
+:1000A00085450145EF1030227D1513351500230AD3
+:1000B000A4FE85450145EF1010217D15133515006F
+:1000C000A30AA4FE85450145EF10F01F7D151335E9
+:1000D0001500230BA4FE85450145EF10D01E7D15AC
+:1000E00013351500A30BA4FE85450145EF10B01D87
+:1000F0007D1513351500230CA4FE85450145EF1031
+:10010000901C7D1513351500A30CA4FE85450145F3
+:10011000EF10701B7D1513351500230DA4FE8545CA
+:100120000145EF10501A7D1513351500A30DA4FEDF
+:1001300085450145EF1030197D1513351500230E47
+:10014000A4FE85450145EF1010187D1513351500E7
+:10015000A30EA4FE85450145EF10F0167D1513355D
+:100160001500230FA4FE85450145EF10D0157D1520
+:1001700013351500A30FA4FE85450145EF10B014FB
+:100180007D151335150008885904E31C94E8226492
+:1001900046BE4EB8411122FC4AF852F45AF062ECC5
+:1001A0006AE813051003130610048969938939B7A7
+:1001B0005959096A130A3AAF89649384C4AE83C556
+:1001C0007901A306C100930A10042307A100A30725
+:1001D00001003375B90E3376BA0EB3D5B40E1305DC
+:1001E000A502D18D09641304A4AF08881305D100BA
+:1001F000EF10700803C5890193052004A306B10020
+:10020000130B2004B375A90E3376AA0E33D5A40EB2
+:100210009386A502B365C50054881305D100EF107D
+:10022000900503C5990193053004A306B100930B13
+:100230003004B375A90E3376AA0E33D5A40E938677
+:10024000A502B365C50034881305D100EF10B002D4
+:1002500003C5A90193054004A306B100130C400493
+:10026000B375A90E3376AA0E33D5A40E9386A502D4
+:10027000B365C50074881305D100EF10C07F03C5B6
+:10028000B90193055004A306B100B375A90E3376E6
+:10029000AA0E33D5A40E9386A502B365C50023022A
+:1002A000D4001305D100EF10007D03C5C9019305EB
+:1002B0006004A306B100B375A90E3376AA0E33D538
+:1002C000A40E9386A502B365C500A302D40013054E
+:1002D000D100EF10407A03C5D90193057004A3063D
+:1002E000B100B375A90E3376AA0E33D5A40E93864A
+:1002F000A502B365C5002303D4001305D100EF1098
+:10030000807703C5E90193058004A306B100B375A6
+:10031000A90E3376AA0E33D5A40E9386A502B36533
+:10032000C500A303D4001305D100EF10C07403C5AA
+:10033000F90193059004A306B100B375A90E3376B5
+:10034000AA0E33D5A40E9386A502B365C500230477
+:10035000D4001305D100EF10007203C50902930504
+:10036000A004A306B100B375A90E3376AA0E33D547
+:10037000A40E9386A502B365C500A304D40013059B
+:10038000D100EF10406F03C519029305B004A30616
+:10039000B100B375A90E3376AA0E33D5A40E938699
+:1003A000A502B365C5002305D4001305D100EF10E5
+:1003B000806C03C529029305C004A306B100B37580
+:1003C000A90E3376AA0E33D5A40E9386A502B36583
+:1003D000C500A305D4001305D100EF10C06903C503
+:1003E00039029305D004A306B100B375A90E337684
+:1003F000AA0E33D5A40E9386A502B365C5002306C5
+:10040000D4001305D100EF10006703C5490293051E
+:10041000E004A306B100B375A90E3376AA0E33D556
+:10042000A40E9386A502B365C500A306D4001305E8
+:10043000D100EF10406403C559029305F004A306F0
+:10044000B100B375A90E3376AA0E33D5A40E9386E8
+:10045000A502B365C5002307D4001305D100EF1032
+:10046000806103C5690293050005A306B100B37559
+:10047000A90E3376AA0E33D5A40E9386A502B365D2
+:10048000C500A307D4001305D100EF10C05E03C55B
+:10049000790293051005A306B100B375A90E337652
+:1004A000AA0E33D5A40E9386A502B365C500230812
+:1004B000D4001305D100EF10005C03C58902930539
+:1004C0002005A306B100B375A90E3376AA0E33D565
+:1004D000A40E9386A502B365C500A308D400130536
+:1004E000D100EF10405903C5990293053005A306CA
+:1004F000B100B375A90E3376AA0E33D5A40E938638
+:10050000A502B365C5002309D4001305D100EF107F
+:10051000805603C5A90293054005A306B100930CBC
+:100520004005B375A90E3376AA0E33D5A40E938673
+:10053000A502B365C500A309D4001305D100EF10CF
+:10054000805303C5D90293052003A3065101130D5F
+:1005500010042307B100B375A90E3376AA0E33D564
+:10056000A40E9386A502B365C500230AD400130523
+:10057000D100EF10405003C5E902A3066101930DBD
+:100580002004B375A90E3376AA0E33D5A40E938634
+:10059000A502B365C500A30AD4001305D100EF106E
+:1005A000804D03C5F902A3067101930A3004B375A7
+:1005B000A90E3376AA0E33D5A40E9386A502B36591
+:1005C000C500230BD4001305D100EF10C04A03C5AA
+:1005D0000903A3068101130B4004B375A90E3376FA
+:1005E000AA0E33D5A40E9386A502B365C500A30B4E
+:1005F000D4001305D100EF10004803C5190393057B
+:100600005004A306B100930B5004B375A90E3376C2
+:10061000AA0E33D5A40E9386A502B365C500230C9C
+:10062000D4001305D100EF10004503C5290393053D
+:100630006004A306B100130C6004B375A90E3376F1
+:10064000AA0E33D5A40E9386A502B365C500A30CEC
+:10065000D4001305D100EF10004203C53903930500
+:100660007004A306B100B375A90E3376AA0E33D574
+:10067000A40E9386A502B365C500230DD40013050F
+:10068000D100EF10403F03C5490393058004A30642
+:10069000B100B375A90E3376AA0E33D5A40E938696
+:1006A000A502B365C500A30DD4001305D100EF105A
+:1006B000803C03C5590393059004A306B100B375AC
+:1006C000A90E3376AA0E33D5A40E9386A502B36580
+:1006D000C500230ED4001305D100EF10C03903C5A7
+:1006E00069039305A004A306B100B375A90E337680
+:1006F000AA0E33D5A40E9386A502B365C500A30E3A
+:10070000D4001305D100EF10003703C5790393051A
+:10071000B004A306B100B375A90E3376AA0E33D583
+:10072000A40E9386A502B365C500230FD40013055C
+:10073000D100EF10403403C589039305C004A3061C
+:10074000B100B375A90E3376AA0E33D5A40E9386E5
+:10075000A502B365C500A30FD4001305D100EF10A7
+:10076000803103C599039305D004A306B100B37586
+:10077000A90E3376AA0E33D5A40E9386A502B365CF
+:10078000C5002300D4021305D100EF10C02E03C50D
+:10079000A9039305E004A306B100B375A90E33764F
+:1007A000AA0E33D5A40E9386A502B365C500A30097
+:1007B000D4021305D100EF10002C03C5B903930533
+:1007C000F004A306B100B375A90E3376AA0E33D593
+:1007D000A40E9386A502B365C5002301D4021305B8
+:1007E000D100EF10402903C5C90393050005A306F6
+:1007F000B100B375A90E3376AA0E33D5A40E938635
+:10080000A502B365C500A301D4021305D100EF1002
+:10081000802603C5D90393051005A306B100B3755F
+:10082000A90E3376AA0E33D5A40E9386A502B3651E
+:10083000C5002302D4021305D100EF10C02303C565
+:10084000E90393052005A306B100B375A90E33761D
+:10085000AA0E33D5A40E9386A502B365C500A302E4
+:10086000D4021305D100EF10002103C5F90393054D
+:100870003005A306B100B375A90E3376AA0E33D5A1
+:10088000A40E9386A502B365C5002303D402130505
+:10089000D100EF10401E03C50904A3069101930C7B
+:1008A0004005B375A90E3376AA0E33D5A40E9386F0
+:1008B000A502B365C500A303D4021305D100EF1050
+:1008C000801B03C5390493053003A306A101130D52
+:1008D00010042307B100B375A90E3376AA0E33D5E1
+:1008E000A40E9386A502B365C5002304D4021305A4
+:1008F000D100EF10401803C54904A306B101930DC0
+:100900002004B375A90E3376AA0E33D5A40E9386B0
+:10091000A502B365C500A304D4021305D100EF10EE
+:10092000801503C55904A3065101930A3004B37519
+:10093000A90E3376AA0E33D5A40E9386A502B3650D
+:10094000C5002305D4021305D100EF10C01203C562
+:100950006904A3066101130B4004B375A90E337635
+:10096000AA0E33D5A40E9386A502B365C500A305D0
+:10097000D4021305D100EF10001003C57904A306BB
+:100980007101930B5004B375A90E3376AA0E33D5BB
+:10099000A40E9386A502B365C5002306D4021305F1
+:1009A000D100EF10400D03C58904A3068101130C8B
+:1009B0006004B375A90E3376AA0E33D5A40E9386C0
+:1009C000A502B365C500A306D4021305D100EF103C
+:1009D000800A03C5990493057004A306B100B3759A
+:1009E000A90E3376AA0E33D5A40E9386A502B3655D
+:1009F000C5002307D4021305D100EF10C00703C5BB
+:100A0000A90493058004A306B100B375A90E33763B
+:100A1000AA0E33D5A40E9386A502B365C500A3071D
+:100A2000D4021305D100EF10000503C5B9049305E6
+:100A30009004A306B100B375A90E3376AA0E33D580
+:100A4000A40E9386A502B365C5002308D40213053E
+:100A5000D100EF10400203C5C9049305A004A3060A
+:100A6000B100B375A90E3376AA0E33D5A40E9386C2
+:100A7000A502B365C500A308D4021305D100EF0099
+:100A8000907F03C5D9049305B004A306B100B375E4
+:100A9000A90E3376AA0E33D5A40E9386A502B365AC
+:100AA000C5002309D4021305D100EF00D07C03C593
+:100AB000E9049305C004A306B100B375A90E33760B
+:100AC000AA0E33D5A40E9386A502B365C500A3096B
+:100AD000D4021305D100EF00107A03C5F904930581
+:100AE000D004A306B100B375A90E3376AA0E33D590
+:100AF000A40E9386A502B365C500230AD40213058C
+:100B0000D100EF00507703C509059305E004A30663
+:100B1000B100B375A90E3376AA0E33D5A40E938611
+:100B2000A502B365C500A30AD4021305D100EF00E6
+:100B3000907403C519059305F004A306B100B375BD
+:100B4000A90E3376AA0E33D5A40E9386A502B365FB
+:100B5000C500230BD4021305D100EF00D07103C5EB
+:100B6000290593050005A306B100B375A90E3376D8
+:100B7000AA0E33D5A40E9386A502B365C500A30BB8
+:100B8000D4021305D100EF00106F03C5390593059A
+:100B90001005A306B100B375A90E3376AA0E33D59E
+:100BA000A40E9386A502B365C500230CD4021305D9
+:100BB000D100EF00506C03C5490593052005A3063D
+:100BC000B100B375A90E3376AA0E33D5A40E938661
+:100BD000A502B365C500A30CD4021305D100EF0034
+:100BE000906903C5590593053005A306B100B37597
+:100BF000A90E3376AA0E33D5A40E9386A502B3654B
+:100C0000C500230DD4021305D100EF00D06603C543
+:100C10006905A3069101930C4005B375A90E3376BF
+:100C2000AA0E33D5A40E9386A502B365C500A30D05
+:100C3000D4021305D100EF00106403C59905930594
+:100C40004003A306A101130D10042307B100B375DF
+:100C5000A90E3376AA0E33D5A40E9386A502B365EA
+:100C6000C500230ED4021305D100EF00D06003C5E8
+:100C7000A905A306B101930D2004B375A90E33761F
+:100C8000AA0E33D5A40E9386A502B365C500A30EA4
+:100C9000D4021305D100EF00105E03C5B905A30609
+:100CA0005101930A3004B375A90E3376AA0E33D5D9
+:100CB000A40E9386A502B365C500230FD4021305C5
+:100CC000D100EF00505B03C5C905A3066101130BFA
+:100CD0004004B375A90E3376AA0E33D5A40E9386BD
+:100CE000A502B365C500A30FD4021305D100EF0020
+:100CF000905803C5D905A3067101930B5004B37531
+:100D0000A90E3376AA0E33D5A40E9386A502B36539
+:100D1000C5002300D4041305D100EF00D05503C54E
+:100D2000E905A3068101130C6004B375A90E33769F
+:100D3000AA0E33D5A40E9386A502B365C500A30001
+:100D4000D4041305D100EF00105303C5F905930532
+:100D50007004A306B100B375A90E3376AA0E33D57D
+:100D6000A40E9386A502B365C5002301D404130520
+:100D7000D100EF00505003C5090693058004A30677
+:100D8000B100B375A90E3376AA0E33D5A40E93869F
+:100D9000A502B365C500A301D4041305D100EF007B
+:100DA000904D03C5190693059004A306B100B375D1
+:100DB000A90E3376AA0E33D5A40E9386A502B36589
+:100DC000C5002302D4041305D100EF00D04A03C5A7
+:100DD00029069305A004A306B100B375A90E3376C6
+:100DE000AA0E33D5A40E9386A502B365C500A3024F
+:100DF000D4041305D100EF00104803C5390693054C
+:100E0000B004A306B100B375A90E3376AA0E33D58C
+:100E1000A40E9386A502B365C5002303D40413056D
+:100E2000D100EF00504503C549069305C004A30651
+:100E3000B100B375A90E3376AA0E33D5A40E9386EE
+:100E4000A502B365C500A303D4041305D100EF00C8
+:100E5000904203C559069305D004A306B100B375AB
+:100E6000A90E3376AA0E33D5A40E9386A502B365D8
+:100E7000C5002304D4041305D100EF00D03F03C5FF
+:100E800069069305E004A306B100B375A90E337695
+:100E9000AA0E33D5A40E9386A502B365C500A3049C
+:100EA000D4041305D100EF00103D03C57906930566
+:100EB000F004A306B100B375A90E3376AA0E33D59C
+:100EC000A40E9386A502B365C5002305D4041305BB
+:100ED000D100EF00503A03C5890693050005A3062B
+:100EE000B100B375A90E3376AA0E33D5A40E93863E
+:100EF000A502B365C500A305D4041305D100EF0016
+:100F0000903703C5990693051005A306B100B37584
+:100F1000A90E3376AA0E33D5A40E9386A502B36527
+:100F2000C5002306D4041305D100EF00D03403C557
+:100F3000A90693052005A306B100B375A90E337663
+:100F4000AA0E33D5A40E9386A502B365C500A306E9
+:100F5000D4041305D100EF00103203C5B906930580
+:100F60003005A306B100B375A90E3376AA0E33D5AA
+:100F7000A40E9386A502B365C5002307D404130508
+:100F8000D100EF00502F03C5C906A3069101B37528
+:100F9000A90E3376AA0E33D5A40E9386A502B365A7
+:100FA000C500A307D4041305D100EF00D02C03C55E
+:100FB000F90693055003A306A101930C100423071F
+:100FC000B100B375A90E3376AA0E33D5A40E93865D
+:100FD000A502B365C5002308D4041305D100EF00B2
+:100FE000902903C50907A306B101130D2004B375A9
+:100FF000A90E3376AA0E33D5A40E9386A502B36547
+:10100000C500A308D4041305D100EF00D02603C502
+:101010001907A3065101930D3004B375A90E337659
+:10102000AA0E33D5A40E9386A502B365C500230985
+:10103000D4041305D100EF00102403C52907A3062B
+:101040006101930A4004B375A90E3376AA0E33D515
+:10105000A40E9386A502B365C500A309D4041305A5
+:10106000D100EF00502103C53907A3067101130B0E
+:101070005004B375A90E3376AA0E33D5A40E938609
+:10108000A502B365C500230AD4041305D100EF00FF
+:10109000901E03C54907A3068101930B6004B37535
+:1010A000A90E3376AA0E33D5A40E9386A502B36596
+:1010B000C500A30AD4041305D100EF00D01B03C55B
+:1010C000590793057004A306B100130C7004B3759F
+:1010D000A90E3376AA0E33D5A40E9386A502B36566
+:1010E000C500230BD4041305D100EF00D01803C5AD
+:1010F000690793058004A306B100B375A90E337682
+:10110000AA0E33D5A40E9386A502B365C500A30B22
+:10111000D4041305D100EF00101603C57907930519
+:101120009004A306B100B375A90E3376AA0E33D589
+:10113000A40E9386A502B365C500230CD404130541
+:10114000D100EF00501303C589079305A004A3063F
+:10115000B100B375A90E3376AA0E33D5A40E9386CB
+:10116000A502B365C500A30CD4041305D100EF009C
+:10117000901003C599079305B004A306B100B37599
+:10118000A90E3376AA0E33D5A40E9386A502B365B5
+:10119000C500230DD4041305D100EF00D00D03C505
+:1011A000A9079305C004A306B100B375A90E337651
+:1011B000AA0E33D5A40E9386A502B365C500A30D70
+:1011C000D4041305D100EF00100B03C5B907930534
+:1011D000D004A306B100B375A90E3376AA0E33D599
+:1011E000A40E9386A502B365C500230ED40413058F
+:1011F000D100EF00500803C5C9079305E004A3061A
+:10120000B100B375A90E3376AA0E33D5A40E93861A
+:10121000A502B365C500A30ED4041305D100EF00E9
+:10122000900503C5D9079305F004A306B100B37573
+:10123000A90E3376AA0E33D5A40E9386A502B36504
+:10124000C500230FD4041305D100EF00D00203C55D
+:10125000E90793050005A306B100B375A90E33761F
+:10126000AA0E33D5A40E9386A502B365C500A30FBD
+:10127000D4041305D100EF00100003C5F90793054E
+:101280001005A306B100B375A90E3376AA0E33D5A7
+:10129000A40E9386A502B365C5002300D4061305EA
+:1012A000D100D12F03C5090893052005A306B1007D
+:1012B000B375A90E3376AA0E33D5A40E9386A50274
+:1012C000B365C500A300D4061305D1006D2703C57F
+:1012D000190893053005A306B100B375A90E33763E
+:1012E000AA0E33D5A40E9386A502B365C5002301CB
+:1012F000D4061305D100412703C5290893054005ED
+:10130000A306B100B375A90E3376AA0E33D5A40E89
+:101310009386A502B365C500A301D4061305D100C9
+:10132000992F03C5590893056003A306910123076C
+:10133000B100B375A90E3376AA0E33D5A40E9386E9
+:10134000A502B365C5002302D4061305D1002527E5
+:1013500003C56908A306A101B375A90E3376AA0EC9
+:1013600033D5A40E9386A502B365C500A302D406A7
+:101370001305D100092703C57908A306B101B37588
+:10138000A90E3376AA0E33D5A40E9386A502B365B3
+:10139000C5002303D4061305D100F12D03C5890828
+:1013A000A3065101B375A90E3376AA0E33D5A40E48
+:1013B0009386A502B365C500A303D4061305D10027
+:1013C0005D2D03C59908A3066101B375A90E337697
+:1013D000AA0E33D5A40E9386A502B365C5002304D7
+:1013E000D4061305D100412D03C5A908A306710138
+:1013F000B375A90E3376AA0E33D5A40E9386A50233
+:10140000B365C500A304D4061305D100AD2503C5FB
+:10141000B908A3068101B375A90E3376AA0E33D598
+:10142000A40E9386A502B365C5002305D406130553
+:10143000D100912503C5C90893058004A306B10016
+:10144000B375A90E3376AA0E33D5A40E9386A502E2
+:10145000B365C500A305D4061305D100292D03C526
+:10146000D90893059004A306B100B375A90E33768D
+:10147000AA0E33D5A40E9386A502B365C500230634
+:10148000D4061305D100C52B03C5E9089305A004B4
+:10149000A306B100B375A90E3376AA0E33D5A40EF8
+:1014A0009386A502B365C500A306D4061305D10033
+:1014B000D92303C5F9089305B004A306B100B37599
+:1014C000A90E3376AA0E33D5A40E9386A502B36572
+:1014D000C5002307D4061305D100712B03C50909E4
+:1014E0009305C004A306B100B375A90E3376AA0E06
+:1014F00033D5A40E9386A502B365C500A307D40611
+:101500001305D1008D2B03C519099305D004A3063B
+:10151000B100B375A90E3376AA0E33D5A40E938607
+:10152000A502B365C5002308D4061305D100A12385
+:1015300003C529099305E004A306B100B375A90EFC
+:101540003376AA0E33D5A40E9386A502B365C500E3
+:10155000A308D4061305D100392B03C53909930517
+:10156000F004A306B100B375A90E3376AA0E33D5E5
+:10157000A40E9386A502B365C5002309D4061305FE
+:10158000D100D52903C5490993050005A306B1007B
+:10159000B375A90E3376AA0E33D5A40E9386A50291
+:1015A000B365C500A309D4061305D100E92103C51D
+:1015B000590993051005A306B100B375A90E33763A
+:1015C000AA0E33D5A40E9386A502B365C500230ADF
+:1015D000D4061305D100452103C5690993052005EB
+:1015E000A306B100B375A90E3376AA0E33D5A40EA7
+:1015F0009386A502B365C500A30AD4061305D100DE
+:101600009D2903C5790993053005A306B100B3757B
+:10161000A90E3376AA0E33D5A40E9386A502B36520
+:10162000C500230BD4061305D100B12103C58909D8
+:1016300093054005A306B100B375A90E3376AA0E33
+:1016400033D5A40E9386A502B365C500A30BD406BB
+:101650001305D1000D21230C040622852921627473
+:101660004279227A027B626C426D41014EBE8965ED
+:10167000938535B72E95834595FE0346A5FE834693
+:10168000B5FE0347F5FFB295508183475501BA96E1
+:1016900003476501034575013E96B6953A96B295A6
+:1016A0002E9582808965938535B713884501908191
+:1016B000D481B88183C7650183C8850103C5C5028C
+:1016C00036963E9783C6750183C7D50246953A96EE
+:1016D00003C7E5023E953295138615003A951377B8
+:1016E000E500751579171335150013371700337595
+:1016F000D50EB356D70E558DA383A50CB285E3182E
+:1017000006FB0965130535B7130845010346650156
+:1017100083467501034785018347C5028348E50277
+:1017200083452504B382C6003E978346D50283478E
+:101730003504C695034645041697BE95BA95B295ED
+:1017400013F6E500F515791693B515001336160056
+:10175000B3F5D50E3356D60ED18DA30EB50C0505B7
+:10176000E31605FB0965130535B713084501034664
+:10177000C5028346D5020347E50283472504834813
+:10178000450483458505B382C6003E9783463504EC
+:1017900083479505C6950346A5051697BE95BA9548
+:1017A000B29513F6E500F515791693B515001336C5
+:1017B0001600B3F5D50E3356D60ED18DA309B50E4E
+:1017C0000505E31605FB0968130838B7930598105B
+:1017D0009308D81183C695F303C7A5F383C7B5F360
+:1017E00003C5F5F483C215F503C655F63303D700D8
+:1017F0003E9503C705F583C765F6169683C675F64D
+:101800001A953E96329536951376E500751579163C
+:1018100013351500133616003375E50E3356E60EF4
+:10182000518D88898505E39715FB9305F811930879
+:10183000381303C595F383C6A5F303C7B5F383C770
+:10184000F5F483C215F503C655F63383A6003E971B
+:1018500083C605F583C765F6169603C575F61A9710
+:101860003E963A9632951376E5007515791613353E
+:101870001500133616003375D50E3356D60E518D1E
+:1018800088898505E39715FB9305A8091308E80ADD
+:1018900003C645FD83C655FD03C765FD83C7A5FE89
+:1018A00083C8C5FE888136963E9783C6B5FEDC8127
+:1018B00046953A96B8813E953295138615003A952D
+:1018C0001377E500751579171335150013371700D1
+:1018D0003375D50EB356D70E558DA38DA508B28599
+:1018E000E31806FB82808965938535B71385A50DBE
+:1018F0009385E5150346D5FE8346E5FE0347F5FED1
+:10190000834705FFA30EC5F2230FD5F2A30FE5F21F
+:101910002300F5F4034615FF834625FF034735FFF3
+:10192000834745FFA300C5F42301D5F4A301E5F4E3
+:101930002302F5F4034655FF834665FF034775FF11
+:10194000834785FFA302C5F42303D5F4A303E5F47D
+:101950002304F5F4034695FF8346A5FF0347B5FF2F
+:101960008347C5FFA304C5F42305D5F4A305E5F417
+:101970002306F5F40346D5FF8346E5FF0347F5FF4D
+:101980001C81A306C5F42307D5F4A307E5F42308B7
+:10199000F5F45905E310B5F6828046B822E4EFE08D
+:1019A0002FE70965130535B71304A50D9304E51555
+:1019B000EFE02FFEC53922858345D5FE0346E5FEBF
+:1019C0008346F5FE034705FFA30EB5F2230FC5F2CC
+:1019D000A30FD5F22300E5F4834515FF034625FF49
+:1019E000834635FF034745FFA300B5F42301C5F443
+:1019F000A301D5F42302E5F4834555FF034665FFB3
+:101A0000834675FF034785FFA302B5F42303C5F49E
+:101A1000A303D5F42304E5F4834595FF0346A5FF0E
+:101A20008346B5FF0347C5FFA304B5F42305C5F4FA
+:101A3000A305D5F42306E5F48345D5FF0346E5FF6A
+:101A40008346F5FF1881A306B5F42307C5F4A30761
+:101A5000D5F42308E5F45905E31095F691BF8548C0
+:101A60007300000082809148730000008280AD48BE
+:101A700073000000828093081008730000008280C9
+:101A80009308500873000000828093087008730068
+:101A900000008280732510C08280732500C0828080
+:101AA000930860087300000082800589F32200809B
+:101AB00093920248B3E2A20073900280828095481C
+:101AC0007300000082809308000873000000828089
+:101AD000A148730000008280930830087300000062
+:101AE000828093084008730000008280666661610E
+:0A1AF0003535003535323230300054
+:101AFA007800000000000000000000000000000064
+:101B0A0000000000000000000000000000000000CB
+:101B1A0000000000000000000000000000000000BB
+:101B2A0000000000000000000000000000000000AB
+:101B3A00000000000000000000000000000000009B
+:101B4A00000000000000000000000000000000008B
+:101B5A00000000000000000000000000000000007B
+:101B6A00000000000000000000000000000000006B
+:101B7A00000000000000000000000000000000005B
+:101B8A00000000000000000000000000000000004B
+:101B9A00000000000000000000000000000000003B
+:101BAA00000000000000000000000000000000002B
+:101BBA00000000000000000000000000000000001B
+:101BCA00000000000000000000000000000000000B
+:101BDA0000000000000000000000000000000000FB
+:101BEA0000000000000000000000000000000000EB
+:101BFA0000000000000000000000000000000000DB
+:101C0A0000000000000000000000000000000000CA
+:101C1A0000000000000000000000000000000000BA
+:101C2A0000000000000000000000000000000000AA
+:101C3A00000000000000000000000000000000009A
+:101C4A00000000000000000000000000000000008A
+:101C5A00000000000000000000000000000000007A
+:101C6A00000000000000000000000000000000006A
+:101C7A00000000000000000000000000000000005A
+:101C8A00000000000000000000000000000000004A
+:101C9A00000000000000000000000000000000003A
+:101CAA00000000000000000000000000000000002A
+:101CBA00000000000000000000000000000000001A
+:091CCA0000000000000000000011
+:00000001FF
diff --git a/c/gol/gol.o b/c/gol/gol.o
new file mode 100644
index 0000000..6c841a1
--- /dev/null
+++ b/c/gol/gol.o
Binary files differ
diff --git a/c/gol/rvcontroller.ld b/c/gol/rvcontroller.ld
new file mode 100644
index 0000000..985892b
--- /dev/null
+++ b/c/gol/rvcontroller.ld
@@ -0,0 +1,45 @@
+/* Thanks https://github.com/darklife/darkriscv */
+ __heap_size = 0x200; /* required amount of heap */
+ __stack_size = 0x800; /* required amount of stack */
+ ENTRY(_start);
+ MEMORY
+ {
+ RAM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x10000
+ }
+ SECTIONS
+ {
+ .text :
+ {
+ *(.text.startup)
+ *(.text)
+ *(.text)
+ *(.rodata*)
+ } > RAM
+ .data :
+ {
+ *(.sbss)
+ *(.data)
+ *(.bss)
+ *(.rela*)
+ *(COMMON)
+ } > RAM
+
+ .heap :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ _sheap = .;
+ . = . + __heap_size;
+ . = ALIGN(4);
+ _eheap = .;
+ } >RAM
+
+ .stack :
+ {
+ . = ALIGN(4);
+ _estack = .;
+ . = . + __stack_size;
+ . = ALIGN(4);
+ _sstack = .;
+ } >RAM
+ }
diff --git a/c/menu/Makefile b/c/menu/Makefile
new file mode 100644
index 0000000..bd92e6a
--- /dev/null
+++ b/c/menu/Makefile
@@ -0,0 +1,44 @@
+CC ?= clang
+CFLAGS_MARCH ?= -march=rv32imacb_zicntr_zicond_zicsr_zifencei_zihintpause_zilsd_zclsd_zabha_zacas_zbkb_zbkx_zcb_zcmp_zcmt
+CFLAGS_OPT ?= -O3
+CFLAGS ?= ${CFLAGS_MARCH} ${CFLAGS_OPT}
+
+ifeq (${CC}, clang)
+ CC := ${CC} -target riscv32-none-elf
+endif
+
+.PHONY: all dump load clean
+
+all: menu.hex
+
+menu.o: menu.c calculator.h digilines.h games.h screensaver.h
+ ${CC} -I../rvcontroller-libraries ${CFLAGS} -ffreestanding -c -o menu.o menu.c
+
+calculator.o: calculator.c
+ ${CC} -I../rvcontroller-libraries ${CFLAGS} -ffreestanding -c -o calculator.o calculator.c
+
+digilines.o: digilines.c
+ ${CC} -I../rvcontroller-libraries ${CFLAGS} -ffreestanding -c -o digilines.o digilines.c
+
+games.o: games.c
+ ${CC} -I../rvcontroller-libraries ${CFLAGS} -ffreestanding -c -o games.o games.c
+
+screensaver.o: screensaver.c
+ ${CC} -I../rvcontroller-libraries ${CFLAGS} -ffreestanding -c -o screensaver.o screensaver.c
+
+menu.elf: ../rvcontroller-libraries/rvcontroller-init.o ../rvcontroller-libraries/rvcontroller-ecalls.o menu.o calculator.o digilines.o games.o screensaver.o
+# riscv32-none-elf-ld -T rvcontroller.ld --no-warn-rwx-segments -o menu.elf ../rvcontroller-libraries/rvcontroller-init.o ../rvcontroller-libraries/rvcontroller-ecalls.o menu.o calculator.o digilines.o games.o
+ ${CC} -T rvcontroller.ld -nostdlib -nostartfiles -Xlinker --no-warn-rwx-segments -o menu.elf ../rvcontroller-libraries/rvcontroller-init.o ../rvcontroller-libraries/rvcontroller-ecalls.o menu.o calculator.o digilines.o games.o screensaver.o
+
+dump: menu.elf
+ riscv32-none-elf-objdump -d menu.elf
+
+menu.hex: menu.elf
+ riscv32-none-elf-objcopy -O ihex menu.elf menu.hex
+
+load: menu.hex
+ bash -c "wl-copy < menu.hex"
+
+clean:
+ rm -f menu.bin menu.elf menu.o init.o calculator.o digilines.o games.o screensaver.o
+
diff --git a/c/menu/calculator.c b/c/menu/calculator.c
new file mode 100644
index 0000000..ff26f07
--- /dev/null
+++ b/c/menu/calculator.c
@@ -0,0 +1,95 @@
+/* Menu Thing for RVController - Calculator
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "rvcontroller-ecalls.h"
+
+void runCalculator(void) {
+ char input[2] = {0};
+ int32_t num1 = 0;
+ int32_t num2 = 0;
+ int32_t result = 0;
+
+ printstr("\n\n\n\n\n\n");
+ printstr("Enter number 1:\n> ");
+ num1 = readint();
+ printint(num1);
+ printstr("\nEnter number 2:\n> ");
+ num2 = readint();
+ printint(num2);
+
+ bool opok = false;
+ while (!opok) {
+ printstr("\nSelect operation:\n[+-*/%&|^<<>>] > ");
+ readstr(input,2);
+ printstr(input);
+
+ switch (input[0]) {
+ case '<':
+ case '>':
+ // Duplicate the character for these two to give the illusion that I bothered to store both
+ // Then fall through
+ printstr(input);
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case '&':
+ case '|':
+ case '^':
+ printchar('\n');
+ opok = true;
+ break;
+ default:
+ printstr("\nInvalid operation\n");
+ }
+ }
+
+ switch (input[0]) {
+ case '+':
+ printint(num1+num2);
+ break;
+ case '-':
+ printint(num1-num2);
+ break;
+ case '*':
+ printint(num1*num2);
+ break;
+ case '/':
+ printint(num1/num2);
+ break;
+ case '%':
+ printint(num1%num2);
+ break;
+ case '&':
+ printint(num1&num2);
+ break;
+ case '|':
+ printint(num1|num2);
+ break;
+ case '^':
+ printint(num1^num2);
+ break;
+ case '<':
+ if (num2 < 0 || num2 > 31) {
+ printstr("Nice try.");
+ } else {
+ printint(num1<<num2);
+ }
+ break;
+ case '>' :
+ if (num2 < 0 || num2 > 31) {
+ printstr("Nice try.");
+ } else {
+ printint(num1>>num2);
+ }
+ break;
+ }
+
+ printstr("\nPress any key");
+ readstr(input,1);
+}
diff --git a/c/menu/calculator.h b/c/menu/calculator.h
new file mode 100644
index 0000000..4a70356
--- /dev/null
+++ b/c/menu/calculator.h
@@ -0,0 +1,6 @@
+/* Menu Thing for RVController - Calculator
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+void runCalculator(void);
diff --git a/c/menu/calculator.o b/c/menu/calculator.o
new file mode 100644
index 0000000..7247432
--- /dev/null
+++ b/c/menu/calculator.o
Binary files differ
diff --git a/c/menu/digilines.c b/c/menu/digilines.c
new file mode 100644
index 0000000..620d61f
--- /dev/null
+++ b/c/menu/digilines.c
@@ -0,0 +1,66 @@
+/* Menu Thing for RVController - Digilines
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "rvcontroller-ecalls.h"
+
+char dispbuf[] = "\nLast channel:\n(none) \nLast message:\n(none) \ns: Send\nq: Quit";
+
+void dispWrite(char *text,int pos) {
+ int outpos;
+ for (int i=0;;i++) {
+ if (text[i] == 0) { break; }
+ outpos = pos + i;
+ dispbuf[outpos] = text[i];
+ }
+}
+
+void sendUI(void) {
+ char channeloutbuf[19];
+ char msgoutbuf[19];
+ printstr("\n\n\n\n\nEnter channel:\n> ");
+ readstr(channeloutbuf,19);
+ printstr(channeloutbuf);
+ printstr("\nEnter message:\n> ");
+ readstr(msgoutbuf,19);
+ printstr(msgoutbuf);
+ digiline_send(channeloutbuf,msgoutbuf);
+ printstr("\nSent!\nPress any key");
+ readstr(channeloutbuf,1);
+}
+
+void runDigilines(void) {
+ char channelinbuf[21];
+ char msginbuf[21];
+ char kbinput;
+ bool quit = false;
+
+ console_clearbuffer();
+ digiline_clearbuffer();
+ dispWrite("(none) ",15);
+ dispWrite("(none) ",50);
+
+ while (!quit) {
+ if (digiline_bufferlevel() > 0) {
+ digiline_receive(channelinbuf,21,msginbuf,21);
+ dispWrite(" ",15);
+ dispWrite(" ",50);
+ dispWrite(channelinbuf,15);
+ dispWrite(msginbuf,50);
+ }
+ printstr(dispbuf);
+
+ kbinput = console_readchar();
+ switch (kbinput) {
+ case 's':
+ sendUI();
+ break;
+ case 'q':
+ quit = true;
+ break;
+ }
+ }
+}
diff --git a/c/menu/digilines.h b/c/menu/digilines.h
new file mode 100644
index 0000000..480623a
--- /dev/null
+++ b/c/menu/digilines.h
@@ -0,0 +1,6 @@
+/* Menu Thing for RVController - Digilines
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+void runDigilines(void);
diff --git a/c/menu/digilines.o b/c/menu/digilines.o
new file mode 100644
index 0000000..95a2ac8
--- /dev/null
+++ b/c/menu/digilines.o
Binary files differ
diff --git a/c/menu/games.c b/c/menu/games.c
new file mode 100644
index 0000000..574c6f0
--- /dev/null
+++ b/c/menu/games.c
@@ -0,0 +1,121 @@
+/* Menu Thing for RVController - Games
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "rvcontroller-ecalls.h"
+
+void runCasino(void) {
+ int32_t input;
+ int32_t money = 10;
+ bool quit = false;
+ char strscratch[1];
+
+ printstr("\nCASINO\n");
+
+ while (!quit) {
+ printstr("You have:\n$");
+ printint(money);
+ printstr("\nBet how much?\n(0 to quit)\n> ");
+ input = readint();
+ printint(input);
+ printchar('\n');
+
+ if (input == 0) {
+ quit = true;
+ } else if (input < 0 || input > money) {
+ printstr("Nice try.\n");
+ } else {
+ if (randomint(0,9) >= 6) { // Of course it's not a fair chance. This is a casino, gotta make money here!
+ printstr("You win!\n");
+ money = money + input;
+ if (money >= 1000000000) {
+ printstr("You're a \nbillionaire!\nBest quit while\nyou're ahead...\n\nPress any key");
+ readstr(strscratch,1);
+ quit = true;
+ }
+ } else {
+ printstr("You lose.\n");
+ money = money - input;
+ if (money <= 0) {
+ printstr("You've gambled away\nyour life savings.\nTime to go home...\n\nPress any key");
+ readstr(strscratch,1);
+ quit = true;
+ }
+ }
+ }
+ }
+}
+
+void runGuessNum(void) {
+ int32_t answer = randomint(1,99);
+ int32_t entry;
+ int32_t guesses = 0;
+ uint32_t time = rdtime();
+ bool quit = false;
+ char strscratch[1];
+
+ printstr("GUESS THE NUMBER\nThe computer will\npick a number from\n1 to 99 and you need\nto guess it.\n\nPress any key");
+ readstr(strscratch,1);
+ printstr("\n\n\n\n");
+
+ while (!quit) {
+ printstr("Enter your guess:\n(0 to quit)\n> ");
+ entry = readint();
+ if (entry == 0) {
+ quit = true;
+ }
+ printint(entry);
+ guesses = guesses + 1;
+
+ if (entry == answer) {
+ printstr("\nCorrect!\n\nYou got it in:\n");
+ printint(guesses);
+ printstr(" guess");
+ if (guesses != 1) { printstr("es"); }
+ printchar('\n');
+ time = rdtime() - time;
+ printint(time);
+ printstr(" second");
+ if (time != 1) { printchar('s'); }
+ printstr("\nPress any key");
+ readstr(strscratch,1);
+ quit = true;
+ } else if (entry > answer) {
+ printstr("\nToo high!\n\n");
+ } else {
+ printstr("\nToo low!\n\n");
+ }
+ }
+}
+
+void runGames(void) {
+ char inputbuf[2];
+ bool quit = false;
+ while (!quit) {
+ printstr("\nGAMES\n");
+ printstr("1: Casino\n");
+ printstr("2: Guess the Number\n");
+ printstr("\n\n0: Back");
+ readstr(inputbuf,2);
+
+ switch (inputbuf[0]) {
+ case '0':
+ quit = true;
+ break;
+ case '1':
+ runCasino();
+ quit = true;
+ break;
+ case '2':
+ runGuessNum();
+ quit = true;
+ break;
+ default:
+ printstr("\nInvalid option\n\nPress any key\n\n\n");
+ readstr(inputbuf,2);
+ }
+ }
+}
diff --git a/c/menu/games.h b/c/menu/games.h
new file mode 100644
index 0000000..d2b67be
--- /dev/null
+++ b/c/menu/games.h
@@ -0,0 +1,6 @@
+/* Menu Thing for RVController - Games
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+void runGames(void);
diff --git a/c/menu/games.o b/c/menu/games.o
new file mode 100644
index 0000000..749068a
--- /dev/null
+++ b/c/menu/games.o
Binary files differ
diff --git a/c/menu/menu.c b/c/menu/menu.c
new file mode 100644
index 0000000..4d3aa14
--- /dev/null
+++ b/c/menu/menu.c
@@ -0,0 +1,74 @@
+/* Menu Thing for RVController - Main Menu
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "rvcontroller-ecalls.h"
+#include "calculator.h"
+#include "digilines.h"
+#include "games.h"
+#include "screensaver.h"
+
+uint_fast8_t menupage = 0;
+
+void main(void) {
+ char inputbuf[32] = {0}; // Overkill for now but it's not like I'm short on RAM
+ while (true) {
+ switch (menupage) {
+ case 0:
+ printstr("\nMAIN MENU Page 1\n");
+ printstr("< > to change page\n");
+ printstr("1: Calculator\n");
+ printstr("2: Calendar\n");
+ printstr("3: Digilines\n");
+ printstr("4: Games");
+ break;
+ case 1:
+ printstr("\nMAIN MENU Page 2\n");
+ printstr("< > to change page\n");
+ printstr("5: Screensaver\n");
+ printstr("6: Text Editor\n");
+ printstr("More coming soon\n");
+ printstr("(maybe)");
+ break;
+ default:
+ printstr("\nInvalid menu page\n\n\n\n\n\n");
+ }
+
+ readstr(inputbuf,32);
+
+ switch (inputbuf[0]) {
+ case '<':
+ if (menupage > 0) {
+ menupage--;
+ } else {
+ menupage = 1;
+ }
+ break;
+ case '>':
+ menupage = (menupage + 1) % 2;
+ break;
+ case '1':
+ runCalculator();
+ break;
+ case '3':
+ runDigilines();
+ break;
+ case '4':
+ runGames();
+ break;
+ case '5':
+ runScreensaver();
+ break;
+ default:
+ printstr("\nUnknown or\n");
+ printstr("unimplemented\n");
+ printstr("command\n");
+ printstr("\n");
+ printstr("Press any key\n");
+ readstr(inputbuf,32);
+ }
+ }
+}
diff --git a/c/menu/menu.elf b/c/menu/menu.elf
new file mode 100755
index 0000000..92b42fe
--- /dev/null
+++ b/c/menu/menu.elf
Binary files differ
diff --git a/c/menu/menu.hex b/c/menu/menu.hex
new file mode 100644
index 0000000..2b96462
--- /dev/null
+++ b/c/menu/menu.hex
@@ -0,0 +1,377 @@
+:10000000370101006128A9487300000082808548FB
+:100010007300000082809148730000008280AD4828
+:100020007300000082809308100873000000828033
+:1000300093085008730000008280930870087300D2
+:1000400000008280732510C08280732500C08280EA
+:10005000930860087300000082800589F322008005
+:1000600093920248B3E2A200739002808280954886
+:1000700073000000828093080008730000008280F3
+:10008000A1487300000082809308300873000000CC
+:100090008280930840087300000082804EB80111EE
+:1000A000A2E4CAE052FC5AF862F46AF002C802CA3A
+:1000B00002CC02CE02C002C202C402C6056D856D2A
+:1000C000938D5DFF0569130979FE85699389A9FD03
+:1000D000056A130ABAFC856A938A4AFA354B856B1E
+:1000E000938BCBF611A0712583456D77568552848D
+:1000F000CE8C4A8CEE8495C585649384B404054502
+:10010000639CA50205651305E5FF0564130414014E
+:10011000856C938C1C02056C130C1C038564938402
+:100120003404D53D0565130575FBF5352285E535A8
+:100130006685D5356285C5352685F13D0A859305E9
+:1001400000023D3F034501001305F5FC6360AB026F
+:1001500033457521084102859D2079B703456D77A8
+:10016000854533F5A540230BAD76BDBF0565130569
+:1001700045065535056513051507713D05651305DC
+:100180000508513D056513053536713505651305BF
+:10019000950851350A8593050002DD35B1B74D222A
+:1001A000A1B7EF00105089B703456D7709C57D15DC
+:1001B000230BAD7615BF0545230BAD7635B74AB891
+:1001C00022EC4AE852E42313010005651305E535E6
+:1001D00099350565130585093D3D513D2A89053D44
+:1001E00005651305B50A053D5935AA890D35056420
+:1001F0001304F40B93047005056A130A4A0E856A0A
+:10020000938A4A3A19A05285393522852935130532
+:1002100061008945B53513056100F53B0345610073
+:100220001305B5FDE3E1A4FE3345552108410285E0
+:100230002945F533034561001305B5FD93057005A8
+:1002400063E2A5088565938545503345B52008418F
+:10025000028533653903B5A0130561006D3B29455F
+:100260007D3B034561001305B5FD93057005E3FB78
+:10027000A5FC89A833852903A9A03345390391A09A
+:1002800033F529013DA81305000263F9A9003315D0
+:10029000390105A81305000263E3A90205651305EA
+:1002A000850F953B05A03385290121A833053941E8
+:1002B00009A833E5290131A033C5290119A0335517
+:1002C0003941B13305651305051CB13313056100D0
+:1002D00085457D3362644269226A4ABE108119CA2B
+:1002E00085669386066AB695050590891081050591
+:1002F000850565FE82804EB8056513052510213BF6
+:100300001305D101CD45AD3B1305D1012933056559
+:100310001305951109331305A100CD459533130538
+:10032000A100D5391305D1019305A100ED3905656B
+:100330001305C512CD311305D101854591334EBE4C
+:100340004EB85D71A2FCCAF8D2F4DAF0E2ECEAE849
+:10035000253BFD3905641304046A930680021306E5
+:10036000E0061307F0061305500693059002930468
+:100370000002930A6101130B1100930B300705690A
+:1003800013092910856993899911056A130ACA12FC
+:10039000A307D4002308C400A308E4002309C40071
+:1003A0002309D402A309C402230AE402A30AC40253
+:1003B000130C1007A309A400230AB400A30A940095
+:1003C000230B9400A30B9400230C9400A30C940023
+:1003D000230D9400A30D9400230E9400A30E94000B
+:1003E000230F9400A30F940023009402A30094020F
+:1003F00023019402230BA402A30BB402230C940246
+:10040000A30C9402230D9402A30D9402230E9402D4
+:10041000A30E9402230F9402A30F940223009404CA
+:10042000A300940423019404A301940423029404DC
+:10043000A3029404930C2403130DF40035A84A85F9
+:10044000D93E1305D103CD4525391305D103E13636
+:100450004E85D1361305A102CD451D311305A102EC
+:100460005D3E1305D1039305A102753E52856536A5
+:100470001305D10385452931653E79C9130551011D
+:10048000D5450A86D546553EA30794002308940017
+:10049000A308940023099400A3099400230A94005C
+:1004A000A30A9400230B9400A30B9400230C940044
+:1004B000A30C9400230D9400A30D9400230E94002C
+:1004C000A30E9400230F9400A30F94002300940222
+:1004D000A30094022301940223099402A309940225
+:1004E000230A9402A30A9402230B9402A30B9402FE
+:1004F000230C9402A30C9402230D9402A30D9402E6
+:10050000230E9402A30E9402230F9402A30F9402CD
+:1005100023009404A300940403455101230194048F
+:10052000A301940423029404A302940401C9EA855C
+:100530005686888908820506850565FD0345010004
+:1005400001C9E6855A86888908820506850565FD04
+:100550002285D1343D3EE30475EFE31F85F16674D7
+:100560004679267A067B666C466D61614EBE4EB852
+:10057000411122FC4AF852F45AF062EC6AE805652F
+:1005800013051514493C05651305A514693429455F
+:10059000A944B53C056513056515B53CC93C2A84DD
+:1005A000BD342945AD3C51C4056913094917856916
+:1005B0009389A914856B938B6B15194C856A938A63
+:1005C000FA17856C938C9C1837D59A3B056B130BE7
+:1005D000FB1C130DF59F056A130AAA1D39A84A854D
+:1005E0001D3C4E850D3C26851D345E852D344134E1
+:1005F0002A84313C294525340DCCE34204FEE3C076
+:1006000084FEA5450145853C634885015685213416
+:10061000A294E3589DFC39A05A85F53A818CE342B7
+:1006200090FC11A0668A5285FD321305F1008545C4
+:10063000813C62744279227A027B626C426D410194
+:100640004EBEBAB822EC4AE852E40545930530069E
+:10065000854415342A8BFD322A8905651305352218
+:100660005D3A130571008545213C05651305053686
+:100670005D3205651305A528793AD53A2A84413AB1
+:100680006318640505651305B52A713205454132C5
+:1006900005651305652C4132294551326532330415
+:1006A00025412285AD3205651305D52CAD32630594
+:1006B000940013053007A53205651305051CA13A02
+:1006C0001305710085456D3A62644269226ABABEBB
+:1006D000635B8B0005651305552D353A11E862649F
+:1006E0004269226ABABE05651305252E2D3265D8EA
+:1006F00005651305A52805329D3AAA84093A0944DF
+:10070000638C640385699389592D056A130AAA28A5
+:10071000856A938A2A2E63569B004E85ED3889E4BC
+:100720007DBF5685CD38C5DC5285F5308932AA8427
+:10073000F9380504E39164FF05651305B52AE1382E
+:100740002285F13005651305652CF130056513052B
+:10075000B5FFD1302945E130F530330425412285FC
+:100760007D3005651305D52C7D300545E313A4F4D4
+:10077000A1B74EB822F44AF052EC5AE805691309C1
+:10078000E92E85699389692F056A130A1A30056B6A
+:10079000130B6B311304000393042003930B10031A
+:1007A000856A938A0A324A85BD304E85AD305285BE
+:1007B0009D305A858D301305E1008945D1300345C0
+:1007C000E100630E8500630195026309750156859A
+:1007D00099301305E10089456530F1B7493B227432
+:1007E0000279626A426B4EBEA93D22740279626A46
+:1007F000426B4EBE81453306B5001082850565FE0D
+:100800001385F5FF8280FD573307F5005883850770
+:1008100065FF63C405023387F500514893284701FB
+:100820003307B8403377170FB3D7170FB368F70004
+:100830002E882A87634A1001A9A801483307B540CA
+:10084000B388F50063571005B347C62033C6C720E9
+:1008500085C2429605651305756F32950505B30788
+:100860001501930500020C890505E31EF5FE15A090
+:10087000429685669386766F4698B305B5403305F4
+:10088000D6000505C2951083050710890505E31CF0
+:10089000B7FE82804AB822EC4AE852E45AE0954515
+:1008A0000145EFF04FFD2A84EFF00FFEEFF06FFEF1
+:1008B00005691309796FCD4419C105457DA04D5ACD
+:1008C000856993892934930B1900D54A214B29A8AE
+:1008D00095450145EFF02FFA2A84D1444A85EFF07F
+:1008E0008FF3EFF00FFB2DE1E3549AFE1385F4FF35
+:1008F000635B900063C16403B3849A402A86CE850B
+:10090000634E90001DA80146B38599408505B1044A
+:10091000634690001DA0B544CE852A86B346842048
+:10092000DE94B3C68620B2963386DB00A696988105
+:10093000188A05068505E31CD6FEAA844A85EFF0D1
+:100940008FEDEFF00FF54DD163CA04001D4563ED47
+:10095000A4005145058D634AA00035A01385D4003D
+:1009600081446344A00005A03545B3458420CA9462
+:10097000B3C58520A69585052E951306000290899E
+:100980008505E39EA5FE62644269226A026B4ABE47
+:100990004EB822F44AF052EC5AE862E46AE0EFF012
+:1009A000AFEEEFF00FEF314985699389796F01C59B
+:1009B0008144014501AA814A8144854C138A19006A
+:1009C00013040002056B130B0B35D14B214C054D65
+:1009D0002DA813A514007D1D3375AD0E93A51A0027
+:1009E000FD1CB3F5BC0E13A674007D160505336D12
+:1009F000A60013A55A007D158505B36CB5004E857C
+:100A0000EFF06FE1EFF0EFE851E963CA040063EE45
+:100A1000840133859B40A685634BA0003DA08145A2
+:100A20001385C4006345A0000DA03145A68533C6DB
+:100A30005A21B306AA0033455621AA953305BA00B8
+:100A4000B69500890505E31EB5FEEA94E69A63CBE8
+:100A5000040063E18403B3859B4026865A85634E78
+:100A6000B00085BF014633059B409385C4006346B3
+:100A7000B00085B7B1455A852686B3C65A213307DB
+:100A8000BA00B3C556212E96B305CA003A96148112
+:100A9000948985050505E39CC5FE25BF33C55A210C
+:100AA0003345552163CB0400A14563EDB400D14526
+:100AB000338995406348200105A01389C40081440F
+:100AC000635C200126954E9505052A999305000241
+:100AD0000C890505E31E25FF22740279626A426BC8
+:100AE000226C026D4EBE4EB83971A2F4CAF0D2EC3F
+:100AF000DAE8E2E4EAE079556D58FD52F1566157C3
+:100B0000A547B1480944C94505469D442ADE194315
+:100B10003AD636D816DA42DC954B3ED4114532CC63
+:100B20002ECE22D046D28D4526CA930D00022EC26B
+:100B30002AC45EC61AC82311B101EFF0EFD4EFF05A
+:100B40004FD5056A130A7A6F630A051EA300BA011E
+:100B50002301BA01A301BA012302BA01A302BA0117
+:100B60002303BA01A303BA012304BA01A304BA01FF
+:100B70002305BA01A305BA012306BA01A306BA01E7
+:100B80002307BA01A307BA012308BA01A308BA01CF
+:100B90002309BA01A309BA01230ABA01230BBA0136
+:100BA000A30BBA01230CBA01A30CBA01230DBA019D
+:100BB000A30DBA01230EBA01A30EBA01230FBA0185
+:100BC000A30FBA012300BA03A300BA032301BA0397
+:100BD000A301BA032302BA03A302BA032303BA038D
+:100BE000A303BA032304BA03A304BA03A305BA03F5
+:100BF0002306BA03A306BA032307BA03A307BA035B
+:100C00002308BA03A308BA032309BA03A309BA0342
+:100C1000230ABA03A30ABA03230BBA03A30BBA032A
+:100C2000230CBA03A30CBA03230DBA03A30DBA0312
+:100C3000230EBA03A30EBA03230FBA032300BA0587
+:100C4000A300BA052301BA05A301BA052302BA0518
+:100C5000A302BA052303BA05A303BA052304BA0500
+:100C6000A304BA052305BA05A305BA052306BA05E8
+:100C7000A306BA052307BA05A307BA052308BA05D0
+:100C8000A308BA052309BA05A309BA05A30ABA0538
+:100C9000230BBA05A30BBA05230CBA05A30CBA059E
+:100CA000230DBA05A30DBA05230EBA05A30EBA0586
+:100CB000230FBA05A30FBA052300BA07A300BA078A
+:100CC0002301BA07A301BA072302BA07A302BA078E
+:100CD0002303BA07A303BA072304BA072305BA07F5
+:100CE000A305BA072306BA07A306BA072307BA075C
+:100CF000A307BA072308BA07A308BA072309BA0744
+:100D0000A309BA07230ABA07A30ABA07230BBA072B
+:100D1000A30BBA07230CBA07A30CBA07230DBA0713
+:100D2000A30DBA07230EBA07A30EBA0726740679D5
+:100D3000666A466B266C066D21614EBE014D6410DD
+:100D4000130B810113042100130C6A0121A0050D6E
+:100D5000630F7D05B3499D2003A90900930C190079
+:100D600023A09901130510029305A007EFF0AFB07F
+:100D70002301A10063E99B0733456D210841FD551F
+:100D80003306B4005082850565FE3306B50063481E
+:100D9000050213264601D146898EB3F6C60E33D618
+:100DA000C50E558E930521006340C0022DA85285C3
+:100DB000EFF06FA6EFF0EFAD014D49DD41BBB3059C
+:100DC000A44001456351C002B3462921B3C6262180
+:100DD000AA963305DC00E2963696948114890505BF
+:100DE0008505E31CC5FE4800B34AAD2003A50A00F3
+:100DF000B385AC4063E7BB06B3456D218C417D569E
+:100E0000B306C400D4820506E5FE93D6F501338708
+:100E1000C500D1478D8F93244701B3F7970E335602
+:100E2000960E5D8E3376D60EB356D70E558E641061
+:100E3000E35FC0F0B3E5050AB3462921B3C6262116
+:100E40003347A5203347A720B6953305EC402E95B0
+:100E5000998DE2952E962300B5010505E31DC5FE8B
+:100E6000FDB51945E3C5A5EE85450145EFF0AFA0F9
+:100E70008545E31EB5EC05458D45EFF0CF9F330565
+:100E8000A04023A0A900CD450145EFF0CF9EB3457A
+:100E90006D2188C10945A145EFF0EF9D23A0AA006F
+:100EA0007DB54EB8411122FC4AF852F45AF062EC7A
+:100EB0006AE805691309D935856993895936056A40
+:100EC000130A2A37856A938AEA37056B130B0B39A5
+:100ED000056C130C3C3605641304B43993041003F9
+:100EE000930C0003856B938B0B32130D2003930D32
+:100EF000300309A85E85EFF00F9213057100854558
+:100F0000EFF00F984A85EFF00F914E85EFF0AF901C
+:100F10005285EFF04F905685EFF0EF8F5A85EFF046
+:100F20008F8F6285EFF02F8F2285EFF0CF8E130524
+:100F300071008945EFF0CF940345710063C7A400A9
+:100F4000630E9501E31895FA09A86306A501E3135A
+:100F5000B5FB513E21A02D3C11A02D3A627442797F
+:100F6000227A027B626C426D41014EBE5801000044
+:100F70006C0100009E010000E6000000A2010000DC
+:100F80006C0100006C0100006C0100006C010000AD
+:100F90006C0100006C010000A80100006C01000061
+:100FA0005C0100000A4D41494E204D454E552050F0
+:100FB00061676520310A003C203E20746F20636821
+:100FC000616E676520706167650A00313A20436190
+:100FD0006C63756C61746F720A00323A2043616C05
+:100FE000656E6461720A00333A20446967696C690E
+:100FF0006E65730A00343A2047616D6573000A4DCF
+:1010000041494E204D454E55205061676520320ABA
+:1010100000353A2053637265656E73617665720AB6
+:1010200000363A205465787420456469746F720AFA
+:10103000004D6F726520636F6D696E6720736F6F0F
+:101040006E0A00286D6179626529000A496E766131
+:101050006C6964206D656E7520706167650A0A0AA7
+:101060000A0A0A000A556E6B6E6F776E206F720A5D
+:1010700000756E696D706C656D656E7465640A00EF
+:10108000636F6D6D616E640A0050726573732061E9
+:101090006E79206B65790A00456E746572206E75F5
+:1010A0006D62657220313A0A3E20000A456E746511
+:1010B00072206E756D62657220323A0A3E20000A17
+:1010C00053656C656374206F7065726174696F6ECF
+:1010D0003A0A5B2B2D2A2F25267C5E3C3C3E3E5D4A
+:1010E000203E20000A496E76616C6964206F70654D
+:1010F000726174696F6E0A004E696365207472795B
+:101100002E000A0A0A0A0A456E7465722063686135
+:101110006E6E656C3A0A3E20000A456E7465722058
+:101120006D6573736167653A0A3E20000A53656E08
+:1011300074210A507265737320616E79206B657932
+:10114000000A434153494E4F0A00596F75206861A8
+:1011500076653A0A24000A42657420686F77206D2C
+:101160007563683F0A283020746F2071756974298F
+:101170000A3E20004E696365207472792E0A005978
+:101180006F752077696E210A00596F752772652087
+:1011900061200A62696C6C696F6E61697265210A0F
+:1011A000426573742071756974207768696C650A8B
+:1011B000796F752772652061686561642E2E2E0A2D
+:1011C0000A507265737320616E79206B65790059DE
+:1011D0006F75206C6F73652E0A00596F75277665E1
+:1011E0002067616D626C656420617761790A796F4F
+:1011F0007572206C69666520736176696E67732EFF
+:101200000A54696D6520746F20676F20686F6D6583
+:101210002E2E2E0A0A507265737320616E79206B30
+:10122000657900475545535320544845204E554D48
+:101230004245520A54686520636F6D70757465721B
+:101240002077696C6C0A7069636B2061206E756D24
+:101250006265722066726F6D0A3120746F203939B1
+:1012600020616E6420796F75206E6565640A746F05
+:101270002067756573732069742E0A0A507265734E
+:101280007320616E79206B657900456E74657220FC
+:10129000796F75722067756573733A0A2830207408
+:1012A0006F2071756974290A3E20000A436F7272BB
+:1012B000656374210A0A596F7520676F7420697419
+:1012C00020696E3A0A0020677565737300207365A4
+:1012D000636F6E64000A546F6F2068696768210A43
+:1012E0000A000A546F6F206C6F77210A0A000A47C0
+:1012F000414D45530A00313A20436173696E6F0ACC
+:1013000000323A20477565737320746865204E7506
+:101310006D6265720A000A0A303A204261636B000E
+:101320000A496E76616C6964206F7074696F6E0A29
+:101330000A507265737320616E79206B65790A0AB1
+:101340000A005256436F6E74726F6C6C65722000A7
+:101350005256436F6E74726F6C6C6572000A0A0AA3
+:101360000A0A0A0A0053435245454E534156455214
+:101370000A00313A204D6172717565650A00323A92
+:1013800020426F756E63696E6720546578740A0039
+:10139000333A204D61747269780A00303A204578FA
+:1013A00069740000300200003002000006020000F4
+:1013B00006020000060200003002000030020000B9
+:1013C00006020000300200000602000030020000A9
+:1013D00006020000060200000602000006020000ED
+:1013E00006020000060200000602000006020000DD
+:1013F00006020000060200000602000006020000CD
+:101400005802000006020000580200000602000018
+:1014100006020000060200000602000006020000AC
+:10142000060200000602000006020000060200009C
+:10143000060200000602000006020000060200008C
+:10144000060200000602000006020000060200007C
+:10145000060200000602000006020000060200006C
+:10146000060200000602000006020000060200005C
+:10147000060200000602000006020000060200004C
+:101480000602000006020000300200000602000012
+:10149000060200000602000006020000060200002C
+:1014A000060200000602000006020000060200001C
+:1014B000060200000602000006020000060200000C
+:1014C00006020000060200000602000006020000FC
+:1014D00006020000060200000602000006020000EC
+:1014E00006020000060200000602000006020000DC
+:1014F00006020000060200000602000006020000CC
+:10150000300200005202000080020000C40200000D
+:10151000C4020000C402000074020000A602000021
+:10152000C4020000AC020000C40200007A02000005
+:10153000C4020000C4020000C4020000C402000093
+:10154000C4020000C4020000C4020000C402000083
+:10155000C4020000C4020000C4020000C402000073
+:1015600086020000C402000094020000C4020000D1
+:10157000C4020000C4020000C4020000C402000053
+:10158000C4020000C4020000C4020000C402000043
+:10159000C4020000C4020000C4020000C402000033
+:1015A000C4020000C4020000C4020000C402000023
+:1015B000C4020000C4020000C4020000C402000013
+:1015C000C4020000C4020000C4020000C402000003
+:1015D000C4020000C4020000C4020000C4020000F3
+:1015E000C4020000C4020000B8020000C4020000EF
+:1015F000C4020000C4020000C4020000C4020000D3
+:10160000C4020000C4020000C4020000C4020000C2
+:10161000C4020000C4020000C4020000C4020000B2
+:10162000C4020000C4020000C4020000C4020000A2
+:10163000C4020000C4020000C4020000C402000092
+:10164000C4020000C4020000C4020000C402000082
+:10165000C4020000C4020000C4020000C402000072
+:10166000B2020000F8FFFFFFFCFFFFFFFFFFFFFFDC
+:10167000FBFFFFFFFEFFFFFF010000001200000064
+:10168000020000000C000000090000000300000040
+:101690000400000005000000060000000700000034
+:1016A0000A4C617374206368616E6E656C3A0A2837
+:1016B0006E6F6E65292020202020202020202020F1
+:1016C0002020200A4C617374206D65737361676517
+:1016D0003A0A286E6F6E65292020202020202020C5
+:1016E0002020202020200A733A2053656E640A715E
+:1016F0003A2051756974000A2020202020202020E3
+:101700002020202020202020202020200A202020EF
+:1017100020202020202020202020202020202020C9
+:10172000200A2020202020202020202020202020CF
+:101730002020202020200A202020202020202020BF
+:1017400020202020202020202020200A20202020AF
+:101750002020202020202020202020202020202089
+:101760000A2020202020202020202020202020208F
+:0717700020202020200000D2
+:00000001FF
diff --git a/c/menu/menu.o b/c/menu/menu.o
new file mode 100644
index 0000000..43e4e58
--- /dev/null
+++ b/c/menu/menu.o
Binary files differ
diff --git a/c/menu/rvcontroller.ld b/c/menu/rvcontroller.ld
new file mode 100644
index 0000000..985892b
--- /dev/null
+++ b/c/menu/rvcontroller.ld
@@ -0,0 +1,45 @@
+/* Thanks https://github.com/darklife/darkriscv */
+ __heap_size = 0x200; /* required amount of heap */
+ __stack_size = 0x800; /* required amount of stack */
+ ENTRY(_start);
+ MEMORY
+ {
+ RAM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x10000
+ }
+ SECTIONS
+ {
+ .text :
+ {
+ *(.text.startup)
+ *(.text)
+ *(.text)
+ *(.rodata*)
+ } > RAM
+ .data :
+ {
+ *(.sbss)
+ *(.data)
+ *(.bss)
+ *(.rela*)
+ *(COMMON)
+ } > RAM
+
+ .heap :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ _sheap = .;
+ . = . + __heap_size;
+ . = ALIGN(4);
+ _eheap = .;
+ } >RAM
+
+ .stack :
+ {
+ . = ALIGN(4);
+ _estack = .;
+ . = . + __stack_size;
+ . = ALIGN(4);
+ _sstack = .;
+ } >RAM
+ }
diff --git a/c/menu/screensaver.c b/c/menu/screensaver.c
new file mode 100644
index 0000000..70e1647
--- /dev/null
+++ b/c/menu/screensaver.c
@@ -0,0 +1,137 @@
+/* Menu Thing for RVController - Screensaver
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "rvcontroller-ecalls.h"
+
+char screensaverbuf[] = "\n \n \n \n \n \n ";
+
+int strlen(char *string) {
+ int i;
+ for (i = 0;string[i] != 0;i++) {}
+ return i;
+}
+
+void screensaverWriteText(char *text, int column, int row, bool erase) {
+ int textlen = strlen(text);
+ if (column < 0) {
+ // Cut the left side off of the text and change the start position to the left side of the screen
+ text = text + (0 - column);
+ textlen = textlen + column;
+ column = 0;
+ } else if (column + textlen > 19) {
+ // Cut the right side off of the text
+ textlen = 20 - column;
+ }
+ for (int i=0;i < textlen;i++) {
+ if (erase) {
+ screensaverbuf[(row*21)+column+i+1] = 0x20;
+ } else {
+ screensaverbuf[(row*21)+column+i+1] = text[i];
+ }
+ }
+}
+
+void doMarquee(void) {
+ char text[] = "RVController ";
+ int col = 19;
+ int row = randomint(0,5);
+ console_clearbuffer();
+ while (console_readchar() == 0) {
+ col--;
+ if (col < (0 - strlen(text))) {
+ col = 20;
+ row = randomint(0,5);
+ }
+ screensaverWriteText(text,col,row,false);
+ printstr(screensaverbuf);
+ }
+ screensaverWriteText(text,col,row,true);
+}
+
+void doBouncingText(void) {
+ char text[] = "RVController";
+ int col = 0;
+ int row = 0;
+ int xdir = 1;
+ int ydir = 1;
+ console_clearbuffer();
+ while (console_readchar() == 0) {
+ screensaverWriteText(text,col,row,true);
+ col = col + xdir;
+ row = row + ydir;
+ if (col <= 0) { xdir = 1; }
+ if (col >= (19 - strlen(text))) { xdir = -1; }
+ if (row <= 0) { ydir = 1; }
+ if (row >= 5) { ydir = -1; }
+ screensaverWriteText(text,col,row,false);
+ printstr(screensaverbuf);
+ }
+ screensaverWriteText(text,col,row,true);
+}
+
+void doMatrix(void) {
+ int row[] = {-8,-4,-1,-5,-2}; // "Random" positions off the top of the screen to give "random" start delays
+ int col[] = {1,18,2,12,9};
+ int len[] = {3,4,5,6,7};
+ char textscratch[] = " ";
+ console_clearbuffer();
+ while (console_readchar() == 0) {
+ for (int i=0;i<=4;i++) {
+ row[i]++;
+ textscratch[0] = randomint(0x21,0x7a);
+ if (row[i] <= 5 && row[i] >= 0) {
+ screensaverWriteText(textscratch,col[i],row[i],false);
+ }
+ if ((row[i] - len[i]) <= 5 && (row[i] - len[i]) >= 0) {
+ screensaverWriteText(textscratch,col[i],(row[i] - len[i]),true);
+ } else if ((row[i] - len[i]) > 5 && randomint(0,1) == 1) {
+ row[i] = 0 - randomint(1,3);
+ col[i] = randomint(0,19);
+ len[i] = randomint(2,8);
+ }
+ }
+ printstr(screensaverbuf);
+ }
+ for (int i=0;i <= 5;i++) {
+ screensaverWriteText(" ",0,i,true);
+ }
+}
+
+void runScreensaver(void) {
+ char inputbuf[9];
+ bool quit = false;
+ while (!quit) {
+ printstr("\n\n\n\n\n\n\n");
+ printstr("SCREENSAVER\n");
+ printstr("1: Marquee\n");
+ printstr("2: Bouncing Text\n");
+ printstr("3: Matrix\n");
+ printstr("\n");
+ printstr("0: Exit");
+ readstr(inputbuf,2);
+ switch (inputbuf[0]) {
+ case '0':
+ quit = true;
+ break;
+ case '1':
+ doMarquee();
+ quit = true;
+ break;
+ case '2':
+ doBouncingText();
+ quit = true;
+ break;
+ case '3':
+ doMatrix();
+ quit = true;
+ break;
+ default:
+ printstr("\nInvalid option\n\nPress any key\n\n\n");
+ readstr(inputbuf,1);
+ }
+ }
+}
diff --git a/c/menu/screensaver.h b/c/menu/screensaver.h
new file mode 100644
index 0000000..f56811a
--- /dev/null
+++ b/c/menu/screensaver.h
@@ -0,0 +1,6 @@
+/* Menu Thing for RVController - Screensaver
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+void runScreensaver(void);
diff --git a/c/menu/screensaver.o b/c/menu/screensaver.o
new file mode 100644
index 0000000..1f725d3
--- /dev/null
+++ b/c/menu/screensaver.o
Binary files differ
diff --git a/c/rrxing/Makefile b/c/rrxing/Makefile
new file mode 100644
index 0000000..1087a53
--- /dev/null
+++ b/c/rrxing/Makefile
@@ -0,0 +1,20 @@
+all: rrxing.hex
+
+rrxing.o: rrxing.c
+ clang -target riscv32-none-elf -I../rvcontroller-libraries -march=rv32imacb_zicntr_zicond_zicsr_zifencei_zihintpause_zilsd_zclsd_zabha_zacas_zbkb_zbkx_zcb_zcmp_zcmt -ffreestanding -O3 -c -o rrxing.o rrxing.c
+
+rrxing.elf: ../rvcontroller-libraries/rvcontroller-init.o ../rvcontroller-libraries/rvcontroller-ecalls.o rrxing.o
+ riscv32-none-elf-ld -T rvcontroller.ld --no-warn-rwx-segments -o rrxing.elf ../rvcontroller-libraries/rvcontroller-init.o rrxing.o ../rvcontroller-libraries/rvcontroller-ecalls.o
+
+dump: rrxing.elf
+ riscv32-none-elf-objdump -d rrxing.elf
+
+rrxing.hex: rrxing.elf
+ riscv32-none-elf-objcopy -O ihex rrxing.elf rrxing.hex
+
+load: rrxing.hex
+ bash -c "wl-copy < rrxing.hex"
+
+clean:
+ rm -f rrxing.bin rrxing.elf rrxing.o init.o
+
diff --git a/c/rrxing/rrxing.c b/c/rrxing/rrxing.c
new file mode 100644
index 0000000..e867e8a
--- /dev/null
+++ b/c/rrxing/rrxing.c
@@ -0,0 +1,86 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include "rvcontroller-ecalls.h"
+
+bool streq(char *a, char *b) {
+ for (int i=0;a[i] != 0 || b[i] != 0;i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void sleep(uint32_t delay) {
+ //This will start having problems after about 130 years
+ //of uptime, but that's probably acceptable
+ uint32_t endtime = rdtime() + delay;
+ while (rdtime() < endtime) {}
+ return;
+}
+
+bool checkdetector(void) {
+ char channelbuf[16];
+ char msgbuf[16];
+ while (digiline_bufferlevel() > 0) {
+ lightweight_mode(0);
+ digiline_receive(channelbuf,16,msgbuf,16);
+ if (streq(channelbuf,"detect")) {
+ return true;
+ }
+ }
+ lightweight_mode(1);
+ return false;
+}
+
+void main() {
+ printstr("Railroad Crossing\nfor RVController\nInitializing HW\n");
+ digiline_send("light","OFF");
+ digiline_send("bell","off");
+ digiline_send("gate","up");
+ digiline_clearbuffer();
+ while (true) {
+ printstr("Idle\n");
+ lightweight_mode(1);
+ printstr("Lightweight: On\n");
+ while (!checkdetector()) {}
+ printstr("Train detected\nLightweight: Off\n");
+ lightweight_mode(0);
+ digiline_send("light","YELLOW");
+ printstr("Light: Yellow\n");
+ sleep(2);
+ digiline_send("bell","on");
+ printstr("Bell: On\n");
+ sleep(2);
+ digiline_send("light","RED");
+ printstr("Light: Red\n");
+ sleep(3);
+ digiline_send("gate","down");
+ printstr("Gate: Down\n");
+ sleep(4);
+ digiline_send("bell","off");
+ printstr("Bell: Off\n");
+
+ digiline_clearbuffer();
+ for (uint8_t time = 15;time > 0;time--) {
+ printstr("Timeout in ");
+ printint(time);
+ printstr("s\n");
+ sleep(1);
+ bool train = checkdetector();
+ lightweight_mode(0); //checkdetector() turns this on
+ if (train) {
+ digiline_clearbuffer();
+ time = 25;
+ printstr("Time reset by train\n");
+ }
+ }
+ printstr("Timed out\n");
+
+ digiline_send("gate","up");
+ printstr("Gate: Up\n");
+ sleep(2);
+ digiline_send("light","OFF");
+ printstr("Light: Off\n");
+ }
+}
diff --git a/c/rrxing/rrxing.elf b/c/rrxing/rrxing.elf
new file mode 100755
index 0000000..fd70937
--- /dev/null
+++ b/c/rrxing/rrxing.elf
Binary files differ
diff --git a/c/rrxing/rrxing.hex b/c/rrxing/rrxing.hex
new file mode 100644
index 0000000..a6ac7d8
--- /dev/null
+++ b/c/rrxing/rrxing.hex
@@ -0,0 +1,70 @@
+:10000000370101006520A948730000008280148137
+:10001000988133E6E60009C685050505E389E6FE15
+:1000200013351600828052B82A84452C2A947524F0
+:10003000E36F85FE52BE4EB822F44AF0692435C102
+:100040001309400693045006130440079309300631
+:1000500019A0952C39C50145612C0808C1450A86AF
+:10006000C146BD2403450101E31525FF03451101E8
+:10007000E31195FE03452101E31D85FC0345310194
+:10008000E31995FC03454101E31535FD0345510195
+:10009000E31185FC034561014DFD0545227402799C
+:1000A0004EBE0545B124227402794EBC4EB80111F2
+:1000B000A2E4CAE052FC5AF862F46AF01305203355
+:1000C000F522130460369305C0362285C52A9309AC
+:1000D0000037930550374E85D52213059037930589
+:1000E000E037E92A0924930B4006130C5006930DC0
+:1000F000400713093006930C8040130D4041930ACA
+:100100007041130510385D220545DD221305703856
+:10011000712A552A21C50145E12A0808C1450A86E8
+:10012000C1467D2203450101E31575FF0345110119
+:10013000E31185FF03452101E31DB5FD03453101B1
+:10014000E31985FD03454101E31525FD03455101F3
+:10015000E311B5FD034561014DFD21A00545492A87
+:100160004DBF1305803999220145592222859305F7
+:10017000903BA9221305003C152A852293042500F3
+:10018000A92AE36F95FE4E859305F03C052A1305D9
+:10019000203D292A9922930425008122E36F95FEB0
+:1001A00022859305C03D192A1305003E0122352200
+:1001B000930435001D22E36F95FE130590379305D8
+:1001C000C03EED281305103FD520012A93044500B9
+:1001D0002922E36F95FE4E8A4E8593055037F92804
+:1001E0001305D03FE1200122BD4909A80545092298
+:1001F0000145FD28FD1913F5F90F3DC913FBF90F52
+:1002000066856D205A8579286A854D20F9209304EA
+:100210001500E120E36F95FE7D2069D90145C928CD
+:100220000808C1450A86C146652003450101E3155A
+:1002300075FF03451101E31185FF03452101E31D0E
+:10024000B5FD03453101E31985FD03454101E31582
+:1002500025FD03455101E311B5FD034561014DFD48
+:100260004128512056859920E14913F5F90F59F598
+:100270001305C0422528130590379305E0373D2824
+:10028000130570432520912893042500B920E36FBE
+:1002900095FE22859305C03615201305104439209C
+:1002A000D28985B58548730000008280914873002B
+:1002B00000008280AD48730000008280930810081F
+:1002C0007300000082809308500873000000828051
+:1002D00093087008730000008280732510C082802C
+:1002E000732500C08280930860087300000082803C
+:1002F0000589F322008093920248B3E2A200739032
+:100300000280828095487300000082809308000874
+:10031000730000008280A14873000000828093086F
+:1003200030087300000082809308400873000000CA
+:1003300082805261696C726F61642043726F737363
+:10034000696E670A666F72205256436F6E74726FE1
+:100350006C6C65720A496E697469616C697A696E60
+:10036000672048570A006C69676874004F4646006A
+:1003700062656C6C006F666600676174650075701D
+:100380000049646C650A004C696768747765696741
+:1003900068743A204F6E0A00547261696E20646579
+:1003A0007465637465640A4C696768747765696726
+:1003B00068743A204F66660A0059454C4C4F570006
+:1003C0004C696768743A2059656C6C6F770A006FE6
+:1003D0006E0042656C6C3A204F6E0A005245440034
+:1003E0004C696768743A205265640A00646F776EDE
+:1003F00000476174653A20446F776E0A0042656C6D
+:100400006C3A204F66660A0054696D656F757420FA
+:10041000696E2000730A0054696D6520726573650A
+:100420007420627920747261696E0A0054696D6586
+:1004300064206F75740A00476174653A2055700A2C
+:0D044000004C696768743A204F66660A0038
+:00000001FF
diff --git a/c/rrxing/rrxing.o b/c/rrxing/rrxing.o
new file mode 100644
index 0000000..3d0bd00
--- /dev/null
+++ b/c/rrxing/rrxing.o
Binary files differ
diff --git a/c/rrxing/rvcontroller.ld b/c/rrxing/rvcontroller.ld
new file mode 100644
index 0000000..985892b
--- /dev/null
+++ b/c/rrxing/rvcontroller.ld
@@ -0,0 +1,45 @@
+/* Thanks https://github.com/darklife/darkriscv */
+ __heap_size = 0x200; /* required amount of heap */
+ __stack_size = 0x800; /* required amount of stack */
+ ENTRY(_start);
+ MEMORY
+ {
+ RAM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x10000
+ }
+ SECTIONS
+ {
+ .text :
+ {
+ *(.text.startup)
+ *(.text)
+ *(.text)
+ *(.rodata*)
+ } > RAM
+ .data :
+ {
+ *(.sbss)
+ *(.data)
+ *(.bss)
+ *(.rela*)
+ *(COMMON)
+ } > RAM
+
+ .heap :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ _sheap = .;
+ . = . + __heap_size;
+ . = ALIGN(4);
+ _eheap = .;
+ } >RAM
+
+ .stack :
+ {
+ . = ALIGN(4);
+ _estack = .;
+ . = . + __stack_size;
+ . = ALIGN(4);
+ _sstack = .;
+ } >RAM
+ }
diff --git a/c/rvcontroller-libraries/Makefile b/c/rvcontroller-libraries/Makefile
new file mode 100644
index 0000000..eca2a8c
--- /dev/null
+++ b/c/rvcontroller-libraries/Makefile
@@ -0,0 +1,10 @@
+all: rvcontroller-init.o rvcontroller-ecalls.o
+
+rvcontroller-init.o: rvcontroller-init.S
+ riscv32-none-elf-as -march=rv32imcb_zicsr_zbkx -o rvcontroller-init.o rvcontroller-init.S
+
+rvcontroller-ecalls.o: rvcontroller-ecalls.S
+ riscv32-none-elf-as -march=rv32imcb_zicsr_zbkx -o rvcontroller-ecalls.o rvcontroller-ecalls.S
+
+clean:
+ rm -f rvcontroller-init.o rvcontroller-ecalls.o
diff --git a/c/rvcontroller-libraries/rvcontroller-ecalls.S b/c/rvcontroller-libraries/rvcontroller-ecalls.S
new file mode 100644
index 0000000..454bcb6
--- /dev/null
+++ b/c/rvcontroller-libraries/rvcontroller-ecalls.S
@@ -0,0 +1,108 @@
+#RVController ecall C Library - Assembly Portion
+#A product of Advanced Mesecons Devices, a Cheapie Systems company
+#This is free and unencumbered software released into the public domain.
+#See http://unlicense.org/ for more information
+
+printint:
+# Number to print is already in a0
+li a7,1 # Write number
+ecall
+ret
+
+printstr:
+# String address is already in a0
+li a7,4
+ecall
+ret
+
+printchar:
+# Character is already in a0
+li a7,11
+ecall
+ret
+
+digiline_send:
+# Channel pointer is already in a0, message pointer is already in a1
+li a7,129
+ecall
+ret
+
+digiline_bufferlevel:
+li a7,133
+ecall
+# Result is already in a0
+ret
+
+digiline_receive:
+# Arguments are already in a0-a3
+li a7,135
+ecall
+ret
+
+rdtime:
+rdtime a0
+ret
+
+rdcycle:
+rdcycle a0
+ret
+
+digiline_clearbuffer:
+li a7,134
+ecall
+ret
+
+lightweight_mode:
+andi a0,a0,1
+csrrs t0,0x800,x0
+bclri t0,t0,0
+or t0,t0,a0
+csrrw x0,0x800,t0
+ret
+
+readint:
+li a7,5
+ecall
+# Result is already in a0
+ret
+
+randomint:
+li a7,128
+# Arguments are already in a0 and a1
+ecall
+# Result is already in a0
+ret
+
+readstr:
+li a7,8
+# Arguments are already in a0 and a1
+ecall
+# Result is already in a0
+ret
+
+console_clearbuffer:
+li a7,131
+ecall
+ret
+
+console_readchar:
+li a7,132
+ecall
+# Result is already in a0
+ret
+
+.globl printint
+.globl printstr
+.globl printchar
+.globl digiline_send
+.globl digiline_bufferlevel
+.globl digiline_receive
+.globl rdtime
+.globl rdcycle
+.globl digiline_clearbuffer
+.globl lightweight_mode
+.globl readint
+.globl randomint
+.globl readstr
+.globl console_clearbuffer
+.globl console_readchar
diff --git a/c/rvcontroller-libraries/rvcontroller-ecalls.h b/c/rvcontroller-libraries/rvcontroller-ecalls.h
new file mode 100644
index 0000000..7107d21
--- /dev/null
+++ b/c/rvcontroller-libraries/rvcontroller-ecalls.h
@@ -0,0 +1,108 @@
+/* RVController ecall C Library - C Header Portion
+ * A product of Advanced Mesecons Devices, a Cheapie Systems company
+ * This is free and unencumbered software released into the public domain.
+ * See http://unlicense.org/ for more information */
+
+#ifndef _STDINT_H
+#include <stdint.h>
+#endif
+
+/* printint(number)
+ *
+ * Prints a 32-bit signed integer to standard output.
+ * number: The number to print */
+void printint(int32_t number);
+
+/* printstr(*str)
+ *
+ * Prints a null-terminated ASCII string to standard output.
+ * *str: Pointer to the start of the string data */
+void printstr(char *str);
+
+/* printchar(c)
+ *
+ * Prints a single ASCII character to standard output.
+ * c: The character to print */
+void printchar(char c);
+
+/* digiline_send(*channel,*msg)
+ *
+ * Sends an arbitrary digilines message on an arbitrary channel.
+ * *channel: Pointer to the start of the null-terminated channel string
+ * *msg: Pointer to the start of the null-terminated message string */
+void digiline_send(char *channel, char *msg);
+
+/* digiline_bufferlevel()
+ *
+ * Reads the current number of digilines messages that have been received
+ * but not yet read.
+ * Returns: Number of messages */
+uint8_t digiline_bufferlevel(void);
+
+/* digiline_receive(*channelbuf,channelbuflen,*msgbuf,msgbuflen)
+ *
+ * Reads the first (oldest) digilines message from the receive queue and removes
+ * the message from the queue.
+ * Null termination will be added to all received strings.
+ * *channelbuf: Pointer to the location of a buffer into which the channel will be placed
+ * channelbuflen: The size of the buffer pointed to by channelbuf
+ * *msgbuf: Pointer to the location of a buffer into which the message will be placed
+ * msgbuflen: The size of the buffer pointed to by channelbuf */
+void digiline_receive(char *channelbuf, int channelbuflen, char *msgbuf, int msgbuflen);
+
+/* rdcycle()
+ *
+ * Reads the number of clock cycles that have passed since the processor was started.
+ * Returns: Number of clock cycles */
+uint32_t rdcycle(void);
+
+/* rdtime()
+ *
+ * Reads the number of seconds that have elapsed since the processor was started.
+ * Returns: Number of seconds */
+uint32_t rdtime(void);
+
+/* digiline_clearbuffer()
+ *
+ * Discards all received digilines messages currently waiting in the queue. */
+void digiline_clearbuffer(void);
+
+/* lightweight_mode(enabled)
+ *
+ * Turns lightweight mode (see RVController documentation) or or off.
+ * enabled: 1 to enable, 0 to disable, other values are reserved */
+void lightweight_mode(char enabled);
+
+/* readint()
+ *
+ * Reads a 32-bit signed integer from the console.
+ * This will block until the user enters a valid number.
+ * returns: The number typed by the user */
+int32_t readint(void);
+
+/* readstr()
+ *
+ * Reads a null-terminated string from the console.
+ * This will block until the user enters something.
+ * buffer: Pointer to a buffer that the string will be stored in
+ * bufsize: The size of the buffer */
+void readstr(char *buffer, uint32_t bufsize);
+
+/* randomint(lowlimit,highlimit)
+ *
+ * Generates a random integer between lowlimit and highlimit.
+ * lowlimit: The lowest number that can be generated (inclusive)
+ * highlimit: The highest number that can be generated (inclusive)
+ * returns: Random number */
+int32_t randomint(int32_t lowlimit,int32_t highlimit);
+
+/* console_clearbuffer()
+ *
+ * Discards all characters currently waiting in the console input buffer. */
+void console_clearbuffer(void);
+
+/* console_readchar()
+ *
+ * Reads one character from the console input buffer.
+ * returns: Character, or 0 if no characters are available to read */
+char console_readchar(void);
diff --git a/c/rvcontroller-libraries/rvcontroller-ecalls.o b/c/rvcontroller-libraries/rvcontroller-ecalls.o
new file mode 100644
index 0000000..e23d3fe
--- /dev/null
+++ b/c/rvcontroller-libraries/rvcontroller-ecalls.o
Binary files differ
diff --git a/c/rvcontroller-libraries/rvcontroller-init.S b/c/rvcontroller-libraries/rvcontroller-init.S
new file mode 100644
index 0000000..83cab9d
--- /dev/null
+++ b/c/rvcontroller-libraries/rvcontroller-init.S
@@ -0,0 +1,26 @@
+#Assembly stub for C programs targeting RVController
+#A product of Advanced Mesecons Devices, a Cheapie Systems company
+#This is free and unencumbered software released into the public domain.
+#See http://unlicense.org/ for more information
+
+#This file should always be linked first.
+#RVController has a default reset vector of 0,
+#therefore _start should end up as the first thing in the file.
+
+.section .text.startup
+_start:
+
+# Set up stack pointer
+li sp,0x10000
+
+# Call main function
+call main
+
+# Exit program
+li a7,10
+ecall
+
+# Shouldn't ever get here, will crash if it does
+ret
+
+.globl _start
diff --git a/c/rvcontroller-libraries/rvcontroller-init.o b/c/rvcontroller-libraries/rvcontroller-init.o
new file mode 100644
index 0000000..3f57faf
--- /dev/null
+++ b/c/rvcontroller-libraries/rvcontroller-init.o
Binary files differ
diff --git a/c/squares/Makefile b/c/squares/Makefile
new file mode 100644
index 0000000..f957bfa
--- /dev/null
+++ b/c/squares/Makefile
@@ -0,0 +1,20 @@
+all: squares.hex
+
+squares.o: squares.c
+ clang -target riscv32-none-elf -I../rvcontroller-libraries -march=rv32imacb_zicntr_zicond_zicsr_zifencei_zihintpause_zilsd_zclsd_zabha_zacas_zbkb_zbkx_zcb_zcmp_zcmt -ffreestanding -O3 -c -o squares.o squares.c
+
+squares.elf: ../rvcontroller-libraries/rvcontroller-init.o ../rvcontroller-libraries/rvcontroller-ecalls.o squares.o
+ riscv32-none-elf-ld -T rvcontroller.ld --no-warn-rwx-segments -o squares.elf ../rvcontroller-libraries/rvcontroller-init.o squares.o ../rvcontroller-libraries/rvcontroller-ecalls.o
+
+dump: squares.elf
+ riscv32-none-elf-objdump -d squares.elf
+
+squares.hex: squares.elf
+ riscv32-none-elf-objcopy -O ihex squares.elf squares.hex
+
+load: squares.hex
+ bash -c "wl-copy < squares.hex"
+
+clean:
+ rm -f squares.bin squares.elf squares.o init.o
+
diff --git a/c/squares/rvcontroller.ld b/c/squares/rvcontroller.ld
new file mode 100644
index 0000000..985892b
--- /dev/null
+++ b/c/squares/rvcontroller.ld
@@ -0,0 +1,45 @@
+/* Thanks https://github.com/darklife/darkriscv */
+ __heap_size = 0x200; /* required amount of heap */
+ __stack_size = 0x800; /* required amount of stack */
+ ENTRY(_start);
+ MEMORY
+ {
+ RAM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x10000
+ }
+ SECTIONS
+ {
+ .text :
+ {
+ *(.text.startup)
+ *(.text)
+ *(.text)
+ *(.rodata*)
+ } > RAM
+ .data :
+ {
+ *(.sbss)
+ *(.data)
+ *(.bss)
+ *(.rela*)
+ *(COMMON)
+ } > RAM
+
+ .heap :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ _sheap = .;
+ . = . + __heap_size;
+ . = ALIGN(4);
+ _eheap = .;
+ } >RAM
+
+ .stack :
+ {
+ . = ALIGN(4);
+ _estack = .;
+ . = . + __stack_size;
+ . = ALIGN(4);
+ _sstack = .;
+ } >RAM
+ }
diff --git a/c/squares/squares.b b/c/squares/squares.b
new file mode 100644
index 0000000..b235485
--- /dev/null
+++ b/c/squares/squares.b
@@ -0,0 +1,8 @@
+++++[>+++++<-]>[<+++++>-]+<+[
+ >[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]+
+ >>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]
+ <<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<]]<[>+<-]>]<<-]<<-
+]
+[Outputs square numbers from 0 to 10000.
+Daniel B Cristofani (cristofdathevanetdotcom)
+http://www.hevanet.com/cristofd/brainfuck/]
diff --git a/c/squares/squares.c b/c/squares/squares.c
new file mode 100644
index 0000000..435ddff
--- /dev/null
+++ b/c/squares/squares.c
@@ -0,0 +1,169 @@
+/* This is a translation of squares.b, generated by bftoc.py (by Paul Kaefer)
+ * It was generated on Friday, May 15, 2026 at 07:20PM
+ */
+
+#include "rvcontroller-ecalls.h"
+
+void main(void)
+{
+ int size = 1000;
+ int tape[size];
+ int i = 0;
+
+ /* Clearing the tape (array) */
+ for (i=0; i<size; i++)
+ tape[i] = 0;
+
+ int ptr = 0;
+
+ tape[ptr] += 4;
+ while (tape[ptr] != 0)
+ {
+ ptr += 1;
+ tape[ptr] += 5;
+ ptr -= 1;
+ tape[ptr] -= 1;
+ }
+ ptr += 1;
+ while (tape[ptr] != 0)
+ {
+ ptr -= 1;
+ tape[ptr] += 5;
+ ptr += 1;
+ tape[ptr] -= 1;
+ }
+ tape[ptr] += 1;
+ ptr -= 1;
+ tape[ptr] += 1;
+ while (tape[ptr] != 0)
+ {
+ ptr += 1;
+ while (tape[ptr] != 0)
+ {
+ ptr += 1;
+ tape[ptr] += 1;
+ ptr += 1;
+ tape[ptr] += 1;
+ ptr -= 2;
+ tape[ptr] -= 1;
+ }
+ tape[ptr] += 2;
+ ptr += 2;
+ while (tape[ptr] != 0)
+ {
+ ptr -= 2;
+ tape[ptr] += 1;
+ ptr += 2;
+ tape[ptr] -= 1;
+ }
+ ptr += 3;
+ while (tape[ptr] != 0)
+ {
+ tape[ptr] -= 1;
+ }
+ tape[ptr] += 2;
+ ptr += 1;
+ while (tape[ptr] != 0)
+ {
+ tape[ptr] -= 1;
+ }
+ tape[ptr] += 1;
+ ptr += 3;
+ tape[ptr] += 1;
+ while (tape[ptr] != 0)
+ {
+ while (tape[ptr] != 0)
+ {
+ tape[ptr] -= 1;
+ }
+ tape[ptr] += 6;
+ ptr += 3;
+ }
+ ptr -= 3;
+ while (tape[ptr] != 0)
+ {
+ while (tape[ptr] != 0)
+ {
+ ptr -= 1;
+ tape[ptr] += 8;
+ ptr -= 1;
+ tape[ptr] += 2;
+ ptr += 2;
+ tape[ptr] -= 1;
+ }
+ tape[ptr] += 1;
+ ptr -= 1;
+ printchar(tape[ptr]);
+ ptr -= 1;
+ while (tape[ptr] != 0)
+ {
+ ptr += 1;
+ tape[ptr] -= 4;
+ ptr -= 1;
+ tape[ptr] -= 1;
+ }
+ ptr -= 1;
+ }
+ ptr -= 2;
+ while (tape[ptr] != 0)
+ {
+ ptr += 5;
+ while (tape[ptr] != 0)
+ {
+ ptr += 3;
+ while (tape[ptr] != 0)
+ {
+ tape[ptr] -= 1;
+ }
+ tape[ptr] += 9;
+ ptr -= 1;
+ while (tape[ptr] != 0)
+ {
+ ptr += 1;
+ tape[ptr] -= 1;
+ ptr -= 1;
+ tape[ptr] -= 1;
+ }
+ tape[ptr] += 9;
+ ptr += 1;
+ while (tape[ptr] != 0)
+ {
+ tape[ptr] -= 1;
+ while (tape[ptr] != 0)
+ {
+ ptr -= 1;
+ tape[ptr] -= 1;
+ ptr += 1;
+ tape[ptr] -= 1;
+ }
+ tape[ptr] += 1;
+ while (tape[ptr] != 0)
+ {
+ ptr -= 3;
+ }
+ }
+ ptr -= 1;
+ while (tape[ptr] != 0)
+ {
+ ptr += 1;
+ tape[ptr] += 1;
+ ptr -= 1;
+ tape[ptr] -= 1;
+ }
+ ptr += 1;
+ }
+ ptr -= 2;
+ tape[ptr] -= 1;
+ }
+ ptr -= 2;
+ tape[ptr] -= 1;
+ }
+ while (tape[ptr] != 0)
+ {
+ printchar(tape[ptr]);
+ printchar(tape[ptr]);
+ printchar(tape[ptr]);
+ }
+
+}
+
diff --git a/c/squares/squares.elf b/c/squares/squares.elf
new file mode 100755
index 0000000..e0050b8
--- /dev/null
+++ b/c/squares/squares.elf
Binary files differ
diff --git a/c/squares/squares.hex b/c/squares/squares.hex
new file mode 100644
index 0000000..0df4797
--- /dev/null
+++ b/c/squares/squares.hex
@@ -0,0 +1,42 @@
+:10000000370101002920A9487300000082804EB802
+:10001000130101801301018605650A95233485FCCF
+:1000200005650A95233025FD05650A95233C45FBAA
+:1000300005650A95233865FB08089305F57F9385C8
+:10004000157A232005001105E31DB5FE4245D24572
+:10005000130645003345A5202E955105B3F5C50E71
+:100060003355C50E4D8D0DCD3345A5208545050570
+:100070002AC82ECA0DE905650A95033485FC056575
+:100080000A95033905FC05650A95033A85FB056564
+:100090000A95033B05FB1301017F1301017B4EBE53
+:1000A00005452AC82ACA8144930B0101930981029C
+:1000B0000949054A254B994A080809A89304E5FF10
+:1000C00033C574210C41FD150CC1D5D54C4199C9DE
+:1000D000104554452E96B69510C54CC523222501D2
+:1000E00091E519A84C452322250199C50946FD151E
+:1000F0000506F5FD50C14CC5232C2501232E4501D5
+:10010000A90433C574210C4185050CC199C54C4522
+:100110002320550131058D04FDF91385D4FF3344A7
+:100120007521084009ED1385B4FFB34575218C4155
+:10013000B9E969B7032544FF5114F5146DD583253A
+:10014000C4FF032684FFB365B5203325C520232CC7
+:10015000A4FE232EB4FE2320440113F5F50F7520D1
+:10016000032584FF61D98325C4FF0A05898D232CCB
+:1001700004FE232EB4FE7DBF7915B3457521904151
+:100180007D1690C105DE1505B345752190416DD6EC
+:10019000904523A6650109CADD567D16850675FEC4
+:1001A000B306D04090C5D4C523A46501130635001D
+:1001B000B34576219441638B460199E232851DA0B7
+:1001C00003A6C5FF158E050623AEC5FE23A0450177
+:1001D00013066500B3453521328503A645FFD115C9
+:1001E000751565FE03A6C5FF41DA23AE05FE90C175
+:1001F000B3457521904149FE41B785487300000021
+:1002000082809148730000008280AD487300000036
+:1002100082809308100873000000828093085008C1
+:1002200073000000828093087008730000008280D1
+:10023000732510C08280732500C0828093086008F7
+:100240007300000082800589F322008093920248A7
+:10025000B3E2A20073900280828095487300000090
+:10026000828093080008730000008280A148730018
+:100270000000828093083008730000008280930899
+:080280004008730000008280B9
+:00000001FF
diff --git a/c/squares/squares.o b/c/squares/squares.o
new file mode 100644
index 0000000..64e0c71
--- /dev/null
+++ b/c/squares/squares.o
Binary files differ
diff --git a/cross-links b/cross-links
new file mode 100644
index 0000000..8f17550
--- /dev/null
+++ b/cross-links
@@ -0,0 +1,3 @@
+https://wiki.osdev.org/GCC_Cross-Compiler
+https://stackoverflow.com/questions/31022638/risc-v-rv32i-soft-float-lib-calls-mul-and-mulhu-instructions-in-muldf3
+
diff --git a/cross-toolchain/activate.sh b/cross-toolchain/activate.sh
new file mode 100755
index 0000000..0bc429f
--- /dev/null
+++ b/cross-toolchain/activate.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+export PREFIX="/home/cheapie/rvcontroller/cross-toolchain/install" # Edit this for your system!
+export TARGET=riscv32-none-elf
+export PATH="$PREFIX/bin:$PATH"
+export PS1="(cross) $PS1"
+export CC=clang
diff --git a/fib.S b/fib.S
new file mode 100644
index 0000000..e43195d
--- /dev/null
+++ b/fib.S
@@ -0,0 +1,29 @@
+li t0,0
+li t1,1
+li t3,0x7fffffff
+loop:
+add t2,t1,t0
+mv t0,t1
+mv t1,t2
+li a7,1
+mv a0,t0
+ecall
+li a7,11
+li a0,0x0a
+ecall
+bltu t2,t3,loop
+
+li a0,0xa
+li a7,11
+ecall
+li a7,1
+rdinstret a0
+ecall
+la a0,instructions
+li a7,4
+ecall
+
+li a7,10
+ecall
+
+instructions: .asciz " instructions\n"
diff --git a/guessnum-random.S b/guessnum-random.S
new file mode 100644
index 0000000..0f890cd
--- /dev/null
+++ b/guessnum-random.S
@@ -0,0 +1,126 @@
+restart:
+rdtime t3 # Get the time the program was started at
+
+li a7,11 # Print character
+li a0,0xa # \n
+ecall
+li t0,0 # Number of guesses
+
+# Get a random number for the player to guess
+li a7,128 # Get random integer
+li a0,1 # Lower bound = 1
+li a1,99 # Upper bound = 99
+ecall
+mv t1,a0 # Put the result in t1 where it's expected
+
+loop:
+# Increment number of guesses
+addi t0,t0,1
+
+# Prompt player to enter their guess
+li a7,4 # Write string
+la a0,prompt # 'Enter your guess' prompt address
+ecall
+
+# Read the player's guess
+li a7,5 # Read integer
+ecall
+mv t2,a0 # Store it in t2
+
+# Print it back out
+li a7,1 # Write integer
+ecall
+li a7,11 # Write character
+li a0,0xa # \n
+ecall
+
+# Replace it with a random number
+li a0,0 # Lower bound = 0
+li a1,100 # Upper bound = 100
+li a7,128 # Get random integer
+ecall
+mv t2,a0
+
+# Too low?
+blt t2,t1,toolow
+
+# Too high?
+blt t1,t2,toohigh
+
+# Otherwise it must be right
+j correct
+
+toolow:
+# Show too low message
+li a7,4 # Write string
+la a0,toolowmsg
+ecall
+j loop # Go back for the next guess
+
+toohigh:
+# Show too high message
+li a7,4 # Write string
+la a0,toohighmsg
+ecall
+j loop # Go back for the next guess
+
+correct:
+# Show congratulations message
+li a7,4 # Write string
+la a0,correctmsg
+ecall
+
+# Show number of guesses
+mv a0,t0 # Get the number of guesses
+li a7,1 # Write integer
+ecall
+
+# Add proper suffix depending on whether it should be plural or not
+li a7,4 # Write string
+la a0,guessesmsg # "guess"
+ecall
+li t2,1
+beq t0,t2,playagain # Leave it singular if it was 1
+la a0,guessespluralize # "es"
+ecall
+
+playagain:
+li a7,11 # Write character
+li a0,0xa # \n
+ecall
+# Show the number of seconds the player took
+rdtime t4 # Get the current time
+sub a0,t4,t3 # Subtract the start time
+li a7,1 # Write integer
+ecall
+li a7,4 # Write string
+la a0,seconds
+ecall
+
+li a7,11 # Print character
+li a0,0xa # \n
+ecall
+
+# Ask the user if they want to play again
+li a7,4 # Write string
+la a0,playagainmsg
+ecall
+li a7,12 # Read character
+ecall
+li a7,11 # Write character
+ecall
+li t0,0x6e # n
+bne a0,t0,restart
+
+li a7,10 # Exit program
+ecall
+
+
+prompt: .asciz "Enter your guess:\n> "
+toolowmsg: .asciz "Too low! Try again\n"
+toohighmsg: .asciz "Too high! Try again\n"
+correctmsg: .asciz "Correct!\nYou got it in:\n"
+guessesmsg: .asciz " guess"
+guessespluralize: .asciz "es"
+seconds: .asciz " seconds"
+playagainmsg: .asciz "Play again? [Y/n]"
diff --git a/guessnum.S b/guessnum.S
new file mode 100644
index 0000000..8d5b2fb
--- /dev/null
+++ b/guessnum.S
@@ -0,0 +1,119 @@
+restart:
+rdtime t3 # Get the time the program was started at
+
+li a7,11 # Print character
+li a0,0xa # \n
+ecall
+li t0,0 # Number of guesses
+
+# Get a random number for the player to guess
+li a7,128 # Get random integer
+li a0,1 # Lower bound = 1
+li a1,99 # Upper bound = 99
+ecall
+mv t1,a0 # Put the result in t1 where it's expected
+
+loop:
+# Increment number of guesses
+addi t0,t0,1
+
+# Prompt player to enter their guess
+li a7,4 # Write string
+la a0,prompt # 'Enter your guess' prompt address
+ecall
+
+# Read the player's guess
+li a7,5 # Read integer
+ecall
+mv t2,a0 # Store it in t2
+
+# Print it back out
+li a7,1 # Write integer
+ecall
+li a7,11 # Write character
+li a0,0xa # \n
+ecall
+
+# Too low?
+blt t2,t1,toolow
+
+# Too high?
+blt t1,t2,toohigh
+
+# Otherwise it must be right
+j correct
+
+toolow:
+# Show too low message
+li a7,4 # Write string
+la a0,toolowmsg
+ecall
+j loop # Go back for the next guess
+
+toohigh:
+# Show too high message
+li a7,4 # Write string
+la a0,toohighmsg
+ecall
+j loop # Go back for the next guess
+
+correct:
+# Show congratulations message
+li a7,4 # Write string
+la a0,correctmsg
+ecall
+
+# Show number of guesses
+mv a0,t0 # Get the number of guesses
+li a7,1 # Write integer
+ecall
+
+# Add proper suffix depending on whether it should be plural or not
+li a7,4 # Write string
+la a0,guessesmsg # "guess"
+ecall
+li t2,1
+beq t0,t2,playagain # Leave it singular if it was 1
+la a0,guessespluralize # "es"
+ecall
+
+playagain:
+li a7,11 # Write character
+li a0,0xa # \n
+ecall
+# Show the number of seconds the player took
+rdtime t4 # Get the current time
+sub a0,t4,t3 # Subtract the start time
+li a7,1 # Write integer
+ecall
+li a7,4 # Write string
+la a0,seconds
+ecall
+
+li a7,11 # Print character
+li a0,0xa # \n
+ecall
+
+# Ask the user if they want to play again
+li a7,4 # Write string
+la a0,playagainmsg
+ecall
+li a7,12 # Read character
+ecall
+li a7,11 # Write character
+ecall
+li t0,0x6e # n
+bne a0,t0,restart
+
+li a7,10 # Exit program
+ecall
+
+
+prompt: .asciz "Enter your guess:\n> "
+toolowmsg: .asciz "Too low! Try again\n"
+toohighmsg: .asciz "Too high! Try again\n"
+correctmsg: .asciz "Correct!\nYou got it in:\n"
+guessesmsg: .asciz " guess"
+guessespluralize: .asciz "es"
+seconds: .asciz " seconds"
+playagainmsg: .asciz "Play again? [Y/n]"
diff --git a/hello.S b/hello.S
new file mode 100644
index 0000000..3eecf13
--- /dev/null
+++ b/hello.S
@@ -0,0 +1,6 @@
+la a0,message
+li a7,4
+ecall
+li a7,10
+ecall
+message: .asciz "Hello, world!\n"
diff --git a/loader.lua b/loader.lua
new file mode 100644
index 0000000..0622dc9
--- /dev/null
+++ b/loader.lua
@@ -0,0 +1,83 @@
+--RVController Loader
+--A product of Advanced Mesecons Devices, a Cheapie Systems company
+--This is free and unencumbered software released into the public domain.
+--See http://unlicense.org/ for more information
+
+local function formspec_escape(text)
+ local ret = ""
+ local badchars = {
+ ["\\"] = true,
+ ["["] = true,
+ ["]"] = true,
+ [";"] = true,
+ [","] = true
+ }
+ for i=1,string.len(text),1 do
+ local char = string.sub(text,i,i)
+ if badchars[char] then ret = ret.."\\" end
+ ret = ret..char
+ end
+ return ret
+end
+
+local function sendfs()
+ digiline_send("touchscreen","formspec_version[10]size[15,15]textarea[0,0;15,14;program;;"..formspec_escape(mem.data).."]button_exit[6.5,14;2,1;go;Load]checkbox[0.5,14.5;autorun;Run after load;"..tostring(mem.autorun).."]")
+end
+
+if event.type == "program" then
+ mem.autorun = true
+ mem.data = "(paste Intel HEX data here)"
+ sendfs()
+elseif event.channel == "touchscreen" and event.msg.autorun then
+ mem.autorun = event.msg.autorun == "true"
+ mem.data = event.msg.program
+ sendfs()
+elseif event.channel == "touchscreen" and event.msg.go then
+ mem.data = event.msg.program
+ mem.addresshigh = 0
+ mem.addressmid = 0
+ digiline_send("reset","")
+ interrupt(1,"tick")
+elseif event.iid == "tick" then
+ local nlpos = string.find(mem.data,"\n",1,true)
+ local thisline
+ if nlpos then
+ thisline = string.sub(mem.data,1,nlpos-1)
+ mem.data = string.sub(mem.data,nlpos+1,-1)
+ else
+ thisline = mem.data
+ mem.data = ""
+ end
+ local startpos = string.find(thisline,":",1,true)
+ local eof = false
+ if startpos then
+ thisline = string.sub(thisline,startpos+1,-1)
+ local rectype = string.sub(thisline,7,8)
+ if rectype == "00" then
+ --data
+ local bytecount = tonumber(string.sub(thisline,1,2),16)
+ local addresslow = tonumber(string.sub(thisline,3,6),16)
+ local linedata = string.sub(thisline,9,-3)
+ local address = (mem.addresshigh*2^16)+(mem.addressmid*2^4)+addresslow
+ digiline_send("load",{address=address,data=linedata,size=bytecount})
+ elseif rectype == "01" then
+ --end of file
+ eof = true
+ digiline_send("load",{done=true,autorun=mem.autorun})
+ elseif rectype == "02" then
+ --extended segment address
+ mem.addressmid = tonumber(string.sub(thisline,9,12),16)
+ elseif rectype == "04" then
+ --extended linear address
+ mem.addresshigh = tonumber(string.sub(thisline,9,12),16)
+ end
+ end
+ if string.len(mem.data) > 0 and not eof then
+ interrupt(0.05,"tick")
+ else
+ mem.data = "(paste Intel HEX data here)"
+ sendfs()
+ end
+elseif event.iid == "run" then
+ digiline_send("monitorkb","run")
+end
diff --git a/misa.S b/misa.S
new file mode 100644
index 0000000..4bd93ef
--- /dev/null
+++ b/misa.S
@@ -0,0 +1,112 @@
+csrr t0,0x301 # Read misa
+
+li a7,11 # Print character
+li a0,'R'
+ecall
+li a0,'V'
+ecall
+li a0,'3'
+ecall
+li a0,'2'
+ecall
+
+bexti t1,t0,8
+li a7,11
+li a0,'I'
+czero.eqz a7,a7,t1 # Clear ecall function if bit isn't set
+ecall
+
+bexti t1,t0,4
+li a7,11
+li a0,'E'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,12
+li a7,11
+li a0,'M'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,0
+li a7,11
+li a0,'A'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,5
+li a7,11
+li a0,'F'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,3
+li a7,11
+li a0,'D'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,16
+li a7,11
+li a0,'Q'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,11
+li a7,11
+li a0,'L'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,2
+li a7,11
+li a0,'C'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,1
+li a7,11
+li a0,'B'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,9
+li a7,11
+li a0,'J'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,19
+li a7,11
+li a0,'T'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,15
+li a7,11
+li a0,'P'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,21
+li a7,11
+li a0,'V'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,7
+li a7,11
+li a0,'H'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,18
+li a7,11
+li a0,'S'
+czero.eqz a7,a7,t1
+ecall
+
+bexti t1,t0,2
+
+li a7,10
+ecall
diff --git a/rrxing.S b/rrxing.S
new file mode 100644
index 0000000..61fb41c
--- /dev/null
+++ b/rrxing.S
@@ -0,0 +1,198 @@
+li a7,134 # Clear digilines buffer
+ecall
+
+restart:
+# Hardware initialization
+
+# Make sure light is off
+li a7,129 # Send digilines message
+la a0,lightchannel
+la a1,lightoffmsg
+ecall
+
+# Make sure bell is off
+li a7,129 # Send digilines message
+la a0,bellchannel
+la a1,belloffmsg
+ecall
+
+# Make sure gate is up
+li a7,129 # Send digilines message
+la a0,gatechannel
+la a1,gateupmsg
+ecall
+
+receiveloop:
+li a7,133 # Get digilines buffer level
+ecall
+beq a0,x0,receiveloop # If no messages yet, restart the loop
+
+li a7,135 # Read digilines message
+la a0,channelbuf
+li a1,16 # Channel buffer size
+la a2,msgbuf
+li a3,16 # Message buffer size
+ecall
+
+# Check if it's the right channel
+la a0,channelbuf
+la a1,detectchannel
+call strcmp
+beq a0,x0,receiveloop # Not the right channel, ignore it
+
+# Turn the light yellow
+li a7,129 # Send digilines message
+la a0,lightchannel
+la a1,lightyellowmsg
+ecall
+
+# Wait 1 second
+li a0,1
+call sleep
+
+# Turn the bell on
+li a7,129 # Send digilines message
+la a0,bellchannel
+la a1,bellonmsg
+ecall
+
+# Wait 2 seconds
+li a0,2
+call sleep
+
+# Turn the light red
+li a7,129 # Send digilines message
+la a0,lightchannel
+la a1,lightredmsg
+ecall
+
+# Wait 3 seconds
+li a0,3
+call sleep
+
+# Lower the gate
+li a7,129 # Send digilines message
+la a0,gatechannel
+la a1,gatedownmsg
+ecall
+
+# Wait 5 seconds
+li a0,5
+call sleep
+
+# Turn the bell off
+li a7,129 # Send digilines message
+la a0,bellchannel
+la a1,belloffmsg
+ecall
+
+waitlonger:
+
+# Wait 10 seconds
+li a0,10
+call sleep
+
+# Check if any more trains have been detected
+receiveloop2:
+li a7,133 # Get digilines buffer level
+ecall
+beq a0,x0,raise # If no messages yet, go ahead with timing out
+
+# If there is a message, check if it's a train
+
+li a7,135 # Read digilines message
+la a0,channelbuf
+li a1,16 # Channel buffer size
+la a2,msgbuf
+li a3,16 # Message buffer size
+ecall
+
+# Check if it's the right channel
+la a0,channelbuf
+la a1,detectchannel
+call strcmp
+beq a0,x0,receiveloop2 # Not the right channel, ignore this message and go on to the next
+
+# If it is the right channel, then get rid of the rest of the messages (if any)
+li a7,134 # Clear digilines buffer
+ecall
+
+j waitlonger # And go wait another 10 seconds
+
+raise:
+
+# Raise the gate
+li a7,129 # Send digilines message
+la a0,gatechannel
+la a1,gateupmsg
+ecall
+
+# Wait 2 seconds
+li a0,2
+call sleep
+
+# Turn the light off
+li a7,129 # Send digilines message
+la a0,lightchannel
+la a1,lightoffmsg
+ecall
+
+# And go wait for the next train
+j restart
+
+sleep:
+ # Expects a number of seconds in a0
+ # Uses t0
+ rdtime t0
+ add a0,t0,a0
+ sleep_loop:
+ rdtime t0
+ bltu t0,a0,sleep_loop
+ret
+
+strcmp:
+ # Expects string pointers in a0 and a1
+ # Compares until a NUL is reached on the first string
+ # Uses t0, t1, and t2
+ # Returns a0=1 if strings match, a0=0 otherwise
+ li t0,0 # t0 is the loop counter
+ strcmp_loop:
+ # Calculate addresses
+ add t1,a0,t0 # t1 is the pointer for the first string
+ add t2,a1,t0 # t2 is the pointer for the second string
+
+ # Read the bytes from each string
+ lb t1,0(t1)
+ lb t2,0(t2)
+
+ # Increment the loop counter
+ addi t0,t0,1
+
+ # And compare
+ bne t1,t2,strcmp_mismatch
+
+ # Check if a terminator was reached yet, keep going otherwise
+ li t2,0
+ bne t1,t2,strcmp_loop
+
+ # If we got here they match
+ li a0,1
+ ret
+
+ strcmp_mismatch:
+ li a0,0
+ ret
+
+channelbuf: .ascii " "
+msgbuf: .ascii " "
+lightchannel: .asciz "light"
+bellchannel: .asciz "bell"
+gatechannel: .asciz "gate"
+lightoffmsg: .asciz "OFF"
+lightyellowmsg: .asciz "YELLOW"
+lightredmsg: .asciz "RED"
+bellonmsg: .asciz "on"
+belloffmsg: .asciz "off"
+gateupmsg: .asciz "up"
+gatedownmsg: .asciz "down"
+detectchannel: .asciz "detect"
diff --git a/rvcontroller.ld b/rvcontroller.ld
new file mode 100644
index 0000000..3203776
--- /dev/null
+++ b/rvcontroller.ld
@@ -0,0 +1,45 @@
+/* Thanks https://github.com/darklife/darkriscv */
+ __heap_size = 0x200; /* required amount of heap */
+ __stack_size = 0x800; /* required amount of stack */
+
+ MEMORY
+ {
+ RAM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x10000
+ }
+ SECTIONS
+ {
+ .text :
+ {
+ *(.boot)
+ *(.text)
+ *(.text)
+ *(.rodata*)
+ } > RAM
+ .data :
+ {
+ *(.sbss)
+ *(.data)
+ *(.bss)
+ *(.rela*)
+ *(COMMON)
+ } > RAM
+
+ .heap :
+ {
+ . = ALIGN(4);
+ PROVIDE ( end = . );
+ _sheap = .;
+ . = . + __heap_size;
+ . = ALIGN(4);
+ _eheap = .;
+ } >RAM
+
+ .stack :
+ {
+ . = ALIGN(4);
+ _estack = .;
+ . = . + __stack_size;
+ . = ALIGN(4);
+ _sstack = .;
+ } >RAM
+ }
diff --git a/rvcontroller.lua b/rvcontroller.lua
new file mode 100644
index 0000000..3fda5db
--- /dev/null
+++ b/rvcontroller.lua
@@ -0,0 +1,2604 @@
+--RVController
+--A product of Advanced Mesecons Devices, a Cheapie Systems company
+--This is free and unencumbered software released into the public domain.
+--See http://unlicense.org/ for more information
+
+--[[
+
+Emulated system specifications:
+
+Single RISC-V core, RV32IMACB_Zicntr_Zicond_Zicsr_Zifencei_Zihintpause_Zilsd_Zabha_Zacas_Zcb_Zclsd_Zcmp_Zcmt_Zbkb_Zbkx instruction set, little-endian
+65536 bytes of RAM (configurable in settings below) starting at base address 0
+
+Intended to be compliant with the following specifications:
+* RV32I Base Integer Instruction Set, Version 2.1
+* "Zifencei" Extension for Instruction-Fetch Fence, Version 2.0
+ - Note: Implemented as a 'nop' instruction as memory is always consistent (see note on RVWMO below)
+* "Zicsr" Extension for Control and Status Register (CSR) Instructions, Version 2.0
+* "Zicond" Extension for Integer Conditional Operations, Version 1.0.0
+* "Zicntr" Extension for Counters, Version 2.0
+* "M" Extension for Integer Multiplication and Division, Version 2.0
+ - Note: This implies the following:
+ - * Zmmul Extension, Version 1.0
+* "A" Extension for Atomic Instructions, Version 2.1
+ - Note: This implies the following:
+ - * "Zalrsc" Extension for Load-Reserved/Store-Conditional Instructions
+ - * "Zaamo" Extension for Atomic Memory Operations
+* RVWMO Memory Consistency Model, Version 2.0
+ - Note: The actual implemented memory model is significantly more strict (memory is always consistent, there is no cache)
+* "Ztso" Extension for Total Store Ordering, Version 1.0
+* "C" Extension for Compressed Instructions, Version 2.0
+ - Note: This implies the following:
+ - * "Zca" Extension for Code Size Reduction, Version 1.0.0
+* Zcb: Extension for Code Size Reduction, Version 1.0.0
+* Zcmp: Extension for Code Size Reduction, Version 1.0.0
+* Zcmt: Extension for Code Size Reduction, Version 1.0.0
+* "B" Extension for Bit Manipulation, Version 1.0.0
+ - Note: This implies the following:
+ - * Zba: Extension for Address generation, Version 1.0.0
+ - * Zbb: Extension for Basic bit-manipulation, Version 1.0.0
+ - * Zbs: Extension for Single-bit instructions, Version 1.0.0
+* "Zihintpause" Extension for Pause Hint, Version 2.0
+* Zilsd, Zclsd: Extensions for Load/Store pair for RV32, Version 1.0
+* "Zabha" Extension for Byte and Halfword Atomic Memory Operations, Version 1.0
+* "Zacas" Extension for Atomic Compare-and-Swap (CAS) Instructions, Version 1.0.0
+* Zbkb: Extension for Bit-manipulation for Cryptography, Version 1.0.0
+* Zbkx: Extension for Crossbar permutations, Version 1.0.0
+
+See https://docs.riscv.org/reference/isa/unpriv/unpriv-index.html for full specifications.
+
+Monitor commands:
+
+peek <address>
+Reads and displays the byte (8 bits) value from RAM at the specified address
+
+poke <address> <data>
+Writes the specified byte (8 bits) value to RAM at the specified address
+
+peekw <address>
+Reads and displays the word (32 bits) value from RAM starting at the specified address
+
+pokew <address> <data>
+Writes the specified word (32 bits) value to RAM starting at the specified address
+
+getreg <register number>
+Displays the current value of the specified register number (0-31)
+
+setreg <register number> <value>
+Sets the specified register (0-31) to the specified value
+
+getpc
+Displays the current value of the program counter
+
+setpc <value>
+Sets the program counter to the specified value
+
+reset
+Stops the CPU, resets all registers to zero, and clears all RAM
+
+step
+Allows the CPU to run for one instruction, then halts
+
+run
+Allows the CPU to run indefinitely
+
+stop
+Halts the CPU
+
+setbreak <address>
+Sets a breakpoint on the specified address.
+Note that the breakpoint triggers just *before* the instruction fetch,
+as in the instruction with the breakpoint on it will not have executed yet.
+There can only be one breakpoint at a time. If one is already set, the new one will replace it.
+
+clearbreak
+Clears any set breakpoint. Note that an ebreak instruction will still cause a break.
+
+help [command]
+Shows information on a monitor command, or a list of commands if none is specified
+
+
+ecall operations:
+
+a7 = 1
+Prints the integer value from register a0
+
+a7 = 4
+Prints the null-terminated string from the address specified by register a0
+
+a7 = 5
+Reads an integer from the console and stores it into register a0
+This will block until the user enters a valid number
+
+a7 = 8
+Reads a string from the console and stores it (with a null terminator) into the address pointed to by register a0
+Will not read more than the length specified in register a1, anything more is discarded
+This will block until the user types something
+
+a7 = 10
+Exits the program (halts the CPU)
+
+a7 = 11
+Prints the character stored in the register a0
+
+a7 = 12
+Reads one character from the console (any more characters on the line are discarded) and stores it into register a0
+
+a7 = 128
+Gets a random integer (between the values in registers a0 and a1) and stores it into register a0
+
+a7 = 129
+Sends a digilines string message:
+* channel is specified by the null-terminated string at the address specified by register a0
+* message is specified by the null-terminated string at the address specified by register a1
+
+a7 = 130
+Gets the number of characters available to read from the console input buffer
+Result is stored in register a0
+
+a7 = 131
+Clears the console input buffer
+
+a7 = 132
+Reads one character from the console input buffer and stores it into register a0
+This will not block - if no data is available to read, a NUL character (0) is returned
+The input buffer can store up to 256 characters - if full, incoming characters are dropped
+
+a7 = 133
+Gets the number of messages in the digilines receive buffer
+Result is stored in register a0
+
+a7 = 134
+Clears the digilines receive buffer
+
+a7 = 135
+Reads one message from the digilines receive buffer, returns channel and message as null-terminated strings
+This will not block - if no data is available to read, zero-length strings will be returned
+Arguments:
+a0 - Address that the channel string will be written to
+a1 - Size of the buffer that the channel string will be written into
+a2 - Address that the message will be written to
+a3 - Size of the buffer that the message will be written into
+
+Custom CSRs:
+
+0x800[0] = Lightweight mode, controls processor clock speed and behavior when mapblock is unloaded:
+0: 10 Hz (adjustable in settings below), processor does not stop when mapblock is unloaded
+1: 1 Hz, processor stops when mapblock is unloaded
+Note that when set to 0, a digilines message being received will cause the processor to run for one cycle.
+This is intended to be used to check if the digilines message needs action to be taken in response,
+and the program can then turn lightweight mode off if so.
+
+]]
+
+--Settings
+local RAM_SIZE = 0x10000 --RAM size in bytes, must be a multiple of 256
+local CLOCK_SPEED = 20 --Clock speed in Hz when not in lightweight mode
+local INSTRUCTIONS_PER_CLOCK = 50 --Maximum number of instructions that will be run on each clock cycle
+local STDOUT_TO_TERMINAL = false --Whether to show standard output on the Luacontroller terminal in addition to the screen
+
+
+local function implodebits(bits,count,signed)
+ local negative = false
+ if signed then
+ negative = bits[count-1]
+ end
+ local out = 0
+ for i=0,count-1 do
+ if bits[i] then out = out + (2^i) end
+ end
+ if negative then out = out - (2^count) end
+ return out
+end
+
+local function explodebits(num,count)
+ num = num%(2^count)
+ if num < 0 then
+ num = num + (2^count)
+ end
+ local out = {}
+ for i=0,count-1 do
+ out[i] = num%(2^(i+1)) >= 2^i
+ end
+ return out
+end
+
+local function signextend(bits,fromcount,tocount)
+ for i=fromcount,tocount-1 do
+ bits[i] = bits[fromcount-1]
+ end
+end
+
+local function mul64(a,b,asigned,bsigned)
+ --If in signed mode and the number is too big to be positive, make it negative
+ if asigned and a >= 2^31 then a = a - 2^32 end
+ if bsigned and b >= 2^31 then b = b - 2^32 end
+
+ --Break 32-bit arguments into 16-bit pieces
+ local alow = a%2^16
+ local ahigh = math.floor(a/2^16)
+ local blow = b%2^16
+ local bhigh = math.floor(b/2^16)
+
+ --Multiply 16x16-bit numbers to get 32-bit partial products
+ local pp1 = alow*blow
+ local pp2 = alow*bhigh
+ local pp3 = ahigh*blow
+ local pp4 = ahigh*bhigh
+
+ --Split the two partial products that will straddle the 32-bit boundary
+ local pp2low = pp2%2^16
+ local pp2high = math.floor(pp2/2^16)
+ local pp3low = pp3%2^16
+ local pp3high = math.floor(pp3/2^16)
+
+ --And give them the proper 16-bit shift
+ pp2low = pp2low*2^16
+ pp3low = pp3low*2^16
+
+ --Sum the lower partial products into a 34-bit value
+ local lowresult = pp1+pp2low+pp3low
+
+ --Split the upper 2 bits off into a carry value
+ local carry = math.floor(lowresult/2^32)
+ lowresult = lowresult%2^32
+
+ --Sum the upper partial products and carry
+ local highresult = carry+pp2high+pp3high+pp4
+
+ return lowresult,highresult
+end
+
+local function getreg(reg)
+ return reg == 0 and 0 or mem.registers[reg]
+end
+
+local function setreg(reg,val)
+ if val < 0 then val = val + (2^32) end
+ if reg ~= 0 then mem.registers[reg] = math.floor(val%(2^32)) end
+end
+
+local function readram(address,bytes)
+ if address > RAM_SIZE-1 then
+ digiline_send("monitordisp",string.format("Out-of-bounds\nmemory read\nAddress: %08X\nPC: %08X\nSystem halted",address,mem.registers.pc))
+ mem.running = false
+ return 0
+ end
+ local out = 0
+ for i=0,bytes-1 do
+ local offsetaddr = address+i
+ local segment = math.floor(offsetaddr/256)
+ local offset = offsetaddr%256
+ out = out + (string.byte(string.sub(mem.ram[segment],offset+1,offset+1)) or 0) * 2^(8*i)
+ end
+ return out
+end
+
+local function writeram(address,data,bytes)
+ if address > RAM_SIZE-1 then
+ digiline_send("monitordisp",string.format("Out-of-bounds\nmemory write\nAddress: %08X\nPC: %08X\nSystem halted",address,mem.registers.pc))
+ mem.running = false
+ return
+ end
+ if mem.reservationset then
+ if mem.reservationset + 4 >= address and mem.reservationset <= address+bytes-1 then
+ mem.reservationset = nil
+ end
+ end
+ for i=0,bytes-1 do
+ local thisbyte = data % (2^((i+1)*8)) / 2^(i*8)
+ thisbyte = math.floor(thisbyte) % 2^32
+ local offsetaddr = address+i
+ local segment = math.floor(offsetaddr/256)
+ local offset = offsetaddr%256
+ mem.ram[segment] = string.sub(mem.ram[segment],0,offset)..string.char(thisbyte)..string.sub(mem.ram[segment],offset+2,-1)
+ end
+end
+
+local stdoutdirty = false
+
+local function scrollstdout(lines)
+ lines = lines or 1
+ for i=1,lines do
+ table.remove(mem.stdout,1)
+ mem.stdout[6] = ""
+ end
+end
+
+local function stdout(text)
+ if string.len(text) == 0 then return end
+ if STDOUT_TO_TERMINAL then print(text) end
+ stdoutdirty = true
+ for i=1,string.len(text) do
+ local thischar = string.sub(text,i,i)
+ if string.len(mem.stdout[6]) == 20 or thischar == "\n" then
+ scrollstdout(1)
+ if thischar ~= "\n" then mem.stdout[6] = mem.stdout[6]..thischar end
+ elseif thischar ~= string.char(0) then
+ mem.stdout[6] = mem.stdout[6]..thischar
+ end
+ end
+end
+
+local function readcsr(address)
+ if not mem.csr[address] then
+ digiline_send("monitordisp",string.format("W: Attempted read\nfrom unknown\nCSR 0x%03X\nPC: %08X",address,mem.registers.pc))
+ return 0
+ end
+ return mem.csr[address]
+end
+
+local function writecsr(address,data)
+ if address == 0x17 then
+ --jvt
+ data = math.floor(data/2^6)*2^6 --WARL, and mode is required to be 0
+ elseif address == 0xc00 or address == 0xc01 or address == 0xc02 or address == 0xc80 or address == 0xc81 or address == 0xc82 then
+ --One of the read-only CSRs from Zicntr, just ignore the write
+ return
+ elseif address == 0xf11 or address == 0xf12 or address == 0xf13 or address == 0xf14 or address == 0xf15 or address == 0x300 or address == 0x301 or address == 0x310 then
+ --Read-only machine information register, ignore write
+ return
+ end
+ if not mem.csr[address] then
+ digiline_send("monitordisp",string.format("W: Attempted write\nto unknown\nCSR 0x%03X\nPC: %08X",address,mem.registers.pc))
+ return
+ end
+ mem.csr[address] = data
+end
+
+local cmpushpopreglists = {
+ [4] = {registers = {1},stack = 16},
+ [5] = {registers = {1,8},stack = 16},
+ [6] = {registers = {1,8,9},stack = 16},
+ [7] = {registers = {1,8,9,18},stack = 16},
+ [8] = {registers = {1,8,9,18,19},stack = 32},
+ [9] = {registers = {1,8,9,18,19,20},stack = 32},
+ [10] = {registers = {1,8,9,18,19,20,21},stack = 32},
+ [11] = {registers = {1,8,9,18,19,20,21,22},stack = 32},
+ [12] = {registers = {1,8,9,18,19,20,21,22,23},stack = 48},
+ [13] = {registers = {1,8,9,18,19,20,21,22,23,24},stack = 48},
+ [14] = {registers = {1,8,9,18,19,20,21,22,23,24,25},stack = 48},
+ [15] = {registers = {1,8,9,18,19,20,21,22,23,24,25,26,27},stack = 64},
+ }
+
+local operations = {
+ add = function(rd,rs1,rs2)
+ setreg(rd,getreg(rs1)+getreg(rs2))
+ end,
+ sub = function(rd,rs1,rs2)
+ setreg(rd,getreg(rs1)-getreg(rs2))
+ end,
+ xor = function(rd,rs1,rs2)
+ local rs1bits = explodebits(getreg(rs1),32)
+ local rs2bits = explodebits(getreg(rs2),32)
+ local rdbits = {}
+ for i=0,31 do rdbits[i] = rs1bits[i] ~= rs2bits[i] end
+ setreg(rd,implodebits(rdbits,32,false))
+ end,
+ orr = function(rd,rs1,rs2) --instruction is "or" but that's a reserved word
+ local rs1bits = explodebits(getreg(rs1),32)
+ local rs2bits = explodebits(getreg(rs2),32)
+ local rdbits = {}
+ for i=0,31 do rdbits[i] = rs1bits[i] or rs2bits[i] end
+ setreg(rd,implodebits(rdbits,32,false))
+ end,
+ andr = function(rd,rs1,rs2) --instruction is "and" but that's a reserved word
+ local rs1bits = explodebits(getreg(rs1),32)
+ local rs2bits = explodebits(getreg(rs2),32)
+ local rdbits = {}
+ for i=0,31 do rdbits[i] = rs1bits[i] and rs2bits[i] end
+ setreg(rd,implodebits(rdbits,32,false))
+ end,
+ xnor = function(rd,rs1,rs2)
+ local rs1bits = explodebits(getreg(rs1),32)
+ local rs2bits = explodebits(getreg(rs2),32)
+ local rdbits = {}
+ for i=0,31 do rdbits[i] = rs1bits[i] == rs2bits[i] end
+ setreg(rd,implodebits(rdbits,32,false))
+ end,
+ orn = function(rd,rs1,rs2)
+ local rs1bits = explodebits(getreg(rs1),32)
+ local rs2bits = explodebits(getreg(rs2),32)
+ local rdbits = {}
+ for i=0,31 do rdbits[i] = rs1bits[i] or not rs2bits[i] end
+ setreg(rd,implodebits(rdbits,32,false))
+ end,
+ andn = function(rd,rs1,rs2)
+ local rs1bits = explodebits(getreg(rs1),32)
+ local rs2bits = explodebits(getreg(rs2),32)
+ local rdbits = {}
+ for i=0,31 do rdbits[i] = rs1bits[i] and not rs2bits[i] end
+ setreg(rd,implodebits(rdbits,32,false))
+ end,
+ sll = function(rd,rs1,rs2)
+ setreg(rd,getreg(rs1)*(2^(getreg(rs2)%2^5)))
+ end,
+ srl = function(rd,rs1,rs2)
+ setreg(rd,getreg(rs1)/(2^(getreg(rs2)%2^5)))
+ end,
+ sra = function(rd,rs1,rs2)
+ local num = getreg(rs1)
+ local amount = getreg(rs2)%2^5
+ local sign = num>=(2^31)
+ if amount == 0 then return end
+ for _=1,amount do
+ num = num/2
+ if sign then num = num+(2^31) end
+ end
+ setreg(rd,num)
+ end,
+ slt = function(rd,rs1,rs2)
+ local num1 = getreg(rs1)
+ local num2 = getreg(rs2)
+ if num1 >= 2^31 then num1 = num1-(2^32) end
+ if num2 >= 2^31 then num2 = num2-(2^32) end
+ setreg(rd,num1 < num2 and 1 or 0)
+ end,
+ sltu = function(rd,rs1,rs2)
+ local num1 = getreg(rs1)
+ local num2 = getreg(rs2)
+ setreg(rd,num1 < num2 and 1 or 0)
+ end,
+ addi = function(rd,rs1,imm)
+ local immbits = explodebits(imm,12)
+ signextend(immbits,12,32)
+ imm = implodebits(immbits,32,false)
+ setreg(rd,getreg(rs1)+imm)
+ end,
+ xori = function(rd,rs1,imm)
+ local rs1bits = explodebits(getreg(rs1),32)
+ local immbits = explodebits(imm,12)
+ signextend(immbits,12,32)
+ local rdbits = {}
+ for i=0,31 do
+ rdbits[i] = rs1bits[i] ~= immbits[i]
+ end
+ setreg(rd,implodebits(rdbits,32,false))
+ end,
+ ori = function(rd,rs1,imm)
+ local rs1bits = explodebits(getreg(rs1),32)
+ local immbits = explodebits(imm,12)
+ signextend(immbits,12,32)
+ local rdbits = {}
+ for i=0,31 do
+ rdbits[i] = rs1bits[i] or immbits[i]
+ end
+ setreg(rd,implodebits(rdbits,32,false))
+ end,
+ andi = function(rd,rs1,imm)
+ local rs1bits = explodebits(getreg(rs1),32)
+ local immbits = explodebits(imm,12)
+ signextend(immbits,12,32)
+ local rdbits = {}
+ for i=0,31 do
+ rdbits[i] = rs1bits[i] and immbits[i]
+ end
+ setreg(rd,implodebits(rdbits,32,false))
+ end,
+ slli = function(rd,rs1,imm)
+ setreg(rd,getreg(rs1)*(2^imm))
+ end,
+ srli = function(rd,rs1,imm)
+ setreg(rd,getreg(rs1)/(2^imm))
+ end,
+ srai = function(rd,rs1,imm)
+ local num = getreg(rs1)
+ local sign = num>=(2^31)
+ if imm == 0 then return end
+ for _=1,imm do
+ num = num/2
+ if sign then num = num+(2^31) end
+ end
+ setreg(rd,num)
+ end,
+ slti = function(rd,rs1,imm)
+ local num1 = getreg(rs1)
+ local immbits = explodebits(imm,12)
+ signextend(immbits,12,32)
+ local num2 = implodebits(immbits,32,false)
+ if num1 >= 2^31 then num1 = num1-(2^32) end
+ if num2 >= 2^31 then num2 = num2-(2^32) end
+ setreg(rd,num1 < num2 and 1 or 0)
+ end,
+ sltiu = function(rd,rs1,imm)
+ local num1 = getreg(rs1)
+ local immbits = explodebits(imm,12)
+ signextend(immbits,12,32)
+ local num2 = implodebits(immbits,32,false)
+ setreg(rd,num1 < num2 and 1 or 0)
+ end,
+ beq = function(rs1,rs2,imm)
+ local num1 = getreg(rs1)
+ local num2 = getreg(rs2)
+ if num1 == num2 then
+ local immbits = explodebits(imm,13)
+ signextend(immbits,13,32)
+ imm = implodebits(immbits,13,true)
+ mem.registers.pc = (mem.registers.pc + imm) % 2^32
+ return true
+ end
+ end,
+ bne = function(rs1,rs2,imm)
+ local num1 = getreg(rs1)
+ local num2 = getreg(rs2)
+ if num1 ~= num2 then
+ local immbits = explodebits(imm,13)
+ signextend(immbits,13,32)
+ imm = implodebits(immbits,13,true)
+ mem.registers.pc = (mem.registers.pc + imm) % 2^32
+ return true
+ end
+ end,
+ blt = function(rs1,rs2,imm)
+ local num1 = getreg(rs1)
+ local num2 = getreg(rs2)
+ if num1 >= 2^31 then num1 = num1-(2^32) end
+ if num2 >= 2^31 then num2 = num2-(2^32) end
+ if num1 < num2 then
+ local immbits = explodebits(imm,13)
+ signextend(immbits,13,32)
+ imm = implodebits(immbits,13,true)
+ mem.registers.pc = (mem.registers.pc + imm) % 2^32
+ return true
+ end
+ end,
+ bge = function(rs1,rs2,imm)
+ local num1 = getreg(rs1)
+ local num2 = getreg(rs2)
+ if num1 >= 2^31 then num1 = num1-(2^32) end
+ if num2 >= 2^31 then num2 = num2-(2^32) end
+ if num1 >= num2 then
+ local immbits = explodebits(imm,13)
+ signextend(immbits,13,32)
+ imm = implodebits(immbits,13,true)
+ mem.registers.pc = (mem.registers.pc + imm) % 2^32
+ return true
+ end
+ end,
+ bltu = function(rs1,rs2,imm)
+ local num1 = getreg(rs1)
+ local num2 = getreg(rs2)
+ if num1 < num2 then
+ local immbits = explodebits(imm,13)
+ signextend(immbits,13,32)
+ imm = implodebits(immbits,13,true)
+ mem.registers.pc = (mem.registers.pc + imm) % 2^32
+ return true
+ end
+ end,
+ bgeu = function(rs1,rs2,imm)
+ local num1 = getreg(rs1)
+ local num2 = getreg(rs2)
+ if num1 >= num2 then
+ local immbits = explodebits(imm,13)
+ signextend(immbits,13,32)
+ imm = implodebits(immbits,13,true)
+ mem.registers.pc = (mem.registers.pc + imm) % 2^32
+ return true
+ end
+ end,
+ jal = function(rd,imm,compressed)
+ setreg(rd,mem.registers.pc+(compressed and 2 or 4))
+ local immbits = explodebits(imm,21)
+ signextend(immbits,21,32)
+ imm = implodebits(immbits,32,true)
+ local oldpc = mem.registers.pc
+ mem.registers.pc = (mem.registers.pc + imm) % 2^32
+ return true
+ end,
+ jalr = function(rd,rs1,imm,compressed)
+ local oldpc = mem.registers.pc
+ local immbits = explodebits(imm,12)
+ signextend(immbits,12,32)
+ imm = implodebits(immbits,32,true)
+ mem.registers.pc = (getreg(rs1) + imm) % 2^32
+ if mem.registers.pc%2 == 1 then mem.registers.pc = mem.registers.pc - 1 end
+ setreg(rd,oldpc+(compressed and 2 or 4))
+ return true
+ end,
+ lui = function(rd,imm)
+ setreg(rd,imm)
+ end,
+ auipc = function(rd,imm)
+ setreg(rd,mem.registers.pc+imm)
+ end,
+ lb = function(rd,rs1,imm)
+ if imm >= 2^11 then imm = imm - 2^12 end
+ local data = readram(getreg(rs1)+imm,1)
+ data = explodebits(data,8)
+ signextend(data,8,32)
+ data = implodebits(data,32,false)
+ setreg(rd,data)
+ end,
+ lh = function(rd,rs1,imm)
+ if imm >= 2^11 then imm = imm - 2^12 end
+ local data = readram(getreg(rs1)+imm,2)
+ data = explodebits(data,16)
+ signextend(data,16,32)
+ data = implodebits(data,32,false)
+ setreg(rd,data)
+ end,
+ lw = function(rd,rs1,imm)
+ if imm >= 2^11 then imm = imm - 2^12 end
+ local data = readram(getreg(rs1)+imm,4)
+ setreg(rd,data)
+ end,
+ ld = function(rd,rs1,imm)
+ if rd == 0 or rd == 31 then return end
+ if imm >= 2^11 then imm = imm - 2^12 end
+ local address = getreg(rs1)+imm
+ setreg(rd,readram(address,4))
+ setreg(rd+1,readram(address+4,4))
+ end,
+ lhu = function(rd,rs1,imm)
+ if imm >= 2^11 then imm = imm - 2^12 end
+ local data = readram(getreg(rs1)+imm,2)
+ setreg(rd,data)
+ end,
+ lbu = function(rd,rs1,imm)
+ if imm >= 2^11 then imm = imm - 2^12 end
+ local data = readram(getreg(rs1)+imm,1)
+ setreg(rd,data)
+ end,
+ sb = function(rs1,rs2,imm)
+ if imm >= 2^11 then imm = imm - 2^12 end
+ writeram(getreg(rs1)+imm,getreg(rs2)%0x100,1)
+ end,
+ sh = function(rs1,rs2,imm)
+ if imm >= 2^11 then imm = imm - 2^12 end
+ writeram(getreg(rs1)+imm,getreg(rs2)%0x10000,2)
+ end,
+ sw = function(rs1,rs2,imm)
+ if imm >= 2^11 then imm = imm - 2^12 end
+ writeram(getreg(rs1)+imm,getreg(rs2),4)
+ end,
+ sd = function(rs1,rs2,imm)
+ if rs2 == 31 then return end
+ if imm >= 2^11 then imm = imm - 2^12 end
+ local address = getreg(rs1)+imm
+ writeram(address,getreg(rs2),4)
+ writeram(address+4,getreg(rs2+1),4)
+ end,
+ ecall = function()
+ local func = getreg(17)
+ local param1 = getreg(10)
+ local param2 = getreg(11)
+ if func == 1 then
+ --a7=1 - Print Integer
+ if param1 > 2^31 then param1 = param1-2^32 end
+ stdout(string.format("%d",param1))
+ elseif func == 4 then
+ --a7=4 - Print String
+ local str = ""
+ for i=0,255 do
+ local byte = readram(param1+i,1)
+ if byte == 0 then break end
+ str = str..string.char(byte)
+ end
+ stdout(str)
+ elseif func == 5 then
+ --a7=5 - Read Integer
+ digiline_send("monitordisp","Waiting for input")
+ mem.running = false
+ mem.inputwaiting = true
+ mem.inputwaittype = "integer"
+ return false,true
+ elseif func == 8 then
+ --a7=8 - Read String
+ digiline_send("monitordisp","Waiting for input")
+ mem.running = false
+ mem.inputwaiting = true
+ mem.inputwaittype = "string"
+ mem.inputaddr = getreg(10)
+ mem.inputmax = getreg(11)
+ return false,true
+ elseif func == 10 then
+ --a7=10 - Exit Program
+ mem.running = false
+ digiline_send("monitordisp","Program\nexited normally")
+ digiline_send("monitordisp","System halted")
+ digiline_send("monitordisp",string.format("PC:%08X",mem.registers.pc))
+ elseif func == 11 then
+ --a7=11 - Print Character
+ stdout(string.char(getreg(10)))
+ elseif func == 12 then
+ --a7=12 - Read Character
+ digiline_send("monitordisp","Waiting for input")
+ mem.running = false
+ mem.inputwaiting = true
+ mem.inputwaittype = "char"
+ return false,true
+ elseif func == 128 then
+ --a7=128 - Get Random Integer
+ local lowlimit = getreg(10)
+ local highlimit = getreg(11)
+ if lowlimit >= 2^31 then lowlimit = lowlimit - 2^32 end
+ if highlimit >= 2^31 then highlimit = highlimit - 2^32 end
+ local result = math.random(lowlimit,highlimit)
+ if result < 0 then result = result + 2^32 end
+ setreg(10,result)
+ elseif func == 129 then
+ --a7=129 - Send digilines string message
+ local channel = ""
+ for i=0,255 do
+ local byte = readram(param1+i,1)
+ if byte == 0 then break end
+ channel = channel..string.char(byte)
+ end
+ local message = ""
+ for i=0,255 do
+ local byte = readram(param2+i,1)
+ if byte == 0 then break end
+ message = message..string.char(byte)
+ end
+ digiline_send(channel,message)
+ elseif func == 130 then
+ --a7=130 - Get Input Buffer Level
+ setreg(10,string.len(mem.inputbuf))
+ elseif func == 131 then
+ --a7=131 - Clear Input Buffer
+ mem.inputbuf = ""
+ elseif func == 132 then
+ --a7=132 -- Read Character From Input Buffer
+ if mem.inputbuf == "" then
+ setreg(10,0)
+ else
+ setreg(10,string.byte(string.sub(mem.inputbuf,1,1)))
+ mem.inputbuf = string.sub(mem.inputbuf,2,-1)
+ end
+ elseif func == 133 then
+ --a7=133 - Get Digilines Buffer Level
+ setreg(10,#mem.digilinesqueue)
+ elseif func == 134 then
+ --a7=134 - Clear Digilines Buffer
+ mem.digilinesqueue = {}
+ elseif func == 135 then
+ --a7=135 - Read Digilines Message
+ local dlevent = mem.digilinesqueue[1]
+ if not dlevent then dlevent = {channel = "",msg = ""} end
+ dlevent.channel = string.sub(dlevent.channel,1,getreg(11)-1).."\0"
+ dlevent.msg = string.sub(dlevent.msg,1,getreg(13)-1).."\0"
+ local channelstart = getreg(10)
+ for i=1,string.len(dlevent.channel) do
+ local address = channelstart+i-1
+ writeram(address,string.byte(string.sub(dlevent.channel,i,i)),1)
+ end
+ local msgstart = getreg(12)
+ for i=1,string.len(dlevent.msg) do
+ local address = msgstart+i-1
+ writeram(address,string.byte(string.sub(dlevent.msg,i,i)),1)
+ end
+ table.remove(mem.digilinesqueue,1)
+ end
+ end,
+ ebreak = function()
+ mem.running = false
+ digiline_send("monitordisp","Hit breakpoint")
+ digiline_send("montiordisp","System halted")
+ digiline_send("monitordisp",string.format("PC:%08X",mem.registers.pc))
+ end,
+ csrrw = function(rd,rs1,imm)
+ setreg(rd,readcsr(imm))
+ writecsr(imm,getreg(rs1))
+ end,
+ csrrs = function(rd,rs1,imm)
+ setreg(rd,readcsr(imm))
+ if rs1 == 0 then return end
+ local csrbits = explodebits(readcsr(imm),32)
+ local rs1bits = explodebits(getreg(rs1),32)
+ for i=0,31 do
+ csrbits[i] = csrbits[i] or rs1bits[i]
+ end
+ writecsr(imm,implodebits(csrbits,32))
+ end,
+ csrrc = function(rd,rs1,imm)
+ setreg(rd,readcsr(imm))
+ if rs1 == 0 then return end
+ local csrbits = explodebits(readcsr(imm),32)
+ local rs1bits = explodebits(getreg(rs1),32)
+ for i=0,31 do
+ csrbits[i] = csrbits[i] and not rs1bits[i]
+ end
+ writecsr(imm,implodebits(csrbits,32))
+ end,
+ csrrwi = function(rd,rs1,imm)
+ setreg(rd,readcsr(imm))
+ writecsr(imm,rs1)
+ end,
+ csrrsi = function(rd,rs1,imm)
+ setreg(rd,readcsr(imm))
+ if rs1 == 0 then return end
+ local csrbits = explodebits(readcsr(imm),32)
+ local rs1bits = explodebits(rs1,32)
+ for i=0,31 do
+ csrbits[i] = csrbits[i] or rs1bits[i]
+ end
+ writecsr(imm,implodebits(csrbits,32))
+ end,
+ csrrci = function(rd,rs1,imm)
+ setreg(rd,readcsr(imm))
+ if rs1 == 0 then return end
+ local csrbits = explodebits(readcsr(imm),32)
+ local rs1bits = explodebits(rs1,32)
+ for i=0,31 do
+ csrbits[i] = csrbits[i] and not rs1bits[i]
+ end
+ writecsr(imm,implodebits(csrbits,32))
+ end,
+ mul = function(rd,rs1,rs2)
+ local plow = mul64(getreg(rs1),getreg(rs2),false,false)
+ setreg(rd,plow)
+ end,
+ mulh = function(rd,rs1,rs2)
+ local _,phigh = mul64(getreg(rs1),getreg(rs2),true,true)
+ setreg(rd,phigh)
+ end,
+ mulsu = function(rd,rs1,rs2)
+ local _,phigh = mul64(getreg(rs1),getreg(rs2),true,false)
+ setreg(rd,phigh)
+ end,
+ mulu = function(rd,rs1,rs2)
+ local _,phigh = mul64(getreg(rs1),getreg(rs2),false,false)
+ setreg(rd,phigh)
+ end,
+ div = function(rd,rs1,rs2)
+ local a = getreg(rs1)
+ local b = getreg(rs2)
+ if b == 0 then
+ --Division by zero
+ setreg(rd,2^32-1)
+ return
+ end
+ if a >= 2^31 then a = a - 2^32 end
+ if b >= 2^31 then b = b - 2^32 end
+ if a == -2^31 and b == -1 then
+ --Divide overflow
+ setreg(rd,a)
+ end
+ local result = math.floor(a/b)
+ if result < 0 then result = result + 2^32 end
+ setreg(rd,result)
+ end,
+ rem = function(rd,rs1,rs2)
+ local a = getreg(rs1)
+ local b = getreg(rs2)
+ if b == 0 then
+ --Division by zero
+ setreg(rd,a)
+ return
+ end
+ if a >= 2^31 then a = a - 2^32 end
+ if b >= 2^31 then b = b - 2^32 end
+ if a == -2^31 and b == -1 then
+ --Divide overflow
+ setreg(rd,0)
+ end
+ local result = a%b
+ setreg(rd,result)
+ end,
+ divu = function(rd,rs1,rs2)
+ local a = getreg(rs1)
+ local b = getreg(rs2)
+ if b == 0 then
+ --Division by zero
+ setreg(rd,2^32-1)
+ return
+ end
+ local result = math.floor(a/b)
+ setreg(rd,result)
+ end,
+ remu = function(rd,rs1,rs2)
+ local a = getreg(rs1)
+ local b = getreg(rs2)
+ if b == 0 then
+ --Division by zero
+ setreg(rd,a)
+ return
+ end
+ local result = a%b
+ setreg(rd,result)
+ end,
+ sh1add = function(rd,rs1,rs2)
+ setreg(rd,getreg(rs1)*2+getreg(rs2))
+ end,
+ sh2add = function(rd,rs1,rs2)
+ setreg(rd,getreg(rs1)*4+getreg(rs2))
+ end,
+ sh3add = function(rd,rs1,rs2)
+ setreg(rd,getreg(rs1)*8+getreg(rs2))
+ end,
+ clz = function(rd,rs1)
+ local bits = explodebits(getreg(rs1),32)
+ for i=31,0,-1 do
+ if bits[i] then
+ setreg(rd,31-i)
+ return
+ end
+ end
+ setreg(rd,32)
+ end,
+ ctz = function(rd,rs1)
+ local bits = explodebits(getreg(rs1),32)
+ for i=0,31 do
+ if bits[i] then
+ setreg(rd,i)
+ return
+ end
+ end
+ setreg(rd,32)
+ end,
+ cpop = function(rd,rs1)
+ local bits = explodebits(getreg(rs1),32)
+ local out = 0
+ for i=0,31 do
+ if bits[i] then
+ out = out + 1
+ end
+ end
+ setreg(rd,out)
+ end,
+ maxu = function(rd,rs1,rs2)
+ setreg(rd,math.max(getreg(rs1),getreg(rs2)))
+ end,
+ minu = function(rd,rs1,rs2)
+ setreg(rd,math.min(getreg(rs1),getreg(rs2)))
+ end,
+ max = function(rd,rs1,rs2)
+ local a = getreg(rs1)
+ local b = getreg(rs2)
+ if a >= 2^31 then a = a - 2^32 end
+ if b >= 2^31 then b = b - 2^32 end
+ local out = math.max(a,b)
+ if out < 0 then out = out + 2^32 end
+ setreg(rd,out)
+ end,
+ min = function(rd,rs1,rs2)
+ local a = getreg(rs1)
+ local b = getreg(rs2)
+ if a >= 2^31 then a = a - 2^32 end
+ if b >= 2^31 then b = b - 2^32 end
+ local out = math.min(a,b)
+ if out < 0 then out = out + 2^32 end
+ setreg(rd,out)
+ end,
+ sextb = function(rd,rs1)
+ local bits = explodebits(getreg(rs1),8)
+ signextend(bits,8,32)
+ setreg(rd,implodebits(bits,32))
+ end,
+ sexth = function(rd,rs1)
+ local bits = explodebits(getreg(rs1),16)
+ signextend(bits,16,32)
+ setreg(rd,implodebits(bits,32))
+ end,
+ zexth = function(rd,rs1)
+ setreg(rd,getreg(rs1)%2^16)
+ end,
+ rol = function(rd,rs1,rs2)
+ local num = getreg(rs1)
+ local amount = getreg(rs2)%32
+ if amount == 0 then return end
+ for i=1,amount do
+ local endbit = num >= 2^31
+ num = (num*2)%2^32
+ if endbit then num = num + 1 end
+ end
+ setreg(rd,num)
+ end,
+ ror = function(rd,rs1,rs2)
+ local num = getreg(rs1)
+ local amount = getreg(rs2)%32
+ if amount == 0 then
+ setreg(rd,num)
+ return
+ end
+ for _=1,amount do
+ local endbit = num%2 == 1
+ num = math.floor(num/2)
+ if endbit then num = num + 2^31 end
+ end
+ setreg(rd,num)
+ end,
+ rori = function(rd,rs1,imm)
+ local num = getreg(rs1)
+ local amount = imm%32
+ if amount == 0 then
+ setreg(rd,num)
+ return
+ end
+ for _=1,amount do
+ local endbit = num%2 == 1
+ num = math.floor(num/2)
+ if endbit then num = num + 2^31 end
+ end
+ setreg(rd,num)
+ end,
+ orcb = function(rd,rs1)
+ local input = getreg(rs1)
+ local b1 = input%2^8 > 0
+ local b2 = math.floor(input/2^8)%2^8 > 0
+ local b3 = math.floor(input/2^16)%2^8 > 0
+ local b4 = math.floor(input/2^24)%2^8 > 0
+ local out = 0
+ if b1 then out = out + 0xff end
+ if b2 then out = out + 0xff00 end
+ if b3 then out = out + 0xff0000 end
+ if b4 then out = out + 0xff000000 end
+ setreg(rd,out)
+ end,
+ rev8 = function(rd,rs1)
+ local input = getreg(rs1)
+ local b1 = input%2^8
+ local b2 = math.floor(input/2^8)%2^8
+ local b3 = math.floor(input/2^16)%2^8
+ local b4 = math.floor(input/2^24)%2^8
+ local out = b4
+ out = out + (b3*2^8)
+ out = out + (b2*2^16)
+ out = out + (b1*2^24)
+ setreg(rd,out)
+ end,
+ bclr = function(rd,rs1,rs2)
+ local bits = explodebits(getreg(rs1),32)
+ bits[getreg(rs2)%32] = false
+ setreg(rd,implodebits(bits,32))
+ end,
+ bset = function(rd,rs1,rs2)
+ local bits = explodebits(getreg(rs1),32)
+ bits[getreg(rs2)%32] = true
+ setreg(rd,implodebits(bits,32))
+ end,
+ binv = function(rd,rs1,rs2)
+ local bits = explodebits(getreg(rs1),32)
+ bits[getreg(rs2)%32] = not bits[getreg(rs2)%32]
+ setreg(rd,implodebits(bits,32))
+ end,
+ bclri = function(rd,rs1,imm)
+ local bits = explodebits(getreg(rs1),32)
+ bits[imm%32] = false
+ setreg(rd,implodebits(bits,32))
+ end,
+ bseti = function(rd,rs1,imm)
+ local bits = explodebits(getreg(rs1),32)
+ bits[imm%32] = true
+ setreg(rd,implodebits(bits,32))
+ end,
+ binvi = function(rd,rs1,imm)
+ local bits = explodebits(getreg(rs1),32)
+ bits[imm%32] = not bits[imm%32]
+ setreg(rd,implodebits(bits,32))
+ end,
+ bext = function(rd,rs1,rs2)
+ local bit = explodebits(getreg(rs1),32)[getreg(rs2)%32]
+ setreg(rd,bit and 1 or 0)
+ end,
+ bexti = function(rd,rs1,imm)
+ local bit = explodebits(getreg(rs1),32)[imm%32]
+ setreg(rd,bit and 1 or 0)
+ end,
+ xperm8 = function(rd,rs1,rs2)
+ local a = getreg(rs1)
+ local outputs = {
+ [0] = a%2^8,
+ math.floor(a/2^8)%2^8,
+ math.floor(a/2^16)%2^8,
+ math.floor(a/2^24)%2^8,
+ }
+ local b = getreg(rs2)
+ local selections = {
+ [0] = b%2^8,
+ math.floor(b/2^8)%2^8,
+ math.floor(b/2^16)%2^8,
+ math.floor(b/2^24)%2^8,
+ }
+ local out = 0
+ for i=0,3 do
+ local num = outputs[selections[i]] or 0
+ out = out+(num*2^(i*8))
+ end
+ setreg(rd,out)
+ end,
+ xperm4 = function(rd,rs1,rs2)
+ local a = getreg(rs1)
+ local outputs = {
+ [0] = a%2^4,
+ math.floor(a/2^4)%2^4,
+ math.floor(a/2^8)%2^4,
+ math.floor(a/2^12)%2^4,
+ math.floor(a/2^16)%2^4,
+ math.floor(a/2^20)%2^4,
+ math.floor(a/2^24)%2^4,
+ math.floor(a/2^28)%2^4,
+ }
+ local b = getreg(rs2)
+ local selections = {
+ [0] = b%2^4,
+ math.floor(b/2^4)%2^4,
+ math.floor(b/2^8)%2^4,
+ math.floor(b/2^12)%2^4,
+ math.floor(b/2^16)%2^4,
+ math.floor(b/2^20)%2^4,
+ math.floor(b/2^24)%2^4,
+ math.floor(b/2^28)%2^4,
+ }
+ local out = 0
+ for i=0,7 do
+ local num = outputs[selections[i]] or 0
+ out = out+(num*2^(i*4))
+ end
+ setreg(rd,out)
+ end,
+ lr = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ setreg(rd,readram(address,4))
+ mem.reservationset = address
+ end,
+ sc = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ if mem.reservationset == address then
+ writeram(address,getreg(rs2),4)
+ setreg(rd,0)
+ else
+ setreg(rd,1)
+ end
+ mem.reservationset = nil
+ end,
+ amoswapw = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local newdata = getreg(rs2)
+ setreg(rd,readram(address,4))
+ writeram(address,newdata,4)
+ end,
+ amoaddw = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,4)
+ local newdata = getreg(rs2)
+ setreg(rd,data)
+ writeram(address,(data+newdata)%2^32,4)
+ end,
+ amoandw = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,4)
+ local newdata = getreg(rs2)
+ setreg(rd,data)
+ local bits = explodebits(data,32)
+ local newbits = explodebits(newdata,32)
+ for i=0,31 do bits[i] = bits[i] and newbits[i] end
+ writeram(address,implodebits(bits,32),4)
+ end,
+ amoorw = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,4)
+ local newdata = getreg(rs2)
+ setreg(rd,data)
+ local bits = explodebits(data,32)
+ local newbits = explodebits(newdata,32)
+ for i=0,31 do bits[i] = bits[i] or newbits[i] end
+ writeram(address,implodebits(bits,32),4)
+ end,
+ amoxorw = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,4)
+ local newdata = getreg(rs2)
+ setreg(rd,data)
+ local bits = explodebits(data,32)
+ local newbits = explodebits(newdata,32)
+ for i=0,31 do bits[i] = bits[i] ~= newbits[i] end
+ writeram(address,implodebits(bits,32),4)
+ end,
+ amomaxw = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,4)
+ local newdata = getreg(rs2)
+ setreg(rd,data)
+ if data > 2^31 then data = data - 2^32 end
+ if newdata > 2^31 then newdata = newdata - 2^32 end
+ newdata = math.max(data,newdata)
+ if newdata < 0 then newdata = newdata + 2^32 end
+ writeram(address,newdata,4)
+ end,
+ amomaxuw = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,4)
+ local newdata = getreg(rs2)
+ setreg(rd,data)
+ newdata = math.max(data,newdata)
+ writeram(address,newdata,4)
+ end,
+ amominw = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,4)
+ local newdata = getreg(rs2)
+ setreg(rd,data)
+ if data > 2^31 then data = data - 2^32 end
+ if newdata > 2^31 then newdata = newdata - 2^32 end
+ newdata = math.min(data,newdata)
+ if newdata < 0 then newdata = newdata + 2^32 end
+ writeram(address,newdata,4)
+ end,
+ amominuw = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,4)
+ local newdata = getreg(rs2)
+ setreg(rd,data)
+ newdata = math.min(data,newdata)
+ writeram(address,newdata,4)
+ end,
+ amocasw = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,4)
+ local compare = getreg(rd)
+ if data == compare then
+ writeram(address,getreg(rs2),4)
+ end
+ setreg(rd,data)
+ end,
+ amocasd = function(rd,rs1,rs2)
+ if rd == 31 then return end
+ if rs2 == 31 then return end
+ local address = getreg(rs1)
+ local datalow = readram(address,4)
+ local datahigh = readram(address+4,4)
+ local comparelow = getreg(rd)
+ local comparehigh = rd == 0 and 0 or getreg(rd+1)
+ if datalow == comparelow and datahigh == comparehigh then
+ writeram(address,getreg(rs2),4)
+ writeram(address+4,rs2 == 0 and 0 or getreg(rs2+1),4)
+ end
+ if rd ~= 0 then
+ setreg(rd,datalow)
+ setreg(rd+1,datahigh)
+ end
+ end,
+ amoswaph = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local newdata = getreg(rs2)%2^16
+ local olddata = explodebits(readram(address,2),16)
+ signextend(olddata,16,32)
+ setreg(rd,implodebits(olddata,32))
+ writeram(address,newdata,2)
+ end,
+ amoaddh = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,2)
+ local newdata = getreg(rs2)%2^16
+ local oldbits = explodebits(data,16)
+ signextend(oldbits,16,32)
+ setreg(rd,implodebits(oldbits,32))
+ writeram(address,(data+newdata)%2^16,2)
+ end,
+ amoandh = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,2)
+ local newdata = getreg(rs2)%2^16
+ local bits = explodebits(data,16)
+ signextend(bits,16,32)
+ setreg(rd,implodebits(bits,32))
+ local newbits = explodebits(newdata,16)
+ for i=0,15 do bits[i] = bits[i] and newbits[i] end
+ writeram(address,implodebits(bits,16),2)
+ end,
+ amoorh = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,2)
+ local newdata = getreg(rs2)%2^16
+ local bits = explodebits(data,16)
+ signextend(bits,16,32)
+ setreg(rd,implodebits(bits,32))
+ local newbits = explodebits(newdata,16)
+ for i=0,15 do bits[i] = bits[i] or newbits[i] end
+ writeram(address,implodebits(bits,16),2)
+ end,
+ amoxorh = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,2)
+ local newdata = getreg(rs2)%2^16
+ local bits = explodebits(data,16)
+ signextend(bits,16,32)
+ setreg(rd,implodebits(bits,32))
+ local newbits = explodebits(newdata,16)
+ for i=0,15 do bits[i] = bits[i] ~= newbits[i] end
+ writeram(address,implodebits(bits,16),2)
+ end,
+ amomaxh = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,2)
+ local newdata = getreg(rs2)%2^16
+ local bits = explodebits(data,16)
+ signextend(bits,16,32)
+ setreg(rd,implodebits(bits,32))
+ if data > 2^15 then data = data - 2^16 end
+ if newdata > 2^15 then newdata = newdata - 2^16 end
+ newdata = math.max(data,newdata)
+ if newdata < 0 then newdata = newdata + 2^16 end
+ writeram(address,newdata,2)
+ end,
+ amomaxuh = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,2)
+ local newdata = getreg(rs2)%2^16
+ local bits = explodebits(data,16)
+ signextend(bits,16,32)
+ setreg(rd,implodebits(bits,32))
+ newdata = math.max(data,newdata)
+ writeram(address,newdata,2)
+ end,
+ amominh = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,2)
+ local newdata = getreg(rs2)%2^16
+ local bits = explodebits(data,16)
+ signextend(bits,16,32)
+ setreg(rd,implodebits(bits,32))
+ if data > 2^15 then data = data - 2^16 end
+ if newdata > 2^15 then newdata = newdata - 2^16 end
+ newdata = math.min(data,newdata)
+ if newdata < 0 then newdata = newdata + 2^16 end
+ writeram(address,newdata,2)
+ end,
+ amominuh = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,2)
+ local newdata = getreg(rs2)%2^16
+ local bits = explodebits(data,16)
+ signextend(bits,16,32)
+ setreg(rd,implodebits(bits,32))
+ newdata = math.min(data,newdata)
+ writeram(address,newdata,2)
+ end,
+ amocash = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,2)
+ local compare = getreg(rd)%2^16
+ if data == compare then
+ writeram(address,getreg(rs2)%2^16,2)
+ end
+ local bits = explodebits(data,16)
+ signextend(bits,16,32)
+ setreg(rd,implodebits(bits,32))
+ end,
+ amoswapb = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local newdata = getreg(rs2)%2^8
+ local olddata = explodebits(readram(address,1),8)
+ signextend(olddata,8,32)
+ setreg(rd,implodebits(olddata,32))
+ writeram(address,newdata,1)
+ end,
+ amoaddb = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,1)
+ local newdata = getreg(rs2)%2^8
+ local oldbits = explodebits(data,8)
+ signextend(oldbits,8,32)
+ setreg(rd,implodebits(oldbits,32))
+ writeram(address,(data+newdata)%2^8,1)
+ end,
+ amoandb = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,1)
+ local newdata = getreg(rs2)%2^8
+ local bits = explodebits(data,8)
+ signextend(bits,8,32)
+ setreg(rd,implodebits(bits,32))
+ local newbits = explodebits(newdata,8)
+ for i=0,7 do bits[i] = bits[i] and newbits[i] end
+ writeram(address,implodebits(bits,8),1)
+ end,
+ amoorb = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,1)
+ local newdata = getreg(rs2)%2^8
+ local bits = explodebits(data,8)
+ signextend(bits,8,32)
+ setreg(rd,implodebits(bits,32))
+ local newbits = explodebits(newdata,8)
+ for i=0,7 do bits[i] = bits[i] or newbits[i] end
+ writeram(address,implodebits(bits,8),1)
+ end,
+ amoxorb = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,1)
+ local newdata = getreg(rs2)%2^8
+ local bits = explodebits(data,8)
+ signextend(bits,8,32)
+ setreg(rd,implodebits(bits,32))
+ local newbits = explodebits(newdata,8)
+ for i=0,7 do bits[i] = bits[i] ~= newbits[i] end
+ writeram(address,implodebits(bits,8),1)
+ end,
+ amomaxb = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,1)
+ local newdata = getreg(rs2)%2^8
+ local bits = explodebits(data,8)
+ signextend(bits,8,32)
+ setreg(rd,implodebits(bits,32))
+ if data > 2^7 then data = data - 2^8 end
+ if newdata > 2^7 then newdata = newdata - 2^8 end
+ newdata = math.max(data,newdata)
+ if newdata < 0 then newdata = newdata + 2^8 end
+ writeram(address,newdata,1)
+ end,
+ amomaxub = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,1)
+ local newdata = getreg(rs2)%2^8
+ local bits = explodebits(data,8)
+ signextend(bits,8,32)
+ setreg(rd,implodebits(bits,32))
+ newdata = math.max(data,newdata)
+ writeram(address,newdata,1)
+ end,
+ amominb = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,1)
+ local newdata = getreg(rs2)%2^8
+ local bits = explodebits(data,8)
+ signextend(bits,8,32)
+ setreg(rd,implodebits(bits,32))
+ if data > 2^7 then data = data - 2^8 end
+ if newdata > 2^7 then newdata = newdata - 2^8 end
+ newdata = math.min(data,newdata)
+ if newdata < 0 then newdata = newdata + 2^8 end
+ writeram(address,newdata,1)
+ end,
+ amominub = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,1)
+ local newdata = getreg(rs2)%2^8
+ local bits = explodebits(data,8)
+ signextend(bits,8,32)
+ setreg(rd,implodebits(bits,8))
+ newdata = math.min(data,newdata)
+ writeram(address,newdata,1)
+ end,
+ amocasb = function(rd,rs1,rs2)
+ local address = getreg(rs1)
+ local data = readram(address,1)
+ local compare = getreg(rd)%2^8
+ if data == compare then
+ writeram(address,getreg(rs2)%2^8,1)
+ end
+ local bits = explodebits(data,8)
+ signextend(bits,8,32)
+ setreg(rd,implodebits(bits,32))
+ end,
+ pack = function(rd,rs1,rs2)
+ local lowhalf = getreg(rs1)%2^16
+ local highhalf = (getreg(rs2)%2^16)*2^16
+ setreg(rd,lowhalf+highhalf)
+ end,
+ packh = function(rd,rs1,rs2)
+ local lowhalf = getreg(rs1)%2^8
+ local highhalf = (getreg(rs2)%2^8)*2^8
+ setreg(rd,lowhalf+highhalf)
+ end,
+ brev8 = function(rd,rs1,imm)
+ local bits = explodebits(getreg(rs1),32)
+ local newbits = {}
+ for byte=0,3 do
+ for bit=0,7 do
+ local source = byte*8+bit
+ local destination = byte*8+(7-bit)
+ newbits[destination] = bits[source]
+ end
+ end
+ setreg(rd,implodebits(newbits,32))
+ end,
+ zip = function(rd,rs1,imm)
+ local bits = explodebits(getreg(rs1),32)
+ local newbits = {}
+ for i=0,15 do
+ newbits[i*2] = bits[i]
+ newbits[i*2+1] = bits[i+16]
+ end
+ setreg(rd,implodebits(newbits,32))
+ end,
+ unzip = function(rd,rs1,imm)
+ local bits = explodebits(getreg(rs1),32)
+ local newbits = {}
+ for i=0,15 do
+ newbits[i] = bits[i*2]
+ newbits[i+16] = bits[i*2+1]
+ end
+ setreg(rd,implodebits(newbits,32))
+ end,
+ czeroeqz = function(rd,rs1,rs2)
+ if getreg(rs2) == 0 then
+ setreg(rd,0)
+ else
+ setreg(rd,getreg(rs1))
+ end
+ end,
+ czeronez = function(rd,rs1,rs2)
+ if getreg(rs2) ~= 0 then
+ setreg(rd,0)
+ else
+ setreg(rd,getreg(rs1))
+ end
+ end,
+}
+
+local function runinst(instruction)
+ local bits = explodebits(instruction,32)
+ local opcode = implodebits(bits,7)
+ if opcode == 0x33 then
+ --R-type
+ --This is spectaularly inefficient and will probably need to be optimized later.
+ --Really, the whole program is.
+ --Focus is on making it work first...
+ local f3bits = {[0] = bits[12],bits[13],bits[14]}
+ local f3 = implodebits(f3bits,3)
+ local f7bits = {[0] = bits[25],bits[26],bits[27],bits[28],bits[29],bits[30],bits[31]}
+ local f7 = implodebits(f7bits,7)
+ local rdbits = {[0] = bits[7],bits[8],bits[9],bits[10],bits[11]}
+ local rd = implodebits(rdbits,5)
+ local rs1bits = {[0] = bits[15],bits[16],bits[17],bits[18],bits[19]}
+ local rs1 = implodebits(rs1bits,5)
+ local rs2bits = {[0] = bits[20],bits[21],bits[22],bits[23],bits[24]}
+ local rs2 = implodebits(rs2bits,5)
+ if f3 == 0x0 and f7 == 0x0 then
+ operations.add(rd,rs1,rs2)
+ elseif f3 == 0x0 and f7 == 0x20 then
+ operations.sub(rd,rs1,rs2)
+ elseif f3 == 0x4 and f7 == 0x0 then
+ operations.xor(rd,rs1,rs2)
+ elseif f3 == 0x6 and f7 == 0x0 then
+ operations.orr(rd,rs1,rs2)
+ elseif f3 == 0x7 and f7 == 0x0 then
+ operations.andr(rd,rs1,rs2)
+ elseif f3 == 0x1 and f7 == 0x0 then
+ operations.sll(rd,rs1,rs2)
+ elseif f3 == 0x5 and f7 == 0x0 then
+ operations.srl(rd,rs1,rs2)
+ elseif f3 == 0x5 and f7 == 0x20 then
+ operations.sra(rd,rs1,rs2)
+ elseif f3 == 0x2 and f7 == 0x0 then
+ operations.slt(rd,rs1,rs2)
+ elseif f3 == 0x3 and f7 == 0x0 then
+ operations.sltu(rd,rs1,rs2)
+ elseif f3 == 0x0 and f7 == 0x1 then
+ operations.mul(rd,rs1,rs2)
+ elseif f3 == 0x1 and f7 == 0x1 then
+ operations.mulh(rd,rs1,rs2)
+ elseif f3 == 0x2 and f7 == 0x1 then
+ operations.mulsu(rd,rs1,rs2)
+ elseif f3 == 0x3 and f7 == 0x1 then
+ operations.mulu(rd,rs1,rs2)
+ elseif f3 == 0x4 and f7 == 0x1 then
+ operations.div(rd,rs1,rs2)
+ elseif f3 == 0x5 and f7 == 0x1 then
+ operations.divu(rd,rs1,rs2)
+ elseif f3 == 0x6 and f7 == 0x1 then
+ operations.rem(rd,rs1,rs2)
+ elseif f3 == 0x7 and f7 == 0x1 then
+ operations.remu(rd,rs1,rs2)
+ elseif f3 == 0x2 and f7 == 0x10 then
+ operations.sh1add(rd,rs1,rs2)
+ elseif f3 == 0x4 and f7 == 0x10 then
+ operations.sh2add(rd,rs1,rs2)
+ elseif f3 == 0x6 and f7 == 0x10 then
+ operations.sh3add(rd,rs1,rs2)
+ elseif f3 == 0x7 and f7 == 0x20 then
+ operations.andn(rd,rs1,rs2)
+ elseif f3 == 0x6 and f7 == 0x20 then
+ operations.orn(rd,rs1,rs2)
+ elseif f3 == 0x4 and f7 == 0x20 then
+ operations.xnor(rd,rs1,rs2)
+ elseif f3 == 0x6 and f7 == 0x5 then
+ operations.max(rd,rs1,rs2)
+ elseif f3 == 0x7 and f7 == 0x5 then
+ operations.maxu(rd,rs1,rs2)
+ elseif f3 == 0x4 and f7 == 0x5 then
+ operations.min(rd,rs1,rs2)
+ elseif f3 == 0x5 and f7 == 0x5 then
+ operations.minu(rd,rs1,rs2)
+ elseif f3 == 0x4 and f7 == 0x4 and rs2 == 0x0 then
+ operations.zexth(rd,rs1)
+ elseif f3 == 0x1 and f7 == 0x30 then
+ operations.rol(rd,rs1,rs2)
+ elseif f3 == 0x5 and f7 == 0x30 then
+ operations.ror(rd,rs1,rs2)
+ elseif f3 == 0x1 and f7 == 0x24 then
+ operations.bclr(rd,rs1,rs2)
+ elseif f3 == 0x5 and f7 == 0x24 then
+ operations.bext(rd,rs1,rs2)
+ elseif f3 == 0x1 and f7 == 0x34 then
+ operations.binv(rd,rs1,rs2)
+ elseif f3 == 0x1 and f7 == 0x14 then
+ operations.bset(rd,rs1,rs2)
+ elseif f3 == 0x2 and f7 == 0x14 then
+ operations.xperm4(rd,rs1,rs2)
+ elseif f3 == 0x4 and f7 == 0x14 then
+ operations.xperm8(rd,rs1,rs2)
+ elseif f3 == 0x4 and f7 == 0x4 then
+ operations.pack(rd,rs1,rs2)
+ elseif f3 == 0x7 and f7 == 0x4 then
+ operations.packh(rd,rs1,rs2)
+ elseif f3 == 0x5 and f7 == 0x7 then
+ operations.czeroeqz(rd,rs1,rs2)
+ elseif f3 == 0x7 and f7 == 0x7 then
+ operations.czeronez(rd,rs1,rs2)
+ end
+ elseif opcode == 0x13 or opcode == 0x3 or opcode == 0x67 or opcode == 0x73 then
+ --I-type
+ local f3bits = {[0] = bits[12],bits[13],bits[14]}
+ local f3 = implodebits(f3bits,3)
+ local rdbits = {[0] = bits[7],bits[8],bits[9],bits[10],bits[11]}
+ local rd = implodebits(rdbits,5)
+ local rs1bits = {[0] = bits[15],bits[16],bits[17],bits[18],bits[19]}
+ local rs1 = implodebits(rs1bits,5)
+ local immbits = {[0] = bits[20],bits[21],bits[22],bits[23],bits[24],bits[25],bits[26],bits[27],bits[28],bits[29],bits[30],bits[31]}
+ local imm = implodebits(immbits,12)
+ if opcode == 0x13 then
+ if f3 == 0x0 then
+ operations.addi(rd,rs1,imm)
+ elseif f3 == 0x4 then
+ operations.xori(rd,rs1,imm)
+ elseif f3 == 0x6 then
+ operations.ori(rd,rs1,imm)
+ elseif f3 == 0x7 then
+ operations.andi(rd,rs1,imm)
+ elseif f3 == 0x1 and math.floor(imm/0x20) == 0x0 then
+ operations.slli(rd,rs1,imm%0x20)
+ elseif f3 == 0x5 and math.floor(imm/0x20) == 0x0 then
+ operations.srli(rd,rs1,imm%0x20)
+ elseif f3 == 0x5 and math.floor(imm/0x20) == 0x20 then
+ operations.srai(rd,rs1,imm%0x20)
+ elseif f3 == 0x2 then
+ operations.slti(rd,rs1,imm)
+ elseif f3 == 0x3 then
+ operations.sltiu(rd,rs1,imm)
+ elseif f3 == 0x1 and imm == 0x600 then
+ operations.clz(rd,rs1)
+ elseif f3 == 0x1 and imm == 0x601 then
+ operations.ctz(rd,rs1)
+ elseif f3 == 0x1 and imm == 0x602 then
+ operations.cpop(rd,rs1)
+ elseif f3 == 0x1 and imm == 0x604 then
+ operations.sextb(rd,rs1)
+ elseif f3 == 0x1 and imm == 0x605 then
+ operations.sexth(rd,rs1)
+ elseif f3 == 0x5 and math.floor(imm/2^5) == 0x30 then
+ operations.rori(rd,rs1,imm)
+ elseif f3 == 0x5 and imm == 0x287 then
+ operations.orcb(rd,rs1)
+ elseif f3 == 0x5 and imm == 0x698 then
+ operations.rev8(rd,rs1)
+ elseif f3 == 0x1 and math.floor(imm/2^5) == 0x24 then
+ operations.bclri(rd,rs1,imm)
+ elseif f3 == 0x5 and math.floor(imm/2^5) == 0x24 then
+ operations.bexti(rd,rs1,imm)
+ elseif f3 == 0x1 and math.floor(imm/2^5) == 0x34 then
+ operations.binvi(rd,rs1,imm)
+ elseif f3 == 0x1 and math.floor(imm/2^5) == 0x24 then
+ operations.bseti(rd,rs1,imm)
+ elseif f3 == 0x5 and imm == 0x687 then
+ operations.brev8(rd,rs1,imm)
+ elseif f3 == 0x1 and imm == 0x8f then
+ operations.zip(rd,rs1,imm)
+ elseif f3 == 0x5 and imm == 0x8f then
+ operations.unzip(rd,rs1,imm)
+ end
+ elseif opcode == 0x3 then
+ if f3 == 0x0 then
+ operations.lb(rd,rs1,imm)
+ elseif f3 == 0x1 then
+ operations.lh(rd,rs1,imm)
+ elseif f3 == 0x2 then
+ operations.lw(rd,rs1,imm)
+ elseif f3 == 0x3 then
+ operations.ld(rd,rs1,imm)
+ elseif f3 == 0x4 then
+ operations.lbu(rd,rs1,imm)
+ elseif f3 == 0x5 then
+ operations.lhu(rd,rs1,imm)
+ end
+ elseif opcode == 0x67 then
+ if f3 == 0x0 then
+ return operations.jalr(rd,rs1,imm)
+ end
+ elseif opcode == 0x73 then
+ if f3 == 0x0 then
+ if imm == 0x0 then
+ operations.ecall()
+ elseif imm == 0x1 then
+ operations.ebreak()
+ end
+ elseif f3 == 0x1 then
+ operations.csrrw(rd,rs1,imm)
+ elseif f3 == 0x2 then
+ operations.csrrs(rd,rs1,imm)
+ elseif f3 == 0x3 then
+ operations.csrrc(rd,rs1,imm)
+ elseif f3 == 0x5 then
+ operations.csrrwi(rd,rs1,imm)
+ elseif f3 == 0x6 then
+ operations.csrrsi(rd,rs1,imm)
+ elseif f3 == 0x7 then
+ operations.csrrci(rd,rs1,imm)
+ end
+ end
+ elseif opcode == 0x23 then
+ --S-type
+ local f3bits = {[0] = bits[12],bits[13],bits[14]}
+ local f3 = implodebits(f3bits,3)
+ local rs1bits = {[0] = bits[15],bits[16],bits[17],bits[18],bits[19]}
+ local rs1 = implodebits(rs1bits,5)
+ local rs2bits = {[0] = bits[20],bits[21],bits[22],bits[23],bits[24]}
+ local rs2 = implodebits(rs2bits,5)
+ local immbits = {[0] = bits[7],bits[8],bits[9],bits[10],bits[11],bits[25],bits[26],bits[27],bits[28],bits[29],bits[30],bits[31]}
+ local imm = implodebits(immbits,12)
+ if f3 == 0x0 then
+ operations.sb(rs1,rs2,imm)
+ elseif f3 == 0x1 then
+ operations.sh(rs1,rs2,imm)
+ elseif f3 == 0x2 then
+ operations.sw(rs1,rs2,imm)
+ elseif f3 == 0x3 then
+ operations.sd(rs1,rs2,imm)
+ end
+ elseif opcode == 0x63 then
+ --B-type
+ local f3bits = {[0] = bits[12],bits[13],bits[14]}
+ local f3 = implodebits(f3bits,3)
+ local rs1bits = {[0] = bits[15],bits[16],bits[17],bits[18],bits[19]}
+ local rs1 = implodebits(rs1bits,5)
+ local rs2bits = {[0] = bits[20],bits[21],bits[22],bits[23],bits[24]}
+ local rs2 = implodebits(rs2bits,5)
+ local immbits = {[0] = false,bits[8],bits[9],bits[10],bits[11],bits[25],bits[26],bits[27],bits[28],bits[29],bits[30],bits[7],bits[31]}
+ local imm = implodebits(immbits,13)
+ if f3 == 0x0 then
+ return operations.beq(rs1,rs2,imm)
+ elseif f3 == 0x1 then
+ return operations.bne(rs1,rs2,imm)
+ elseif f3 == 0x4 then
+ return operations.blt(rs1,rs2,imm)
+ elseif f3 == 0x5 then
+ return operations.bge(rs1,rs2,imm)
+ elseif f3 == 0x6 then
+ return operations.bltu(rs1,rs2,imm)
+ elseif f3 == 0x7 then
+ return operations.bgeu(rs1,rs2,imm)
+ end
+ elseif opcode == 0x37 or opcode == 0x17 then
+ --U-type
+ local rdbits = {[0] = bits[7],bits[8],bits[9],bits[10],bits[11]}
+ local rd = implodebits(rdbits,5)
+ --Immediate bits in this type actually all line up between the instruction and their actual value(!)
+ --This means it's way easier to just mask out rd/opcode
+ local imm = instruction - (instruction % 0x1000)
+ if opcode == 0x37 then
+ operations.lui(rd,imm)
+ elseif opcode == 0x17 then
+ operations.auipc(rd,imm)
+ end
+ elseif opcode == 0x6f then
+ --J-type
+ local rdbits = {[0] = bits[7],bits[8],bits[9],bits[10],bits[11]}
+ local rd = implodebits(rdbits,5)
+ --Something had to give after how easy the U-type immediates were
+ local immbits = {[0] = false,bits[21],bits[22],bits[23],bits[24],bits[25],bits[26],bits[27],bits[28],bits[29],bits[30],bits[20],bits[12],bits[13],bits[14],bits[15],bits[16],bits[17],bits[18],bits[19],bits[31]}
+ local imm = implodebits(immbits,21)
+ return operations.jal(rd,imm)
+ elseif opcode == 0x2f then
+ --Atomic memory operation
+ local f5 = math.floor(instruction/2^27)
+ local f3 = implodebits({[0] = bits[12],bits[13],bits[14]},3)
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
+ local rs1 = implodebits({[0] = bits[15],bits[16],bits[17],bits[18],bits[19]},5)
+ local rs2 = implodebits({[0] = bits[20],bits[21],bits[22],bits[23],bits[24]},5)
+ --Due to the way the memory model is implemented, aq and rl bits can be ignored
+ if f3 == 2 then
+ if f5 == 2 then
+ --lr.w
+ operations.lr(rd,rs1,rs2)
+ elseif f5 == 3 then
+ --sc.w
+ operations.sc(rd,rs1,rs2)
+ elseif f5 == 1 then
+ --amoswap.w
+ operations.amoswapw(rd,rs1,rs2)
+ elseif f5 == 0 then
+ --amoadd.w
+ operations.amoaddw(rd,rs1,rs2)
+ elseif f5 == 4 then
+ --amoxor.w
+ operations.amoxorw(rd,rs1,rs2)
+ elseif f5 == 12 then
+ --amoand.w
+ operations.amoandw(rd,rs1,rs2)
+ elseif f5 == 8 then
+ --amoor.w
+ operations.amoorw(rd,rs1,rs2)
+ elseif f5 == 16 then
+ --amomin.w
+ operations.amominw(rd,rs1,rs2)
+ elseif f5 == 20 then
+ --amomax.w
+ operations.amomaxw(rd,rs1,rs2)
+ elseif f5 == 24 then
+ --amominu.w
+ operations.amominuw(rd,rs1,rs2)
+ elseif f5 == 28 then
+ --amomaxu.w
+ operations.amomaxuw(rd,rs1,rs2)
+ elseif f5 == 5 then
+ --amocas.w
+ operations.amocasw(rd,rs1,rs2)
+ end
+ elseif f3 == 3 then
+ if f5 == 5 then
+ --amocas.d
+ operations.amocasd(rd,rs1,rs2)
+ end
+ elseif f3 == 0 then
+ if f5 == 1 then
+ --amoswap.b
+ operations.amoswapb(rd,rs1,rs2)
+ elseif f5 == 0 then
+ --amoadd.b
+ operations.amoaddb(rd,rs1,rs2)
+ elseif f5 == 4 then
+ --amoxor.b
+ operations.amoxorb(rd,rs1,rs2)
+ elseif f5 == 12 then
+ --amoamd.b
+ operations.amoandb(rd,rs1,rs2)
+ elseif f5 == 8 then
+ --amoor.b
+ operations.amoorb(rd,rs1,rs2)
+ elseif f5 == 16 then
+ --amomin.b
+ operations.amominb(rd,rs1,rs2)
+ elseif f5 == 20 then
+ --amomax.b
+ operations.amomaxb(rd,rs1,rs2)
+ elseif f5 == 24 then
+ --amominu.b
+ operations.amominub(rd,rs1,rs2)
+ elseif f5 == 28 then
+ --amomaxu.b
+ operations.amomaxub(rd,rs1,rs2)
+ elseif f5 == 5 then
+ --amocas.b
+ operations.amocasb(rd,rs1,rs2)
+ end
+ elseif f3 == 1 then
+ if f5 == 1 then
+ --amoswap.h
+ operations.amoswaph(rd,rs1,rs2)
+ elseif f5 == 0 then
+ --amoadd.h
+ operations.amoaddh(rd,rs1,rs2)
+ elseif f5 == 4 then
+ --amoxor.h
+ operations.amoxorh(rd,rs1,rs2)
+ elseif f5 == 12 then
+ --amoamd.h
+ operations.amoandh(rd,rs1,rs2)
+ elseif f5 == 8 then
+ --amoor.h
+ operations.amoorh(rd,rs1,rs2)
+ elseif f5 == 16 then
+ --amomin.h
+ operations.amominh(rd,rs1,rs2)
+ elseif f5 == 20 then
+ --amomax.h
+ operations.amomaxh(rd,rs1,rs2)
+ elseif f5 == 24 then
+ --amominu.h
+ operations.amominuh(rd,rs1,rs2)
+ elseif f5 == 28 then
+ --amomaxu.h
+ operations.amomaxuh(rd,rs1,rs2)
+ elseif f5 == 5 then
+ --amocas.h
+ operations.amocash(rd,rs1,rs2)
+ end
+ end
+ elseif opcode == 0x0f then
+ --Memory is always consistent on this implementation,
+ --so all fences can just turn into NOPs
+ if instruction == 0x0100000f then
+ --pause
+ return false,true
+ end
+ else
+ mem.running = false
+ digiline_send("monitordisp",string.format("Invalid opcode %02X,\nhalted",opcode))
+ end
+end
+
+local function runcinst(instruction)
+ local bits = explodebits(instruction,16)
+ local opcode = instruction%2^2
+ local f8 = math.floor(instruction/2^8)
+ local f6 = math.floor(f8/2^2)
+ local f4 = math.floor(f6/2^2)
+ local f3 = math.floor(f4/2)
+ if opcode == 2 and f3 == 2 then
+ --c.lwsp (CI)
+ local imm = implodebits({[0] = false,false,bits[4],bits[5],bits[6],bits[12],bits[2],bits[3]},8)
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
+ operations.lw(rd,2,imm)
+ elseif opcode == 2 and f3 == 3 then
+ --c.ldsp
+ local imm = implodebits({[0] = false,false,false,bits[5],bits[6],bits[12],bits[2],bits[3],bits[4]},9)
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
+ operations.ld(rd,2,imm)
+ elseif opcode == 2 and f3 == 6 then
+ --c.swsp (CSS)
+ local imm = implodebits({[0] = false,false,bits[9],bits[10],bits[11],bits[12],bits[7],bits[8]},8)
+ local rs2 = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6]},5)
+ operations.sw(2,rs2,imm)
+ elseif opcode == 2 and f3 == 7 then
+ --c.sdsp
+ local imm = implodebits({[0] = false,false,false,bits[10],bits[11],bits[12],bits[7],bits[8],bits[9]},9)
+ local rs2 = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6]},5)
+ operations.sd(2,rs2,imm)
+ elseif opcode == 0 and f3 == 2 then
+ --c.lw (CL)
+ local imm = implodebits({[0] = false,false,bits[6],bits[10],bits[11],bits[12],bits[5]},7)
+ local rd = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ operations.lw(rd,rs1,imm)
+ elseif opcode == 0 and f3 == 3 then
+ --c.ld
+ local imm = implodebits({[0] = false,false,false,bits[6],bits[10],bits[11],bits[12],bits[5]},8)
+ local rd = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ operations.ld(rd,rs1,imm)
+ elseif opcode == 0 and f3 == 6 then
+ --c.sw (CS)
+ local imm = implodebits({[0] = false,false,bits[6],bits[10],bits[11],bits[12],bits[5]},7)
+ local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ operations.sw(rs1,rs2,imm)
+ elseif opcode == 0 and f3 == 7 then
+ --c.sd
+ local imm = implodebits({[0] = false,false,false,bits[6],bits[10],bits[11],bits[12],bits[5]},8)
+ local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ operations.sd(rs1,rs2,imm)
+ elseif opcode == 1 and f3 == 5 then
+ --c.j (CJ)
+ local immbits = {[0] = false,bits[3],bits[4],bits[5],bits[11],bits[2],bits[7],bits[6],bits[9],bits[10],bits[8],bits[12]}
+ signextend(immbits,12,21)
+ local offset = implodebits(immbits,21)
+ return operations.jal(0,offset,true)
+ elseif opcode == 1 and f3 == 1 then
+ --c.jal (CJ)
+ local immbits = {[0] = false,bits[3],bits[4],bits[5],bits[11],bits[2],bits[7],bits[6],bits[9],bits[10],bits[8],bits[12]}
+ signextend(immbits,12,21)
+ local offset = implodebits(immbits,21)
+ return operations.jal(1,offset,true)
+ elseif opcode == 2 and f4 == 8 and math.floor(instruction/2^2)%2^5 == 0 then
+ --c.jr (CR)
+ local rs1 = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
+ return operations.jalr(0,rs1,0,true)
+ elseif opcode == 2 and f4 == 9 then
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
+ local rs1 = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
+ local rs2 = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6]},5)
+ if rd == 0 and rs2 == 0 then
+ --c.ebreak (CR)
+ operations.ebreak()
+ elseif rs2 == 0 then
+ --c.jalr (CR)
+ return operations.jalr(1,rs1,0,true)
+ else
+ --c.add (CR)
+ operations.add(rd,rd,rs2)
+ end
+ elseif opcode == 1 and f3 == 6 then
+ --c.beqz (CB)
+ local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ local imm = implodebits({[0] = false,bits[3],bits[4],bits[10],bits[11],bits[2],bits[5],bits[6],bits[12]},9,true)
+ return operations.beq(rs1,0,imm)
+ elseif opcode == 1 and f3 == 7 then
+ --c.bnez (CB)
+ local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ local imm = implodebits({[0] = false,bits[3],bits[4],bits[10],bits[11],bits[2],bits[5],bits[6],bits[12]},9,true)
+ if imm >= 2^8 then imm = imm - 2^9 end
+ return operations.bne(rs1,0,imm)
+ elseif opcode == 1 and f3 == 2 then
+ local imm = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]},6,true)
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
+ if imm >= 2^5 then imm = imm - 2^6 end
+ --c.li (CI)
+ operations.addi(rd,0,imm)
+ elseif opcode == 1 and f3 == 3 then
+ local immbits = {[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]}
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
+ if rd == 2 then
+ --c.addi16sp (CI)
+ --For whatever reason this has a completely different immediate format than c.lui
+ imm = implodebits({[0] = false,false,false,false,bits[6],bits[2],bits[5],bits[3],bits[4],bits[12]},10,true)
+ operations.addi(2,2,imm)
+ else
+ --c.lui (CI)
+ signextend(immbits,6,20)
+ local imm = implodebits(immbits,20)
+ imm = imm*2^12
+ operations.lui(rd,imm)
+ end
+ elseif opcode == 1 and f3 == 0 then
+ --c.addi (CI)
+ local imm = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]},6,true)
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
+ operations.addi(rd,rd,imm)
+ elseif opcode == 0 and f3 == 0 and instruction ~= 0 then
+ --c.addi4spn (CIW)
+ local imm = implodebits({[0] = false,false,bits[6],bits[5],bits[11],bits[12],bits[7],bits[8],bits[9],bits[10]},10)
+ local rd = (math.floor(instruction/2^2)%2^3)+8
+ operations.addi(rd,2,imm)
+ elseif opcode == 2 and f3 == 0 then
+ --c.slli (CI)
+ local imm = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]},6)
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
+ operations.slli(rd,rd,imm)
+ elseif opcode == 1 and f6 == 0x20 then
+ --c.srli (CB)
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ local imm = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]},6)
+ operations.srli(rd,rd,imm)
+ elseif opcode == 1 and f6 == 0x21 then
+ --c.srai (CB)
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ local imm = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]},6)
+ operations.srai(rd,rd,imm)
+ elseif opcode == 1 and (f6 == 0x22 or f6 == 0x26) then
+ --c.andi (CB)
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ local immbits = {[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[12]}
+ signextend(immbits,6,12)
+ local imm = implodebits(immbits,12)
+ operations.andi(rd,rd,imm)
+ elseif opcode == 2 and f4 == 8 then
+ --c.mv (CR)
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9],bits[10],bits[11]},5)
+ local rs2 = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6]},5)
+ operations.add(rd,0,rs2)
+ elseif opcode == 1 and f6 == 0x23 and bits[5] and bits[6] then
+ --c.and (CS)
+ local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ operations.andr(rd,rd,rs2)
+ elseif opcode == 1 and f6 == 0x23 and bits[6] and not bits[5] then
+ --c.or (CS)
+ local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ operations.orr(rd,rd,rs2)
+ elseif opcode == 1 and f6 == 0x23 and bits[5] and not bits[6] then
+ --c.xor (CS)
+ local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ operations.xor(rd,rd,rs2)
+ elseif opcode == 1 and f6 == 0x23 and not (bits[5] or bits[6]) then
+ --c.sub (CS)
+ local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ operations.sub(rd,rd,rs2)
+ elseif opcode == 0 and f6 == 0x20 then
+ --c.lbu
+ local rd = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ local imm = implodebits({[0] = bits[6],bits[5]},2)
+ operations.lbu(rd,rs1,imm)
+ elseif opcode == 0 and f6 == 0x21 and not bits[6] then
+ --c.lhu
+ local rd = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ local imm = implodebits({[0] = bits[5],bits[6]},2)
+ operations.lhu(rd,rs1,imm)
+ elseif opcode == 0 and f6 == 0x21 and bits[6] then
+ --c.lh
+ local rd = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ local imm = implodebits({[0] = false,bits[5]},2)
+ operations.lh(rd,rs1,imm)
+ elseif opcode == 0 and f6 == 0x22 then
+ --c.sb
+ local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ local imm = implodebits({[0] = bits[6],bits[5]},2)
+ operations.sb(rs1,rs2,imm)
+ elseif opcode == 0 and f6 == 0x23 and not bits[6] then
+ --c.sh
+ local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ local rs1 = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ local imm = implodebits({[0] = false,bits[5]},2)
+ operations.sh(rs1,rs2,imm)
+ elseif opcode == 1 and f6 == 0x27 and bits[5] and bits[6] and not (bits[2] or bits[3] or bits[4]) then
+ --c.zext.b
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ operations.andi(rd,rd,0xff)
+ elseif opcode == 1 and f6 == 0x27 and bits[5] and bits[6] and bits[2] and not (bits[3] or bits[4]) then
+ --c.sext.b
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ operations.sextb(rd,rd)
+ elseif opcode == 1 and f6 == 0x27 and bits[5] and bits[6] and bits[3] and not (bits[2] or bits[4]) then
+ --c.zext.h
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ operations.zexth(rd,rd)
+ elseif opcode == 1 and f6 == 0x27 and bits[5] and bits[6] and bits[2] and bits[3] and not bits[4] then
+ --c.sext.h
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ operations.sexth(rd,rd)
+ elseif opcode == 1 and f6 == 0x27 and bits[5] and bits[6] and bits[2] and bits[4] and not bits[3] then
+ --c.not
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ operations.xori(rd,rd,0xffffffff)
+ elseif opcode == 1 and f6 == 0x27 and bits[6] and not bits[5] then
+ --c.mul
+ local rd = implodebits({[0] = bits[7],bits[8],bits[9]},3)+8
+ local rs2 = implodebits({[0] = bits[2],bits[3],bits[4]},3)+8
+ operations.mul(rd,rd,rs2)
+ elseif opcode == 2 and f8 == 0xb8 then
+ --cm.push
+ --This one decodes into possibly a whole bunch of instructions
+ local rlist = cmpushpopreglists[implodebits({[0] = bits[4],bits[5],bits[6],bits[7]},4)]
+ if not rlist then return end
+ stack = implodebits({[0] = bits[2],bits[3]},2) * 16 + rlist.stack
+ for i,reg in ipairs(rlist.registers) do
+ operations.sw(2,reg,-4*i)
+ end
+ operations.addi(2,2,-1 * stack)
+ elseif opcode == 2 and f8 == 0xba then
+ --cm.pop
+ --This one decodes into possibly a whole bunch of instructions
+ local rlist = cmpushpopreglists[implodebits({[0] = bits[4],bits[5],bits[6],bits[7]},4)]
+ if not rlist then return end
+ stack = implodebits({[0] = bits[2],bits[3]},2) * 16 + rlist.stack
+ operations.addi(2,2,stack)
+ for i,reg in ipairs(rlist.registers) do
+ operations.lw(reg,2,-4*i)
+ end
+ elseif opcode == 2 and f8 == 0xbc then
+ --cm.popretz
+ --This one decodes into a whole bunch of instructions
+ local rlist = cmpushpopreglists[implodebits({[0] = bits[4],bits[5],bits[6],bits[7]},4)]
+ if not rlist then return end
+ local stack = implodebits({[0] = bits[2],bits[3]},2) * 16 + rlist.stack
+ operations.addi(2,2,stack)
+ for i,reg in ipairs(rlist.registers) do
+ operations.lw(reg,2,-4*i)
+ end
+ operations.addi(10,0,0)
+ return operations.jalr(0,1,0)
+ --more like CISC-V amirite?
+ elseif opcode == 2 and f8 == 0xbe then
+ --cm.popret
+ --This one decodes into a whole bunch of instructions
+ local rlist = cmpushpopreglists[implodebits({[0] = bits[4],bits[5],bits[6],bits[7]},4)]
+ if not rlist then return end
+ local stack = implodebits({[0] = bits[2],bits[3]},2) * 16 + rlist.stack
+ operations.addi(2,2,stack)
+ for i,reg in ipairs(rlist.registers) do
+ operations.lw(reg,2,-4*i)
+ end
+ return operations.jalr(0,1,0)
+ elseif opcode == 2 and f6 == 0x2b and bits[5] and not bits[6] then
+ --cm.mvsa01
+ --This one decodes into multiple instructions
+ local sreg = {[0] = 8,9,18,19,20,21,22,23}
+ local r1 = sreg[implodebits({[0] = bits[7],bits[8],bits[9]},3)]
+ local r2 = sreg[implodebits({[0] = bits[2],bits[3],bits[4]},3)]
+ operations.addi(r1,10,0)
+ operations.addi(r2,11,0)
+ elseif opcode == 2 and f6 == 0x2b and bits[5] and bits[6] then
+ --cm.mva01s
+ --This one decodes into multiple instructions
+ local sreg = {[0] = 8,9,18,19,20,21,22,23}
+ local r1 = sreg[implodebits({[0] = bits[7],bits[8],bits[9]},3)]
+ local r2 = sreg[implodebits({[0] = bits[2],bits[3],bits[4]},3)]
+ operations.addi(10,r1,0)
+ operations.addi(11,r2,0)
+ elseif opcode == 2 and f6 == 0x28 then
+ local index = implodebits({[0] = bits[2],bits[3],bits[4],bits[5],bits[6],bits[7],bits[8],bits[9]},8)
+ if index < 32 then
+ --cm.jt
+ local address = readcsr(0x17) --jvt
+ address = address + 4*index
+ local target = readram(address,4)
+ mem.registers.pc = target
+ return true
+ else
+ --cm.jalt
+ local address = readcsr(0x17) --jvt
+ address = address + 4*index
+ local target = readram(address,4)
+ setreg(1,mem.registers.pc+2)
+ mem.registers.pc = target
+ return true
+ end
+ else
+ mem.running = false
+ digiline_send("monitordisp","Invalid compressed\ninstruction, halted")
+ end
+end
+
+local function run(limit)
+ --0xc00 = CYCLE
+ --0xc80 = CYCLEH
+ mem.csr[0xc00] = mem.csr[0xc00] + 1
+ if mem.csr[0xc00] >= 2^32 then
+ mem.csr[0xc80] = mem.csr[0xc80] + math.floor(mem.csr[0xc00]/2^32)
+ mem.csr[0xc00] = mem.csr[0xc00]%2^32
+ end
+
+ --0xc01 = TIME
+ --0xc81 = TIMEH
+ local timediff = os.time()-mem.starttime
+ mem.csr[0xc01] = timediff%2^32
+ mem.csr[0xc81] = math.floor(timediff/2^32)
+
+ local first = true
+ repeat
+ if mem.registers.pc == mem.breakpoint and not first then
+ digiline_send("monitordisp","Hit breakpoint")
+ mem.running = false
+ break
+ end
+ first = false
+ local instruction = readram(mem.registers.pc,4)
+ if instruction%4 == 3 then
+ local jumped,stop = runinst(instruction)
+ if not jumped then mem.registers.pc = (mem.registers.pc + 4) % 2^32 end
+ if stop then break end
+ else
+ local jumped,stop = runcinst(instruction%2^16)
+ if not jumped then mem.registers.pc = (mem.registers.pc + 2) % 2^32 end
+ if stop then break end
+ end
+
+ --0xc02 = INSTRET
+ --0xc82 = INSTRETH
+ mem.csr[0xc02] = mem.csr[0xc02] + 1
+ if mem.csr[0xc02] >= 2^32 then
+ mem.csr[0xc82] = mem.csr[0xc82] + math.floor(mem.csr[0xc02]/2^32)
+ mem.csr[0xc02] = mem.csr[0xc02]%2^32
+ end
+ limit = limit - 1
+ until (not mem.running) or limit <= 0
+end
+
+local regaliases = {
+ zero = 0,
+ ra = 1,
+ sp = 2,
+ gp = 3,
+ tp = 4,
+ t0 = 5,
+ t1 = 6,
+ t2 = 7,
+ fp = 8,
+ s0 = 8,
+ s1 = 9,
+ a0 = 10,
+ a1 = 11,
+ a2 = 12,
+ a3 = 13,
+ a4 = 14,
+ a5 = 15,
+ a6 = 16,
+ a7 = 17,
+ s2 = 18,
+ s3 = 19,
+ s4 = 20,
+ s5 = 21,
+ s6 = 22,
+ s7 = 23,
+ s8 = 24,
+ s9 = 25,
+ s10 = 26,
+ s11 = 27,
+ t3 = 28,
+ t4 = 29,
+ t5 = 30,
+ t6 = 31,
+}
+
+if event.type == "program" or event.iid == "reset" then
+ mem.ram = {}
+ for i=0,(RAM_SIZE/256)-1 do
+ mem.ram[i] = string.rep(string.char(0),256)
+ end
+ mem.registers = {}
+ for i=0,31 do mem.registers[i] = 0 end
+ mem.registers.pc = 0
+ mem.running = false
+ mem.inputwaiting = false
+ mem.stdout = {}
+ mem.starttime = os.time()
+ mem.csr = {
+ [0x017] = 0, --jvt
+ [0xf11] = 0, --mvendorid
+ [0xf12] = 0x6f435652, --marchid ("RVCo")
+ [0xf13] = 0, --mimpid
+ [0xf14] = 0, --mhartid
+ [0x300] = 0, --mstatus
+ [0x301] = 0x40001107, --misa (RV32IMACB)
+ [0x310] = 0, --mstatush
+ [0x800] = 0, --Lightweight Mode
+ [0xc00] = 0, --CYCLE
+ [0xc01] = 0, --TIME
+ [0xc02] = 0, --INSTRET
+ [0xc80] = 0, --CYCLEH
+ [0xc81] = 0, --TIMEH
+ [0xc82] = 0, --INSTRETH
+ }
+ for i=1,6 do mem.stdout[i] = "" end
+ local mdisp = event.type == "program" and "\nReset: Cold" or "\nReset: Warm"
+ digiline_send("monitordisp",mdisp.."\n\nRVController Monitor\n\nType 'help' for help\nReady\n")
+ digiline_send("stdout","\n\n\n\n\n\n\n")
+ mem.inputbuf = ""
+ mem.digilinesqueue = {}
+ mem.breakpoint = -1
+ mem.hexloading = false
+ mem.reservationset = nil
+elseif event.channel == "reset" then
+ mem.running = false
+ digiline_send("monitordisp","\n\n\n\n\n\n\n")
+ digiline_send("stdout","\n\n\n\n\n\n\n")
+ interrupt(0.5,"reset")
+elseif event.channel == "monitorkb" then
+ digiline_send("monitordisp","> "..event.msg)
+ local function validateandclamp(value,min,max,base)
+ base = base or 16
+ value = tonumber(value or "",base)
+ if (not value) or value < min or value > max or value ~= math.floor(value) then
+ return
+ end
+ return value
+ end
+ local argv = {}
+ while true do
+ local spacepos = string.find(event.msg," ",nil,true) or string.len(event.msg)+1
+ table.insert(argv,string.sub(event.msg,1,spacepos-1))
+ event.msg = string.sub(event.msg,spacepos+1,-1)
+ if event.msg == "" then break end
+ end
+ local argc = #argv
+ if argv[1] == "peek" then
+ local address = validateandclamp(argv[2],0,RAM_SIZE-1)
+ if not address then
+ digiline_send("monitordisp","Bad address")
+ return
+ end
+ local data = readram(address,1)
+ digiline_send("monitordisp",string.format("%08X:%02X",address,data))
+ elseif argv[1] == "peekw" then
+ local address = validateandclamp(argv[2],0,RAM_SIZE-1)
+ if not address then
+ digiline_send("monitordisp","Bad address")
+ return
+ end
+ local data = readram(address,4)
+ digiline_send("monitordisp",string.format("%08X:%08X",address,data))
+ elseif argv[1] == "poke" then
+ local address = validateandclamp(argv[2],0,RAM_SIZE-1)
+ if not address then
+ digiline_send("monitordisp","Bad address")
+ return
+ end
+ local data = validateandclamp(argv[3],0,0xff)
+ if not data then
+ digiline_send("monitordisp","Bad data")
+ return
+ end
+ writeram(address,data,1)
+ digiline_send("monitordisp",string.format("%08X:%02X",address,data))
+ elseif argv[1] == "pokew" then
+ local address = validateandclamp(argv[2],0,RAM_SIZE-1)
+ if not address then
+ digiline_send("monitordisp","Bad address")
+ return
+ end
+ local data = validateandclamp(argv[3],0,0xffffffff)
+ if not data then
+ digiline_send("monitordisp","Bad data")
+ return
+ end
+ writeram(address,data,4)
+ digiline_send("monitordisp",string.format("%08X:%08X",address,data))
+ elseif argv[1] == "setreg" then
+ argv[2] = regaliases[argv[2]] or argv[2]
+ local reg = validateandclamp(argv[2],0,0x1f,10)
+ if not reg then
+ digiline_send("monitordisp","Bad register")
+ return
+ end
+ local data = validateandclamp(argv[3],0,0xffffffff)
+ if not data then
+ digiline_send("monitordisp","Bad data")
+ return
+ end
+ setreg(reg,data)
+ digiline_send("monitordisp",string.format("x%02d:%08X",reg,data))
+ elseif argv[1] == "getreg" then
+ argv[2] = regaliases[argv[2]] or argv[2]
+ local reg = validateandclamp(argv[2],0,0x1f,10)
+ if not reg then
+ digiline_send("monitordisp","Bad register")
+ return
+ end
+ local data = getreg(reg)
+ digiline_send("monitordisp",string.format("x%02d:%08X",reg,data))
+ elseif argv[1] == "getpc" then
+ digiline_send("monitordisp",string.format("PC:%08X",mem.registers.pc))
+ elseif argv[1] == "setpc" then
+ local address = validateandclamp(argv[2],0,0xffffffff)
+ if not address then
+ digiline_send("monitordisp","Bad address")
+ return
+ end
+ mem.registers.pc = address
+ digiline_send("monitordisp",string.format("PC:%08X",address))
+ elseif argv[1] == "reset" then
+ mem.running = false
+ digiline_send("monitordisp","\n\n\n\n\n\n\n")
+ digiline_send("stdout","\n\n\n\n\n\n\n")
+ interrupt(0.5,"reset")
+ elseif argv[1] == "step" then
+ run(1)
+ digiline_send("monitordisp",string.format("PC:%08X",mem.registers.pc))
+ elseif argv[1] == "run" then
+ mem.starttime = os.time()
+ mem.running = true
+ digiline_send("monitordisp","CPU started\n\n")
+ run(50)
+ interrupt(0.1,"tick")
+ elseif argv[1] == "stop" then
+ mem.running = false
+ mem.inputwaiting = false
+ digiline_send("monitordisp","Stopped by user")
+ elseif argv[1] == "h" then
+ --Easter egg
+ digiline_send("monitordisp","h")
+ elseif argv[1] == "setbreak" then
+ local address = validateandclamp(argv[2],0,RAM_SIZE-1)
+ if not address then
+ digiline_send("monitordisp","Bad address")
+ return
+ end
+ mem.breakpoint = address
+ elseif argv[1] == "clearbreak" then
+ mem.breakpoint = -1
+ elseif argv[1] == "help" then
+ if argc == 1 or argv[2] == "1" then
+ digiline_send("monitordisp","Use: help <command>")
+ digiline_send("monitordisp","Commands:\npoke pokew peek\npeekw setreg getreg\ngetpc setpc step run\n'help 2' for page 2")
+ elseif argv[2] == "poke" then
+ digiline_send("monitordisp","poke <addr> <data>\nWrites the specified\nbyte (8 bits) to\nmemory at the\nspecified address")
+ elseif argv[2] == "pokew" then
+ digiline_send("monitordisp","pokew <addr> <data>\nWrites the specified\nword (32 bits) to\nmemory at the\nspecified address")
+ elseif argv[2] == "peek" then
+ digiline_send("monitordisp","peek <address>\nReads the byte (8\nbits) value from\nmemory at the\nspecified address")
+ elseif argv[2] == "peekw" then
+ digiline_send("monitordisp","peekw <address>\nReads the word (32\nbits) value from\nmemory at the\nspecified address")
+ elseif argv[2] == "setreg" then
+ digiline_send("monitordisp","setreg <reg> <data>\nWrites the specified\nword (32 bits) data\nto the specified\nregister")
+ elseif argv[2] == "getreg" then
+ digiline_send("monitordisp","getreg <register>\nReads the word (32\nbits) data from the\nspecified register")
+ elseif argv[2] == "getpc" then
+ digiline_send("monitordisp","getpc\nReads the current\nvalue of the program\ncounter")
+ elseif argv[2] == "setpc" then
+ digiline_send("monitordisp","setpc <value>\nWrites the specified\nvalue into the\nprogram counter")
+ elseif argv[2] == "step" then
+ digiline_send("monitordisp","step\nAllows the CPU to\nrun one instruction,\nthen halts")
+ elseif argv[2] == "run" then
+ digiline_send("monitordisp","run\nAllows the CPU to\nrun indefinitely")
+ elseif argv[2] == "stop" then
+ digiline_send("monitordisp","stop\nHalts the CPU")
+ elseif argv[2] == "reset" then
+ digiline_send("monitordisp","reset\nStops the CPU and\nclears RAM and all\nregisters")
+ elseif argv[2] == "help" then
+ digiline_send("monitordisp","help [command]\nShows information\nabout the specified\ncommand, or a list\nof commands if none\nis supplied")
+ elseif argv[2] == "2" then
+ digiline_send("monitordisp","Page 2\nreset stop help\nsetbreak clearbreak")
+ elseif argv[2] == "h" then
+ digiline_send("monitordisp","h\nhhhhhhhhhh")
+ elseif argv[2] == "setbreak" then
+ digiline_send("monitordisp","setbreak <address>\nSets a breakpoint\nat the specified\naddress")
+ elseif argv[2] == "clearbreak" then
+ digiline_send("monitordisp","clearbreak\nClears any set\nbreakpoint")
+ else
+ digiline_send("monitordisp","No such command or\nno help available")
+ end
+ else
+ digiline_send("monitordisp","Unknown command")
+ end
+elseif event.channel == "stdin" then
+ if mem.inputwaiting then
+ --Blocking read in progress
+ if mem.inputwaittype == "string" then
+ event.msg = string.sub(event.msg,1,mem.inputmax-1)..string.char(0)
+ for i=1,string.len(event.msg) do
+ writeram(mem.inputaddr+i-1,string.byte(string.sub(event.msg,i,i)),1)
+ end
+ mem.inputwaiting = false
+ mem.running = true
+ digiline_send("monitordisp","CPU started")
+ run(INSTRUCTIONS_PER_CLOCK)
+ interrupt(1/CLOCK_SPEED,"tick")
+ elseif mem.inputwaittype == "integer" and tonumber(event.msg) then
+ event.msg = math.floor(event.msg)
+ if event.msg >= 2^32 then event.msg = 2^32-1 end
+ if event.msg < -1*(2^31) then event.msg = -1*(2^31) end
+ if event.msg < 0 then event.msg = event.msg + 2^32 end
+ setreg(10,event.msg)
+ mem.inputwaiting = false
+ mem.running = true
+ digiline_send("monitordisp","CPU started")
+ run(INSTRUCTIONS_PER_CLOCK)
+ interrupt(1/CLOCK_SPEED,"tick")
+ elseif mem.inputwaittype == "char" then
+ event.msg = string.sub(event.msg,1,1)
+ if event.msg == "" then event.msg = string.char(0) end
+ setreg(10,string.byte(event.msg))
+ mem.inputwaiting = false
+ mem.running = true
+ digiline_send("monitordisp","CPU started")
+ run(INSTRUCTIONS_PER_CLOCK)
+ interrupt(1/CLOCK_SPEED,"tick")
+ end
+ else
+ --No blocking read in progress, buffer the data for nonblocking reads later
+ mem.inputbuf = string.sub(mem.inputbuf..event.msg,1,256)
+ end
+elseif event.channel == "load" then
+ if event.msg.done then
+ mem.hexloading = false
+ digiline_send("monitordisp","Load complete\n")
+ if event.msg.autorun then
+ mem.running = true
+ digiline_send("monitordisp","CPU started\n")
+ run(INSTRUCTIONS_PER_CLOCK)
+ interrupt(1/CLOCK_SPEED,"tick")
+ end
+ else
+ if not mem.hexloading then
+ if mem.running then digiline_send("monitordisp","System halted\n") end
+ mem.running = false
+ mem.hexloading = true
+ digiline_send("monitordisp","Loading Intel\nHEX data")
+ digiline_send("stdout","\n\n\n\n\n\n\n")
+ mem.registers.pc = 0
+ end
+ local address = event.msg.address
+ local data = event.msg.data
+ local size = event.msg.size
+ digiline_send("monitordisp",string.format("%08X\n",address))
+ for i=0,size-1 do
+ local thisdata = tonumber(string.sub(data,i*2+1,i*2+2),16)
+ local thisaddress = address + i
+ writeram(thisaddress,thisdata,1)
+ end
+ end
+elseif event.type == "digiline" then
+ --Unrecognized digilines signals get forwarded on to the program
+ event.channel = string.sub(event.channel,1,256)
+ event.msg = string.sub(tostring(event.msg),1,256)
+ if #mem.digilinesqueue < 16 then
+ table.insert(mem.digilinesqueue,{channel = event.channel, msg = event.msg})
+ end
+ if mem.csr[0x800]%2 == 1 then
+ interrupt(0,"tick")
+ end
+elseif event.iid == "tick" and mem.running then
+ run(INSTRUCTIONS_PER_CLOCK)
+ if mem.csr[0x800]%2 == 1 then
+ interrupt(1,"tick",true)
+ else
+ interrupt(1/CLOCK_SPEED,"tick")
+ end
+end
+
+if stdoutdirty then
+ local text = table.concat(mem.stdout,"\n")
+ digiline_send("stdout",text.."\n")
+ stdoutdirty = false
+end