github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/runtime_tinygoriscv_qemu.go (about)

     1  //go:build tinygo.riscv && virt && qemu
     2  
     3  package runtime
     4  
     5  import (
     6  	"device/riscv"
     7  	"runtime/volatile"
     8  	"unsafe"
     9  )
    10  
    11  // This file implements the VirtIO RISC-V interface implemented in QEMU, which
    12  // is an interface designed for emulation.
    13  
    14  type timeUnit int64
    15  
    16  var timestamp timeUnit
    17  
    18  //export main
    19  func main() {
    20  	preinit()
    21  	run()
    22  	exit(0)
    23  }
    24  
    25  func ticksToNanoseconds(ticks timeUnit) int64 {
    26  	return int64(ticks)
    27  }
    28  
    29  func nanosecondsToTicks(ns int64) timeUnit {
    30  	return timeUnit(ns)
    31  }
    32  
    33  func sleepTicks(d timeUnit) {
    34  	// TODO: actually sleep here for the given time.
    35  	timestamp += d
    36  }
    37  
    38  func ticks() timeUnit {
    39  	return timestamp
    40  }
    41  
    42  // Memory-mapped I/O as defined by QEMU.
    43  // Source: https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c
    44  // Technically this is an implementation detail but hopefully they won't change
    45  // the memory-mapped I/O registers.
    46  var (
    47  	// UART0 output register.
    48  	stdoutWrite = (*volatile.Register8)(unsafe.Pointer(uintptr(0x10000000)))
    49  	// SiFive test finisher
    50  	testFinisher = (*volatile.Register32)(unsafe.Pointer(uintptr(0x100000)))
    51  )
    52  
    53  func putchar(c byte) {
    54  	stdoutWrite.Set(uint8(c))
    55  }
    56  
    57  func getchar() byte {
    58  	// dummy, TODO
    59  	return 0
    60  }
    61  
    62  func buffered() int {
    63  	// dummy, TODO
    64  	return 0
    65  }
    66  
    67  func abort() {
    68  	exit(1)
    69  }
    70  
    71  func exit(code int) {
    72  	// Make sure the QEMU process exits.
    73  	if code == 0 {
    74  		testFinisher.Set(0x5555) // FINISHER_PASS
    75  	} else {
    76  		// Exit code is stored in the upper 16 bits of the 32 bit value.
    77  		testFinisher.Set(uint32(code)<<16 | 0x3333) // FINISHER_FAIL
    78  	}
    79  
    80  	// Lock up forever (as a fallback).
    81  	for {
    82  		riscv.Asm("wfi")
    83  	}
    84  }