maixbit (uart): serial is working with echo example

Этот коммит содержится в:
Yannis Huber 2020-06-16 14:55:55 +02:00 коммит произвёл Ron Evans
родитель 75bcbbe6d8
коммит dfab1aa717
11 изменённых файлов: 263 добавлений и 27 удалений

60
src/device/riscv/start64.S Обычный файл
Просмотреть файл

@ -0,0 +1,60 @@
.section .init
.global _start
.type _start,@function
_start:
// Load the stack pointer.
la sp, _stack_top
// Load the globals pointer. The program will load pointers relative to this
// register, so it must be set to the right value on startup.
// See: https://gnu-mcu-eclipse.github.io/arch/riscv/programmer/#the-gp-global-pointer-register
la gp, __global_pointer$
// Jump to runtime.main
call main
.section .text.handleInterruptASM
.global handleInterruptASM
.type handleInterruptASM,@function
handleInterruptASM:
// Save and restore all registers, because the hardware only saves/restores
// the pc.
// Note: we have to do this in assembly because the "interrupt"="machine"
// attribute is broken in LLVM: https://bugs.llvm.org/show_bug.cgi?id=42984
addi sp, sp, -128
sd ra, 120(sp)
sd t0, 112(sp)
sd t1, 104(sp)
sd t2, 96(sp)
sd a0, 88(sp)
sd a1, 80(sp)
sd a2, 72(sp)
sd a3, 64(sp)
sd a4, 56(sp)
sd a5, 48(sp)
sd a6, 40(sp)
sd a7, 32(sp)
sd t3, 24(sp)
sd t4, 16(sp)
sd t5, 8(sp)
sd t6, 0(sp)
call handleInterrupt
ld t6, 0(sp)
ld t5, 8(sp)
ld t4, 16(sp)
ld t3, 24(sp)
ld a7, 32(sp)
ld a6, 40(sp)
ld a5, 48(sp)
ld a4, 56(sp)
ld a3, 64(sp)
ld a2, 72(sp)
ld a1, 80(sp)
ld a0, 88(sp)
ld t2, 96(sp)
ld t1, 104(sp)
ld t0, 112(sp)
ld ra, 120(sp)
addi sp, sp, 128
mret

Просмотреть файл

@ -60,22 +60,21 @@ var (
) )
func (uart UART) Configure(config UARTConfig) { func (uart UART) Configure(config UARTConfig) {
div := CPUFrequency()/115200 - 1 div := CPUFrequency()/115200 - 1
uart.Bus.DIV.Set(div) uart.Bus.DIV.Set(div)
uart.Bus.TXCTRL.Set(kendryte.UARTHS_TXCTRL_TXEN) uart.Bus.TXCTRL.Set(kendryte.UARTHS_TXCTRL_TXEN)
uart.Bus.RXCTRL.Set(kendryte.UARTHS_RXCTRL_RXEN) uart.Bus.RXCTRL.Set(kendryte.UARTHS_RXCTRL_RXEN)
//uart.Bus.IP.Set(kendryte.UARTHS_IP_TXWM | kendryte.UARTHS_IP_RXWM)
//uart.Bus.IE.Set(kendryte.UARTHS_IE_RXWM)
/*intr := interrupt.New(kendryte.IRQ_UARTHS, UART0.handleInterrupt) // Enable interrupts on receive.
uart.Bus.IE.Set(kendryte.UARTHS_IE_RXWM)
intr := interrupt.New(kendryte.IRQ_UARTHS, UART0.handleInterrupt)
intr.SetPriority(5) intr.SetPriority(5)
intr.Enable()*/ intr.Enable()
} }
func (uart UART) handleInterrupt(interrupt.Interrupt) { func (uart *UART) handleInterrupt(interrupt.Interrupt) {
rxdata := uart.Bus.RXDATA.Get() rxdata := uart.Bus.RXDATA.Get()
c := byte(rxdata) c := byte(rxdata)
if uint32(c) != rxdata { if uint32(c) != rxdata {

Просмотреть файл

@ -1,4 +1,4 @@
// +build tinygo.riscv // +build tinygo.riscv32
package runtime package runtime

92
src/runtime/arch_tinygoriscv64.go Обычный файл
Просмотреть файл

@ -0,0 +1,92 @@
// +build tinygo.riscv64
package runtime
import "device/riscv"
const GOARCH = "arm64" // riscv pretends to be arm
// The bitness of the CPU (e.g. 8, 32, 64).
const TargetBits = 64
// Align on word boundary.
func align(ptr uintptr) uintptr {
return (ptr + 7) &^ 7
}
func getCurrentStackPointer() uintptr {
return riscv.AsmFull("mv {}, sp", nil)
}
// Documentation:
// * https://llvm.org/docs/Atomics.html
// * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html
//
// In the case of RISC-V, some operations may be implemented with libcalls if
// the operation is too big to be handled by assembly. Officially, these calls
// should be implemented with a lock-free algorithm but as (as of this time) all
// supported RISC-V chips have a single hart, we can simply disable interrupts
// to get the same behavior.
//export __atomic_load_8
func __atomic_load_8(ptr *uint64, ordering int32) uint64 {
mask := riscv.DisableInterrupts()
value := *ptr
riscv.EnableInterrupts(mask)
return value
}
//export __atomic_store_8
func __atomic_store_8(ptr *uint64, value uint64, ordering int32) {
mask := riscv.DisableInterrupts()
*ptr = value
riscv.EnableInterrupts(mask)
}
//export __atomic_exchange_8
func __atomic_exchange_8(ptr *uint64, value uint64, ordering int32) uint64 {
mask := riscv.DisableInterrupts()
oldValue := *ptr
*ptr = value
riscv.EnableInterrupts(mask)
return oldValue
}
//export __atomic_compare_exchange_8
func __atomic_compare_exchange_8(ptr, expected *uint64, desired uint64, success_ordering, failure_ordering int32) bool {
mask := riscv.DisableInterrupts()
oldValue := *ptr
success := oldValue == *expected
if success {
*ptr = desired
} else {
*expected = oldValue
}
riscv.EnableInterrupts(mask)
return success
}
//export __atomic_fetch_add_8
func __atomic_fetch_add_8(ptr *uint64, value uint64, ordering int32) uint64 {
mask := riscv.DisableInterrupts()
oldValue := *ptr
*ptr = oldValue + value
riscv.EnableInterrupts(mask)
return oldValue
}
// The safest thing to do here would just be to disable interrupts for
// procPin/procUnpin. Note that a global variable is safe in this case, as any
// access to procPinnedMask will happen with interrupts disabled.
var procPinnedMask uintptr
//go:linkname procPin sync/atomic.runtime_procPin
func procPin() {
procPinnedMask = riscv.DisableInterrupts()
}
//go:linkname procUnpin sync/atomic.runtime_procUnpin
func procUnpin() {
riscv.EnableInterrupts(procPinnedMask)
}

Просмотреть файл

@ -20,15 +20,11 @@ func postinit() {}
//export main //export main
func main() { func main() {
// Only use one core for the moment // Both harts should disable all interrupts on startup.
if riscv.MHARTID.Get() == 0 { initPLIC()
// Zero the PLIC enable bits at startup.
for i := 0; i < ((kendryte.IRQ_max + 32) / 32); i++ {
kendryte.PLIC.TARGET_ENABLES[0].ENABLE[i].Set(0) // core 0
}
// Zero the PLIC threshold bits to allow all interrupts. // Only use one hart for the moment.
kendryte.PLIC.TARGETS[0].THRESHOLD.Set(0) if riscv.MHARTID.Get() == 0 {
// Reset all interrupt source priorities to zero. // Reset all interrupt source priorities to zero.
for i := 0; i < kendryte.IRQ_max; i++ { for i := 0; i < kendryte.IRQ_max; i++ {
@ -56,14 +52,26 @@ func main() {
} }
} }
func initPLIC() {
hartId := riscv.MHARTID.Get()
// Zero the PLIC enable bits at startup.
for i := 0; i < ((kendryte.IRQ_max + 32) / 32); i++ {
kendryte.PLIC.TARGET_ENABLES[hartId].ENABLE[i].Set(0)
}
// Zero the PLIC threshold bits to allow all interrupts.
kendryte.PLIC.TARGETS[hartId].THRESHOLD.Set(0)
}
//go:extern handleInterruptASM //go:extern handleInterruptASM
var handleInterruptASM [0]uintptr var handleInterruptASM [0]uintptr
//export handleInterrupt //export handleInterrupt
func handleInterrupt() { func handleInterrupt() {
cause := riscv.MCAUSE.Get() cause := riscv.MCAUSE.Get()
code := uint(cause &^ (1 << 31)) code := uint64(cause &^ (1 << 63))
if cause&(1<<31) != 0 { if cause&(1<<63) != 0 {
// Topmost bit is set, which means that it is an interrupt. // Topmost bit is set, which means that it is an interrupt.
switch code { switch code {
case 7: // Machine timer interrupt case 7: // Machine timer interrupt
@ -73,12 +81,14 @@ func handleInterrupt() {
// this interrupt returns. // this interrupt returns.
riscv.MIE.ClearBits(1 << 7) // MTIE bit riscv.MIE.ClearBits(1 << 7) // MTIE bit
case 11: // Machine external interrupt case 11: // Machine external interrupt
hartId := riscv.MHARTID.Get()
// Claim this interrupt. // Claim this interrupt.
id := kendryte.PLIC.TARGETS[0].CLAIM.Get() id := kendryte.PLIC.TARGETS[hartId].CLAIM.Get()
// Call the interrupt handler, if any is registered for this ID. // Call the interrupt handler, if any is registered for this ID.
callInterruptHandler(int(0)) callInterruptHandler(int(id))
// Complete this interrupt. // Complete this interrupt.
kendryte.PLIC.TARGETS[0].CLAIM.Set(id) kendryte.PLIC.TARGETS[hartId].CLAIM.Set(id)
} }
} else { } else {
// Topmost bit is clear, so it is an exception of some sort. // Topmost bit is clear, so it is an exception of some sort.
@ -133,7 +143,7 @@ func sleepTicks(d timeUnit) {
// handleException is called from the interrupt handler for any exception. // handleException is called from the interrupt handler for any exception.
// Exceptions can be things like illegal instructions, invalid memory // Exceptions can be things like illegal instructions, invalid memory
// read/write, and similar issues. // read/write, and similar issues.
func handleException(code uint) { func handleException(code uint64) {
// For a list of exception codes, see: // For a list of exception codes, see:
// https://content.riscv.org/wp-content/uploads/2019/08/riscv-privileged-20190608-1.pdf#page=49 // https://content.riscv.org/wp-content/uploads/2019/08/riscv-privileged-20190608-1.pdf#page=49
print("fatal error: exception with mcause=") print("fatal error: exception with mcause=")

Просмотреть файл

@ -1,4 +1,4 @@
// +build tinygo.riscv // +build tinygo.riscv32
package runtime package runtime

38
src/runtime/runtime_tinygoriscv64.go Обычный файл
Просмотреть файл

@ -0,0 +1,38 @@
// +build tinygo.riscv64
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) {
*(*uint64)(ptr) = 0
ptr = unsafe.Pointer(uintptr(ptr) + 8)
}
// Initialize .data: global variables initialized from flash.
src := unsafe.Pointer(&_sidata)
dst := unsafe.Pointer(&_sdata)
for dst != unsafe.Pointer(&_edata) {
*(*uint64)(dst) = *(*uint64)(src)
dst = unsafe.Pointer(uintptr(dst) + 8)
src = unsafe.Pointer(uintptr(src) + 8)
}
}

32
src/runtime/scheduler_tinygoriscv64.S Обычный файл
Просмотреть файл

@ -0,0 +1,32 @@
.section .text.tinygo_scanCurrentStack
.global tinygo_scanCurrentStack
.type tinygo_scanCurrentStack, %function
tinygo_scanCurrentStack:
// Push callee-saved registers onto the stack.
addi sp, sp, -128
sd ra, 120(sp)
sd s11, 112(sp)
sd s10, 104(sp)
sd s9, 96(sp)
sd s8, 88(sp)
sd s7, 80(sp)
sd s6, 72(sp)
sd s5, 64(sp)
sd s4, 56(sp)
sd s3, 48(sp)
sd s2, 40(sp)
sd s1, 32(sp)
sd s0, 24(sp)
// Scan the stack.
mv a0, sp
call tinygo_scanstack
// Restore return address.
ld ra, 60(sp)
// Restore stack state.
addi sp, sp, 128
// Return to the caller.
ret

Просмотреть файл

@ -16,9 +16,5 @@
"ldflags": [ "ldflags": [
"--gc-sections" "--gc-sections"
], ],
"extra-files": [
"src/device/riscv/start.S",
"src/runtime/scheduler_tinygoriscv.S"
],
"gdb": "riscv64-unknown-elf-gdb" "gdb": "riscv64-unknown-elf-gdb"
} }

Просмотреть файл

@ -1,6 +1,7 @@
{ {
"inherits": ["riscv"], "inherits": ["riscv"],
"llvm-target": "riscv32--none", "llvm-target": "riscv32--none",
"build-tags": ["tinygo.riscv32"],
"cflags": [ "cflags": [
"--target=riscv32--none", "--target=riscv32--none",
"-march=rv32imac", "-march=rv32imac",
@ -8,5 +9,9 @@
], ],
"ldflags": [ "ldflags": [
"-melf32lriscv" "-melf32lriscv"
],
"extra-files": [
"src/runtime/scheduler_tinygoriscv.S",
"src/device/riscv/start.S"
] ]
} }

Просмотреть файл

@ -9,5 +9,9 @@
], ],
"ldflags": [ "ldflags": [
"-melf64lriscv" "-melf64lriscv"
],
"extra-files": [
"src/runtime/scheduler_tinygoriscv64.S",
"src/device/riscv/start64.S"
] ]
} }