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
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
compile_commands.json
|
||||
.ccls-cache
|
||||
.cache
|
||||
elfy/.ccls-cache
|
||||
rvc
|
||||
!rvc/
|
||||
|
34
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:
|
||||
|
@ -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:
|
||||
|
BIN
bare_metal_test/bare.a.png
Normal file
After Width: | Height: | Size: 894 B |
BIN
bare_metal_test/bare.b.png
Normal file
After Width: | Height: | Size: 897 B |
@ -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");
|
||||
|
||||
|
BIN
bare_metal_test/bare.g.png
Normal file
After Width: | Height: | Size: 925 B |
BIN
bare_metal_test/bare.r.png
Normal file
After Width: | Height: | Size: 920 B |
@ -1,6 +1,6 @@
|
||||
MEMORY
|
||||
{
|
||||
RAM : ORIGIN = 0x80000000, LENGTH = 31M
|
||||
RAM : ORIGIN = 0x80000000, LENGTH = 60M
|
||||
}
|
||||
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
|
31
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 {
|
||||
|
119
guest-root/examples/pi.js
Normal 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
@ -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
@ -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
@ -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
|
@ -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
|
||||
|
49
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
|
||||
|
BIN
linux_payload.a.png
Normal file
After Width: | Height: | Size: 773 KiB |
BIN
linux_payload.b.png
Normal file
After Width: | Height: | Size: 774 KiB |
BIN
linux_payload.g.png
Normal file
After Width: | Height: | Size: 775 KiB |
BIN
linux_payload.r.png
Normal file
After Width: | Height: | Size: 774 KiB |
@ -1 +1 @@
|
||||
Subproject commit b4895fc56b16815d622b088d188ac65d640d25ab
|
||||
Subproject commit 8ee69d7a5dc7ef6d8b2bda96bf86d2923f2cf176
|
BIN
rust_raytrace.a.bmp.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
rust_raytrace.b.bmp.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
rust_raytrace.g.bmp.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
rust_raytrace.r.bmp.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
@ -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
|
||||
|
||||
}
|
||||
|
36
rust_raytrace/src/fb.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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,16 +46,25 @@ 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_usize(heap_start);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
44
rust_raytrace/src/output.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
238
rust_raytrace/src/text.rs
Normal 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" }
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
56
src/csr.h
@ -3,9 +3,11 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#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,8 +131,33 @@ 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;
|
||||
};
|
||||
|
40
src/emu.h
@ -3,12 +3,15 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <math.h>
|
||||
#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);
|
||||
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);
|
||||
|
74
src/main.c
@ -8,9 +8,11 @@
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include "types.h"
|
||||
#include "cpu.h"
|
||||
#include "uart.h"
|
||||
#include "net.h"
|
||||
#include <termios.h>
|
||||
|
||||
#include "../elfy/elfy.h"
|
||||
@ -59,12 +61,29 @@ uint8_t* get_mmap_ptr(const char* filename) {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n\nCaught signal!\n");
|
||||
buf_on();
|
||||
cpu_dump(&cpu);
|
||||
@ -79,7 +98,7 @@ void term(int signum)
|
||||
|
||||
/* print_tracebuf(); */
|
||||
|
||||
write_ram_as_png("ram.png");
|
||||
/* write_ram_as_png("ram.png"); */
|
||||
|
||||
/* printf("\n"); */
|
||||
exit(EXIT_FAILURE);
|
||||
@ -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) {
|
||||
|
62
src/mem.h
@ -5,21 +5,36 @@
|
||||
#include <assert.h>
|
||||
#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 ((addr & 0x80000000) == 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)) { */
|
||||
/* return cpu->mtd[addr - 0x40000000]; */
|
||||
/* } */
|
||||
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
|
||||
@ -82,10 +97,11 @@ uint do_mem_get_byte(cpu_t *cpu, uint addr) {
|
||||
/* case 0x80001047: return 0; */
|
||||
}
|
||||
|
||||
if ((addr & 0x80000000) == 0) {
|
||||
return 0;
|
||||
if (VERBOSE >= 1) {
|
||||
printf("WARN: out-of-bounds mmio read @0x%08x\n", addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
addr = addr & 0x7FFFFFFF;
|
||||
if (addr >= MEM_SIZE) {
|
||||
if (VERBOSE >= 1) {
|
||||
@ -96,6 +112,7 @@ uint do_mem_get_byte(cpu_t *cpu, uint addr) {
|
||||
|
||||
return cpu->mem[addr];
|
||||
}
|
||||
}
|
||||
|
||||
uint mem_get_byte(cpu_t *cpu, uint addr) {
|
||||
uint ret = do_mem_get_byte(cpu, addr);
|
||||
@ -117,10 +134,34 @@ 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);
|
||||
|
||||
if ((addr & 0x80000000) == 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
@ -187,11 +228,7 @@ void mem_set_byte(cpu_t *cpu, uint addr, uint val) {
|
||||
/* case 0x80001046: return; */
|
||||
/* case 0x80001047: return; */
|
||||
}
|
||||
|
||||
if ((addr & 0x80000000) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
const int MEM_SIZE = 1024 * 1024 * 128;
|
||||
|
||||
addr = addr & 0x7FFFFFFF;
|
||||
@ -203,6 +240,7 @@ void mem_set_byte(cpu_t *cpu, uint addr, uint val) {
|
||||
}
|
||||
cpu->mem[addr] = val;
|
||||
}
|
||||
}
|
||||
|
||||
void mem_set_half_word(cpu_t *cpu, uint addr, uint val) {
|
||||
/* assert((addr & ~(0x1)) == addr); */
|
||||
|
223
src/net.h
Normal 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
@ -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
|
27
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,36 +142,38 @@ 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) {
|
||||
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
|
||||
// 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));
|
||||
|
12
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;
|
||||
|
23
test.c
Normal 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;
|
||||
}
|
@ -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();
|
||||
}
|
||||
|