altos: Start work on stm32f1 support
authorKeith Packard <keithp@keithp.com>
Sat, 18 Feb 2023 07:02:16 +0000 (23:02 -0800)
committerKeith Packard <keithp@keithp.com>
Thu, 1 Feb 2024 01:50:19 +0000 (17:50 -0800)
Got clocks working. CPU now running at 72MHz.
Got systick timer working. Ticks at 100Hz.
Got GPIO working. LED blinks.

Signed-off-by: Keith Packard <keithp@keithp.com>
17 files changed:
src/stm32f1/Makefile-raw.defs [new file with mode: 0644]
src/stm32f1/Makefile-stm32f1.defs [new file with mode: 0644]
src/stm32f1/Makefile.defs [new file with mode: 0644]
src/stm32f1/altos-ram.ld [new file with mode: 0644]
src/stm32f1/altos-raw.ld [new file with mode: 0644]
src/stm32f1/ao_arch.h [new file with mode: 0644]
src/stm32f1/ao_arch_funcs.h [new file with mode: 0644]
src/stm32f1/ao_clock.c [new file with mode: 0644]
src/stm32f1/ao_interrupt.c [new file with mode: 0644]
src/stm32f1/ao_timer.c [new file with mode: 0644]
src/stm32f1/openocd-stm32f1 [new file with mode: 0755]
src/stm32f1/registers.ld [new file with mode: 0644]
src/stm32f1/stm32f1.h [new file with mode: 0644]
src/stm32f103-nucleo/Makefile [new file with mode: 0644]
src/stm32f103-nucleo/ao_pins.h [new file with mode: 0644]
src/stm32f103-nucleo/hello.c [new file with mode: 0644]
src/stm32f103-nucleo/hello.ld [new file with mode: 0644]

diff --git a/src/stm32f1/Makefile-raw.defs b/src/stm32f1/Makefile-raw.defs
new file mode 100644 (file)
index 0000000..91d30bd
--- /dev/null
@@ -0,0 +1,13 @@
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+include $(TOPDIR)/stm32f1/Makefile-stm32f1.defs
+
+LOADER=flash-loader/$(PROGNAME)-altos-flash-$(VERSION).elf
+MAKEBIN=$(TOPDIR)/../ao-tools/ao-makebin/ao-makebin
+FLASH_ADDR=0x08000000
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm32f1 -Taltos-ram.ld -n
+
+.DEFAULT_GOAL=all
diff --git a/src/stm32f1/Makefile-stm32f1.defs b/src/stm32f1/Makefile-stm32f1.defs
new file mode 100644 (file)
index 0000000..b84f739
--- /dev/null
@@ -0,0 +1,12 @@
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+include $(TOPDIR)/Makefile.defs
+
+vpath % $(TOPDIR)/stm32f1:$(AO_VPATH)
+
+CC=$(ARM_CC)
+
+STM32F1_CFLAGS=-mlittle-endian -mcpu=cortex-m3 -mthumb \
+       -I$(TOPDIR)/stm32f1 $(AO_CFLAGS) $(PICOLIBC_CFLAGS)
diff --git a/src/stm32f1/Makefile.defs b/src/stm32f1/Makefile.defs
new file mode 100644 (file)
index 0000000..e292fc6
--- /dev/null
@@ -0,0 +1,11 @@
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+include $(TOPDIR)/stm32f1/Makefile-stm32f1.defs
+
+STM32F1_LINKER_SCRIPT=altos-raw.ld
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm32f1 -T$(STM32F1_LINKER_SCRIPT) -n
+
+.DEFAULT_GOAL=all
diff --git a/src/stm32f1/altos-ram.ld b/src/stm32f1/altos-ram.ld
new file mode 100644 (file)
index 0000000..d409d2c
--- /dev/null
@@ -0,0 +1,8 @@
+__flash = 0x20000000;
+__flash_size = 12k;
+__ram   = 0x20003000;
+__ram_size = 4k;
+__stack_size = 512;
+
+INCLUDE registers.ld
+INCLUDE picolibc.ld
diff --git a/src/stm32f1/altos-raw.ld b/src/stm32f1/altos-raw.ld
new file mode 100644 (file)
index 0000000..1a7ccdd
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright © 2018 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+__flash = 0x08000000;
+__flash_size = 64k;
+__ram = 0x20000000;
+__ram_size = 20k;
+__stack_size = 512;
+
+INCLUDE registers.ld
+INCLUDE picolibc.ld
diff --git a/src/stm32f1/ao_arch.h b/src/stm32f1/ao_arch.h
new file mode 100644 (file)
index 0000000..de5f215
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_ARCH_H_
+#define _AO_ARCH_H_
+
+#include <stm32f1.h>
+
+#ifndef AO_STACK_SIZE
+#define AO_STACK_SIZE  512
+#endif
+
+#define AO_PORT_TYPE   uint16_t
+
+#define ao_arch_naked_declare  __attribute__((naked))
+#define ao_arch_naked_define
+#define __interrupt(n)
+#define __at(n)
+
+#define ao_arch_nop()          asm("nop")
+
+#define ao_arch_interrupt(n)   /* nothing */
+
+#define AO_ROMCONFIG_SYMBOL __attribute__((section(".init.1"))) const
+#define AO_USBCONFIG_SYMBOL __attribute__((section(".init.2"))) const
+
+#define AO_SYSTICK     (AO_HCLK / 8)
+
+#if AO_NONMASK_INTERRUPT
+#define AO_STM_NVIC_NONMASK_PRIORITY   0x00
+
+/* Set the basepri register to this value to mask all
+ * non-maskable priorities
+ */
+#define AO_STM_NVIC_BASEPRI_MASK       0x10
+#endif
+
+#define AO_STM_NVIC_HIGH_PRIORITY      0x40
+#define AO_STM_NVIC_MED_PRIORITY       0x80
+#define AO_STM_NVIC_LOW_PRIORITY       0xC0
+#define AO_STM_NVIC_CLOCK_PRIORITY     0xf0
+
+#endif /* _AO_ARCH_H_ */
diff --git a/src/stm32f1/ao_arch_funcs.h b/src/stm32f1/ao_arch_funcs.h
new file mode 100644 (file)
index 0000000..db3cf9e
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_ARCH_FUNCS_H_
+#define _AO_ARCH_FUNCS_H_
+
+static inline void
+ao_enable_port(struct stm_gpio *port)
+{
+       if ((port) == &stm_gpioa)
+               stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPAEN);
+       else if ((port) == &stm_gpiob)
+               stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPBEN);
+       else if ((port) == &stm_gpioc)
+               stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPCEN);
+       else if ((port) == &stm_gpiod)
+               stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPDEN);
+       else if ((port) == &stm_gpioe)
+               stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPEEN);
+}
+
+static inline void
+ao_disable_port(struct stm_gpio *port)
+{
+       if ((port) == &stm_gpioa)
+               stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPAEN);
+       else if ((port) == &stm_gpiob)
+               stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPBEN);
+       else if ((port) == &stm_gpioc)
+               stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPCEN);
+       else if ((port) == &stm_gpiod)
+               stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPDEN);
+       else if ((port) == &stm_gpioe)
+               stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPEEN);
+}
+
+#define ao_gpio_set(port, bit, v) stm_gpio_set(port, bit, v)
+
+#define ao_gpio_get(port, bit) stm_gpio_get(port, bit)
+
+#define ao_gpio_set_bits(port, bits) stm_gpio_set_bits(port, bits)
+
+#define ao_gpio_set_mask(port, bits, mask) stm_gpio_set_mask(port, bits, mask)
+
+#define ao_gpio_clr_bits(port, bits) stm_gpio_clr_bits(port, bits);
+
+#define ao_gpio_get_all(port) stm_gpio_get_all(port)
+
+static inline void
+ao_enable_output(struct stm_gpio *port, int bit, uint8_t v)
+{
+       ao_enable_port(port);
+       ao_gpio_set(port, bit, v);
+       stm_gpio_conf(port, bit,
+                     STM_GPIO_CR_MODE_OUTPUT_10MHZ,
+                     STM_GPIO_CR_CNF_OUTPUT_PUSH_PULL);
+}
+
+#endif /* _AO_ARCH_FUNCS_H_ */
diff --git a/src/stm32f1/ao_clock.c b/src/stm32f1/ao_clock.c
new file mode 100644 (file)
index 0000000..1ce32a9
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+void
+ao_clock_init(void)
+{
+       uint32_t        cfgr;
+
+       /* Switch to HSI while messing about */
+       stm_rcc.cr |= (1 << STM_RCC_CR_HSION);
+       while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSIRDY)))
+               ao_arch_nop();
+
+       stm_rcc.cfgr = (stm_rcc.cfgr & ~(uint32_t) (STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW)) |
+               (STM_RCC_CFGR_SW_HSI << STM_RCC_CFGR_SW);
+
+       /* wait for system to switch to HSI */
+       while ((stm_rcc.cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) !=
+              (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS))
+               ao_arch_nop();
+
+       /* Disable all interrupts */
+       stm_rcc.cir = 0;
+
+#if AO_HSE
+#if AO_HSE_BYPASS
+       stm_rcc.cr |= (1 << STM_RCC_CR_HSEBYP);
+#else
+       stm_rcc.cr &= ~(uint32_t) (1 << STM_RCC_CR_HSEBYP);
+#endif
+       /* Enable HSE clock */
+       stm_rcc.cr |= (1 << STM_RCC_CR_HSEON);
+       while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSERDY)))
+               asm("nop");
+
+#define STM_RCC_CFGR_SWS_TARGET_CLOCK          (STM_RCC_CFGR_SWS_HSE << STM_RCC_CFGR_SWS)
+#define STM_RCC_CFGR_SW_TARGET_CLOCK           (STM_RCC_CFGR_SW_HSE)
+#define STM_PLLSRC                             AO_HSE
+#define STM_RCC_CFGR_PLLSRC_TARGET_CLOCK       (STM_RCC_CFGR_PLLSRC_HSE << STM_RCC_CFGR_PLLSRC)
+#else
+#define STM_HSI                                16000000
+#define STM_RCC_CFGR_SWS_TARGET_CLOCK          (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS)
+#define STM_RCC_CFGR_SW_TARGET_CLOCK           (STM_RCC_CFGR_SW_HSI)
+#define STM_PLLSRC                             (STM_HSI/2)
+#define STM_RCC_CFGR_PLLSRC_TARGET_CLOCK       (STM_RCC_CFGR_PLLSRC_HSI_2 << STM_RCC_CFGR_PLLSRC)
+#endif
+
+#if !AO_HSE || HAS_ADC || HAS_ADC_SINGLE
+       /* Enable HSI RC clock 16MHz */
+       stm_rcc.cr |= (1 << STM_RCC_CR_HSION);
+       while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSIRDY)))
+               asm("nop");
+#endif
+
+#if 0
+       /* Set flash latency to tolerate 32MHz SYSCLK  -> 1 wait state */
+
+       /* Enable 64-bit access and prefetch */
+       stm_flash.acr |= (1 << STM_FLASH_ACR_ACC64);
+       stm_flash.acr |= (1 << STM_FLASH_ACR_PRFEN);
+
+       /* Enable 1 wait state so the CPU can run at 32MHz */
+       stm_flash.acr |= (1 << STM_FLASH_ACR_LATENCY);
+#endif
+
+       /* Enable power interface clock */
+       stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
+
+#if 0
+       /* Set voltage range to 1.8V */
+
+       /* poll VOSF bit in PWR_CSR. Wait until it is reset to 0 */
+       while ((stm_pwr.csr & (1 << STM_PWR_CSR_VOSF)) != 0)
+               asm("nop");
+
+       /* Configure voltage scaling range */
+       cr = stm_pwr.cr;
+       cr &= ~(STM_PWR_CR_VOS_MASK << STM_PWR_CR_VOS);
+       cr |= (STM_PWR_CR_VOS_1_8 << STM_PWR_CR_VOS);
+       stm_pwr.cr = cr;
+
+       /* poll VOSF bit in PWR_CSR. Wait until it is reset to 0 */
+       while ((stm_pwr.csr & (1 << STM_PWR_CSR_VOSF)) != 0)
+               asm("nop");
+#endif
+
+       /* HCLK */
+       cfgr = stm_rcc.cfgr;
+       cfgr &= ~(STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE);
+       cfgr |= (AO_RCC_CFGR_HPRE_DIV << STM_RCC_CFGR_HPRE);
+       stm_rcc.cfgr = cfgr;
+       while ((stm_rcc.cfgr & (STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE)) !=
+              (AO_RCC_CFGR_HPRE_DIV << STM_RCC_CFGR_HPRE))
+               asm ("nop");
+
+       /* APB1 Prescaler = AO_APB1_PRESCALER */
+       cfgr = stm_rcc.cfgr;
+       cfgr &= ~(STM_RCC_CFGR_PPRE1_MASK << STM_RCC_CFGR_PPRE1);
+       cfgr |= (AO_RCC_CFGR_PPRE1_DIV << STM_RCC_CFGR_PPRE1);
+       stm_rcc.cfgr = cfgr;
+
+       /* APB2 Prescaler = AO_APB2_PRESCALER */
+       cfgr = stm_rcc.cfgr;
+       cfgr &= ~(STM_RCC_CFGR_PPRE2_MASK << STM_RCC_CFGR_PPRE2);
+       cfgr |= (AO_RCC_CFGR_PPRE2_DIV << STM_RCC_CFGR_PPRE2);
+       stm_rcc.cfgr = cfgr;
+
+       /* Disable the PLL */
+       stm_rcc.cr &= ~(1UL << STM_RCC_CR_PLLON);
+       while (stm_rcc.cr & (1UL << STM_RCC_CR_PLLRDY))
+               asm("nop");
+
+       /* PLLVCO */
+       cfgr = stm_rcc.cfgr;
+       cfgr &= ~(STM_RCC_CFGR_PLLMUL_MASK << STM_RCC_CFGR_PLLMUL);
+
+       cfgr |= (AO_RCC_CFGR_PLLMUL << STM_RCC_CFGR_PLLMUL);
+
+       /* PLL source */
+       cfgr &= ~(1UL << STM_RCC_CFGR_PLLSRC);
+       cfgr |= STM_RCC_CFGR_PLLSRC_TARGET_CLOCK;
+
+       stm_rcc.cfgr = cfgr;
+
+       /* Enable the PLL and wait for it */
+       stm_rcc.cr |= (1 << STM_RCC_CR_PLLON);
+       while (!(stm_rcc.cr & (1 << STM_RCC_CR_PLLRDY)))
+               asm("nop");
+
+       /* Switch to the PLL for the system clock */
+
+       cfgr = stm_rcc.cfgr;
+       cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW);
+       cfgr |= (STM_RCC_CFGR_SW_PLL << STM_RCC_CFGR_SW);
+       stm_rcc.cfgr = cfgr;
+       for (;;) {
+               uint32_t        c, part, mask, val;
+
+               c = stm_rcc.cfgr;
+               mask = (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS);
+               val = (STM_RCC_CFGR_SWS_PLL << STM_RCC_CFGR_SWS);
+               part = c & mask;
+               if (part == val)
+                       break;
+       }
+
+#if 0
+       stm_rcc.apb2rstr = 0xffff;
+       stm_rcc.apb1rstr = 0xffff;
+       stm_rcc.ahbrstr = 0x3f;
+       stm_rcc.ahbenr = (1 << STM_RCC_AHBENR_FLITFEN);
+       stm_rcc.apb2enr = 0;
+       stm_rcc.apb1enr = 0;
+       stm_rcc.ahbrstr = 0;
+       stm_rcc.apb1rstr = 0;
+       stm_rcc.apb2rstr = 0;
+#endif
+
+       /* Clear reset flags */
+       stm_rcc.csr |= (1 << STM_RCC_CSR_RMVF);
+
+
+#if DEBUG_THE_CLOCK
+       /* Output SYSCLK on PA8 for measurments */
+
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
+
+       stm_afr_set(&stm_gpioa, 8, STM_AFR_AF0);
+       stm_moder_set(&stm_gpioa, 8, STM_MODER_ALTERNATE);
+       stm_ospeedr_set(&stm_gpioa, 8, STM_OSPEEDR_40MHz);
+
+       stm_rcc.cfgr |= (STM_RCC_CFGR_MCOPRE_DIV_1 << STM_RCC_CFGR_MCOPRE);
+       stm_rcc.cfgr |= (STM_RCC_CFGR_MCOSEL_HSE << STM_RCC_CFGR_MCOSEL);
+#endif
+}
diff --git a/src/stm32f1/ao_interrupt.c b/src/stm32f1/ao_interrupt.c
new file mode 100644 (file)
index 0000000..831a2c2
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include "stm32f1.h"
+#include <string.h>
+#include <ao_boot.h>
+
+extern void main(void);
+
+/* Interrupt functions */
+
+void stm_halt_isr(void)
+{
+//     ao_panic(AO_PANIC_CRASH);
+}
+
+void stm_ignore_isr(void)
+{
+}
+
+#define STRINGIFY(x) #x
+
+#define isr(name) \
+       void __attribute__ ((weak)) stm_ ## name ## _isr(void); \
+       _Pragma(STRINGIFY(weak stm_ ## name ## _isr = stm_ignore_isr))
+
+#define isr_halt(name) \
+       void __attribute__ ((weak)) stm_ ## name ## _isr(void); \
+       _Pragma(STRINGIFY(weak stm_ ## name ## _isr = stm_halt_isr))
+
+isr(nmi);
+isr_halt(hardfault);
+isr_halt(memmanage);
+isr_halt(busfault);
+isr_halt(usagefault);
+isr(svc);
+isr(debugmon);
+isr(pendsv);
+isr(systick);
+isr(wwdg);
+isr(pvd);
+isr(tamper_stamp);
+isr(rtc_wkup);
+isr(flash);
+isr(rcc);
+isr(exti0);
+isr(exti1);
+isr(exti2);
+isr(exti3);
+isr(exti4);
+isr(dma1_channel1);
+isr(dma1_channel2);
+isr(dma1_channel3);
+isr(dma1_channel4);
+isr(dma1_channel5);
+isr(dma1_channel6);
+isr(dma1_channel7);
+isr(adc1_2);
+isr(usb_hp);
+isr(usb_lp);
+isr(can_rx1);
+isr(can_sce);
+isr(exti9_5);
+isr(tim1_brk);
+isr(tim1_up);
+isr(tim1_trg_com);
+isr(tim1_cc);
+isr(tim2);
+isr(tim3);
+isr(tim4);
+isr(i2c1_ev);
+isr(i2c1_er);
+isr(i2c2_ev);
+isr(i2c2_er);
+isr(spi1);
+isr(spi2);
+isr(usart1);
+isr(usart2);
+isr(usart3);
+isr(exti15_10);
+isr(rtc_alarm);
+isr(usb_wakeup);
+isr(tim8_brk);
+isr(tim8_up);
+isr(tim8_trg_com);
+isr(tim8_cc);
+isr(adc3);
+isr(fsmc);
+isr(sdio);
+isr(tim5);
+isr(spi3);
+isr(uart4);
+isr(uart5);
+isr(tim6);
+isr(tim7);
+isr(dma2_channel1);
+isr(dma2_channel2);
+isr(dma2_channel3);
+isr(dma2_channel4_5);
+
+#define i(addr,name)   [(addr)/4] = stm_ ## name ## _isr
+
+extern char __stack[];
+void _start(void) __attribute__((__noreturn__));
+void main(void) __attribute__((__noreturn__));
+void ao_setup(void) __attribute__((constructor));
+
+/* This must be exactly 304 bytes long so that the configuration data
+ * gets loaded at the right place
+ */
+
+__attribute__ ((section(".init")))
+const void * const __interrupt_vector[76] = {
+       [0] = &__stack,
+       [1] = _start,
+       i(0x08, nmi),
+       i(0x0c, hardfault),
+       i(0x10, memmanage),
+       i(0x14, busfault),
+       i(0x18, usagefault),
+       i(0x2c, svc),
+       i(0x30, debugmon),
+       i(0x38, pendsv),
+       i(0x3c, systick),
+       i(0x40, wwdg),
+       i(0x44, pvd),
+       i(0x48, tamper_stamp),
+       i(0x4c, rtc_wkup),
+       i(0x50, flash),
+       i(0x54, rcc),
+       i(0x58, exti0),
+       i(0x5c, exti1),
+       i(0x60, exti2),
+       i(0x64, exti3),
+       i(0x68, exti4),
+       i(0x6c, dma1_channel1),
+       i(0x70, dma1_channel2),
+       i(0x74, dma1_channel3),
+       i(0x78, dma1_channel4),
+       i(0x7c, dma1_channel5),
+       i(0x80, dma1_channel6),
+       i(0x84, dma1_channel7),
+       i(0x88, adc1_2),
+       i(0x8c, usb_hp),
+       i(0x90, usb_lp),
+       i(0x94, can_rx1),
+       i(0x98, can_sce),
+       i(0x9c, exti9_5),
+       i(0xa0, tim1_brk),
+       i(0xa4, tim1_up),
+       i(0xa8, tim1_trg_com),
+       i(0xac, tim1_cc),
+       i(0xb0, tim2),
+       i(0xb4, tim3),
+       i(0xb8, tim4),
+       i(0xbc, i2c1_ev),
+       i(0xc0, i2c1_er),
+       i(0xc4, i2c2_ev),
+       i(0xc8, i2c2_er),
+       i(0xcc, spi1),
+       i(0xd0, spi2),
+       i(0xd4, usart1),
+       i(0xd8, usart2),
+       i(0xdc, usart3),
+       i(0xe0, exti15_10),
+       i(0xe4, rtc_alarm),
+       i(0xe8, usb_wakeup),
+       i(0xec, tim8_brk),
+       i(0xf0, tim8_up),
+       i(0xf4, tim8_trg_com),
+       i(0xf8, tim8_cc),
+       i(0xfc, adc3),
+       i(0x100, fsmc),
+       i(0x104, sdio),
+       i(0x108, tim5),
+       i(0x10c, spi3),
+       i(0x110, uart4),
+       i(0x114, uart5),
+       i(0x118, tim6),
+       i(0x11c, tim7),
+       i(0x120, dma2_channel1),
+       i(0x124, dma2_channel2),
+       i(0x128, dma2_channel3),
+       i(0x12c, dma2_channel4_5),
+};
+
+void __attribute__((constructor)) ao_setup(void) {
+#ifdef AO_BOOT_CHAIN
+       if (ao_boot_check_chain()) {
+#ifdef AO_BOOT_PIN
+               if (ao_boot_check_pin())
+#endif
+               {
+                       ao_boot_chain(AO_BOOT_APPLICATION_BASE);
+               }
+       }
+#endif
+       /* Set interrupt vector table offset */
+       stm_nvic.vto = (uint32_t) &__interrupt_vector;
+}
diff --git a/src/stm32f1/ao_timer.c b/src/stm32f1/ao_timer.c
new file mode 100644 (file)
index 0000000..116d33a
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include <ao_task.h>
+
+#ifndef HAS_TICK
+#define HAS_TICK 1
+#endif
+
+volatile AO_TICK_TYPE ao_tick_count;
+
+AO_TICK_TYPE
+ao_time(void)
+{
+       return ao_tick_count;
+}
+
+uint64_t
+ao_time_ns(void)
+{
+       AO_TICK_TYPE    before, after;
+       uint32_t        val;
+
+       do {
+               before = ao_tick_count;
+               val = stm_systick.val;
+               after = ao_tick_count;
+       } while (before != after);
+
+       return (uint64_t) after * (1000000000ULL / AO_HERTZ) +
+               (uint64_t) val * (1000000000ULL / AO_SYSTICK);
+}
+
+void stm_systick_isr(void)
+{
+       if (stm_systick.ctrl & (1 << STM_SYSTICK_CTRL_COUNTFLAG)) {
+               ++ao_tick_count;
+//             ao_task_check_alarm();
+#ifdef AO_TIMER_HOOK
+               AO_TIMER_HOOK;
+#endif
+       }
+}
+
+#define SYSTICK_RELOAD (AO_SYSTICK / 100 - 1)
+
+void
+ao_timer_init(void)
+{
+       stm_systick.load = SYSTICK_RELOAD;
+       stm_systick.val = 0;
+       stm_systick.ctrl = ((1 << STM_SYSTICK_CTRL_ENABLE) |
+                           (1 << STM_SYSTICK_CTRL_TICKINT) |
+                           (STM_SYSTICK_CTRL_CLKSOURCE_HCLK_8 << STM_SYSTICK_CTRL_CLKSOURCE));
+//     stm_nvic.shpr15_12 |= (uint32_t) AO_STM_NVIC_CLOCK_PRIORITY << 24;
+}
diff --git a/src/stm32f1/openocd-stm32f1 b/src/stm32f1/openocd-stm32f1
new file mode 100755 (executable)
index 0000000..20b074e
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+#OPENOCD=openocd
+#OPENOCD=/usr/bin/openocd
+#OPENOCD=/local/src/openocd/src/openocd
+OPENOCD=/local/bin/openocd
+exec $OPENOCD \
+       -f interface/stlink.cfg \
+       -c 'transport select hla_swd' \
+       -f target/stm32f1x.cfg -c init \
+       -c 'reset halt' \
+       -c 'stm32f1x.cpu arm semihosting enable' \
+       "$@"
diff --git a/src/stm32f1/registers.ld b/src/stm32f1/registers.ld
new file mode 100644 (file)
index 0000000..b943165
--- /dev/null
@@ -0,0 +1,45 @@
+stm_crc           = 0x40023000;
+stm_flash  = 0x40022000;
+stm_rcc    = 0x40021000;
+stm_dma    = 0x40020000;
+stm_usart1 = 0x40013800;
+stm_spi1   = 0x40013000;
+stm_tim1   = 0x40012c00;
+stm_adc2   = 0x40012800;
+stm_adc1   = 0x40012400;
+stm_gpioe  = 0x40011800;
+stm_gpiod  = 0x40011400;
+stm_gpioc  = 0x40011000;
+stm_gpiob  = 0x40010c00;
+stm_gpioa  = 0x40010800;
+stm_exti   = 0x40010400;
+stm_afio   = 0x40010000;
+stm_pwr    = 0x40007000;
+stm_bkp    = 0x40006c00;
+stm_bxcan  = 0x40006400;
+stm_usb_sram = 0x40006000;
+stm_usb    = 0x40005c00;
+stm_i2c2   = 0x40005800;
+stm_i2c1   = 0x40005400;
+stm_usart3 = 0x40004800;
+stm_usart2 = 0x40004400;
+stm_spi2   = 0x40003800;
+stm_iwdg   = 0x40003000;
+stm_wwdg   = 0x40002c00;
+stm_rtc    = 0x40002800;
+stm_tim4   = 0x40000800;
+stm_tim3   = 0x40000400;
+stm_tim2   = 0x40000000;
+
+stm_systick = 0xe000e010;
+
+stm_nvic   = 0xe000e100;
+
+stm_scb    = 0xe000ed00;
+
+stm_mpu    = 0xe000ed90;
+
+stm_dbg_mcu = 0xe0042000;
+
+/* data in system memory */
+stm_flash_data = 0x1ffff7e0;
diff --git a/src/stm32f1/stm32f1.h b/src/stm32f1/stm32f1.h
new file mode 100644 (file)
index 0000000..5ac99e6
--- /dev/null
@@ -0,0 +1,522 @@
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _STM32F1_H_
+#define _STM32F1_H_
+
+#include <stdint.h>
+
+typedef volatile uint32_t      vuint32_t;
+typedef volatile uint16_t      vuint16_t;
+typedef volatile void *                vvoid_t;
+
+struct stm_rcc {
+       vuint32_t       cr;
+       vuint32_t       cfgr;
+       vuint32_t       cir;
+       vuint32_t       apb2rstr;
+
+       vuint32_t       apb1rstr;
+       vuint32_t       ahbenr;
+       vuint32_t       apb2enr;
+       vuint32_t       apb1enr;
+
+       vuint32_t       bdcr;
+       vuint32_t       csr;
+       vuint32_t       ahbstr;
+       vuint32_t       cfgr2;
+};
+
+extern struct stm_rcc stm_rcc;
+
+//#define stm_rcc    (*((struct stm_rcc *) 0x40021000))
+
+#define STM_RCC_CR_RTCPRE      (29)
+#define  STM_RCC_CR_RTCPRE_HSE_DIV_2   0
+#define  STM_RCC_CR_RTCPRE_HSE_DIV_4   1
+#define  STM_RCC_CR_RTCPRE_HSE_DIV_8   2
+#define  STM_RCC_CR_RTCPRE_HSE_DIV_16  3
+#define  STM_RCC_CR_RTCPRE_HSE_MASK    3UL
+
+#define STM_RCC_CR_PLL3RDY     (29)
+#define STM_RCC_CR_PLL3ON      (28)
+#define STM_RCC_CR_PLL2RDY     (27)
+#define STM_RCC_CR_PLL2ON      (26)
+#define STM_RCC_CR_PLLRDY      (25)
+#define STM_RCC_CR_PLLON       (24)
+#define STM_RCC_CR_CSSON       (19)
+#define STM_RCC_CR_HSEBYP      (18)
+#define STM_RCC_CR_HSERDY      (17)
+#define STM_RCC_CR_HSEON       (16)
+#define STM_RCC_CR_HSICAL      (8)
+#define STM_RCC_CR_HSITRIM     (3)
+#define STM_RCC_CR_HSIRDY      (1)
+#define STM_RCC_CR_HSION       (0)
+
+#define STM_RCC_CFGR_MCOPRE    (28)
+#define  STM_RCC_CFGR_MCOPRE_DIV_1     0
+#define  STM_RCC_CFGR_MCOPRE_DIV_2     1
+#define  STM_RCC_CFGR_MCOPRE_DIV_4     2
+#define  STM_RCC_CFGR_MCOPRE_DIV_8     3
+#define  STM_RCC_CFGR_MCOPRE_DIV_16    4
+#define  STM_RCC_CFGR_MCOPRE_MASK      7UL
+
+#define STM_RCC_CFGR_MCO       (24)
+#define  STM_RCC_CFGR_MCO_DISABLE      0
+#define  STM_RCC_CFGR_MCO_SYSCLK       4
+#define  STM_RCC_CFGR_MCO_HSI  5
+#define  STM_RCC_CFGR_MCO_HSE  6
+#define  STM_RCC_CFGR_MCO_PLL_2        7
+#define  STM_RCC_CFGR_MCO_MASK 7UL
+
+#define STM_RCC_CFGR_USBPRE    (22)
+#define  STM_RCC_CFGR_USBPRE_1_5       0
+#define  STM_RCC_CFGR_USBPRE_1         1
+
+#define STM_RCC_CFGR_PLLMUL    (18)
+#define  STM_RCC_CFGR_PLLMUL_2         0
+#define  STM_RCC_CFGR_PLLMUL_3         1
+#define  STM_RCC_CFGR_PLLMUL_4         2
+#define  STM_RCC_CFGR_PLLMUL_5         3
+#define  STM_RCC_CFGR_PLLMUL_6         4
+#define  STM_RCC_CFGR_PLLMUL_7         5
+#define  STM_RCC_CFGR_PLLMUL_8         6
+#define  STM_RCC_CFGR_PLLMUL_9         7
+#define  STM_RCC_CFGR_PLLMUL_10                8
+#define  STM_RCC_CFGR_PLLMUL_11                9
+#define  STM_RCC_CFGR_PLLMUL_12                10
+#define  STM_RCC_CFGR_PLLMUL_13                11
+#define  STM_RCC_CFGR_PLLMUL_14                12
+#define  STM_RCC_CFGR_PLLMUL_15                13
+#define  STM_RCC_CFGR_PLLMUL_16                14
+#define  STM_RCC_CFGR_PLLMUL_MASK      0xfUL
+
+#define STM_RCC_CFGR_PLLXTPRE  (17)
+#define  STM_RCC_CFGR_PLLXTPRE_1       0
+#define  STM_RCC_CFGR_PLLXTPRE_2       1
+
+#define STM_RCC_CFGR_PLLSRC    (16)
+#define  STM_RCC_CFGR_PLLSRC_HSI_2     0
+#define  STM_RCC_CFGR_PLLSRC_HSE       1
+
+#define STM_RCC_CFGR_ADCPRE    (14)
+#define  STM_RCC_CFGR_ADCPRE_2         0
+#define  STM_RCC_CFGR_ADCPRE_4         1
+#define  STM_RCC_CFGR_ADCPRE_6         2
+#define  STM_RCC_CFGR_ADCPRE_8         3
+
+#define STM_RCC_CFGR_PPRE2     (11)
+#define  STM_RCC_CFGR_PPRE2_DIV_1      0
+#define  STM_RCC_CFGR_PPRE2_DIV_2      4
+#define  STM_RCC_CFGR_PPRE2_DIV_4      5
+#define  STM_RCC_CFGR_PPRE2_DIV_8      6
+#define  STM_RCC_CFGR_PPRE2_DIV_16     7
+#define  STM_RCC_CFGR_PPRE2_MASK       7UL
+
+#define STM_RCC_CFGR_PPRE1     (8)
+#define  STM_RCC_CFGR_PPRE1_DIV_1      0
+#define  STM_RCC_CFGR_PPRE1_DIV_2      4
+#define  STM_RCC_CFGR_PPRE1_DIV_4      5
+#define  STM_RCC_CFGR_PPRE1_DIV_8      6
+#define  STM_RCC_CFGR_PPRE1_DIV_16     7
+#define  STM_RCC_CFGR_PPRE1_MASK       7UL
+
+#define STM_RCC_CFGR_HPRE      (4)
+#define  STM_RCC_CFGR_HPRE_DIV_1       0
+#define  STM_RCC_CFGR_HPRE_DIV_2       8
+#define  STM_RCC_CFGR_HPRE_DIV_4       9
+#define  STM_RCC_CFGR_HPRE_DIV_8       0xa
+#define  STM_RCC_CFGR_HPRE_DIV_16      0xb
+#define  STM_RCC_CFGR_HPRE_DIV_64      0xc
+#define  STM_RCC_CFGR_HPRE_DIV_128     0xd
+#define  STM_RCC_CFGR_HPRE_DIV_256     0xe
+#define  STM_RCC_CFGR_HPRE_DIV_512     0xf
+#define  STM_RCC_CFGR_HPRE_MASK                0xfUL
+
+#define STM_RCC_CFGR_SWS       (2)
+#define  STM_RCC_CFGR_SWS_HSI          0
+#define  STM_RCC_CFGR_SWS_HSE          1
+#define  STM_RCC_CFGR_SWS_PLL          2
+#define  STM_RCC_CFGR_SWS_MASK         3UL
+
+#define STM_RCC_CFGR_SW                (0)
+#define  STM_RCC_CFGR_SW_HSI           0
+#define  STM_RCC_CFGR_SW_HSE           1
+#define  STM_RCC_CFGR_SW_PLL           2
+#define  STM_RCC_CFGR_SW_MASK          3UL
+
+#define STM_RCC_AHBENR_CRCEN   6
+#define STM_RCC_AHBENR_FLITFEN 4
+#define STM_RCC_AHBENR_SRAMEN  2
+#define STM_RCC_AHBENR_DMA2EN  1
+#define STM_RCC_AHBENR_DMA1EN  0
+
+
+#define STM_RCC_APB2ENR_USART1EN       14
+#define STM_RCC_APB2ENR_SPI1EN         12
+#define STM_RCC_APB2ENR_TIM1EN         11
+#define STM_RCC_APB2ENR_ADC2EN         10
+#define STM_RCC_APB2ENR_ADC1EN         9
+#define STM_RCC_APB2ENR_IOPEEN         6
+#define STM_RCC_APB2ENR_IOPDEN         5
+#define STM_RCC_APB2ENR_IOPCEN         4
+#define STM_RCC_APB2ENR_IOPBEN         3
+#define STM_RCC_APB2ENR_IOPAEN         2
+#define STM_RCC_APB2ENR_AFIOEN         0
+
+#define STM_RCC_APB1ENR_DACEN          29
+#define STM_RCC_APB1ENR_PWREN          28
+#define STM_RCC_APB1ENR_BKPEN          27
+#define STM_RCC_APB1ENR_CAN2EN         26
+#define STM_RCC_APB1ENR_CAN1EN         25
+#define STM_RCC_APB1ENR_I2C2EN         22
+#define STM_RCC_APB1ENR_I2C1EN         21
+#define STM_RCC_APB1ENR_UART5EN                20
+#define STM_RCC_APB1ENR_UART4EN                19
+#define STM_RCC_APB1ENR_USART3EN       18
+#define STM_RCC_APB1ENR_USART2EN       17
+#define STM_RCC_APB1ENR_SPI3EN         15
+#define STM_RCC_APB1ENR_SPI2EN         14
+#define STM_RCC_APB1ENR_WWDGEN         11
+#define STM_RCC_APB1ENR_TIM7EN         5
+#define STM_RCC_APB1ENR_TIM6EN         4
+#define STM_RCC_APB1ENR_TIM5EN         3
+#define STM_RCC_APB1ENR_TIM4EN         2
+#define STM_RCC_APB1ENR_TIM3EN         1
+#define STM_RCC_APB1ENR_TIM2EN         0
+
+#define STM_RCC_CSR_LPWRRSTF           (31)
+#define STM_RCC_CSR_WWDGRSTF           (30)
+#define STM_RCC_CSR_IWDGRSTF           (29)
+#define STM_RCC_CSR_SFTRSTF            (28)
+#define STM_RCC_CSR_PORRSTF            (27)
+#define STM_RCC_CSR_PINRSTF            (26)
+#define STM_RCC_CSR_RMVF               (24)
+#define STM_RCC_CSR_LSIRDY             (1)
+#define STM_RCC_CSR_LSION              (0)
+
+struct stm_systick {
+       vuint32_t       ctrl;
+       vuint32_t       load;
+       vuint32_t       val;
+       vuint32_t       calib;
+};
+
+extern struct stm_systick stm_systick;
+
+#define stm_systick    (*((struct stm_systick *) 0xe000e010))
+
+#define STM_SYSTICK_CTRL_ENABLE                0
+#define STM_SYSTICK_CTRL_TICKINT       1
+#define STM_SYSTICK_CTRL_CLKSOURCE     2
+#define  STM_SYSTICK_CTRL_CLKSOURCE_HCLK_8             0
+#define  STM_SYSTICK_CTRL_CLKSOURCE_HCLK               1
+#define STM_SYSTICK_CTRL_COUNTFLAG     16
+
+/* The NVIC starts at 0xe000e100, so add that to the offsets to find the absolute address */
+
+struct stm_nvic {
+       vuint32_t       iser[8];        /* 0x000 0xe000e100 Set Enable Register */
+
+       uint8_t         _unused020[0x080 - 0x020];
+
+       vuint32_t       icer[8];        /* 0x080 0xe000e180 Clear Enable Register */
+
+       uint8_t         _unused0a0[0x100 - 0x0a0];
+
+       vuint32_t       ispr[8];        /* 0x100 0xe000e200 Set Pending Register */
+
+       uint8_t         _unused120[0x180 - 0x120];
+
+       vuint32_t       icpr[8];        /* 0x180 0xe000e280 Clear Pending Register */
+
+       uint8_t         _unused1a0[0x200 - 0x1a0];
+
+       vuint32_t       iabr[8];        /* 0x200 0xe000e300 Active Bit Register */
+
+       uint8_t         _unused220[0x300 - 0x220];
+
+       vuint32_t       ipr[60];        /* 0x300 0xe000e400 Priority Register */
+
+       uint8_t         _unused3f0[0xc00 - 0x3f0];
+
+       vuint32_t       cpuid_base;     /* 0xc00 0xe000ed00 CPUID Base Register */
+       vuint32_t       ics;            /* 0xc04 0xe000ed04 Interrupt Control State Register */
+       vuint32_t       vto;            /* 0xc08 0xe000ed08 Vector Table Offset Register */
+       vuint32_t       ai_rc;          /* 0xc0c 0xe000ed0c Application Interrupt/Reset Control Register */
+       vuint32_t       sc;             /* 0xc10 0xe000ed10 System Control Register */
+       vuint32_t       cc;             /* 0xc14 0xe000ed14 Configuration Control Register */
+
+       vuint32_t       shpr7_4;        /* 0xc18 0xe000ed18 System Hander Priority Registers */
+       vuint32_t       shpr11_8;       /* 0xc1c */
+       vuint32_t       shpr15_12;      /* 0xc20 */
+
+       uint8_t         _unusedc18[0xe00 - 0xc24];
+
+       vuint32_t       stir;           /* 0xe00 */
+};
+
+extern struct stm_nvic stm_nvic;
+
+#define stm_nvic (*((struct stm_nvic *) 0xe000e100))
+
+#define IRQ_REG(irq)   ((irq) >> 5)
+#define IRQ_BIT(irq)   ((irq) & 0x1f)
+#define IRQ_MASK(irq)  (1 << IRQ_BIT(irq))
+#define IRQ_BOOL(v,irq)        (((v) >> IRQ_BIT(irq)) & 1)
+
+static inline void
+stm_nvic_set_enable(int irq) {
+       stm_nvic.iser[IRQ_REG(irq)] = IRQ_MASK(irq);
+}
+
+static inline void
+stm_nvic_clear_enable(int irq) {
+       stm_nvic.icer[IRQ_REG(irq)] = IRQ_MASK(irq);
+}
+
+static inline int
+stm_nvic_enabled(int irq) {
+       return IRQ_BOOL(stm_nvic.iser[IRQ_REG(irq)], irq);
+}
+
+static inline void
+stm_nvic_set_pending(int irq) {
+       stm_nvic.ispr[IRQ_REG(irq)] = IRQ_MASK(irq);
+}
+
+static inline void
+stm_nvic_clear_pending(int irq) {
+       stm_nvic.icpr[IRQ_REG(irq)] = IRQ_MASK(irq);
+}
+
+static inline int
+stm_nvic_pending(int irq) {
+       return IRQ_BOOL(stm_nvic.ispr[IRQ_REG(irq)], irq);
+}
+
+static inline int
+stm_nvic_active(int irq) {
+       return IRQ_BOOL(stm_nvic.iabr[IRQ_REG(irq)], irq);
+}
+
+#define IRQ_PRIO_REG(irq)      ((irq) >> 2)
+#define IRQ_PRIO_BIT(irq)      (((irq) & 3) << 3)
+#define IRQ_PRIO_MASK(irq)     (0xff << IRQ_PRIO_BIT(irq))
+
+static inline void
+stm_nvic_set_priority(int irq, uint8_t prio) {
+       int             n = IRQ_PRIO_REG(irq);
+       uint32_t        v;
+
+       v = stm_nvic.ipr[n];
+       v &= (uint32_t) ~IRQ_PRIO_MASK(irq);
+       v |= (prio) << IRQ_PRIO_BIT(irq);
+       stm_nvic.ipr[n] = v;
+}
+
+static inline uint8_t
+stm_nvic_get_priority(int irq) {
+       return (stm_nvic.ipr[IRQ_PRIO_REG(irq)] >> IRQ_PRIO_BIT(irq)) & IRQ_PRIO_MASK(0);
+}
+
+struct stm_flash_data {
+       vuint16_t       f_size;
+       vuint16_t       unused02;
+       vuint32_t       unused04;
+       vuint32_t       device_id[3];
+};
+
+extern struct stm_flash_data   stm_flash_data;
+
+static inline uint32_t stm_flash_size(void) { return (uint32_t) stm_flash_data.f_size * 1024; }
+
+#define stm_flash_data (*((struct stm_flash_data *) 0x1ffff7e0))
+
+struct stm_gpio {
+       vuint32_t       cr[2];
+       vuint32_t       idr;
+       vuint32_t       odr;
+
+       vuint32_t       bsrr;
+       vuint32_t       brr;
+       vuint32_t       lckr;
+};
+
+#define STM_GPIO_CR(y)         ((uint8_t) (y) >> 3)
+#define STM_GPIO_CR_CNF(y)     ((((uint8_t) (y) & 7) << 2) + 2)
+#define  STM_GPIO_CR_CNF_INPUT_ANALOG          0
+#define  STM_GPIO_CR_CNF_INPUT_FLOATING                1
+#define  STM_GPIO_CR_CNF_INPUT_PULL            2
+#define  STM_GPIO_CR_CNF_OUTPUT_PUSH_PULL      0
+#define         STM_GPIO_CR_CNF_OUTPUT_OPEN_DRAIN      1
+#define         STM_GPIO_CR_CNF_OUTPUT_AF_PUSH_PULL    2
+#define         STM_GPIO_CR_CNF_OUTPUT_AF_OPEN_DRAIN   3
+#define  STM_GPIO_CR_CNF_MASK                  3U
+#define STM_GPIO_CR_MODE(y)    ((((y) & 7) << 2))
+#define  STM_GPIO_CR_MODE_INPUT                        0
+#define  STM_GPIO_CR_MODE_OUTPUT_10MHZ         1
+#define  STM_GPIO_CR_MODE_OUTPUT_2MHZ          2
+#define  STM_GPIO_CR_MODE_OUTPUT_50MHZ         3
+#define  STM_GPIO_CR_MODE_MASK                 3U
+
+static inline void
+stm_gpio_conf(struct stm_gpio *gpio, int pin, uint8_t mode, uint8_t cnf)
+{
+       uint8_t         cr = STM_GPIO_CR(pin);
+       uint32_t        v = gpio->cr[cr];
+
+       v &= ~((STM_GPIO_CR_CNF_MASK << STM_GPIO_CR_CNF(pin)) |
+              (STM_GPIO_CR_MODE_MASK << STM_GPIO_CR_MODE(pin)));
+       v |= (mode << STM_GPIO_CR_MODE(pin)) | (cnf << STM_GPIO_CR_CNF(pin));
+       gpio->cr[cr] = v;
+}
+
+static inline void
+stm_gpio_set(struct stm_gpio *gpio, int pin, uint8_t value) {
+       /* Use the bit set/reset register to do this atomically */
+       gpio->bsrr = ((uint32_t) (value ^ 1) << (pin + 16)) | ((uint32_t) value << pin);
+}
+
+static inline void
+stm_gpio_set_mask(struct stm_gpio *gpio, uint16_t bits, uint16_t mask) {
+       /* Use the bit set/reset register to do this atomically */
+       gpio->bsrr = ((uint32_t) (~bits & mask) << 16) | ((uint32_t) (bits & mask));
+}
+
+static inline void
+stm_gpio_set_bits(struct stm_gpio *gpio, uint16_t bits) {
+       gpio->bsrr = bits;
+}
+
+static inline void
+stm_gpio_clr_bits(struct stm_gpio *gpio, uint16_t bits) {
+       gpio->bsrr = ((uint32_t) bits) << 16;
+}
+
+static inline uint8_t
+stm_gpio_get(struct stm_gpio *gpio, int pin) {
+       return (gpio->idr >> pin) & 1;
+}
+
+static inline uint16_t
+stm_gpio_get_all(struct stm_gpio *gpio) {
+       return (uint16_t) gpio->idr;
+}
+
+extern struct stm_gpio stm_gpioa;
+extern struct stm_gpio stm_gpiob;
+extern struct stm_gpio stm_gpioc;
+extern struct stm_gpio stm_gpiod;
+extern struct stm_gpio stm_gpioe;
+
+#define stm_gpioe  (*((struct stm_gpio *) 0x40011800))
+#define stm_gpiod  (*((struct stm_gpio *) 0x40011400))
+#define stm_gpioc  (*((struct stm_gpio *) 0x40011000))
+#define stm_gpiob  (*((struct stm_gpio *) 0x40010c00))
+#define stm_gpioa  (*((struct stm_gpio *) 0x40010800))
+
+struct stm_afio {
+       vuint32_t       evcr;
+       vuint32_t       mapr;
+       vuint32_t       exticr[4];
+       vuint32_t       mapr2;
+};
+
+extern struct stm_afio stm_afio;
+
+#define stm_afio       (*((struct stm_afio *) 0x40010000))
+
+#define isr_decl(name) void stm_ ## name ## _isr(void)
+
+isr_decl(halt);
+isr_decl(ignore);
+
+isr_decl(nmi);
+isr_decl(hardfault);
+isr_decl(memmanage);
+isr_decl(busfault);
+isr_decl(usagefault);
+isr_decl(svc);
+isr_decl(debugmon);
+isr_decl(pendsv);
+isr_decl(systick);
+isr_decl(wwdg);
+isr_decl(pvd);
+isr_decl(tamper_stamp);
+isr_decl(rtc_wkup);
+isr_decl(flash);
+isr_decl(rcc);
+isr_decl(exti0);
+isr_decl(exti1);
+isr_decl(exti2);
+isr_decl(exti3);
+isr_decl(exti4);
+isr_decl(dma1_channel1);
+isr_decl(dma1_channel2);
+isr_decl(dma1_channel3);
+isr_decl(dma1_channel4);
+isr_decl(dma1_channel5);
+isr_decl(dma1_channel6);
+isr_decl(dma1_channel7);
+isr_decl(adc1_2);
+isr_decl(usb_hp);
+isr_decl(usb_lp);
+isr_decl(can_rx1);
+isr_decl(can_sce);
+isr_decl(exti9_5);
+isr_decl(tim1_brk);
+isr_decl(tim1_up);
+isr_decl(tim1_trg_com);
+isr_decl(tim1_cc);
+isr_decl(tim2);
+isr_decl(tim3);
+isr_decl(tim4);
+isr_decl(i2c1_ev);
+isr_decl(i2c1_er);
+isr_decl(i2c2_ev);
+isr_decl(i2c2_er);
+isr_decl(spi1);
+isr_decl(spi2);
+isr_decl(usart1);
+isr_decl(usart2);
+isr_decl(usart3);
+isr_decl(exti15_10);
+isr_decl(rtc_alarm);
+isr_decl(usb_wakeup);
+isr_decl(tim8_brk);
+isr_decl(tim8_up);
+isr_decl(tim8_trg_com);
+isr_decl(tim8_cc);
+isr_decl(adc3);
+isr_decl(fsmc);
+isr_decl(sdio);
+isr_decl(tim5);
+isr_decl(spi3);
+isr_decl(uart4);
+isr_decl(uart5);
+isr_decl(tim6);
+isr_decl(tim7);
+isr_decl(dma2_channel1);
+isr_decl(dma2_channel2);
+isr_decl(dma2_channel3);
+isr_decl(dma2_channel4_5);
+
+#undef isr_decl
+
+#endif
diff --git a/src/stm32f103-nucleo/Makefile b/src/stm32f103-nucleo/Makefile
new file mode 100644 (file)
index 0000000..3adc4ac
--- /dev/null
@@ -0,0 +1,39 @@
+include ../stm32f1/Makefile-raw.defs
+
+INC = \
+       ao.h \
+       ao_pins.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       stm32f1.h \
+       Makefile
+
+ALTOS_SRC = \
+       ao_clock.c \
+       ao_timer.c \
+       ao_interrupt.c \
+       ao_led.c
+
+CFLAGS = $(PRODUCT_DEF) $(STM32F1_CFLAGS)
+
+PROGNAME=nucleo
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) hello.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ)
+       $(call quiet,CC) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) --oslib=semihost
+
+$(OBJ): $(INC)
+
+clean:
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx $(PROGNAME)-*.map
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/stm32f103-nucleo/ao_pins.h b/src/stm32f103-nucleo/ao_pins.h
new file mode 100644 (file)
index 0000000..37adc39
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define AO_HSE         1
+#define AO_HSE_BYPASS  1
+
+#define AO_SYSCLK      72000000
+#define AO_HCLK                72000000
+#define AO_APB1CLK     36000000
+#define AO_APB2CLK     72000000
+#define AO_ADCCLK      12000000
+
+#define AO_RCC_CFGR_USBPRE     STM_RCC_CFGR_USBPRE_1_5
+#define AO_RCC_CFGR_PLLMUL     STM_RCC_CFGR_PLLMUL_9
+#define AO_RCC_CFGR_PLLXTPRE   STM_RCC_CFGR_PLLXTPRE_1
+#define AO_RCC_CFGR_PPRE2_DIV  STM_RCC_CFGR_PPRE2_DIV_1
+#define AO_RCC_CFGR_PPRE1_DIV  STM_RCC_CFGR_PPRE1_DIV_2
+#define AO_RCC_CFGR_HPRE_DIV   STM_RCC_CFGR_HPRE_DIV_1
+#define AO_RCC_CFGR_ADCPRE     STM_RCC_CFGR_ADCPRE_6
+
+#define HAS_LED                1
+#define LED_0_PORT     (&stm_gpioa)
+#define LED_0_PIN      5
+#define AO_LED_GREEN   (1 << 0)
diff --git a/src/stm32f103-nucleo/hello.c b/src/stm32f103-nucleo/hello.c
new file mode 100644 (file)
index 0000000..938afd2
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2023 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+void
+ao_delay(AO_TICK_TYPE ticks)
+{
+       uint32_t then = ao_time();
+       while ((int32_t) (ao_time() - then) < (int32_t) ticks)
+               ao_arch_nop();
+}
+
+int main(void)
+{
+       ao_clock_init();
+       ao_timer_init();
+       ao_led_init();
+       for (;;) {
+               ao_led_for(AO_LED_GREEN, 50);
+               ao_delay(50);
+       }
+}
diff --git a/src/stm32f103-nucleo/hello.ld b/src/stm32f103-nucleo/hello.ld
new file mode 100644 (file)
index 0000000..cc57e00
--- /dev/null
@@ -0,0 +1,7 @@
+__flash = 0x20000000;
+__flash_size = 4k;
+__ram   = 0x20001000;
+__ram_size = 4k;
+__stack_size = 512;
+
+INCLUDE picolibc.ld