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..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/posborne/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 diff --git a/Makefile b/Makefile index 3295b9cd0e..03bf15dca7 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 @@ -318,6 +322,8 @@ ifneq ($(AVR), 0) endif $(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1 @$(MD5SUM) test.hex + $(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 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 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/src/device/riscv/handleinterrupt.S b/src/device/riscv/handleinterrupt.S new file mode 100644 index 0000000000..c206c01595 --- /dev/null +++ b/src/device/riscv/handleinterrupt.S @@ -0,0 +1,130 @@ +#ifdef __riscv_flen +#define NREG 48 +#define LFREG flw +#define SFREG fsw +#else +#define NREG 16 +#endif + +#if __riscv_xlen==64 +#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 __riscv_flen + 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 __riscv_flen + 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/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/machine/board_k210.go b/src/machine/board_k210.go new file mode 100644 index 0000000000..2b934e5eca --- /dev/null +++ b/src/machine/board_k210.go @@ -0,0 +1,354 @@ +// +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. +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 +) + +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 new file mode 100644 index 0000000000..c1d002f36a --- /dev/null +++ b/src/machine/board_maixbit.go @@ -0,0 +1,72 @@ +// +build maixbit + +package machine + +// Pins on the MAix Bit. +const ( + 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 +) + +const ( + LED = LED1 + LED1 = LED_RED + LED2 = LED_GREEN + LED3 = LED_BLUE + LED_RED = D13 + LED_GREEN = D12 + LED_BLUE = D14 +) + +// Default pins for UARTHS. +const ( + UART_TX_PIN = D5 + UART_RX_PIN = D4 +) + +// SPI pins. +const ( + SPI0_SCK_PIN = D27 + 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 new file mode 100644 index 0000000000..3c75a4dfb1 --- /dev/null +++ b/src/machine/board_maixbit_baremetal.go @@ -0,0 +1,28 @@ +// +build k210,maixbit + +package machine + +import "device/kendryte" + +// SPI on the MAix Bit. +var ( + SPI0 = SPI{ + Bus: kendryte.SPI0, + } + SPI1 = SPI{ + 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 new file mode 100644 index 0000000000..caa1592baf --- /dev/null +++ b/src/machine/machine_k210.go @@ -0,0 +1,635 @@ +// +build k210 + +package machine + +import ( + "device/kendryte" + "device/riscv" + "errors" + "runtime/interrupt" +) + +func CPUFrequency() uint32 { + return 390000000 +} + +type PinMode uint8 +type fpioaPullMode uint8 +type PinChange uint8 + +// Pin modes. +const ( + PinInput PinMode = iota + PinInputPullUp + PinInputPullDown + PinOutput +) + +// FPIOA internal pull resistors. +const ( + fpioaPullNone fpioaPullMode = iota + fpioaPullDown + fpioaPullUp +) + +// GPIOHS pin interrupt events. +const ( + PinRising PinChange = 1 << iota + PinFalling + PinToggle = PinRising | PinFalling +) + +var ( + errUnsupportedSPIController = errors.New("SPI controller not supported. Use SPI0 or SPI1.") + errI2CTxAbort = errors.New("I2C transmition has been aborted.") +) + +func (p Pin) setFPIOAIOPull(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) + } +} + +// 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 + + // 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. + } + + // 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) + input = true + case PinInputPullUp: + p.setFPIOAIOPull(fpioaPullUp) + input = true + case PinInputPullDown: + p.setFPIOAIOPull(fpioaPullDown) + input = true + case PinOutput: + p.setFPIOAIOPull(fpioaPullNone) + input = false + } + + 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 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) + 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) { + + // 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 f >= FUNC_GPIOHS0 && f <= FUNC_GPIOHS31 { + gpioPin := uint8(f - FUNC_GPIOHS0) + + 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 { + + // 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 f >= FUNC_GPIO0 && f <= FUNC_GPIO7 { + gpioPin := uint8(f - FUNC_GPIO0) + val = kendryte.GPIO.DATA_INPUT.Get() & (1 << gpioPin) + } else if f >= FUNC_GPIOHS0 && f <= FUNC_GPIOHS31 { + gpioPin := uint8(f - FUNC_GPIOHS0) + val = kendryte.GPIOHS.INPUT_VAL.Get() & (1 << gpioPin) + } + 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. + f := p.FPIOAFunction() + if f < FUNC_GPIOHS0 || f > FUNC_GPIOHS31 { + return ErrInvalidDataPin + } + + gpioPin := uint8(f - FUNC_GPIOHS0) + + // 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) + } + + 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) + // 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) + // 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) + } + + pinCallbacks[pin](Pin(pin)) + } + + var ir interrupt.Interrupt + + switch f { + case FUNC_GPIOHS0: + ir = interrupt.New(kendryte.IRQ_GPIOHS0, handleInterrupt) + case FUNC_GPIOHS1: + ir = interrupt.New(kendryte.IRQ_GPIOHS1, handleInterrupt) + case FUNC_GPIOHS2: + ir = interrupt.New(kendryte.IRQ_GPIOHS2, handleInterrupt) + case FUNC_GPIOHS3: + ir = interrupt.New(kendryte.IRQ_GPIOHS3, handleInterrupt) + case FUNC_GPIOHS4: + ir = interrupt.New(kendryte.IRQ_GPIOHS4, handleInterrupt) + case FUNC_GPIOHS5: + ir = interrupt.New(kendryte.IRQ_GPIOHS5, handleInterrupt) + case FUNC_GPIOHS6: + ir = interrupt.New(kendryte.IRQ_GPIOHS6, handleInterrupt) + case FUNC_GPIOHS7: + ir = interrupt.New(kendryte.IRQ_GPIOHS7, handleInterrupt) + case FUNC_GPIOHS8: + ir = interrupt.New(kendryte.IRQ_GPIOHS8, handleInterrupt) + case FUNC_GPIOHS9: + ir = interrupt.New(kendryte.IRQ_GPIOHS9, handleInterrupt) + case FUNC_GPIOHS10: + ir = interrupt.New(kendryte.IRQ_GPIOHS10, handleInterrupt) + case FUNC_GPIOHS11: + ir = interrupt.New(kendryte.IRQ_GPIOHS11, handleInterrupt) + case FUNC_GPIOHS12: + ir = interrupt.New(kendryte.IRQ_GPIOHS12, handleInterrupt) + case FUNC_GPIOHS13: + ir = interrupt.New(kendryte.IRQ_GPIOHS13, handleInterrupt) + case FUNC_GPIOHS14: + ir = interrupt.New(kendryte.IRQ_GPIOHS14, handleInterrupt) + case FUNC_GPIOHS15: + ir = interrupt.New(kendryte.IRQ_GPIOHS15, handleInterrupt) + case FUNC_GPIOHS16: + ir = interrupt.New(kendryte.IRQ_GPIOHS16, handleInterrupt) + case FUNC_GPIOHS17: + ir = interrupt.New(kendryte.IRQ_GPIOHS17, handleInterrupt) + case FUNC_GPIOHS18: + ir = interrupt.New(kendryte.IRQ_GPIOHS18, handleInterrupt) + case FUNC_GPIOHS19: + ir = interrupt.New(kendryte.IRQ_GPIOHS19, handleInterrupt) + case FUNC_GPIOHS20: + ir = interrupt.New(kendryte.IRQ_GPIOHS20, handleInterrupt) + case FUNC_GPIOHS21: + ir = interrupt.New(kendryte.IRQ_GPIOHS21, handleInterrupt) + case FUNC_GPIOHS22: + ir = interrupt.New(kendryte.IRQ_GPIOHS22, handleInterrupt) + case FUNC_GPIOHS23: + ir = interrupt.New(kendryte.IRQ_GPIOHS23, handleInterrupt) + case FUNC_GPIOHS24: + ir = interrupt.New(kendryte.IRQ_GPIOHS24, handleInterrupt) + case FUNC_GPIOHS25: + ir = interrupt.New(kendryte.IRQ_GPIOHS25, handleInterrupt) + case FUNC_GPIOHS26: + ir = interrupt.New(kendryte.IRQ_GPIOHS26, handleInterrupt) + case FUNC_GPIOHS27: + ir = interrupt.New(kendryte.IRQ_GPIOHS27, handleInterrupt) + case FUNC_GPIOHS28: + ir = interrupt.New(kendryte.IRQ_GPIOHS28, handleInterrupt) + case FUNC_GPIOHS29: + ir = interrupt.New(kendryte.IRQ_GPIOHS29, handleInterrupt) + case FUNC_GPIOHS30: + ir = interrupt.New(kendryte.IRQ_GPIOHS30, handleInterrupt) + case FUNC_GPIOHS31: + ir = interrupt.New(kendryte.IRQ_GPIOHS31, handleInterrupt) + } + + ir.SetPriority(5) + ir.Enable() + + return nil + +} + +type UART struct { + Bus *kendryte.UARTHS_Type + Buffer *RingBuffer +} + +var ( + UART0 = UART{Bus: kendryte.UARTHS, Buffer: NewRingBuffer()} +) + +func (uart UART) Configure(config UARTConfig) { + + // 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) + uart.Bus.RXCTRL.Set(kendryte.UARTHS_RXCTRL_RXEN) + + // 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) { + 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)) +} + +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 APB2 clock. + kendryte.SYSCTL.CLK_EN_CENT.SetBits(kendryte.SYSCTL_CLK_EN_CENT_APB2_CLK_EN) + + switch spi.Bus { + case kendryte.SPI0: + // 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) + + // 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 + } + + // Set default frequency. + if config.Frequency == 0 { + config.Frequency = 500000 + } + + baudr := CPUFrequency() / config.Frequency + 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 +} + +// 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 := 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 +} 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 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/arch_tinygoriscv.go b/src/runtime/arch_tinygoriscv.go index 7aa34b50dc..3dcbcec255 100644 --- a/src/runtime/arch_tinygoriscv.go +++ b/src/runtime/arch_tinygoriscv.go @@ -4,16 +4,6 @@ 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 new file mode 100644 index 0000000000..a4a8c14f06 --- /dev/null +++ b/src/runtime/arch_tinygoriscv64.go @@ -0,0 +1,13 @@ +// +build tinygo.riscv64 + +package runtime + +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 +} diff --git a/src/runtime/interrupt/interrupt_k210.go b/src/runtime/interrupt/interrupt_k210.go new file mode 100644 index 0000000000..31e056c164 --- /dev/null +++ b/src/runtime/interrupt/interrupt_k210.go @@ -0,0 +1,27 @@ +// +build k210 + +package interrupt + +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() { + 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 +// 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)) +} + +// GetNumber returns the interrupt number for this interrupt. +func (irq Interrupt) GetNumber() int { + return irq.num +} diff --git a/src/runtime/runtime_k210.go b/src/runtime/runtime_k210.go new file mode 100644 index 0000000000..457a1e1773 --- /dev/null +++ b/src/runtime/runtime_k210.go @@ -0,0 +1,161 @@ +// +build k210 + +// This file implements target-specific things for the K210 chip as used in the +// MAix Bit with Mic. + +package runtime + +import ( + "device/kendryte" + "device/riscv" + "machine" + "runtime/volatile" + "unsafe" +) + +type timeUnit int64 + +func postinit() {} + +//export main +func main() { + + // Both harts should disable all interrupts on startup. + initPLIC() + + // Only use one hart for the moment. + 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) + } + + // 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() +} + +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 := 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 + // 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 + hartId := riscv.MHARTID.Get() + + // Claim this interrupt. + id := kendryte.PLIC.TARGETS[hartId].CLAIM.Get() + // Call the interrupt handler, if any is registered for this ID. + callInterruptHandler(int(id)) + // Complete this interrupt. + kendryte.PLIC.TARGETS[hartId].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() { + // 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) + + machine.UART0.Configure(machine.UARTConfig{}) +} + +func putchar(c byte) { + machine.UART0.WriteByte(c) +} + +const asyncScheduler = false + +var timerWakeup volatile.Register8 + +func ticks() timeUnit { + 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) { + 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. +// Exceptions can be things like illegal instructions, invalid memory +// read/write, and similar issues. +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=") + 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..0f9932496a --- /dev/null +++ b/src/runtime/runtime_k210_baremetal.go @@ -0,0 +1,28 @@ +// +build k210,!qemu + +package runtime + +import ( + "device/riscv" +) + +// ticksToNanoseconds converts CPU ticks to nanoseconds. +func ticksToNanoseconds(ticks timeUnit) int64 { + // 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 CPU ticks. +func nanosecondsToTicks(ns int64) timeUnit { + return timeUnit(ns * 39 / 5000) +} + +func abort() { + // lock up forever + for { + riscv.Asm("wfi") + } +} 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_tinygoriscv.S b/src/runtime/scheduler_tinygoriscv.S index 3766bae754..e0aeada5db 100644 --- a/src/runtime/scheduler_tinygoriscv.S +++ b/src/runtime/scheduler_tinygoriscv.S @@ -1,32 +1,42 @@ +#if __riscv_xlen==64 +#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/targets/k210.json b/targets/k210.json new file mode 100644 index 0000000000..5ddd9dbab9 --- /dev/null +++ b/targets/k210.json @@ -0,0 +1,5 @@ +{ + "inherits": ["riscv64"], + "features": ["+a", "+c", "+m", "+f", "+d"], + "build-tags": ["k210", "kendryte"] +} diff --git a/targets/maixbit.json b/targets/maixbit.json new file mode 100644 index 0000000000..8799fd2b21 --- /dev/null +++ b/targets/maixbit.json @@ -0,0 +1,6 @@ +{ + "inherits": ["k210"], + "build-tags": ["maixbit"], + "linkerscript": "targets/maixbit.ld", + "flash-command": "kflash -p {port} {bin}" +} diff --git a/targets/maixbit.ld b/targets/maixbit.ld new file mode 100644 index 0000000000..c2cffae98f --- /dev/null +++ b/targets/maixbit.ld @@ -0,0 +1,69 @@ + +MEMORY +{ + /* 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 +} + +_stack_size = 2K; + +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; diff --git a/targets/riscv.json b/targets/riscv.json index 313aa85811..da40416bf8 100644 --- a/targets/riscv.json +++ b/targets/riscv.json @@ -18,7 +18,8 @@ ], "extra-files": [ "src/device/riscv/start.S", - "src/runtime/scheduler_tinygoriscv.S" + "src/runtime/scheduler_tinygoriscv.S", + "src/device/riscv/handleinterrupt.S" ], "gdb": "riscv64-unknown-elf-gdb" } diff --git a/targets/riscv.ld b/targets/riscv.ld index 7f4427a8cf..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(4); + . = ALIGN(16); . += _stack_size; _stack_top = .; } >RAM diff --git a/targets/riscv32.json b/targets/riscv32.json index dc07c209c3..24f5cee906 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",