aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEthan Reesor <[email protected]>2020-01-21 21:23:10 -0600
committerRon Evans <[email protected]>2020-07-08 21:58:15 +0200
commit079a789d492431cff100824421aa276a731ac369 (patch)
tree3a0b9f4dbd16e4b45cacd3fc99d7b3f8e1046eac
parentca8e1b075a0445f2ca72dfefd6db517c1b0cfec0 (diff)
downloadtinygo-079a789d492431cff100824421aa276a731ac369.tar.gz
tinygo-079a789d492431cff100824421aa276a731ac369.zip
Minimal NXP/Teensy support
-rw-r--r--.gitignore2
-rw-r--r--Makefile8
-rw-r--r--README.md2
-rw-r--r--src/machine/board_teensy36.go39
-rw-r--r--src/machine/machine_nxp.go33
-rw-r--r--src/machine/machine_nxpmk66f18.go56
-rw-r--r--src/runtime/runtime_nxp.go5
-rw-r--r--src/runtime/runtime_nxpmk66f18.go342
-rw-r--r--src/runtime/volatile/register_nxpmk66f18.go84
-rw-r--r--targets/nxpmk66f18.ld94
-rw-r--r--targets/teensy36.json18
-rwxr-xr-xtools/gen-device-svd/gen-device-svd.go79
12 files changed, 754 insertions, 8 deletions
diff --git a/.gitignore b/.gitignore
index 84f90ddbc..760bbf0a1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,8 @@ src/device/avr/*.ld
src/device/avr/*.s
src/device/nrf/*.go
src/device/nrf/*.s
+src/device/nxp/*.go
+src/device/nxp/*.s
src/device/sam/*.go
src/device/sam/*.s
src/device/sifive/*.go
diff --git a/Makefile b/Makefile
index 5a1fd02c4..0e033dfbc 100644
--- a/Makefile
+++ b/Makefile
@@ -51,7 +51,7 @@ else
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=OFF'
endif
-.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-avr
+.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-nxp gen-device-avr
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf executionengine frontendopenmp instrumentation interpreter ipo irreader linker lto mc mcjit objcarcopts option profiledata scalaropts support target
@@ -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-kendryte
+gen-device: gen-device-avr gen-device-nrf gen-device-sam gen-device-sifive gen-device-stm32 gen-device-kendryte gen-device-nxp
gen-device-avr:
$(GO) build -o ./build/gen-device-avr ./tools/gen-device-avr/
@@ -133,6 +133,10 @@ gen-device-nrf: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/NordicSemiconductor/nrfx/tree/master/mdk lib/nrfx/mdk/ src/device/nrf/
GO111MODULE=off $(GO) fmt ./src/device/nrf
+gen-device-nxp: build/gen-device-svd
+ ./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/NXP lib/cmsis-svd/data/NXP/ src/device/nxp/
+ GO111MODULE=off $(GO) fmt ./src/device/nxp
+
gen-device-sam: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Atmel lib/cmsis-svd/data/Atmel/ src/device/sam/
GO111MODULE=off $(GO) fmt ./src/device/sam
diff --git a/README.md b/README.md
index 1c8ab784f..24231630e 100644
--- a/README.md
+++ b/README.md
@@ -140,3 +140,5 @@ The original reasoning was: if [Python](https://micropython.org/) can run on mic
This project is licensed under the BSD 3-clause license, just like the [Go project](https://golang.org/LICENSE) itself.
Some code has been copied from the LLVM project and is therefore licensed under [a variant of the Apache 2.0 license](http://releases.llvm.org/10.0.0/LICENSE.TXT). This has been clearly indicated in the header of these files.
+
+Some code has been copied and/or ported from Paul Stoffregen's Teensy libraries and is therefore licensed under PJRC's license. This has been clearly indicated in the header of these files.
diff --git a/src/machine/board_teensy36.go b/src/machine/board_teensy36.go
new file mode 100644
index 000000000..1b78677b1
--- /dev/null
+++ b/src/machine/board_teensy36.go
@@ -0,0 +1,39 @@
+// +build nxp,mk66f18,teensy36
+
+package machine
+
+import (
+ "device/nxp"
+)
+
+//go:keep
+//go:section .flashconfig
+var FlashConfig = [16]byte{
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xF9, 0xFF, 0xFF,
+}
+
+func CPUFrequency() uint32 {
+ return 180000000
+}
+
+// LED on the Teensy
+const LED Pin = 13
+
+var _pinRegisters [64]pinRegisters
+
+func init() {
+ _pinRegisters[13].Bit = 5
+ _pinRegisters[13].PCR = &nxp.PORTC.PCR5
+ _pinRegisters[13].PDOR = nxp.GPIOC.PDOR.Bit(5)
+ _pinRegisters[13].PSOR = nxp.GPIOC.PSOR.Bit(5)
+ _pinRegisters[13].PCOR = nxp.GPIOC.PCOR.Bit(5)
+ _pinRegisters[13].PTOR = nxp.GPIOC.PTOR.Bit(5)
+ _pinRegisters[13].PDIR = nxp.GPIOC.PDIR.Bit(5)
+ _pinRegisters[13].PDDR = nxp.GPIOC.PDDR.Bit(5)
+}
+
+//go:inline
+func (p Pin) registers() pinRegisters {
+ return _pinRegisters[p]
+}
diff --git a/src/machine/machine_nxp.go b/src/machine/machine_nxp.go
new file mode 100644
index 000000000..b29d4328c
--- /dev/null
+++ b/src/machine/machine_nxp.go
@@ -0,0 +1,33 @@
+// +build nxp
+
+package machine
+
+import (
+ "device/arm"
+ "device/nxp"
+)
+
+type PinMode uint8
+
+const (
+ PinInput PinMode = iota
+ PinOutput
+)
+
+// Stop enters STOP (deep sleep) mode
+func Stop() {
+ // set SLEEPDEEP to enable deep sleep
+ nxp.SystemControl.SCR.SetBits(nxp.SystemControl_SCR_SLEEPDEEP)
+
+ // enter STOP mode
+ arm.Asm("wfi")
+}
+
+// Wait enters WAIT (sleep) mode
+func Wait() {
+ // clear SLEEPDEEP bit to disable deep sleep
+ nxp.SystemControl.SCR.ClearBits(nxp.SystemControl_SCR_SLEEPDEEP)
+
+ // enter WAIT mode
+ arm.Asm("wfi")
+}
diff --git a/src/machine/machine_nxpmk66f18.go b/src/machine/machine_nxpmk66f18.go
new file mode 100644
index 000000000..ab15ed136
--- /dev/null
+++ b/src/machine/machine_nxpmk66f18.go
@@ -0,0 +1,56 @@
+// +build nxp,mk66f18
+
+package machine
+
+import (
+ "device/nxp"
+ "runtime/volatile"
+)
+
+const (
+ PortControlRegisterSRE = nxp.PORT_PCR0_SRE
+ PortControlRegisterDSE = nxp.PORT_PCR0_DSE
+ PortControlRegisterODE = nxp.PORT_PCR0_ODE
+)
+
+func PortControlRegisterMUX(v uint8) uint32 {
+ return (uint32(v) << nxp.PORT_PCR0_MUX_Pos) & nxp.PORT_PCR0_MUX_Msk
+}
+
+type pinRegisters struct {
+ Bit uintptr
+ PCR *volatile.Register32
+ PDOR *volatile.BitRegister
+ PSOR *volatile.BitRegister
+ PCOR *volatile.BitRegister
+ PTOR *volatile.BitRegister
+ PDIR *volatile.BitRegister
+ PDDR *volatile.BitRegister
+}
+
+// Configure this pin with the given configuration.
+func (p Pin) Configure(config PinConfig) {
+ switch config.Mode {
+ case PinInput:
+ panic("todo")
+
+ case PinOutput:
+ p.registers().PDDR.Set()
+ p.registers().PCR.SetBits(PortControlRegisterSRE | PortControlRegisterDSE | PortControlRegisterMUX(1))
+ p.registers().PCR.ClearBits(PortControlRegisterODE)
+ }
+}
+
+// Set changes the value of the GPIO pin. The pin must be configured as output.
+func (p Pin) Set(value bool) {
+ if value {
+ p.registers().PSOR.Set()
+ } else {
+ p.registers().PCOR.Set()
+ }
+}
+
+// Get returns the current value of a GPIO pin.
+func (p Pin) Get() bool {
+ return p.registers().PDIR.Get()
+}
diff --git a/src/runtime/runtime_nxp.go b/src/runtime/runtime_nxp.go
new file mode 100644
index 000000000..08f6635c4
--- /dev/null
+++ b/src/runtime/runtime_nxp.go
@@ -0,0 +1,5 @@
+// +build nxp
+
+package runtime
+
+type timeUnit int64
diff --git a/src/runtime/runtime_nxpmk66f18.go b/src/runtime/runtime_nxpmk66f18.go
new file mode 100644
index 000000000..99617a402
--- /dev/null
+++ b/src/runtime/runtime_nxpmk66f18.go
@@ -0,0 +1,342 @@
+// Derivative work of Teensyduino Core Library
+// http://www.pjrc.com/teensy/
+// Copyright (c) 2017 PJRC.COM, LLC.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// 1. The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// 2. If the Software is incorporated into a build system that allows
+// selection among a list of target devices, then similar target
+// devices manufactured by PJRC.COM must be included in the list of
+// target devices and selectable in the same manner.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+// +build nxp,mk66f18
+
+package runtime
+
+import (
+ "device/arm"
+ "device/nxp"
+ "machine"
+ "runtime/volatile"
+)
+
+const (
+ WDOG_UNLOCK_SEQ1 = 0xC520
+ WDOG_UNLOCK_SEQ2 = 0xD928
+
+ DEFAULT_FTM_MOD = 61440 - 1
+ DEFAULT_FTM_PRESCALE = 1
+)
+
+var (
+ SIM_SOPT2_IRC48SEL = nxp.SIM_SOPT2_PLLFLLSEL(3)
+ SMC_PMCTRL_HSRUN = nxp.SMC_PMCTRL_RUNM(3)
+ SMC_PMSTAT_HSRUN = nxp.SMC_PMSTAT_PMSTAT(0x80)
+)
+
+//go:section .resetHandler
+//go:export Reset_Handler
+func main() {
+ nxp.WDOG.UNLOCK.Set(WDOG_UNLOCK_SEQ1)
+ nxp.WDOG.UNLOCK.Set(WDOG_UNLOCK_SEQ2)
+ arm.Asm("nop")
+ arm.Asm("nop")
+ startupEarlyHook()
+
+ // enable clocks to always-used peripherals
+ nxp.SIM.SCGC3.Set(nxp.SIM_SCGC3_ADC1 | nxp.SIM_SCGC3_FTM2 | nxp.SIM_SCGC3_FTM3)
+ nxp.SIM.SCGC5.Set(0x00043F82) // clocks active to all GPIO
+ nxp.SIM.SCGC6.Set(nxp.SIM_SCGC6_RTC | nxp.SIM_SCGC6_FTM0 | nxp.SIM_SCGC6_FTM1 | nxp.SIM_SCGC6_ADC0 | nxp.SIM_SCGC6_FTF)
+ nxp.SystemControl.CPACR.Set(0x00F00000)
+ nxp.LMEM.PCCCR.Set(0x85000003)
+
+ // release I/O pins hold, if we woke up from VLLS mode
+ if nxp.PMC.REGSC.HasBits(nxp.PMC_REGSC_ACKISO) {
+ nxp.PMC.REGSC.SetBits(nxp.PMC_REGSC_ACKISO)
+ }
+
+ // since this is a write once register, make it visible to all F_CPU's
+ // so we can into other sleep modes in the future at any speed
+ nxp.SMC.PMPROT.Set(nxp.SMC_PMPROT_AHSRUN | nxp.SMC_PMPROT_AVLP | nxp.SMC_PMPROT_ALLS | nxp.SMC_PMPROT_AVLLS)
+
+ preinit()
+
+ // copy the vector table to RAM default all interrupts to medium priority level
+ // for (i=0; i < NVIC_NUM_INTERRUPTS + 16; i++) _VectorsRam[i] = _VectorsFlash[i];
+ for i := uint32(0); i <= nxp.IRQ_max; i++ {
+ arm.SetPriority(i, 128)
+ }
+ // SCB_VTOR = (uint32_t)_VectorsRam; // use vector table in RAM
+
+ // hardware always starts in FEI mode
+ // C1[CLKS] bits are written to 00
+ // C1[IREFS] bit is written to 1
+ // C6[PLLS] bit is written to 0
+ // MCG_SC[FCDIV] defaults to divide by two for internal ref clock
+ // I tried changing MSG_SC to divide by 1, it didn't work for me
+ // enable capacitors for crystal
+ nxp.OSC.CR.Set(nxp.OSC_CR_SC8P | nxp.OSC_CR_SC2P | nxp.OSC_CR_ERCLKEN)
+ // enable osc, 8-32 MHz range, low power mode
+ nxp.MCG.C2.Set(uint8(nxp.MCG_C2_RANGE(2) | nxp.MCG_C2_EREFS))
+ // switch to crystal as clock source, FLL input = 16 MHz / 512
+ nxp.MCG.C1.Set(uint8(nxp.MCG_C1_CLKS(2) | nxp.MCG_C1_FRDIV(4)))
+ // wait for crystal oscillator to begin
+ for !nxp.MCG.S.HasBits(nxp.MCG_S_OSCINIT0) {
+ }
+ // wait for FLL to use oscillator
+ for nxp.MCG.S.HasBits(nxp.MCG_S_IREFST) {
+ }
+ // wait for MCGOUT to use oscillator
+ for (nxp.MCG.S.Get() & nxp.MCG_S_CLKST_Msk) != nxp.MCG_S_CLKST(2) {
+ }
+
+ // now in FBE mode
+ // C1[CLKS] bits are written to 10
+ // C1[IREFS] bit is written to 0
+ // C1[FRDIV] must be written to divide xtal to 31.25-39 kHz
+ // C6[PLLS] bit is written to 0
+ // C2[LP] is written to 0
+ // we need faster than the crystal, turn on the PLL (F_CPU > 120000000)
+ nxp.SMC.PMCTRL.Set(SMC_PMCTRL_HSRUN) // enter HSRUN mode
+ for nxp.SMC.PMSTAT.Get() != SMC_PMSTAT_HSRUN {
+ } // wait for HSRUN
+ nxp.MCG.C5.Set(nxp.MCG_C5_PRDIV(1))
+ nxp.MCG.C6.Set(nxp.MCG_C6_PLLS | nxp.MCG_C6_VDIV(29))
+
+ // wait for PLL to start using xtal as its input
+ for !nxp.MCG.S.HasBits(nxp.MCG_S_PLLST) {
+ }
+ // wait for PLL to lock
+ for !nxp.MCG.S.HasBits(nxp.MCG_S_LOCK0) {
+ }
+ // now we're in PBE mode
+
+ // now program the clock dividers
+ // config divisors: 180 MHz core, 60 MHz bus, 25.7 MHz flash, USB = IRC48M
+ nxp.SIM.CLKDIV1.Set(nxp.SIM_CLKDIV1_OUTDIV1(0) | nxp.SIM_CLKDIV1_OUTDIV2(2) | nxp.SIM_CLKDIV1_OUTDIV4(6))
+ nxp.SIM.CLKDIV2.Set(nxp.SIM_CLKDIV2_USBDIV(0))
+
+ // switch to PLL as clock source, FLL input = 16 MHz / 512
+ nxp.MCG.C1.Set(nxp.MCG_C1_CLKS(0) | nxp.MCG_C1_FRDIV(4))
+ // wait for PLL clock to be used
+ for (nxp.MCG.S.Get() & nxp.MCG_S_CLKST_Msk) != nxp.MCG_S_CLKST(3) {
+ }
+ // now we're in PEE mode
+ // trace is CPU clock, CLKOUT=OSCERCLK0
+ // USB uses IRC48
+ nxp.SIM.SOPT2.Set(nxp.SIM_SOPT2_USBSRC | SIM_SOPT2_IRC48SEL | nxp.SIM_SOPT2_TRACECLKSEL | nxp.SIM_SOPT2_CLKOUTSEL(6))
+
+ // If the RTC oscillator isn't enabled, get it started. For Teensy 3.6
+ // we don't do this early. See comment above about slow rising power.
+ if !nxp.RTC.CR.HasBits(nxp.RTC_CR_OSCE) {
+ nxp.RTC.SR.Set(0)
+ nxp.RTC.CR.Set(nxp.RTC_CR_SC16P | nxp.RTC_CR_SC4P | nxp.RTC_CR_OSCE)
+ }
+
+ // initialize the SysTick counter
+ nxp.SysTick.RVR.Set((machine.CPUFrequency() / 1000) - 1)
+ nxp.SysTick.CVR.Set(0)
+ nxp.SysTick.CSR.Set(nxp.SysTick_CSR_CLKSOURCE | nxp.SysTick_CSR_TICKINT | nxp.SysTick_CSR_ENABLE)
+ nxp.SystemControl.SHPR3.Set(0x20200000) // Systick = priority 32
+
+ arm.Asm("CPSIE i")
+ initTeensyInternal()
+ startupLateHook()
+
+ // initAll()
+ runMain()
+ // abort()
+
+ for {
+
+ }
+}
+
+// ported _init_Teensyduino_internal_ from pins_teensy.c from teensy3 core libraries
+func initTeensyInternal() {
+ arm.EnableIRQ(nxp.IRQ_PORTA)
+ arm.EnableIRQ(nxp.IRQ_PORTB)
+ arm.EnableIRQ(nxp.IRQ_PORTC)
+ arm.EnableIRQ(nxp.IRQ_PORTD)
+ arm.EnableIRQ(nxp.IRQ_PORTE)
+
+ nxp.FTM0.CNT.Set(0)
+ nxp.FTM0.MOD.Set(DEFAULT_FTM_MOD)
+ nxp.FTM0.C0SC.Set(0x28) // MSnB:MSnA = 10, ELSnB:ELSnA = 10
+ nxp.FTM0.C1SC.Set(0x28)
+ nxp.FTM0.C2SC.Set(0x28)
+ nxp.FTM0.C3SC.Set(0x28)
+ nxp.FTM0.C4SC.Set(0x28)
+ nxp.FTM0.C5SC.Set(0x28)
+ nxp.FTM0.C6SC.Set(0x28)
+ nxp.FTM0.C7SC.Set(0x28)
+
+ nxp.FTM3.C0SC.Set(0x28)
+ nxp.FTM3.C1SC.Set(0x28)
+ nxp.FTM3.C2SC.Set(0x28)
+ nxp.FTM3.C3SC.Set(0x28)
+ nxp.FTM3.C4SC.Set(0x28)
+ nxp.FTM3.C5SC.Set(0x28)
+ nxp.FTM3.C6SC.Set(0x28)
+ nxp.FTM3.C7SC.Set(0x28)
+
+ nxp.FTM0.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(DEFAULT_FTM_PRESCALE))
+ nxp.FTM1.CNT.Set(0)
+ nxp.FTM1.MOD.Set(DEFAULT_FTM_MOD)
+ nxp.FTM1.C0SC.Set(0x28)
+ nxp.FTM1.C1SC.Set(0x28)
+ nxp.FTM1.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(DEFAULT_FTM_PRESCALE))
+
+ // nxp.FTM2.CNT.Set(0)
+ // nxp.FTM2.MOD.Set(DEFAULT_FTM_MOD)
+ // nxp.FTM2.C0SC.Set(0x28)
+ // nxp.FTM2.C1SC.Set(0x28)
+ // nxp.FTM2.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(DEFAULT_FTM_PRESCALE))
+
+ nxp.FTM3.CNT.Set(0)
+ nxp.FTM3.MOD.Set(DEFAULT_FTM_MOD)
+ nxp.FTM3.C0SC.Set(0x28)
+ nxp.FTM3.C1SC.Set(0x28)
+ nxp.FTM3.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(DEFAULT_FTM_PRESCALE))
+
+ nxp.SIM.SCGC2.SetBits(nxp.SIM_SCGC2_TPM1)
+ nxp.SIM.SOPT2.SetBits(nxp.SIM_SOPT2_TPMSRC(2))
+ nxp.TPM1.CNT.Set(0)
+ nxp.TPM1.MOD.Set(32767)
+ nxp.TPM1.C0SC.Set(0x28)
+ nxp.TPM1.C1SC.Set(0x28)
+ nxp.TPM1.SC.Set(nxp.FTM_SC_CLKS(1) | nxp.FTM_SC_PS(0))
+
+ // analog_init();
+
+ // #if !defined(TEENSY_INIT_USB_DELAY_BEFORE)
+ // #if TEENSYDUINO >= 142
+ // #define TEENSY_INIT_USB_DELAY_BEFORE 25
+ // #else
+ // #define TEENSY_INIT_USB_DELAY_BEFORE 50
+ // #endif
+ // #endif
+
+ // #if !defined(TEENSY_INIT_USB_DELAY_AFTER)
+ // #if TEENSYDUINO >= 142
+ // #define TEENSY_INIT_USB_DELAY_AFTER 275
+ // #else
+ // #define TEENSY_INIT_USB_DELAY_AFTER 350
+ // #endif
+ // #endif
+
+ // // for background about this startup delay, please see these conversations
+ // // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
+ // // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
+
+ // delay(TEENSY_INIT_USB_DELAY_BEFORE);
+ // usb_init();
+ // delay(TEENSY_INIT_USB_DELAY_AFTER);
+}
+
+func startupEarlyHook() {
+ // TODO allow override
+ // > programs using the watchdog timer or needing to initialize hardware as
+ // > early as possible can implement startup_early_hook()
+
+ nxp.WDOG.STCTRLH.Set(nxp.WDOG_STCTRLH_ALLOWUPDATE)
+}
+
+func startupLateHook() {
+ // TODO allow override
+}
+
+//go:noinline
+func runMain() {
+ // this is a separate function to ensure that Reset_Handler fits in 0x230 bytes regardless of whether (user) main requires scheduling
+ callMain()
+}
+
+func putchar(c byte) {
+}
+
+// ???
+const asyncScheduler = false
+
+// microseconds per tick
+const tickMicros = 1000
+
+// number of ticks since boot
+var tickMilliCount uint32
+
+//go:export SysTick_Handler
+func tickHandler() {
+ volatile.StoreUint32(&tickMilliCount, volatile.LoadUint32(&tickMilliCount)+1)
+}
+
+// ticks are in microseconds
+func ticks() timeUnit {
+ m := arm.DisableInterrupts()
+ current := nxp.SysTick.CVR.Get()
+ count := tickMilliCount
+ istatus := nxp.SystemControl.ICSR.Get()
+ arm.EnableInterrupts(m)
+
+ if istatus&nxp.SystemControl_ICSR_PENDSTSET != 0 && current > 50 {
+ count++
+ }
+
+ current = ((machine.CPUFrequency() / tickMicros) - 1) - current
+ return timeUnit(count*tickMicros + current/(machine.CPUFrequency()/1000000))
+}
+
+// sleepTicks spins for a number of microseconds
+func sleepTicks(d timeUnit) {
+ // TODO actually sleep
+
+ if d <= 0 {
+ return
+ }
+
+ start := ticks()
+ ms := d / 1000
+
+ for {
+ for ticks()-start >= 1000 {
+ ms--
+ if ms <= 0 {
+ return
+ }
+ start += 1000
+ }
+ // Gosched()
+ }
+}
+
+func Sleep(d int64) {
+ sleepTicks(timeUnit(d))
+}
+
+// func abort() {
+// for {
+// // keep polling some communication while in fault
+// // mode, so we don't completely die.
+// if nxp.SIM.SCGC4.HasBits(nxp.SIM_SCGC4_USBOTG) usb_isr();
+// if nxp.SIM.SCGC4.HasBits(nxp.SIM_SCGC4_UART0) uart0_status_isr();
+// if nxp.SIM.SCGC4.HasBits(nxp.SIM_SCGC4_UART1) uart1_status_isr();
+// if nxp.SIM.SCGC4.HasBits(nxp.SIM_SCGC4_UART2) uart2_status_isr();
+// }
+// }
diff --git a/src/runtime/volatile/register_nxpmk66f18.go b/src/runtime/volatile/register_nxpmk66f18.go
new file mode 100644
index 000000000..272205a4d
--- /dev/null
+++ b/src/runtime/volatile/register_nxpmk66f18.go
@@ -0,0 +1,84 @@
+// +build nxp,mk66f18
+
+package volatile
+
+import "unsafe"
+
+const registerBase = 0x40000000
+const registerEnd = 0x40100000
+const bitbandBase = 0x42000000
+const ptrBytes = unsafe.Sizeof(uintptr(0))
+
+//go:inline
+func bitbandAddress(reg uintptr, bit uintptr) uintptr {
+ if bit > ptrBytes*8 {
+ panic("invalid bit position")
+ }
+ if reg < registerBase || reg >= registerEnd {
+ panic("register is out of range")
+ }
+ return (reg-registerBase)*ptrBytes*8 + bit*ptrBytes + bitbandBase
+}
+
+// Special types that causes loads/stores to be volatile (necessary for
+// memory-mapped registers).
+type BitRegister struct {
+ Reg uint32
+}
+
+// Get returns the of the mapped register bit. It is the volatile equivalent of:
+//
+// *r.Reg
+//
+//go:inline
+func (r *BitRegister) Get() bool {
+ return LoadUint32(&r.Reg) != 0
+}
+
+// Set sets the mapped register bit. It is the volatile equivalent of:
+//
+// *r.Reg = 1
+//
+//go:inline
+func (r *BitRegister) Set() {
+ StoreUint32(&r.Reg, 1)
+}
+
+// Clear clears the mapped register bit. It is the volatile equivalent of:
+//
+// *r.Reg = 0
+//
+//go:inline
+func (r *BitRegister) Clear() {
+ StoreUint32(&r.Reg, 0)
+}
+
+// Bit maps bit N of register R to the corresponding bitband address. Bit panics
+// if R is not an AIPS or GPIO register or if N is out of range (greater than
+// the number of bits in a register minus one).
+//
+// go:inline
+func (r *Register8) Bit(bit uintptr) *BitRegister {
+ ptr := bitbandAddress(uintptr(unsafe.Pointer(&r.Reg)), bit)
+ return (*BitRegister)(unsafe.Pointer(ptr))
+}
+
+// Bit maps bit N of register R to the corresponding bitband address. Bit panics
+// if R is not an AIPS or GPIO register or if N is out of range (greater than
+// the number of bits in a register minus one).
+//
+// go:inline
+func (r *Register16) Bit(bit uintptr) *BitRegister {
+ ptr := bitbandAddress(uintptr(unsafe.Pointer(&r.Reg)), bit)
+ return (*BitRegister)(unsafe.Pointer(ptr))
+}
+
+// Bit maps bit N of register R to the corresponding bitband address. Bit panics
+// if R is not an AIPS or GPIO register or if N is out of range (greater than
+// the number of bits in a register minus one).
+//
+// go:inline
+func (r *Register32) Bit(bit uintptr) *BitRegister {
+ ptr := bitbandAddress(uintptr(unsafe.Pointer(&r.Reg)), bit)
+ return (*BitRegister)(unsafe.Pointer(ptr))
+}
diff --git a/targets/nxpmk66f18.ld b/targets/nxpmk66f18.ld
new file mode 100644
index 000000000..74e22761f
--- /dev/null
+++ b/targets/nxpmk66f18.ld
@@ -0,0 +1,94 @@
+
+/* Unused, but here to silence a linker warning. */
+ENTRY(Reset_Handler)
+
+/* define memory layout */
+MEMORY
+{
+ FLASH_TEXT (rx) : ORIGIN = 0x00000000, LENGTH = 1024K
+ RAM (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 256K
+}
+
+_stack_size = 2K;
+
+/* define output sections */
+SECTIONS
+{
+ /* Program code and read-only data goes to FLASH_TEXT. */
+ .text :
+ {
+ /* vector table MUST start at 0x0 */
+ . = 0;
+ _vector_table = .;
+ KEEP(*(.isr_vector))
+
+ /* this works as long as reset handler doesn't overflow past 0x400 */
+ *(.resetHandler)
+
+ /* flash configuration MUST be at 0x400 */
+ . = 0x400;
+ KEEP(*(.flashconfig))
+
+ /* everything else */
+ *(.text)
+ *(.text*)
+ *(.rodata)
+ *(.rodata*)
+ . = ALIGN(4);
+ } >FLASH_TEXT = 0xFF
+
+ /* Put the stack at the bottom of RAM, so that the application will
+ * crash on stack overflow instead of silently corrupting memory.
+ * See: http://blog.japaric.io/stack-overflow-protection/ */
+ .stack (NOLOAD) :
+ {
+ . = ALIGN(4);
+ . += _stack_size;
+ _stack_top = .;
+ } >RAM
+
+ /* Start address (in flash) of .data, used by startup code. */
+ _sidata = LOADADDR(.data);
+
+ /* todo add .usbdescriptortable .dmabuffers .usbbuffers */
+
+ /* Globals with initial value */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* used by startup code */
+ *(.data)
+ *(.data*)
+ . = ALIGN(4);
+ _edata = .; /* used by startup code */
+ } >RAM AT>FLASH_TEXT
+
+ /* Zero-initialized globals */
+ .bss :
+ {
+ . = ALIGN(4);
+ _sbss = .; /* used by startup code */
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .; /* used by startup code */
+ } >RAM
+
+ /DISCARD/ :
+ {
+ *(.ARM.exidx) /* causes 'no memory region specified' error in lld */
+ *(.ARM.exidx.*) /* causes spurious 'undefined reference' errors */
+
+ /* all this makes it much harder to debug via disassembly */
+ *(.debug*)
+ *(.ARM.*)
+ *(.comment*)
+ }
+}
+
+/* For the memory allocator. */
+_heap_start = _ebss;
+_heap_end = ORIGIN(RAM) + LENGTH(RAM);
+_globals_start = _sdata;
+_globals_end = _ebss;
diff --git a/targets/teensy36.json b/targets/teensy36.json
new file mode 100644
index 000000000..fecd3c357
--- /dev/null
+++ b/targets/teensy36.json
@@ -0,0 +1,18 @@
+{
+ "inherits": ["cortex-m"],
+ "llvm-target": "armv7em-none-eabi",
+ "cpu": "cortex-m4",
+ "build-tags": ["teensy36", "teensy", "mk66f18", "nxp"],
+ "cflags": [
+ "--target=armv7em-none-eabi",
+ "-Qunused-arguments",
+ "-mfloat-abi=hard",
+ "-mfpu=fpv4-sp-d16"
+ ],
+ "linkerscript": "targets/nxpmk66f18.ld",
+ "extra-files": [
+ "src/device/nxp/mk66f18.s"
+ ],
+ "flash-command": "teensy_loader_cli -mmcu=mk66fx1m0 -v -w {hex}"
+}
+
diff --git a/tools/gen-device-svd/gen-device-svd.go b/tools/gen-device-svd/gen-device-svd.go
index f376a6932..ee1a86bbb 100755
--- a/tools/gen-device-svd/gen-device-svd.go
+++ b/tools/gen-device-svd/gen-device-svd.go
@@ -16,6 +16,7 @@ import (
)
var validName = regexp.MustCompile("^[a-zA-Z0-9_]+$")
+var enumBitSpecifier = regexp.MustCompile("^#[x01]+$")
type SVDFile struct {
XMLName xml.Name `xml:"device"`
@@ -41,6 +42,7 @@ type SVDRegister struct {
Name string `xml:"name"`
Description string `xml:"description"`
Dim *string `xml:"dim"`
+ DimIndex *string `xml:"dimIndex"`
DimIncrement string `xml:"dimIncrement"`
Size *string `xml:"size"`
Fields []*SVDField `xml:"fields>field"`
@@ -484,13 +486,24 @@ func parseBitfields(groupName, regName string, fieldEls []*SVDField, bitfieldPre
}
for _, enumEl := range fieldEl.EnumeratedValues {
enumName := enumEl.Name
+ if strings.EqualFold(enumName, "reserved") || !validName.MatchString(enumName) {
+ continue
+ }
if !unicode.IsUpper(rune(enumName[0])) && !unicode.IsDigit(rune(enumName[0])) {
enumName = strings.ToUpper(enumName)
}
enumDescription := strings.Replace(enumEl.Description, "\n", " ", -1)
enumValue, err := strconv.ParseUint(enumEl.Value, 0, 32)
if err != nil {
- panic(err)
+ if enumBitSpecifier.MatchString(enumEl.Value) {
+ // NXP SVDs use the form #xx1x, #x0xx, etc for values
+ enumValue, err = strconv.ParseUint(strings.Replace(enumEl.Value[1:], "x", "0", -1), 2, 32)
+ if err != nil {
+ panic(err)
+ }
+ } else {
+ panic(err)
+ }
}
fields = append(fields, Bitfield{
name: fmt.Sprintf("%s_%s%s_%s_%s", groupName, bitfieldPrefix, regName, fieldName, enumName),
@@ -545,6 +558,59 @@ func (r *Register) dim() int {
return int(dim)
}
+func (r *Register) dimIndex() []string {
+ defer func() {
+ if err := recover(); err != nil {
+ fmt.Println("register", r.name())
+ panic(err)
+ }
+ }()
+
+ dim := r.dim()
+ if r.element.DimIndex == nil {
+ if dim <= 0 {
+ return nil
+ }
+
+ idx := make([]string, dim)
+ for i := range idx {
+ idx[i] = strconv.FormatInt(int64(i), 10)
+ }
+ return idx
+ }
+
+ t := strings.Split(*r.element.DimIndex, "-")
+ if len(t) == 2 {
+ x, err := strconv.ParseInt(t[0], 0, 32)
+ if err != nil {
+ panic(err)
+ }
+ y, err := strconv.ParseInt(t[1], 0, 32)
+ if err != nil {
+ panic(err)
+ }
+
+ if x < 0 || y < x || y-x != int64(dim-1) {
+ panic("invalid dimIndex")
+ }
+
+ idx := make([]string, dim)
+ for i := x; i <= y; i++ {
+ idx[i-x] = strconv.FormatInt(i, 10)
+ }
+ return idx
+ } else if len(t) > 2 {
+ panic("invalid dimIndex")
+ }
+
+ s := strings.Split(*r.element.DimIndex, ",")
+ if len(s) != dim {
+ panic("invalid dimIndex")
+ }
+
+ return s
+}
+
func (r *Register) size() int {
if r.element.Size != nil {
size, err := strconv.ParseInt(*r.element.Size, 0, 32)
@@ -568,10 +634,10 @@ func parseRegister(groupName string, regEl *SVDRegister, baseAddress uint64, bit
// a "spaced array" of registers, special processing required
// we need to generate a separate register for each "element"
var results []*PeripheralField
- for i := uint64(0); i < uint64(reg.dim()); i++ {
- regAddress := reg.address() + (i * dimIncrement)
+ for i, j := range reg.dimIndex() {
+ regAddress := reg.address() + (uint64(i) * dimIncrement)
results = append(results, &PeripheralField{
- name: strings.ToUpper(strings.Replace(reg.name(), "%s", strconv.FormatUint(i, 10), -1)),
+ name: strings.ToUpper(strings.Replace(reg.name(), "%s", j, -1)),
address: regAddress,
description: reg.description(),
array: -1,
@@ -589,11 +655,12 @@ func parseRegister(groupName string, regEl *SVDRegister, baseAddress uint64, bit
regName = strings.ToUpper(regName)
}
+ bitfields := parseBitfields(groupName, regName, regEl.Fields, bitfieldPrefix)
return []*PeripheralField{&PeripheralField{
name: regName,
address: reg.address(),
description: reg.description(),
- bitfields: parseBitfields(groupName, regName, regEl.Fields, bitfieldPrefix),
+ bitfields: bitfields,
array: reg.dim(),
elementSize: reg.size(),
}}
@@ -770,7 +837,7 @@ var (
if register.array != -1 {
regType = fmt.Sprintf("[%d]%s", register.array, regType)
}
- fmt.Fprintf(w, "\t%s %s\n", register.name, regType)
+ fmt.Fprintf(w, "\t%s %s // 0x%X\n", register.name, regType, register.address-peripheral.BaseAddress)
// next address
if lastCluster {