riscv: implement VirtIO target
This allows running RISC-V tests in CI using QEMU, which should help catch bugs.
Этот коммит содержится в:
родитель
c4fd19be99
коммит
980068543a
6 изменённых файлов: 132 добавлений и 33 удалений
|
@ -54,6 +54,14 @@ func TestCompiler(t *testing.T) {
|
||||||
runPlatTests("cortex-m-qemu", matches, t)
|
runPlatTests("cortex-m-qemu", matches, t)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
|
||||||
|
// Note: running only on Windows and macOS because Linux (as of 2020)
|
||||||
|
// usually has an outdated QEMU version that doesn't support RISC-V yet.
|
||||||
|
t.Run("EmulatedRISCV", func(t *testing.T) {
|
||||||
|
runPlatTests("riscv-qemu", matches, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
t.Run("ARMLinux", func(t *testing.T) {
|
t.Run("ARMLinux", func(t *testing.T) {
|
||||||
runPlatTests("arm--linux-gnueabihf", matches, t)
|
runPlatTests("arm--linux-gnueabihf", matches, t)
|
||||||
|
|
|
@ -16,21 +16,6 @@ import (
|
||||||
|
|
||||||
type timeUnit int64
|
type timeUnit int64
|
||||||
|
|
||||||
//go:extern _sbss
|
|
||||||
var _sbss [0]byte
|
|
||||||
|
|
||||||
//go:extern _ebss
|
|
||||||
var _ebss [0]byte
|
|
||||||
|
|
||||||
//go:extern _sdata
|
|
||||||
var _sdata [0]byte
|
|
||||||
|
|
||||||
//go:extern _sidata
|
|
||||||
var _sidata [0]byte
|
|
||||||
|
|
||||||
//go:extern _edata
|
|
||||||
var _edata [0]byte
|
|
||||||
|
|
||||||
func postinit() {}
|
func postinit() {}
|
||||||
|
|
||||||
//go:export main
|
//go:export main
|
||||||
|
@ -108,24 +93,6 @@ func initPeripherals() {
|
||||||
machine.UART0.Configure(machine.UARTConfig{})
|
machine.UART0.Configure(machine.UARTConfig{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func preinit() {
|
|
||||||
// Initialize .bss: zero-initialized global variables.
|
|
||||||
ptr := unsafe.Pointer(&_sbss)
|
|
||||||
for ptr != unsafe.Pointer(&_ebss) {
|
|
||||||
*(*uint32)(ptr) = 0
|
|
||||||
ptr = unsafe.Pointer(uintptr(ptr) + 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize .data: global variables initialized from flash.
|
|
||||||
src := unsafe.Pointer(&_sidata)
|
|
||||||
dst := unsafe.Pointer(&_sdata)
|
|
||||||
for dst != unsafe.Pointer(&_edata) {
|
|
||||||
*(*uint32)(dst) = *(*uint32)(src)
|
|
||||||
dst = unsafe.Pointer(uintptr(dst) + 4)
|
|
||||||
src = unsafe.Pointer(uintptr(src) + 4)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func putchar(c byte) {
|
func putchar(c byte) {
|
||||||
machine.UART0.WriteByte(c)
|
machine.UART0.WriteByte(c)
|
||||||
}
|
}
|
||||||
|
|
38
src/runtime/runtime_tinygoriscv.go
Обычный файл
38
src/runtime/runtime_tinygoriscv.go
Обычный файл
|
@ -0,0 +1,38 @@
|
||||||
|
// +build tinygo.riscv
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
//go:extern _sbss
|
||||||
|
var _sbss [0]byte
|
||||||
|
|
||||||
|
//go:extern _ebss
|
||||||
|
var _ebss [0]byte
|
||||||
|
|
||||||
|
//go:extern _sdata
|
||||||
|
var _sdata [0]byte
|
||||||
|
|
||||||
|
//go:extern _sidata
|
||||||
|
var _sidata [0]byte
|
||||||
|
|
||||||
|
//go:extern _edata
|
||||||
|
var _edata [0]byte
|
||||||
|
|
||||||
|
func preinit() {
|
||||||
|
// Initialize .bss: zero-initialized global variables.
|
||||||
|
ptr := unsafe.Pointer(&_sbss)
|
||||||
|
for ptr != unsafe.Pointer(&_ebss) {
|
||||||
|
*(*uint32)(ptr) = 0
|
||||||
|
ptr = unsafe.Pointer(uintptr(ptr) + 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize .data: global variables initialized from flash.
|
||||||
|
src := unsafe.Pointer(&_sidata)
|
||||||
|
dst := unsafe.Pointer(&_sdata)
|
||||||
|
for dst != unsafe.Pointer(&_edata) {
|
||||||
|
*(*uint32)(dst) = *(*uint32)(src)
|
||||||
|
dst = unsafe.Pointer(uintptr(dst) + 4)
|
||||||
|
src = unsafe.Pointer(uintptr(src) + 4)
|
||||||
|
}
|
||||||
|
}
|
63
src/runtime/runtime_tinygoriscv_qemu.go
Обычный файл
63
src/runtime/runtime_tinygoriscv_qemu.go
Обычный файл
|
@ -0,0 +1,63 @@
|
||||||
|
// +build tinygo.riscv,qemu
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/riscv"
|
||||||
|
"runtime/volatile"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file implements the VirtIO RISC-V interface implemented in QEMU, which
|
||||||
|
// is an interface designed for emulation.
|
||||||
|
|
||||||
|
type timeUnit int64
|
||||||
|
|
||||||
|
const tickMicros = 1
|
||||||
|
|
||||||
|
var timestamp timeUnit
|
||||||
|
|
||||||
|
func postinit() {}
|
||||||
|
|
||||||
|
//go:export main
|
||||||
|
func main() {
|
||||||
|
preinit()
|
||||||
|
run()
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
|
func sleepTicks(d timeUnit) {
|
||||||
|
// TODO: actually sleep here for the given time.
|
||||||
|
timestamp += d
|
||||||
|
}
|
||||||
|
|
||||||
|
func ticks() timeUnit {
|
||||||
|
return timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory-mapped I/O as defined by QEMU.
|
||||||
|
// Source: https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c
|
||||||
|
// Technically this is an implementation detail but hopefully they won't change
|
||||||
|
// the memory-mapped I/O registers.
|
||||||
|
var (
|
||||||
|
// UART0 output register.
|
||||||
|
stdoutWrite = (*volatile.Register8)(unsafe.Pointer(uintptr(0x10000000)))
|
||||||
|
// SiFive test finisher
|
||||||
|
testFinisher = (*volatile.Register16)(unsafe.Pointer(uintptr(0x100000)))
|
||||||
|
)
|
||||||
|
|
||||||
|
func putchar(c byte) {
|
||||||
|
stdoutWrite.Set(uint8(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
func abort() {
|
||||||
|
// Make sure the QEMU process exits.
|
||||||
|
testFinisher.Set(0x5555) // FINISHER_PASS
|
||||||
|
|
||||||
|
// Lock up forever (as a fallback).
|
||||||
|
for {
|
||||||
|
riscv.Asm("wfi")
|
||||||
|
}
|
||||||
|
}
|
7
targets/riscv-qemu.json
Обычный файл
7
targets/riscv-qemu.json
Обычный файл
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"inherits": ["riscv"],
|
||||||
|
"features": ["+a", "+c", "+m"],
|
||||||
|
"build-tags": ["virt", "qemu"],
|
||||||
|
"linkerscript": "targets/riscv-qemu.ld",
|
||||||
|
"emulator": ["qemu-system-riscv32", "-machine", "virt", "-nographic", "-bios", "none", "-kernel"]
|
||||||
|
}
|
16
targets/riscv-qemu.ld
Обычный файл
16
targets/riscv-qemu.ld
Обычный файл
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
/* Memory map:
|
||||||
|
* https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c
|
||||||
|
* RAM and flash are set to 1MB each. That should be enough for the foreseeable
|
||||||
|
* future. QEMU does not seem to limit the flash/RAM size and in fact doesn't
|
||||||
|
* seem to differentiate between it.
|
||||||
|
*/
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
FLASH_TEXT (rw) : ORIGIN = 0x80000000, LENGTH = 0x100000
|
||||||
|
RAM (xrw) : ORIGIN = 0x80100000, LENGTH = 0x100000
|
||||||
|
}
|
||||||
|
|
||||||
|
_stack_size = 2K;
|
||||||
|
|
||||||
|
INCLUDE "targets/riscv.ld"
|
Загрузка…
Создание таблицы
Сослаться в новой задаче