Skip to content

Instantly share code, notes, and snippets.

@iamgreaser
Last active April 21, 2024 09:04
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iamgreaser/15a0a81cd117d4efd1c47ce598c13c91 to your computer and use it in GitHub Desktop.
Save iamgreaser/15a0a81cd117d4efd1c47ce598c13c91 to your computer and use it in GitHub Desktop.
RV64 QEMU virt VGA mode 13h
// 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
#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;
}
}
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
}
@fpetrot
Copy link

fpetrot commented Feb 1, 2023

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment