Last active
April 21, 2024 09:04
-
-
Save iamgreaser/15a0a81cd117d4efd1c47ce598c13c91 to your computer and use it in GitHub Desktop.
RV64 QEMU virt VGA mode 13h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// riscv64-elf-gcc -Os -mcmodel=medany -nostdlib -march=rv64gc -Wl,-T,qemu.ld -o vga-hello.elf boot.S main.c | |
// qemu-system-riscv64 -machine virt -device VGA -smp 1 -kernel vga-hello.elf | |
.section .text | |
.global _start | |
.global _enter | |
_start: | |
_enter: | |
//1: j 1b | |
.option push | |
.option norelax | |
la gp, __global_pointer$ | |
.option pop | |
// Set an early trap | |
la t0, trap_hcf | |
csrw mtvec, t0 | |
// If this isn't hart 0, lock up. | |
csrr t0, mhartid | |
li t1, 0 | |
beq t0, t1, 2f | |
1: | |
wfi | |
j 1b | |
2: | |
// Set up a stack | |
.extern cmain_stack | |
la sp, cmain_stack+4096 | |
// PCI is at 0x30000000 | |
// VGA is at 00:01.0, using extended control regs (4096 bytes) | |
// TODO: Scan for Vendor ID / Product ID | |
la t0, 0x30000000|(1<<15)|(0<<12) | |
// Set up frame buffer | |
la t1, 0x50000008 | |
sw t1, 0x10(t0) | |
// Set up I/O | |
la t2, 0x40000000 | |
sw t2, 0x18(t0) | |
// Enable memory accesses for this device | |
lw a0, 0x04(t0) | |
ori a0, a0, 0x02 | |
sw a0, 0x04(t0) | |
lw a0, 0x04(t0) | |
// Set up video mode somehow | |
li t3, 0x60 // Enable LFB, enable 8-bit DAC | |
sh t3, 0x508(t2) | |
//1: wfi | |
//j 1b | |
// Set Mode 13h by hand | |
la a0, mode_13h_regs | |
addi a1, t2, 0x400-0xC0 | |
la t3, 0xC0 | |
1: | |
// Grab address | |
lbu a3, 0(a0) | |
beq a3, zero, 2f | |
add a2, a1, a3 | |
// Grab index and data | |
lb a4, 1(a0) | |
lbu a5, 2(a0) | |
// Advance a0 | |
addi a0, a0, 3 | |
// If this is for the attribute controller, | |
// treat it specially. | |
blt a3, t3, 3f | |
// If this is an external register, | |
// also treat it specially. | |
blt a4, zero, 4f | |
// Normal case | |
sb a4, 0(a2) | |
sb a5, 1(a2) | |
j 1b | |
3: | |
// The attribute controller is a special case | |
lb zero, 0xDA(a1) | |
sb a4, 0(a2) | |
sb a5, 0(a2) | |
j 1b | |
4: | |
// External registers are also special | |
// but not as special as the attribute controller | |
sb a5, 0(a2) | |
j 1b | |
2: | |
// Set up a palette | |
li t3, 0 | |
sb t3, 0x408(t2) | |
li t3, 0 | |
li t4, 256*3 | |
la a0, initial_palette | |
1: | |
lb t5, 0(a0) | |
sb t5, 0x409(t2) | |
addi a0, a0, 1 | |
addi t3, t3, 1 | |
bltu t3, t4, 1b | |
// Enable floats | |
la t0, 1<<13 | |
csrs mstatus, t0 | |
// Jump to c_main | |
.extern c_main | |
jal c_main | |
// Halt | |
1: wfi | |
j 1b | |
.align 3 | |
trap_hcf: | |
// Halt | |
1: wfi | |
j 1b | |
mode_13h_regs: | |
// Miscellaneous Output Register: | |
// Just a single port. | |
// But bit 0 determines whether we use 3Dx or 3Bx. | |
// So we need to set this early. | |
.byte 0xC2, 0xFF, 0x63 | |
// Sequencer: | |
// Disable reset here. | |
.byte 0xC4, 0x00, 0x00 | |
// Attributes: | |
// - Read 3DA to reset flip-flop | |
// - Write 3C0 for address | |
// - Write 3C0 for data | |
.byte 0xC0, 0x00, 0x00 | |
.byte 0xC0, 0x01, 0x02 | |
.byte 0xC0, 0x02, 0x08 | |
.byte 0xC0, 0x03, 0x0A | |
.byte 0xC0, 0x04, 0x20 | |
.byte 0xC0, 0x05, 0x22 | |
.byte 0xC0, 0x06, 0x28 | |
.byte 0xC0, 0x07, 0x2A | |
.byte 0xC0, 0x08, 0x15 | |
.byte 0xC0, 0x09, 0x17 | |
.byte 0xC0, 0x0A, 0x1D | |
.byte 0xC0, 0x0B, 0x1F | |
.byte 0xC0, 0x0C, 0x35 | |
.byte 0xC0, 0x0D, 0x37 | |
.byte 0xC0, 0x0E, 0x3D | |
.byte 0xC0, 0x0F, 0x3F | |
.byte 0xC0, 0x30, 0x41 | |
.byte 0xC0, 0x31, 0x00 | |
.byte 0xC0, 0x32, 0x0F | |
.byte 0xC0, 0x33, 0x00 | |
.byte 0xC0, 0x34, 0x00 | |
// Graphics Mode | |
.byte 0xCE, 0x00, 0x00 | |
.byte 0xCE, 0x01, 0x00 | |
.byte 0xCE, 0x02, 0x00 | |
.byte 0xCE, 0x03, 0x00 | |
.byte 0xCE, 0x04, 0x00 | |
.byte 0xCE, 0x05, 0x40 | |
.byte 0xCE, 0x06, 0x05 | |
.byte 0xCE, 0x07, 0x00 | |
.byte 0xCE, 0x08, 0xFF | |
// CRTC | |
.byte 0xD4, 0x11, 0x0E // Do this to unprotect the registers | |
.byte 0xD4, 0x00, 0x5F | |
.byte 0xD4, 0x01, 0x4F | |
.byte 0xD4, 0x02, 0x50 | |
.byte 0xD4, 0x03, 0x82 | |
.byte 0xD4, 0x04, 0x54 | |
.byte 0xD4, 0x05, 0x80 | |
.byte 0xD4, 0x06, 0xBF | |
.byte 0xD4, 0x07, 0x1F | |
.byte 0xD4, 0x08, 0x00 | |
.byte 0xD4, 0x09, 0x41 | |
.byte 0xD4, 0x0A, 0x20 | |
.byte 0xD4, 0x0B, 0x1F | |
.byte 0xD4, 0x0C, 0x00 | |
.byte 0xD4, 0x0D, 0x00 | |
.byte 0xD4, 0x0E, 0xFF | |
.byte 0xD4, 0x0F, 0xFF | |
.byte 0xD4, 0x10, 0x9C | |
.byte 0xD4, 0x11, 0x8E // Registers are now reprotected | |
.byte 0xD4, 0x12, 0x8F | |
.byte 0xD4, 0x13, 0x28 | |
.byte 0xD4, 0x14, 0x40 | |
.byte 0xD4, 0x15, 0x96 | |
.byte 0xD4, 0x16, 0xB9 | |
.byte 0xD4, 0x17, 0xA3 | |
// Sequencer | |
.byte 0xC4, 0x01, 0x01 | |
.byte 0xC4, 0x02, 0x0F | |
.byte 0xC4, 0x03, 0x00 | |
.byte 0xC4, 0x04, 0x0E | |
.byte 0x00 | |
initial_palette: | |
.byte 0x00, 0x00, 0x00 | |
.byte 0x00, 0x00, 0x55 | |
.byte 0x00, 0x00, 0xAA | |
.byte 0x00, 0x00, 0xFF | |
.byte 0x00, 0x55, 0x00 | |
.byte 0x00, 0x55, 0x55 | |
.byte 0x00, 0x55, 0xAA | |
.byte 0x00, 0x55, 0xFF | |
.byte 0x00, 0xAA, 0x00 | |
.byte 0x00, 0xAA, 0x55 | |
.byte 0x00, 0xAA, 0xAA | |
.byte 0x00, 0xAA, 0xFF | |
.byte 0x00, 0xFF, 0x00 | |
.byte 0x00, 0xFF, 0x55 | |
.byte 0x00, 0xFF, 0xAA | |
.byte 0x00, 0xFF, 0xFF | |
.byte 0x55, 0x00, 0x00 | |
.byte 0x55, 0x00, 0x55 | |
.byte 0x55, 0x00, 0xAA | |
.byte 0x55, 0x00, 0xFF | |
.byte 0x55, 0x55, 0x00 | |
.byte 0x55, 0x55, 0x55 | |
.byte 0x55, 0x55, 0xAA | |
.byte 0x55, 0x55, 0xFF | |
.byte 0x55, 0xAA, 0x00 | |
.byte 0x55, 0xAA, 0x55 | |
.byte 0x55, 0xAA, 0xAA | |
.byte 0x55, 0xAA, 0xFF | |
.byte 0x55, 0xFF, 0x00 | |
.byte 0x55, 0xFF, 0x55 | |
.byte 0x55, 0xFF, 0xAA | |
.byte 0x55, 0xFF, 0xFF | |
.byte 0xAA, 0x00, 0x00 | |
.byte 0xAA, 0x00, 0x55 | |
.byte 0xAA, 0x00, 0xAA | |
.byte 0xAA, 0x00, 0xFF | |
.byte 0xAA, 0x55, 0x00 | |
.byte 0xAA, 0x55, 0x55 | |
.byte 0xAA, 0x55, 0xAA | |
.byte 0xAA, 0x55, 0xFF | |
.byte 0xAA, 0xAA, 0x00 | |
.byte 0xAA, 0xAA, 0x55 | |
.byte 0xAA, 0xAA, 0xAA | |
.byte 0xAA, 0xAA, 0xFF | |
.byte 0xAA, 0xFF, 0x00 | |
.byte 0xAA, 0xFF, 0x55 | |
.byte 0xAA, 0xFF, 0xAA | |
.byte 0xAA, 0xFF, 0xFF | |
.byte 0xFF, 0x00, 0x00 | |
.byte 0xFF, 0x00, 0x55 | |
.byte 0xFF, 0x00, 0xAA | |
.byte 0xFF, 0x00, 0xFF | |
.byte 0xFF, 0x55, 0x00 | |
.byte 0xFF, 0x55, 0x55 | |
.byte 0xFF, 0x55, 0xAA | |
.byte 0xFF, 0x55, 0xFF | |
.byte 0xFF, 0xAA, 0x00 | |
.byte 0xFF, 0xAA, 0x55 | |
.byte 0xFF, 0xAA, 0xAA | |
.byte 0xFF, 0xAA, 0xFF | |
.byte 0xFF, 0xFF, 0x00 | |
.byte 0xFF, 0xFF, 0x55 | |
.byte 0xFF, 0xFF, 0xAA | |
.byte 0xFF, 0xFF, 0xFF | |
.byte 0x00, 0x00, 0x00 | |
.byte 0x00, 0x00, 0x55 | |
.byte 0x00, 0x00, 0xAA | |
.byte 0x00, 0x00, 0xFF | |
.byte 0x00, 0x55, 0x00 | |
.byte 0x00, 0x55, 0x55 | |
.byte 0x00, 0x55, 0xAA | |
.byte 0x00, 0x55, 0xFF | |
.byte 0x00, 0xAA, 0x00 | |
.byte 0x00, 0xAA, 0x55 | |
.byte 0x00, 0xAA, 0xAA | |
.byte 0x00, 0xAA, 0xFF | |
.byte 0x00, 0xFF, 0x00 | |
.byte 0x00, 0xFF, 0x55 | |
.byte 0x00, 0xFF, 0xAA | |
.byte 0x00, 0xFF, 0xFF | |
.byte 0x55, 0x00, 0x00 | |
.byte 0x55, 0x00, 0x55 | |
.byte 0x55, 0x00, 0xAA | |
.byte 0x55, 0x00, 0xFF | |
.byte 0x55, 0x55, 0x00 | |
.byte 0x55, 0x55, 0x55 | |
.byte 0x55, 0x55, 0xAA | |
.byte 0x55, 0x55, 0xFF | |
.byte 0x55, 0xAA, 0x00 | |
.byte 0x55, 0xAA, 0x55 | |
.byte 0x55, 0xAA, 0xAA | |
.byte 0x55, 0xAA, 0xFF | |
.byte 0x55, 0xFF, 0x00 | |
.byte 0x55, 0xFF, 0x55 | |
.byte 0x55, 0xFF, 0xAA | |
.byte 0x55, 0xFF, 0xFF | |
.byte 0xAA, 0x00, 0x00 | |
.byte 0xAA, 0x00, 0x55 | |
.byte 0xAA, 0x00, 0xAA | |
.byte 0xAA, 0x00, 0xFF | |
.byte 0xAA, 0x55, 0x00 | |
.byte 0xAA, 0x55, 0x55 | |
.byte 0xAA, 0x55, 0xAA | |
.byte 0xAA, 0x55, 0xFF | |
.byte 0xAA, 0xAA, 0x00 | |
.byte 0xAA, 0xAA, 0x55 | |
.byte 0xAA, 0xAA, 0xAA | |
.byte 0xAA, 0xAA, 0xFF | |
.byte 0xAA, 0xFF, 0x00 | |
.byte 0xAA, 0xFF, 0x55 | |
.byte 0xAA, 0xFF, 0xAA | |
.byte 0xAA, 0xFF, 0xFF | |
.byte 0xFF, 0x00, 0x00 | |
.byte 0xFF, 0x00, 0x55 | |
.byte 0xFF, 0x00, 0xAA | |
.byte 0xFF, 0x00, 0xFF | |
.byte 0xFF, 0x55, 0x00 | |
.byte 0xFF, 0x55, 0x55 | |
.byte 0xFF, 0x55, 0xAA | |
.byte 0xFF, 0x55, 0xFF | |
.byte 0xFF, 0xAA, 0x00 | |
.byte 0xFF, 0xAA, 0x55 | |
.byte 0xFF, 0xAA, 0xAA | |
.byte 0xFF, 0xAA, 0xFF | |
.byte 0xFF, 0xFF, 0x00 | |
.byte 0xFF, 0xFF, 0x55 | |
.byte 0xFF, 0xFF, 0xAA | |
.byte 0xFF, 0xFF, 0xFF | |
.byte 0x00, 0x00, 0x00 | |
.byte 0x00, 0x00, 0x55 | |
.byte 0x00, 0x00, 0xAA | |
.byte 0x00, 0x00, 0xFF | |
.byte 0x00, 0x55, 0x00 | |
.byte 0x00, 0x55, 0x55 | |
.byte 0x00, 0x55, 0xAA | |
.byte 0x00, 0x55, 0xFF | |
.byte 0x00, 0xAA, 0x00 | |
.byte 0x00, 0xAA, 0x55 | |
.byte 0x00, 0xAA, 0xAA | |
.byte 0x00, 0xAA, 0xFF | |
.byte 0x00, 0xFF, 0x00 | |
.byte 0x00, 0xFF, 0x55 | |
.byte 0x00, 0xFF, 0xAA | |
.byte 0x00, 0xFF, 0xFF | |
.byte 0x55, 0x00, 0x00 | |
.byte 0x55, 0x00, 0x55 | |
.byte 0x55, 0x00, 0xAA | |
.byte 0x55, 0x00, 0xFF | |
.byte 0x55, 0x55, 0x00 | |
.byte 0x55, 0x55, 0x55 | |
.byte 0x55, 0x55, 0xAA | |
.byte 0x55, 0x55, 0xFF | |
.byte 0x55, 0xAA, 0x00 | |
.byte 0x55, 0xAA, 0x55 | |
.byte 0x55, 0xAA, 0xAA | |
.byte 0x55, 0xAA, 0xFF | |
.byte 0x55, 0xFF, 0x00 | |
.byte 0x55, 0xFF, 0x55 | |
.byte 0x55, 0xFF, 0xAA | |
.byte 0x55, 0xFF, 0xFF | |
.byte 0xAA, 0x00, 0x00 | |
.byte 0xAA, 0x00, 0x55 | |
.byte 0xAA, 0x00, 0xAA | |
.byte 0xAA, 0x00, 0xFF | |
.byte 0xAA, 0x55, 0x00 | |
.byte 0xAA, 0x55, 0x55 | |
.byte 0xAA, 0x55, 0xAA | |
.byte 0xAA, 0x55, 0xFF | |
.byte 0xAA, 0xAA, 0x00 | |
.byte 0xAA, 0xAA, 0x55 | |
.byte 0xAA, 0xAA, 0xAA | |
.byte 0xAA, 0xAA, 0xFF | |
.byte 0xAA, 0xFF, 0x00 | |
.byte 0xAA, 0xFF, 0x55 | |
.byte 0xAA, 0xFF, 0xAA | |
.byte 0xAA, 0xFF, 0xFF | |
.byte 0xFF, 0x00, 0x00 | |
.byte 0xFF, 0x00, 0x55 | |
.byte 0xFF, 0x00, 0xAA | |
.byte 0xFF, 0x00, 0xFF | |
.byte 0xFF, 0x55, 0x00 | |
.byte 0xFF, 0x55, 0x55 | |
.byte 0xFF, 0x55, 0xAA | |
.byte 0xFF, 0x55, 0xFF | |
.byte 0xFF, 0xAA, 0x00 | |
.byte 0xFF, 0xAA, 0x55 | |
.byte 0xFF, 0xAA, 0xAA | |
.byte 0xFF, 0xAA, 0xFF | |
.byte 0xFF, 0xFF, 0x00 | |
.byte 0xFF, 0xFF, 0x55 | |
.byte 0xFF, 0xFF, 0xAA | |
.byte 0xFF, 0xFF, 0xFF | |
.byte 0x00, 0x00, 0x00 | |
.byte 0x00, 0x00, 0x55 | |
.byte 0x00, 0x00, 0xAA | |
.byte 0x00, 0x00, 0xFF | |
.byte 0x00, 0x55, 0x00 | |
.byte 0x00, 0x55, 0x55 | |
.byte 0x00, 0x55, 0xAA | |
.byte 0x00, 0x55, 0xFF | |
.byte 0x00, 0xAA, 0x00 | |
.byte 0x00, 0xAA, 0x55 | |
.byte 0x00, 0xAA, 0xAA | |
.byte 0x00, 0xAA, 0xFF | |
.byte 0x00, 0xFF, 0x00 | |
.byte 0x00, 0xFF, 0x55 | |
.byte 0x00, 0xFF, 0xAA | |
.byte 0x00, 0xFF, 0xFF | |
.byte 0x55, 0x00, 0x00 | |
.byte 0x55, 0x00, 0x55 | |
.byte 0x55, 0x00, 0xAA | |
.byte 0x55, 0x00, 0xFF | |
.byte 0x55, 0x55, 0x00 | |
.byte 0x55, 0x55, 0x55 | |
.byte 0x55, 0x55, 0xAA | |
.byte 0x55, 0x55, 0xFF | |
.byte 0x55, 0xAA, 0x00 | |
.byte 0x55, 0xAA, 0x55 | |
.byte 0x55, 0xAA, 0xAA | |
.byte 0x55, 0xAA, 0xFF | |
.byte 0x55, 0xFF, 0x00 | |
.byte 0x55, 0xFF, 0x55 | |
.byte 0x55, 0xFF, 0xAA | |
.byte 0x55, 0xFF, 0xFF | |
.byte 0xAA, 0x00, 0x00 | |
.byte 0xAA, 0x00, 0x55 | |
.byte 0xAA, 0x00, 0xAA | |
.byte 0xAA, 0x00, 0xFF | |
.byte 0xAA, 0x55, 0x00 | |
.byte 0xAA, 0x55, 0x55 | |
.byte 0xAA, 0x55, 0xAA | |
.byte 0xAA, 0x55, 0xFF | |
.byte 0xAA, 0xAA, 0x00 | |
.byte 0xAA, 0xAA, 0x55 | |
.byte 0xAA, 0xAA, 0xAA | |
.byte 0xAA, 0xAA, 0xFF | |
.byte 0xAA, 0xFF, 0x00 | |
.byte 0xAA, 0xFF, 0x55 | |
.byte 0xAA, 0xFF, 0xAA | |
.byte 0xAA, 0xFF, 0xFF | |
.byte 0xFF, 0x00, 0x00 | |
.byte 0xFF, 0x00, 0x55 | |
.byte 0xFF, 0x00, 0xAA | |
.byte 0xFF, 0x00, 0xFF | |
.byte 0xFF, 0x55, 0x00 | |
.byte 0xFF, 0x55, 0x55 | |
.byte 0xFF, 0x55, 0xAA | |
.byte 0xFF, 0x55, 0xFF | |
.byte 0xFF, 0xAA, 0x00 | |
.byte 0xFF, 0xAA, 0x55 | |
.byte 0xFF, 0xAA, 0xAA | |
.byte 0xFF, 0xAA, 0xFF | |
.byte 0xFF, 0xFF, 0x00 | |
.byte 0xFF, 0xFF, 0x55 | |
.byte 0xFF, 0xFF, 0xAA | |
.byte 0xFF, 0xFF, 0xFF |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdbool.h> | |
#include <stddef.h> | |
#include <stdint.h> | |
#define VRAM ((volatile uint8_t *)0x50000000) | |
uintptr_t cmain_stack[4096/sizeof(uintptr_t)]; | |
int mandelbrot(float cr, float ci) | |
{ | |
uint32_t reps = 0; | |
float zr = 0.0f; | |
float zi = 0.0f; | |
for ( ; reps < 256; reps++ ) { | |
float tr = zr*zr - zi*zi; | |
float ti = 2.0f*zr*zi; | |
zr = tr + cr; | |
zi = ti + ci; | |
if ( zr*zr + zi*zi >= 2.0f*2.0f ) { | |
break; | |
} | |
} | |
return reps; | |
} | |
void c_main(void) | |
{ | |
float zoom = 4.0f; | |
for ( ;; ) { | |
float ci_delta = zoom/200.0f; | |
float cr_delta = zoom/200.0f; | |
float initial_cr = -0.598f + cr_delta*-160; | |
float initial_ci = -0.665f + ci_delta*-100; | |
// Do initial render | |
{ | |
float ci = initial_ci; | |
for ( uint32_t y = 0, i = 0; y < 200; y += 4 ) { | |
float cr = initial_cr; | |
for ( uint32_t x = 0; x < 320; x += 4 ) { | |
int reps = mandelbrot(cr, ci); | |
VRAM[y*320+x] = reps; | |
cr += cr_delta*4; | |
} | |
ci += ci_delta*4; | |
} | |
} | |
#if 0 | |
// Fill in horizontally 8->4 | |
{ | |
float ci = initial_ci; | |
for ( uint32_t y = 0, i = 0; y < 200; y += 8 ) { | |
float cr = initial_cr+ci_delta*4; | |
for ( uint32_t x = 0; x < 320; x += 8 ) { | |
int reps = mandelbrot(cr, ci); | |
int r0 = VRAM[(y+0)*320+(x+0)]; | |
int r1 = (x+8 >= 320 ? r0+1 : VRAM[(y+0)*320+(x+8)]); | |
if ( r0 != r1 ) { | |
VRAM[(y+0)*320+(x+4)] = reps; | |
} else { | |
VRAM[(y+0)*320+(x+4)] = r0; | |
} | |
cr += cr_delta*8; | |
} | |
ci += ci_delta*8; | |
} | |
} | |
// Fill in vertically 8->4 | |
{ | |
float ci = initial_ci+cr_delta*4; | |
for ( uint32_t y = 0, i = 0; y < 200; y += 8 ) { | |
float cr = initial_cr; | |
for ( uint32_t x = 0; x < 320; x += 4 ) { | |
int reps = mandelbrot(cr, ci); | |
int r0 = VRAM[(y+0)*320+(x+0)]; | |
int r1 = (y+8 >= 200 ? r0+1 : VRAM[(y+8)*320+(x+0)]); | |
if ( r0 != r1 ) { | |
VRAM[(y+4)*320+(x+0)] = reps; | |
} else { | |
VRAM[(y+4)*320+(x+0)] = r0; | |
} | |
cr += cr_delta*4; | |
} | |
ci += ci_delta*8; | |
} | |
} | |
#endif | |
// Fill in horizontally 4->2 | |
{ | |
float ci = initial_ci; | |
for ( uint32_t y = 0, i = 0; y < 200; y += 4 ) { | |
float cr = initial_cr+ci_delta*2; | |
for ( uint32_t x = 0; x < 320; x += 4 ) { | |
int reps = mandelbrot(cr, ci); | |
int r0 = VRAM[(y+0)*320+(x+0)]; | |
int r1 = (x+4 >= 320 ? r0+1 : VRAM[(y+0)*320+(x+4)]); | |
if ( r0 != r1 ) { | |
VRAM[(y+0)*320+(x+2)] = reps; | |
} else { | |
VRAM[(y+0)*320+(x+2)] = r0; | |
} | |
cr += cr_delta*4; | |
} | |
ci += ci_delta*4; | |
} | |
} | |
// Fill in vertically 4->2 | |
{ | |
float ci = initial_ci+cr_delta*2; | |
for ( uint32_t y = 0, i = 0; y < 200; y += 4 ) { | |
float cr = initial_cr; | |
for ( uint32_t x = 0; x < 320; x += 2 ) { | |
int reps = mandelbrot(cr, ci); | |
int r0 = VRAM[(y+0)*320+(x+0)]; | |
int r1 = (y+4 >= 200 ? r0+1 : VRAM[(y+4)*320+(x+0)]); | |
if ( r0 != r1 ) { | |
VRAM[(y+2)*320+(x+0)] = reps; | |
} else { | |
VRAM[(y+2)*320+(x+0)] = r0; | |
} | |
cr += cr_delta*2; | |
} | |
ci += ci_delta*4; | |
} | |
} | |
// Fill in horizontally 2->1 | |
{ | |
float ci = initial_ci; | |
for ( uint32_t y = 0, i = 0; y < 200; y += 2 ) { | |
float cr = initial_cr+cr_delta; | |
for ( uint32_t x = 0; x < 320; x += 2 ) { | |
int reps = mandelbrot(cr, ci); | |
int r0 = VRAM[(y+0)*320+(x+0)]; | |
int r1 = (x+2 >= 320 ? r0+1 : VRAM[(y+0)*320+(x+2)]); | |
if ( r0 != r1 ) { | |
VRAM[(y+0)*320+(x+1)] = reps; | |
} else { | |
VRAM[(y+0)*320+(x+1)] = r0; | |
} | |
cr += cr_delta*2; | |
} | |
ci += ci_delta*2; | |
} | |
} | |
// Fill in vertically 2->1 | |
{ | |
float ci = initial_ci+ci_delta; | |
for ( uint32_t y = 0, i = 0; y < 200; y += 2 ) { | |
float cr = initial_cr; | |
for ( uint32_t x = 0; x < 320; x += 1 ) { | |
int reps = mandelbrot(cr, ci); | |
int r0 = VRAM[(y+0)*320+(x+0)]; | |
int r1 = (y+2 >= 200 ? r0+1 : VRAM[(y+2)*320+(x+0)]); | |
if ( r0 != r1 ) { | |
VRAM[(y+1)*320+(x+0)] = reps; | |
} else { | |
VRAM[(y+1)*320+(x+0)] = r0; | |
} | |
cr += cr_delta; | |
} | |
ci += ci_delta*2; | |
} | |
} | |
zoom *= 0.99f; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
OUTPUT_ARCH("riscv") | |
ENTRY(_enter) | |
MEMORY | |
{ | |
ram (rwxai) : ORIGIN = 0x80000000, LENGTH = 0x1000000 | |
} | |
PHDRS | |
{ | |
flash PT_LOAD; | |
ram PT_LOAD; | |
ram_init PT_LOAD; | |
itim PT_LOAD; | |
itim_init PT_LOAD; | |
} | |
SECTIONS | |
{ | |
__stack_size = DEFINED(__stack_size) ? __stack_size : 0x400; | |
PROVIDE(__stack_size = __stack_size); | |
__heap_size = DEFINED(__heap_size) ? __heap_size : 0x800; | |
PROVIDE(__metal_boot_hart = 0); | |
PROVIDE(__metal_chicken_bit = 0); | |
.init : { | |
KEEP (*(.text.metal.init.enter)) | |
KEEP (*(.text.metal.init.*)) | |
KEEP (*(SORT_NONE(.init))) | |
KEEP (*(.text.libgloss.start)) | |
} >ram AT>ram :flash | |
.fini : { | |
KEEP (*(SORT_NONE(.fini))) | |
} >ram AT>ram :flash | |
.text : { | |
*(.text.unlikely .text.unlikely.*) | |
*(.text.startup .text.startup.*) | |
*(.text .text.*) | |
*(.gnu.linkonce.t.*) | |
} >ram AT>ram :flash | |
PROVIDE (__etext = .); | |
PROVIDE (_etext = .); | |
PROVIDE (etext = .); | |
.rodata : { | |
*(.rdata) | |
*(.rodata .rodata.*) | |
*(.gnu.linkonce.r.*) | |
. = ALIGN(8); | |
*(.srodata.cst16) | |
*(.srodata.cst8) | |
*(.srodata.cst4) | |
*(.srodata.cst2) | |
*(.srodata .srodata.*) | |
} >ram AT>ram :flash | |
. = ALIGN(8); | |
.preinit_array : { | |
PROVIDE_HIDDEN (__preinit_array_start = .); | |
KEEP (*(.preinit_array)) | |
PROVIDE_HIDDEN (__preinit_array_end = .); | |
} >ram AT>ram :flash | |
.init_array : { | |
PROVIDE_HIDDEN (__init_array_start = .); | |
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) | |
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) | |
PROVIDE_HIDDEN (__init_array_end = .); | |
} >ram AT>ram :flash | |
.fini_array : { | |
PROVIDE_HIDDEN (__fini_array_start = .); | |
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) | |
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) | |
PROVIDE_HIDDEN (__fini_array_end = .); | |
} >ram AT>ram :flash | |
.ctors : { | |
KEEP (*crtbegin.o(.ctors)) | |
KEEP (*crtbegin?.o(.ctors)) | |
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) | |
KEEP (*(SORT(.ctors.*))) | |
KEEP (*(.ctors)) | |
} >ram AT>ram :flash | |
.dtors : { | |
KEEP (*crtbegin.o(.dtors)) | |
KEEP (*crtbegin?.o(.dtors)) | |
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) | |
KEEP (*(SORT(.dtors.*))) | |
KEEP (*(.dtors)) | |
} >ram AT>ram :flash | |
.itim : ALIGN(8) { | |
*(.itim .itim.*) | |
} >ram AT>ram :itim_init | |
PROVIDE( metal_segment_itim_source_start = LOADADDR(.itim) ); | |
PROVIDE( metal_segment_itim_target_start = ADDR(.itim) ); | |
PROVIDE( metal_segment_itim_target_end = ADDR(.itim) + SIZEOF(.itim) ); | |
.data : ALIGN(8) { | |
*(.data .data.*) | |
*(.gnu.linkonce.d.*) | |
. = ALIGN(8); | |
PROVIDE( __global_pointer$ = . + 0x800 ); | |
*(.sdata .sdata.* .sdata2.*) | |
*(.gnu.linkonce.s.*) | |
. = ALIGN(8); | |
*(.srodata.cst16) | |
*(.srodata.cst8) | |
*(.srodata.cst4) | |
*(.srodata.cst2) | |
*(.srodata .srodata.*) | |
. = ALIGN(8); | |
*(.rdata) | |
*(.rodata .rodata.*) | |
*(.gnu.linkonce.r.*) | |
} >ram AT>ram :ram_init | |
PROVIDE( metal_segment_data_source_start = LOADADDR(.data) ); | |
PROVIDE( metal_segment_data_target_start = ADDR(.data) ); | |
PROVIDE( metal_segment_data_target_end = ADDR(.data) + SIZEOF(.data) ); | |
.bss : ALIGN(8) { | |
*(.sbss*) | |
*(.gnu.linkonce.sb.*) | |
*(.bss .bss.*) | |
*(.gnu.linkonce.b.*) | |
*(COMMON) | |
} >ram AT>ram :ram | |
PROVIDE( metal_segment_bss_target_start = ADDR(.bss) ); | |
PROVIDE( metal_segment_bss_target_end = ADDR(.bss) + SIZEOF(.bss) ); | |
.stack : { | |
PROVIDE(metal_segment_stack_begin = .); | |
. += __stack_size; | |
PROVIDE( _sp = . ); | |
PROVIDE(metal_segment_stack_end = .); | |
} >ram AT>ram :ram | |
.heap : { | |
PROVIDE( metal_segment_heap_target_start = . ); | |
. = __heap_size; | |
PROVIDE( metal_segment_heap_target_end = . ); | |
PROVIDE( _heap_end = . ); | |
} >ram AT>ram :ram | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice ! Thx for sharing, you saved my (teaching) day.
A small fix for those that are not QEMU natives : add the
-bios none
option to QEMU command line to avoid the "qemu-system-riscv64: Some ROM regions are overlapping" message (may depend upon your qemu configuration) , i.e.:qemu-system-riscv64 -machine virt -device VGA -smp 1 -bios none -kernel vga-hello.elf