Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
33 changes: 0 additions & 33 deletions src/runtime/runtime_fe310.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down
38 changes: 38 additions & 0 deletions src/runtime/runtime_tinygoriscv.go
Original file line number Diff line number Diff line change
@@ -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 changes: 63 additions & 0 deletions src/runtime/runtime_tinygoriscv_qemu.go
Original file line number Diff line number Diff line change
@@ -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 changes: 7 additions & 0 deletions targets/riscv-qemu.json
Original file line number Diff line number Diff line change
@@ -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 changes: 16 additions & 0 deletions targets/riscv-qemu.ld
Original file line number Diff line number Diff line change
@@ -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"