RISC-V QEMU で動作するベアメタルプログラム

RISC-V量子拡張は, 「RiscV.RV32IU」として @k_yamaz 蛙 が提案しています.
(詳しくは, 技術ブログ Qiita に投稿した RISC-Vの量子計算拡張 をご参照ください. )
思いつきなどをメモしていきます.

VSCode でビルドしたプログラムの動作がうまく行かないままですので, 自作でベアメタルプログラムのサンプルを作成します.

簡単なテストコードとして, 次の main.c を作成します.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define UART0DR (volatile unsigned char *) 0x10000000
#define PRINT_UART0(x) print_uart(UART0DR, x)

void print_uart(volatile unsigned char* base_addr, const char *s) {
while(*s != '\0') {
*UART0DR = (unsigned char)(*s);
s++;
}
}

int main() {
const char* msg = "Hello world!\n";
PRINT_UART0(msg);
return 0;
}

ライブラリが使えないので, UART0 のアドレスにメッセージ ( msg )のキャラクタコードを書き込むプログラムです.

つぎに, 簡易的なブートローダー startup.S を作成します.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.align 6

.equ UART_BASE, 0x10000000
.equ REG_RBR, 0
.equ REG_TBR, 0
.equ REG_IIR, 2
.equ IIR_TX_RDY, 2
.equ IIR_RX_RDY, 4

.section .text
.globl _start
.globl stack_top

_start:
la sp, stack_top
call main

loop_here: j loop_here

次のリンカーに渡すセクション等を定義したスクリプト ( link.ld ) を使って, この2つのプログラムをコンパイルします.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
SECTIONS
{
/* text: test code section */
. = 0x80000000;
.text : { *(.text) }
/* data: Initialized data segment */
.data : { *(.data) }
.rodata : { *(.rodata) }
.sdata : { *(.sdata) }
.debug : { *(.debug) }
. += 0x8000;
stack_top = .;

/* End of uninitalized data segement */
_end = .;
}

(コンパイルの実行)

1
riscv32-unknown-elf-gcc -T link.ld startup.S main.c -o hello -mabi=ilp32 -fPIC -nostdlib -nostartfiles

(QEMUでベアメタルプログラムとして実行)

1
qemu-system-riscv32 -nographic -machine virt -kernel hello

(出力される画面)

1
Hello world!

Ctrl-A x で QEMU は終了します.