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)
|
||||
})
|
||||
|
||||
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" {
|
||||
t.Run("ARMLinux", func(t *testing.T) {
|
||||
runPlatTests("arm--linux-gnueabihf", matches, t)
|
||||
|
|
|
@ -16,21 +16,6 @@ import (
|
|||
|
||||
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() {}
|
||||
|
||||
//go:export main
|
||||
|
@ -108,24 +93,6 @@ func initPeripherals() {
|
|||
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) {
|
||||
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"
|
Загрузка…
Создание таблицы
Сослаться в новой задаче