riscv: implement VirtIO target

This allows running RISC-V tests in CI using QEMU, which should help
catch bugs.
Этот коммит содержится в:
Ayke van Laethem 2020-03-22 20:11:46 +01:00 коммит произвёл Ron Evans
родитель 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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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"