diff --git a/.gitignore b/.gitignore index bd69889e..8aa6909a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ compile_commands.json .ccls-cache +.cache elfy/.ccls-cache rvc !rvc/ diff --git a/Makefile b/Makefile index 82e38a9a..06d1de1c 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,8 @@ SRC_DIRS ?= ./src ./tinypngout CC=clang +BUILDROOT := "buildroot-2022.02.1" + SRCS := $(shell find $(SRC_DIRS) -name '*.cpp' -or -name '*.c' -or -name '*.s') OBJS := $(addsuffix .o,$(basename $(SRCS))) DEPS := $(OBJS:.o=.d) @@ -10,12 +12,18 @@ DEPS := $(OBJS:.o=.d) INC_DIRS := $(shell find $(SRC_DIRS) -type d) INC_FLAGS := $(addprefix -I,$(INC_DIRS)) -Q=$(CURDIR)/buildroot-2021.05/output/host/bin/riscv32-buildroot-linux-gnu- +Q=$(CURDIR)/$(BUILDROOT)/output/host/bin/riscv32-buildroot-linux-gnu- CFLAGS ?= -g -O2 -$(TARGET): $(OBJS) - $(CC) $(LDFLAGS) -I./elfy/elfy.h -I./tinypngout/TinyPngOut.h $(OBJS) -o $@ $(LOADLIBES) $(LDLIBS) -L./elfy/target/release/ -Wl,--no-as-needed -ldl -lpthread -lelfy +.PHONY: $(TARGET) +$(TARGET): + touch src/main.c + rm -f src/main.o + $(MAKE) $(TARGET)-real + +$(TARGET)-real: $(OBJS) + $(CC) $(LDFLAGS) -I./elfy/elfy.h -I./tinypngout/TinyPngOut.h $(OBJS) -o $(TARGET) $(LOADLIBES) $(LDLIBS) -L./elfy/target/release/ -Wl,--no-as-needed -ldl -lpthread -lelfy -lm -include $(DEPS) @@ -28,11 +36,9 @@ PAYLOAD=rust_payload/target/riscv32ima-unknown-none-elf/release/rust_payload.bin LINUX_PAYLOAD=linux/arch/riscv/boot/Image RAYTRACE_PAYLOAD=rust_raytrace/target/riscv32ima-unknown-none-elf/release/rust_raytrace.bin -BUILDROOT_MARKER=buildroot-2021.05/build.marker +BUILDROOT_MARKER=$(BUILDROOT)/build.marker $(BUILDROOT_MARKER): - $(MAKE) -C buildroot-2021.05 - cd buildroot-2021.05 && cp init output/target/ && cp pi.js output/target/ - $(MAKE) -C buildroot-2021.05 + if [ ! -f $(BUILDROOT_MARKER) ]; then $(MAKE) -C $(BUILDROOT); fi touch $@ $(PAYLOAD): $(shell find rust_payload/src -type f) @@ -66,7 +72,7 @@ rust_payload.elf: $(PAYLOAD) $(BUILDROOT_MARKER) .PHONY: $(LINUX_PAYLOAD) $(LINUX_PAYLOAD): linux $(BUILDROOT_MARKER) - cd linux && (git am ../linux-_pi_-patches-for-rvc.patch || true) + # cd linux && (git apply ../linux-_pi_-patches-for-rvc.patch || true) cd linux && \ env CROSS_COMPILE=$(Q) \ CFLAGS="-march=rv32ima -mabi=ilp32" \ @@ -74,12 +80,14 @@ $(LINUX_PAYLOAD): linux $(BUILDROOT_MARKER) ARCH=riscv \ KCONFIG_ALLCONFIG=../linux.config \ make allnoconfig + cd linux && ./scripts/clang-tools/gen_compile_commands.py cd linux && \ env CROSS_COMPILE=$(Q) \ CFLAGS="-march=rv32ima -mabi=ilp32" \ LDFLAGS="-march=rv32ima -mabi=ilp32" \ ARCH=riscv \ - intercept-build make -j$(shell nproc) + make -j$(shell nproc) + cd linux && ./scripts/clang-tools/gen_compile_commands.py linux_payload.bin: linux_payload.elf cp $(OPENSBI_BUILD)/fw_payload.bin ./linux_payload.bin @@ -99,9 +107,17 @@ linux_payload.elf: $(LINUX_PAYLOAD) $(BUILDROOT_MARKER) run: fw_payload.bin $(TARGET) dts.dtb ./rvc -b fw_payload.bin -d dts.dtb +.PHONY: run-v1 run-v1: fw_payload.bin $(TARGET) dts.dtb ./rvc -b fw_payload.bin -d dts.dtb -v1 +.PHONY: run-network +run-network: linux_payload.bin $(TARGET) dts.dtb + tmux new -s rvc-network -d "./rvc -b linux_payload.bin -d dts.dtb -n /tmp/rvc-test.sock -i ./$(BUILDROOT)/output/images/rootfs.romfs -f" + tmux split-window -t rvc-network "./rvc -b linux_payload.bin -d dts.dtb -N /tmp/rvc-test.sock -i ./$(BUILDROOT)/output/images/rootfs.romfs -f" + tmux select-layout -t rvc-network even-horizontal + tmux attach -t rvc-network + tmux kill-session -t rvc-network || true .PHONY: clean clean: diff --git a/bare_metal_test/Makefile b/bare_metal_test/Makefile index 35966e11..f02cac92 100644 --- a/bare_metal_test/Makefile +++ b/bare_metal_test/Makefile @@ -5,7 +5,7 @@ PREFIX ?= ../buildroot-2021.05/output/host/bin/riscv32-buildroot-linux-gnu- CC := $(PREFIX)cc AS := $(PREFIX)as LD := $(PREFIX)ld -OBJDUMP := $(PREFIX)objcopy +OBJCOPY := $(PREFIX)objcopy SRCS := $(wildcard *.S) SRCS += $(wildcard *.c) @@ -23,7 +23,7 @@ $(TARGET): $(OBJS) $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LOADLIBES) $(LDLIBS) $(TARGET).img: $(TARGET) - riscv32-elf-objcopy -O binary $< $@ + $(OBJCOPY) -O binary $< $@ .PHONY: clean clean: diff --git a/bare_metal_test/bare b/bare_metal_test/bare index 7008f504..f0dbb592 100755 Binary files a/bare_metal_test/bare and b/bare_metal_test/bare differ diff --git a/bare_metal_test/bare.a.png b/bare_metal_test/bare.a.png new file mode 100644 index 00000000..0d10189e Binary files /dev/null and b/bare_metal_test/bare.a.png differ diff --git a/bare_metal_test/bare.b.png b/bare_metal_test/bare.b.png new file mode 100644 index 00000000..453a6566 Binary files /dev/null and b/bare_metal_test/bare.b.png differ diff --git a/bare_metal_test/bare.c b/bare_metal_test/bare.c index 5adea961..61df1e2a 100644 --- a/bare_metal_test/bare.c +++ b/bare_metal_test/bare.c @@ -101,6 +101,20 @@ int main(void) { print("\n"); } + print("[bare] testing memory writeback...\n"); + volatile unsigned int *ptr = (unsigned int*)0x80010000; + *ptr = 0xccddeeff; + __asm volatile("fence.i"); + unsigned int readback = *ptr; + if (readback != 0xccddeeff) { + print("[bare/writeback] test failed! expected=0xccddeeff got=0x"); + print_hex(readback); + print("\n"); + __asm volatile ("ebreak"); + while (true) {} + } + print("[bare/writeback] success!\n"); + print("[bare] testing trap handler...\n"); __asm volatile("csrw sip, 0x2"); diff --git a/bare_metal_test/bare.g.png b/bare_metal_test/bare.g.png new file mode 100644 index 00000000..e4292143 Binary files /dev/null and b/bare_metal_test/bare.g.png differ diff --git a/bare_metal_test/bare.r.png b/bare_metal_test/bare.r.png new file mode 100644 index 00000000..0cd6e27e Binary files /dev/null and b/bare_metal_test/bare.r.png differ diff --git a/bare_metal_test/riscv32.ld b/bare_metal_test/riscv32.ld index f609fa32..86908f8c 100644 --- a/bare_metal_test/riscv32.ld +++ b/bare_metal_test/riscv32.ld @@ -1,6 +1,6 @@ MEMORY { - RAM : ORIGIN = 0x80000000, LENGTH = 31M + RAM : ORIGIN = 0x80000000, LENGTH = 60M } _estack = ORIGIN(RAM) + LENGTH(RAM); diff --git a/dts.a.png b/dts.a.png new file mode 100644 index 00000000..046b4cbc Binary files /dev/null and b/dts.a.png differ diff --git a/dts.b.png b/dts.b.png new file mode 100644 index 00000000..7683cb70 Binary files /dev/null and b/dts.b.png differ diff --git a/dts.dts b/dts.dts index 348cdc44..bc442cf8 100644 --- a/dts.dts +++ b/dts.dts @@ -6,23 +6,38 @@ compatible = "riscv-virtio"; model = "generic,rvc"; - chosen { - bootargs = "console=hvc0 earlycon=sbi loglevel=15 debug single"; - //stdout-path = "/uart@10000000"; + aliases { + serial0 = &uart0; }; - uart@10000000 { - interrupts = <0x1>; - interrupt-parent = <&irqchip>; + chosen { + bootargs = "root=mtd:root rootfstype=romfs ro init=/rvcinit phram.phram=root,0x40000000,256Mi console=hvc0 earlycon=sbi"; + stdout-path = "/uart@10000000"; + }; + + uart0: uart@10000000 { + /* interrupts = <0x9>; */ + /* interrupt-parent = <&irqchip>; */ clock-frequency = <0x384000>; reg = <0x0 0x10000000 0x0 0x100>; compatible = "ns16550a"; }; + rtc@3000000 { + compatible = "maxim,ds1742"; + reg = <0x0 0x3000000 0x0 0x800>; + }; + + rvcnet { + compatible = "pi,rvcnet"; + }; + cpus { #address-cells = <0x1>; #size-cells = <0x0>; - timebase-frequency = <0x1000000>; + + /* 100/20 kHz, must match frequency in emu.h */ + timebase-frequency = <0x1388>; cpu-map { cluster0 { @@ -51,7 +66,7 @@ memory@80000000 { device_type = "memory"; - reg = <0x0 0x80000000 0x0 0x03B00000>; /* includes safety margin at end? */ + reg = <0x0 0x80000000 0x0 0x07B00000>; /* includes safety margin at end? */ }; soc { diff --git a/dts.g.png b/dts.g.png new file mode 100644 index 00000000..b74942ad Binary files /dev/null and b/dts.g.png differ diff --git a/dts.r.png b/dts.r.png new file mode 100644 index 00000000..e47baae2 Binary files /dev/null and b/dts.r.png differ diff --git a/guest-root/examples/pi.js b/guest-root/examples/pi.js new file mode 100644 index 00000000..2a655835 --- /dev/null +++ b/guest-root/examples/pi.js @@ -0,0 +1,119 @@ +/* + * PI computation in Javascript using the BigInt type + * from: https://bellard.org/quickjs/pi.html + */ +"use strict"; + +/* return floor(log2(a)) for a > 0 and 0 for a = 0 */ +function floor_log2(a) +{ + var k_max, a1, k, i; + k_max = 0n; + while ((a >> (2n ** k_max)) != 0n) { + k_max++; + } + k = 0n; + a1 = a; + for(i = k_max - 1n; i >= 0n; i--) { + a1 = a >> (2n ** i); + if (a1 != 0n) { + a = a1; + k |= (1n << i); + } + } + return k; +} + +/* return ceil(log2(a)) for a > 0 */ +function ceil_log2(a) +{ + return floor_log2(a - 1n) + 1n; +} + +/* return floor(sqrt(a)) (not efficient but simple) */ +function int_sqrt(a) +{ + var l, u, s; + if (a == 0n) + return a; + l = ceil_log2(a); + u = 1n << ((l + 1n) / 2n); + /* u >= floor(sqrt(a)) */ + for(;;) { + s = u; + u = ((a / s) + s) / 2n; + if (u >= s) + break; + } + return s; +} + +/* return pi * 2**prec */ +function calc_pi(prec) { + const CHUD_A = 13591409n; + const CHUD_B = 545140134n; + const CHUD_C = 640320n; + const CHUD_C3 = 10939058860032000n; /* C^3/24 */ + const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */ + + /* return [P, Q, G] */ + function chud_bs(a, b, need_G) { + var c, P, Q, G, P1, Q1, G1, P2, Q2, G2; + if (a == (b - 1n)) { + G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n); + P = G * (CHUD_B * b + CHUD_A); + if (b & 1n) + P = -P; + Q = b * b * b * CHUD_C3; + } else { + c = (a + b) >> 1n; + [P1, Q1, G1] = chud_bs(a, c, true); + [P2, Q2, G2] = chud_bs(c, b, need_G); + P = P1 * Q2 + P2 * G1; + Q = Q1 * Q2; + if (need_G) + G = G1 * G2; + else + G = 0n; + } + return [P, Q, G]; + } + + var n, P, Q, G; + /* number of serie terms */ + n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n; + [P, Q, G] = chud_bs(0n, n, false); + Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A); + G = int_sqrt(CHUD_C << (2n * prec)); + return (Q * G) >> prec; +} + +function main(args) { + var r, n_digits, n_bits, out; + if (args.length < 1) { + print("usage: pi n_digits"); + return; + } + n_digits = args[0] | 0; + + /* we add more bits to reduce the probability of bad rounding for + the last digits */ + n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n; + r = calc_pi(n_bits); + r = ((10n ** BigInt(n_digits)) * r) >> n_bits; + out = r.toString(); + print(out[0] + "." + out.slice(1)); +} + +var args; +if (typeof scriptArgs != "undefined") { + args = scriptArgs; + args.shift(); +} else if (typeof arguments != "undefined") { + args = arguments; +} else { + /* default: 1000 digits */ + args=[1000]; +} + +main(args); diff --git a/guest-root/install.sh b/guest-root/install.sh new file mode 100755 index 00000000..207f1584 --- /dev/null +++ b/guest-root/install.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +BUILDROOT="buildroot-2022.02.1" + +set -e + +# target directory +Q=$1 + +# enter current directory +cd ../guest-root + +for f in *; do + if [ "$f" == "install.sh" ]; then continue; fi + cp -r -v "$f" "$Q" +done + +mkdir -p "$Q/tmp/work" +mkdir -p "$Q/tmp/upper" +mkdir -p "$Q/tmp/newroot" + +# install beluga +cd ../riscv32_beluga +sed -i 's|$(CC) -o $S/ecgen|$(HOSTCC) -o $S/ecgen|' bcc/Makefile +make clean +make -j1 CC=$PWD/../$BUILDROOT/output/host/bin/riscv32-buildroot-linux-gnu-gcc HOSTCC=gcc +cd .. +mkdir -p $BUILDROOT/output/target/usr/local/bin +cp riscv32_beluga/build/{bcc,beluga} $BUILDROOT/output/target/usr/local/bin +# ln -s libc.so.6 $(BUILDROOT)/output/target/lib32/libc.so || true +# ln -s libm.so.6 $(BUILDROOT)/output/target/lib32/libm.so || true +# cp riscv32_beluga/riscvbin/bin/{as,ld,ar,dof} $(BUILDROOT)/output/target/usr/local/bin +mkdir -p $BUILDROOT/output/target/usr/local/lib32/bcc +cp riscv32_beluga/build/xfloat.o $BUILDROOT/output/target/usr/local/lib32/bcc/ +cp -Lr riscv32_beluga/build/include $BUILDROOT/output/target/usr/local/lib32/bcc/ +cp riscv32_beluga/riscvbin/ar/libc.a $BUILDROOT/output/target/usr/local/lib32/ +cp $BUILDROOT/output/host/lib/gcc/riscv32-buildroot-linux-gnu/11.2.0/libgcc.a $BUILDROOT/output/target/usr/local/lib32/ +cp $BUILDROOT/output/host/lib/gcc/riscv32-buildroot-linux-gnu/11.2.0/libgcc_eh.a $BUILDROOT/output/target/usr/local/lib32/ + diff --git a/guest-root/network-setup.sh b/guest-root/network-setup.sh new file mode 100755 index 00000000..631cc172 --- /dev/null +++ b/guest-root/network-setup.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +echo "Configuring network..." + +# Start loopback interface, it will auto-assign 127.0.0.1/8 as IP +ip link set up lo + +PLID=$(cat /sys/kernel/rvc/player_id) +echo "Player ID: $PLID" +PLID=$(( (PLID + 1) % 255 )) +echo "Network ID: $PLID" + +# Configure rvcnet for external networking +ip link set dev rvcnet up +ip addr add "10.0.0.$PLID/24" dev rvcnet + +echo "Network state:" +ip addr show diff --git a/guest-root/rvcinit b/guest-root/rvcinit new file mode 100755 index 00000000..c10a696c --- /dev/null +++ b/guest-root/rvcinit @@ -0,0 +1,44 @@ +#!/bin/sh + +if [ "$1" != "chroot" ]; then + echo + echo "> Welcome to userland!" + echo "> Setting up overlay mount for writeable root" + mount -t tmpfs tmpfs /tmp + mkdir /tmp/upper + mkdir /tmp/work + mkdir /tmp/newroot + mount -t overlay overlay \ + -o lowerdir=/,upperdir=/tmp/upper,workdir=/tmp/work /tmp/newroot + mount --bind /dev /tmp/newroot/dev + chroot /tmp/newroot /rvcinit chroot +else + echo "> Entered overlay chroot, mounting /proc & /sys" + mount -t proc proc /proc + mount -t sysfs sys /sys + + echo "> Startup took: $(cut -d' ' -f0 < +|_| \_/ \___| |_|_|_| |_|\__,_/_/\_\ + + + by _pi_ + +EOF + + echo "> Starting login shell on TTY /dev/hvc0" + + export PATH="$PATH:/usr/local/bin" + + while true; do + # use getty to start a shell in a new tty + getty -l /bin/sh -n 0 /dev/hvc0 + echo "> Restarting login shell" + done +fi diff --git a/linux b/linux index f4e0f631..0bd94b14 160000 --- a/linux +++ b/linux @@ -1 +1 @@ -Subproject commit f4e0f631965ce23bca273bdcc7c1637bc9993365 +Subproject commit 0bd94b14f8b6b838bbd48e5c204e819df621e659 diff --git a/linux-_pi_-patches-for-rvc.patch b/linux-_pi_-patches-for-rvc.patch deleted file mode 100644 index a940012a..00000000 --- a/linux-_pi_-patches-for-rvc.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 30022eebb78abc5a8a9289aecbd30a155fafcff0 Mon Sep 17 00:00:00 2001 -From: Stefan -Date: Sun, 1 Aug 2021 20:58:20 +0200 -Subject: [PATCH] _pi_ patches for rvc - -* use MEMOP extension for faster memcpy -* don't poison init kernel area, we don't care about security -* print more messages about initramfs loading, since otherwise it just - looks like it got stuck - -Signed-off-by: Stefan ---- - arch/riscv/lib/memcpy.S | 14 ++++++++++++++ - include/linux/mm.h | 2 +- - init/initramfs.c | 19 +++++++++++++++++-- - 3 files changed, 32 insertions(+), 3 deletions(-) - -diff --git a/arch/riscv/lib/memcpy.S b/arch/riscv/lib/memcpy.S -index 51ab716253fa..67e3cf24d9d0 100644 ---- a/arch/riscv/lib/memcpy.S -+++ b/arch/riscv/lib/memcpy.S -@@ -41,6 +41,19 @@ WEAK(memcpy) - beqz a4, 4f - add a3, a1, a4 - 3: -+ # fast memcpy for page-sized chunks -+ lla t0, 10f -+ li t2, 4096 -+ bne a2, t2, 11f -+ -+ csrw 0x0b1, a1 # src -+ csrw 0x0b2, t6 # dst -+ csrw 0x0b3, a2 # n -+ li t2, 0x1 -+ csrw 0x0b0, t2 # memcpy -+ j 10f -+ -+11: - REG_L a4, 0(a1) - REG_L a5, SZREG(a1) - REG_L a6, 2*SZREG(a1) -@@ -76,6 +89,7 @@ WEAK(memcpy) - REG_S t1, 15*SZREG(t6) - addi t6, t6, 16*SZREG - bltu a1, a3, 3b -+10: - andi a2, a2, (16*SZREG)-1 /* Update count */ - - 4: -diff --git a/include/linux/mm.h b/include/linux/mm.h -index 9afb8998e7e5..881f1c1cf7ea 100644 ---- a/include/linux/mm.h -+++ b/include/linux/mm.h -@@ -2420,7 +2420,7 @@ static inline unsigned long free_initmem_default(int poison) - extern char __init_begin[], __init_end[]; - - return free_reserved_area(&__init_begin, &__init_end, -- poison, "unused kernel"); -+ 0x1ff, "unused kernel"); - } - - static inline unsigned long get_num_physpages(void) -diff --git a/init/initramfs.c b/init/initramfs.c -index af27abc59643..1124f0cf6c8f 100644 ---- a/init/initramfs.c -+++ b/init/initramfs.c -@@ -43,8 +43,10 @@ static ssize_t __init xwrite(struct file *file, const char *p, size_t count, - static __initdata char *message; - static void __init error(char *x) - { -- if (!message) -+ if (!message) { - message = x; -+ pr_err("[_pi_] initramfs error: %s\n", x); -+ } - } - - static void panic_show_mem(const char *fmt, ...) -@@ -467,6 +469,9 @@ static char * __init unpack_to_rootfs(char *buf, unsigned long len) - const char *compress_name; - static __initdata char msg_buf[64]; - -+ unsigned long len_orig = len; -+ unsigned long len_percent = 0, len_percent_tmp; -+ - header_buf = kmalloc(110, GFP_KERNEL); - symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL); - name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL); -@@ -474,11 +479,20 @@ static char * __init unpack_to_rootfs(char *buf, unsigned long len) - if (!header_buf || !symlink_buf || !name_buf) - panic_show_mem("can't allocate buffers"); - -+ pr_info("[_pi_] loading initramfs now, this may take a while...\n"); -+ - state = Start; - this_header = 0; - message = NULL; - while (!message && len) { - loff_t saved_offset = this_header; -+ -+ len_percent_tmp = (len * 10) / len_orig; -+ if (len_percent_tmp != len_percent) { -+ len_percent = len_percent_tmp; -+ pr_info("[_pi_] initramfs: %lu0%% done\n", 10 - len_percent); -+ } -+ - if (*buf == '0' && !(this_header & 3)) { - state = Start; - written = write_buffer(buf, len); -@@ -494,7 +508,7 @@ static char * __init unpack_to_rootfs(char *buf, unsigned long len) - } - this_header = 0; - decompress = decompress_method(buf, len, &compress_name); -- pr_debug("Detected %s compressed data\n", compress_name); -+ pr_info("Detected %s compressed data\n", compress_name); - if (decompress) { - int res = decompress(buf, len, NULL, flush_buffer, NULL, - &my_inptr, error); -@@ -519,6 +533,7 @@ static char * __init unpack_to_rootfs(char *buf, unsigned long len) - kfree(name_buf); - kfree(symlink_buf); - kfree(header_buf); -+ pr_info("[_pi_] unpack_to_rootfs retval: %s\n", (message && *message) ? message : ""); - return message; - } - --- -2.32.0 - diff --git a/linux.config b/linux.config index e742ce5a..ab1a2c90 100644 --- a/linux.config +++ b/linux.config @@ -17,10 +17,11 @@ CONFIG_INITRAMFS_COMPRESSION_LZ4=n CONFIG_INITRAMFS_COMPRESSION_ZSTD=n CONFIG_INITRAMFS_COMPRESSION_NONE=y -CONFIG_INITRAMFS_SOURCE="../buildroot-2021.05/output/images/rootfs.cpio" +# CONFIG_INITRAMFS_SOURCE="../buildroot-2021.05/output/images/rootfs.cpio" -CONFIG_BLK_DEV=y -CONFIG_BLK_DEV_INITRD=y +CONFIG_BLOCK=n +CONFIG_BLK_DEV=n +CONFIG_BLK_DEV_INITRD=n CONFIG_DEBUG=y CONFIG_DEBUG_KERNEL=y @@ -57,18 +58,22 @@ CONFIG_TTY=y CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_VT_HW_CONSOLE_BINDING=y -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_CORE=n +CONFIG_SERIAL_CORE_CONSOLE=n CONFIG_SERIAL_8250=n CONFIG_SERIAL_8250_CONSOLE=n -CONFIG_SERIAL_OF_PLATFORM=y -CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250_16550A_VARIANTS=n +CONFIG_SERIAL_EARLYCON=n CONFIG_CONSOLE_POLL=n CONFIG_UNIX98_PTYS=n CONFIG_LEGACY_PTYS=n CONFIG_RISCV_TIMER=y CONFIG_PREEMPT_NONE=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HZ_20=y +CONFIG_HZ=20 CONFIG_DTC=y CONFIG_OF=y @@ -78,6 +83,11 @@ CONFIG_OF_KOBJ=y CONFIG_OF_ADDRESS=y CONFIG_OF_IRQ=y CONFIG_OF_RESERVED_MEM=y +CONFIG_OF_SERIAL=y +CONFIG_SERIAL_OF_PLATFORM=y + +CONFIG_MTD=y +CONFIG_MTD_PHRAM=y CONFIG_RAMFS=y CONFIG_TMPFS=y @@ -85,19 +95,20 @@ CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_PROC_FS=y CONFIG_SYSFS=y -CONFIG_EXPORTFS=n + +CONFIG_MISC_FILESYSTEMS=y +CONFIG_ROMFS_FS=y +CONFIG_ROMFS_BACKED_BY_MTD=y +CONFIG_ROMFS_BACKED_BY_BLOCK=n +CONFIG_OVERLAY_FS=y CONFIG_MSDOS_PARTITION=n CONFIG_EFI_PARTITION=n CONFIG_FW_LOADER=n CONFIG_SCSI_MOD=n -CONFIG_BLK_DEV_BSG=n CONFIG_MQ_IOSCHED_KYBER=n CONFIG_MQ_IOSCHED_DEADLINE=n CONFIG_IO_WQ=n -CONFIG_SERIAL_8250_16550A_VARIANTS=n -CONFIG_SERIAL_8250_NR_UARTS=1 -CONFIG_SERIAL_8250_RUNTIME_UARTS=1 CONFIG_VGA_CONSOLE=n CONFIG_HID=n CONFIG_USB_SUPPORT=n @@ -112,3 +123,17 @@ CONFIG_USB=n CONFIG_HAVE_SYSCALL_TRACEPOINTS=n CONFIG_TRACING_SUPPORT=n CONFIG_FTRACE=n + +CONFIG_NET=y +CONFIG_NET_CORE=y +CONFIG_NETDEVICES=y +CONFIG_PACKET=y +CONFIG_NETLINK_DIAG=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_RVCNET=y + +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_DRV_DS1742=y diff --git a/linux_payload.a.png b/linux_payload.a.png new file mode 100644 index 00000000..85ac46d1 Binary files /dev/null and b/linux_payload.a.png differ diff --git a/linux_payload.b.png b/linux_payload.b.png new file mode 100644 index 00000000..e5b695d5 Binary files /dev/null and b/linux_payload.b.png differ diff --git a/linux_payload.g.png b/linux_payload.g.png new file mode 100644 index 00000000..f51ca880 Binary files /dev/null and b/linux_payload.g.png differ diff --git a/linux_payload.r.png b/linux_payload.r.png new file mode 100644 index 00000000..52ef630c Binary files /dev/null and b/linux_payload.r.png differ diff --git a/riscv-rust b/riscv-rust index b4895fc5..8ee69d7a 160000 --- a/riscv-rust +++ b/riscv-rust @@ -1 +1 @@ -Subproject commit b4895fc56b16815d622b088d188ac65d640d25ab +Subproject commit 8ee69d7a5dc7ef6d8b2bda96bf86d2923f2cf176 diff --git a/rust_raytrace.a.bmp.png b/rust_raytrace.a.bmp.png new file mode 100644 index 00000000..af97813a Binary files /dev/null and b/rust_raytrace.a.bmp.png differ diff --git a/rust_raytrace.b.bmp.png b/rust_raytrace.b.bmp.png new file mode 100644 index 00000000..c761c42b Binary files /dev/null and b/rust_raytrace.b.bmp.png differ diff --git a/rust_raytrace.g.bmp.png b/rust_raytrace.g.bmp.png new file mode 100644 index 00000000..1485d845 Binary files /dev/null and b/rust_raytrace.g.bmp.png differ diff --git a/rust_raytrace.r.bmp.png b/rust_raytrace.r.bmp.png new file mode 100644 index 00000000..87f72a92 Binary files /dev/null and b/rust_raytrace.r.bmp.png differ diff --git a/rust_raytrace/linker.ld b/rust_raytrace/linker.ld index 15a9060e..5f9cd063 100644 --- a/rust_raytrace/linker.ld +++ b/rust_raytrace/linker.ld @@ -4,7 +4,7 @@ ENTRY( _start ) MEMORY { - ram (rwx) : ORIGIN = 0x80000000, LENGTH = 0x80000 + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 0x100000 } SECTIONS @@ -17,14 +17,18 @@ SECTIONS } > ram .stack (NOLOAD) : { - . = . + 0x20000; + . = . + 0x70000; PROVIDE(_end_stack = .); } > ram .heap (NOLOAD) : { - PROVIDE(_begin_heap = .); - . = . + 0x40000; + . = . + 0x70000; PROVIDE(_end_heap = .); } > ram + .textbuf (NOLOAD) : { + . = . + 0x10000; + PROVIDE(_end_textbuf = .); + } > ram + } diff --git a/rust_raytrace/src/fb.rs b/rust_raytrace/src/fb.rs new file mode 100644 index 00000000..1fc40599 --- /dev/null +++ b/rust_raytrace/src/fb.rs @@ -0,0 +1,36 @@ +use super::math::Color; + +const RAM_BASE: u32 = 0x80000000; +const FB_START: u32 = 0x80000; +pub const FB_WIDTH: u32 = 2048; +pub const FB_HEIGHT: u32 = 2048 - 32 /* progmem */ - 128 /* CPU state */; +pub const FB_HEIGHT_SLICE: u32 = 224; // FB_HEIGHT / 8 + +#[inline(always)] +/// accelerated "big" pixel drawing, superscale is size of pixel, forces stall +pub unsafe fn write_px_memop(x: u32, y: u32, col: Color, superscale: u32) { + let bits: u32 = col.r * 0xffffff; + asm!("csrrw x0, {1}, {0}", in(reg) bits, const 0x0b3); // CSR_MEMOP_R + let bits: u32 = col.g * 0xffffff; + asm!("csrrw x0, {1}, {0}", in(reg) bits, const 0x0b4); // CSR_MEMOP_G + let bits: u32 = col.b * 0xffffff; + asm!("csrrw x0, {1}, {0}", in(reg) bits, const 0x0b5); // CSR_MEMOP_B + + let bits: u32 = x | (y << 16); + asm!("csrrw x0, {1}, {0}", in(reg) bits, const 0x0b1); // CSR_MEMOP_SRC + let bits: u32 = (x + superscale) | ((y + superscale) << 16); + asm!("csrrw x0, {1}, {0}", in(reg) bits, const 0x0b2); // CSR_MEMOP_DST + + let bits: u32 = 1; + asm!("csrrw x0, {1}, {0}", in(reg) bits, const 0x0b0); // CSR_MEMOP_OP +} + +#[inline(always)] +/// write a single pixel, unaccelerated, uses main memory but doesn't stall +pub fn write_px_raw(x: u32, y: u32, col: u128) { + unsafe { + let ptr = (FB_START + RAM_BASE) as *mut u128; + let ptr = ptr.add((x + y * FB_WIDTH) as usize); + ptr.write(col); + } +} diff --git a/rust_raytrace/src/low_level/mod.rs b/rust_raytrace/src/low_level/mod.rs index 8488ce60..97ca0aec 100644 --- a/rust_raytrace/src/low_level/mod.rs +++ b/rust_raytrace/src/low_level/mod.rs @@ -1,8 +1,8 @@ use core::panic::PanicInfo; use linked_list_allocator::LockedHeap; +use super::output::*; -mod uart; -pub use uart::*; +pub mod uart; #[naked] #[no_mangle] @@ -13,7 +13,11 @@ extern "C" fn _start() -> ! { unsafe { asm!( " + csrr t0, 0xf14 la sp, {end_stack} + li t2, 4096 + mul t1, t0, t2 + sub sp, sp, t1 j main ", end_stack = sym _end_stack, @@ -31,6 +35,7 @@ fn alloc_error(_layout: core::alloc::Layout) -> ! { #[panic_handler] fn panic(_info: &PanicInfo) -> ! { println("PANIC!"); + unsafe { asm! { "ebreak" } } loop {} } @@ -41,22 +46,31 @@ extern "C" { static _end_heap: usize; } +// not actually safe between harts, but shouldn't be used so ignore? #[global_allocator] static ALLOCATOR: LockedHeap = LockedHeap::empty(); +#[inline(always)] +pub fn hartid() -> usize { + let hartid: usize; + unsafe { asm!("csrrs {0}, {1}, x0", out(reg) hartid, const 0xf14); } + return hartid; +} + pub unsafe fn init_heap() { let stack_end = &_end_stack as *const usize as usize; - let heap_start = &_begin_heap as *const usize as usize; + let heap_start = stack_end + hartid() * 4096; let heap_end = &_end_heap as *const usize as usize; + let heap_end = heap_end.min(heap_start + 4096); let heap_size = heap_end - heap_start; - print("> stack_end: "); + print("> stack_end(sym): "); print_usize(stack_end); - print("\n> heap_start: "); + print("\n> heap_start: "); print_usize(heap_start); - print("\n> heap_end: "); + print("\n> heap_end: "); print_usize(heap_end); - print("\n> heap_size: "); + print("\n> heap_size: "); print_usize(heap_size); print("\n"); diff --git a/rust_raytrace/src/low_level/uart.rs b/rust_raytrace/src/low_level/uart.rs index f37211df..c3cf63cd 100644 --- a/rust_raytrace/src/low_level/uart.rs +++ b/rust_raytrace/src/low_level/uart.rs @@ -6,46 +6,3 @@ pub fn print_char(ch: u8) { thr.write_volatile(ch); } } - -pub fn println(s: &str) { - print(s); - print_char('\n' as u8); -} - -pub fn print(s: &str) { - s.chars().for_each(|c| print_char(c as u8)); -} - -#[inline(always)] -fn print_hex_part(u: u8) { - match u { - 0 => print("0"), - 1 => print("1"), - 2 => print("2"), - 3 => print("3"), - 4 => print("4"), - 5 => print("5"), - 6 => print("6"), - 7 => print("7"), - 8 => print("8"), - 9 => print("9"), - 10 => print("a"), - 11 => print("b"), - 12 => print("c"), - 13 => print("d"), - 14 => print("e"), - 15 => print("f"), - _ => unreachable!(), - } -} - -pub fn print_usize(u: usize) { - print("0x"); - for i in 0..=3 { - let part = ((u >> ((3 - i) * 8)) & 0xff) as u8; - let l = part & 0xF; - let h = (part >> 4) & 0xF; - print_hex_part(h); - print_hex_part(l); - } -} diff --git a/rust_raytrace/src/main.rs b/rust_raytrace/src/main.rs index b0562cd9..fce0f661 100644 --- a/rust_raytrace/src/main.rs +++ b/rust_raytrace/src/main.rs @@ -10,30 +10,42 @@ extern crate alloc; mod low_level; use low_level::*; +mod output; +use output::*; + mod raytrace; use raytrace::*; mod math; use math::*; -const RAM_BASE: u32 = 0x80000000; -const FB_START: u32 = 0x80000; -const FB_WIDTH: u32 = 2048; -const FB_HEIGHT: u32 = 2048 - 16 /* progmem */ - 128 /* CPU state */; -// const AA_BORDER: u32 = 10; +mod fb; +use fb::*; -static mut SUPERSCALE: u32 = 96; // start at 48 -pub fn superscale() -> u32 { - unsafe { SUPERSCALE } -} +mod text; +use text::*; + +// const AA_BORDER: u32 = 10; +const SUPERSCALE: u32 = 112; #[no_mangle] pub fn main() -> ! { + print("hartid (core) = "); + print_usize(hartid()); + println(""); + println("Initializing heap..."); unsafe { init_heap(); } + if hartid() == 7 { + println("Starting text rendering loop..."); + println("\nThis core is responsible for printing all the\ntext you see here, while the other 7 are\nrunning the raytracing algorithm."); + println("\nThe image will gradually gain more resolution,\nand if you let it run, it will eventually be\npixel perfect!"); + render_text(); + } + println("Setting up scene..."); let mut scene = Scene::new(); @@ -132,25 +144,30 @@ pub fn main() -> ! { intensity: 0.07, }); - while superscale() > 1 { - unsafe { SUPERSCALE /= 2 }; + let mut superscale = SUPERSCALE; + let starty = FB_HEIGHT_SLICE * hartid() as u32; + + while superscale > 1 { + superscale /= 2; print("Tracing @"); - print_usize(superscale() as usize); + print_usize(superscale as usize); print(" "); - for y in (0..(FB_HEIGHT / superscale())).rev() { - for x in 0..(FB_WIDTH / superscale()) { + let sy = starty/superscale; + for y in sy..(FB_HEIGHT_SLICE / superscale + sy) { + for x in 0..(FB_WIDTH / superscale) { // Testpattern: - // let col = Vector3::new( - // if (x % 2) == 0 { 255 } else { 0 }, - // ((y * 255) / (FB_HEIGHT / superscale())) as i32, - // if (y % 2) == 0 { 255 } else { 0 }, - // ); + // let col = Color { + // r: if (x % 2) == 0 { 255 } else { 0 }, + // g: (y * 255) / (FB_HEIGHT / superscale), + // b: if (y % 2) == 0 { 255 } else { 0 }, + // }; let col = scene.raytrace( - x as i32 - (FB_WIDTH / superscale() / 2) as i32, - y as i32 - (FB_HEIGHT / superscale() / 2) as i32, + x as i32 - (FB_WIDTH / superscale / 2) as i32, + y as i32 - ((FB_HEIGHT - FB_HEIGHT_SLICE) / superscale / 2) as i32, + superscale, ); - write_px(x, y, col); + write_px(x, y, col, superscale); } print("."); @@ -158,7 +175,7 @@ pub fn main() -> ! { // print(" Done!\nAnti-Aliasing"); - // for y in 0..(FB_HEIGHT / superscale()) { + // for y in 0..(FB_HEIGHTxxx / superscale()) { // for x in 0..(FB_WIDTH / superscale()) { // // tap neighboring pixels and mix into borders // let cur = read_px_raw(x * superscale() + superscale() / 2, y * superscale() + superscale() / 2); @@ -205,26 +222,24 @@ pub fn main() -> ! { loop {} } -fn write_px(x: u32, y: u32, col: Color) { - let col = col.to_u128(); - let x = x * superscale(); - let y = y * superscale(); +fn write_px(x: u32, y: u32, col: Color, superscale: u32) { + let x = x * superscale; + let y = y * superscale; - for ys in 0..superscale() { - for xs in 0..superscale() { + if superscale > 7 { + unsafe { write_px_memop(x, y+32, col, superscale); } + return; + } + + let col = col.to_u128(); + + for ys in 0..superscale { + for xs in 0..superscale { write_px_raw(x + xs, y + ys, col); } } } -fn write_px_raw(x: u32, y: u32, col: u128) { - unsafe { - let ptr = (FB_START | RAM_BASE) as *mut u128; - let ptr = ptr.add((x + y * FB_WIDTH) as usize); - ptr.write(col); - } -} - // fn read_px_raw(x: u32, y: u32) -> Color { // let col: u128; // unsafe { diff --git a/rust_raytrace/src/output.rs b/rust_raytrace/src/output.rs new file mode 100644 index 00000000..27bbde1c --- /dev/null +++ b/rust_raytrace/src/output.rs @@ -0,0 +1,44 @@ +use super::text::print_char; + +pub fn println(s: &str) { + print(s); + print_char('\n' as u8); +} + +pub fn print(s: &str) { + s.chars().for_each(|c| print_char(c as u8)); +} + +#[inline(always)] +fn print_hex_part(u: u8) { + match u { + 0 => print("0"), + 1 => print("1"), + 2 => print("2"), + 3 => print("3"), + 4 => print("4"), + 5 => print("5"), + 6 => print("6"), + 7 => print("7"), + 8 => print("8"), + 9 => print("9"), + 10 => print("a"), + 11 => print("b"), + 12 => print("c"), + 13 => print("d"), + 14 => print("e"), + 15 => print("f"), + _ => unreachable!(), + } +} + +pub fn print_usize(u: usize) { + print("0x"); + for i in 0..=3 { + let part = ((u >> ((3 - i) * 8)) & 0xff) as u8; + let l = part & 0xF; + let h = (part >> 4) & 0xF; + print_hex_part(h); + print_hex_part(l); + } +} diff --git a/rust_raytrace/src/raytrace.rs b/rust_raytrace/src/raytrace.rs index ad91b64c..7ef1a3ec 100644 --- a/rust_raytrace/src/raytrace.rs +++ b/rust_raytrace/src/raytrace.rs @@ -172,17 +172,17 @@ impl Scene { self.lights.push(light); } - fn view_vector(x: i32, y: i32) -> Vector3 { + fn view_vector(x: i32, y: i32, superscale: u32) -> Vector3 { Vector3::new( x as f32, y as f32, - (crate::FB_WIDTH / crate::superscale() / 2) as f32, + (crate::FB_WIDTH / superscale / 2) as f32, ) .normalized() } - pub fn raytrace(&self, x: i32, y: i32) -> Color { - let view = Self::view_vector(x, y); + pub fn raytrace(&self, x: i32, y: i32, superscale: u32) -> Color { + let view = Self::view_vector(x, y, superscale); self.do_raytrace( &Vector3::ZERO, &view, diff --git a/rust_raytrace/src/text.rs b/rust_raytrace/src/text.rs new file mode 100644 index 00000000..b4ffc88f --- /dev/null +++ b/rust_raytrace/src/text.rs @@ -0,0 +1,238 @@ +use super::fb::*; +use super::low_level::hartid; +use super::math::Color; + +const BITMAP_FONT: [(u32, u32); 96] = [ + (0, 0), // 0 32 ' ' + (4472896, 4472896), // 1 33 '!' // 0100 0100 0100 0000 0100 0000 0100 0100 0100 0000 0100 0000 + (11141120, 11141120), // 2 34 '"' // 1010 1010 0000 0000 0000 0000 1010 1010 0000 0000 0000 0000 + (11447968, 11447968), // 3 35 '#' // 1010 1110 1010 1110 1010 0000 1010 1110 1010 1110 1010 0000 + (5162720, 5162724), // 4 36 '$' // 0100 1110 1100 0110 1110 0000 0100 1110 1100 0110 1110 0100 + (0, 0), // 5 37 '%' // NOT WRITTEN + (4868704, 15395552), // 6 38 '&' // 0100 1010 0100 1010 0110 0000 1110 1010 1110 1010 1110 0000 + (4456448, 4456448), // 7 39 ''' // 0100 0100 0000 0000 0000 0000 1110 1010 1110 1010 1110 0000 + (2376736, 6571104), // 8 40 '(' // 0010 0100 0100 0100 0010 0000 0110 0100 0100 0100 0110 0000 + (8668288, 12862656), // 9 41 ')' // 1000 0100 0100 0100 1000 0000 1100 0100 0100 0100 1100 0000 + (674304, 978432), // 10 42 '*' // 0000 1010 0100 1010 0000 0000 0000 1110 1110 1110 0000 0000 + (320512, 320512), // 11 43 '+' // 0000 0100 1110 0100 0000 0000 0000 0100 1110 0100 0000 0000 + (1088, 1228), // 12 44 ',' // 0000 0000 0000 0100 0100 0000 0000 0000 0000 0100 1100 1100 + (57344, 57344), // 13 45 '-' // 0000 0000 1110 0000 0000 0000 0000 0000 1110 0000 0000 0000 + (64, 64), // 14 46 '.' // 0000 0000 0000 0000 0100 0000 0000 0000 0000 0000 0100 0000 + (2246784, 2287744), // 15 47 '/' // 0010 0010 0100 1000 1000 0000 0010 0010 1110 1000 1000 0000 + (6990528, 15379168), // 16 48 '0' // 0110 1010 1010 1010 1100 0000 1110 1010 1010 1010 1110 0000 + (4998368, 4998368), // 17 49 '1' // 0100 1100 0100 0100 1110 0000 0100 1100 0100 0100 1110 0000 + (14870752, 14870752), // 18 50 '2' // 1110 0010 1110 1000 1110 0000 1110 0010 1110 1000 1110 0000 + (14828256, 14836448), // 19 51 '3' // 1110 0010 0100 0010 1110 0000 1110 0010 0110 0010 1110 0000 + (9101856, 9101856), // 20 52 '4' // 1000 1010 1110 0010 0010 0000 1000 1010 1110 0010 0010 0000 + (15262432, 15262432), // 21 53 '5' // 1110 1000 1110 0010 1110 0000 1110 1000 1110 0010 1110 0000 + (6875872, 15264480), // 22 54 '6' // 0110 1000 1110 1010 1110 0000 1110 1000 1110 1010 1110 0000 + (14829120, 14836800), // 23 55 '7' // 1110 0010 0100 0110 0100 0000 1110 0010 0110 0100 0100 0000 + (15395552, 15395552), // 24 56 '8' // 1110 1010 1110 1010 1110 0000 1110 1010 1110 1010 1110 0000 + (15393472, 15393504), // 25 57 '9' // 1110 1010 1110 0010 1100 0000 1110 1010 1110 0010 1110 0000 + (263168, 263168), // 26 58 ':' // 0000 0100 0000 0100 0000 0000 0000 0100 0000 0100 0000 0000 + (263232, 263244), // 27 59 ';' // 0000 0100 0000 0100 0100 0000 0000 0100 0000 0100 0100 1100 + (2393120, 7261792), // 28 60 '<' // 0010 0100 1000 0100 0010 0000 0110 1110 1100 1110 0110 0000 + (921088, 921088), // 29 61 '=' // 0000 1110 0000 1110 0000 0000 0000 1110 0000 1110 0000 0000 + (8660096, 13528768), // 30 62 '>' // 1000 0100 0010 0100 1000 0000 1100 1110 0110 1110 1100 0000 + (12730432, 14836800), // 31 63 '?' // 1100 0010 0100 0000 0100 0000 1110 0010 0110 0100 0100 0000 + (0, 0), // 32 64 '@' // NOT WRITTEN + (15395488, 15395488), // 33 65 'A' // 1110 1010 1110 1010 1010 0000 1110 1010 1110 1010 1010 0000 + (15387360, 15395552), // 34 66 'B' // 1110 1010 1100 1010 1110 0000 1110 1010 1110 1010 1110 0000 + (15239392, 15239392), // 35 67 'C' // 1110 1000 1000 1000 1110 0000 1110 1000 1000 1000 1110 0000 + (13281984, 15379168), // 36 68 'D' // 1100 1010 1010 1010 1100 0000 1110 1010 1010 1010 1110 0000 + (15255776, 15255776), // 37 69 'E' // 1110 1000 1100 1000 1110 0000 1110 1000 1100 1000 1110 0000 + (15255680, 15255680), // 38 70 'F' // 1110 1000 1100 1000 1000 0000 1110 1000 1100 1000 1000 0000 + (15248096, 15248096), // 39 71 'G' // 1110 1000 1010 1010 1110 0000 1110 1000 1010 1010 1110 0000 + (11201184, 11201184), // 40 72 'H' // 1010 1010 1110 1010 1010 0000 1010 1010 1110 1010 1010 0000 + (14959840, 14959840), // 41 73 'I' // 1110 0100 0100 0100 1110 0000 1110 0100 0100 0100 1110 0000 + (2239200, 2239200), // 42 74 'J' // 0010 0010 0010 1010 1110 0000 0010 0010 0010 1010 1110 0000 + (11192992, 11201184), // 43 75 'K' // 1010 1010 1100 1010 1010 0000 1010 1010 1110 1010 1010 0000 + (8947936, 8947936), // 44 76 'L' // 1000 1000 1000 1000 1110 0000 1000 1000 1000 1000 1110 0000 + (11463328, 15657632), // 45 77 'M' // 1010 1110 1110 1010 1010 0000 1110 1110 1110 1010 1010 0000 + (13281952, 15379104), // 46 78 'N' // 1100 1010 1010 1010 1010 0000 1110 1010 1010 1010 1010 0000 + (15379168, 15379168), // 47 79 'O' // 1110 1010 1010 1010 1110 0000 1110 1010 1010 1010 1110 0000 + (15394944, 15394944), // 48 80 'P' // 1110 1010 1110 1000 1000 0000 1110 1010 1110 1000 1000 0000 + (15379040, 15379168), // 49 81 'Q' // 1110 1010 1010 1010 0110 0000 1110 1010 1010 1010 1110 0000 + (15387296, 15395488), // 50 82 'R' // 1110 1010 1100 1010 1010 0000 1110 1010 1110 1010 1010 0000 + (6873792, 15262432), // 51 83 'S' // 0110 1000 1110 0010 1100 0000 1110 1000 1110 0010 1110 0000 + (14959680, 14959680), // 52 84 'T' // 1110 0100 0100 0100 0100 0000 1110 0100 0100 0100 0100 0000 + (11184736, 11184864), // 53 85 'U' // 1010 1010 1010 1010 0110 0000 1010 1010 1010 1010 1110 0000 + (11445472, 11202112), // 54 86 'V' // 1010 1110 1010 0100 1110 0000 1010 1010 1110 1110 0100 0000 + (11202208, 11202272), // 55 87 'W' // 1010 1010 1110 1110 1010 0000 1010 1010 1110 1110 1110 0000 + (11160224, 11201184), // 56 88 'X' // 1010 1010 0100 1010 1010 0000 1010 1010 1110 1010 1010 0000 + (15352896, 11420736), // 57 89 'Y' // 1110 1010 0100 0100 0100 0000 1010 1110 0100 0100 0100 0000 + (14829792, 14870752), // 58 90 'Z' // 1110 0010 0100 1000 1110 0000 1110 0010 1110 1000 1110 0000 + (0, 0), // 59 91 '[' // NOT WRITTEN + (0, 0), // 60 92 '\' // NOT WRITTEN + (0, 0), // 61 93 ']' // NOT WRITTEN + (4849664, 15597568), // 62 94 '^' // 0100 1010 0000 0000 0000 0000 1110 1110 0000 0000 0000 0000 + (224, 224), // 63 95 '_' // 0000 0000 0000 0000 1110 0000 0000 0000 0000 0000 1110 0000 + (0, 0), // 64 96 '`' // NOT WRITTEN + (436832, 961248), // 65 97 'a' // 0000 0110 1010 1010 0110 0000 0000 1110 1010 1010 1110 0000 + (9349856, 9349856), // 66 98 'b' // 1000 1110 1010 1010 1110 0000 1000 1110 1010 1010 1110 0000 + (952544, 952544), // 67 99 'c' // 0000 1110 1000 1000 1110 0000 0000 1110 1000 1000 1110 0000 + (3058400, 3058400), // 68 100 'd' // 0010 1110 1010 1010 1110 0000 0010 1110 1010 1010 1110 0000 + (961760, 962272), // 69 101 'e' // 0000 1110 1010 1100 1110 0000 0000 1110 1010 1110 1110 0000 + (6612032, 6612032), // 70 102 'f' // 0110 0100 1110 0100 0100 0000 0110 0100 1110 0100 0100 0000 + (976608, 962272), // 71 103 'g' // 0000 1110 1110 0110 1110 0000 0000 1110 1010 1110 1110 0000 + (9349792, 9349792), // 72 104 'h' // 1000 1110 1010 1010 1010 0000 1000 1110 1010 1010 1010 0000 + (4474080, 4867296), // 73 105 'i' // 0100 0100 0100 0100 1110 0000 0100 1010 0100 0100 1110 0000 + (2239200, 2435808), // 74 106 'j' // 0010 0010 0010 1010 1110 0000 0010 0101 0010 1010 1110 0000 + (9096352, 9105056), // 75 107 'k' // 1000 1010 1100 1100 1010 0000 1000 1010 1110 1110 1010 0000 + (4474080, 12862688), // 76 108 'l' // 0100 0100 0100 0100 1110 0000 1100 0100 0100 0100 1110 0000 + (715424, 977568), // 77 109 'm' // 0000 1010 1110 1010 1010 0000 0000 1110 1110 1010 1010 0000 + (830112, 961184), // 78 110 'n' // 0000 1100 1010 1010 1010 0000 0000 1110 1010 1010 1010 0000 + (961248, 961248), // 79 111 'o' // 0000 1110 1010 1010 1110 0000 0000 1110 1010 1010 1110 0000 + (962176, 962176), // 80 112 'p' // 0000 1110 1010 1110 1000 0000 0000 1110 1010 1110 1000 0000 + (962080, 962080), // 81 113 'q' // 0000 1110 1010 1110 0010 0000 0000 1110 1010 1110 0010 0000 + (714880, 968832), // 82 114 'r' // 0000 1010 1110 1000 1000 0000 0000 1110 1100 1000 1000 0000 + (968416, 968416), // 83 115 's' // 0000 1110 1100 0110 1110 0000 0000 1110 1100 0110 1110 0000 + (5129280, 5129280), // 84 116 't' // 0100 1110 0100 0100 0100 0000 0100 1110 0100 0100 0100 0000 + (699104, 699104), // 85 117 'u' // 0000 1010 1010 1010 1110 0000 0000 1010 1010 1010 1110 0000 + (715328, 700128), // 86 118 'v' // 0000 1010 1110 1010 0100 0000 0000 1010 1010 1110 1110 0000 + (700064, 700128), // 87 119 'w' // 0000 1010 1010 1110 1010 0000 0000 1010 1010 1110 1110 0000 + (672928, 716448), // 88 120 'x' // 0000 1010 0100 0100 1010 0000 0000 1010 1110 1110 1010 0000 + (713312, 713440), // 89 121 'y' // 0000 1010 1110 0010 0110 0000 0000 1010 1110 0010 1110 0000 + (945376, 945376), // 90 122 'z' // 0000 1110 0110 1100 1110 0000 0000 1110 0110 1100 1110 0000 + (0, 0), // 91 123 '(' // NOT WRITTEN + (0, 0), // 92 124 '|' // NOT WRITTEN + (0, 0), // 93 125 ')' // NOT WRITTEN + (0, 0), // 94 126 '~' // NOT WRITTEN + (0xffffffff, 0xffffffff), // 95 127 ERROR SQUARE +]; + +fn draw_char(ch: u8, px: u32, py: u32, scale: u32, col: &Color) { + let ch = if ch == 0 { 127 } else { ch }; + if ch < 32 || ch > 127 { + return; + } + let bitmap_a: u32 = BITMAP_FONT[(ch - 32) as usize].0; + let bitmap_b: u32 = BITMAP_FONT[(ch - 32) as usize].1; + if scale <= 2 { + for x in 0..(4 * scale) { + for y in 0..(6 * scale) { + if ((bitmap_a >> (5 - (y / scale)) * 4) >> (4 - (x / scale))) & 1 == 1 { + if ((bitmap_b >> (5 - (y / scale)) * 4) >> (4 - (x / scale))) & 1 == 1 { + write_px_raw(px + x, py + y, col.to_u128()); + } + } + } + } + } else { + for x in 0..4 { + for y in 0..6 { + if ((bitmap_a >> (5 - y) * 4) >> (4 - x)) & 1 == 1 { + if ((bitmap_b >> (5 - y) * 4) >> (4 - x)) & 1 == 1 { + unsafe { + write_px_memop( + px + x * scale, + py + y * scale, + col.clone(), + scale, + ); + } + } + } + } + } + } +} + +fn draw_line>(s: S, px: u32, py: u32, scale: u32, col: &Color) { + let s = s.as_ref(); + let mut i = 0; + for c in s.bytes() { + draw_char(c, px + i * 5 * scale, py, scale, &col); + i += 1; + } +} + +// defined by linker script +extern "C" { + static _end_textbuf: usize; +} + +/// put a character into the buffer for the output hart to read and print +unsafe fn print_char_unsafe(ch: u8) { + // calculate text buffer base + let end_textbuf = &_end_textbuf as *const usize as usize; + let tbase = (end_textbuf - hartid() * 4096) as *mut usize; + let cur_ptr = tbase.read_volatile(); + if cur_ptr == 4096 { + // TODO: make work lol + return; + } + // this works because while write visibility is not synchronized, the order + // in which writes appear is always upheld + ((cur_ptr + tbase as usize + 4) as *mut u8).write_unaligned(ch); + tbase.write_volatile(cur_ptr + 1); +} + +pub fn print_char(ch: u8) { + unsafe { + print_char_unsafe(ch); + } +} + +const STARTY: u32 = 1622; +const HEADER: &str = "rvc (RISC-V CPU emulator) by _pi_"; +const HEADER_REPO: &str = "github.com/pimaker/rvc"; +const HEADER_STATE: &str = "above: main memory (which doubles as framebuffer)"; +const HEADER_TEXT: &str = "below: hart nr. 8 collects text output from others and draws it"; +const WHITE: Color = Color { r: 255, g: 255, b: 255 }; +const GRAY: Color = Color { r: 120, g: 120, b: 120 }; +const PURPLE: Color = Color { r: 255, g: 40, b: 255 }; +pub fn render_text() -> ! { + draw_line(HEADER, 1024, STARTY, 6, &PURPLE); + draw_line(HEADER_REPO, 1024, STARTY + 36, 3, &GRAY); + draw_line(HEADER_STATE, 16, STARTY, 3, &WHITE); + draw_line(HEADER_TEXT, 16, STARTY + 26, 3, &WHITE); + draw_line("(hart = core in risc-v)", 138, STARTY + 32, 1, &GRAY); + + let mut ptrs = [0usize; 8]; + + // if I make this an array of (0, 0) tuples it doesn't work - bug somewhere? + let mut pos_x = [0; 8]; + let mut pos_y = [0; 8]; + + loop { + for hart in (0..8).rev() { + unsafe { + let end_textbuf = &_end_textbuf as *const usize as usize; + let tbase = (end_textbuf - hart * 4096) as *const usize; + let cur_ptr = tbase.read(); + while ptrs[hart] < cur_ptr { + let ch = ((ptrs[hart] + tbase as usize + 4) as *const u8).read_unaligned(); + // if ch != 0 { + // super::low_level::uart::print_char(ch); + // } else { + // super::low_level::uart::print_char('0' as u8); + // } + ptrs[hart] += 1; + if ch == ('\n' as u8) { + pos_x[hart] = 0; + pos_y[hart] += 1; + } else { + draw_char( + ch, + pos_x[hart] * 5 + hart as u32 * 48 * 5 + 16, + pos_y[hart] * 7 + 64 + STARTY, + 1, + if hart == 7 { &WHITE } else { &GRAY }, + ); + pos_x[hart] += 1; + if pos_x[hart] >= 48 { + pos_x[hart] = 0; + pos_y[hart] += 1; + } + } + } + } + } + + // stall, we know that without a new commit cycle no new data will come + unsafe { + asm! { "fence.i" } + } + } +} diff --git a/src/cpu.h b/src/cpu.h index 6d162d42..6851b521 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "types.h" #include "mem.h" #include "emu.h" @@ -26,6 +27,9 @@ cpu_t cpu_init(uint8_t *mem, uint8_t *dtb, uint8_t *mtd, uint mtd_size) { ret.mtd = mtd; ret.mtd_size = mtd_size; + ret.net.netrx = malloc(4096); + ret.net.nettx = malloc(4096); + ret.clint.msip = false; ret.clint.mtimecmp_lo = 0; ret.clint.mtimecmp_hi = 0; @@ -40,6 +44,8 @@ cpu_t cpu_init(uint8_t *mem, uint8_t *dtb, uint8_t *mtd, uint mtd_size) { ret.mmu.mode = 0; ret.mmu.ppn = 0; + ret.start_time_ref = _Time; + return ret; } diff --git a/src/csr.h b/src/csr.h index f26f4e4e..f9c4cb67 100644 --- a/src/csr.h +++ b/src/csr.h @@ -3,9 +3,11 @@ #include #include +#include #include "types.h" #include "trap.h" #include "mmu.h" +#include "net.h" const uint CSR_USTATUS = 0x000; const uint CSR_UIE = 0x004; @@ -50,11 +52,33 @@ const uint CSR_MEMOP_SRC = 0x0b1; const uint CSR_MEMOP_DST = 0x0b2; const uint CSR_MEMOP_N = 0x0b3; +const uint CSR_PLAYER_ID = 0xbe; +const uint CSR_RNG = 0x0bf; + +const uint CSR_NET_TX_BUF_ADDR = 0x0c0; +const uint CSR_NET_TX_BUF_SIZE_AND_SEND = 0x0c1; +const uint CSR_NET_RX_BUF_ADDR = 0x0c2; +const uint CSR_NET_RX_BUF_READY = 0x0c3; + #define MMU_ACCESS_FETCH 0 #define MMU_ACCESS_READ 1 #define MMU_ACCESS_WRITE 2 extern uint mmu_translate(ins_ret *ins, uint addr, uint mode); +uint xorshift(uint seed) { + seed ^= seed << 13; + seed ^= seed >> 17; + seed ^= seed << 5; + return seed; +} + +uint rng() { + // assume this always works I'm too lazy to error check + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return xorshift(ts.tv_nsec); +} + bool has_csr_access_privilege(cpu_t *cpu, uint addr) { uint privilege = (addr >> 8) & 0x3; return privilege <= cpu->csr.privilege; @@ -71,11 +95,16 @@ uint read_csr_raw(cpu_t *cpu, uint address) { case CSR_CYCLE: return cpu->clock; case CSR_MHARTID: return 0; case CSR_SATP: return (cpu->mmu.mode << 31) | cpu->mmu.ppn; + case CSR_RNG: return rng(); + case CSR_PLAYER_ID: return is_server() ? 2 : 1; + case CSR_NET_TX_BUF_ADDR: return 0x11000000; + case CSR_NET_RX_BUF_ADDR: return 0x11001000; default: return cpu->csr.data[address & 0xffff]; } } void write_csr_raw(cpu_t *cpu, uint address, uint value) { + switch (address) { case CSR_SSTATUS: cpu->csr.data[CSR_MSTATUS] &= ~0x000de162; @@ -102,9 +131,34 @@ void write_csr_raw(cpu_t *cpu, uint address, uint value) { uint src = mmu_translate(&ins, cpu->csr.data[CSR_MEMOP_SRC], MMU_ACCESS_READ); uint dst = mmu_translate(&ins, cpu->csr.data[CSR_MEMOP_DST], MMU_ACCESS_WRITE); uint n = cpu->csr.data[CSR_MEMOP_N]; - memcpy(&cpu->mem[dst & (~0x80000000)], &cpu->mem[src & (~0x80000000)], n); + uint8_t *srcb, *dstb; + // FIXME: can still crash with non-ram and non-mtd addresses + if (src & 0x80000000) { + srcb = cpu->mem; + src &= ~0x80000000; + } else { + srcb = cpu->mtd; + src &= ~0x40000000; + src %= cpu->mtd_size; + } + if (dst & 0x80000000) { + dstb = cpu->mem; + dst &= ~0x80000000; + } else { + dstb = cpu->mtd; + dst &= ~0x40000000; + dst %= cpu->mtd_size - n; // FIXME: incorrect for boundary + } + memcpy(dstb + dst, srcb + src, n); } break; + case CSR_NET_TX_BUF_SIZE_AND_SEND: + /* cpu->csr.data[address] = value; */ + net_send(cpu->net.nettx, value); + break; + case CSR_NET_RX_BUF_READY: + cpu->net.rx_ready = value; + break; default: cpu->csr.data[address] = value; break; }; } diff --git a/src/emu.h b/src/emu.h index 9b636bab..d51e24ef 100644 --- a/src/emu.h +++ b/src/emu.h @@ -3,12 +3,15 @@ #include #include +#include +#include #include "types.h" #include "ins.h" #include "mem.h" #include "mmu.h" #include "trap.h" #include "csr.h" +#include "net.h" #include "pngout.h" static int ebreak_png = 0; @@ -202,10 +205,12 @@ DEF(divu, FormatR, { // rv32m } WR_RD(result) }) +extern void cpu_dump(cpu_t *cpu); DEF(ebreak, FormatEmpty, { // system printf("EBREAK!\n"); - VERBOSE=4; - SINGLE_STEP=1; + cpu_dump(cpu); + /* VERBOSE=4; */ + /* SINGLE_STEP=1; */ /* char buf[12]; */ /* sprintf(buf, "ram_%d.png", ebreak_png++); */ /* int ret = write_ram_as_png(buf); */ @@ -597,6 +602,10 @@ ins_ret ins_select(cpu_t *cpu, uint ins_word) { void emulate(cpu_t *cpu) { + bool net_has_data; + uint8_t *net_data; + uint32_t net_data_len; + uint ins_word = 0; ins_ret ret = ins_ret_noop(cpu); if ((cpu->pc & 0x3) == 0) { @@ -624,19 +633,38 @@ void emulate(cpu_t *cpu) { cpu->csr.data[CSR_MIP] |= MIP_MSIP; } - cpu->clint.mtime_lo++; - cpu->clint.mtime_hi += cpu->clint.mtime_lo == 0 ? 1 : 0; + double mtime = _Time * 1000000.0 / 20.0 * 0.1; + cpu->clint.mtime_lo = (uint)(fmod(mtime, 4294967296.0)); // & 0xffffffff + cpu->clint.mtime_hi = (uint)(mtime / 4294967296.0); // >> 32 if ((cpu->clint.mtimecmp_lo != 0 || cpu->clint.mtimecmp_hi != 0) && (cpu->clint.mtime_hi > cpu->clint.mtimecmp_hi || (cpu->clint.mtime_hi == cpu->clint.mtimecmp_hi && cpu->clint.mtime_lo >= cpu->clint.mtimecmp_lo))) { cpu->csr.data[CSR_MIP] |= MIP_MTIP; - if (VERBOSE >= 1) + if (VERBOSE >= 4) printf("timer irq: %d >= %d\n", cpu->clint.mtime_lo, cpu->clint.mtimecmp_lo); } uart_tick(cpu); - if (cpu->uart.interrupting) { - uint cur_mip = read_csr_raw(cpu, CSR_MIP); - write_csr_raw(cpu, CSR_MIP, cur_mip | MIP_SEIP); + uint cur_mip = read_csr_raw(cpu, CSR_MIP); + if (!(cur_mip & MIP_SEIP)) { + if (cpu->uart.interrupting) { + // uart interrupt + write_csr_raw(cpu, CSR_MIP, cur_mip | MIP_SEIP); + } else if (cpu->net.rx_ready) { + net_has_data = net_recv(&net_data, &net_data_len); + if (net_has_data) { + // network interrupt + write_csr_raw(cpu, CSR_MIP, cur_mip | MIP_SEIP); + uint8_t *dmabuf = cpu->net.netrx; + if (net_data_len > 4096 - sizeof(uint32_t)) { + // maximum of one page size + net_data_len = 4096 - sizeof(uint32_t); + } + *((uint32_t*)dmabuf) = net_data_len; + memcpy(dmabuf + sizeof(uint32_t), net_data, net_data_len); + cpu->net.rx_ready = false; + free(net_data); + } + } } handle_irq_and_trap(cpu, &ret); diff --git a/src/main.c b/src/main.c index d588bba5..b9d99755 100644 --- a/src/main.c +++ b/src/main.c @@ -8,9 +8,11 @@ #include #include #include +#include #include "types.h" #include "cpu.h" #include "uart.h" +#include "net.h" #include #include "../elfy/elfy.h" @@ -59,30 +61,47 @@ uint8_t* get_mmap_ptr(const char* filename) { } void usage() { - printf("Usage: rvc (-e |-b ) [-d ] [-i ] [-v (0|1|2|3|4)] [-s] [-t] [-x]\n"); + printf("Usage: rvc (-e |-b ) [-d ] [-i ] [-v (0|1|2|3|4)] [-s (single step)] [-t (trace)] [-x (allow exit ecall)] [-f (signal forward)] [-n / -N ]\n"); exit(EXIT_FAILURE); } +static bool signal_forward = false; +#define MAX_INPUT_STACK 128 +static char input_stack[MAX_INPUT_STACK]; +static uint input_stack_idx = 0; +static time_t last_signal_time = 0; + void term(int signum) { - printf("\n\nCaught signal!\n"); - buf_on(); - cpu_dump(&cpu); - printf("\n"); + if (signal_forward) { + time_t cur_time = time(NULL); + if (cur_time - last_signal_time >= 1) { + last_signal_time = cur_time; + if (input_stack_idx > (MAX_INPUT_STACK - 2)) return; + /* input_stack[input_stack_idx++] = 0x1b; */ + input_stack[input_stack_idx++] = 0x03; /* ETX / Ctrl-C */ + return; + } + } - /* ins_ret ret; */ - /* for (uint i = 0x10000; i < 0x11000; i += 4) { */ - /* uint pa = mmu_translate(&ret, i, MMU_ACCESS_READ); */ - /* uint val = mem_get_word(&cpu, pa); */ - /* printf("%05x: %08x\n", i, val); */ - /* } */ + printf("\n\nCaught signal!\n"); + buf_on(); + cpu_dump(&cpu); + printf("\n"); - /* print_tracebuf(); */ + /* ins_ret ret; */ + /* for (uint i = 0x10000; i < 0x11000; i += 4) { */ + /* uint pa = mmu_translate(&ret, i, MMU_ACCESS_READ); */ + /* uint val = mem_get_word(&cpu, pa); */ + /* printf("%05x: %08x\n", i, val); */ + /* } */ - write_ram_as_png("ram.png"); + /* print_tracebuf(); */ - /* printf("\n"); */ - exit(EXIT_FAILURE); + /* write_ram_as_png("ram.png"); */ + + /* printf("\n"); */ + exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { @@ -92,12 +111,18 @@ int main(int argc, char *argv[]) { char *initrd = NULL; uint mtd_size = 0; + char *socket = NULL; + bool server = false; + int c; bool trace = false; - while ((c = getopt (argc, argv, "e:b:d:v:i:stx")) != -1) { + while ((c = getopt (argc, argv, "e:b:d:v:i:n:N:stxf")) != -1) { switch (c) { + case 'f': + signal_forward = true; + break; case 'x': allow_ecall_exit = true; break; @@ -122,6 +147,14 @@ int main(int argc, char *argv[]) { case 'i': initrd = optarg; break; + case 'n': + socket = optarg; + server = true; + break; + case 'N': + socket = optarg; + server = false; + break; case '?': default: usage(); @@ -133,6 +166,7 @@ int main(int argc, char *argv[]) { } uint8_t *mem = malloc(MEM_SIZE); + memset(mem, 0, MEM_SIZE); if (elf) { if (load_elf(elf, strlen(elf) + 1, mem, MEM_SIZE, VERBOSE >= 1)) { exit(EXIT_FAILURE+1); @@ -150,6 +184,10 @@ int main(int argc, char *argv[]) { memcpy(mtd, mtd_ptr, mtd_size); } + if (socket) { + net_init(socket, server); + } + struct sigaction action; memset(&action, 0, sizeof(action)); action.sa_handler = term; @@ -170,12 +208,16 @@ int main(int argc, char *argv[]) { buf_off(); // LIMITER (set to high number to ignore) - const unsigned long restr = 200000*1000; + const unsigned long restr = 200000*10000; unsigned long cur = 0; unsigned long t = time(NULL); uint init_verbose = VERBOSE; + struct timeval now; + gettimeofday(&now, NULL); + uint64_t base_clock = now.tv_sec; + while (1) { cur++; unsigned long t2 = time(NULL); @@ -187,6 +229,10 @@ int main(int argc, char *argv[]) { continue; } + gettimeofday(&now, NULL); + _Time = (float)((now.tv_sec - base_clock) * 1000000 + now.tv_usec) / 1000000.0f; + /* printf("Time: %lu %lu %.2f\n", now.tv_sec, now.tv_usec, _Time); */ + cpu_tick(&cpu); if (trace) @@ -226,8 +272,24 @@ int main(int argc, char *argv[]) { cpu_dump(&cpu); char input = 0; - if (!SINGLE_STEP && !uart_input_value && read(0, &input, 1)) { - uart_input_value = input; + if (!SINGLE_STEP && input_stack_idx < MAX_INPUT_STACK && read(0, &input, 1)) { + /* if (input == '+') { */ + /* VERBOSE = (VERBOSE + 1) % 5; */ + /* printf("\nVERBOSE = %d\n", VERBOSE); */ + /* } else { */ + /* uart_input_value = input; */ + /* } */ + if (input) + input_stack[input_stack_idx++] = input; + } + + if (!uart_input_value && input_stack_idx > 0) { + uart_input_value = input_stack[0]; + input_stack_idx--; + // shift stack forward + for (int i = 0; i < input_stack_idx; i++) { + input_stack[i] = input_stack[i+1]; + } } if (SINGLE_STEP) { diff --git a/src/mem.h b/src/mem.h index db88b31a..893badbd 100644 --- a/src/mem.h +++ b/src/mem.h @@ -5,96 +5,113 @@ #include #include "types.h" #include "uart.h" +#include "rtc.h" -const int MEM_SIZE = 1024 * 1024 * 64 - 2048 * 128; +const int MEM_SIZE = 1024 * 1024 * 256 - 2048 * 128; // little endian, zero extended uint do_mem_get_byte(cpu_t *cpu, uint addr) { - if (cpu->dtb != NULL && addr >= 0x1020 && addr <= 0x1fff) { - if (VERBOSE >= 2) - printf("DTB read @%04x/%04x\n", addr, addr - 0x1020); - return cpu->dtb[addr - 0x1020]; - } - - /* if (cpu->mtd != NULL && addr >= 0x40000000 && addr < (0x40000000 + MEM_SIZE)) { */ - /* return cpu->mtd[addr - 0x40000000]; */ - /* } */ - - switch (addr) { - // CLINT - case 0x02000000: return cpu->clint.msip ? 1 : 0; - case 0x02000001: return 0; - case 0x02000002: return 0; - case 0x02000003: return 0; - - case 0x02004000: return (cpu->clint.mtimecmp_lo >> 0) & 0xFF; - case 0x02004001: return (cpu->clint.mtimecmp_lo >> 8) & 0xFF; - case 0x02004002: return (cpu->clint.mtimecmp_lo >> 16) & 0xFF; - case 0x02004003: return (cpu->clint.mtimecmp_lo >> 24) & 0xFF; - case 0x02004004: return (cpu->clint.mtimecmp_hi >> 0) & 0xFF; - case 0x02004005: return (cpu->clint.mtimecmp_hi >> 8) & 0xFF; - case 0x02004006: return (cpu->clint.mtimecmp_hi >> 16) & 0xFF; - case 0x02004007: return (cpu->clint.mtimecmp_hi >> 24) & 0xFF; - - case 0x0200bff8: return (cpu->clint.mtime_lo >> 0) & 0xFF; - case 0x0200bff9: return (cpu->clint.mtime_lo >> 8) & 0xFF; - case 0x0200bffa: return (cpu->clint.mtime_lo >> 16) & 0xFF; - case 0x0200bffb: return (cpu->clint.mtime_lo >> 24) & 0xFF; - case 0x0200bffc: return (cpu->clint.mtime_hi >> 0) & 0xFF; - case 0x0200bffd: return (cpu->clint.mtime_hi >> 8) & 0xFF; - case 0x0200bffe: return (cpu->clint.mtime_hi >> 16) & 0xFF; - case 0x0200bfff: return (cpu->clint.mtime_hi >> 24) & 0xFF; - - // UART (first has rbr_thr_ier_iir, second has lcr_mcr_lsr_scr) - case 0x10000000: - if ((UART_GET2(LCR) >> 7) == 0) { - uint rbr = UART_GET1(RBR); - UART_SET1(RBR, 0); - UART_SET2(LSR, (UART_GET2(LSR) & ~LSR_DATA_AVAILABLE)); - uart_update_iir(cpu); - return rbr; - } else { - return 0; - } - case 0x10000001: return UART_GET2(LCR) >> 7 == 0 ? UART_GET1(IER) : 0; - case 0x10000002: return UART_GET1(IIR); - case 0x10000003: return UART_GET2(LCR); - case 0x10000004: return UART_GET2(MCR); - case 0x10000005: return UART_GET2(LSR); - case 0x10000007: return UART_GET2(SCR); - - /* case 0x80001000: return 0; */ - /* case 0x80001001: return 0; */ - /* case 0x80001002: return 0; */ - /* case 0x80001003: return 0; */ - /* case 0x80001004: return 0; */ - /* case 0x80001005: return 0; */ - /* case 0x80001006: return 0; */ - /* case 0x80001007: return 0; */ - /* case 0x80001040: return 0; */ - /* case 0x80001041: return 0; */ - /* case 0x80001042: return 0; */ - /* case 0x80001043: return 0; */ - /* case 0x80001044: return 0; */ - /* case 0x80001045: return 0; */ - /* case 0x80001046: return 0; */ - /* case 0x80001047: return 0; */ - } - if ((addr & 0x80000000) == 0) { - return 0; - } + if (cpu->dtb != NULL && addr >= 0x1020 && addr <= 0x1fff) { + if (VERBOSE >= 2) + printf("DTB read @%04x/%04x\n", addr, addr - 0x1020); + return cpu->dtb[addr - 0x1020]; + } + + if (cpu->mtd != NULL && addr >= 0x40000000 && addr < (0x40000000 + MEM_SIZE)) { + if (VERBOSE >= 3) + printf("MTD read @%08x/%04x\n", addr, addr - 0x40000000); + return cpu->mtd[addr - 0x40000000]; + } + + if (addr >= 0x11001000 && addr < (0x11001000 + 4096)) { + if (VERBOSE >= 3) + printf("NETRX read @%08x/%04x\n", addr, addr - 0x11001000); + return cpu->net.netrx[addr - 0x11001000]; + } + + // RTC, see device tree + if (addr >= 0x03000000 && addr < (0x03000000 + 0x800)) { + return rtc_read(cpu, addr - 0x03000000); + } + + switch (addr) { + // CLINT + case 0x02000000: return cpu->clint.msip ? 1 : 0; + case 0x02000001: return 0; + case 0x02000002: return 0; + case 0x02000003: return 0; + + case 0x02004000: return (cpu->clint.mtimecmp_lo >> 0) & 0xFF; + case 0x02004001: return (cpu->clint.mtimecmp_lo >> 8) & 0xFF; + case 0x02004002: return (cpu->clint.mtimecmp_lo >> 16) & 0xFF; + case 0x02004003: return (cpu->clint.mtimecmp_lo >> 24) & 0xFF; + case 0x02004004: return (cpu->clint.mtimecmp_hi >> 0) & 0xFF; + case 0x02004005: return (cpu->clint.mtimecmp_hi >> 8) & 0xFF; + case 0x02004006: return (cpu->clint.mtimecmp_hi >> 16) & 0xFF; + case 0x02004007: return (cpu->clint.mtimecmp_hi >> 24) & 0xFF; + + case 0x0200bff8: return (cpu->clint.mtime_lo >> 0) & 0xFF; + case 0x0200bff9: return (cpu->clint.mtime_lo >> 8) & 0xFF; + case 0x0200bffa: return (cpu->clint.mtime_lo >> 16) & 0xFF; + case 0x0200bffb: return (cpu->clint.mtime_lo >> 24) & 0xFF; + case 0x0200bffc: return (cpu->clint.mtime_hi >> 0) & 0xFF; + case 0x0200bffd: return (cpu->clint.mtime_hi >> 8) & 0xFF; + case 0x0200bffe: return (cpu->clint.mtime_hi >> 16) & 0xFF; + case 0x0200bfff: return (cpu->clint.mtime_hi >> 24) & 0xFF; + + // UART (first has rbr_thr_ier_iir, second has lcr_mcr_lsr_scr) + case 0x10000000: + if ((UART_GET2(LCR) >> 7) == 0) { + uint rbr = UART_GET1(RBR); + UART_SET1(RBR, 0); + UART_SET2(LSR, (UART_GET2(LSR) & ~LSR_DATA_AVAILABLE)); + uart_update_iir(cpu); + return rbr; + } else { + return 0; + } + case 0x10000001: return UART_GET2(LCR) >> 7 == 0 ? UART_GET1(IER) : 0; + case 0x10000002: return UART_GET1(IIR); + case 0x10000003: return UART_GET2(LCR); + case 0x10000004: return UART_GET2(MCR); + case 0x10000005: return UART_GET2(LSR); + case 0x10000007: return UART_GET2(SCR); + + /* case 0x80001000: return 0; */ + /* case 0x80001001: return 0; */ + /* case 0x80001002: return 0; */ + /* case 0x80001003: return 0; */ + /* case 0x80001004: return 0; */ + /* case 0x80001005: return 0; */ + /* case 0x80001006: return 0; */ + /* case 0x80001007: return 0; */ + /* case 0x80001040: return 0; */ + /* case 0x80001041: return 0; */ + /* case 0x80001042: return 0; */ + /* case 0x80001043: return 0; */ + /* case 0x80001044: return 0; */ + /* case 0x80001045: return 0; */ + /* case 0x80001046: return 0; */ + /* case 0x80001047: return 0; */ + } - addr = addr & 0x7FFFFFFF; - if (addr >= MEM_SIZE) { if (VERBOSE >= 1) { - printf("WARN: out-of-bounds memory read @0x%08x\n", addr | 0x80000000); + printf("WARN: out-of-bounds mmio read @0x%08x\n", addr); } return 0; - } + } else { + addr = addr & 0x7FFFFFFF; + if (addr >= MEM_SIZE) { + if (VERBOSE >= 1) { + printf("WARN: out-of-bounds memory read @0x%08x\n", addr | 0x80000000); + } + return 0; + } - return cpu->mem[addr]; + return cpu->mem[addr]; + } } uint mem_get_byte(cpu_t *cpu, uint addr) { @@ -117,91 +134,112 @@ uint mem_get_word(cpu_t *cpu, uint addr) { ((uint32_t)mem_get_byte(cpu, addr + 3) << 24); } +extern uint read_csr_raw(cpu_t *cpu, uint address); +extern void write_csr_raw(cpu_t *cpu, uint address, uint value); +extern const uint CSR_MIP, MIP_MTIP, MIP_STIP; + void mem_set_byte(cpu_t *cpu, uint addr, uint val) { if (VERBOSE >= 3) printf("mem_set_byte(%08x, %08x)\n", addr, val); - switch (addr) { - // CLINT - case 0x02000000: cpu->clint.msip = (val & 1) != 0; return; - case 0x02000001: return; - case 0x02000002: return; - case 0x02000003: return; - - case 0x02004000: cpu->clint.mtimecmp_lo = (cpu->clint.mtimecmp_lo & ~(0xff << 0)) | (val << 0); return; - case 0x02004001: cpu->clint.mtimecmp_lo = (cpu->clint.mtimecmp_lo & ~(0xff << 8)) | (val << 8); return; - case 0x02004002: cpu->clint.mtimecmp_lo = (cpu->clint.mtimecmp_lo & ~(0xff << 16)) | (val << 16); return; - case 0x02004003: cpu->clint.mtimecmp_lo = (cpu->clint.mtimecmp_lo & ~(0xff << 24)) | (val << 24); return; - case 0x02004004: cpu->clint.mtimecmp_hi = (cpu->clint.mtimecmp_hi & ~(0xff << 0)) | (val << 0); return; - case 0x02004005: cpu->clint.mtimecmp_hi = (cpu->clint.mtimecmp_hi & ~(0xff << 8)) | (val << 8); return; - case 0x02004006: cpu->clint.mtimecmp_hi = (cpu->clint.mtimecmp_hi & ~(0xff << 16)) | (val << 16); return; - case 0x02004007: cpu->clint.mtimecmp_hi = (cpu->clint.mtimecmp_hi & ~(0xff << 24)) | (val << 24); return; - - case 0x0200bff8: cpu->clint.mtime_lo = (cpu->clint.mtime_lo & ~(0xff << 0)) | (val << 0); return; - case 0x0200bff9: cpu->clint.mtime_lo = (cpu->clint.mtime_lo & ~(0xff << 8)) | (val << 8); return; - case 0x0200bffa: cpu->clint.mtime_lo = (cpu->clint.mtime_lo & ~(0xff << 16)) | (val << 16); return; - case 0x0200bffb: cpu->clint.mtime_lo = (cpu->clint.mtime_lo & ~(0xff << 24)) | (val << 24); return; - case 0x0200bffc: cpu->clint.mtime_hi = (cpu->clint.mtime_hi & ~(0xff << 0)) | (val << 0); return; - case 0x0200bffd: cpu->clint.mtime_hi = (cpu->clint.mtime_hi & ~(0xff << 8)) | (val << 8); return; - case 0x0200bffe: cpu->clint.mtime_hi = (cpu->clint.mtime_hi & ~(0xff << 16)) | (val << 16); return; - case 0x0200bfff: cpu->clint.mtime_hi = (cpu->clint.mtime_hi & ~(0xff << 24)) | (val << 24); return; - - // UART (first has rbr_thr_ier_iir, second has lcr_mcr_lsr_scr) - case 0x10000000: - if ((UART_GET2(LCR) >> 7) == 0) { - UART_SET1(THR, val); - UART_SET2(LSR, (UART_GET2(LSR) & ~LSR_THR_EMPTY)); - uart_update_iir(cpu); - } - return; - case 0x10000001: - if (UART_GET2(LCR) >> 7 == 0) { - if ((UART_GET1(IER) & IER_THREINT_BIT) == 0 && - (val & IER_THREINT_BIT) != 0 && - UART_GET1(THR) == 0) - { - cpu->uart.thre_ip = true; - } - UART_SET1(IER, val); - uart_update_iir(cpu); - } - return; - case 0x10000003: UART_SET2(LCR, val); return; - case 0x10000004: UART_SET2(MCR, val); return; - case 0x10000007: UART_SET2(SCR, val); return; - - /* case 0x80001000: printf("%c", (unsigned char)val); return; */ - /* case 0x80001001: return; */ - /* case 0x80001002: return; */ - /* case 0x80001003: return; */ - /* case 0x80001004: return; */ - /* case 0x80001005: return; */ - /* case 0x80001006: return; */ - /* case 0x80001007: return; */ - /* case 0x80001040: return; */ - /* case 0x80001041: return; */ - /* case 0x80001042: return; */ - /* case 0x80001043: return; */ - /* case 0x80001044: return; */ - /* case 0x80001045: return; */ - /* case 0x80001046: return; */ - /* case 0x80001047: return; */ - } - if ((addr & 0x80000000) == 0) { - return; - } - - const int MEM_SIZE = 1024 * 1024 * 128; - - addr = addr & 0x7FFFFFFF; - if (addr >= MEM_SIZE) { - if (VERBOSE >= 1) { - printf("WARN: out-of-bounds memory write @0x%08x\n", addr | 0x80000000); + if (addr >= 0x11000000 && addr < 0x11001000) { + if (VERBOSE >= 3) + printf("NETTX write @%08x/%04x = %08x\n", addr, addr - 0x11001000, val); + cpu->net.nettx[addr - 0x11000000] = val; + return; } - return; + + // RTC, see device tree + if (addr >= 0x03000000 && addr < (0x03000000 + 0x800)) { + rtc_write(cpu, addr - 0x03000000, val); + return; + } + + // MTIP (machine timer interrupt pending) resets when mtimecmp is written + if (addr >= 0x02004000 && addr < 0x02004004) { + uint cur_mip = read_csr_raw(cpu, CSR_MIP); + write_csr_raw(cpu, CSR_MIP, cur_mip & ~(MIP_MTIP | MIP_STIP)); + } + + switch (addr) { + // CLINT + case 0x02000000: cpu->clint.msip = (val & 1) != 0; return; + case 0x02000001: return; + case 0x02000002: return; + case 0x02000003: return; + + case 0x02004000: cpu->clint.mtimecmp_lo = (cpu->clint.mtimecmp_lo & ~(0xff << 0)) | (val << 0); return; + case 0x02004001: cpu->clint.mtimecmp_lo = (cpu->clint.mtimecmp_lo & ~(0xff << 8)) | (val << 8); return; + case 0x02004002: cpu->clint.mtimecmp_lo = (cpu->clint.mtimecmp_lo & ~(0xff << 16)) | (val << 16); return; + case 0x02004003: cpu->clint.mtimecmp_lo = (cpu->clint.mtimecmp_lo & ~(0xff << 24)) | (val << 24); return; + case 0x02004004: cpu->clint.mtimecmp_hi = (cpu->clint.mtimecmp_hi & ~(0xff << 0)) | (val << 0); return; + case 0x02004005: cpu->clint.mtimecmp_hi = (cpu->clint.mtimecmp_hi & ~(0xff << 8)) | (val << 8); return; + case 0x02004006: cpu->clint.mtimecmp_hi = (cpu->clint.mtimecmp_hi & ~(0xff << 16)) | (val << 16); return; + case 0x02004007: cpu->clint.mtimecmp_hi = (cpu->clint.mtimecmp_hi & ~(0xff << 24)) | (val << 24); return; + + case 0x0200bff8: cpu->clint.mtime_lo = (cpu->clint.mtime_lo & ~(0xff << 0)) | (val << 0); return; + case 0x0200bff9: cpu->clint.mtime_lo = (cpu->clint.mtime_lo & ~(0xff << 8)) | (val << 8); return; + case 0x0200bffa: cpu->clint.mtime_lo = (cpu->clint.mtime_lo & ~(0xff << 16)) | (val << 16); return; + case 0x0200bffb: cpu->clint.mtime_lo = (cpu->clint.mtime_lo & ~(0xff << 24)) | (val << 24); return; + case 0x0200bffc: cpu->clint.mtime_hi = (cpu->clint.mtime_hi & ~(0xff << 0)) | (val << 0); return; + case 0x0200bffd: cpu->clint.mtime_hi = (cpu->clint.mtime_hi & ~(0xff << 8)) | (val << 8); return; + case 0x0200bffe: cpu->clint.mtime_hi = (cpu->clint.mtime_hi & ~(0xff << 16)) | (val << 16); return; + case 0x0200bfff: cpu->clint.mtime_hi = (cpu->clint.mtime_hi & ~(0xff << 24)) | (val << 24); return; + + // UART (first has rbr_thr_ier_iir, second has lcr_mcr_lsr_scr) + case 0x10000000: + if ((UART_GET2(LCR) >> 7) == 0) { + UART_SET1(THR, val); + UART_SET2(LSR, (UART_GET2(LSR) & ~LSR_THR_EMPTY)); + uart_update_iir(cpu); + } + return; + case 0x10000001: + if (UART_GET2(LCR) >> 7 == 0) { + if ((UART_GET1(IER) & IER_THREINT_BIT) == 0 && + (val & IER_THREINT_BIT) != 0 && + UART_GET1(THR) == 0) + { + cpu->uart.thre_ip = true; + } + UART_SET1(IER, val); + uart_update_iir(cpu); + } + return; + case 0x10000003: UART_SET2(LCR, val); return; + case 0x10000004: UART_SET2(MCR, val); return; + case 0x10000007: UART_SET2(SCR, val); return; + + /* case 0x80001000: printf("%c", (unsigned char)val); return; */ + /* case 0x80001001: return; */ + /* case 0x80001002: return; */ + /* case 0x80001003: return; */ + /* case 0x80001004: return; */ + /* case 0x80001005: return; */ + /* case 0x80001006: return; */ + /* case 0x80001007: return; */ + /* case 0x80001040: return; */ + /* case 0x80001041: return; */ + /* case 0x80001042: return; */ + /* case 0x80001043: return; */ + /* case 0x80001044: return; */ + /* case 0x80001045: return; */ + /* case 0x80001046: return; */ + /* case 0x80001047: return; */ + } + } else { + const int MEM_SIZE = 1024 * 1024 * 128; + + addr = addr & 0x7FFFFFFF; + if (addr >= MEM_SIZE) { + if (VERBOSE >= 1) { + printf("WARN: out-of-bounds memory write @0x%08x\n", addr | 0x80000000); + } + return; + } + cpu->mem[addr] = val; } - cpu->mem[addr] = val; } void mem_set_half_word(cpu_t *cpu, uint addr, uint val) { diff --git a/src/net.h b/src/net.h new file mode 100644 index 00000000..e30d6c3e --- /dev/null +++ b/src/net.h @@ -0,0 +1,223 @@ +#ifndef NET_H +#define NET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "types.h" + +static int net_fd = -1; +static int net_fd_conn = -1; +static bool g_server; + +static struct { + union { + int32_t i32; + uint8_t buf[4]; + } len; + uint32_t i; + + uint8_t *buf; + uint32_t buf_pos; + + bool valid; + int reads; +} recv_info; + +bool is_server() { + return g_server; +} + +void net_init(char *path, bool server) +{ + struct sockaddr_un addr; + int flags; + + recv_info.len.i32 = -1; + recv_info.valid = false; + g_server = server; + + if (strlen(path) > sizeof(addr.sun_path) - 1) { + perror("path too long"); + exit(1); + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); + + if (server) { + net_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (net_fd < 0) { + perror("socket"); + exit(1); + } + + if (unlink(path) == -1 && errno != ENOENT) { + perror("unlink"); + } + + if (bind(net_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("bind"); + exit(1); + } + + if (listen(net_fd, 1) < 0) { + perror("listen"); + exit(1); + } + + printf("waiting for net client on %s\n", path); + net_fd_conn = accept(net_fd, NULL, NULL); + printf("net client connected\n"); + } else { + net_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (net_fd < 0) { + perror("socket"); + exit(1); + } + + printf("connecting to net server on %s\n", path); + + if (connect(net_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("connect"); + exit(1); + } + + printf("net client connected\n"); + net_fd_conn = net_fd; + } + + flags = fcntl(net_fd_conn, F_GETFL, 0); + fcntl(net_fd_conn, F_SETFL, flags | O_NONBLOCK); +} + +#define min(a, b) ((a) < (b) ? (a) : (b)) +static void pkt_hex_dump(uint8_t *data, size_t len) +{ + int rowsize = 16; + int i, l, linelen, remaining; + int li = 0; + uint8_t ch; + + remaining = len; + for (i = 0; i < len; i += rowsize) { + printf("%06d\t", li); + + linelen = min(remaining, rowsize); + remaining -= rowsize; + + for (l = 0; l < linelen; l++) { + ch = data[l]; + printf("%02X ", (uint32_t) ch); + } + + data += linelen; + li += 10; + + printf("\n"); + } +} + +void net_send(uint8_t *data, uint32_t len) +{ + if (VERBOSE >= 1) + printf("net_send: %d\n", len); + if (net_fd_conn != -1) { + for (uint32_t i = 0; i < 4; i++) { + uint8_t data = (len >> (i * 8)) & 0xFF; + if (write(net_fd_conn, &data, 1) < 0) { + fprintf(stderr, "net_send: write error (length %d): %s\n", i, strerror(errno)); + exit(1); + } + } + if (VERBOSE >= 3) + pkt_hex_dump(data, len); + if (write(net_fd_conn, data, len) != len) { + fprintf(stderr, "net_send: write error (data): %s\n", strerror(errno)); + exit(1); + } + } +} + +bool net_recv(uint8_t **data_out, uint32_t *len_out) { + int data_read; + + if (net_fd_conn == -1) { + return false; + } + + if (!recv_info.valid) { + // read length + for (; recv_info.i < 4; recv_info.i++) { + uint8_t data; + if ((data_read = read(net_fd_conn, &data, 1)) <= 0) { + if (data_read == 0 && recv_info.i == 0) { + // no data waiting + return false; + } + // we're in the middle of reading the length, the rest should + // arrive shortly + if (data_read != 0 && errno != EAGAIN) { + fprintf(stderr, "net_recv: read error (at byte %d): %s\n", recv_info.i, strerror(errno)); + exit(1); + } + // next emulation loop will retry + return false; + } + recv_info.len.buf[recv_info.i] = data; + } + // length received, prime for receiving data + if (VERBOSE >= 1) + printf("net_recv: awaiting %d\n", recv_info.len.i32); + recv_info.i = 0; + recv_info.buf = malloc(recv_info.len.i32); + if (recv_info.buf == NULL) { + fprintf(stderr, "net_recv: malloc error\n"); + exit(1); + } + recv_info.valid = true; + } + + // read data + if ((data_read = read(net_fd_conn, recv_info.buf + recv_info.buf_pos, recv_info.len.i32 - recv_info.buf_pos)) < 0) { + if (errno != EAGAIN) { + fprintf(stderr, "net_recv: read error (data): %s\n", strerror(errno)); + exit(1); + } + // next emulation loop will retry + return false; + } + + recv_info.reads++; + + recv_info.buf_pos += data_read; + if (recv_info.buf_pos == recv_info.len.i32) { + // full data packet received, return it + if (VERBOSE >= 1) + printf("net_recv: got %d in %d\n", recv_info.len.i32, recv_info.reads); + if (VERBOSE >= 3) + pkt_hex_dump(recv_info.buf, recv_info.len.i32); + *data_out = recv_info.buf; + *len_out = (uint32_t)recv_info.len.i32; + recv_info.reads = 0; + recv_info.buf_pos = 0; + recv_info.len.i32 = 0; + recv_info.valid = false; + return true; + } + + // still some data left + return false; +} + +#endif diff --git a/src/rtc.h b/src/rtc.h new file mode 100644 index 00000000..740ccf8d --- /dev/null +++ b/src/rtc.h @@ -0,0 +1,73 @@ +#ifndef RTC_H +#define RTC_H + +#include +#include +#include "types.h" + +// Defines taken from ds1742 linux kernel driver +#define bcd2bin(x) (((x) & 0x0f) + ((x) >> 4) * 10) +#define bin2bcd(x) ((((x) / 10) << 4) + (x) % 10) + + +#define RTC_SIZE 8 +#define RTC_ADDRESS (0x800 - RTC_SIZE) + +#define RTC_CONTROL (0 + RTC_ADDRESS) +#define RTC_CENTURY (0 + RTC_ADDRESS) +#define RTC_SECONDS (1 + RTC_ADDRESS) +#define RTC_MINUTES (2 + RTC_ADDRESS) +#define RTC_HOURS (3 + RTC_ADDRESS) +#define RTC_DAY (4 + RTC_ADDRESS) +#define RTC_DATE (5 + RTC_ADDRESS) +#define RTC_MONTH (6 + RTC_ADDRESS) +#define RTC_YEAR (7 + RTC_ADDRESS) + +#define RTC_CENTURY_MASK 0x3f +#define RTC_SECONDS_MASK 0x7f +#define RTC_DAY_MASK 0x07 + +/* Bits in the Control/Century register */ +#define RTC_WRITE 0x80 +#define RTC_READ 0x40 + +/* Bits in the Seconds register */ +#define RTC_STOP 0x80 + +/* Bits in the Day register */ +#define RTC_BATT_FLAG 0x80 + +uint8_t rtc_read(cpu_t *cpu, uint32_t offset) { + offset -= RTC_ADDRESS; + if (offset > 3) { + return (cpu->rtc1 >> ((offset - 4) * 8)) & 0xff; + } + return (cpu->rtc0 >> (offset * 8)) & 0xff; +} + +void rtc_write(cpu_t *cpu, uint32_t offset, uint8_t data) { + switch (offset) { + case RTC_CONTROL: + if (data == RTC_READ) { + if (VERBOSE >= 1) + printf("RTC update!\n"); + // Get real time from host + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + struct tm *t = localtime(&ts.tv_sec); + cpu->rtc0 = + bin2bcd((t->tm_year + 1900) / 100) | + bin2bcd(t->tm_sec) << 8 | + bin2bcd(t->tm_min) << 16 | + bin2bcd(t->tm_hour) << 24; + cpu->rtc1 = + bin2bcd(t->tm_wday) | + bin2bcd(t->tm_mday) << 8 | + bin2bcd(t->tm_mon + 1) << 16 | + bin2bcd(t->tm_year % 100) << 24; + } + break; + } +} + +#endif diff --git a/src/trap.h b/src/trap.h index 1c8bce3f..f669b2a9 100644 --- a/src/trap.h +++ b/src/trap.h @@ -45,8 +45,7 @@ const uint MIP_ALL = MIP_MEIP | MIP_MTIP | MIP_MSIP | MIP_SEIP | MIP_STIP | MIP_ #include "csr.h" // returns true if IRQ was handled or !is_interrupt -bool handle_trap(cpu_t *cpu, ins_ret *ret, bool is_interrupt) { - trap t = ret->trap; +bool handle_trap(cpu_t *cpu, ins_ret *ret, trap t, bool is_interrupt) { uint current_privilege = cpu->csr.privilege; uint mdeleg = read_csr_raw(cpu, is_interrupt ? CSR_MIDELEG : CSR_MEDELEG); @@ -131,6 +130,8 @@ bool handle_trap(cpu_t *cpu, ins_ret *ret, bool is_interrupt) { } // NOTE: No user mode interrupt/exception handling! + // Importantly, this clears xIE in mstatus, so even if MIP isn't cleared, + // the interrupt will not be immediately reentrant. if (new_privilege == PRIV_MACHINE) { uint mie = (mstatus >> 3) & 1; uint new_status = (mstatus & ~0x1888) | (mie << 7) | (current_privilege << 11); @@ -141,37 +142,39 @@ bool handle_trap(cpu_t *cpu, ins_ret *ret, bool is_interrupt) { write_csr_raw(cpu, CSR_SSTATUS, new_status); } - if (VERBOSE >= (is_interrupt ? 1 : 2)) + if (VERBOSE >= (is_interrupt && t.type != trap_MachineTimerInterrupt && t.type != trap_SupervisorTimerInterrupt ? 1 : 2)) printf("trap: type=%08x value=%08x (IRQ: %d) moved PC from @%08x (#%d) to @%08x (#%d)\n", t.type, t.value, is_interrupt, cpu->pc, current_privilege, ret->pc_val, new_privilege); return true; } void handle_irq_and_trap(cpu_t *cpu, ins_ret *ret) { - bool trap = ret->trap.en; + trap t = ret->trap; uint mip_reset = MIP_ALL; uint cur_mip = read_csr_raw(cpu, CSR_MIP); + bool irq = false; - if (!trap) { + if (!t.en) { + irq = true; uint mirq = cur_mip & read_csr_raw(cpu, CSR_MIE); -#define HANDLE(mip, ttype) case mip: mip_reset = mip; ret->trap.en = true; ret->trap.type = ttype; break; - switch (mirq & MIP_ALL) { - HANDLE(MIP_MEIP, trap_MachineExternalInterrupt) - HANDLE(MIP_MSIP, trap_MachineSoftwareInterrupt) - HANDLE(MIP_MTIP, trap_MachineTimerInterrupt) - HANDLE(MIP_SEIP, trap_SupervisorExternalInterrupt) - HANDLE(MIP_SSIP, trap_SupervisorSoftwareInterrupt) - HANDLE(MIP_STIP, trap_SupervisorTimerInterrupt) - } + if (false) {} +#define HANDLE(mip, ttype) else if (mirq & mip) { mip_reset = mip; t.en = true; t.type = ttype; } + HANDLE(MIP_MEIP, trap_MachineExternalInterrupt) + HANDLE(MIP_MSIP, trap_MachineSoftwareInterrupt) + HANDLE(MIP_MTIP, trap_MachineTimerInterrupt) + HANDLE(MIP_SEIP, trap_SupervisorExternalInterrupt) + HANDLE(MIP_SSIP, trap_SupervisorSoftwareInterrupt) + HANDLE(MIP_STIP, trap_SupervisorTimerInterrupt) #undef HANDLE } - bool irq = mip_reset != MIP_ALL; - if (trap || irq) { - bool handled = handle_trap(cpu, ret, irq); + if (t.en) { + bool handled = handle_trap(cpu, ret, t, irq); if (handled && irq) { - // reset MIP value since IRQ was handled - write_csr_raw(cpu, CSR_MIP, cur_mip & ~mip_reset); + // reset MIP value if IRQ other than timer was handled + // (MTIP/STIP will be reset by write to mtimecmp) + if ((mip_reset & 0x0A0) == 0) + write_csr_raw(cpu, CSR_MIP, cur_mip & ~mip_reset); if (VERBOSE >= 3) printf("IRQ handled: old_mip=%03x new_mip=%03x\n", cur_mip, read_csr_raw(cpu, CSR_MIP)); } diff --git a/src/types.h b/src/types.h index 95800a04..eec60057 100644 --- a/src/types.h +++ b/src/types.h @@ -11,6 +11,8 @@ static bool SINGLE_STEP = false; typedef uint32_t uint; typedef uint32_t uint; +static float _Time; + typedef struct { uint data[4096]; uint privilege; @@ -36,6 +38,12 @@ typedef struct { uint ppn; } mmu_state; +typedef struct { + uint rx_ready; + uint8_t *nettx; + uint8_t *netrx; +} net_state; + typedef struct { uint clock; uint xreg[32]; @@ -48,6 +56,10 @@ typedef struct { clint_state clint; uart_state uart; mmu_state mmu; + net_state net; + + uint rtc0, rtc1; + float start_time_ref; bool reservation_en; uint reservation_addr; diff --git a/test.c b/test.c new file mode 100644 index 00000000..f3fec325 --- /dev/null +++ b/test.c @@ -0,0 +1,23 @@ +#include + +#define OFFSET_UINT2_POS(x, y, w, h, n) uint2((x + n) % w, y + ((n + x) / h)) +#define RAM_L1_ARRAY_IDX(a) (((a >> 2) & 127) | (((a >> 11) & 0x3) << 7)) + +void uint2(int x, int y) { + printf("x=%d y=%d\n", x, y); +} + +int main() { + OFFSET_UINT2_POS(20, 0, 128, 128, 10); + OFFSET_UINT2_POS(120, 0, 128, 128, 10); + OFFSET_UINT2_POS(20, 3, 128, 128, 140); + OFFSET_UINT2_POS(120, 0, 128, 128, (128*8 + 4)); + + printf("\n"); + + for (unsigned int i = 0; i < 128*128*16; i+=4) { + printf("%03d: %d\n", i/4, RAM_L1_ARRAY_IDX(i)); + } + + return 0; +} diff --git a/toimg/src/main.rs b/toimg/src/main.rs index f62fde11..ddae963e 100644 --- a/toimg/src/main.rs +++ b/toimg/src/main.rs @@ -113,8 +113,8 @@ fn main() { let y = idx / width; println!("Saving result... (required size: x={} y={})", width, y + 1); - fr.save(input.clone().with_extension("r.bmp")).unwrap(); - fg.save(input.clone().with_extension("g.bmp")).unwrap(); - fb.save(input.clone().with_extension("b.bmp")).unwrap(); - fa.save(input.clone().with_extension("a.bmp")).unwrap(); + fr.save(input.clone().with_extension("r.png")).unwrap(); + fg.save(input.clone().with_extension("g.png")).unwrap(); + fb.save(input.clone().with_extension("b.png")).unwrap(); + fa.save(input.clone().with_extension("a.png")).unwrap(); }