add rng, rtc, networking, more CSR paravirt exts and fixes

honestly forgot what I added all over the last year or so, but here you
go, enjoy more cursed code
This commit is contained in:
pi 2022-11-25 23:11:56 +01:00
parent 1b74a7a85d
commit 134e85e485
50 changed files with 1458 additions and 466 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
compile_commands.json compile_commands.json
.ccls-cache .ccls-cache
.cache
elfy/.ccls-cache elfy/.ccls-cache
rvc rvc
!rvc/ !rvc/

View File

@ -3,6 +3,8 @@ SRC_DIRS ?= ./src ./tinypngout
CC=clang CC=clang
BUILDROOT := "buildroot-2022.02.1"
SRCS := $(shell find $(SRC_DIRS) -name '*.cpp' -or -name '*.c' -or -name '*.s') SRCS := $(shell find $(SRC_DIRS) -name '*.cpp' -or -name '*.c' -or -name '*.s')
OBJS := $(addsuffix .o,$(basename $(SRCS))) OBJS := $(addsuffix .o,$(basename $(SRCS)))
DEPS := $(OBJS:.o=.d) DEPS := $(OBJS:.o=.d)
@ -10,12 +12,18 @@ DEPS := $(OBJS:.o=.d)
INC_DIRS := $(shell find $(SRC_DIRS) -type d) INC_DIRS := $(shell find $(SRC_DIRS) -type d)
INC_FLAGS := $(addprefix -I,$(INC_DIRS)) 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 CFLAGS ?= -g -O2
$(TARGET): $(OBJS) .PHONY: $(TARGET)
$(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 $(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) -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 LINUX_PAYLOAD=linux/arch/riscv/boot/Image
RAYTRACE_PAYLOAD=rust_raytrace/target/riscv32ima-unknown-none-elf/release/rust_raytrace.bin 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): $(BUILDROOT_MARKER):
$(MAKE) -C buildroot-2021.05 if [ ! -f $(BUILDROOT_MARKER) ]; then $(MAKE) -C $(BUILDROOT); fi
cd buildroot-2021.05 && cp init output/target/ && cp pi.js output/target/
$(MAKE) -C buildroot-2021.05
touch $@ touch $@
$(PAYLOAD): $(shell find rust_payload/src -type f) $(PAYLOAD): $(shell find rust_payload/src -type f)
@ -66,7 +72,7 @@ rust_payload.elf: $(PAYLOAD) $(BUILDROOT_MARKER)
.PHONY: $(LINUX_PAYLOAD) .PHONY: $(LINUX_PAYLOAD)
$(LINUX_PAYLOAD): linux $(BUILDROOT_MARKER) $(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 && \ cd linux && \
env CROSS_COMPILE=$(Q) \ env CROSS_COMPILE=$(Q) \
CFLAGS="-march=rv32ima -mabi=ilp32" \ CFLAGS="-march=rv32ima -mabi=ilp32" \
@ -74,12 +80,14 @@ $(LINUX_PAYLOAD): linux $(BUILDROOT_MARKER)
ARCH=riscv \ ARCH=riscv \
KCONFIG_ALLCONFIG=../linux.config \ KCONFIG_ALLCONFIG=../linux.config \
make allnoconfig make allnoconfig
cd linux && ./scripts/clang-tools/gen_compile_commands.py
cd linux && \ cd linux && \
env CROSS_COMPILE=$(Q) \ env CROSS_COMPILE=$(Q) \
CFLAGS="-march=rv32ima -mabi=ilp32" \ CFLAGS="-march=rv32ima -mabi=ilp32" \
LDFLAGS="-march=rv32ima -mabi=ilp32" \ LDFLAGS="-march=rv32ima -mabi=ilp32" \
ARCH=riscv \ 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 linux_payload.bin: linux_payload.elf
cp $(OPENSBI_BUILD)/fw_payload.bin ./linux_payload.bin 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 run: fw_payload.bin $(TARGET) dts.dtb
./rvc -b fw_payload.bin -d dts.dtb ./rvc -b fw_payload.bin -d dts.dtb
.PHONY: run-v1
run-v1: fw_payload.bin $(TARGET) dts.dtb run-v1: fw_payload.bin $(TARGET) dts.dtb
./rvc -b fw_payload.bin -d dts.dtb -v1 ./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 .PHONY: clean
clean: clean:

View File

@ -5,7 +5,7 @@ PREFIX ?= ../buildroot-2021.05/output/host/bin/riscv32-buildroot-linux-gnu-
CC := $(PREFIX)cc CC := $(PREFIX)cc
AS := $(PREFIX)as AS := $(PREFIX)as
LD := $(PREFIX)ld LD := $(PREFIX)ld
OBJDUMP := $(PREFIX)objcopy OBJCOPY := $(PREFIX)objcopy
SRCS := $(wildcard *.S) SRCS := $(wildcard *.S)
SRCS += $(wildcard *.c) SRCS += $(wildcard *.c)
@ -23,7 +23,7 @@ $(TARGET): $(OBJS)
$(CC) $(LDFLAGS) $(OBJS) -o $@ $(LOADLIBES) $(LDLIBS) $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LOADLIBES) $(LDLIBS)
$(TARGET).img: $(TARGET) $(TARGET).img: $(TARGET)
riscv32-elf-objcopy -O binary $< $@ $(OBJCOPY) -O binary $< $@
.PHONY: clean .PHONY: clean
clean: clean:

Binary file not shown.

BIN
bare_metal_test/bare.a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

BIN
bare_metal_test/bare.b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 B

View File

@ -101,6 +101,20 @@ int main(void) {
print("\n"); 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"); print("[bare] testing trap handler...\n");
__asm volatile("csrw sip, 0x2"); __asm volatile("csrw sip, 0x2");

BIN
bare_metal_test/bare.g.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

BIN
bare_metal_test/bare.r.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 920 B

View File

@ -1,6 +1,6 @@
MEMORY MEMORY
{ {
RAM : ORIGIN = 0x80000000, LENGTH = 31M RAM : ORIGIN = 0x80000000, LENGTH = 60M
} }
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM);

BIN
dts.a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

BIN
dts.b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

31
dts.dts
View File

@ -6,23 +6,38 @@
compatible = "riscv-virtio"; compatible = "riscv-virtio";
model = "generic,rvc"; model = "generic,rvc";
chosen { aliases {
bootargs = "console=hvc0 earlycon=sbi loglevel=15 debug single"; serial0 = &uart0;
//stdout-path = "/uart@10000000";
}; };
uart@10000000 { chosen {
interrupts = <0x1>; bootargs = "root=mtd:root rootfstype=romfs ro init=/rvcinit phram.phram=root,0x40000000,256Mi console=hvc0 earlycon=sbi";
interrupt-parent = <&irqchip>; stdout-path = "/uart@10000000";
};
uart0: uart@10000000 {
/* interrupts = <0x9>; */
/* interrupt-parent = <&irqchip>; */
clock-frequency = <0x384000>; clock-frequency = <0x384000>;
reg = <0x0 0x10000000 0x0 0x100>; reg = <0x0 0x10000000 0x0 0x100>;
compatible = "ns16550a"; compatible = "ns16550a";
}; };
rtc@3000000 {
compatible = "maxim,ds1742";
reg = <0x0 0x3000000 0x0 0x800>;
};
rvcnet {
compatible = "pi,rvcnet";
};
cpus { cpus {
#address-cells = <0x1>; #address-cells = <0x1>;
#size-cells = <0x0>; #size-cells = <0x0>;
timebase-frequency = <0x1000000>;
/* 100/20 kHz, must match frequency in emu.h */
timebase-frequency = <0x1388>;
cpu-map { cpu-map {
cluster0 { cluster0 {
@ -51,7 +66,7 @@
memory@80000000 { memory@80000000 {
device_type = "memory"; device_type = "memory";
reg = <0x0 0x80000000 0x0 0x03B00000>; /* includes safety margin at end? */ reg = <0x0 0x80000000 0x0 0x07B00000>; /* includes safety margin at end? */
}; };
soc { soc {

BIN
dts.g.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 B

BIN
dts.r.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

119
guest-root/examples/pi.js Normal file
View File

@ -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);

39
guest-root/install.sh Executable file
View File

@ -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/

18
guest-root/network-setup.sh Executable file
View File

@ -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

44
guest-root/rvcinit Executable file
View File

@ -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 </proc/uptime)s"
cat << EOF
_ _
| (_)
_ ____ _____ | |_ _ __ _ ___ __
| '__\ \ / / __| | | | '_ \| | | \ \/ /
| | \ V / (__ | | | | | | |_| |> <
|_| \_/ \___| |_|_|_| |_|\__,_/_/\_\
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

2
linux

@ -1 +1 @@
Subproject commit f4e0f631965ce23bca273bdcc7c1637bc9993365 Subproject commit 0bd94b14f8b6b838bbd48e5c204e819df621e659

View File

@ -1,129 +0,0 @@
From 30022eebb78abc5a8a9289aecbd30a155fafcff0 Mon Sep 17 00:00:00 2001
From: Stefan <stefan@pimaker.at>
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 <stefan@pimaker.at>
---
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 : "<success>");
return message;
}
--
2.32.0

View File

@ -17,10 +17,11 @@ CONFIG_INITRAMFS_COMPRESSION_LZ4=n
CONFIG_INITRAMFS_COMPRESSION_ZSTD=n CONFIG_INITRAMFS_COMPRESSION_ZSTD=n
CONFIG_INITRAMFS_COMPRESSION_NONE=y 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_BLOCK=n
CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV=n
CONFIG_BLK_DEV_INITRD=n
CONFIG_DEBUG=y CONFIG_DEBUG=y
CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_KERNEL=y
@ -57,18 +58,22 @@ CONFIG_TTY=y
CONFIG_VT=y CONFIG_VT=y
CONFIG_VT_CONSOLE=y CONFIG_VT_CONSOLE=y
CONFIG_VT_HW_CONSOLE_BINDING=y CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE=n
CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_CORE_CONSOLE=n
CONFIG_SERIAL_8250=n CONFIG_SERIAL_8250=n
CONFIG_SERIAL_8250_CONSOLE=n CONFIG_SERIAL_8250_CONSOLE=n
CONFIG_SERIAL_OF_PLATFORM=y CONFIG_SERIAL_8250_16550A_VARIANTS=n
CONFIG_SERIAL_EARLYCON=y CONFIG_SERIAL_EARLYCON=n
CONFIG_CONSOLE_POLL=n CONFIG_CONSOLE_POLL=n
CONFIG_UNIX98_PTYS=n CONFIG_UNIX98_PTYS=n
CONFIG_LEGACY_PTYS=n CONFIG_LEGACY_PTYS=n
CONFIG_RISCV_TIMER=y CONFIG_RISCV_TIMER=y
CONFIG_PREEMPT_NONE=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_DTC=y
CONFIG_OF=y CONFIG_OF=y
@ -78,6 +83,11 @@ CONFIG_OF_KOBJ=y
CONFIG_OF_ADDRESS=y CONFIG_OF_ADDRESS=y
CONFIG_OF_IRQ=y CONFIG_OF_IRQ=y
CONFIG_OF_RESERVED_MEM=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_RAMFS=y
CONFIG_TMPFS=y CONFIG_TMPFS=y
@ -85,19 +95,20 @@ CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y CONFIG_DEVTMPFS_MOUNT=y
CONFIG_PROC_FS=y CONFIG_PROC_FS=y
CONFIG_SYSFS=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_MSDOS_PARTITION=n
CONFIG_EFI_PARTITION=n CONFIG_EFI_PARTITION=n
CONFIG_FW_LOADER=n CONFIG_FW_LOADER=n
CONFIG_SCSI_MOD=n CONFIG_SCSI_MOD=n
CONFIG_BLK_DEV_BSG=n
CONFIG_MQ_IOSCHED_KYBER=n CONFIG_MQ_IOSCHED_KYBER=n
CONFIG_MQ_IOSCHED_DEADLINE=n CONFIG_MQ_IOSCHED_DEADLINE=n
CONFIG_IO_WQ=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_VGA_CONSOLE=n
CONFIG_HID=n CONFIG_HID=n
CONFIG_USB_SUPPORT=n CONFIG_USB_SUPPORT=n
@ -112,3 +123,17 @@ CONFIG_USB=n
CONFIG_HAVE_SYSCALL_TRACEPOINTS=n CONFIG_HAVE_SYSCALL_TRACEPOINTS=n
CONFIG_TRACING_SUPPORT=n CONFIG_TRACING_SUPPORT=n
CONFIG_FTRACE=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

BIN
linux_payload.a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 KiB

BIN
linux_payload.b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 KiB

BIN
linux_payload.g.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 KiB

BIN
linux_payload.r.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 KiB

@ -1 +1 @@
Subproject commit b4895fc56b16815d622b088d188ac65d640d25ab Subproject commit 8ee69d7a5dc7ef6d8b2bda96bf86d2923f2cf176

BIN
rust_raytrace.a.bmp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

BIN
rust_raytrace.b.bmp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
rust_raytrace.g.bmp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

BIN
rust_raytrace.r.bmp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -4,7 +4,7 @@ ENTRY( _start )
MEMORY MEMORY
{ {
ram (rwx) : ORIGIN = 0x80000000, LENGTH = 0x80000 ram (rwx) : ORIGIN = 0x80000000, LENGTH = 0x100000
} }
SECTIONS SECTIONS
@ -17,14 +17,18 @@ SECTIONS
} > ram } > ram
.stack (NOLOAD) : { .stack (NOLOAD) : {
. = . + 0x20000; . = . + 0x70000;
PROVIDE(_end_stack = .); PROVIDE(_end_stack = .);
} > ram } > ram
.heap (NOLOAD) : { .heap (NOLOAD) : {
PROVIDE(_begin_heap = .); . = . + 0x70000;
. = . + 0x40000;
PROVIDE(_end_heap = .); PROVIDE(_end_heap = .);
} > ram } > ram
.textbuf (NOLOAD) : {
. = . + 0x10000;
PROVIDE(_end_textbuf = .);
} > ram
} }

36
rust_raytrace/src/fb.rs Normal file
View File

@ -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);
}
}

View File

@ -1,8 +1,8 @@
use core::panic::PanicInfo; use core::panic::PanicInfo;
use linked_list_allocator::LockedHeap; use linked_list_allocator::LockedHeap;
use super::output::*;
mod uart; pub mod uart;
pub use uart::*;
#[naked] #[naked]
#[no_mangle] #[no_mangle]
@ -13,7 +13,11 @@ extern "C" fn _start() -> ! {
unsafe { unsafe {
asm!( asm!(
" "
csrr t0, 0xf14
la sp, {end_stack} la sp, {end_stack}
li t2, 4096
mul t1, t0, t2
sub sp, sp, t1
j main j main
", ",
end_stack = sym _end_stack, end_stack = sym _end_stack,
@ -31,6 +35,7 @@ fn alloc_error(_layout: core::alloc::Layout) -> ! {
#[panic_handler] #[panic_handler]
fn panic(_info: &PanicInfo) -> ! { fn panic(_info: &PanicInfo) -> ! {
println("PANIC!"); println("PANIC!");
unsafe { asm! { "ebreak" } }
loop {} loop {}
} }
@ -41,22 +46,31 @@ extern "C" {
static _end_heap: usize; static _end_heap: usize;
} }
// not actually safe between harts, but shouldn't be used so ignore?
#[global_allocator] #[global_allocator]
static ALLOCATOR: LockedHeap = LockedHeap::empty(); 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() { pub unsafe fn init_heap() {
let stack_end = &_end_stack as *const usize as usize; 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 = &_end_heap as *const usize as usize;
let heap_end = heap_end.min(heap_start + 4096);
let heap_size = heap_end - heap_start; let heap_size = heap_end - heap_start;
print("> stack_end: "); print("> stack_end(sym): ");
print_usize(stack_end); print_usize(stack_end);
print("\n> heap_start: "); print("\n> heap_start: ");
print_usize(heap_start); print_usize(heap_start);
print("\n> heap_end: "); print("\n> heap_end: ");
print_usize(heap_end); print_usize(heap_end);
print("\n> heap_size: "); print("\n> heap_size: ");
print_usize(heap_size); print_usize(heap_size);
print("\n"); print("\n");

View File

@ -6,46 +6,3 @@ pub fn print_char(ch: u8) {
thr.write_volatile(ch); 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);
}
}

View File

@ -10,30 +10,42 @@ extern crate alloc;
mod low_level; mod low_level;
use low_level::*; use low_level::*;
mod output;
use output::*;
mod raytrace; mod raytrace;
use raytrace::*; use raytrace::*;
mod math; mod math;
use math::*; use math::*;
const RAM_BASE: u32 = 0x80000000; mod fb;
const FB_START: u32 = 0x80000; use fb::*;
const FB_WIDTH: u32 = 2048;
const FB_HEIGHT: u32 = 2048 - 16 /* progmem */ - 128 /* CPU state */;
// const AA_BORDER: u32 = 10;
static mut SUPERSCALE: u32 = 96; // start at 48 mod text;
pub fn superscale() -> u32 { use text::*;
unsafe { SUPERSCALE }
} // const AA_BORDER: u32 = 10;
const SUPERSCALE: u32 = 112;
#[no_mangle] #[no_mangle]
pub fn main() -> ! { pub fn main() -> ! {
print("hartid (core) = ");
print_usize(hartid());
println("");
println("Initializing heap..."); println("Initializing heap...");
unsafe { unsafe {
init_heap(); 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..."); println("Setting up scene...");
let mut scene = Scene::new(); let mut scene = Scene::new();
@ -132,25 +144,30 @@ pub fn main() -> ! {
intensity: 0.07, intensity: 0.07,
}); });
while superscale() > 1 { let mut superscale = SUPERSCALE;
unsafe { SUPERSCALE /= 2 }; let starty = FB_HEIGHT_SLICE * hartid() as u32;
while superscale > 1 {
superscale /= 2;
print("Tracing @"); print("Tracing @");
print_usize(superscale() as usize); print_usize(superscale as usize);
print(" "); print(" ");
for y in (0..(FB_HEIGHT / superscale())).rev() { let sy = starty/superscale;
for x in 0..(FB_WIDTH / superscale()) { for y in sy..(FB_HEIGHT_SLICE / superscale + sy) {
for x in 0..(FB_WIDTH / superscale) {
// Testpattern: // Testpattern:
// let col = Vector3::new( // let col = Color {
// if (x % 2) == 0 { 255 } else { 0 }, // r: if (x % 2) == 0 { 255 } else { 0 },
// ((y * 255) / (FB_HEIGHT / superscale())) as i32, // g: (y * 255) / (FB_HEIGHT / superscale),
// if (y % 2) == 0 { 255 } else { 0 }, // b: if (y % 2) == 0 { 255 } else { 0 },
// ); // };
let col = scene.raytrace( let col = scene.raytrace(
x as i32 - (FB_WIDTH / superscale() / 2) as i32, x as i32 - (FB_WIDTH / superscale / 2) as i32,
y as i32 - (FB_HEIGHT / 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("."); print(".");
@ -158,7 +175,7 @@ pub fn main() -> ! {
// print(" Done!\nAnti-Aliasing"); // 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()) { // for x in 0..(FB_WIDTH / superscale()) {
// // tap neighboring pixels and mix into borders // // tap neighboring pixels and mix into borders
// let cur = read_px_raw(x * superscale() + superscale() / 2, y * superscale() + superscale() / 2); // let cur = read_px_raw(x * superscale() + superscale() / 2, y * superscale() + superscale() / 2);
@ -205,26 +222,24 @@ pub fn main() -> ! {
loop {} loop {}
} }
fn write_px(x: u32, y: u32, col: Color) { fn write_px(x: u32, y: u32, col: Color, superscale: u32) {
let col = col.to_u128(); let x = x * superscale;
let x = x * superscale(); let y = y * superscale;
let y = y * superscale();
for ys in 0..superscale() { if superscale > 7 {
for xs in 0..superscale() { 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); 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 { // fn read_px_raw(x: u32, y: u32) -> Color {
// let col: u128; // let col: u128;
// unsafe { // unsafe {

View File

@ -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);
}
}

View File

@ -172,17 +172,17 @@ impl Scene {
self.lights.push(light); self.lights.push(light);
} }
fn view_vector(x: i32, y: i32) -> Vector3 { fn view_vector(x: i32, y: i32, superscale: u32) -> Vector3 {
Vector3::new( Vector3::new(
x as f32, x as f32,
y as f32, y as f32,
(crate::FB_WIDTH / crate::superscale() / 2) as f32, (crate::FB_WIDTH / superscale / 2) as f32,
) )
.normalized() .normalized()
} }
pub fn raytrace(&self, x: i32, y: i32) -> Color { pub fn raytrace(&self, x: i32, y: i32, superscale: u32) -> Color {
let view = Self::view_vector(x, y); let view = Self::view_vector(x, y, superscale);
self.do_raytrace( self.do_raytrace(
&Vector3::ZERO, &Vector3::ZERO,
&view, &view,

238
rust_raytrace/src/text.rs Normal file
View File

@ -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: AsRef<str>>(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" }
}
}
}

View File

@ -4,6 +4,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/time.h>
#include "types.h" #include "types.h"
#include "mem.h" #include "mem.h"
#include "emu.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 = mtd;
ret.mtd_size = mtd_size; ret.mtd_size = mtd_size;
ret.net.netrx = malloc(4096);
ret.net.nettx = malloc(4096);
ret.clint.msip = false; ret.clint.msip = false;
ret.clint.mtimecmp_lo = 0; ret.clint.mtimecmp_lo = 0;
ret.clint.mtimecmp_hi = 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.mode = 0;
ret.mmu.ppn = 0; ret.mmu.ppn = 0;
ret.start_time_ref = _Time;
return ret; return ret;
} }

View File

@ -3,9 +3,11 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <time.h>
#include "types.h" #include "types.h"
#include "trap.h" #include "trap.h"
#include "mmu.h" #include "mmu.h"
#include "net.h"
const uint CSR_USTATUS = 0x000; const uint CSR_USTATUS = 0x000;
const uint CSR_UIE = 0x004; 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_DST = 0x0b2;
const uint CSR_MEMOP_N = 0x0b3; 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_FETCH 0
#define MMU_ACCESS_READ 1 #define MMU_ACCESS_READ 1
#define MMU_ACCESS_WRITE 2 #define MMU_ACCESS_WRITE 2
extern uint mmu_translate(ins_ret *ins, uint addr, uint mode); 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) { bool has_csr_access_privilege(cpu_t *cpu, uint addr) {
uint privilege = (addr >> 8) & 0x3; uint privilege = (addr >> 8) & 0x3;
return privilege <= cpu->csr.privilege; 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_CYCLE: return cpu->clock;
case CSR_MHARTID: return 0; case CSR_MHARTID: return 0;
case CSR_SATP: return (cpu->mmu.mode << 31) | cpu->mmu.ppn; 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]; default: return cpu->csr.data[address & 0xffff];
} }
} }
void write_csr_raw(cpu_t *cpu, uint address, uint value) { void write_csr_raw(cpu_t *cpu, uint address, uint value) {
switch (address) { switch (address) {
case CSR_SSTATUS: case CSR_SSTATUS:
cpu->csr.data[CSR_MSTATUS] &= ~0x000de162; 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 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 dst = mmu_translate(&ins, cpu->csr.data[CSR_MEMOP_DST], MMU_ACCESS_WRITE);
uint n = cpu->csr.data[CSR_MEMOP_N]; 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; 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; default: cpu->csr.data[address] = value; break;
}; };
} }

View File

@ -3,12 +3,15 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/time.h>
#include <math.h>
#include "types.h" #include "types.h"
#include "ins.h" #include "ins.h"
#include "mem.h" #include "mem.h"
#include "mmu.h" #include "mmu.h"
#include "trap.h" #include "trap.h"
#include "csr.h" #include "csr.h"
#include "net.h"
#include "pngout.h" #include "pngout.h"
static int ebreak_png = 0; static int ebreak_png = 0;
@ -202,10 +205,12 @@ DEF(divu, FormatR, { // rv32m
} }
WR_RD(result) WR_RD(result)
}) })
extern void cpu_dump(cpu_t *cpu);
DEF(ebreak, FormatEmpty, { // system DEF(ebreak, FormatEmpty, { // system
printf("EBREAK!\n"); printf("EBREAK!\n");
VERBOSE=4; cpu_dump(cpu);
SINGLE_STEP=1; /* VERBOSE=4; */
/* SINGLE_STEP=1; */
/* char buf[12]; */ /* char buf[12]; */
/* sprintf(buf, "ram_%d.png", ebreak_png++); */ /* sprintf(buf, "ram_%d.png", ebreak_png++); */
/* int ret = write_ram_as_png(buf); */ /* 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) { void emulate(cpu_t *cpu) {
bool net_has_data;
uint8_t *net_data;
uint32_t net_data_len;
uint ins_word = 0; uint ins_word = 0;
ins_ret ret = ins_ret_noop(cpu); ins_ret ret = ins_ret_noop(cpu);
if ((cpu->pc & 0x3) == 0) { if ((cpu->pc & 0x3) == 0) {
@ -624,19 +633,38 @@ void emulate(cpu_t *cpu) {
cpu->csr.data[CSR_MIP] |= MIP_MSIP; cpu->csr.data[CSR_MIP] |= MIP_MSIP;
} }
cpu->clint.mtime_lo++; double mtime = _Time * 1000000.0 / 20.0 * 0.1;
cpu->clint.mtime_hi += cpu->clint.mtime_lo == 0 ? 1 : 0; 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))) { 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; 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); printf("timer irq: %d >= %d\n", cpu->clint.mtime_lo, cpu->clint.mtimecmp_lo);
} }
uart_tick(cpu); uart_tick(cpu);
if (cpu->uart.interrupting) { uint cur_mip = read_csr_raw(cpu, CSR_MIP);
uint cur_mip = read_csr_raw(cpu, CSR_MIP); if (!(cur_mip & MIP_SEIP)) {
write_csr_raw(cpu, CSR_MIP, 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); handle_irq_and_trap(cpu, &ret);

View File

@ -8,9 +8,11 @@
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <time.h> #include <time.h>
#include <sys/time.h>
#include "types.h" #include "types.h"
#include "cpu.h" #include "cpu.h"
#include "uart.h" #include "uart.h"
#include "net.h"
#include <termios.h> #include <termios.h>
#include "../elfy/elfy.h" #include "../elfy/elfy.h"
@ -59,30 +61,47 @@ uint8_t* get_mmap_ptr(const char* filename) {
} }
void usage() { void usage() {
printf("Usage: rvc (-e <ELF binary>|-b <raw binary>) [-d <device tree binary>] [-i <initramfs>] [-v (0|1|2|3|4)] [-s] [-t] [-x]\n"); printf("Usage: rvc (-e <ELF binary>|-b <raw binary>) [-d <device tree binary>] [-i <initramfs>] [-v (0|1|2|3|4)] [-s (single step)] [-t (trace)] [-x (allow exit ecall)] [-f (signal forward)] [-n <server socket path> / -N <client socket path>]\n");
exit(EXIT_FAILURE); 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) void term(int signum)
{ {
printf("\n\nCaught signal!\n"); if (signal_forward) {
buf_on(); time_t cur_time = time(NULL);
cpu_dump(&cpu); if (cur_time - last_signal_time >= 1) {
printf("\n"); 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; */ printf("\n\nCaught signal!\n");
/* for (uint i = 0x10000; i < 0x11000; i += 4) { */ buf_on();
/* uint pa = mmu_translate(&ret, i, MMU_ACCESS_READ); */ cpu_dump(&cpu);
/* uint val = mem_get_word(&cpu, pa); */ printf("\n");
/* printf("%05x: %08x\n", i, val); */
/* } */
/* 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"); */ /* write_ram_as_png("ram.png"); */
exit(EXIT_FAILURE);
/* printf("\n"); */
exit(EXIT_FAILURE);
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -92,12 +111,18 @@ int main(int argc, char *argv[]) {
char *initrd = NULL; char *initrd = NULL;
uint mtd_size = 0; uint mtd_size = 0;
char *socket = NULL;
bool server = false;
int c; int c;
bool trace = false; 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) switch (c)
{ {
case 'f':
signal_forward = true;
break;
case 'x': case 'x':
allow_ecall_exit = true; allow_ecall_exit = true;
break; break;
@ -122,6 +147,14 @@ int main(int argc, char *argv[]) {
case 'i': case 'i':
initrd = optarg; initrd = optarg;
break; break;
case 'n':
socket = optarg;
server = true;
break;
case 'N':
socket = optarg;
server = false;
break;
case '?': case '?':
default: default:
usage(); usage();
@ -133,6 +166,7 @@ int main(int argc, char *argv[]) {
} }
uint8_t *mem = malloc(MEM_SIZE); uint8_t *mem = malloc(MEM_SIZE);
memset(mem, 0, MEM_SIZE);
if (elf) { if (elf) {
if (load_elf(elf, strlen(elf) + 1, mem, MEM_SIZE, VERBOSE >= 1)) { if (load_elf(elf, strlen(elf) + 1, mem, MEM_SIZE, VERBOSE >= 1)) {
exit(EXIT_FAILURE+1); exit(EXIT_FAILURE+1);
@ -150,6 +184,10 @@ int main(int argc, char *argv[]) {
memcpy(mtd, mtd_ptr, mtd_size); memcpy(mtd, mtd_ptr, mtd_size);
} }
if (socket) {
net_init(socket, server);
}
struct sigaction action; struct sigaction action;
memset(&action, 0, sizeof(action)); memset(&action, 0, sizeof(action));
action.sa_handler = term; action.sa_handler = term;
@ -170,12 +208,16 @@ int main(int argc, char *argv[]) {
buf_off(); buf_off();
// LIMITER (set to high number to ignore) // 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 cur = 0;
unsigned long t = time(NULL); unsigned long t = time(NULL);
uint init_verbose = VERBOSE; uint init_verbose = VERBOSE;
struct timeval now;
gettimeofday(&now, NULL);
uint64_t base_clock = now.tv_sec;
while (1) { while (1) {
cur++; cur++;
unsigned long t2 = time(NULL); unsigned long t2 = time(NULL);
@ -187,6 +229,10 @@ int main(int argc, char *argv[]) {
continue; 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); cpu_tick(&cpu);
if (trace) if (trace)
@ -226,8 +272,24 @@ int main(int argc, char *argv[]) {
cpu_dump(&cpu); cpu_dump(&cpu);
char input = 0; char input = 0;
if (!SINGLE_STEP && !uart_input_value && read(0, &input, 1)) { if (!SINGLE_STEP && input_stack_idx < MAX_INPUT_STACK && read(0, &input, 1)) {
uart_input_value = input; /* 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) { if (SINGLE_STEP) {

352
src/mem.h
View File

@ -5,96 +5,113 @@
#include <assert.h> #include <assert.h>
#include "types.h" #include "types.h"
#include "uart.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 // little endian, zero extended
uint do_mem_get_byte(cpu_t *cpu, uint addr) { 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) { 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) { 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; 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) { 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); ((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) { void mem_set_byte(cpu_t *cpu, uint addr, uint val) {
if (VERBOSE >= 3) if (VERBOSE >= 3)
printf("mem_set_byte(%08x, %08x)\n", addr, val); 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) { if ((addr & 0x80000000) == 0) {
return; if (addr >= 0x11000000 && addr < 0x11001000) {
} if (VERBOSE >= 3)
printf("NETTX write @%08x/%04x = %08x\n", addr, addr - 0x11001000, val);
const int MEM_SIZE = 1024 * 1024 * 128; cpu->net.nettx[addr - 0x11000000] = val;
return;
addr = addr & 0x7FFFFFFF;
if (addr >= MEM_SIZE) {
if (VERBOSE >= 1) {
printf("WARN: out-of-bounds memory write @0x%08x\n", addr | 0x80000000);
} }
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) { void mem_set_half_word(cpu_t *cpu, uint addr, uint val) {

223
src/net.h Normal file
View File

@ -0,0 +1,223 @@
#ifndef NET_H
#define NET_H
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#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

73
src/rtc.h Normal file
View File

@ -0,0 +1,73 @@
#ifndef RTC_H
#define RTC_H
#include <stdio.h>
#include <time.h>
#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

View File

@ -45,8 +45,7 @@ const uint MIP_ALL = MIP_MEIP | MIP_MTIP | MIP_MSIP | MIP_SEIP | MIP_STIP | MIP_
#include "csr.h" #include "csr.h"
// returns true if IRQ was handled or !is_interrupt // returns true if IRQ was handled or !is_interrupt
bool handle_trap(cpu_t *cpu, ins_ret *ret, bool is_interrupt) { bool handle_trap(cpu_t *cpu, ins_ret *ret, trap t, bool is_interrupt) {
trap t = ret->trap;
uint current_privilege = cpu->csr.privilege; uint current_privilege = cpu->csr.privilege;
uint mdeleg = read_csr_raw(cpu, is_interrupt ? CSR_MIDELEG : CSR_MEDELEG); 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! // 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) { if (new_privilege == PRIV_MACHINE) {
uint mie = (mstatus >> 3) & 1; uint mie = (mstatus >> 3) & 1;
uint new_status = (mstatus & ~0x1888) | (mie << 7) | (current_privilege << 11); 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); 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); 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; return true;
} }
void handle_irq_and_trap(cpu_t *cpu, ins_ret *ret) { 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 mip_reset = MIP_ALL;
uint cur_mip = read_csr_raw(cpu, CSR_MIP); 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); 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; if (false) {}
switch (mirq & MIP_ALL) { #define HANDLE(mip, ttype) else if (mirq & mip) { mip_reset = mip; t.en = true; t.type = ttype; }
HANDLE(MIP_MEIP, trap_MachineExternalInterrupt) HANDLE(MIP_MEIP, trap_MachineExternalInterrupt)
HANDLE(MIP_MSIP, trap_MachineSoftwareInterrupt) HANDLE(MIP_MSIP, trap_MachineSoftwareInterrupt)
HANDLE(MIP_MTIP, trap_MachineTimerInterrupt) HANDLE(MIP_MTIP, trap_MachineTimerInterrupt)
HANDLE(MIP_SEIP, trap_SupervisorExternalInterrupt) HANDLE(MIP_SEIP, trap_SupervisorExternalInterrupt)
HANDLE(MIP_SSIP, trap_SupervisorSoftwareInterrupt) HANDLE(MIP_SSIP, trap_SupervisorSoftwareInterrupt)
HANDLE(MIP_STIP, trap_SupervisorTimerInterrupt) HANDLE(MIP_STIP, trap_SupervisorTimerInterrupt)
}
#undef HANDLE #undef HANDLE
} }
bool irq = mip_reset != MIP_ALL; if (t.en) {
if (trap || irq) { bool handled = handle_trap(cpu, ret, t, irq);
bool handled = handle_trap(cpu, ret, irq);
if (handled && irq) { if (handled && irq) {
// reset MIP value since IRQ was handled // reset MIP value if IRQ other than timer was handled
write_csr_raw(cpu, CSR_MIP, cur_mip & ~mip_reset); // (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) if (VERBOSE >= 3)
printf("IRQ handled: old_mip=%03x new_mip=%03x\n", cur_mip, read_csr_raw(cpu, CSR_MIP)); printf("IRQ handled: old_mip=%03x new_mip=%03x\n", cur_mip, read_csr_raw(cpu, CSR_MIP));
} }

View File

@ -11,6 +11,8 @@ static bool SINGLE_STEP = false;
typedef uint32_t uint; typedef uint32_t uint;
typedef uint32_t uint; typedef uint32_t uint;
static float _Time;
typedef struct { typedef struct {
uint data[4096]; uint data[4096];
uint privilege; uint privilege;
@ -36,6 +38,12 @@ typedef struct {
uint ppn; uint ppn;
} mmu_state; } mmu_state;
typedef struct {
uint rx_ready;
uint8_t *nettx;
uint8_t *netrx;
} net_state;
typedef struct { typedef struct {
uint clock; uint clock;
uint xreg[32]; uint xreg[32];
@ -48,6 +56,10 @@ typedef struct {
clint_state clint; clint_state clint;
uart_state uart; uart_state uart;
mmu_state mmu; mmu_state mmu;
net_state net;
uint rtc0, rtc1;
float start_time_ref;
bool reservation_en; bool reservation_en;
uint reservation_addr; uint reservation_addr;

23
test.c Normal file
View File

@ -0,0 +1,23 @@
#include <stdio.h>
#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;
}

View File

@ -113,8 +113,8 @@ fn main() {
let y = idx / width; let y = idx / width;
println!("Saving result... (required size: x={} y={})", width, y + 1); println!("Saving result... (required size: x={} y={})", width, y + 1);
fr.save(input.clone().with_extension("r.bmp")).unwrap(); fr.save(input.clone().with_extension("r.png")).unwrap();
fg.save(input.clone().with_extension("g.bmp")).unwrap(); fg.save(input.clone().with_extension("g.png")).unwrap();
fb.save(input.clone().with_extension("b.bmp")).unwrap(); fb.save(input.clone().with_extension("b.png")).unwrap();
fa.save(input.clone().with_extension("a.bmp")).unwrap(); fa.save(input.clone().with_extension("a.png")).unwrap();
} }