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
|
compile_commands.json
|
||||||
.ccls-cache
|
.ccls-cache
|
||||||
|
.cache
|
||||||
elfy/.ccls-cache
|
elfy/.ccls-cache
|
||||||
rvc
|
rvc
|
||||||
!rvc/
|
!rvc/
|
||||||
|
34
Makefile
@ -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:
|
||||||
|
@ -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:
|
||||||
|
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("\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
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
|
MEMORY
|
||||||
{
|
{
|
||||||
RAM : ORIGIN = 0x80000000, LENGTH = 31M
|
RAM : ORIGIN = 0x80000000, LENGTH = 60M
|
||||||
}
|
}
|
||||||
|
|
||||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||||
|
31
dts.dts
@ -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 {
|
||||||
|
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_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
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
|
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
@ -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 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");
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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 {
|
||||||
|
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);
|
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
@ -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 <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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
56
src/csr.h
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
44
src/emu.h
@ -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);
|
||||||
|
100
src/main.c
@ -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
@ -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
@ -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
|
41
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"
|
#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));
|
||||||
}
|
}
|
||||||
|
12
src/types.h
@ -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
@ -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;
|
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();
|
||||||
}
|
}
|
||||||
|