From d1f82ba47153a7fd345c0412e35924676637c58d Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Mon, 1 Jun 2020 14:44:12 +0200 Subject: [PATCH 01/28] Add new kendryte k210 target definition --- .gitignore | 2 ++ .gitmodules | 2 +- Makefile | 6 +++++- lib/cmsis-svd | 2 +- targets/fe310.json | 16 +++++++++++++++- targets/k210.json | 19 +++++++++++++++++++ targets/maix-bit-mic.json | 6 ++++++ targets/maix-bit-mic.ld | 10 ++++++++++ 8 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 targets/k210.json create mode 100644 targets/maix-bit-mic.json create mode 100644 targets/maix-bit-mic.ld diff --git a/.gitignore b/.gitignore index 81ed9b6647..84f90ddbc3 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ src/device/sifive/*.go src/device/sifive/*.s src/device/stm32/*.go src/device/stm32/*.s +src/device/kendryte/*.go +src/device/kendryte/*.s vendor llvm-build llvm-project diff --git a/.gitmodules b/.gitmodules index af6e1809aa..cbab142b2b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,7 +9,7 @@ url = https://github.com/avr-rust/avr-mcu.git [submodule "lib/cmsis-svd"] path = lib/cmsis-svd - url = https://github.com/posborne/cmsis-svd + url = https://github.com/yannishuber/cmsis-svd [submodule "lib/compiler-rt"] path = lib/compiler-rt url = https://github.com/llvm-mirror/compiler-rt.git diff --git a/Makefile b/Makefile index 3295b9cd0e..270c894d73 100644 --- a/Makefile +++ b/Makefile @@ -118,7 +118,7 @@ fmt-check: @unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1 -gen-device: gen-device-avr gen-device-nrf gen-device-sam gen-device-sifive gen-device-stm32 +gen-device: gen-device-avr gen-device-nrf gen-device-sam gen-device-sifive gen-device-stm32 gen-device-kendryte gen-device-avr: $(GO) build -o ./build/gen-device-avr ./tools/gen-device-avr/ @@ -141,6 +141,10 @@ gen-device-sifive: build/gen-device-svd ./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/SiFive-Community -interrupts=software lib/cmsis-svd/data/SiFive-Community/ src/device/sifive/ GO111MODULE=off $(GO) fmt ./src/device/sifive +gen-device-kendryte: build/gen-device-svd + ./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Kendryte-Community -interrupts=software lib/cmsis-svd/data/Kendryte-Community/ src/device/kendryte/ + GO111MODULE=off $(GO) fmt ./src/device/kendryte + gen-device-stm32: build/gen-device-svd ./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/STMicro lib/cmsis-svd/data/STMicro/ src/device/stm32/ GO111MODULE=off $(GO) fmt ./src/device/stm32 diff --git a/lib/cmsis-svd b/lib/cmsis-svd index 15b462f152..a155cfd832 160000 --- a/lib/cmsis-svd +++ b/lib/cmsis-svd @@ -1 +1 @@ -Subproject commit 15b462f152af86f3d15b952e1a5cf1bb9e2693e8 +Subproject commit a155cfd832c9e6ddf193244d8d90489f4d089cc7 diff --git a/targets/fe310.json b/targets/fe310.json index 76f7497053..636b4f2d9f 100644 --- a/targets/fe310.json +++ b/targets/fe310.json @@ -1,5 +1,19 @@ { "inherits": ["riscv32"], "features": ["+a", "+c", "+m"], - "build-tags": ["fe310", "sifive"] + "build-tags": ["fe310", "sifive"], + "llvm-target": "riscv32--none", + "cflags": [ + "--target=riscv32--none", + "-march=rv32imac", + "-mabi=ilp32", + "-Os", + "-Werror", + "-fno-exceptions", "-fno-unwind-tables", + "-ffunction-sections", "-fdata-sections" + ], + "ldflags": [ + "-melf32lriscv", + "--gc-sections" + ] } diff --git a/targets/k210.json b/targets/k210.json new file mode 100644 index 0000000000..d5772b66bd --- /dev/null +++ b/targets/k210.json @@ -0,0 +1,19 @@ +{ + "inherits": ["riscv"], + "features": ["+a", "+c", "+m", "+f", "+d"], + "build-tags": ["k210", "kendryte"], + "llvm-target": "riscv64--none", + "cflags": [ + "--target=riscv64--none", + "-march=rv64gc", + "-mabi=lp64d", + "-Os", + "-Werror", + "-fno-exceptions", "-fno-unwind-tables", + "-ffunction-sections", "-fdata-sections" + ], + "ldflags": [ + "-melf64lriscv", + "--gc-sections" + ] +} diff --git a/targets/maix-bit-mic.json b/targets/maix-bit-mic.json new file mode 100644 index 0000000000..31d6df568f --- /dev/null +++ b/targets/maix-bit-mic.json @@ -0,0 +1,6 @@ +{ + "inherits": ["k210"], + "build-tags": ["maix-bit-mic"], + "linkerscript": "targets/maix-bit-mic.ld", + "flash-command": "kflash -p /dev/ttyUSB0 {hex}" +} diff --git a/targets/maix-bit-mic.ld b/targets/maix-bit-mic.ld new file mode 100644 index 0000000000..733152a264 --- /dev/null +++ b/targets/maix-bit-mic.ld @@ -0,0 +1,10 @@ + +MEMORY +{ + FLASH_TEXT (rw) : ORIGIN = 0x80000000, LENGTH = (6 * 1024 * 1024) + RAM (xrw) : ORIGIN = 0x80000000, LENGTH = (6 * 1024 * 1024) +} + +_stack_size = 2K; + +INCLUDE "targets/riscv.ld" From c4031810b61f8390f32bb1167570f9f24acf0ab7 Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Mon, 1 Jun 2020 16:39:05 +0200 Subject: [PATCH 02/28] Split RISC-V targets into 32/64-bit --- targets/fe310.json | 16 +--------------- targets/k210.json | 18 ++---------------- targets/maix-bit-mic.json | 6 ------ targets/maix-bit-mic.ld | 10 ---------- targets/maixbit.json | 6 ++++++ targets/maixbit.ld | 11 +++++++++++ targets/riscv.json | 24 ------------------------ 7 files changed, 20 insertions(+), 71 deletions(-) delete mode 100644 targets/maix-bit-mic.json delete mode 100644 targets/maix-bit-mic.ld create mode 100644 targets/maixbit.json create mode 100644 targets/maixbit.ld delete mode 100644 targets/riscv.json diff --git a/targets/fe310.json b/targets/fe310.json index 636b4f2d9f..bc95e8d4e0 100644 --- a/targets/fe310.json +++ b/targets/fe310.json @@ -1,19 +1,5 @@ { "inherits": ["riscv32"], "features": ["+a", "+c", "+m"], - "build-tags": ["fe310", "sifive"], - "llvm-target": "riscv32--none", - "cflags": [ - "--target=riscv32--none", - "-march=rv32imac", - "-mabi=ilp32", - "-Os", - "-Werror", - "-fno-exceptions", "-fno-unwind-tables", - "-ffunction-sections", "-fdata-sections" - ], - "ldflags": [ - "-melf32lriscv", - "--gc-sections" - ] + "build-tags": ["fe310", "sifive"] } diff --git a/targets/k210.json b/targets/k210.json index d5772b66bd..5ddd9dbab9 100644 --- a/targets/k210.json +++ b/targets/k210.json @@ -1,19 +1,5 @@ { - "inherits": ["riscv"], + "inherits": ["riscv64"], "features": ["+a", "+c", "+m", "+f", "+d"], - "build-tags": ["k210", "kendryte"], - "llvm-target": "riscv64--none", - "cflags": [ - "--target=riscv64--none", - "-march=rv64gc", - "-mabi=lp64d", - "-Os", - "-Werror", - "-fno-exceptions", "-fno-unwind-tables", - "-ffunction-sections", "-fdata-sections" - ], - "ldflags": [ - "-melf64lriscv", - "--gc-sections" - ] + "build-tags": ["k210", "kendryte"] } diff --git a/targets/maix-bit-mic.json b/targets/maix-bit-mic.json deleted file mode 100644 index 31d6df568f..0000000000 --- a/targets/maix-bit-mic.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "inherits": ["k210"], - "build-tags": ["maix-bit-mic"], - "linkerscript": "targets/maix-bit-mic.ld", - "flash-command": "kflash -p /dev/ttyUSB0 {hex}" -} diff --git a/targets/maix-bit-mic.ld b/targets/maix-bit-mic.ld deleted file mode 100644 index 733152a264..0000000000 --- a/targets/maix-bit-mic.ld +++ /dev/null @@ -1,10 +0,0 @@ - -MEMORY -{ - FLASH_TEXT (rw) : ORIGIN = 0x80000000, LENGTH = (6 * 1024 * 1024) - RAM (xrw) : ORIGIN = 0x80000000, LENGTH = (6 * 1024 * 1024) -} - -_stack_size = 2K; - -INCLUDE "targets/riscv.ld" diff --git a/targets/maixbit.json b/targets/maixbit.json new file mode 100644 index 0000000000..f0f5e8b274 --- /dev/null +++ b/targets/maixbit.json @@ -0,0 +1,6 @@ +{ + "inherits": ["k210"], + "build-tags": ["maixbit"], + "linkerscript": "targets/maixbit.ld", + "flash-command": "kflash -p /dev/ttyUSB0 {hex}" +} diff --git a/targets/maixbit.ld b/targets/maixbit.ld new file mode 100644 index 0000000000..9206809b03 --- /dev/null +++ b/targets/maixbit.ld @@ -0,0 +1,11 @@ + +MEMORY +{ + RAM (xrw) : ORIGIN = 0xffffffff80000000, LENGTH = 6M +} + +REGION_ALIAS("FLASH_TEXT", RAM); + +_stack_size = 2K; + +INCLUDE "targets/riscv.ld" diff --git a/targets/riscv.json b/targets/riscv.json deleted file mode 100644 index 313aa85811..0000000000 --- a/targets/riscv.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "goos": "linux", - "goarch": "arm", - "build-tags": ["tinygo.riscv", "baremetal", "linux", "arm"], - "gc": "conservative", - "compiler": "clang", - "linker": "ld.lld", - "rtlib": "compiler-rt", - "libc": "picolibc", - "cflags": [ - "-Os", - "-Werror", - "-fno-exceptions", "-fno-unwind-tables", - "-ffunction-sections", "-fdata-sections" - ], - "ldflags": [ - "--gc-sections" - ], - "extra-files": [ - "src/device/riscv/start.S", - "src/runtime/scheduler_tinygoriscv.S" - ], - "gdb": "riscv64-unknown-elf-gdb" -} From 0050a8282c0e6e203d8653b85595d38a820dc3da Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Tue, 2 Jun 2020 20:41:31 +0200 Subject: [PATCH 03/28] Add llvm code model option in target definition --- compileopts/target.go | 1 + targets/maixbit.ld | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compileopts/target.go b/compileopts/target.go index 5d5e2f1b3d..d6a30a3fd7 100644 --- a/compileopts/target.go +++ b/compileopts/target.go @@ -276,6 +276,7 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) { GDB: "gdb", PortReset: "false", FlashMethod: "native", + CodeModel: "default", } if goos == "darwin" { spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip") diff --git a/targets/maixbit.ld b/targets/maixbit.ld index 9206809b03..9b277a6cea 100644 --- a/targets/maixbit.ld +++ b/targets/maixbit.ld @@ -1,7 +1,7 @@ MEMORY { - RAM (xrw) : ORIGIN = 0xffffffff80000000, LENGTH = 6M + RAM (xrw) : ORIGIN = 0x80000000, LENGTH = (6 * 1024 * 1024) } REGION_ALIAS("FLASH_TEXT", RAM); From 99c777ca9d84786009f4b4b8ede8f488886b543e Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Fri, 5 Jun 2020 09:27:45 +0200 Subject: [PATCH 04/28] Changes according to @aykevl's feedback --- compileopts/target.go | 1 - targets/fe310.json | 2 +- targets/maixbit.ld | 2 +- targets/riscv.json | 24 ++++++++++++++++++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 targets/riscv.json diff --git a/compileopts/target.go b/compileopts/target.go index d6a30a3fd7..5d5e2f1b3d 100644 --- a/compileopts/target.go +++ b/compileopts/target.go @@ -276,7 +276,6 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) { GDB: "gdb", PortReset: "false", FlashMethod: "native", - CodeModel: "default", } if goos == "darwin" { spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip") diff --git a/targets/fe310.json b/targets/fe310.json index bc95e8d4e0..76f7497053 100644 --- a/targets/fe310.json +++ b/targets/fe310.json @@ -1,5 +1,5 @@ { "inherits": ["riscv32"], "features": ["+a", "+c", "+m"], - "build-tags": ["fe310", "sifive"] + "build-tags": ["fe310", "sifive"] } diff --git a/targets/maixbit.ld b/targets/maixbit.ld index 9b277a6cea..e1162a38dc 100644 --- a/targets/maixbit.ld +++ b/targets/maixbit.ld @@ -1,7 +1,7 @@ MEMORY { - RAM (xrw) : ORIGIN = 0x80000000, LENGTH = (6 * 1024 * 1024) + RAM (xrw) : ORIGIN = 0x80000000, LENGTH = 6M } REGION_ALIAS("FLASH_TEXT", RAM); diff --git a/targets/riscv.json b/targets/riscv.json new file mode 100644 index 0000000000..313aa85811 --- /dev/null +++ b/targets/riscv.json @@ -0,0 +1,24 @@ +{ + "goos": "linux", + "goarch": "arm", + "build-tags": ["tinygo.riscv", "baremetal", "linux", "arm"], + "gc": "conservative", + "compiler": "clang", + "linker": "ld.lld", + "rtlib": "compiler-rt", + "libc": "picolibc", + "cflags": [ + "-Os", + "-Werror", + "-fno-exceptions", "-fno-unwind-tables", + "-ffunction-sections", "-fdata-sections" + ], + "ldflags": [ + "--gc-sections" + ], + "extra-files": [ + "src/device/riscv/start.S", + "src/runtime/scheduler_tinygoriscv.S" + ], + "gdb": "riscv64-unknown-elf-gdb" +} From 0b8a88914c4065e0a2bb1675f6b9a68f15dac336 Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Wed, 10 Jun 2020 09:28:51 +0200 Subject: [PATCH 05/28] cmsis-svd: change submodule url to the TinyGo fork --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index cbab142b2b..c877bbafb6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,7 +9,7 @@ url = https://github.com/avr-rust/avr-mcu.git [submodule "lib/cmsis-svd"] path = lib/cmsis-svd - url = https://github.com/yannishuber/cmsis-svd + url = https://github.com/tinygo-org/cmsis-svd [submodule "lib/compiler-rt"] path = lib/compiler-rt url = https://github.com/llvm-mirror/compiler-rt.git From d2edc3fdd66f451e48044bf92cccebefc6c9affa Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Wed, 10 Jun 2020 09:35:20 +0200 Subject: [PATCH 06/28] maix-bit: add code model in target definition This is needed to avoid linking errors because the globals are placed in memory at address 0x80000000 which is out of bounds for the default code model. --- targets/k210.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/targets/k210.json b/targets/k210.json index 5ddd9dbab9..4c5f3f91ff 100644 --- a/targets/k210.json +++ b/targets/k210.json @@ -1,5 +1,6 @@ { "inherits": ["riscv64"], "features": ["+a", "+c", "+m", "+f", "+d"], - "build-tags": ["k210", "kendryte"] + "build-tags": ["k210", "kendryte"], + "code-model": "medium" } From c407177c908268d78bd4e26fee6553a52a0d2714 Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Mon, 15 Jun 2020 08:56:11 +0200 Subject: [PATCH 07/28] maixbit: add board definition and dummy runtime --- src/machine/board_k210.go | 55 +++++++++++++ src/machine/board_maixbit.go | 61 ++++++++++++++ src/machine/machine_k210.go | 30 +++++++ src/runtime/runtime_k210.go | 110 ++++++++++++++++++++++++++ src/runtime/runtime_k210_baremetal.go | 27 +++++++ targets/maixbit.json | 2 +- 6 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 src/machine/board_k210.go create mode 100644 src/machine/board_maixbit.go create mode 100644 src/machine/machine_k210.go create mode 100644 src/runtime/runtime_k210.go create mode 100644 src/runtime/runtime_k210_baremetal.go diff --git a/src/machine/board_k210.go b/src/machine/board_k210.go new file mode 100644 index 0000000000..c72f8fe08b --- /dev/null +++ b/src/machine/board_k210.go @@ -0,0 +1,55 @@ +// +build maixbit + +package machine + +// K210 IO pins. +const ( + P00 Pin = 0 + P01 Pin = 1 + P02 Pin = 2 + P03 Pin = 3 + P04 Pin = 4 + P05 Pin = 5 + P06 Pin = 6 + P07 Pin = 7 + P08 Pin = 8 + P09 Pin = 9 + P10 Pin = 10 + P11 Pin = 11 + P12 Pin = 12 + P13 Pin = 13 + P14 Pin = 14 + P15 Pin = 15 + P16 Pin = 16 + P17 Pin = 17 + P18 Pin = 18 + P19 Pin = 19 + P20 Pin = 20 + P21 Pin = 21 + P22 Pin = 22 + P23 Pin = 23 + P24 Pin = 24 + P25 Pin = 25 + P26 Pin = 26 + P27 Pin = 27 + P28 Pin = 28 + P29 Pin = 29 + P30 Pin = 30 + P31 Pin = 31 + P32 Pin = 32 + P33 Pin = 33 + P34 Pin = 34 + P35 Pin = 35 + P36 Pin = 36 + P37 Pin = 37 + P38 Pin = 38 + P39 Pin = 39 + P40 Pin = 40 + P41 Pin = 41 + P42 Pin = 42 + P43 Pin = 43 + P44 Pin = 44 + P45 Pin = 45 + P46 Pin = 46 + P47 Pin = 47 +) diff --git a/src/machine/board_maixbit.go b/src/machine/board_maixbit.go new file mode 100644 index 0000000000..c68542e844 --- /dev/null +++ b/src/machine/board_maixbit.go @@ -0,0 +1,61 @@ +// +build maixbit + +package machine + +// GPIO pins. +const ( + D0 = P08 + D1 = P09 + D2 = P10 + D3 = P11 + D4 = P12 + D5 = P13 + D6 = P14 + D7 = P15 +) + +// High-speed GPIO pins (GPIOHS). +const ( + DHS0 = P16 + DHS1 = P17 + DHS2 = P18 + DHS3 = P19 + DHS4 = P20 + DHS5 = P21 + DHS6 = P22 + DHS7 = P23 + DHS8 = P24 + DHS9 = P25 + DHS10 = P26 + DHS11 = P27 + DHS12 = P28 + DHS13 = P29 + DHS14 = P30 + DHS15 = P31 + DHS16 = P32 + DHS17 = P33 + DHS18 = P34 + DHS19 = P35 + DHS20 = P36 + DHS21 = P37 + DHS22 = P38 + DHS23 = P39 + DHS24 = P40 + DHS25 = P41 + DHS26 = P42 + DHS27 = P43 + DHS28 = P44 + DHS29 = P45 + DHS30 = P46 + DHS31 = P47 +) + +const ( + LED = LED1 + LED1 = LED_RED + LED2 = LED_GREEN + LED3 = LED_BLUE + LED_RED = D5 + LED_GREEN = D4 + LED_BLUE = D6 +) diff --git a/src/machine/machine_k210.go b/src/machine/machine_k210.go new file mode 100644 index 0000000000..deff5472d2 --- /dev/null +++ b/src/machine/machine_k210.go @@ -0,0 +1,30 @@ +// +build k210 + +package machine + +func CPUFrequency() uint32 { + return 400000000 +} + +type PinMode uint8 + +const ( + PinInput PinMode = iota + PinOutput + PinPWM + PinSPI + PinI2C = PinSPI +) + +// Configure this pin with the given configuration. +func (p Pin) Configure(config PinConfig) { +} + +// Set the pin to high or low. +func (p Pin) Set(high bool) { +} + +// Get returns the current value of a GPIO pin. +func (p Pin) Get() bool { + return true +} diff --git a/src/runtime/runtime_k210.go b/src/runtime/runtime_k210.go new file mode 100644 index 0000000000..5486a3e98d --- /dev/null +++ b/src/runtime/runtime_k210.go @@ -0,0 +1,110 @@ +// +build k210 + +// This file implements target-specific things for the K210 chip as used in the +// MAix Bit with Mic. + +package runtime + +import ( + "unsafe" + + "device/riscv" + "runtime/volatile" +) + +type timeUnit int64 + +func postinit() {} + +//export main +func main() { + // todo + + // Set the interrupt address. + // Note that this address must be aligned specially, otherwise the MODE bits + // of MTVEC won't be zero. + riscv.MTVEC.Set(uintptr(unsafe.Pointer(&handleInterruptASM))) + + // Reset the MIE register and enable external interrupts. + // It must be reset here because it not zeroed at startup. + riscv.MIE.Set(1 << 11) // bit 11 is for machine external interrupts + + // Enable global interrupts now that they've been set up. + riscv.MSTATUS.SetBits(1 << 3) // MIE + + preinit() + initPeripherals() + run() + abort() +} + +//go:extern handleInterruptASM +var handleInterruptASM [0]uintptr + +//export handleInterrupt +func handleInterrupt() { + cause := riscv.MCAUSE.Get() + code := uint(cause &^ (1 << 31)) + if cause&(1<<31) != 0 { + // Topmost bit is set, which means that it is an interrupt. + switch code { + case 7: // Machine timer interrupt + // Signal timeout. + timerWakeup.Set(1) + // Disable the timer, to avoid triggering the interrupt right after + // this interrupt returns. + riscv.MIE.ClearBits(1 << 7) // MTIE bit + case 11: // Machine external interrupt + // Claim this interrupt. + //id := sifive.PLIC.CLAIM.Get() + // Call the interrupt handler, if any is registered for this ID. + callInterruptHandler(int(0)) + // Complete this interrupt. + //sifive.PLIC.CLAIM.Set(id) + } + } else { + // Topmost bit is clear, so it is an exception of some sort. + // We could implement support for unsupported instructions here (such as + // misaligned loads). However, for now we'll just print a fatal error. + handleException(code) + } +} + +// initPeripherals configures periperhals the way the runtime expects them. +func initPeripherals() { + // todo +} + +func putchar(c byte) { + //machine.UART0.WriteByte(c) +} + +const asyncScheduler = false + +var timerWakeup volatile.Register8 + +func ticks() timeUnit { + // todo +} + +func sleepTicks(d timeUnit) { + // todo +} + +// handleException is called from the interrupt handler for any exception. +// Exceptions can be things like illegal instructions, invalid memory +// read/write, and similar issues. +func handleException(code uint) { + // For a list of exception codes, see: + // https://content.riscv.org/wp-content/uploads/2019/08/riscv-privileged-20190608-1.pdf#page=49 + print("fatal error: exception with mcause=") + print(code) + print(" pc=") + print(riscv.MEPC.Get()) + println() + abort() +} + +// callInterruptHandler is a compiler-generated function that calls the +// appropriate interrupt handler for the given interrupt ID. +func callInterruptHandler(id int) diff --git a/src/runtime/runtime_k210_baremetal.go b/src/runtime/runtime_k210_baremetal.go new file mode 100644 index 0000000000..47f862bc94 --- /dev/null +++ b/src/runtime/runtime_k210_baremetal.go @@ -0,0 +1,27 @@ +// +build k210,!qemu + +package runtime + +import ( + "device/kendryte" + "device/riscv" +) + +var clockFrequency uint32 = kendryte.SYSCTL.CLK_FREQ.Get() + +// ticksToNanoseconds converts RTC ticks to nanoseconds. +func ticksToNanoseconds(ticks timeUnit) int64 { + return int64(ticks) * 1e9 / clockFrequency +} + +// nanosecondsToTicks converts nanoseconds to RTC ticks. +func nanosecondsToTicks(ns int64) timeUnit { + return timeUnit(ns * 64 / 1953125) +} + +func abort() { + // lock up forever + for { + riscv.Asm("wfi") + } +} diff --git a/targets/maixbit.json b/targets/maixbit.json index f0f5e8b274..eb664a484b 100644 --- a/targets/maixbit.json +++ b/targets/maixbit.json @@ -2,5 +2,5 @@ "inherits": ["k210"], "build-tags": ["maixbit"], "linkerscript": "targets/maixbit.ld", - "flash-command": "kflash -p /dev/ttyUSB0 {hex}" + "flash-command": "kflash -p {port} {hex}" } From 73cca1fd6eaffb0f7605c403567124e0ec241c6a Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Tue, 16 Jun 2020 00:05:32 +0200 Subject: [PATCH 08/28] maixbit (uart): working on data tx When the data to send is too long the program gives an exception. --- src/machine/board_k210.go | 262 ++++++++++++++++++++++++ src/machine/board_maixbit.go | 6 + src/machine/machine_k210.go | 67 +++++- src/machine/uart.go | 2 +- src/runtime/interrupt/interrupt_k210.go | 19 ++ src/runtime/runtime_k210.go | 83 ++++++-- src/runtime/runtime_k210_baremetal.go | 2 +- targets/maixbit.json | 2 +- 8 files changed, 417 insertions(+), 26 deletions(-) create mode 100644 src/runtime/interrupt/interrupt_k210.go diff --git a/src/machine/board_k210.go b/src/machine/board_k210.go index c72f8fe08b..4f899c2693 100644 --- a/src/machine/board_k210.go +++ b/src/machine/board_k210.go @@ -53,3 +53,265 @@ const ( P46 Pin = 46 P47 Pin = 47 ) + +type FPIOAFunc uint16 + +// FPIOA functions. +const ( + JTAG_TCLK FPIOAFunc = 0 // JTAG Test Clock + JTAG_TDI FPIOAFunc = 1 // JTAG Test Data In + JTAG_TMS FPIOAFunc = 2 // JTAG Test Mode Select + JTAG_TDO FPIOAFunc = 3 // JTAG Test Data Out + SPI0_D0 FPIOAFunc = 4 // SPI0 Data 0 + SPI0_D1 FPIOAFunc = 5 // SPI0 Data 1 + SPI0_D2 FPIOAFunc = 6 // SPI0 Data 2 + SPI0_D3 FPIOAFunc = 7 // SPI0 Data 3 + SPI0_D4 FPIOAFunc = 8 // SPI0 Data 4 + SPI0_D5 FPIOAFunc = 9 // SPI0 Data 5 + SPI0_D6 FPIOAFunc = 10 // SPI0 Data 6 + SPI0_D7 FPIOAFunc = 11 // SPI0 Data 7 + SPI0_SS0 FPIOAFunc = 12 // SPI0 Chip Select 0 + SPI0_SS1 FPIOAFunc = 13 // SPI0 Chip Select 1 + SPI0_SS2 FPIOAFunc = 14 // SPI0 Chip Select 2 + SPI0_SS3 FPIOAFunc = 15 // SPI0 Chip Select 3 + SPI0_ARB FPIOAFunc = 16 // SPI0 Arbitration + SPI0_SCLK FPIOAFunc = 17 // SPI0 Serial Clock + UARTHS_RX FPIOAFunc = 18 // UART High speed Receiver + UARTHS_TX FPIOAFunc = 19 // UART High speed Transmitter + RESV6 FPIOAFunc = 20 // Reserved function + RESV7 FPIOAFunc = 21 // Reserved function + CLK_SPI1 FPIOAFunc = 22 // Clock SPI1 + CLK_I2C1 FPIOAFunc = 23 // Clock I2C1 + GPIOHS0 FPIOAFunc = 24 // GPIO High speed 0 + GPIOHS1 FPIOAFunc = 25 // GPIO High speed 1 + GPIOHS2 FPIOAFunc = 26 // GPIO High speed 2 + GPIOHS3 FPIOAFunc = 27 // GPIO High speed 3 + GPIOHS4 FPIOAFunc = 28 // GPIO High speed 4 + GPIOHS5 FPIOAFunc = 29 // GPIO High speed 5 + GPIOHS6 FPIOAFunc = 30 // GPIO High speed 6 + GPIOHS7 FPIOAFunc = 31 // GPIO High speed 7 + GPIOHS8 FPIOAFunc = 32 // GPIO High speed 8 + GPIOHS9 FPIOAFunc = 33 // GPIO High speed 9 + GPIOHS10 FPIOAFunc = 34 // GPIO High speed 10 + GPIOHS11 FPIOAFunc = 35 // GPIO High speed 11 + GPIOHS12 FPIOAFunc = 36 // GPIO High speed 12 + GPIOHS13 FPIOAFunc = 37 // GPIO High speed 13 + GPIOHS14 FPIOAFunc = 38 // GPIO High speed 14 + GPIOHS15 FPIOAFunc = 39 // GPIO High speed 15 + GPIOHS16 FPIOAFunc = 40 // GPIO High speed 16 + GPIOHS17 FPIOAFunc = 41 // GPIO High speed 17 + GPIOHS18 FPIOAFunc = 42 // GPIO High speed 18 + GPIOHS19 FPIOAFunc = 43 // GPIO High speed 19 + GPIOHS20 FPIOAFunc = 44 // GPIO High speed 20 + GPIOHS21 FPIOAFunc = 45 // GPIO High speed 21 + GPIOHS22 FPIOAFunc = 46 // GPIO High speed 22 + GPIOHS23 FPIOAFunc = 47 // GPIO High speed 23 + GPIOHS24 FPIOAFunc = 48 // GPIO High speed 24 + GPIOHS25 FPIOAFunc = 49 // GPIO High speed 25 + GPIOHS26 FPIOAFunc = 50 // GPIO High speed 26 + GPIOHS27 FPIOAFunc = 51 // GPIO High speed 27 + GPIOHS28 FPIOAFunc = 52 // GPIO High speed 28 + GPIOHS29 FPIOAFunc = 53 // GPIO High speed 29 + GPIOHS30 FPIOAFunc = 54 // GPIO High speed 30 + GPIOHS31 FPIOAFunc = 55 // GPIO High speed 31 + GPIO0 FPIOAFunc = 56 // GPIO pin 0 + GPIO1 FPIOAFunc = 57 // GPIO pin 1 + GPIO2 FPIOAFunc = 58 // GPIO pin 2 + GPIO3 FPIOAFunc = 59 // GPIO pin 3 + GPIO4 FPIOAFunc = 60 // GPIO pin 4 + GPIO5 FPIOAFunc = 61 // GPIO pin 5 + GPIO6 FPIOAFunc = 62 // GPIO pin 6 + GPIO7 FPIOAFunc = 63 // GPIO pin 7 + UART1_RX FPIOAFunc = 64 // UART1 Receiver + UART1_TX FPIOAFunc = 65 // UART1 Transmitter + UART2_RX FPIOAFunc = 66 // UART2 Receiver + UART2_TX FPIOAFunc = 67 // UART2 Transmitter + UART3_RX FPIOAFunc = 68 // UART3 Receiver + UART3_TX FPIOAFunc = 69 // UART3 Transmitter + SPI1_D0 FPIOAFunc = 70 // SPI1 Data 0 + SPI1_D1 FPIOAFunc = 71 // SPI1 Data 1 + SPI1_D2 FPIOAFunc = 72 // SPI1 Data 2 + SPI1_D3 FPIOAFunc = 73 // SPI1 Data 3 + SPI1_D4 FPIOAFunc = 74 // SPI1 Data 4 + SPI1_D5 FPIOAFunc = 75 // SPI1 Data 5 + SPI1_D6 FPIOAFunc = 76 // SPI1 Data 6 + SPI1_D7 FPIOAFunc = 77 // SPI1 Data 7 + SPI1_SS0 FPIOAFunc = 78 // SPI1 Chip Select 0 + SPI1_SS1 FPIOAFunc = 79 // SPI1 Chip Select 1 + SPI1_SS2 FPIOAFunc = 80 // SPI1 Chip Select 2 + SPI1_SS3 FPIOAFunc = 81 // SPI1 Chip Select 3 + SPI1_ARB FPIOAFunc = 82 // SPI1 Arbitration + SPI1_SCLK FPIOAFunc = 83 // SPI1 Serial Clock + SPI_SLAVE_D0 FPIOAFunc = 84 // SPI Slave Data 0 + SPI_SLAVE_SS FPIOAFunc = 85 // SPI Slave Select + SPI_SLAVE_SCLK FPIOAFunc = 86 // SPI Slave Serial Clock + I2S0_MCLK FPIOAFunc = 87 // I2S0 Master Clock + I2S0_SCLK FPIOAFunc = 88 // I2S0 Serial Clock(BCLK) + I2S0_WS FPIOAFunc = 89 // I2S0 Word Select(LRCLK) + I2S0_IN_D0 FPIOAFunc = 90 // I2S0 Serial Data Input 0 + I2S0_IN_D1 FPIOAFunc = 91 // I2S0 Serial Data Input 1 + I2S0_IN_D2 FPIOAFunc = 92 // I2S0 Serial Data Input 2 + I2S0_IN_D3 FPIOAFunc = 93 // I2S0 Serial Data Input 3 + I2S0_OUT_D0 FPIOAFunc = 94 // I2S0 Serial Data Output 0 + I2S0_OUT_D1 FPIOAFunc = 95 // I2S0 Serial Data Output 1 + I2S0_OUT_D2 FPIOAFunc = 96 // I2S0 Serial Data Output 2 + I2S0_OUT_D3 FPIOAFunc = 97 // I2S0 Serial Data Output 3 + I2S1_MCLK FPIOAFunc = 98 // I2S1 Master Clock + I2S1_SCLK FPIOAFunc = 99 // I2S1 Serial Clock(BCLK) + I2S1_WS FPIOAFunc = 100 // I2S1 Word Select(LRCLK) + I2S1_IN_D0 FPIOAFunc = 101 // I2S1 Serial Data Input 0 + I2S1_IN_D1 FPIOAFunc = 102 // I2S1 Serial Data Input 1 + I2S1_IN_D2 FPIOAFunc = 103 // I2S1 Serial Data Input 2 + I2S1_IN_D3 FPIOAFunc = 104 // I2S1 Serial Data Input 3 + I2S1_OUT_D0 FPIOAFunc = 105 // I2S1 Serial Data Output 0 + I2S1_OUT_D1 FPIOAFunc = 106 // I2S1 Serial Data Output 1 + I2S1_OUT_D2 FPIOAFunc = 107 // I2S1 Serial Data Output 2 + I2S1_OUT_D3 FPIOAFunc = 108 // I2S1 Serial Data Output 3 + I2S2_MCLK FPIOAFunc = 109 // I2S2 Master Clock + I2S2_SCLK FPIOAFunc = 110 // I2S2 Serial Clock(BCLK) + I2S2_WS FPIOAFunc = 111 // I2S2 Word Select(LRCLK) + I2S2_IN_D0 FPIOAFunc = 112 // I2S2 Serial Data Input 0 + I2S2_IN_D1 FPIOAFunc = 113 // I2S2 Serial Data Input 1 + I2S2_IN_D2 FPIOAFunc = 114 // I2S2 Serial Data Input 2 + I2S2_IN_D3 FPIOAFunc = 115 // I2S2 Serial Data Input 3 + I2S2_OUT_D0 FPIOAFunc = 116 // I2S2 Serial Data Output 0 + I2S2_OUT_D1 FPIOAFunc = 117 // I2S2 Serial Data Output 1 + I2S2_OUT_D2 FPIOAFunc = 118 // I2S2 Serial Data Output 2 + I2S2_OUT_D3 FPIOAFunc = 119 // I2S2 Serial Data Output 3 + RESV0 FPIOAFunc = 120 // Reserved function + RESV1 FPIOAFunc = 121 // Reserved function + RESV2 FPIOAFunc = 122 // Reserved function + RESV3 FPIOAFunc = 123 // Reserved function + RESV4 FPIOAFunc = 124 // Reserved function + RESV5 FPIOAFunc = 125 // Reserved function + I2C0_SCLK FPIOAFunc = 126 // I2C0 Serial Clock + I2C0_SDA FPIOAFunc = 127 // I2C0 Serial Data + I2C1_SCLK FPIOAFunc = 128 // I2C1 Serial Clock + I2C1_SDA FPIOAFunc = 129 // I2C1 Serial Data + I2C2_SCLK FPIOAFunc = 130 // I2C2 Serial Clock + I2C2_SDA FPIOAFunc = 131 // I2C2 Serial Data + CMOS_XCLK FPIOAFunc = 132 // DVP System Clock + CMOS_RST FPIOAFunc = 133 // DVP System Reset + CMOS_PWDN FPIOAFunc = 134 // DVP Power Down Mode + CMOS_VSYNC FPIOAFunc = 135 // DVP Vertical Sync + CMOS_HREF FPIOAFunc = 136 // DVP Horizontal Reference output + CMOS_PCLK FPIOAFunc = 137 // Pixel Clock + CMOS_D0 FPIOAFunc = 138 // Data Bit 0 + CMOS_D1 FPIOAFunc = 139 // Data Bit 1 + CMOS_D2 FPIOAFunc = 140 // Data Bit 2 + CMOS_D3 FPIOAFunc = 141 // Data Bit 3 + CMOS_D4 FPIOAFunc = 142 // Data Bit 4 + CMOS_D5 FPIOAFunc = 143 // Data Bit 5 + CMOS_D6 FPIOAFunc = 144 // Data Bit 6 + CMOS_D7 FPIOAFunc = 145 // Data Bit 7 + SCCB_SCLK FPIOAFunc = 146 // SCCB Serial Clock + SCCB_SDA FPIOAFunc = 147 // SCCB Serial Data + UART1_CTS FPIOAFunc = 148 // UART1 Clear To Send + UART1_DSR FPIOAFunc = 149 // UART1 Data Set Ready + UART1_DCD FPIOAFunc = 150 // UART1 Data Carrier Detect + UART1_RI FPIOAFunc = 151 // UART1 Ring Indicator + UART1_SIR_IN FPIOAFunc = 152 // UART1 Serial Infrared Input + UART1_DTR FPIOAFunc = 153 // UART1 Data Terminal Ready + UART1_RTS FPIOAFunc = 154 // UART1 Request To Send + UART1_OUT2 FPIOAFunc = 155 // UART1 User-designated Output 2 + UART1_OUT1 FPIOAFunc = 156 // UART1 User-designated Output 1 + UART1_SIR_OUT FPIOAFunc = 157 // UART1 Serial Infrared Output + UART1_BAUD FPIOAFunc = 158 // UART1 Transmit Clock Output + UART1_RE FPIOAFunc = 159 // UART1 Receiver Output Enable + UART1_DE FPIOAFunc = 160 // UART1 Driver Output Enable + UART1_RS485_EN FPIOAFunc = 161 // UART1 RS485 Enable + UART2_CTS FPIOAFunc = 162 // UART2 Clear To Send + UART2_DSR FPIOAFunc = 163 // UART2 Data Set Ready + UART2_DCD FPIOAFunc = 164 // UART2 Data Carrier Detect + UART2_RI FPIOAFunc = 165 // UART2 Ring Indicator + UART2_SIR_IN FPIOAFunc = 166 // UART2 Serial Infrared Input + UART2_DTR FPIOAFunc = 167 // UART2 Data Terminal Ready + UART2_RTS FPIOAFunc = 168 // UART2 Request To Send + UART2_OUT2 FPIOAFunc = 169 // UART2 User-designated Output 2 + UART2_OUT1 FPIOAFunc = 170 // UART2 User-designated Output 1 + UART2_SIR_OUT FPIOAFunc = 171 // UART2 Serial Infrared Output + UART2_BAUD FPIOAFunc = 172 // UART2 Transmit Clock Output + UART2_RE FPIOAFunc = 173 // UART2 Receiver Output Enable + UART2_DE FPIOAFunc = 174 // UART2 Driver Output Enable + UART2_RS485_EN FPIOAFunc = 175 // UART2 RS485 Enable + UART3_CTS FPIOAFunc = 176 // UART3 Clear To Send + UART3_DSR FPIOAFunc = 177 // UART3 Data Set Ready + UART3_DCD FPIOAFunc = 178 // UART3 Data Carrier Detect + UART3_RI FPIOAFunc = 179 // UART3 Ring Indicator + UART3_SIR_IN FPIOAFunc = 180 // UART3 Serial Infrared Input + UART3_DTR FPIOAFunc = 181 // UART3 Data Terminal Ready + UART3_RTS FPIOAFunc = 182 // UART3 Request To Send + UART3_OUT2 FPIOAFunc = 183 // UART3 User-designated Output 2 + UART3_OUT1 FPIOAFunc = 184 // UART3 User-designated Output 1 + UART3_SIR_OUT FPIOAFunc = 185 // UART3 Serial Infrared Output + UART3_BAUD FPIOAFunc = 186 // UART3 Transmit Clock Output + UART3_RE FPIOAFunc = 187 // UART3 Receiver Output Enable + UART3_DE FPIOAFunc = 188 // UART3 Driver Output Enable + UART3_RS485_EN FPIOAFunc = 189 // UART3 RS485 Enable + TIMER0_TOGGLE1 FPIOAFunc = 190 // TIMER0 Toggle Output 1 + TIMER0_TOGGLE2 FPIOAFunc = 191 // TIMER0 Toggle Output 2 + TIMER0_TOGGLE3 FPIOAFunc = 192 // TIMER0 Toggle Output 3 + TIMER0_TOGGLE4 FPIOAFunc = 193 // TIMER0 Toggle Output 4 + TIMER1_TOGGLE1 FPIOAFunc = 194 // TIMER1 Toggle Output 1 + TIMER1_TOGGLE2 FPIOAFunc = 195 // TIMER1 Toggle Output 2 + TIMER1_TOGGLE3 FPIOAFunc = 196 // TIMER1 Toggle Output 3 + TIMER1_TOGGLE4 FPIOAFunc = 197 // TIMER1 Toggle Output 4 + TIMER2_TOGGLE1 FPIOAFunc = 198 // TIMER2 Toggle Output 1 + TIMER2_TOGGLE2 FPIOAFunc = 199 // TIMER2 Toggle Output 2 + TIMER2_TOGGLE3 FPIOAFunc = 200 // TIMER2 Toggle Output 3 + TIMER2_TOGGLE4 FPIOAFunc = 201 // TIMER2 Toggle Output 4 + CLK_SPI2 FPIOAFunc = 202 // Clock SPI2 + CLK_I2C2 FPIOAFunc = 203 // Clock I2C2 + INTERNAL0 FPIOAFunc = 204 // Internal function signal 0 + INTERNAL1 FPIOAFunc = 205 // Internal function signal 1 + INTERNAL2 FPIOAFunc = 206 // Internal function signal 2 + INTERNAL3 FPIOAFunc = 207 // Internal function signal 3 + INTERNAL4 FPIOAFunc = 208 // Internal function signal 4 + INTERNAL5 FPIOAFunc = 209 // Internal function signal 5 + INTERNAL6 FPIOAFunc = 210 // Internal function signal 6 + INTERNAL7 FPIOAFunc = 211 // Internal function signal 7 + INTERNAL8 FPIOAFunc = 212 // Internal function signal 8 + INTERNAL9 FPIOAFunc = 213 // Internal function signal 9 + INTERNAL10 FPIOAFunc = 214 // Internal function signal 10 + INTERNAL11 FPIOAFunc = 215 // Internal function signal 11 + INTERNAL12 FPIOAFunc = 216 // Internal function signal 12 + INTERNAL13 FPIOAFunc = 217 // Internal function signal 13 + INTERNAL14 FPIOAFunc = 218 // Internal function signal 14 + INTERNAL15 FPIOAFunc = 219 // Internal function signal 15 + INTERNAL16 FPIOAFunc = 220 // Internal function signal 16 + INTERNAL17 FPIOAFunc = 221 // Internal function signal 17 + CONSTANT FPIOAFunc = 222 // Constant function + INTERNAL18 FPIOAFunc = 223 // Internal function signal 18 + DEBUG0 FPIOAFunc = 224 // Debug function 0 + DEBUG1 FPIOAFunc = 225 // Debug function 1 + DEBUG2 FPIOAFunc = 226 // Debug function 2 + DEBUG3 FPIOAFunc = 227 // Debug function 3 + DEBUG4 FPIOAFunc = 228 // Debug function 4 + DEBUG5 FPIOAFunc = 229 // Debug function 5 + DEBUG6 FPIOAFunc = 230 // Debug function 6 + DEBUG7 FPIOAFunc = 231 // Debug function 7 + DEBUG8 FPIOAFunc = 232 // Debug function 8 + DEBUG9 FPIOAFunc = 233 // Debug function 9 + DEBUG10 FPIOAFunc = 234 // Debug function 10 + DEBUG11 FPIOAFunc = 235 // Debug function 11 + DEBUG12 FPIOAFunc = 236 // Debug function 12 + DEBUG13 FPIOAFunc = 237 // Debug function 13 + DEBUG14 FPIOAFunc = 238 // Debug function 14 + DEBUG15 FPIOAFunc = 239 // Debug function 15 + DEBUG16 FPIOAFunc = 240 // Debug function 16 + DEBUG17 FPIOAFunc = 241 // Debug function 17 + DEBUG18 FPIOAFunc = 242 // Debug function 18 + DEBUG19 FPIOAFunc = 243 // Debug function 19 + DEBUG20 FPIOAFunc = 244 // Debug function 20 + DEBUG21 FPIOAFunc = 245 // Debug function 21 + DEBUG22 FPIOAFunc = 246 // Debug function 22 + DEBUG23 FPIOAFunc = 247 // Debug function 23 + DEBUG24 FPIOAFunc = 248 // Debug function 24 + DEBUG25 FPIOAFunc = 249 // Debug function 25 + DEBUG26 FPIOAFunc = 250 // Debug function 26 + DEBUG27 FPIOAFunc = 251 // Debug function 27 + DEBUG28 FPIOAFunc = 252 // Debug function 28 + DEBUG29 FPIOAFunc = 253 // Debug function 29 + DEBUG30 FPIOAFunc = 254 // Debug function 30 + DEBUG31 FPIOAFunc = 255 // Debug function 31 +) diff --git a/src/machine/board_maixbit.go b/src/machine/board_maixbit.go index c68542e844..e0c1d9ca36 100644 --- a/src/machine/board_maixbit.go +++ b/src/machine/board_maixbit.go @@ -59,3 +59,9 @@ const ( LED_GREEN = D4 LED_BLUE = D6 ) + +// Default pins for UARTHS +const ( + UART_TX_PIN = P05 + UART_RX_PIN = P04 +) diff --git a/src/machine/machine_k210.go b/src/machine/machine_k210.go index deff5472d2..9f040dc78b 100644 --- a/src/machine/machine_k210.go +++ b/src/machine/machine_k210.go @@ -2,8 +2,13 @@ package machine +import ( + "device/kendryte" + "runtime/interrupt" +) + func CPUFrequency() uint32 { - return 400000000 + return 390000000 } type PinMode uint8 @@ -28,3 +33,63 @@ func (p Pin) Set(high bool) { func (p Pin) Get() bool { return true } + +type FPIOA struct { + Bus *kendryte.FPIOA_Type +} + +var ( + FPIOA0 = FPIOA{Bus: kendryte.FPIOA} +) + +func (fpioa FPIOA) Init() { + // Enable APB0 clock. + kendryte.SYSCTL.CLK_EN_CENT.Set(kendryte.SYSCTL_CLK_EN_CENT_APB0_CLK_EN) + + // Enable FPIOA peripheral. + kendryte.SYSCTL.CLK_EN_PERI.Set(kendryte.SYSCTL_CLK_EN_PERI_FPIOA_CLK_EN) +} + +type UART struct { + Bus *kendryte.UARTHS_Type + Buffer *RingBuffer +} + +var ( + UART0 = UART{Bus: kendryte.UARTHS, Buffer: NewRingBuffer()} +) + +func (uart UART) Configure(config UARTConfig) { + + div := CPUFrequency()/115200 - 1 + + uart.Bus.DIV.Set(div) + uart.Bus.TXCTRL.Set(kendryte.UARTHS_TXCTRL_TXEN) + 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) + intr.SetPriority(5) + intr.Enable()*/ + +} + +func (uart UART) handleInterrupt(interrupt.Interrupt) { + rxdata := uart.Bus.RXDATA.Get() + c := byte(rxdata) + if uint32(c) != rxdata { + // The rxdata has other bits set than just the low 8 bits. This probably + // means that the 'empty' flag is set, which indicates there is no data + // to be read and the byte is garbage. Ignore this byte. + return + } + uart.Receive(c) +} + +func (uart UART) WriteByte(c byte) { + for uart.Bus.TXDATA.Get()&kendryte.UARTHS_TXDATA_FULL != 0 { + } + + uart.Bus.TXDATA.Set(uint32(c)) +} diff --git a/src/machine/uart.go b/src/machine/uart.go index 19febc755f..f3f46a5712 100644 --- a/src/machine/uart.go +++ b/src/machine/uart.go @@ -1,4 +1,4 @@ -// +build avr nrf sam sifive stm32 +// +build avr nrf sam sifive stm32 k210 package machine diff --git a/src/runtime/interrupt/interrupt_k210.go b/src/runtime/interrupt/interrupt_k210.go new file mode 100644 index 0000000000..c75f85ae7a --- /dev/null +++ b/src/runtime/interrupt/interrupt_k210.go @@ -0,0 +1,19 @@ +// +build k210 + +package interrupt + +import "device/kendryte" + +// Enable enables this interrupt. Right after calling this function, the +// interrupt may be invoked if it was already pending. +func (irq Interrupt) Enable() { + // TODO: Use current hartid + kendryte.PLIC.TARGET_ENABLES[0].ENABLE[irq.num/32].SetBits(1 << (uint(irq.num) % 32)) +} + +// SetPriority sets the interrupt priority for this interrupt. A higher priority +// number means a higher priority (unlike Cortex-M). Priority 0 effectively +// disables the interrupt. +func (irq Interrupt) SetPriority(priority uint8) { + kendryte.PLIC.PRIORITY[irq.num].Set(uint32(priority)) +} diff --git a/src/runtime/runtime_k210.go b/src/runtime/runtime_k210.go index 5486a3e98d..ea65890c86 100644 --- a/src/runtime/runtime_k210.go +++ b/src/runtime/runtime_k210.go @@ -6,10 +6,11 @@ package runtime import ( - "unsafe" - + "device/kendryte" "device/riscv" + "machine" "runtime/volatile" + "unsafe" ) type timeUnit int64 @@ -18,24 +19,41 @@ func postinit() {} //export main func main() { - // todo - // Set the interrupt address. - // Note that this address must be aligned specially, otherwise the MODE bits - // of MTVEC won't be zero. - riscv.MTVEC.Set(uintptr(unsafe.Pointer(&handleInterruptASM))) + // Only use one core for the moment + if riscv.MHARTID.Get() == 0 { + // 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 + } - // Reset the MIE register and enable external interrupts. - // It must be reset here because it not zeroed at startup. - riscv.MIE.Set(1 << 11) // bit 11 is for machine external interrupts + // Zero the PLIC threshold bits to allow all interrupts. + kendryte.PLIC.TARGETS[0].THRESHOLD.Set(0) - // Enable global interrupts now that they've been set up. - riscv.MSTATUS.SetBits(1 << 3) // MIE + // Reset all interrupt source priorities to zero. + for i := 0; i < kendryte.IRQ_max; i++ { + kendryte.PLIC.PRIORITY[i].Set(0) + } - preinit() - initPeripherals() - run() - abort() + // Set the interrupt address. + // Note that this address must be aligned specially, otherwise the MODE bits + // of MTVEC won't be zero. + riscv.MTVEC.Set(uintptr(unsafe.Pointer(&handleInterruptASM))) + + // Reset the MIE register and enable external interrupts. + // It must be reset here because it not zeroed at startup. + riscv.MIE.Set(1 << 11) // bit 11 is for machine external interrupts + + // Enable global interrupts now that they've been set up. + riscv.MSTATUS.SetBits(1 << 3) // MIE + + preinit() + initPeripherals() + run() + abort() + } else { + abort() + } } //go:extern handleInterruptASM @@ -56,11 +74,11 @@ func handleInterrupt() { riscv.MIE.ClearBits(1 << 7) // MTIE bit case 11: // Machine external interrupt // Claim this interrupt. - //id := sifive.PLIC.CLAIM.Get() + id := kendryte.PLIC.TARGETS[0].CLAIM.Get() // Call the interrupt handler, if any is registered for this ID. callInterruptHandler(int(0)) // Complete this interrupt. - //sifive.PLIC.CLAIM.Set(id) + kendryte.PLIC.TARGETS[0].CLAIM.Set(id) } } else { // Topmost bit is clear, so it is an exception of some sort. @@ -72,11 +90,14 @@ func handleInterrupt() { // initPeripherals configures periperhals the way the runtime expects them. func initPeripherals() { - // todo + + //machine.FPIOA0.Init() + + machine.UART0.Configure(machine.UARTConfig{}) } func putchar(c byte) { - //machine.UART0.WriteByte(c) + machine.UART0.WriteByte(c) } const asyncScheduler = false @@ -84,11 +105,29 @@ const asyncScheduler = false var timerWakeup volatile.Register8 func ticks() timeUnit { - // todo + highBits := uint32(kendryte.CLINT.MTIME.Get() >> 32) + for { + lowBits := uint32(kendryte.CLINT.MTIME.Get() & 0xffffffff) + newHighBits := uint32(kendryte.CLINT.MTIME.Get() >> 32) + if newHighBits == highBits { + return timeUnit(lowBits) | (timeUnit(highBits) << 32) + } + highBits = newHighBits + } } func sleepTicks(d timeUnit) { - // todo + target := uint64(ticks() + d) + kendryte.CLINT.MTIMECMP[0].Set(target) + riscv.MIE.SetBits(1 << 7) // MTIE + for { + if timerWakeup.Get() != 0 { + timerWakeup.Set(0) + // Disable timer. + break + } + riscv.Asm("wfi") + } } // handleException is called from the interrupt handler for any exception. diff --git a/src/runtime/runtime_k210_baremetal.go b/src/runtime/runtime_k210_baremetal.go index 47f862bc94..f99cb72a01 100644 --- a/src/runtime/runtime_k210_baremetal.go +++ b/src/runtime/runtime_k210_baremetal.go @@ -7,7 +7,7 @@ import ( "device/riscv" ) -var clockFrequency uint32 = kendryte.SYSCTL.CLK_FREQ.Get() +var clockFrequency int64 = int64(kendryte.SYSCTL.CLK_FREQ.Get()) // ticksToNanoseconds converts RTC ticks to nanoseconds. func ticksToNanoseconds(ticks timeUnit) int64 { diff --git a/targets/maixbit.json b/targets/maixbit.json index eb664a484b..8799fd2b21 100644 --- a/targets/maixbit.json +++ b/targets/maixbit.json @@ -2,5 +2,5 @@ "inherits": ["k210"], "build-tags": ["maixbit"], "linkerscript": "targets/maixbit.ld", - "flash-command": "kflash -p {port} {hex}" + "flash-command": "kflash -p {port} {bin}" } From 15330e75396c408a70c672f91c95159354dfb1ff Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Tue, 16 Jun 2020 11:28:19 +0200 Subject: [PATCH 09/28] riscv: align stack and data sections to 8 bytes Alignment on 4 bytes can cause load/store address misalignment exceptions when loading/storing 64bit values on the stack. --- targets/riscv.ld | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/targets/riscv.ld b/targets/riscv.ld index 7f4427a8cf..6ebee27288 100644 --- a/targets/riscv.ld +++ b/targets/riscv.ld @@ -18,7 +18,7 @@ SECTIONS * See: http://blog.japaric.io/stack-overflow-protection/ */ .stack (NOLOAD) : { - . = ALIGN(4); + . = ALIGN(8); . += _stack_size; _stack_top = .; } >RAM @@ -29,25 +29,25 @@ SECTIONS /* Globals with initial value */ .data : { - . = ALIGN(4); + . = ALIGN(8); /* see https://gnu-mcu-eclipse.github.io/arch/riscv/programmer/#the-gp-global-pointer-register */ PROVIDE( __global_pointer$ = . + (4K / 2) ); _sdata = .; /* used by startup code */ *(.sdata) *(.data .data.*) - . = ALIGN(4); + . = ALIGN(8); _edata = .; /* used by startup code */ } >RAM AT>FLASH_TEXT /* Zero-initialized globals */ .bss : { - . = ALIGN(4); + . = ALIGN(8); _sbss = .; /* used by startup code */ *(.sbss) *(.bss .bss.*) *(COMMON) - . = ALIGN(4); + . = ALIGN(8); _ebss = .; /* used by startup code */ } >RAM From 30ca2f4633c089415134a8e06c4e412485fb3dfe Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Tue, 16 Jun 2020 14:55:55 +0200 Subject: [PATCH 10/28] maixbit (uart): serial is working with echo example --- src/device/riscv/start64.S | 60 +++++++++++++++++ src/machine/machine_k210.go | 13 ++-- src/runtime/arch_tinygoriscv.go | 2 +- src/runtime/arch_tinygoriscv64.go | 92 +++++++++++++++++++++++++++ src/runtime/runtime_k210.go | 38 +++++++---- src/runtime/runtime_tinygoriscv.go | 2 +- src/runtime/runtime_tinygoriscv64.go | 38 +++++++++++ src/runtime/scheduler_tinygoriscv64.S | 32 ++++++++++ targets/riscv.json | 4 -- targets/riscv32.json | 5 ++ targets/riscv64.json | 4 ++ 11 files changed, 263 insertions(+), 27 deletions(-) create mode 100644 src/device/riscv/start64.S create mode 100644 src/runtime/arch_tinygoriscv64.go create mode 100644 src/runtime/runtime_tinygoriscv64.go create mode 100644 src/runtime/scheduler_tinygoriscv64.S diff --git a/src/device/riscv/start64.S b/src/device/riscv/start64.S new file mode 100644 index 0000000000..b21bfb13ad --- /dev/null +++ b/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 diff --git a/src/machine/machine_k210.go b/src/machine/machine_k210.go index 9f040dc78b..3e89305e4f 100644 --- a/src/machine/machine_k210.go +++ b/src/machine/machine_k210.go @@ -60,22 +60,21 @@ var ( ) func (uart UART) Configure(config UARTConfig) { - div := CPUFrequency()/115200 - 1 uart.Bus.DIV.Set(div) uart.Bus.TXCTRL.Set(kendryte.UARTHS_TXCTRL_TXEN) 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) - intr.SetPriority(5) - intr.Enable()*/ + // Enable interrupts on receive. + uart.Bus.IE.Set(kendryte.UARTHS_IE_RXWM) + intr := interrupt.New(kendryte.IRQ_UARTHS, UART0.handleInterrupt) + intr.SetPriority(5) + intr.Enable() } -func (uart UART) handleInterrupt(interrupt.Interrupt) { +func (uart *UART) handleInterrupt(interrupt.Interrupt) { rxdata := uart.Bus.RXDATA.Get() c := byte(rxdata) if uint32(c) != rxdata { diff --git a/src/runtime/arch_tinygoriscv.go b/src/runtime/arch_tinygoriscv.go index 7aa34b50dc..8bd0f0767d 100644 --- a/src/runtime/arch_tinygoriscv.go +++ b/src/runtime/arch_tinygoriscv.go @@ -1,4 +1,4 @@ -// +build tinygo.riscv +// +build tinygo.riscv32 package runtime diff --git a/src/runtime/arch_tinygoriscv64.go b/src/runtime/arch_tinygoriscv64.go new file mode 100644 index 0000000000..17cddf60b0 --- /dev/null +++ b/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) +} diff --git a/src/runtime/runtime_k210.go b/src/runtime/runtime_k210.go index ea65890c86..625cdcd009 100644 --- a/src/runtime/runtime_k210.go +++ b/src/runtime/runtime_k210.go @@ -20,15 +20,11 @@ func postinit() {} //export main func main() { - // Only use one core for the moment - if riscv.MHARTID.Get() == 0 { - // 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 - } + // Both harts should disable all interrupts on startup. + initPLIC() - // Zero the PLIC threshold bits to allow all interrupts. - kendryte.PLIC.TARGETS[0].THRESHOLD.Set(0) + // Only use one hart for the moment. + if riscv.MHARTID.Get() == 0 { // Reset all interrupt source priorities to zero. 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 var handleInterruptASM [0]uintptr //export handleInterrupt func handleInterrupt() { cause := riscv.MCAUSE.Get() - code := uint(cause &^ (1 << 31)) - if cause&(1<<31) != 0 { + code := uint64(cause &^ (1 << 63)) + if cause&(1<<63) != 0 { // Topmost bit is set, which means that it is an interrupt. switch code { case 7: // Machine timer interrupt @@ -73,12 +81,14 @@ func handleInterrupt() { // this interrupt returns. riscv.MIE.ClearBits(1 << 7) // MTIE bit case 11: // Machine external interrupt + hartId := riscv.MHARTID.Get() + // 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. - callInterruptHandler(int(0)) + callInterruptHandler(int(id)) // Complete this interrupt. - kendryte.PLIC.TARGETS[0].CLAIM.Set(id) + kendryte.PLIC.TARGETS[hartId].CLAIM.Set(id) } } else { // 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. // Exceptions can be things like illegal instructions, invalid memory // read/write, and similar issues. -func handleException(code uint) { +func handleException(code uint64) { // For a list of exception codes, see: // https://content.riscv.org/wp-content/uploads/2019/08/riscv-privileged-20190608-1.pdf#page=49 print("fatal error: exception with mcause=") diff --git a/src/runtime/runtime_tinygoriscv.go b/src/runtime/runtime_tinygoriscv.go index 93bf1e45fd..857b93a72d 100644 --- a/src/runtime/runtime_tinygoriscv.go +++ b/src/runtime/runtime_tinygoriscv.go @@ -1,4 +1,4 @@ -// +build tinygo.riscv +// +build tinygo.riscv32 package runtime diff --git a/src/runtime/runtime_tinygoriscv64.go b/src/runtime/runtime_tinygoriscv64.go new file mode 100644 index 0000000000..d995efce90 --- /dev/null +++ b/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) + } +} diff --git a/src/runtime/scheduler_tinygoriscv64.S b/src/runtime/scheduler_tinygoriscv64.S new file mode 100644 index 0000000000..204f964f77 --- /dev/null +++ b/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 diff --git a/targets/riscv.json b/targets/riscv.json index 313aa85811..d78026b348 100644 --- a/targets/riscv.json +++ b/targets/riscv.json @@ -16,9 +16,5 @@ "ldflags": [ "--gc-sections" ], - "extra-files": [ - "src/device/riscv/start.S", - "src/runtime/scheduler_tinygoriscv.S" - ], "gdb": "riscv64-unknown-elf-gdb" } diff --git a/targets/riscv32.json b/targets/riscv32.json index dc07c209c3..4fd0d6426a 100644 --- a/targets/riscv32.json +++ b/targets/riscv32.json @@ -1,6 +1,7 @@ { "inherits": ["riscv"], "llvm-target": "riscv32--none", + "build-tags": ["tinygo.riscv32"], "cflags": [ "--target=riscv32--none", "-march=rv32imac", @@ -8,5 +9,9 @@ ], "ldflags": [ "-melf32lriscv" + ], + "extra-files": [ + "src/runtime/scheduler_tinygoriscv.S", + "src/device/riscv/start.S" ] } diff --git a/targets/riscv64.json b/targets/riscv64.json index a2a0641f98..ec5cb50300 100644 --- a/targets/riscv64.json +++ b/targets/riscv64.json @@ -9,5 +9,9 @@ ], "ldflags": [ "-melf64lriscv" + ], + "extra-files": [ + "src/runtime/scheduler_tinygoriscv64.S", + "src/device/riscv/start64.S" ] } From c28e217af84b1dc51009dca954014e6571df764f Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Tue, 16 Jun 2020 15:25:51 +0200 Subject: [PATCH 11/28] riscv: fix offset in 64bit scheduler Also keep common start.S file for 64 and 32 bit architectures. --- src/device/riscv/handleinterrupt32.S | 44 ++++++++++++++++++ .../riscv/{start64.S => handleinterrupt64.S} | 16 ------- src/device/riscv/start.S | 45 ------------------- src/runtime/scheduler_tinygoriscv64.S | 32 ++++++------- targets/riscv.json | 3 ++ targets/riscv32.json | 2 +- targets/riscv64.json | 2 +- 7 files changed, 65 insertions(+), 79 deletions(-) create mode 100644 src/device/riscv/handleinterrupt32.S rename src/device/riscv/{start64.S => handleinterrupt64.S} (72%) diff --git a/src/device/riscv/handleinterrupt32.S b/src/device/riscv/handleinterrupt32.S new file mode 100644 index 0000000000..4358977ae0 --- /dev/null +++ b/src/device/riscv/handleinterrupt32.S @@ -0,0 +1,44 @@ +.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, -64 + sw ra, 60(sp) + sw t0, 56(sp) + sw t1, 52(sp) + sw t2, 48(sp) + sw a0, 44(sp) + sw a1, 40(sp) + sw a2, 36(sp) + sw a3, 32(sp) + sw a4, 28(sp) + sw a5, 24(sp) + sw a6, 20(sp) + sw a7, 16(sp) + sw t3, 12(sp) + sw t4, 8(sp) + sw t5, 4(sp) + sw t6, 0(sp) + call handleInterrupt + lw t6, 0(sp) + lw t5, 4(sp) + lw t4, 8(sp) + lw t3, 12(sp) + lw a7, 16(sp) + lw a6, 20(sp) + lw a5, 24(sp) + lw a4, 28(sp) + lw a3, 32(sp) + lw a2, 36(sp) + lw a1, 40(sp) + lw a0, 44(sp) + lw t2, 48(sp) + lw t1, 52(sp) + lw t0, 56(sp) + lw ra, 60(sp) + addi sp, sp, 64 + mret diff --git a/src/device/riscv/start64.S b/src/device/riscv/handleinterrupt64.S similarity index 72% rename from src/device/riscv/start64.S rename to src/device/riscv/handleinterrupt64.S index b21bfb13ad..e0c6a3bf5e 100644 --- a/src/device/riscv/start64.S +++ b/src/device/riscv/handleinterrupt64.S @@ -1,19 +1,3 @@ -.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 diff --git a/src/device/riscv/start.S b/src/device/riscv/start.S index 06c9c4a2e3..eee57fee72 100644 --- a/src/device/riscv/start.S +++ b/src/device/riscv/start.S @@ -13,48 +13,3 @@ _start: // 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, -64 - sw ra, 60(sp) - sw t0, 56(sp) - sw t1, 52(sp) - sw t2, 48(sp) - sw a0, 44(sp) - sw a1, 40(sp) - sw a2, 36(sp) - sw a3, 32(sp) - sw a4, 28(sp) - sw a5, 24(sp) - sw a6, 20(sp) - sw a7, 16(sp) - sw t3, 12(sp) - sw t4, 8(sp) - sw t5, 4(sp) - sw t6, 0(sp) - call handleInterrupt - lw t6, 0(sp) - lw t5, 4(sp) - lw t4, 8(sp) - lw t3, 12(sp) - lw a7, 16(sp) - lw a6, 20(sp) - lw a5, 24(sp) - lw a4, 28(sp) - lw a3, 32(sp) - lw a2, 36(sp) - lw a1, 40(sp) - lw a0, 44(sp) - lw t2, 48(sp) - lw t1, 52(sp) - lw t0, 56(sp) - lw ra, 60(sp) - addi sp, sp, 64 - mret diff --git a/src/runtime/scheduler_tinygoriscv64.S b/src/runtime/scheduler_tinygoriscv64.S index 204f964f77..84be3e2de6 100644 --- a/src/runtime/scheduler_tinygoriscv64.S +++ b/src/runtime/scheduler_tinygoriscv64.S @@ -3,30 +3,30 @@ .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) + addi sp, sp, -104 + sd ra, 96(sp) + sd s11, 88(sp) + sd s10, 80(sp) + sd s9, 72(sp) + sd s8, 64(sp) + sd s7, 56(sp) + sd s6, 48(sp) + sd s5, 40(sp) + sd s4, 32(sp) + sd s3, 24(sp) + sd s2, 16(sp) + sd s1, 8(sp) + sd s0, 0(sp) // Scan the stack. mv a0, sp call tinygo_scanstack // Restore return address. - ld ra, 60(sp) + ld ra, 96(sp) // Restore stack state. - addi sp, sp, 128 + addi sp, sp, 104 // Return to the caller. ret diff --git a/targets/riscv.json b/targets/riscv.json index d78026b348..a2d4aaeb69 100644 --- a/targets/riscv.json +++ b/targets/riscv.json @@ -16,5 +16,8 @@ "ldflags": [ "--gc-sections" ], + "extra-files": [ + "src/device/riscv/start.S" + ], "gdb": "riscv64-unknown-elf-gdb" } diff --git a/targets/riscv32.json b/targets/riscv32.json index 4fd0d6426a..fb1bdb94f3 100644 --- a/targets/riscv32.json +++ b/targets/riscv32.json @@ -12,6 +12,6 @@ ], "extra-files": [ "src/runtime/scheduler_tinygoriscv.S", - "src/device/riscv/start.S" + "src/device/riscv/handleinterrupt32.S" ] } diff --git a/targets/riscv64.json b/targets/riscv64.json index ec5cb50300..20c7f1baf2 100644 --- a/targets/riscv64.json +++ b/targets/riscv64.json @@ -12,6 +12,6 @@ ], "extra-files": [ "src/runtime/scheduler_tinygoriscv64.S", - "src/device/riscv/start64.S" + "src/device/riscv/handleinterrupt64.S" ] } From c53a80c67c76941f516d5226047e9f4620c18e68 Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Thu, 18 Jun 2020 10:56:51 +0200 Subject: [PATCH 12/28] maixbit: add chip datasheet link and reformat code --- src/machine/board_k210.go | 2 ++ src/runtime/runtime_k210.go | 41 ++++++++++++++++++------------------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/machine/board_k210.go b/src/machine/board_k210.go index 4f899c2693..de96f1efad 100644 --- a/src/machine/board_k210.go +++ b/src/machine/board_k210.go @@ -1,5 +1,7 @@ // +build maixbit +// Chip datasheet: https://s3.cn-north-1.amazonaws.com.cn/dl.kendryte.com/documents/kendryte_datasheet_20181011163248_en.pdf + package machine // K210 IO pins. diff --git a/src/runtime/runtime_k210.go b/src/runtime/runtime_k210.go index 625cdcd009..b33ff5128e 100644 --- a/src/runtime/runtime_k210.go +++ b/src/runtime/runtime_k210.go @@ -24,32 +24,31 @@ func main() { initPLIC() // Only use one hart for the moment. - if riscv.MHARTID.Get() == 0 { + if riscv.MHARTID.Get() != 0 { + abort() + } - // Reset all interrupt source priorities to zero. - for i := 0; i < kendryte.IRQ_max; i++ { - kendryte.PLIC.PRIORITY[i].Set(0) - } + // Reset all interrupt source priorities to zero. + for i := 0; i < kendryte.IRQ_max; i++ { + kendryte.PLIC.PRIORITY[i].Set(0) + } - // Set the interrupt address. - // Note that this address must be aligned specially, otherwise the MODE bits - // of MTVEC won't be zero. - riscv.MTVEC.Set(uintptr(unsafe.Pointer(&handleInterruptASM))) + // Set the interrupt address. + // Note that this address must be aligned specially, otherwise the MODE bits + // of MTVEC won't be zero. + riscv.MTVEC.Set(uintptr(unsafe.Pointer(&handleInterruptASM))) - // Reset the MIE register and enable external interrupts. - // It must be reset here because it not zeroed at startup. - riscv.MIE.Set(1 << 11) // bit 11 is for machine external interrupts + // Reset the MIE register and enable external interrupts. + // It must be reset here because it not zeroed at startup. + riscv.MIE.Set(1 << 11) // bit 11 is for machine external interrupts - // Enable global interrupts now that they've been set up. - riscv.MSTATUS.SetBits(1 << 3) // MIE + // Enable global interrupts now that they've been set up. + riscv.MSTATUS.SetBits(1 << 3) // MIE - preinit() - initPeripherals() - run() - abort() - } else { - abort() - } + preinit() + initPeripherals() + run() + abort() } func initPLIC() { From 7e6252cf16ca67d1deab97a8c48f91f4d14f9bbb Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Thu, 18 Jun 2020 13:15:48 +0200 Subject: [PATCH 13/28] maixbit: remove atomic operations --- src/runtime/arch_tinygoriscv64.go | 73 ------------------------------- 1 file changed, 73 deletions(-) diff --git a/src/runtime/arch_tinygoriscv64.go b/src/runtime/arch_tinygoriscv64.go index 17cddf60b0..f17e1dfd25 100644 --- a/src/runtime/arch_tinygoriscv64.go +++ b/src/runtime/arch_tinygoriscv64.go @@ -17,76 +17,3 @@ func align(ptr uintptr) uintptr { 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) -} From 468dbd907cc6c547f0508757f789fac8f273d334 Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Thu, 18 Jun 2020 15:26:38 +0200 Subject: [PATCH 14/28] maixbit: init fpioa clock at reset --- src/machine/machine_k210.go | 4 ++-- src/runtime/interrupt/interrupt_k210.go | 9 ++++++--- src/runtime/runtime_k210.go | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/machine/machine_k210.go b/src/machine/machine_k210.go index 3e89305e4f..3c3b506e5c 100644 --- a/src/machine/machine_k210.go +++ b/src/machine/machine_k210.go @@ -44,10 +44,10 @@ var ( func (fpioa FPIOA) Init() { // Enable APB0 clock. - kendryte.SYSCTL.CLK_EN_CENT.Set(kendryte.SYSCTL_CLK_EN_CENT_APB0_CLK_EN) + kendryte.SYSCTL.CLK_EN_CENT.SetBits(kendryte.SYSCTL_CLK_EN_CENT_APB0_CLK_EN) // Enable FPIOA peripheral. - kendryte.SYSCTL.CLK_EN_PERI.Set(kendryte.SYSCTL_CLK_EN_PERI_FPIOA_CLK_EN) + kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_FPIOA_CLK_EN) } type UART struct { diff --git a/src/runtime/interrupt/interrupt_k210.go b/src/runtime/interrupt/interrupt_k210.go index c75f85ae7a..a4cf89f590 100644 --- a/src/runtime/interrupt/interrupt_k210.go +++ b/src/runtime/interrupt/interrupt_k210.go @@ -2,13 +2,16 @@ package interrupt -import "device/kendryte" +import ( + "device/kendryte" + "device/riscv" +) // Enable enables this interrupt. Right after calling this function, the // interrupt may be invoked if it was already pending. func (irq Interrupt) Enable() { - // TODO: Use current hartid - kendryte.PLIC.TARGET_ENABLES[0].ENABLE[irq.num/32].SetBits(1 << (uint(irq.num) % 32)) + hartId := riscv.MHARTID.Get() + kendryte.PLIC.TARGET_ENABLES[hartId].ENABLE[irq.num/32].SetBits(1 << (uint(irq.num) % 32)) } // SetPriority sets the interrupt priority for this interrupt. A higher priority diff --git a/src/runtime/runtime_k210.go b/src/runtime/runtime_k210.go index b33ff5128e..b53ec106e6 100644 --- a/src/runtime/runtime_k210.go +++ b/src/runtime/runtime_k210.go @@ -100,7 +100,7 @@ func handleInterrupt() { // initPeripherals configures periperhals the way the runtime expects them. func initPeripherals() { - //machine.FPIOA0.Init() + machine.FPIOA0.Init() machine.UART0.Configure(machine.UARTConfig{}) } From 89ba7d9c01bc949a3db0482e053369b3e37ec862 Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Fri, 19 Jun 2020 17:35:36 +0200 Subject: [PATCH 15/28] maixbit: support both GPIO and GPIOHS controllers --- src/machine/board_k210.go | 262 -------------------------- src/machine/machine_k210.go | 112 +++++++++-- src/runtime/runtime_k210.go | 5 +- src/runtime/runtime_k210_baremetal.go | 15 +- 4 files changed, 104 insertions(+), 290 deletions(-) diff --git a/src/machine/board_k210.go b/src/machine/board_k210.go index de96f1efad..4474728d7a 100644 --- a/src/machine/board_k210.go +++ b/src/machine/board_k210.go @@ -55,265 +55,3 @@ const ( P46 Pin = 46 P47 Pin = 47 ) - -type FPIOAFunc uint16 - -// FPIOA functions. -const ( - JTAG_TCLK FPIOAFunc = 0 // JTAG Test Clock - JTAG_TDI FPIOAFunc = 1 // JTAG Test Data In - JTAG_TMS FPIOAFunc = 2 // JTAG Test Mode Select - JTAG_TDO FPIOAFunc = 3 // JTAG Test Data Out - SPI0_D0 FPIOAFunc = 4 // SPI0 Data 0 - SPI0_D1 FPIOAFunc = 5 // SPI0 Data 1 - SPI0_D2 FPIOAFunc = 6 // SPI0 Data 2 - SPI0_D3 FPIOAFunc = 7 // SPI0 Data 3 - SPI0_D4 FPIOAFunc = 8 // SPI0 Data 4 - SPI0_D5 FPIOAFunc = 9 // SPI0 Data 5 - SPI0_D6 FPIOAFunc = 10 // SPI0 Data 6 - SPI0_D7 FPIOAFunc = 11 // SPI0 Data 7 - SPI0_SS0 FPIOAFunc = 12 // SPI0 Chip Select 0 - SPI0_SS1 FPIOAFunc = 13 // SPI0 Chip Select 1 - SPI0_SS2 FPIOAFunc = 14 // SPI0 Chip Select 2 - SPI0_SS3 FPIOAFunc = 15 // SPI0 Chip Select 3 - SPI0_ARB FPIOAFunc = 16 // SPI0 Arbitration - SPI0_SCLK FPIOAFunc = 17 // SPI0 Serial Clock - UARTHS_RX FPIOAFunc = 18 // UART High speed Receiver - UARTHS_TX FPIOAFunc = 19 // UART High speed Transmitter - RESV6 FPIOAFunc = 20 // Reserved function - RESV7 FPIOAFunc = 21 // Reserved function - CLK_SPI1 FPIOAFunc = 22 // Clock SPI1 - CLK_I2C1 FPIOAFunc = 23 // Clock I2C1 - GPIOHS0 FPIOAFunc = 24 // GPIO High speed 0 - GPIOHS1 FPIOAFunc = 25 // GPIO High speed 1 - GPIOHS2 FPIOAFunc = 26 // GPIO High speed 2 - GPIOHS3 FPIOAFunc = 27 // GPIO High speed 3 - GPIOHS4 FPIOAFunc = 28 // GPIO High speed 4 - GPIOHS5 FPIOAFunc = 29 // GPIO High speed 5 - GPIOHS6 FPIOAFunc = 30 // GPIO High speed 6 - GPIOHS7 FPIOAFunc = 31 // GPIO High speed 7 - GPIOHS8 FPIOAFunc = 32 // GPIO High speed 8 - GPIOHS9 FPIOAFunc = 33 // GPIO High speed 9 - GPIOHS10 FPIOAFunc = 34 // GPIO High speed 10 - GPIOHS11 FPIOAFunc = 35 // GPIO High speed 11 - GPIOHS12 FPIOAFunc = 36 // GPIO High speed 12 - GPIOHS13 FPIOAFunc = 37 // GPIO High speed 13 - GPIOHS14 FPIOAFunc = 38 // GPIO High speed 14 - GPIOHS15 FPIOAFunc = 39 // GPIO High speed 15 - GPIOHS16 FPIOAFunc = 40 // GPIO High speed 16 - GPIOHS17 FPIOAFunc = 41 // GPIO High speed 17 - GPIOHS18 FPIOAFunc = 42 // GPIO High speed 18 - GPIOHS19 FPIOAFunc = 43 // GPIO High speed 19 - GPIOHS20 FPIOAFunc = 44 // GPIO High speed 20 - GPIOHS21 FPIOAFunc = 45 // GPIO High speed 21 - GPIOHS22 FPIOAFunc = 46 // GPIO High speed 22 - GPIOHS23 FPIOAFunc = 47 // GPIO High speed 23 - GPIOHS24 FPIOAFunc = 48 // GPIO High speed 24 - GPIOHS25 FPIOAFunc = 49 // GPIO High speed 25 - GPIOHS26 FPIOAFunc = 50 // GPIO High speed 26 - GPIOHS27 FPIOAFunc = 51 // GPIO High speed 27 - GPIOHS28 FPIOAFunc = 52 // GPIO High speed 28 - GPIOHS29 FPIOAFunc = 53 // GPIO High speed 29 - GPIOHS30 FPIOAFunc = 54 // GPIO High speed 30 - GPIOHS31 FPIOAFunc = 55 // GPIO High speed 31 - GPIO0 FPIOAFunc = 56 // GPIO pin 0 - GPIO1 FPIOAFunc = 57 // GPIO pin 1 - GPIO2 FPIOAFunc = 58 // GPIO pin 2 - GPIO3 FPIOAFunc = 59 // GPIO pin 3 - GPIO4 FPIOAFunc = 60 // GPIO pin 4 - GPIO5 FPIOAFunc = 61 // GPIO pin 5 - GPIO6 FPIOAFunc = 62 // GPIO pin 6 - GPIO7 FPIOAFunc = 63 // GPIO pin 7 - UART1_RX FPIOAFunc = 64 // UART1 Receiver - UART1_TX FPIOAFunc = 65 // UART1 Transmitter - UART2_RX FPIOAFunc = 66 // UART2 Receiver - UART2_TX FPIOAFunc = 67 // UART2 Transmitter - UART3_RX FPIOAFunc = 68 // UART3 Receiver - UART3_TX FPIOAFunc = 69 // UART3 Transmitter - SPI1_D0 FPIOAFunc = 70 // SPI1 Data 0 - SPI1_D1 FPIOAFunc = 71 // SPI1 Data 1 - SPI1_D2 FPIOAFunc = 72 // SPI1 Data 2 - SPI1_D3 FPIOAFunc = 73 // SPI1 Data 3 - SPI1_D4 FPIOAFunc = 74 // SPI1 Data 4 - SPI1_D5 FPIOAFunc = 75 // SPI1 Data 5 - SPI1_D6 FPIOAFunc = 76 // SPI1 Data 6 - SPI1_D7 FPIOAFunc = 77 // SPI1 Data 7 - SPI1_SS0 FPIOAFunc = 78 // SPI1 Chip Select 0 - SPI1_SS1 FPIOAFunc = 79 // SPI1 Chip Select 1 - SPI1_SS2 FPIOAFunc = 80 // SPI1 Chip Select 2 - SPI1_SS3 FPIOAFunc = 81 // SPI1 Chip Select 3 - SPI1_ARB FPIOAFunc = 82 // SPI1 Arbitration - SPI1_SCLK FPIOAFunc = 83 // SPI1 Serial Clock - SPI_SLAVE_D0 FPIOAFunc = 84 // SPI Slave Data 0 - SPI_SLAVE_SS FPIOAFunc = 85 // SPI Slave Select - SPI_SLAVE_SCLK FPIOAFunc = 86 // SPI Slave Serial Clock - I2S0_MCLK FPIOAFunc = 87 // I2S0 Master Clock - I2S0_SCLK FPIOAFunc = 88 // I2S0 Serial Clock(BCLK) - I2S0_WS FPIOAFunc = 89 // I2S0 Word Select(LRCLK) - I2S0_IN_D0 FPIOAFunc = 90 // I2S0 Serial Data Input 0 - I2S0_IN_D1 FPIOAFunc = 91 // I2S0 Serial Data Input 1 - I2S0_IN_D2 FPIOAFunc = 92 // I2S0 Serial Data Input 2 - I2S0_IN_D3 FPIOAFunc = 93 // I2S0 Serial Data Input 3 - I2S0_OUT_D0 FPIOAFunc = 94 // I2S0 Serial Data Output 0 - I2S0_OUT_D1 FPIOAFunc = 95 // I2S0 Serial Data Output 1 - I2S0_OUT_D2 FPIOAFunc = 96 // I2S0 Serial Data Output 2 - I2S0_OUT_D3 FPIOAFunc = 97 // I2S0 Serial Data Output 3 - I2S1_MCLK FPIOAFunc = 98 // I2S1 Master Clock - I2S1_SCLK FPIOAFunc = 99 // I2S1 Serial Clock(BCLK) - I2S1_WS FPIOAFunc = 100 // I2S1 Word Select(LRCLK) - I2S1_IN_D0 FPIOAFunc = 101 // I2S1 Serial Data Input 0 - I2S1_IN_D1 FPIOAFunc = 102 // I2S1 Serial Data Input 1 - I2S1_IN_D2 FPIOAFunc = 103 // I2S1 Serial Data Input 2 - I2S1_IN_D3 FPIOAFunc = 104 // I2S1 Serial Data Input 3 - I2S1_OUT_D0 FPIOAFunc = 105 // I2S1 Serial Data Output 0 - I2S1_OUT_D1 FPIOAFunc = 106 // I2S1 Serial Data Output 1 - I2S1_OUT_D2 FPIOAFunc = 107 // I2S1 Serial Data Output 2 - I2S1_OUT_D3 FPIOAFunc = 108 // I2S1 Serial Data Output 3 - I2S2_MCLK FPIOAFunc = 109 // I2S2 Master Clock - I2S2_SCLK FPIOAFunc = 110 // I2S2 Serial Clock(BCLK) - I2S2_WS FPIOAFunc = 111 // I2S2 Word Select(LRCLK) - I2S2_IN_D0 FPIOAFunc = 112 // I2S2 Serial Data Input 0 - I2S2_IN_D1 FPIOAFunc = 113 // I2S2 Serial Data Input 1 - I2S2_IN_D2 FPIOAFunc = 114 // I2S2 Serial Data Input 2 - I2S2_IN_D3 FPIOAFunc = 115 // I2S2 Serial Data Input 3 - I2S2_OUT_D0 FPIOAFunc = 116 // I2S2 Serial Data Output 0 - I2S2_OUT_D1 FPIOAFunc = 117 // I2S2 Serial Data Output 1 - I2S2_OUT_D2 FPIOAFunc = 118 // I2S2 Serial Data Output 2 - I2S2_OUT_D3 FPIOAFunc = 119 // I2S2 Serial Data Output 3 - RESV0 FPIOAFunc = 120 // Reserved function - RESV1 FPIOAFunc = 121 // Reserved function - RESV2 FPIOAFunc = 122 // Reserved function - RESV3 FPIOAFunc = 123 // Reserved function - RESV4 FPIOAFunc = 124 // Reserved function - RESV5 FPIOAFunc = 125 // Reserved function - I2C0_SCLK FPIOAFunc = 126 // I2C0 Serial Clock - I2C0_SDA FPIOAFunc = 127 // I2C0 Serial Data - I2C1_SCLK FPIOAFunc = 128 // I2C1 Serial Clock - I2C1_SDA FPIOAFunc = 129 // I2C1 Serial Data - I2C2_SCLK FPIOAFunc = 130 // I2C2 Serial Clock - I2C2_SDA FPIOAFunc = 131 // I2C2 Serial Data - CMOS_XCLK FPIOAFunc = 132 // DVP System Clock - CMOS_RST FPIOAFunc = 133 // DVP System Reset - CMOS_PWDN FPIOAFunc = 134 // DVP Power Down Mode - CMOS_VSYNC FPIOAFunc = 135 // DVP Vertical Sync - CMOS_HREF FPIOAFunc = 136 // DVP Horizontal Reference output - CMOS_PCLK FPIOAFunc = 137 // Pixel Clock - CMOS_D0 FPIOAFunc = 138 // Data Bit 0 - CMOS_D1 FPIOAFunc = 139 // Data Bit 1 - CMOS_D2 FPIOAFunc = 140 // Data Bit 2 - CMOS_D3 FPIOAFunc = 141 // Data Bit 3 - CMOS_D4 FPIOAFunc = 142 // Data Bit 4 - CMOS_D5 FPIOAFunc = 143 // Data Bit 5 - CMOS_D6 FPIOAFunc = 144 // Data Bit 6 - CMOS_D7 FPIOAFunc = 145 // Data Bit 7 - SCCB_SCLK FPIOAFunc = 146 // SCCB Serial Clock - SCCB_SDA FPIOAFunc = 147 // SCCB Serial Data - UART1_CTS FPIOAFunc = 148 // UART1 Clear To Send - UART1_DSR FPIOAFunc = 149 // UART1 Data Set Ready - UART1_DCD FPIOAFunc = 150 // UART1 Data Carrier Detect - UART1_RI FPIOAFunc = 151 // UART1 Ring Indicator - UART1_SIR_IN FPIOAFunc = 152 // UART1 Serial Infrared Input - UART1_DTR FPIOAFunc = 153 // UART1 Data Terminal Ready - UART1_RTS FPIOAFunc = 154 // UART1 Request To Send - UART1_OUT2 FPIOAFunc = 155 // UART1 User-designated Output 2 - UART1_OUT1 FPIOAFunc = 156 // UART1 User-designated Output 1 - UART1_SIR_OUT FPIOAFunc = 157 // UART1 Serial Infrared Output - UART1_BAUD FPIOAFunc = 158 // UART1 Transmit Clock Output - UART1_RE FPIOAFunc = 159 // UART1 Receiver Output Enable - UART1_DE FPIOAFunc = 160 // UART1 Driver Output Enable - UART1_RS485_EN FPIOAFunc = 161 // UART1 RS485 Enable - UART2_CTS FPIOAFunc = 162 // UART2 Clear To Send - UART2_DSR FPIOAFunc = 163 // UART2 Data Set Ready - UART2_DCD FPIOAFunc = 164 // UART2 Data Carrier Detect - UART2_RI FPIOAFunc = 165 // UART2 Ring Indicator - UART2_SIR_IN FPIOAFunc = 166 // UART2 Serial Infrared Input - UART2_DTR FPIOAFunc = 167 // UART2 Data Terminal Ready - UART2_RTS FPIOAFunc = 168 // UART2 Request To Send - UART2_OUT2 FPIOAFunc = 169 // UART2 User-designated Output 2 - UART2_OUT1 FPIOAFunc = 170 // UART2 User-designated Output 1 - UART2_SIR_OUT FPIOAFunc = 171 // UART2 Serial Infrared Output - UART2_BAUD FPIOAFunc = 172 // UART2 Transmit Clock Output - UART2_RE FPIOAFunc = 173 // UART2 Receiver Output Enable - UART2_DE FPIOAFunc = 174 // UART2 Driver Output Enable - UART2_RS485_EN FPIOAFunc = 175 // UART2 RS485 Enable - UART3_CTS FPIOAFunc = 176 // UART3 Clear To Send - UART3_DSR FPIOAFunc = 177 // UART3 Data Set Ready - UART3_DCD FPIOAFunc = 178 // UART3 Data Carrier Detect - UART3_RI FPIOAFunc = 179 // UART3 Ring Indicator - UART3_SIR_IN FPIOAFunc = 180 // UART3 Serial Infrared Input - UART3_DTR FPIOAFunc = 181 // UART3 Data Terminal Ready - UART3_RTS FPIOAFunc = 182 // UART3 Request To Send - UART3_OUT2 FPIOAFunc = 183 // UART3 User-designated Output 2 - UART3_OUT1 FPIOAFunc = 184 // UART3 User-designated Output 1 - UART3_SIR_OUT FPIOAFunc = 185 // UART3 Serial Infrared Output - UART3_BAUD FPIOAFunc = 186 // UART3 Transmit Clock Output - UART3_RE FPIOAFunc = 187 // UART3 Receiver Output Enable - UART3_DE FPIOAFunc = 188 // UART3 Driver Output Enable - UART3_RS485_EN FPIOAFunc = 189 // UART3 RS485 Enable - TIMER0_TOGGLE1 FPIOAFunc = 190 // TIMER0 Toggle Output 1 - TIMER0_TOGGLE2 FPIOAFunc = 191 // TIMER0 Toggle Output 2 - TIMER0_TOGGLE3 FPIOAFunc = 192 // TIMER0 Toggle Output 3 - TIMER0_TOGGLE4 FPIOAFunc = 193 // TIMER0 Toggle Output 4 - TIMER1_TOGGLE1 FPIOAFunc = 194 // TIMER1 Toggle Output 1 - TIMER1_TOGGLE2 FPIOAFunc = 195 // TIMER1 Toggle Output 2 - TIMER1_TOGGLE3 FPIOAFunc = 196 // TIMER1 Toggle Output 3 - TIMER1_TOGGLE4 FPIOAFunc = 197 // TIMER1 Toggle Output 4 - TIMER2_TOGGLE1 FPIOAFunc = 198 // TIMER2 Toggle Output 1 - TIMER2_TOGGLE2 FPIOAFunc = 199 // TIMER2 Toggle Output 2 - TIMER2_TOGGLE3 FPIOAFunc = 200 // TIMER2 Toggle Output 3 - TIMER2_TOGGLE4 FPIOAFunc = 201 // TIMER2 Toggle Output 4 - CLK_SPI2 FPIOAFunc = 202 // Clock SPI2 - CLK_I2C2 FPIOAFunc = 203 // Clock I2C2 - INTERNAL0 FPIOAFunc = 204 // Internal function signal 0 - INTERNAL1 FPIOAFunc = 205 // Internal function signal 1 - INTERNAL2 FPIOAFunc = 206 // Internal function signal 2 - INTERNAL3 FPIOAFunc = 207 // Internal function signal 3 - INTERNAL4 FPIOAFunc = 208 // Internal function signal 4 - INTERNAL5 FPIOAFunc = 209 // Internal function signal 5 - INTERNAL6 FPIOAFunc = 210 // Internal function signal 6 - INTERNAL7 FPIOAFunc = 211 // Internal function signal 7 - INTERNAL8 FPIOAFunc = 212 // Internal function signal 8 - INTERNAL9 FPIOAFunc = 213 // Internal function signal 9 - INTERNAL10 FPIOAFunc = 214 // Internal function signal 10 - INTERNAL11 FPIOAFunc = 215 // Internal function signal 11 - INTERNAL12 FPIOAFunc = 216 // Internal function signal 12 - INTERNAL13 FPIOAFunc = 217 // Internal function signal 13 - INTERNAL14 FPIOAFunc = 218 // Internal function signal 14 - INTERNAL15 FPIOAFunc = 219 // Internal function signal 15 - INTERNAL16 FPIOAFunc = 220 // Internal function signal 16 - INTERNAL17 FPIOAFunc = 221 // Internal function signal 17 - CONSTANT FPIOAFunc = 222 // Constant function - INTERNAL18 FPIOAFunc = 223 // Internal function signal 18 - DEBUG0 FPIOAFunc = 224 // Debug function 0 - DEBUG1 FPIOAFunc = 225 // Debug function 1 - DEBUG2 FPIOAFunc = 226 // Debug function 2 - DEBUG3 FPIOAFunc = 227 // Debug function 3 - DEBUG4 FPIOAFunc = 228 // Debug function 4 - DEBUG5 FPIOAFunc = 229 // Debug function 5 - DEBUG6 FPIOAFunc = 230 // Debug function 6 - DEBUG7 FPIOAFunc = 231 // Debug function 7 - DEBUG8 FPIOAFunc = 232 // Debug function 8 - DEBUG9 FPIOAFunc = 233 // Debug function 9 - DEBUG10 FPIOAFunc = 234 // Debug function 10 - DEBUG11 FPIOAFunc = 235 // Debug function 11 - DEBUG12 FPIOAFunc = 236 // Debug function 12 - DEBUG13 FPIOAFunc = 237 // Debug function 13 - DEBUG14 FPIOAFunc = 238 // Debug function 14 - DEBUG15 FPIOAFunc = 239 // Debug function 15 - DEBUG16 FPIOAFunc = 240 // Debug function 16 - DEBUG17 FPIOAFunc = 241 // Debug function 17 - DEBUG18 FPIOAFunc = 242 // Debug function 18 - DEBUG19 FPIOAFunc = 243 // Debug function 19 - DEBUG20 FPIOAFunc = 244 // Debug function 20 - DEBUG21 FPIOAFunc = 245 // Debug function 21 - DEBUG22 FPIOAFunc = 246 // Debug function 22 - DEBUG23 FPIOAFunc = 247 // Debug function 23 - DEBUG24 FPIOAFunc = 248 // Debug function 24 - DEBUG25 FPIOAFunc = 249 // Debug function 25 - DEBUG26 FPIOAFunc = 250 // Debug function 26 - DEBUG27 FPIOAFunc = 251 // Debug function 27 - DEBUG28 FPIOAFunc = 252 // Debug function 28 - DEBUG29 FPIOAFunc = 253 // Debug function 29 - DEBUG30 FPIOAFunc = 254 // Debug function 30 - DEBUG31 FPIOAFunc = 255 // Debug function 31 -) diff --git a/src/machine/machine_k210.go b/src/machine/machine_k210.go index 3c3b506e5c..e7f145aa65 100644 --- a/src/machine/machine_k210.go +++ b/src/machine/machine_k210.go @@ -15,39 +15,111 @@ type PinMode uint8 const ( PinInput PinMode = iota + PinInputPullUp + PinInputPullDown PinOutput - PinPWM - PinSPI - PinI2C = PinSPI ) +type fpioaPullMode uint8 + +const ( + fpioaPullNone fpioaPullMode = iota + fpioaPullDown + fpioaPullUp +) + +func (p Pin) fpioaSetIOPull(pull fpioaPullMode) { + switch pull { + case fpioaPullNone: + kendryte.FPIOA.IO[uint8(p)].ClearBits(kendryte.FPIOA_IO_PU & kendryte.FPIOA_IO_PD) + case fpioaPullUp: + kendryte.FPIOA.IO[uint8(p)].SetBits(kendryte.FPIOA_IO_PU) + kendryte.FPIOA.IO[uint8(p)].ClearBits(kendryte.FPIOA_IO_PD) + case fpioaPullDown: + kendryte.FPIOA.IO[uint8(p)].ClearBits(kendryte.FPIOA_IO_PU) + kendryte.FPIOA.IO[uint8(p)].SetBits(kendryte.FPIOA_IO_PD) + } +} + // Configure this pin with the given configuration. func (p Pin) Configure(config PinConfig) { + var input bool + + kendryte.FPIOA.IO[uint8(p)].SetBits(kendryte.FPIOA_IO_OE_EN | kendryte.FPIOA_IO_IE_EN | kendryte.FPIOA_IO_ST | kendryte.FPIOA_IO_DS_Msk) + switch config.Mode { + case PinInput: + p.fpioaSetIOPull(fpioaPullNone) + input = true + + case PinInputPullUp: + p.fpioaSetIOPull(fpioaPullUp) + input = true + + case PinInputPullDown: + p.fpioaSetIOPull(fpioaPullDown) + input = true + + case PinOutput: + p.fpioaSetIOPull(fpioaPullNone) + input = false + + } + + if p >= P08 && p <= P15 { + // Converts the IO pin number in the effective GPIO number (assuming default FPIOA function). + gpioPin := uint8(p) - 8 + + if input { + kendryte.GPIO.DIRECTION.ClearBits(1 << gpioPin) + } else { + kendryte.GPIO.DIRECTION.SetBits(1 << gpioPin) + } + } else if p >= P16 && p <= P47 { + // Converts the IO pin number in the effective GPIOHS number (assuming default FPIOA function). + gpioPin := uint8(p) - 16 + + if input { + kendryte.GPIOHS.INPUT_EN.SetBits(1 << gpioPin) + kendryte.GPIOHS.OUTPUT_EN.ClearBits(1 << gpioPin) + } else { + kendryte.GPIOHS.OUTPUT_EN.SetBits(1 << gpioPin) + kendryte.GPIOHS.INPUT_EN.ClearBits(1 << gpioPin) + } + } } // Set the pin to high or low. func (p Pin) Set(high bool) { + if p >= P08 && p <= P15 { + gpioPin := uint8(p) - 8 + + if high { + kendryte.GPIO.DATA_OUTPUT.SetBits(1 << gpioPin) + } else { + kendryte.GPIO.DATA_OUTPUT.ClearBits(1 << gpioPin) + } + } else if p >= P16 && p <= P47 { + gpioPin := uint8(p) - 16 + + if high { + kendryte.GPIOHS.OUTPUT_VAL.SetBits(1 << gpioPin) + } else { + kendryte.GPIOHS.OUTPUT_VAL.ClearBits(1 << gpioPin) + } + } } // Get returns the current value of a GPIO pin. func (p Pin) Get() bool { - return true -} - -type FPIOA struct { - Bus *kendryte.FPIOA_Type -} - -var ( - FPIOA0 = FPIOA{Bus: kendryte.FPIOA} -) - -func (fpioa FPIOA) Init() { - // Enable APB0 clock. - kendryte.SYSCTL.CLK_EN_CENT.SetBits(kendryte.SYSCTL_CLK_EN_CENT_APB0_CLK_EN) - - // Enable FPIOA peripheral. - kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_FPIOA_CLK_EN) + var val uint32 + if p >= P08 && p <= P15 { + gpioPin := uint8(p) - 8 + val = kendryte.GPIO.DATA_INPUT.Get() & (1 << gpioPin) + } else if p >= P16 && p <= P47 { + gpioPin := uint8(p) - 16 + val = kendryte.GPIOHS.INPUT_VAL.Get() & (1 << gpioPin) + } + return (val > 0) } type UART struct { diff --git a/src/runtime/runtime_k210.go b/src/runtime/runtime_k210.go index b53ec106e6..457a1e1773 100644 --- a/src/runtime/runtime_k210.go +++ b/src/runtime/runtime_k210.go @@ -99,8 +99,11 @@ func handleInterrupt() { // initPeripherals configures periperhals the way the runtime expects them. func initPeripherals() { + // Enable APB0 clock. + kendryte.SYSCTL.CLK_EN_CENT.SetBits(kendryte.SYSCTL_CLK_EN_CENT_APB0_CLK_EN) - machine.FPIOA0.Init() + // Enable FPIOA peripheral. + kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_FPIOA_CLK_EN) machine.UART0.Configure(machine.UARTConfig{}) } diff --git a/src/runtime/runtime_k210_baremetal.go b/src/runtime/runtime_k210_baremetal.go index f99cb72a01..0f9932496a 100644 --- a/src/runtime/runtime_k210_baremetal.go +++ b/src/runtime/runtime_k210_baremetal.go @@ -3,20 +3,21 @@ package runtime import ( - "device/kendryte" "device/riscv" ) -var clockFrequency int64 = int64(kendryte.SYSCTL.CLK_FREQ.Get()) - -// ticksToNanoseconds converts RTC ticks to nanoseconds. +// ticksToNanoseconds converts CPU ticks to nanoseconds. func ticksToNanoseconds(ticks timeUnit) int64 { - return int64(ticks) * 1e9 / clockFrequency + // The following calculation is actually the following, but with both sides + // reduced to reduce the risk of overflow: + // ticks * 1e9 / (390000000 / 50) + // 50 is the CLINT divider and 390000000 is the CPU frequency. + return int64(ticks) * 5000 / 39 } -// nanosecondsToTicks converts nanoseconds to RTC ticks. +// nanosecondsToTicks converts nanoseconds to CPU ticks. func nanosecondsToTicks(ns int64) timeUnit { - return timeUnit(ns * 64 / 1953125) + return timeUnit(ns * 39 / 5000) } func abort() { From a66a7ea76700127b264bc744c4900055516ef969 Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Thu, 25 Jun 2020 14:37:12 +0200 Subject: [PATCH 16/28] maixbit: add GPIOHS pin interrupt support --- src/machine/machine_k210.go | 180 +++++++++++++++++++++++- src/runtime/interrupt/interrupt_k210.go | 5 + 2 files changed, 183 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_k210.go b/src/machine/machine_k210.go index e7f145aa65..c14d3c40ed 100644 --- a/src/machine/machine_k210.go +++ b/src/machine/machine_k210.go @@ -12,6 +12,8 @@ func CPUFrequency() uint32 { } type PinMode uint8 +type fpioaPullMode uint8 +type PinChange uint8 const ( PinInput PinMode = iota @@ -20,14 +22,20 @@ const ( PinOutput ) -type fpioaPullMode uint8 - const ( fpioaPullNone fpioaPullMode = iota fpioaPullDown fpioaPullUp ) +const ( + PinRising PinChange = iota + 1 + PinFalling + PinToggle + PinHigh + PinLow = 8 +) + func (p Pin) fpioaSetIOPull(pull fpioaPullMode) { switch pull { case fpioaPullNone: @@ -122,6 +130,174 @@ func (p Pin) Get() bool { return (val > 0) } +// Callbacks to be called for GPIOHS pins configured with SetInterrupt. +var pinCallbacks [32]func(Pin) + +// SetInterrupt sets an interrupt to be executed when a particular pin changes +// state. +// +// You can pass a nil func to unset the pin change interrupt. If you do so, +// the change parameter is ignored and can be set to any value (such as 0). +// If the pin is already configured with a callback, you must first unset +// this pins interrupt before you can set a new callback. +func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { + + // Check if the pin is a GPIOHS pin. + if p < P16 && p > P47 { + return ErrInvalidDataPin + } + + gpioPin := uint8(p) - 16 + + // Clear all interrupts. + kendryte.GPIOHS.RISE_IE.ClearBits(1 << gpioPin) + kendryte.GPIOHS.FALL_IE.ClearBits(1 << gpioPin) + kendryte.GPIOHS.HIGH_IE.ClearBits(1 << gpioPin) + kendryte.GPIOHS.LOW_IE.ClearBits(1 << gpioPin) + + // Clear all the pending bits for this pin. + kendryte.GPIOHS.RISE_IP.SetBits(1 << gpioPin) + kendryte.GPIOHS.FALL_IP.SetBits(1 << gpioPin) + kendryte.GPIOHS.HIGH_IP.SetBits(1 << gpioPin) + kendryte.GPIOHS.LOW_IP.SetBits(1 << gpioPin) + + if callback == nil { + if pinCallbacks[gpioPin] != nil { + pinCallbacks[gpioPin] = nil + } + return nil + } + + if pinCallbacks[gpioPin] != nil { + // The pin was already configured. + // To properly re-configure a pin, unset it first and set a new + // configuration. + return ErrNoPinChangeChannel + } + + pinCallbacks[gpioPin] = callback + + // Enable interrupts. + if change&PinRising != 0 { + kendryte.GPIOHS.RISE_IE.SetBits(1 << gpioPin) + } + if change&PinFalling != 0 { + kendryte.GPIOHS.FALL_IE.SetBits(1 << gpioPin) + } + if change&PinHigh != 0 { + kendryte.GPIOHS.HIGH_IE.SetBits(1 << gpioPin) + } + if change&PinLow != 0 { + kendryte.GPIOHS.LOW_IE.SetBits(1 << gpioPin) + } + + handleInterrupt := func(inter interrupt.Interrupt) { + + pin := uint8(inter.GetNumber() - kendryte.IRQ_GPIOHS0) + + if kendryte.GPIOHS.RISE_IE.HasBits(1 << pin) { + kendryte.GPIOHS.RISE_IE.ClearBits(1 << pin) + kendryte.GPIOHS.RISE_IP.SetBits(1 << pin) + kendryte.GPIOHS.RISE_IE.SetBits(1 << pin) + } + + if kendryte.GPIOHS.FALL_IE.HasBits(1 << pin) { + kendryte.GPIOHS.FALL_IE.ClearBits(1 << pin) + kendryte.GPIOHS.FALL_IP.SetBits(1 << pin) + kendryte.GPIOHS.FALL_IE.SetBits(1 << pin) + } + + if kendryte.GPIOHS.HIGH_IE.HasBits(1 << pin) { + kendryte.GPIOHS.HIGH_IE.ClearBits(1 << pin) + kendryte.GPIOHS.HIGH_IP.SetBits(1 << pin) + kendryte.GPIOHS.HIGH_IE.SetBits(1 << pin) + } + + if kendryte.GPIOHS.LOW_IE.HasBits(1 << pin) { + kendryte.GPIOHS.LOW_IE.ClearBits(1 << pin) + kendryte.GPIOHS.LOW_IP.SetBits(1 << pin) + kendryte.GPIOHS.LOW_IE.SetBits(1 << pin) + } + + pinCallbacks[pin](Pin(pin)) + } + + var ir interrupt.Interrupt + + switch p { + case P16: + ir = interrupt.New(kendryte.IRQ_GPIOHS0, handleInterrupt) + case P17: + ir = interrupt.New(kendryte.IRQ_GPIOHS1, handleInterrupt) + case P18: + ir = interrupt.New(kendryte.IRQ_GPIOHS2, handleInterrupt) + case P19: + ir = interrupt.New(kendryte.IRQ_GPIOHS3, handleInterrupt) + case P20: + ir = interrupt.New(kendryte.IRQ_GPIOHS4, handleInterrupt) + case P21: + ir = interrupt.New(kendryte.IRQ_GPIOHS5, handleInterrupt) + case P22: + ir = interrupt.New(kendryte.IRQ_GPIOHS6, handleInterrupt) + case P23: + ir = interrupt.New(kendryte.IRQ_GPIOHS7, handleInterrupt) + case P24: + ir = interrupt.New(kendryte.IRQ_GPIOHS8, handleInterrupt) + case P25: + ir = interrupt.New(kendryte.IRQ_GPIOHS9, handleInterrupt) + case P26: + ir = interrupt.New(kendryte.IRQ_GPIOHS10, handleInterrupt) + case P27: + ir = interrupt.New(kendryte.IRQ_GPIOHS11, handleInterrupt) + case P28: + ir = interrupt.New(kendryte.IRQ_GPIOHS12, handleInterrupt) + case P29: + ir = interrupt.New(kendryte.IRQ_GPIOHS13, handleInterrupt) + case P30: + ir = interrupt.New(kendryte.IRQ_GPIOHS14, handleInterrupt) + case P31: + ir = interrupt.New(kendryte.IRQ_GPIOHS15, handleInterrupt) + case P32: + ir = interrupt.New(kendryte.IRQ_GPIOHS16, handleInterrupt) + case P33: + ir = interrupt.New(kendryte.IRQ_GPIOHS17, handleInterrupt) + case P34: + ir = interrupt.New(kendryte.IRQ_GPIOHS18, handleInterrupt) + case P35: + ir = interrupt.New(kendryte.IRQ_GPIOHS19, handleInterrupt) + case P36: + ir = interrupt.New(kendryte.IRQ_GPIOHS20, handleInterrupt) + case P37: + ir = interrupt.New(kendryte.IRQ_GPIOHS21, handleInterrupt) + case P38: + ir = interrupt.New(kendryte.IRQ_GPIOHS22, handleInterrupt) + case P39: + ir = interrupt.New(kendryte.IRQ_GPIOHS23, handleInterrupt) + case P40: + ir = interrupt.New(kendryte.IRQ_GPIOHS24, handleInterrupt) + case P41: + ir = interrupt.New(kendryte.IRQ_GPIOHS25, handleInterrupt) + case P42: + ir = interrupt.New(kendryte.IRQ_GPIOHS26, handleInterrupt) + case P43: + ir = interrupt.New(kendryte.IRQ_GPIOHS27, handleInterrupt) + case P44: + ir = interrupt.New(kendryte.IRQ_GPIOHS28, handleInterrupt) + case P45: + ir = interrupt.New(kendryte.IRQ_GPIOHS29, handleInterrupt) + case P46: + ir = interrupt.New(kendryte.IRQ_GPIOHS30, handleInterrupt) + case P47: + ir = interrupt.New(kendryte.IRQ_GPIOHS31, handleInterrupt) + } + + ir.SetPriority(5) + ir.Enable() + + return nil + +} + type UART struct { Bus *kendryte.UARTHS_Type Buffer *RingBuffer diff --git a/src/runtime/interrupt/interrupt_k210.go b/src/runtime/interrupt/interrupt_k210.go index a4cf89f590..31e056c164 100644 --- a/src/runtime/interrupt/interrupt_k210.go +++ b/src/runtime/interrupt/interrupt_k210.go @@ -20,3 +20,8 @@ func (irq Interrupt) Enable() { func (irq Interrupt) SetPriority(priority uint8) { kendryte.PLIC.PRIORITY[irq.num].Set(uint32(priority)) } + +// GetNumber returns the interrupt number for this interrupt. +func (irq Interrupt) GetNumber() int { + return irq.num +} From e13c077b58abfe08945e83c51e3ab4d4ca682c60 Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Mon, 29 Jun 2020 09:47:07 +0200 Subject: [PATCH 17/28] maixbit: add SPI support --- src/machine/board_maixbit.go | 113 +++++++++++---------- src/machine/board_maixbit_baremetal.go | 15 +++ src/machine/machine_k210.go | 135 +++++++++++++++++++++++++ src/machine/spi.go | 2 +- 4 files changed, 213 insertions(+), 52 deletions(-) create mode 100644 src/machine/board_maixbit_baremetal.go diff --git a/src/machine/board_maixbit.go b/src/machine/board_maixbit.go index e0c1d9ca36..2c60fc980a 100644 --- a/src/machine/board_maixbit.go +++ b/src/machine/board_maixbit.go @@ -2,52 +2,56 @@ package machine -// GPIO pins. +// Pins on the MAix Bit. const ( - D0 = P08 - D1 = P09 - D2 = P10 - D3 = P11 - D4 = P12 - D5 = P13 - D6 = P14 - D7 = P15 -) - -// High-speed GPIO pins (GPIOHS). -const ( - DHS0 = P16 - DHS1 = P17 - DHS2 = P18 - DHS3 = P19 - DHS4 = P20 - DHS5 = P21 - DHS6 = P22 - DHS7 = P23 - DHS8 = P24 - DHS9 = P25 - DHS10 = P26 - DHS11 = P27 - DHS12 = P28 - DHS13 = P29 - DHS14 = P30 - DHS15 = P31 - DHS16 = P32 - DHS17 = P33 - DHS18 = P34 - DHS19 = P35 - DHS20 = P36 - DHS21 = P37 - DHS22 = P38 - DHS23 = P39 - DHS24 = P40 - DHS25 = P41 - DHS26 = P42 - DHS27 = P43 - DHS28 = P44 - DHS29 = P45 - DHS30 = P46 - DHS31 = P47 + D0 = P00 // JTAG_TCLK + D1 = P01 // JTAG_TDI + D2 = P02 // JTAG_TMS + D3 = P03 // JTAG_TDO + D4 = P04 // UARTHS_RX + D5 = P05 // UARTHS_TX + D6 = P06 // RESV0 + D7 = P07 // RESV0 + D8 = P08 // GPIO1 + D9 = P09 // GPIO2 + D10 = P10 // GPIO3 + D11 = P11 // GPIO4 + D12 = P12 // GPIO5 + D13 = P13 // GPIO6 + D14 = P14 // GPIO7 + D15 = P15 // GPIO8 + D16 = P16 // GPIOHS0 + D17 = P17 // GPIOHS1 + D18 = P18 // GPIOHS2 + D19 = P19 // GPIOHS3 + D20 = P20 // GPIOHS4 + D21 = P21 // GPIOHS5 + D22 = P22 // GPIOHS6 + D23 = P23 // GPIOHS7 + D24 = P24 // GPIOHS8 + D25 = P25 // GPIOHS9 + D26 = P26 // GPIOHS10 / SPI0_MISO + D27 = P27 // GPIOHS11 / SPI0_SCLK + D28 = P28 // GPIOHS12 / SPI0_MOSI + D29 = P29 // GPIOHS13 + D30 = P30 // GPIOHS14 + D31 = P31 // GPIOHS15 + D32 = P32 // GPIOHS16 + D33 = P33 // GPIOHS17 + D34 = P34 // GPIOHS18 + D35 = P35 // GPIOHS19 + D36 = P36 // GPIOHS20 + D37 = P37 // GPIOHS21 + D38 = P38 // GPIOHS22 + D39 = P39 // GPIOHS23 + D40 = P40 // GPIOHS24 + D41 = P41 // GPIOHS25 + D42 = P42 // GPIOHS26 + D43 = P43 // GPIOHS27 + D44 = P44 // GPIOHS28 + D45 = P45 // GPIOHS29 + D46 = P46 // GPIOHS30 + D47 = P47 // GPIOHS31 ) const ( @@ -55,13 +59,20 @@ const ( LED1 = LED_RED LED2 = LED_GREEN LED3 = LED_BLUE - LED_RED = D5 - LED_GREEN = D4 - LED_BLUE = D6 + LED_RED = D13 + LED_GREEN = D12 + LED_BLUE = D14 +) + +// Default pins for UARTHS. +const ( + UART_TX_PIN = D5 + UART_RX_PIN = D4 ) -// Default pins for UARTHS +// SPI pins. const ( - UART_TX_PIN = P05 - UART_RX_PIN = P04 + SPI0_SCK_PIN = D27 + SPI0_MOSI_PIN = D28 + SPI0_MISO_PIN = D26 ) diff --git a/src/machine/board_maixbit_baremetal.go b/src/machine/board_maixbit_baremetal.go new file mode 100644 index 0000000000..98733bee81 --- /dev/null +++ b/src/machine/board_maixbit_baremetal.go @@ -0,0 +1,15 @@ +// +build k210,maixbit + +package machine + +import "device/kendryte" + +// SPI on the MAix Bit. +var ( + SPI0 = SPI{ + Bus: kendryte.SPI0, + } + SPI1 = SPI{ + Bus: kendryte.SPI1, + } +) diff --git a/src/machine/machine_k210.go b/src/machine/machine_k210.go index c14d3c40ed..247db08002 100644 --- a/src/machine/machine_k210.go +++ b/src/machine/machine_k210.go @@ -4,6 +4,7 @@ package machine import ( "device/kendryte" + "errors" "runtime/interrupt" ) @@ -15,6 +16,7 @@ type PinMode uint8 type fpioaPullMode uint8 type PinChange uint8 +// Pin modes. const ( PinInput PinMode = iota PinInputPullUp @@ -22,12 +24,14 @@ const ( PinOutput ) +// FPIOA internal pull resistors. const ( fpioaPullNone fpioaPullMode = iota fpioaPullDown fpioaPullUp ) +// GPIOHS pin interrupt events. const ( PinRising PinChange = iota + 1 PinFalling @@ -36,6 +40,20 @@ const ( PinLow = 8 ) +// FPIOA functions. +const ( + fpioaFuncSpi0Sclk = 17 + fpioaFuncSpi0D0 = 4 + fpioaFuncSpi0D1 = 5 + fpioaFuncSpi1Sclk = 83 + fpioaFuncSpi1D0 = 70 + fpioaFuncSpi1D1 = 71 +) + +var ( + ErrUnsupportedSPIController = errors.New("SPI controller not supported. Use SPI0 or SPI1.") +) + func (p Pin) fpioaSetIOPull(pull fpioaPullMode) { switch pull { case fpioaPullNone: @@ -340,3 +358,120 @@ func (uart UART) WriteByte(c byte) { uart.Bus.TXDATA.Set(uint32(c)) } + +type SPI struct { + Bus *kendryte.SPI_Type +} + +// SPIConfig is used to store config info for SPI. +type SPIConfig struct { + Frequency uint32 + SCK Pin + MOSI Pin + MISO Pin + LSBFirst bool + Mode uint8 +} + +// Configure is intended to setup the SPI interface. +// Only SPI controller 0 and 1 can be used because SPI2 is a special +// slave-mode controller and SPI3 is used for flashing. +func (spi SPI) Configure(config SPIConfig) error { + // Use default pins if not set. + if config.SCK == 0 && config.MOSI == 0 && config.MISO == 0 { + config.SCK = SPI0_SCK_PIN + config.MOSI = SPI0_MOSI_PIN + config.MISO = SPI0_MISO_PIN + } + + // Enable pins for SPI. + sckBits := uint32(kendryte.FPIOA_IO_OE_EN | kendryte.FPIOA_IO_DS_Msk) + dataBits := uint32(kendryte.FPIOA_IO_OE_EN | kendryte.FPIOA_IO_OE_INV | kendryte.FPIOA_IO_IE_EN | + kendryte.FPIOA_IO_IE_INV | kendryte.FPIOA_IO_ST | kendryte.FPIOA_IO_DS_Msk) + + // Enable APB2 clock. + kendryte.SYSCTL.CLK_EN_CENT.SetBits(kendryte.SYSCTL_CLK_EN_CENT_APB2_CLK_EN) + + var fpioaFuncSclk uint32 + var fpioaFuncD0 uint32 + var fpioaFuncD1 uint32 + + switch spi.Bus { + case kendryte.SPI0: + // Initialize FPIOA values. + fpioaFuncSclk = fpioaFuncSpi0Sclk + fpioaFuncD0 = fpioaFuncSpi0D0 + fpioaFuncD1 = fpioaFuncSpi0D1 + + // Initialize SPI clock. + kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_SPI0_CLK_EN) + kendryte.SYSCTL.CLK_TH1.ClearBits(kendryte.SYSCTL_CLK_TH1_SPI0_CLK_Msk) + case kendryte.SPI1: + // Initialize FPIOA values. + fpioaFuncSclk = fpioaFuncSpi1Sclk + fpioaFuncD0 = fpioaFuncSpi1D0 + fpioaFuncD1 = fpioaFuncSpi1D1 + + // Initialize SPI clock. + kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_SPI1_CLK_EN) + kendryte.SYSCTL.CLK_TH1.ClearBits(kendryte.SYSCTL_CLK_TH1_SPI1_CLK_Msk) + default: + return ErrUnsupportedSPIController + } + + // Set FPIOA functins for selected pins. + kendryte.FPIOA.IO[uint8(config.SCK)].Set(uint32(sckBits | fpioaFuncSclk)) + kendryte.FPIOA.IO[uint8(config.MOSI)].Set(uint32(dataBits | fpioaFuncD0)) + kendryte.FPIOA.IO[uint8(config.MISO)].Set(uint32(dataBits | fpioaFuncD1)) + + // Set default frequency. + if config.Frequency == 0 { + config.Frequency = 500000 + } + + baudr := CPUFrequency() / config.Frequency + print(baudr) + spi.Bus.BAUDR.Set(baudr) + + // Configure SPI mode 0, standard frame format, 8-bit data, little-endian. + spi.Bus.IMR.Set(0) + spi.Bus.DMACR.Set(0) + spi.Bus.DMATDLR.Set(0x10) + spi.Bus.DMARDLR.Set(0) + spi.Bus.SER.Set(0) + spi.Bus.SSIENR.Set(0) + spi.Bus.CTRLR0.Set((7 << 16)) + spi.Bus.SPI_CTRLR0.Set(0) + spi.Bus.ENDIAN.Set(0) + + return nil +} + +// Transfer writes/reads a single byte using the SPI interface. +func (spi SPI) Transfer(w byte) (byte, error) { + spi.Bus.SSIENR.Set(0) + + // Set transfer-receive mode. + spi.Bus.CTRLR0.ClearBits(0x3 << 8) + + // Enable/disable SPI. + spi.Bus.SSIENR.Set(1) + defer spi.Bus.SSIENR.Set(0) + + // Enable/disable device. + spi.Bus.SER.Set(0x1) + defer spi.Bus.SER.Set(0) + + spi.Bus.DR0.Set(uint32(w)) + + // Wait for transfer. + for spi.Bus.SR.Get()&0x05 != 0x04 { + } + + // Wait for data. + for spi.Bus.RXFLR.Get() == 0 { + } + + return byte(spi.Bus.DR0.Get()), nil + +} diff --git a/src/machine/spi.go b/src/machine/spi.go index 2b022c4136..51b18dd5ee 100644 --- a/src/machine/spi.go +++ b/src/machine/spi.go @@ -1,4 +1,4 @@ -// +build !baremetal sam stm32 fe310 +// +build !baremetal sam stm32 fe310 k210 package machine From c4e53629a09f01775764e1899c948ab7c8266366 Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Mon, 29 Jun 2020 18:09:48 +0200 Subject: [PATCH 18/28] maixbit: add I2C support --- src/machine/board_k210.go | 297 +++++++++++++++++++++ src/machine/board_maixbit.go | 18 +- src/machine/board_maixbit_baremetal.go | 13 + src/machine/i2c.go | 2 +- src/machine/machine_k210.go | 356 ++++++++++++++++++------- 5 files changed, 576 insertions(+), 110 deletions(-) diff --git a/src/machine/board_k210.go b/src/machine/board_k210.go index 4474728d7a..2b934e5eca 100644 --- a/src/machine/board_k210.go +++ b/src/machine/board_k210.go @@ -55,3 +55,300 @@ const ( P46 Pin = 46 P47 Pin = 47 ) + +type FPIOAFunction uint8 + +// Every pin on the Kendryte K210 is assigned to an FPIOA function. +// Each pin can be configured with every function below. +const ( + FUNC_JTAG_TCLK FPIOAFunction = 0 // JTAG Test Clock + FUNC_JTAG_TDI FPIOAFunction = 1 // JTAG Test Data In + FUNC_JTAG_TMS FPIOAFunction = 2 // JTAG Test Mode Select + FUNC_JTAG_TDO FPIOAFunction = 3 // JTAG Test Data Out + FUNC_SPI0_D0 FPIOAFunction = 4 // SPI0 Data 0 + FUNC_SPI0_D1 FPIOAFunction = 5 // SPI0 Data 1 + FUNC_SPI0_D2 FPIOAFunction = 6 // SPI0 Data 2 + FUNC_SPI0_D3 FPIOAFunction = 7 // SPI0 Data 3 + FUNC_SPI0_D4 FPIOAFunction = 8 // SPI0 Data 4 + FUNC_SPI0_D5 FPIOAFunction = 9 // SPI0 Data 5 + FUNC_SPI0_D6 FPIOAFunction = 10 // SPI0 Data 6 + FUNC_SPI0_D7 FPIOAFunction = 11 // SPI0 Data 7 + FUNC_SPI0_SS0 FPIOAFunction = 12 // SPI0 Chip Select 0 + FUNC_SPI0_SS1 FPIOAFunction = 13 // SPI0 Chip Select 1 + FUNC_SPI0_SS2 FPIOAFunction = 14 // SPI0 Chip Select 2 + FUNC_SPI0_SS3 FPIOAFunction = 15 // SPI0 Chip Select 3 + FUNC_SPI0_ARB FPIOAFunction = 16 // SPI0 Arbitration + FUNC_SPI0_SCLK FPIOAFunction = 17 // SPI0 Serial Clock + FUNC_UARTHS_RX FPIOAFunction = 18 // UART High speed Receiver + FUNC_UARTHS_TX FPIOAFunction = 19 // UART High speed Transmitter + FUNC_RESV6 FPIOAFunction = 20 // Reserved function + FUNC_RESV7 FPIOAFunction = 21 // Reserved function + FUNC_CLK_SPI1 FPIOAFunction = 22 // Clock SPI1 + FUNC_CLK_I2C1 FPIOAFunction = 23 // Clock I2C1 + FUNC_GPIOHS0 FPIOAFunction = 24 // GPIO High speed 0 + FUNC_GPIOHS1 FPIOAFunction = 25 // GPIO High speed 1 + FUNC_GPIOHS2 FPIOAFunction = 26 // GPIO High speed 2 + FUNC_GPIOHS3 FPIOAFunction = 27 // GPIO High speed 3 + FUNC_GPIOHS4 FPIOAFunction = 28 // GPIO High speed 4 + FUNC_GPIOHS5 FPIOAFunction = 29 // GPIO High speed 5 + FUNC_GPIOHS6 FPIOAFunction = 30 // GPIO High speed 6 + FUNC_GPIOHS7 FPIOAFunction = 31 // GPIO High speed 7 + FUNC_GPIOHS8 FPIOAFunction = 32 // GPIO High speed 8 + FUNC_GPIOHS9 FPIOAFunction = 33 // GPIO High speed 9 + FUNC_GPIOHS10 FPIOAFunction = 34 // GPIO High speed 10 + FUNC_GPIOHS11 FPIOAFunction = 35 // GPIO High speed 11 + FUNC_GPIOHS12 FPIOAFunction = 36 // GPIO High speed 12 + FUNC_GPIOHS13 FPIOAFunction = 37 // GPIO High speed 13 + FUNC_GPIOHS14 FPIOAFunction = 38 // GPIO High speed 14 + FUNC_GPIOHS15 FPIOAFunction = 39 // GPIO High speed 15 + FUNC_GPIOHS16 FPIOAFunction = 40 // GPIO High speed 16 + FUNC_GPIOHS17 FPIOAFunction = 41 // GPIO High speed 17 + FUNC_GPIOHS18 FPIOAFunction = 42 // GPIO High speed 18 + FUNC_GPIOHS19 FPIOAFunction = 43 // GPIO High speed 19 + FUNC_GPIOHS20 FPIOAFunction = 44 // GPIO High speed 20 + FUNC_GPIOHS21 FPIOAFunction = 45 // GPIO High speed 21 + FUNC_GPIOHS22 FPIOAFunction = 46 // GPIO High speed 22 + FUNC_GPIOHS23 FPIOAFunction = 47 // GPIO High speed 23 + FUNC_GPIOHS24 FPIOAFunction = 48 // GPIO High speed 24 + FUNC_GPIOHS25 FPIOAFunction = 49 // GPIO High speed 25 + FUNC_GPIOHS26 FPIOAFunction = 50 // GPIO High speed 26 + FUNC_GPIOHS27 FPIOAFunction = 51 // GPIO High speed 27 + FUNC_GPIOHS28 FPIOAFunction = 52 // GPIO High speed 28 + FUNC_GPIOHS29 FPIOAFunction = 53 // GPIO High speed 29 + FUNC_GPIOHS30 FPIOAFunction = 54 // GPIO High speed 30 + FUNC_GPIOHS31 FPIOAFunction = 55 // GPIO High speed 31 + FUNC_GPIO0 FPIOAFunction = 56 // GPIO pin 0 + FUNC_GPIO1 FPIOAFunction = 57 // GPIO pin 1 + FUNC_GPIO2 FPIOAFunction = 58 // GPIO pin 2 + FUNC_GPIO3 FPIOAFunction = 59 // GPIO pin 3 + FUNC_GPIO4 FPIOAFunction = 60 // GPIO pin 4 + FUNC_GPIO5 FPIOAFunction = 61 // GPIO pin 5 + FUNC_GPIO6 FPIOAFunction = 62 // GPIO pin 6 + FUNC_GPIO7 FPIOAFunction = 63 // GPIO pin 7 + FUNC_UART1_RX FPIOAFunction = 64 // UART1 Receiver + FUNC_UART1_TX FPIOAFunction = 65 // UART1 Transmitter + FUNC_UART2_RX FPIOAFunction = 66 // UART2 Receiver + FUNC_UART2_TX FPIOAFunction = 67 // UART2 Transmitter + FUNC_UART3_RX FPIOAFunction = 68 // UART3 Receiver + FUNC_UART3_TX FPIOAFunction = 69 // UART3 Transmitter + FUNC_SPI1_D0 FPIOAFunction = 70 // SPI1 Data 0 + FUNC_SPI1_D1 FPIOAFunction = 71 // SPI1 Data 1 + FUNC_SPI1_D2 FPIOAFunction = 72 // SPI1 Data 2 + FUNC_SPI1_D3 FPIOAFunction = 73 // SPI1 Data 3 + FUNC_SPI1_D4 FPIOAFunction = 74 // SPI1 Data 4 + FUNC_SPI1_D5 FPIOAFunction = 75 // SPI1 Data 5 + FUNC_SPI1_D6 FPIOAFunction = 76 // SPI1 Data 6 + FUNC_SPI1_D7 FPIOAFunction = 77 // SPI1 Data 7 + FUNC_SPI1_SS0 FPIOAFunction = 78 // SPI1 Chip Select 0 + FUNC_SPI1_SS1 FPIOAFunction = 79 // SPI1 Chip Select 1 + FUNC_SPI1_SS2 FPIOAFunction = 80 // SPI1 Chip Select 2 + FUNC_SPI1_SS3 FPIOAFunction = 81 // SPI1 Chip Select 3 + FUNC_SPI1_ARB FPIOAFunction = 82 // SPI1 Arbitration + FUNC_SPI1_SCLK FPIOAFunction = 83 // SPI1 Serial Clock + FUNC_SPI_SLAVE_D0 FPIOAFunction = 84 // SPI Slave Data 0 + FUNC_SPI_SLAVE_SS FPIOAFunction = 85 // SPI Slave Select + FUNC_SPI_SLAVE_SCLK FPIOAFunction = 86 // SPI Slave Serial Clock + FUNC_I2S0_MCLK FPIOAFunction = 87 // I2S0 Master Clock + FUNC_I2S0_SCLK FPIOAFunction = 88 // I2S0 Serial Clock(BCLK) + FUNC_I2S0_WS FPIOAFunction = 89 // I2S0 Word Select(LRCLK) + FUNC_I2S0_IN_D0 FPIOAFunction = 90 // I2S0 Serial Data Input 0 + FUNC_I2S0_IN_D1 FPIOAFunction = 91 // I2S0 Serial Data Input 1 + FUNC_I2S0_IN_D2 FPIOAFunction = 92 // I2S0 Serial Data Input 2 + FUNC_I2S0_IN_D3 FPIOAFunction = 93 // I2S0 Serial Data Input 3 + FUNC_I2S0_OUT_D0 FPIOAFunction = 94 // I2S0 Serial Data Output 0 + FUNC_I2S0_OUT_D1 FPIOAFunction = 95 // I2S0 Serial Data Output 1 + FUNC_I2S0_OUT_D2 FPIOAFunction = 96 // I2S0 Serial Data Output 2 + FUNC_I2S0_OUT_D3 FPIOAFunction = 97 // I2S0 Serial Data Output 3 + FUNC_I2S1_MCLK FPIOAFunction = 98 // I2S1 Master Clock + FUNC_I2S1_SCLK FPIOAFunction = 99 // I2S1 Serial Clock(BCLK) + FUNC_I2S1_WS FPIOAFunction = 100 // I2S1 Word Select(LRCLK) + FUNC_I2S1_IN_D0 FPIOAFunction = 101 // I2S1 Serial Data Input 0 + FUNC_I2S1_IN_D1 FPIOAFunction = 102 // I2S1 Serial Data Input 1 + FUNC_I2S1_IN_D2 FPIOAFunction = 103 // I2S1 Serial Data Input 2 + FUNC_I2S1_IN_D3 FPIOAFunction = 104 // I2S1 Serial Data Input 3 + FUNC_I2S1_OUT_D0 FPIOAFunction = 105 // I2S1 Serial Data Output 0 + FUNC_I2S1_OUT_D1 FPIOAFunction = 106 // I2S1 Serial Data Output 1 + FUNC_I2S1_OUT_D2 FPIOAFunction = 107 // I2S1 Serial Data Output 2 + FUNC_I2S1_OUT_D3 FPIOAFunction = 108 // I2S1 Serial Data Output 3 + FUNC_I2S2_MCLK FPIOAFunction = 109 // I2S2 Master Clock + FUNC_I2S2_SCLK FPIOAFunction = 110 // I2S2 Serial Clock(BCLK) + FUNC_I2S2_WS FPIOAFunction = 111 // I2S2 Word Select(LRCLK) + FUNC_I2S2_IN_D0 FPIOAFunction = 112 // I2S2 Serial Data Input 0 + FUNC_I2S2_IN_D1 FPIOAFunction = 113 // I2S2 Serial Data Input 1 + FUNC_I2S2_IN_D2 FPIOAFunction = 114 // I2S2 Serial Data Input 2 + FUNC_I2S2_IN_D3 FPIOAFunction = 115 // I2S2 Serial Data Input 3 + FUNC_I2S2_OUT_D0 FPIOAFunction = 116 // I2S2 Serial Data Output 0 + FUNC_I2S2_OUT_D1 FPIOAFunction = 117 // I2S2 Serial Data Output 1 + FUNC_I2S2_OUT_D2 FPIOAFunction = 118 // I2S2 Serial Data Output 2 + FUNC_I2S2_OUT_D3 FPIOAFunction = 119 // I2S2 Serial Data Output 3 + FUNC_RESV0 FPIOAFunction = 120 // Reserved function + FUNC_RESV1 FPIOAFunction = 121 // Reserved function + FUNC_RESV2 FPIOAFunction = 122 // Reserved function + FUNC_RESV3 FPIOAFunction = 123 // Reserved function + FUNC_RESV4 FPIOAFunction = 124 // Reserved function + FUNC_RESV5 FPIOAFunction = 125 // Reserved function + FUNC_I2C0_SCLK FPIOAFunction = 126 // I2C0 Serial Clock + FUNC_I2C0_SDA FPIOAFunction = 127 // I2C0 Serial Data + FUNC_I2C1_SCLK FPIOAFunction = 128 // I2C1 Serial Clock + FUNC_I2C1_SDA FPIOAFunction = 129 // I2C1 Serial Data + FUNC_I2C2_SCLK FPIOAFunction = 130 // I2C2 Serial Clock + FUNC_I2C2_SDA FPIOAFunction = 131 // I2C2 Serial Data + FUNC_CMOS_XCLK FPIOAFunction = 132 // DVP System Clock + FUNC_CMOS_RST FPIOAFunction = 133 // DVP System Reset + FUNC_CMOS_PWDN FPIOAFunction = 134 // DVP Power Down Mode + FUNC_CMOS_VSYNC FPIOAFunction = 135 // DVP Vertical Sync + FUNC_CMOS_HREF FPIOAFunction = 136 // DVP Horizontal Reference output + FUNC_CMOS_PCLK FPIOAFunction = 137 // Pixel Clock + FUNC_CMOS_D0 FPIOAFunction = 138 // Data Bit 0 + FUNC_CMOS_D1 FPIOAFunction = 139 // Data Bit 1 + FUNC_CMOS_D2 FPIOAFunction = 140 // Data Bit 2 + FUNC_CMOS_D3 FPIOAFunction = 141 // Data Bit 3 + FUNC_CMOS_D4 FPIOAFunction = 142 // Data Bit 4 + FUNC_CMOS_D5 FPIOAFunction = 143 // Data Bit 5 + FUNC_CMOS_D6 FPIOAFunction = 144 // Data Bit 6 + FUNC_CMOS_D7 FPIOAFunction = 145 // Data Bit 7 + FUNC_SCCB_SCLK FPIOAFunction = 146 // SCCB Serial Clock + FUNC_SCCB_SDA FPIOAFunction = 147 // SCCB Serial Data + FUNC_UART1_CTS FPIOAFunction = 148 // UART1 Clear To Send + FUNC_UART1_DSR FPIOAFunction = 149 // UART1 Data Set Ready + FUNC_UART1_DCD FPIOAFunction = 150 // UART1 Data Carrier Detect + FUNC_UART1_RI FPIOAFunction = 151 // UART1 Ring Indicator + FUNC_UART1_SIR_IN FPIOAFunction = 152 // UART1 Serial Infrared Input + FUNC_UART1_DTR FPIOAFunction = 153 // UART1 Data Terminal Ready + FUNC_UART1_RTS FPIOAFunction = 154 // UART1 Request To Send + FUNC_UART1_OUT2 FPIOAFunction = 155 // UART1 User-designated Output 2 + FUNC_UART1_OUT1 FPIOAFunction = 156 // UART1 User-designated Output 1 + FUNC_UART1_SIR_OUT FPIOAFunction = 157 // UART1 Serial Infrared Output + FUNC_UART1_BAUD FPIOAFunction = 158 // UART1 Transmit Clock Output + FUNC_UART1_RE FPIOAFunction = 159 // UART1 Receiver Output Enable + FUNC_UART1_DE FPIOAFunction = 160 // UART1 Driver Output Enable + FUNC_UART1_RS485_EN FPIOAFunction = 161 // UART1 RS485 Enable + FUNC_UART2_CTS FPIOAFunction = 162 // UART2 Clear To Send + FUNC_UART2_DSR FPIOAFunction = 163 // UART2 Data Set Ready + FUNC_UART2_DCD FPIOAFunction = 164 // UART2 Data Carrier Detect + FUNC_UART2_RI FPIOAFunction = 165 // UART2 Ring Indicator + FUNC_UART2_SIR_IN FPIOAFunction = 166 // UART2 Serial Infrared Input + FUNC_UART2_DTR FPIOAFunction = 167 // UART2 Data Terminal Ready + FUNC_UART2_RTS FPIOAFunction = 168 // UART2 Request To Send + FUNC_UART2_OUT2 FPIOAFunction = 169 // UART2 User-designated Output 2 + FUNC_UART2_OUT1 FPIOAFunction = 170 // UART2 User-designated Output 1 + FUNC_UART2_SIR_OUT FPIOAFunction = 171 // UART2 Serial Infrared Output + FUNC_UART2_BAUD FPIOAFunction = 172 // UART2 Transmit Clock Output + FUNC_UART2_RE FPIOAFunction = 173 // UART2 Receiver Output Enable + FUNC_UART2_DE FPIOAFunction = 174 // UART2 Driver Output Enable + FUNC_UART2_RS485_EN FPIOAFunction = 175 // UART2 RS485 Enable + FUNC_UART3_CTS FPIOAFunction = 176 // UART3 Clear To Send + FUNC_UART3_DSR FPIOAFunction = 177 // UART3 Data Set Ready + FUNC_UART3_DCD FPIOAFunction = 178 // UART3 Data Carrier Detect + FUNC_UART3_RI FPIOAFunction = 179 // UART3 Ring Indicator + FUNC_UART3_SIR_IN FPIOAFunction = 180 // UART3 Serial Infrared Input + FUNC_UART3_DTR FPIOAFunction = 181 // UART3 Data Terminal Ready + FUNC_UART3_RTS FPIOAFunction = 182 // UART3 Request To Send + FUNC_UART3_OUT2 FPIOAFunction = 183 // UART3 User-designated Output 2 + FUNC_UART3_OUT1 FPIOAFunction = 184 // UART3 User-designated Output 1 + FUNC_UART3_SIR_OUT FPIOAFunction = 185 // UART3 Serial Infrared Output + FUNC_UART3_BAUD FPIOAFunction = 186 // UART3 Transmit Clock Output + FUNC_UART3_RE FPIOAFunction = 187 // UART3 Receiver Output Enable + FUNC_UART3_DE FPIOAFunction = 188 // UART3 Driver Output Enable + FUNC_UART3_RS485_EN FPIOAFunction = 189 // UART3 RS485 Enable + FUNC_TIMER0_TOGGLE1 FPIOAFunction = 190 // TIMER0 Toggle Output 1 + FUNC_TIMER0_TOGGLE2 FPIOAFunction = 191 // TIMER0 Toggle Output 2 + FUNC_TIMER0_TOGGLE3 FPIOAFunction = 192 // TIMER0 Toggle Output 3 + FUNC_TIMER0_TOGGLE4 FPIOAFunction = 193 // TIMER0 Toggle Output 4 + FUNC_TIMER1_TOGGLE1 FPIOAFunction = 194 // TIMER1 Toggle Output 1 + FUNC_TIMER1_TOGGLE2 FPIOAFunction = 195 // TIMER1 Toggle Output 2 + FUNC_TIMER1_TOGGLE3 FPIOAFunction = 196 // TIMER1 Toggle Output 3 + FUNC_TIMER1_TOGGLE4 FPIOAFunction = 197 // TIMER1 Toggle Output 4 + FUNC_TIMER2_TOGGLE1 FPIOAFunction = 198 // TIMER2 Toggle Output 1 + FUNC_TIMER2_TOGGLE2 FPIOAFunction = 199 // TIMER2 Toggle Output 2 + FUNC_TIMER2_TOGGLE3 FPIOAFunction = 200 // TIMER2 Toggle Output 3 + FUNC_TIMER2_TOGGLE4 FPIOAFunction = 201 // TIMER2 Toggle Output 4 + FUNC_CLK_SPI2 FPIOAFunction = 202 // Clock SPI2 + FUNC_CLK_I2C2 FPIOAFunction = 203 // Clock I2C2 + FUNC_INTERNAL0 FPIOAFunction = 204 // Internal function signal 0 + FUNC_INTERNAL1 FPIOAFunction = 205 // Internal function signal 1 + FUNC_INTERNAL2 FPIOAFunction = 206 // Internal function signal 2 + FUNC_INTERNAL3 FPIOAFunction = 207 // Internal function signal 3 + FUNC_INTERNAL4 FPIOAFunction = 208 // Internal function signal 4 + FUNC_INTERNAL5 FPIOAFunction = 209 // Internal function signal 5 + FUNC_INTERNAL6 FPIOAFunction = 210 // Internal function signal 6 + FUNC_INTERNAL7 FPIOAFunction = 211 // Internal function signal 7 + FUNC_INTERNAL8 FPIOAFunction = 212 // Internal function signal 8 + FUNC_INTERNAL9 FPIOAFunction = 213 // Internal function signal 9 + FUNC_INTERNAL10 FPIOAFunction = 214 // Internal function signal 10 + FUNC_INTERNAL11 FPIOAFunction = 215 // Internal function signal 11 + FUNC_INTERNAL12 FPIOAFunction = 216 // Internal function signal 12 + FUNC_INTERNAL13 FPIOAFunction = 217 // Internal function signal 13 + FUNC_INTERNAL14 FPIOAFunction = 218 // Internal function signal 14 + FUNC_INTERNAL15 FPIOAFunction = 219 // Internal function signal 15 + FUNC_INTERNAL16 FPIOAFunction = 220 // Internal function signal 16 + FUNC_INTERNAL17 FPIOAFunction = 221 // Internal function signal 17 + FUNC_CONSTANT FPIOAFunction = 222 // Constant function + FUNC_INTERNAL18 FPIOAFunction = 223 // Internal function signal 18 + FUNC_DEBUG0 FPIOAFunction = 224 // Debug function 0 + FUNC_DEBUG1 FPIOAFunction = 225 // Debug function 1 + FUNC_DEBUG2 FPIOAFunction = 226 // Debug function 2 + FUNC_DEBUG3 FPIOAFunction = 227 // Debug function 3 + FUNC_DEBUG4 FPIOAFunction = 228 // Debug function 4 + FUNC_DEBUG5 FPIOAFunction = 229 // Debug function 5 + FUNC_DEBUG6 FPIOAFunction = 230 // Debug function 6 + FUNC_DEBUG7 FPIOAFunction = 231 // Debug function 7 + FUNC_DEBUG8 FPIOAFunction = 232 // Debug function 8 + FUNC_DEBUG9 FPIOAFunction = 233 // Debug function 9 + FUNC_DEBUG10 FPIOAFunction = 234 // Debug function 10 + FUNC_DEBUG11 FPIOAFunction = 235 // Debug function 11 + FUNC_DEBUG12 FPIOAFunction = 236 // Debug function 12 + FUNC_DEBUG13 FPIOAFunction = 237 // Debug function 13 + FUNC_DEBUG14 FPIOAFunction = 238 // Debug function 14 + FUNC_DEBUG15 FPIOAFunction = 239 // Debug function 15 + FUNC_DEBUG16 FPIOAFunction = 240 // Debug function 16 + FUNC_DEBUG17 FPIOAFunction = 241 // Debug function 17 + FUNC_DEBUG18 FPIOAFunction = 242 // Debug function 18 + FUNC_DEBUG19 FPIOAFunction = 243 // Debug function 19 + FUNC_DEBUG20 FPIOAFunction = 244 // Debug function 20 + FUNC_DEBUG21 FPIOAFunction = 245 // Debug function 21 + FUNC_DEBUG22 FPIOAFunction = 246 // Debug function 22 + FUNC_DEBUG23 FPIOAFunction = 247 // Debug function 23 + FUNC_DEBUG24 FPIOAFunction = 248 // Debug function 24 + FUNC_DEBUG25 FPIOAFunction = 249 // Debug function 25 + FUNC_DEBUG26 FPIOAFunction = 250 // Debug function 26 + FUNC_DEBUG27 FPIOAFunction = 251 // Debug function 27 + FUNC_DEBUG28 FPIOAFunction = 252 // Debug function 28 + FUNC_DEBUG29 FPIOAFunction = 253 // Debug function 29 + FUNC_DEBUG30 FPIOAFunction = 254 // Debug function 30 + FUNC_DEBUG31 FPIOAFunction = 255 // Debug function 31 +) + +// These are the default FPIOA values for each function. +// (source: https://github.com/kendryte/kendryte-standalone-sdk/blob/develop/lib/drivers/fpioa.c#L69) +var fpioaFuncDefaults [256]uint32 = [256]uint32{ + 0x00900000, 0x00900001, 0x00900002, 0x00001f03, 0x00b03f04, 0x00b03f05, 0x00b03f06, 0x00b03f07, 0x00b03f08, + 0x00b03f09, 0x00b03f0a, 0x00b03f0b, 0x00001f0c, 0x00001f0d, 0x00001f0e, 0x00001f0f, 0x03900010, 0x00001f11, + 0x00900012, 0x00001f13, 0x00900014, 0x00900015, 0x00001f16, 0x00001f17, 0x00901f18, 0x00901f19, 0x00901f1a, + 0x00901f1b, 0x00901f1c, 0x00901f1d, 0x00901f1e, 0x00901f1f, 0x00901f20, 0x00901f21, 0x00901f22, 0x00901f23, + 0x00901f24, 0x00901f25, 0x00901f26, 0x00901f27, 0x00901f28, 0x00901f29, 0x00901f2a, 0x00901f2b, 0x00901f2c, + 0x00901f2d, 0x00901f2e, 0x00901f2f, 0x00901f30, 0x00901f31, 0x00901f32, 0x00901f33, 0x00901f34, 0x00901f35, + 0x00901f36, 0x00901f37, 0x00901f38, 0x00901f39, 0x00901f3a, 0x00901f3b, 0x00901f3c, 0x00901f3d, 0x00901f3e, + 0x00901f3f, 0x00900040, 0x00001f41, 0x00900042, 0x00001f43, 0x00900044, 0x00001f45, 0x00b03f46, 0x00b03f47, + 0x00b03f48, 0x00b03f49, 0x00b03f4a, 0x00b03f4b, 0x00b03f4c, 0x00b03f4d, 0x00001f4e, 0x00001f4f, 0x00001f50, + 0x00001f51, 0x03900052, 0x00001f53, 0x00b03f54, 0x00900055, 0x00900056, 0x00001f57, 0x00001f58, 0x00001f59, + 0x0090005a, 0x0090005b, 0x0090005c, 0x0090005d, 0x00001f5e, 0x00001f5f, 0x00001f60, 0x00001f61, 0x00001f62, + 0x00001f63, 0x00001f64, 0x00900065, 0x00900066, 0x00900067, 0x00900068, 0x00001f69, 0x00001f6a, 0x00001f6b, + 0x00001f6c, 0x00001f6d, 0x00001f6e, 0x00001f6f, 0x00900070, 0x00900071, 0x00900072, 0x00900073, 0x00001f74, + 0x00001f75, 0x00001f76, 0x00001f77, 0x00000078, 0x00000079, 0x0000007a, 0x0000007b, 0x0000007c, 0x0000007d, + 0x0099107e, 0x0099107f, 0x00991080, 0x00991081, 0x00991082, 0x00991083, 0x00001f84, 0x00001f85, 0x00001f86, + 0x00900087, 0x00900088, 0x00900089, 0x0090008a, 0x0090008b, 0x0090008c, 0x0090008d, 0x0090008e, 0x0090008f, + 0x00900090, 0x00900091, 0x00993092, 0x00993093, 0x00900094, 0x00900095, 0x00900096, 0x00900097, 0x00900098, + 0x00001f99, 0x00001f9a, 0x00001f9b, 0x00001f9c, 0x00001f9d, 0x00001f9e, 0x00001f9f, 0x00001fa0, 0x00001fa1, + 0x009000a2, 0x009000a3, 0x009000a4, 0x009000a5, 0x009000a6, 0x00001fa7, 0x00001fa8, 0x00001fa9, 0x00001faa, + 0x00001fab, 0x00001fac, 0x00001fad, 0x00001fae, 0x00001faf, 0x009000b0, 0x009000b1, 0x009000b2, 0x009000b3, + 0x009000b4, 0x00001fb5, 0x00001fb6, 0x00001fb7, 0x00001fb8, 0x00001fb9, 0x00001fba, 0x00001fbb, 0x00001fbc, + 0x00001fbd, 0x00001fbe, 0x00001fbf, 0x00001fc0, 0x00001fc1, 0x00001fc2, 0x00001fc3, 0x00001fc4, 0x00001fc5, + 0x00001fc6, 0x00001fc7, 0x00001fc8, 0x00001fc9, 0x00001fca, 0x00001fcb, 0x00001fcc, 0x00001fcd, 0x00001fce, + 0x00001fcf, 0x00001fd0, 0x00001fd1, 0x00001fd2, 0x00001fd3, 0x00001fd4, 0x009000d5, 0x009000d6, 0x009000d7, + 0x009000d8, 0x009100d9, 0x00991fda, 0x009000db, 0x009000dc, 0x009000dd, 0x000000de, 0x009000df, 0x00001fe0, + 0x00001fe1, 0x00001fe2, 0x00001fe3, 0x00001fe4, 0x00001fe5, 0x00001fe6, 0x00001fe7, 0x00001fe8, 0x00001fe9, + 0x00001fea, 0x00001feb, 0x00001fec, 0x00001fed, 0x00001fee, 0x00001fef, 0x00001ff0, 0x00001ff1, 0x00001ff2, + 0x00001ff3, 0x00001ff4, 0x00001ff5, 0x00001ff6, 0x00001ff7, 0x00001ff8, 0x00001ff9, 0x00001ffa, 0x00001ffb, + 0x00001ffc, 0x00001ffd, 0x00001ffe, 0x00001fff, +} diff --git a/src/machine/board_maixbit.go b/src/machine/board_maixbit.go index 2c60fc980a..c1d002f36a 100644 --- a/src/machine/board_maixbit.go +++ b/src/machine/board_maixbit.go @@ -40,18 +40,6 @@ const ( D33 = P33 // GPIOHS17 D34 = P34 // GPIOHS18 D35 = P35 // GPIOHS19 - D36 = P36 // GPIOHS20 - D37 = P37 // GPIOHS21 - D38 = P38 // GPIOHS22 - D39 = P39 // GPIOHS23 - D40 = P40 // GPIOHS24 - D41 = P41 // GPIOHS25 - D42 = P42 // GPIOHS26 - D43 = P43 // GPIOHS27 - D44 = P44 // GPIOHS28 - D45 = P45 // GPIOHS29 - D46 = P46 // GPIOHS30 - D47 = P47 // GPIOHS31 ) const ( @@ -76,3 +64,9 @@ const ( SPI0_MOSI_PIN = D28 SPI0_MISO_PIN = D26 ) + +// I2C pins. +const ( + I2C0_SDA_PIN = D34 + I2C0_SCL_PIN = D35 +) diff --git a/src/machine/board_maixbit_baremetal.go b/src/machine/board_maixbit_baremetal.go index 98733bee81..3c75a4dfb1 100644 --- a/src/machine/board_maixbit_baremetal.go +++ b/src/machine/board_maixbit_baremetal.go @@ -13,3 +13,16 @@ var ( Bus: kendryte.SPI1, } ) + +// I2C on the MAix Bit. +var ( + I2C0 = I2C{ + Bus: kendryte.I2C0, + } + I2C1 = I2C{ + Bus: kendryte.I2C1, + } + I2C2 = I2C{ + Bus: kendryte.I2C2, + } +) diff --git a/src/machine/i2c.go b/src/machine/i2c.go index 977c9bad0d..3bab81d0da 100644 --- a/src/machine/i2c.go +++ b/src/machine/i2c.go @@ -1,4 +1,4 @@ -// +build avr nrf sam stm32,!stm32f4disco fe310 +// +build avr nrf sam stm32,!stm32f4disco fe310 k210 package machine diff --git a/src/machine/machine_k210.go b/src/machine/machine_k210.go index 247db08002..243ae54c4c 100644 --- a/src/machine/machine_k210.go +++ b/src/machine/machine_k210.go @@ -40,21 +40,12 @@ const ( PinLow = 8 ) -// FPIOA functions. -const ( - fpioaFuncSpi0Sclk = 17 - fpioaFuncSpi0D0 = 4 - fpioaFuncSpi0D1 = 5 - fpioaFuncSpi1Sclk = 83 - fpioaFuncSpi1D0 = 70 - fpioaFuncSpi1D1 = 71 -) - var ( - ErrUnsupportedSPIController = errors.New("SPI controller not supported. Use SPI0 or SPI1.") + errUnsupportedSPIController = errors.New("SPI controller not supported. Use SPI0 or SPI1.") + errI2CTxAbort = errors.New("I2C transmition has been aborted.") ) -func (p Pin) fpioaSetIOPull(pull fpioaPullMode) { +func (p Pin) setFPIOAIOPull(pull fpioaPullMode) { switch pull { case fpioaPullNone: kendryte.FPIOA.IO[uint8(p)].ClearBits(kendryte.FPIOA_IO_PU & kendryte.FPIOA_IO_PD) @@ -67,42 +58,55 @@ func (p Pin) fpioaSetIOPull(pull fpioaPullMode) { } } +// SetFPIOAFunction is used to configure the pin for one of the FPIOA functions. +// Each pin on the Kendryte K210 can be configured with any of the available FPIOA functions. +func (p Pin) SetFPIOAFunction(f FPIOAFunction) { + kendryte.FPIOA.IO[uint8(p)].Set(fpioaFuncDefaults[uint8(f)]) +} + +// FPIOAFunction returns the current FPIOA function of the pin. +func (p Pin) FPIOAFunction() FPIOAFunction { + return FPIOAFunction((kendryte.FPIOA.IO[uint8(p)].Get() & kendryte.FPIOA_IO_CH_SEL_Msk)) +} + // Configure this pin with the given configuration. +// The pin must already be set as GPIO or GPIOHS pin. func (p Pin) Configure(config PinConfig) { var input bool - kendryte.FPIOA.IO[uint8(p)].SetBits(kendryte.FPIOA_IO_OE_EN | kendryte.FPIOA_IO_IE_EN | kendryte.FPIOA_IO_ST | kendryte.FPIOA_IO_DS_Msk) + // Check if the current pin's FPIOA function is either GPIO or GPIOHS. + f := p.FPIOAFunction() + if f < FUNC_GPIOHS0 || f > FUNC_GPIO7 { + return // The pin is not configured as GPIO or GPIOHS. + } + switch config.Mode { case PinInput: - p.fpioaSetIOPull(fpioaPullNone) + p.setFPIOAIOPull(fpioaPullNone) input = true - case PinInputPullUp: - p.fpioaSetIOPull(fpioaPullUp) + p.setFPIOAIOPull(fpioaPullUp) input = true - case PinInputPullDown: - p.fpioaSetIOPull(fpioaPullDown) + p.setFPIOAIOPull(fpioaPullDown) input = true - case PinOutput: - p.fpioaSetIOPull(fpioaPullNone) + p.setFPIOAIOPull(fpioaPullNone) input = false - } - if p >= P08 && p <= P15 { - // Converts the IO pin number in the effective GPIO number (assuming default FPIOA function). - gpioPin := uint8(p) - 8 + if f >= FUNC_GPIO0 && f <= FUNC_GPIO7 { + // Converts the IO pin number in the effective GPIO number (based on the FPIOA function). + gpioPin := uint8(f - FUNC_GPIO0) if input { kendryte.GPIO.DIRECTION.ClearBits(1 << gpioPin) } else { kendryte.GPIO.DIRECTION.SetBits(1 << gpioPin) } - } else if p >= P16 && p <= P47 { - // Converts the IO pin number in the effective GPIOHS number (assuming default FPIOA function). - gpioPin := uint8(p) - 16 + } else if f >= FUNC_GPIOHS0 && f <= FUNC_GPIOHS31 { + // Converts the IO pin number in the effective GPIOHS number (based on the FPIOA function). + gpioPin := uint8(f - FUNC_GPIOHS0) if input { kendryte.GPIOHS.INPUT_EN.SetBits(1 << gpioPin) @@ -116,16 +120,23 @@ func (p Pin) Configure(config PinConfig) { // Set the pin to high or low. func (p Pin) Set(high bool) { - if p >= P08 && p <= P15 { - gpioPin := uint8(p) - 8 + + // Check if the current pin's FPIOA function is either GPIO or GPIOHS. + f := p.FPIOAFunction() + if f < FUNC_GPIOHS0 || f > FUNC_GPIO7 { + return // The pin is not configured as GPIO or GPIOHS. + } + + if f >= FUNC_GPIO0 && f <= FUNC_GPIO7 { + gpioPin := uint8(f - FUNC_GPIO0) if high { kendryte.GPIO.DATA_OUTPUT.SetBits(1 << gpioPin) } else { kendryte.GPIO.DATA_OUTPUT.ClearBits(1 << gpioPin) } - } else if p >= P16 && p <= P47 { - gpioPin := uint8(p) - 16 + } else if f >= FUNC_GPIOHS0 && f <= FUNC_GPIOHS31 { + gpioPin := uint8(f - FUNC_GPIOHS0) if high { kendryte.GPIOHS.OUTPUT_VAL.SetBits(1 << gpioPin) @@ -137,12 +148,19 @@ func (p Pin) Set(high bool) { // Get returns the current value of a GPIO pin. func (p Pin) Get() bool { + + // Check if the current pin's FPIOA function is either GPIO or GPIOHS. + f := p.FPIOAFunction() + if f < FUNC_GPIOHS0 || f > FUNC_GPIO7 { + return false // The pin is not configured as GPIO or GPIOHS. + } + var val uint32 - if p >= P08 && p <= P15 { - gpioPin := uint8(p) - 8 + if f >= FUNC_GPIO0 && f <= FUNC_GPIO7 { + gpioPin := uint8(f - FUNC_GPIO0) val = kendryte.GPIO.DATA_INPUT.Get() & (1 << gpioPin) - } else if p >= P16 && p <= P47 { - gpioPin := uint8(p) - 16 + } else if f >= FUNC_GPIOHS0 && f <= FUNC_GPIOHS31 { + gpioPin := uint8(f - FUNC_GPIOHS0) val = kendryte.GPIOHS.INPUT_VAL.Get() & (1 << gpioPin) } return (val > 0) @@ -161,11 +179,12 @@ var pinCallbacks [32]func(Pin) func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { // Check if the pin is a GPIOHS pin. - if p < P16 && p > P47 { + f := p.FPIOAFunction() + if f >= FUNC_GPIOHS0 && f <= FUNC_GPIOHS31 { return ErrInvalidDataPin } - gpioPin := uint8(p) - 16 + gpioPin := uint8(f - FUNC_GPIOHS0) // Clear all interrupts. kendryte.GPIOHS.RISE_IE.ClearBits(1 << gpioPin) @@ -242,70 +261,70 @@ func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { var ir interrupt.Interrupt - switch p { - case P16: + switch f { + case FUNC_GPIOHS0: ir = interrupt.New(kendryte.IRQ_GPIOHS0, handleInterrupt) - case P17: + case FUNC_GPIOHS1: ir = interrupt.New(kendryte.IRQ_GPIOHS1, handleInterrupt) - case P18: + case FUNC_GPIOHS2: ir = interrupt.New(kendryte.IRQ_GPIOHS2, handleInterrupt) - case P19: + case FUNC_GPIOHS3: ir = interrupt.New(kendryte.IRQ_GPIOHS3, handleInterrupt) - case P20: + case FUNC_GPIOHS4: ir = interrupt.New(kendryte.IRQ_GPIOHS4, handleInterrupt) - case P21: + case FUNC_GPIOHS5: ir = interrupt.New(kendryte.IRQ_GPIOHS5, handleInterrupt) - case P22: + case FUNC_GPIOHS6: ir = interrupt.New(kendryte.IRQ_GPIOHS6, handleInterrupt) - case P23: + case FUNC_GPIOHS7: ir = interrupt.New(kendryte.IRQ_GPIOHS7, handleInterrupt) - case P24: + case FUNC_GPIOHS8: ir = interrupt.New(kendryte.IRQ_GPIOHS8, handleInterrupt) - case P25: + case FUNC_GPIOHS9: ir = interrupt.New(kendryte.IRQ_GPIOHS9, handleInterrupt) - case P26: + case FUNC_GPIOHS10: ir = interrupt.New(kendryte.IRQ_GPIOHS10, handleInterrupt) - case P27: + case FUNC_GPIOHS11: ir = interrupt.New(kendryte.IRQ_GPIOHS11, handleInterrupt) - case P28: + case FUNC_GPIOHS12: ir = interrupt.New(kendryte.IRQ_GPIOHS12, handleInterrupt) - case P29: + case FUNC_GPIOHS13: ir = interrupt.New(kendryte.IRQ_GPIOHS13, handleInterrupt) - case P30: + case FUNC_GPIOHS14: ir = interrupt.New(kendryte.IRQ_GPIOHS14, handleInterrupt) - case P31: + case FUNC_GPIOHS15: ir = interrupt.New(kendryte.IRQ_GPIOHS15, handleInterrupt) - case P32: + case FUNC_GPIOHS16: ir = interrupt.New(kendryte.IRQ_GPIOHS16, handleInterrupt) - case P33: + case FUNC_GPIOHS17: ir = interrupt.New(kendryte.IRQ_GPIOHS17, handleInterrupt) - case P34: + case FUNC_GPIOHS18: ir = interrupt.New(kendryte.IRQ_GPIOHS18, handleInterrupt) - case P35: + case FUNC_GPIOHS19: ir = interrupt.New(kendryte.IRQ_GPIOHS19, handleInterrupt) - case P36: + case FUNC_GPIOHS20: ir = interrupt.New(kendryte.IRQ_GPIOHS20, handleInterrupt) - case P37: + case FUNC_GPIOHS21: ir = interrupt.New(kendryte.IRQ_GPIOHS21, handleInterrupt) - case P38: + case FUNC_GPIOHS22: ir = interrupt.New(kendryte.IRQ_GPIOHS22, handleInterrupt) - case P39: + case FUNC_GPIOHS23: ir = interrupt.New(kendryte.IRQ_GPIOHS23, handleInterrupt) - case P40: + case FUNC_GPIOHS24: ir = interrupt.New(kendryte.IRQ_GPIOHS24, handleInterrupt) - case P41: + case FUNC_GPIOHS25: ir = interrupt.New(kendryte.IRQ_GPIOHS25, handleInterrupt) - case P42: + case FUNC_GPIOHS26: ir = interrupt.New(kendryte.IRQ_GPIOHS26, handleInterrupt) - case P43: + case FUNC_GPIOHS27: ir = interrupt.New(kendryte.IRQ_GPIOHS27, handleInterrupt) - case P44: + case FUNC_GPIOHS28: ir = interrupt.New(kendryte.IRQ_GPIOHS28, handleInterrupt) - case P45: + case FUNC_GPIOHS29: ir = interrupt.New(kendryte.IRQ_GPIOHS29, handleInterrupt) - case P46: + case FUNC_GPIOHS30: ir = interrupt.New(kendryte.IRQ_GPIOHS30, handleInterrupt) - case P47: + case FUNC_GPIOHS31: ir = interrupt.New(kendryte.IRQ_GPIOHS31, handleInterrupt) } @@ -326,7 +345,22 @@ var ( ) func (uart UART) Configure(config UARTConfig) { - div := CPUFrequency()/115200 - 1 + + // Use default baudrate if not set. + if config.BaudRate == 0 { + config.BaudRate = 115200 + } + + // Use default pins if not set. + if config.TX == 0 && config.RX == 0 { + config.TX = UART_TX_PIN + config.RX = UART_RX_PIN + } + + config.TX.SetFPIOAFunction(FUNC_UARTHS_TX) + config.RX.SetFPIOAFunction(FUNC_UARTHS_RX) + + div := CPUFrequency()/config.BaudRate - 1 uart.Bus.DIV.Set(div) uart.Bus.TXCTRL.Set(kendryte.UARTHS_TXCTRL_TXEN) @@ -384,53 +418,38 @@ func (spi SPI) Configure(config SPIConfig) error { config.MISO = SPI0_MISO_PIN } - // Enable pins for SPI. - sckBits := uint32(kendryte.FPIOA_IO_OE_EN | kendryte.FPIOA_IO_DS_Msk) - dataBits := uint32(kendryte.FPIOA_IO_OE_EN | kendryte.FPIOA_IO_OE_INV | kendryte.FPIOA_IO_IE_EN | - kendryte.FPIOA_IO_IE_INV | kendryte.FPIOA_IO_ST | kendryte.FPIOA_IO_DS_Msk) - // Enable APB2 clock. kendryte.SYSCTL.CLK_EN_CENT.SetBits(kendryte.SYSCTL_CLK_EN_CENT_APB2_CLK_EN) - var fpioaFuncSclk uint32 - var fpioaFuncD0 uint32 - var fpioaFuncD1 uint32 - switch spi.Bus { case kendryte.SPI0: - // Initialize FPIOA values. - fpioaFuncSclk = fpioaFuncSpi0Sclk - fpioaFuncD0 = fpioaFuncSpi0D0 - fpioaFuncD1 = fpioaFuncSpi0D1 - // Initialize SPI clock. kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_SPI0_CLK_EN) kendryte.SYSCTL.CLK_TH1.ClearBits(kendryte.SYSCTL_CLK_TH1_SPI0_CLK_Msk) - case kendryte.SPI1: - // Initialize FPIOA values. - fpioaFuncSclk = fpioaFuncSpi1Sclk - fpioaFuncD0 = fpioaFuncSpi1D0 - fpioaFuncD1 = fpioaFuncSpi1D1 + // Initialize pins. + config.SCK.SetFPIOAFunction(FUNC_SPI0_SCLK) + config.MOSI.SetFPIOAFunction(FUNC_SPI0_D0) + config.MISO.SetFPIOAFunction(FUNC_SPI0_D1) + case kendryte.SPI1: // Initialize SPI clock. kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_SPI1_CLK_EN) kendryte.SYSCTL.CLK_TH1.ClearBits(kendryte.SYSCTL_CLK_TH1_SPI1_CLK_Msk) + + // Initialize pins. + config.SCK.SetFPIOAFunction(FUNC_SPI1_SCLK) + config.MOSI.SetFPIOAFunction(FUNC_SPI1_D0) + config.MISO.SetFPIOAFunction(FUNC_SPI1_D1) default: - return ErrUnsupportedSPIController + return errUnsupportedSPIController } - // Set FPIOA functins for selected pins. - kendryte.FPIOA.IO[uint8(config.SCK)].Set(uint32(sckBits | fpioaFuncSclk)) - kendryte.FPIOA.IO[uint8(config.MOSI)].Set(uint32(dataBits | fpioaFuncD0)) - kendryte.FPIOA.IO[uint8(config.MISO)].Set(uint32(dataBits | fpioaFuncD1)) - // Set default frequency. if config.Frequency == 0 { config.Frequency = 500000 } baudr := CPUFrequency() / config.Frequency - print(baudr) spi.Bus.BAUDR.Set(baudr) // Configure SPI mode 0, standard frame format, 8-bit data, little-endian. @@ -473,5 +492,148 @@ func (spi SPI) Transfer(w byte) (byte, error) { } return byte(spi.Bus.DR0.Get()), nil +} + +// I2C on the K210. +type I2C struct { + Bus *kendryte.I2C_Type +} + +// I2CConfig is used to store config info for I2C. +type I2CConfig struct { + Frequency uint32 + SCL Pin + SDA Pin +} + +// Configure is intended to setup the I2C interface. +func (i2c I2C) Configure(config I2CConfig) error { + + if config.Frequency == 0 { + config.Frequency = TWI_FREQ_100KHZ + } + + if config.SDA == 0 && config.SCL == 0 { + config.SDA = I2C0_SDA_PIN + config.SCL = I2C0_SCL_PIN + } + + // Enable APB0 clock. + kendryte.SYSCTL.CLK_EN_CENT.SetBits(kendryte.SYSCTL_CLK_EN_CENT_APB0_CLK_EN) + + switch i2c.Bus { + case kendryte.I2C0: + // Initialize I2C0 clock. + kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_I2C0_CLK_EN) + kendryte.SYSCTL.CLK_TH5.ReplaceBits(0x03, kendryte.SYSCTL_CLK_TH5_I2C0_CLK_Msk, kendryte.SYSCTL_CLK_TH5_I2C0_CLK_Pos) + + // Initialize pins. + config.SDA.SetFPIOAFunction(FUNC_I2C0_SDA) + config.SCL.SetFPIOAFunction(FUNC_I2C0_SCLK) + case kendryte.I2C1: + // Initialize I2C1 clock. + kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_I2C1_CLK_EN) + kendryte.SYSCTL.CLK_TH5.ReplaceBits(0x03, kendryte.SYSCTL_CLK_TH5_I2C1_CLK_Msk, kendryte.SYSCTL_CLK_TH5_I2C1_CLK_Pos) + + // Initialize pins. + config.SDA.SetFPIOAFunction(FUNC_I2C1_SDA) + config.SCL.SetFPIOAFunction(FUNC_I2C1_SCLK) + case kendryte.I2C2: + // Initialize I2C2 clock. + kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_I2C2_CLK_EN) + kendryte.SYSCTL.CLK_TH5.ReplaceBits(0x03, kendryte.SYSCTL_CLK_TH5_I2C2_CLK_Msk, kendryte.SYSCTL_CLK_TH5_I2C2_CLK_Pos) + + // Initialize pins. + config.SDA.SetFPIOAFunction(FUNC_I2C2_SDA) + config.SCL.SetFPIOAFunction(FUNC_I2C2_SCLK) + } + + div := CPUFrequency() / config.Frequency / 16 + + // Disable controller before setting the prescale register. + i2c.Bus.ENABLE.Set(0) + i2c.Bus.CON.Set(0x63) + + // Set prescaler registers. + i2c.Bus.SS_SCL_HCNT.Set(uint32(div)) + i2c.Bus.SS_SCL_LCNT.Set(uint32(div)) + + i2c.Bus.INTR_MASK.Set(0) + i2c.Bus.DMA_CR.Set(0x03) + i2c.Bus.DMA_RDLR.Set(0) + i2c.Bus.DMA_TDLR.Set(0x4) + + return nil +} + +// Tx does a single I2C transaction at the specified address. +// It clocks out the given address, writes the bytes in w, reads back len(r) +// bytes and stores them in r, and generates a stop condition on the bus. +func (i2c I2C) Tx(addr uint16, w, r []byte) error { + // Set slave address. + i2c.Bus.TAR.Set(uint32(addr)) + // Enable controller. + i2c.Bus.ENABLE.Set(1) + + if len(w) != 0 { + i2c.Bus.CLR_TX_ABRT.Set(i2c.Bus.CLR_TX_ABRT.Get()) + dataLen := uint32(len(w)) + di := 0 + + for dataLen != 0 { + fifoLen := 8 - i2c.Bus.TXFLR.Get() + if dataLen < fifoLen { + fifoLen = dataLen + } + + for i := uint32(0); i < fifoLen; i++ { + i2c.Bus.DATA_CMD.Set(uint32(w[di])) + di += 1 + } + if i2c.Bus.TX_ABRT_SOURCE.Get() != 0 { + return errI2CTxAbort + } + dataLen -= fifoLen + } + + // Wait for transmition to complete. + for i2c.Bus.STATUS.HasBits(kendryte.I2C_STATUS_ACTIVITY) || !i2c.Bus.STATUS.HasBits(kendryte.I2C_STATUS_TFE) { + } + + if i2c.Bus.TX_ABRT_SOURCE.Get() != 0 { + return errI2CTxAbort + } + } + if len(r) != 0 { + dataLen := uint32(len(r)) + cmdLen := uint32(len(r)) + di := 0 + + for dataLen != 0 || cmdLen != 0 { + fifoLen := 8 - i2c.Bus.RXFLR.Get() + if dataLen < fifoLen { + fifoLen = dataLen + } + for i := uint32(0); i < fifoLen; i++ { + r[di] = byte(i2c.Bus.DATA_CMD.Get()) + di += 1 + } + dataLen -= fifoLen + + fifoLen = 8 - i2c.Bus.TXFLR.Get() + if cmdLen < fifoLen { + fifoLen = cmdLen + } + for i := uint32(0); i < fifoLen; i++ { + i2c.Bus.DATA_CMD.Set(0x100) + } + if i2c.Bus.TX_ABRT_SOURCE.Get() != 0 { + return errI2CTxAbort + } + cmdLen -= fifoLen + } + } + + return nil } From 2d30ea685d0de7cf88d739ac5beaea5fb021f45a Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Tue, 30 Jun 2020 14:15:14 +0200 Subject: [PATCH 19/28] maixbit: add smoke test --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 270c894d73..0982c66fc0 100644 --- a/Makefile +++ b/Makefile @@ -324,6 +324,8 @@ endif @$(MD5SUM) test.hex $(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/export $(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/main + $(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1 + @$(MD5SUM) test.hex wasmtest: $(GO) test ./tests/wasm From 40b5481a73c6ff6e2caf283d65f79c4e49b12e8d Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Tue, 30 Jun 2020 16:35:51 +0200 Subject: [PATCH 20/28] builder: add support for 64-bit RISC-V --- builder/library.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builder/library.go b/builder/library.go index 7bb506c765..674a784471 100644 --- a/builder/library.go +++ b/builder/library.go @@ -74,6 +74,9 @@ func (l *Library) Load(target string) (path string, err error) { if strings.HasPrefix(target, "riscv32-") { args = append(args, "-march=rv32imac", "-mabi=ilp32", "-fforce-enable-int128") } + if strings.HasPrefix(target, "riscv64-") { + args = append(args, "-march=rv64gc", "-mabi=lp64") + } // Compile all sources. var objs []string From 0cca6a1ca9297e3df27187d1c2d42026707a5789 Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Wed, 1 Jul 2020 10:17:34 +0200 Subject: [PATCH 21/28] maixbit (i2c): fix rx fifo buffer length --- src/machine/machine_k210.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_k210.go b/src/machine/machine_k210.go index 243ae54c4c..ca5f2d8047 100644 --- a/src/machine/machine_k210.go +++ b/src/machine/machine_k210.go @@ -611,7 +611,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error { di := 0 for dataLen != 0 || cmdLen != 0 { - fifoLen := 8 - i2c.Bus.RXFLR.Get() + fifoLen := i2c.Bus.RXFLR.Get() if dataLen < fifoLen { fifoLen = dataLen } From be7ae858a7154b44ea4b25dffeec46feabbc49f9 Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Wed, 1 Jul 2020 15:46:47 +0200 Subject: [PATCH 22/28] maixbit (gpio): fix pin configuration --- src/machine/machine_k210.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/machine/machine_k210.go b/src/machine/machine_k210.go index ca5f2d8047..b92eab9101 100644 --- a/src/machine/machine_k210.go +++ b/src/machine/machine_k210.go @@ -80,6 +80,9 @@ func (p Pin) Configure(config PinConfig) { return // The pin is not configured as GPIO or GPIOHS. } + // Configure pin. + kendryte.FPIOA.IO[uint8(p)].SetBits(kendryte.FPIOA_IO_OE_EN | kendryte.FPIOA_IO_IE_EN | kendryte.FPIOA_IO_ST | kendryte.FPIOA_IO_DS_Msk) + switch config.Mode { case PinInput: p.setFPIOAIOPull(fpioaPullNone) From fcc79ee731024a84754e356be77a61266526e1dc Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Wed, 1 Jul 2020 15:49:02 +0200 Subject: [PATCH 23/28] maixbit: workaround to avoid medium code model --- targets/k210.json | 3 +-- targets/maixbit.ld | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/targets/k210.json b/targets/k210.json index 4c5f3f91ff..5ddd9dbab9 100644 --- a/targets/k210.json +++ b/targets/k210.json @@ -1,6 +1,5 @@ { "inherits": ["riscv64"], "features": ["+a", "+c", "+m", "+f", "+d"], - "build-tags": ["k210", "kendryte"], - "code-model": "medium" + "build-tags": ["k210", "kendryte"] } diff --git a/targets/maixbit.ld b/targets/maixbit.ld index e1162a38dc..1f8ed4dd46 100644 --- a/targets/maixbit.ld +++ b/targets/maixbit.ld @@ -1,7 +1,11 @@ MEMORY { - RAM (xrw) : ORIGIN = 0x80000000, LENGTH = 6M + /* This is a software workaround to avoid using the medany code model + which causes the llvm9 build to fail. 0x80000000 is mirorred at + 0xffffffff80000000. This is not needed anymore on llvm10. + https://github.com/rust-embedded/riscv-rt/issues/25 */ + RAM (xrw) : ORIGIN = 0xffffffff80000000, LENGTH = 6M } REGION_ALIAS("FLASH_TEXT", RAM); From 35ec8b01f853b066be2dcf313850fe50a12c739a Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Wed, 1 Jul 2020 18:03:18 +0200 Subject: [PATCH 24/28] maixbit (interruptions): fix fpioa function test --- src/machine/machine_k210.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_k210.go b/src/machine/machine_k210.go index b92eab9101..eea477f215 100644 --- a/src/machine/machine_k210.go +++ b/src/machine/machine_k210.go @@ -183,7 +183,7 @@ func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { // Check if the pin is a GPIOHS pin. f := p.FPIOAFunction() - if f >= FUNC_GPIOHS0 && f <= FUNC_GPIOHS31 { + if f < FUNC_GPIOHS0 || f > FUNC_GPIOHS31 { return ErrInvalidDataPin } From 88be30b77f0eb8aeb1ad883f3e37ff5c63999e7c Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Wed, 1 Jul 2020 23:26:33 +0200 Subject: [PATCH 25/28] riscv: refactor assembly files to support RV64 and F extension --- src/device/riscv/handleinterrupt.S | 130 ++++++++++++++++++++++++++ src/device/riscv/handleinterrupt32.S | 44 --------- src/device/riscv/handleinterrupt64.S | 44 --------- src/runtime/scheduler_tinygoriscv.S | 42 +++++---- src/runtime/scheduler_tinygoriscv64.S | 32 ------- targets/k210.json | 3 +- targets/riscv.json | 4 +- targets/riscv32.json | 4 - targets/riscv64.json | 7 +- 9 files changed, 163 insertions(+), 147 deletions(-) create mode 100644 src/device/riscv/handleinterrupt.S delete mode 100644 src/device/riscv/handleinterrupt32.S delete mode 100644 src/device/riscv/handleinterrupt64.S delete mode 100644 src/runtime/scheduler_tinygoriscv64.S diff --git a/src/device/riscv/handleinterrupt.S b/src/device/riscv/handleinterrupt.S new file mode 100644 index 0000000000..dbf54f01ab --- /dev/null +++ b/src/device/riscv/handleinterrupt.S @@ -0,0 +1,130 @@ +#ifdef F_EXTENSION +#define NREG 48 +#define LFREG flw +#define SFREG fsw +#else +#define NREG 16 +#endif + +#ifdef RV64 +#define REGSIZE 8 +#define SREG sd +#define LREG ld +#else +#define REGSIZE 4 +#define SREG sw +#define LREG lw +#endif + +.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, -NREG*REGSIZE + SREG ra, 0*REGSIZE(sp) + SREG t0, 1*REGSIZE(sp) + SREG t1, 2*REGSIZE(sp) + SREG t2, 3*REGSIZE(sp) + SREG a0, 4*REGSIZE(sp) + SREG a1, 5*REGSIZE(sp) + SREG a2, 6*REGSIZE(sp) + SREG a3, 7*REGSIZE(sp) + SREG a4, 8*REGSIZE(sp) + SREG a5, 9*REGSIZE(sp) + SREG a6, 10*REGSIZE(sp) + SREG a7, 11*REGSIZE(sp) + SREG t3, 12*REGSIZE(sp) + SREG t4, 13*REGSIZE(sp) + SREG t5, 14*REGSIZE(sp) + SREG t6, 15*REGSIZE(sp) +#ifdef F_EXTENSION + SFREG f0, (0 + 16)*REGSIZE(sp) + SFREG f1, (1 + 16)*REGSIZE(sp) + SFREG f2, (2 + 16)*REGSIZE(sp) + SFREG f3, (3 + 16)*REGSIZE(sp) + SFREG f4, (4 + 16)*REGSIZE(sp) + SFREG f5, (5 + 16)*REGSIZE(sp) + SFREG f6, (6 + 16)*REGSIZE(sp) + SFREG f7, (7 + 16)*REGSIZE(sp) + SFREG f8, (8 + 16)*REGSIZE(sp) + SFREG f9, (9 + 16)*REGSIZE(sp) + SFREG f10,(10 + 16)*REGSIZE(sp) + SFREG f11,(11 + 16)*REGSIZE(sp) + SFREG f12,(12 + 16)*REGSIZE(sp) + SFREG f13,(13 + 16)*REGSIZE(sp) + SFREG f14,(14 + 16)*REGSIZE(sp) + SFREG f15,(15 + 16)*REGSIZE(sp) + SFREG f16,(16 + 16)*REGSIZE(sp) + SFREG f17,(17 + 16)*REGSIZE(sp) + SFREG f18,(18 + 16)*REGSIZE(sp) + SFREG f19,(19 + 16)*REGSIZE(sp) + SFREG f20,(20 + 16)*REGSIZE(sp) + SFREG f21,(21 + 16)*REGSIZE(sp) + SFREG f22,(22 + 16)*REGSIZE(sp) + SFREG f23,(23 + 16)*REGSIZE(sp) + SFREG f24,(24 + 16)*REGSIZE(sp) + SFREG f25,(25 + 16)*REGSIZE(sp) + SFREG f26,(26 + 16)*REGSIZE(sp) + SFREG f27,(27 + 16)*REGSIZE(sp) + SFREG f28,(28 + 16)*REGSIZE(sp) + SFREG f29,(29 + 16)*REGSIZE(sp) + SFREG f30,(30 + 16)*REGSIZE(sp) + SFREG f31,(31 + 16)*REGSIZE(sp) +#endif + call handleInterrupt +#ifdef F_EXTENSION + LFREG f0, (31 + 16)*REGSIZE(sp) + LFREG f1, (30 + 16)*REGSIZE(sp) + LFREG f2, (29 + 16)*REGSIZE(sp) + LFREG f3, (28 + 16)*REGSIZE(sp) + LFREG f4, (27 + 16)*REGSIZE(sp) + LFREG f5, (26 + 16)*REGSIZE(sp) + LFREG f6, (25 + 16)*REGSIZE(sp) + LFREG f7, (24 + 16)*REGSIZE(sp) + LFREG f8, (23 + 16)*REGSIZE(sp) + LFREG f9, (22 + 16)*REGSIZE(sp) + LFREG f10,(21 + 16)*REGSIZE(sp) + LFREG f11,(20 + 16)*REGSIZE(sp) + LFREG f12,(19 + 16)*REGSIZE(sp) + LFREG f13,(18 + 16)*REGSIZE(sp) + LFREG f14,(17 + 16)*REGSIZE(sp) + LFREG f15,(16 + 16)*REGSIZE(sp) + LFREG f16,(15 + 16)*REGSIZE(sp) + LFREG f17,(14 + 16)*REGSIZE(sp) + LFREG f18,(13 + 16)*REGSIZE(sp) + LFREG f19,(12 + 16)*REGSIZE(sp) + LFREG f20,(11 + 16)*REGSIZE(sp) + LFREG f21,(10 + 16)*REGSIZE(sp) + LFREG f22,(9 + 16)*REGSIZE(sp) + LFREG f23,(8 + 16)*REGSIZE(sp) + LFREG f24,(7 + 16)*REGSIZE(sp) + LFREG f25,(6 + 16)*REGSIZE(sp) + LFREG f26,(5 + 16)*REGSIZE(sp) + LFREG f27,(4 + 16)*REGSIZE(sp) + LFREG f28,(3 + 16)*REGSIZE(sp) + LFREG f29,(2 + 16)*REGSIZE(sp) + LFREG f30,(1 + 16)*REGSIZE(sp) + LFREG f31,(0 + 16)*REGSIZE(sp) +#endif + LREG t6, 15*REGSIZE(sp) + LREG t5, 14*REGSIZE(sp) + LREG t4, 13*REGSIZE(sp) + LREG t3, 12*REGSIZE(sp) + LREG a7, 11*REGSIZE(sp) + LREG a6, 10*REGSIZE(sp) + LREG a5, 9*REGSIZE(sp) + LREG a4, 8*REGSIZE(sp) + LREG a3, 7*REGSIZE(sp) + LREG a2, 6*REGSIZE(sp) + LREG a1, 5*REGSIZE(sp) + LREG a0, 4*REGSIZE(sp) + LREG t2, 3*REGSIZE(sp) + LREG t1, 2*REGSIZE(sp) + LREG t0, 1*REGSIZE(sp) + LREG ra, 0*REGSIZE(sp) + addi sp, sp, NREG*REGSIZE + mret diff --git a/src/device/riscv/handleinterrupt32.S b/src/device/riscv/handleinterrupt32.S deleted file mode 100644 index 4358977ae0..0000000000 --- a/src/device/riscv/handleinterrupt32.S +++ /dev/null @@ -1,44 +0,0 @@ -.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, -64 - sw ra, 60(sp) - sw t0, 56(sp) - sw t1, 52(sp) - sw t2, 48(sp) - sw a0, 44(sp) - sw a1, 40(sp) - sw a2, 36(sp) - sw a3, 32(sp) - sw a4, 28(sp) - sw a5, 24(sp) - sw a6, 20(sp) - sw a7, 16(sp) - sw t3, 12(sp) - sw t4, 8(sp) - sw t5, 4(sp) - sw t6, 0(sp) - call handleInterrupt - lw t6, 0(sp) - lw t5, 4(sp) - lw t4, 8(sp) - lw t3, 12(sp) - lw a7, 16(sp) - lw a6, 20(sp) - lw a5, 24(sp) - lw a4, 28(sp) - lw a3, 32(sp) - lw a2, 36(sp) - lw a1, 40(sp) - lw a0, 44(sp) - lw t2, 48(sp) - lw t1, 52(sp) - lw t0, 56(sp) - lw ra, 60(sp) - addi sp, sp, 64 - mret diff --git a/src/device/riscv/handleinterrupt64.S b/src/device/riscv/handleinterrupt64.S deleted file mode 100644 index e0c6a3bf5e..0000000000 --- a/src/device/riscv/handleinterrupt64.S +++ /dev/null @@ -1,44 +0,0 @@ -.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 diff --git a/src/runtime/scheduler_tinygoriscv.S b/src/runtime/scheduler_tinygoriscv.S index 3766bae754..9749ca2217 100644 --- a/src/runtime/scheduler_tinygoriscv.S +++ b/src/runtime/scheduler_tinygoriscv.S @@ -1,32 +1,42 @@ +#ifdef RV64 +#define REGSIZE 8 +#define SREG sd +#define LREG ld +#else +#define REGSIZE 4 +#define SREG sw +#define LREG lw +#endif + .section .text.tinygo_scanCurrentStack .global tinygo_scanCurrentStack .type tinygo_scanCurrentStack, %function tinygo_scanCurrentStack: // Push callee-saved registers onto the stack. - addi sp, sp, -64 - sw ra, 60(sp) - sw s11, 56(sp) - sw s10, 52(sp) - sw s9, 48(sp) - sw s8, 44(sp) - sw s7, 40(sp) - sw s6, 36(sp) - sw s5, 32(sp) - sw s4, 28(sp) - sw s3, 24(sp) - sw s2, 20(sp) - sw s1, 16(sp) - sw s0, 12(sp) + addi sp, sp, -13*REGSIZE + SREG ra, 0*REGSIZE(sp) + SREG s11, 1*REGSIZE(sp) + SREG s10, 2*REGSIZE(sp) + SREG s9, 3*REGSIZE(sp) + SREG s8, 4*REGSIZE(sp) + SREG s7, 5*REGSIZE(sp) + SREG s6, 6*REGSIZE(sp) + SREG s5, 7*REGSIZE(sp) + SREG s4, 8*REGSIZE(sp) + SREG s3, 9*REGSIZE(sp) + SREG s2, 10*REGSIZE(sp) + SREG s1, 11*REGSIZE(sp) + SREG s0, 12*REGSIZE(sp) // Scan the stack. mv a0, sp call tinygo_scanstack // Restore return address. - lw ra, 60(sp) + LREG ra, 0(sp) // Restore stack state. - addi sp, sp, 64 + addi sp, sp, 13*REGSIZE // Return to the caller. ret diff --git a/src/runtime/scheduler_tinygoriscv64.S b/src/runtime/scheduler_tinygoriscv64.S deleted file mode 100644 index 84be3e2de6..0000000000 --- a/src/runtime/scheduler_tinygoriscv64.S +++ /dev/null @@ -1,32 +0,0 @@ -.section .text.tinygo_scanCurrentStack -.global tinygo_scanCurrentStack -.type tinygo_scanCurrentStack, %function -tinygo_scanCurrentStack: - // Push callee-saved registers onto the stack. - addi sp, sp, -104 - sd ra, 96(sp) - sd s11, 88(sp) - sd s10, 80(sp) - sd s9, 72(sp) - sd s8, 64(sp) - sd s7, 56(sp) - sd s6, 48(sp) - sd s5, 40(sp) - sd s4, 32(sp) - sd s3, 24(sp) - sd s2, 16(sp) - sd s1, 8(sp) - sd s0, 0(sp) - - // Scan the stack. - mv a0, sp - call tinygo_scanstack - - // Restore return address. - ld ra, 96(sp) - - // Restore stack state. - addi sp, sp, 104 - - // Return to the caller. - ret diff --git a/targets/k210.json b/targets/k210.json index 5ddd9dbab9..77fcc53d6e 100644 --- a/targets/k210.json +++ b/targets/k210.json @@ -1,5 +1,6 @@ { "inherits": ["riscv64"], "features": ["+a", "+c", "+m", "+f", "+d"], - "build-tags": ["k210", "kendryte"] + "build-tags": ["k210", "kendryte"], + "cflags": ["-D=F_EXTENSION"] } diff --git a/targets/riscv.json b/targets/riscv.json index a2d4aaeb69..da40416bf8 100644 --- a/targets/riscv.json +++ b/targets/riscv.json @@ -17,7 +17,9 @@ "--gc-sections" ], "extra-files": [ - "src/device/riscv/start.S" + "src/device/riscv/start.S", + "src/runtime/scheduler_tinygoriscv.S", + "src/device/riscv/handleinterrupt.S" ], "gdb": "riscv64-unknown-elf-gdb" } diff --git a/targets/riscv32.json b/targets/riscv32.json index fb1bdb94f3..24f5cee906 100644 --- a/targets/riscv32.json +++ b/targets/riscv32.json @@ -9,9 +9,5 @@ ], "ldflags": [ "-melf32lriscv" - ], - "extra-files": [ - "src/runtime/scheduler_tinygoriscv.S", - "src/device/riscv/handleinterrupt32.S" ] } diff --git a/targets/riscv64.json b/targets/riscv64.json index 20c7f1baf2..f73700c9c4 100644 --- a/targets/riscv64.json +++ b/targets/riscv64.json @@ -5,13 +5,10 @@ "cflags": [ "--target=riscv64--none", "-march=rv64gc", - "-mabi=lp64" + "-mabi=lp64", + "-D=RV64" ], "ldflags": [ "-melf64lriscv" - ], - "extra-files": [ - "src/runtime/scheduler_tinygoriscv64.S", - "src/device/riscv/handleinterrupt64.S" ] } From 2be5923d74e0ec1b9b0048be923f81390def0862 Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Sat, 4 Jul 2020 14:24:15 +0200 Subject: [PATCH 26/28] maixbit: use custom linker script This linker script does not offer stack overflow protection because the stack cannot be placed at the bottom of the RAM. --- targets/maixbit.ld | 60 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/targets/maixbit.ld b/targets/maixbit.ld index 1f8ed4dd46..c2cffae98f 100644 --- a/targets/maixbit.ld +++ b/targets/maixbit.ld @@ -8,8 +8,62 @@ MEMORY RAM (xrw) : ORIGIN = 0xffffffff80000000, LENGTH = 6M } -REGION_ALIAS("FLASH_TEXT", RAM); - _stack_size = 2K; -INCLUDE "targets/riscv.ld" +SECTIONS +{ + .text : + { + . = ALIGN(16); + KEEP(*(.init)) + . = ALIGN(16); + *(.text.handleInterruptASM) + *(.text) + *(.text.*) + *(.rodata) + *(.rodata.*) + . = ALIGN(16); + } >RAM + + + /* Start address (in flash) of .data, used by startup code. */ + _sidata = LOADADDR(.data); + + /* Globals with initial value */ + .data : + { + . = ALIGN(16); + /* see https://gnu-mcu-eclipse.github.io/arch/riscv/programmer/#the-gp-global-pointer-register */ + PROVIDE( __global_pointer$ = . + (4K / 2) ); + _sdata = .; /* used by startup code */ + *(.sdata) + *(.data .data.*) + . = ALIGN(16); + _edata = .; /* used by startup code */ + } >RAM + + /* Zero-initialized globals */ + .bss : + { + . = ALIGN(16); + _sbss = .; /* used by startup code */ + *(.sbss) + *(.bss .bss.*) + *(COMMON) + . = ALIGN(16); + _ebss = .; /* used by startup code */ + } >RAM + + /DISCARD/ : + { + *(.eh_frame) /* causes 'no memory region specified' error in lld */ + } +} + +PROVIDE(_stack_top = ORIGIN(RAM) + LENGTH(RAM)); + +/* For the memory allocator. */ +_heap_start = _ebss; +_heap_end = ORIGIN(RAM) + LENGTH(RAM) - _stack_size; +_globals_start = _sdata; +_globals_end = _ebss; From c874cbeecf4f3b15154cf97add663c03afef259a Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Sat, 4 Jul 2020 15:13:44 +0200 Subject: [PATCH 27/28] runtime: reuse common code between 32 and 64-bit RISC-V --- src/runtime/arch_tinygoriscv.go | 12 +----------- src/runtime/arch_tinygoriscv32.go | 13 +++++++++++++ src/runtime/arch_tinygoriscv64.go | 6 ------ 3 files changed, 14 insertions(+), 17 deletions(-) create mode 100644 src/runtime/arch_tinygoriscv32.go diff --git a/src/runtime/arch_tinygoriscv.go b/src/runtime/arch_tinygoriscv.go index 8bd0f0767d..3dcbcec255 100644 --- a/src/runtime/arch_tinygoriscv.go +++ b/src/runtime/arch_tinygoriscv.go @@ -1,19 +1,9 @@ -// +build tinygo.riscv32 +// +build tinygo.riscv package runtime import "device/riscv" -const GOARCH = "arm" // riscv pretends to be arm - -// The bitness of the CPU (e.g. 8, 32, 64). -const TargetBits = 32 - -// Align on word boundary. -func align(ptr uintptr) uintptr { - return (ptr + 3) &^ 3 -} - func getCurrentStackPointer() uintptr { return riscv.AsmFull("mv {}, sp", nil) } diff --git a/src/runtime/arch_tinygoriscv32.go b/src/runtime/arch_tinygoriscv32.go new file mode 100644 index 0000000000..dcae760470 --- /dev/null +++ b/src/runtime/arch_tinygoriscv32.go @@ -0,0 +1,13 @@ +// +build tinygo.riscv32 + +package runtime + +const GOARCH = "arm" // riscv pretends to be arm + +// The bitness of the CPU (e.g. 8, 32, 64). +const TargetBits = 32 + +// Align on word boundary. +func align(ptr uintptr) uintptr { + return (ptr + 3) &^ 3 +} diff --git a/src/runtime/arch_tinygoriscv64.go b/src/runtime/arch_tinygoriscv64.go index f17e1dfd25..a4a8c14f06 100644 --- a/src/runtime/arch_tinygoriscv64.go +++ b/src/runtime/arch_tinygoriscv64.go @@ -2,8 +2,6 @@ package runtime -import "device/riscv" - const GOARCH = "arm64" // riscv pretends to be arm // The bitness of the CPU (e.g. 8, 32, 64). @@ -13,7 +11,3 @@ const TargetBits = 64 func align(ptr uintptr) uintptr { return (ptr + 7) &^ 7 } - -func getCurrentStackPointer() uintptr { - return riscv.AsmFull("mv {}, sp", nil) -} From c0bc2a2ec6e7d1bf220c750041909174c386025e Mon Sep 17 00:00:00 2001 From: Yannis Huber Date: Sat, 4 Jul 2020 19:31:05 +0200 Subject: [PATCH 28/28] maixbit: changes according to feedback --- Makefile | 4 +-- src/device/riscv/handleinterrupt.S | 8 +++--- src/machine/machine_k210.go | 41 ++++++++++++----------------- src/runtime/scheduler_tinygoriscv.S | 2 +- targets/k210.json | 3 +-- targets/riscv.ld | 10 +++---- targets/riscv64.json | 3 +-- 7 files changed, 31 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index 0982c66fc0..03bf15dca7 100644 --- a/Makefile +++ b/Makefile @@ -322,10 +322,10 @@ ifneq ($(AVR), 0) endif $(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1 @$(MD5SUM) test.hex - $(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/export - $(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/main $(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1 @$(MD5SUM) test.hex + $(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/export + $(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/main wasmtest: $(GO) test ./tests/wasm diff --git a/src/device/riscv/handleinterrupt.S b/src/device/riscv/handleinterrupt.S index dbf54f01ab..c206c01595 100644 --- a/src/device/riscv/handleinterrupt.S +++ b/src/device/riscv/handleinterrupt.S @@ -1,4 +1,4 @@ -#ifdef F_EXTENSION +#ifdef __riscv_flen #define NREG 48 #define LFREG flw #define SFREG fsw @@ -6,7 +6,7 @@ #define NREG 16 #endif -#ifdef RV64 +#if __riscv_xlen==64 #define REGSIZE 8 #define SREG sd #define LREG ld @@ -41,7 +41,7 @@ handleInterruptASM: SREG t4, 13*REGSIZE(sp) SREG t5, 14*REGSIZE(sp) SREG t6, 15*REGSIZE(sp) -#ifdef F_EXTENSION +#ifdef __riscv_flen SFREG f0, (0 + 16)*REGSIZE(sp) SFREG f1, (1 + 16)*REGSIZE(sp) SFREG f2, (2 + 16)*REGSIZE(sp) @@ -76,7 +76,7 @@ handleInterruptASM: SFREG f31,(31 + 16)*REGSIZE(sp) #endif call handleInterrupt -#ifdef F_EXTENSION +#ifdef __riscv_flen LFREG f0, (31 + 16)*REGSIZE(sp) LFREG f1, (30 + 16)*REGSIZE(sp) LFREG f2, (29 + 16)*REGSIZE(sp) diff --git a/src/machine/machine_k210.go b/src/machine/machine_k210.go index eea477f215..caa1592baf 100644 --- a/src/machine/machine_k210.go +++ b/src/machine/machine_k210.go @@ -4,6 +4,7 @@ package machine import ( "device/kendryte" + "device/riscv" "errors" "runtime/interrupt" ) @@ -33,11 +34,9 @@ const ( // GPIOHS pin interrupt events. const ( - PinRising PinChange = iota + 1 + PinRising PinChange = 1 << iota PinFalling - PinToggle - PinHigh - PinLow = 8 + PinToggle = PinRising | PinFalling ) var ( @@ -224,12 +223,6 @@ func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { if change&PinFalling != 0 { kendryte.GPIOHS.FALL_IE.SetBits(1 << gpioPin) } - if change&PinHigh != 0 { - kendryte.GPIOHS.HIGH_IE.SetBits(1 << gpioPin) - } - if change&PinLow != 0 { - kendryte.GPIOHS.LOW_IE.SetBits(1 << gpioPin) - } handleInterrupt := func(inter interrupt.Interrupt) { @@ -237,28 +230,28 @@ func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { if kendryte.GPIOHS.RISE_IE.HasBits(1 << pin) { kendryte.GPIOHS.RISE_IE.ClearBits(1 << pin) - kendryte.GPIOHS.RISE_IP.SetBits(1 << pin) + // Acknowledge interrupt atomically. + riscv.AsmFull( + "amoor.w {}, {mask}, {reg}", + map[string]interface{}{ + "mask": uint32(1 << pin), + "reg": &kendryte.GPIOHS.RISE_IP.Reg, + }) kendryte.GPIOHS.RISE_IE.SetBits(1 << pin) } if kendryte.GPIOHS.FALL_IE.HasBits(1 << pin) { kendryte.GPIOHS.FALL_IE.ClearBits(1 << pin) - kendryte.GPIOHS.FALL_IP.SetBits(1 << pin) + // Acknowledge interrupt atomically. + riscv.AsmFull( + "amoor.w {}, {mask}, {reg}", + map[string]interface{}{ + "mask": uint32(1 << pin), + "reg": &kendryte.GPIOHS.FALL_IP.Reg, + }) kendryte.GPIOHS.FALL_IE.SetBits(1 << pin) } - if kendryte.GPIOHS.HIGH_IE.HasBits(1 << pin) { - kendryte.GPIOHS.HIGH_IE.ClearBits(1 << pin) - kendryte.GPIOHS.HIGH_IP.SetBits(1 << pin) - kendryte.GPIOHS.HIGH_IE.SetBits(1 << pin) - } - - if kendryte.GPIOHS.LOW_IE.HasBits(1 << pin) { - kendryte.GPIOHS.LOW_IE.ClearBits(1 << pin) - kendryte.GPIOHS.LOW_IP.SetBits(1 << pin) - kendryte.GPIOHS.LOW_IE.SetBits(1 << pin) - } - pinCallbacks[pin](Pin(pin)) } diff --git a/src/runtime/scheduler_tinygoriscv.S b/src/runtime/scheduler_tinygoriscv.S index 9749ca2217..e0aeada5db 100644 --- a/src/runtime/scheduler_tinygoriscv.S +++ b/src/runtime/scheduler_tinygoriscv.S @@ -1,4 +1,4 @@ -#ifdef RV64 +#if __riscv_xlen==64 #define REGSIZE 8 #define SREG sd #define LREG ld diff --git a/targets/k210.json b/targets/k210.json index 77fcc53d6e..5ddd9dbab9 100644 --- a/targets/k210.json +++ b/targets/k210.json @@ -1,6 +1,5 @@ { "inherits": ["riscv64"], "features": ["+a", "+c", "+m", "+f", "+d"], - "build-tags": ["k210", "kendryte"], - "cflags": ["-D=F_EXTENSION"] + "build-tags": ["k210", "kendryte"] } diff --git a/targets/riscv.ld b/targets/riscv.ld index 6ebee27288..2b9f502767 100644 --- a/targets/riscv.ld +++ b/targets/riscv.ld @@ -18,7 +18,7 @@ SECTIONS * See: http://blog.japaric.io/stack-overflow-protection/ */ .stack (NOLOAD) : { - . = ALIGN(8); + . = ALIGN(16); . += _stack_size; _stack_top = .; } >RAM @@ -29,25 +29,25 @@ SECTIONS /* Globals with initial value */ .data : { - . = ALIGN(8); + . = ALIGN(4); /* see https://gnu-mcu-eclipse.github.io/arch/riscv/programmer/#the-gp-global-pointer-register */ PROVIDE( __global_pointer$ = . + (4K / 2) ); _sdata = .; /* used by startup code */ *(.sdata) *(.data .data.*) - . = ALIGN(8); + . = ALIGN(4); _edata = .; /* used by startup code */ } >RAM AT>FLASH_TEXT /* Zero-initialized globals */ .bss : { - . = ALIGN(8); + . = ALIGN(4); _sbss = .; /* used by startup code */ *(.sbss) *(.bss .bss.*) *(COMMON) - . = ALIGN(8); + . = ALIGN(4); _ebss = .; /* used by startup code */ } >RAM diff --git a/targets/riscv64.json b/targets/riscv64.json index f73700c9c4..a2a0641f98 100644 --- a/targets/riscv64.json +++ b/targets/riscv64.json @@ -5,8 +5,7 @@ "cflags": [ "--target=riscv64--none", "-march=rv64gc", - "-mabi=lp64", - "-D=RV64" + "-mabi=lp64" ], "ldflags": [ "-melf64lriscv"