summaryrefslogtreecommitdiff
path: root/src/cortexelf-v1
diff options
context:
space:
mode:
Diffstat (limited to 'src/cortexelf-v1')
-rw-r--r--src/cortexelf-v1/Makefile137
-rw-r--r--src/cortexelf-v1/ao_1802.c328
-rw-r--r--src/cortexelf-v1/ao_1802.h129
-rw-r--r--src/cortexelf-v1/ao_cortexelf.c291
-rw-r--r--src/cortexelf-v1/ao_flip_bits.5c24
-rw-r--r--src/cortexelf-v1/ao_hex.c36
-rw-r--r--src/cortexelf-v1/ao_hex.h21
-rw-r--r--src/cortexelf-v1/ao_lisp_os.h65
-rw-r--r--src/cortexelf-v1/ao_lisp_os_save.c53
-rw-r--r--src/cortexelf-v1/ao_pins.h265
-rw-r--r--src/cortexelf-v1/cortexelf.ld101
-rw-r--r--src/cortexelf-v1/flash-loader/Makefile8
-rw-r--r--src/cortexelf-v1/flash-loader/ao_pins.h35
13 files changed, 1493 insertions, 0 deletions
diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile
new file mode 100644
index 00000000..8cc6ce31
--- /dev/null
+++ b/src/cortexelf-v1/Makefile
@@ -0,0 +1,137 @@
+#
+# AltOS build
+#
+#
+
+include ../stm/Makefile.defs
+LDFLAGS=-L../stm -Wl,-Tcortexelf.ld
+
+INC = \
+ ao.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_boot.h \
+ ao_pins.h \
+ ao_kalman.h \
+ ao_product.h \
+ ao_profile.h \
+ ao_task.h \
+ math.h \
+ ao_mpu.h \
+ stm32l.h \
+ math.h \
+ ao_vga.h \
+ ao_draw.h \
+ ao_draw_int.h \
+ ao_font.h \
+ ao_ps2.h \
+ ao_lisp.h \
+ ao_lisp_const.h \
+ ao_lisp_os.h \
+ ao_flip_bits.h \
+ Makefile
+
+#PROFILE=ao_profile.c
+#PROFILE_DEF=-DAO_PROFILE=1
+
+#STACK_GUARD=ao_mpu_stm.c
+#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
+
+
+ALTOS_SRC = \
+ ao_boot_chain.c \
+ ao_interrupt.c \
+ ao_product.c \
+ ao_romconfig.c \
+ ao_cmd.c \
+ ao_config.c \
+ ao_task.c \
+ ao_stdio.c \
+ ao_panic.c \
+ ao_timer.c \
+ ao_mutex.c \
+ ao_serial_stm.c \
+ ao_dma_stm.c \
+ ao_spi_stm.c \
+ ao_usb_stm.c \
+ ao_exti_stm.c \
+ ao_i2c_stm.c \
+ ao_as1107.c \
+ ao_matrix.c \
+ ao_vga.c \
+ ao_blt.c \
+ ao_copy.c \
+ ao_rect.c \
+ ao_text.c \
+ ao_line.c \
+ ao_ps2.c \
+ ao_console.c \
+ ao_sdcard.c \
+ ao_bufio.c \
+ ao_fat.c \
+ ao_flash_stm.c \
+ ao_button.c \
+ ao_event.c \
+ ao_1802.c \
+ ao_hex.c \
+ ao_lisp_lex.c \
+ ao_lisp_mem.c \
+ ao_lisp_cons.c \
+ ao_lisp_eval.c \
+ ao_lisp_string.c \
+ ao_lisp_atom.c \
+ ao_lisp_int.c \
+ ao_lisp_poly.c \
+ ao_lisp_builtin.c \
+ ao_lisp_read.c \
+ ao_lisp_rep.c \
+ ao_lisp_frame.c \
+ ao_lisp_error.c \
+ ao_lisp_lambda.c \
+ ao_lisp_save.c \
+ ao_lisp_stack.c \
+ ao_lisp_os_save.c \
+ $(PROFILE) \
+ $(SAMPLE_PROFILE) \
+ $(STACK_GUARD)
+
+PRODUCT=CortexELF-v1
+PRODUCT_DEF=-DCORTEXELF
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+
+PROGNAME=cortexelf-v1
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_cortexelf.c
+OBJ=$(SRC:.c=.o)
+
+all:: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) cortexelf.ld
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+../altitude-pa.h: make-altitude-pa
+ nickle $< > $@
+
+$(OBJ): $(INC)
+
+ao_product.h: ao-make-product.5c ../Version
+ $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean: clean
+
+clean::
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+ rm -f ao_product.h ao_flip_bits.h
+
+ao_flip_bits.h: ao_flip_bits.5c
+ nickle ao_flip_bits.5c > $@
+
+include ../lisp/Makefile-lisp
+
+install:
+
+uninstall:
diff --git a/src/cortexelf-v1/ao_1802.c b/src/cortexelf-v1/ao_1802.c
new file mode 100644
index 00000000..9fb36595
--- /dev/null
+++ b/src/cortexelf-v1/ao_1802.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#include <ao.h>
+#include <ao_flip_bits.h>
+#include <ao_1802.h>
+#include <ao_exti.h>
+
+/* Decoded address driven by TPA/TPB signals */
+uint16_t ADDRESS;
+
+/* Decoded data, driven by TPB signal */
+uint8_t DATA;
+
+/* Mux control */
+#define _MUX_1802 0
+#define _MUX_STM 1
+
+uint8_t MUX_CONTROL;
+
+/* Signals muxed between 1802 and STM */
+uint8_t
+MRD(void) {
+ return ao_gpio_get(MRD_PORT, MRD_BIT, MRD_PIN);
+}
+
+void
+MRD_set(uint8_t value) {
+ ao_gpio_set(MRD_PORT, MRD_BIT, MRD_PIN, value);
+}
+
+uint8_t
+MWR(void) {
+ return ao_gpio_get(MWR_PORT, MWR_BIT, MWR_PIN);
+}
+
+void
+MWR_set(uint8_t value) {
+ ao_gpio_set(MWR_PORT, MWR_BIT, MWR_PIN, value);
+}
+
+static void
+TPA_rising(void)
+{
+ ADDRESS = (ADDRESS & 0x00ff) | ((uint16_t) MA() << 8);
+ ao_wakeup(&ADDRESS);
+}
+
+uint8_t
+TPA(void) {
+ return ao_gpio_get(TPA_PORT, TPA_BIT, TPA_PIN);
+}
+
+void
+TPA_set(uint8_t tpa) {
+ ao_gpio_set(TPA_PORT, TPA_BIT, TPA_PIN, tpa);
+ if (tpa)
+ TPA_rising();
+}
+
+static void
+TPB_rising(void)
+{
+ ADDRESS = (ADDRESS & 0xff00) | MA();
+ if (MWR() == 0 || MRD() == 0)
+ DATA = BUS();
+ ao_wakeup(&ADDRESS);
+}
+
+static void
+TPB_falling(void)
+{
+}
+
+uint8_t
+TPB(void) {
+ return ao_gpio_get(TPB_PORT, TPB_BIT, TPB_PIN);
+}
+
+void
+TPB_set(uint8_t tpb) {
+ ao_gpio_set(TPB_PORT, TPB_BIT, TPB_PIN, tpb);
+ if (tpb)
+ TPB_rising();
+ else
+ TPB_falling();
+}
+
+uint8_t
+MA(void) {
+ return (ao_gpio_get_all(MA_PORT) >> MA_SHIFT) & MA_MASK;
+}
+
+void
+MA_set(uint8_t ma) {
+ ao_gpio_set_mask(MA_PORT, ((uint16_t) ma) << MA_SHIFT, MA_MASK << MA_SHIFT);
+}
+
+/* Tri-state data bus */
+
+uint8_t
+BUS(void) {
+ return ao_flip_bits_8[(ao_gpio_get_all(BUS_PORT) >> BUS_SHIFT) & BUS_MASK];
+}
+
+void
+BUS_set(uint8_t bus) {
+ ao_gpio_set_mask(BUS_PORT, ao_flip_bits_8[bus] << BUS_SHIFT, BUS_MASK << BUS_SHIFT);
+}
+
+void
+BUS_stm(void)
+{
+ ao_set_output_mask(BUS_PORT, BUS_MASK << BUS_SHIFT);
+}
+
+void
+BUS_1802(void)
+{
+ ao_set_input_mask(BUS_PORT, BUS_MASK << BUS_SHIFT);
+}
+
+/* Pins controlled by 1802 */
+uint8_t
+SC(void) {
+ return ao_flip_bits_2[(ao_gpio_get_all(SC_PORT) >> SC_SHIFT) & SC_MASK];
+}
+
+uint8_t
+Q(void) {
+ return ao_gpio_get(Q_PORT, Q_BIT, Q_PIN);
+}
+
+uint8_t
+N(void) {
+ return (ao_gpio_get_all(N_PORT) >> N_SHIFT) & N_MASK;
+}
+
+/* Pins controlled by STM */
+uint8_t
+EF(void) {
+ return (ao_gpio_get_all(EF_PORT) >> EF_SHIFT) & EF_MASK;
+}
+
+void
+EF_set(uint8_t ef) {
+ ao_gpio_set_mask(EF_PORT, ef << EF_SHIFT, EF_MASK << EF_SHIFT);
+}
+
+uint8_t
+DMA_IN(void) {
+ return ao_gpio_get(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN);
+}
+
+void
+DMA_IN_set(uint8_t dma_in) {
+ ao_gpio_set(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN, dma_in);
+}
+
+uint8_t
+DMA_OUT(void) {
+ return ao_gpio_get(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN);
+}
+
+void
+DMA_OUT_set(uint8_t dma_out) {
+ ao_gpio_set(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN, dma_out);
+}
+
+uint8_t
+INT(void) {
+ return ao_gpio_get(INT_PORT, INT_BIT, INT_PIN);
+}
+
+void
+INT_set(uint8_t dma_out) {
+ ao_gpio_set(INT_PORT, INT_BIT, INT_PIN, dma_out);
+}
+
+uint8_t
+CLEAR(void) {
+ return ao_gpio_get(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN);
+}
+
+void
+CLEAR_set(uint8_t dma_out) {
+ ao_gpio_set(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN, dma_out);
+}
+
+uint8_t
+WAIT(void) {
+ return ao_gpio_get(WAIT_PORT, WAIT_BIT, WAIT_PIN);
+}
+
+void
+WAIT_set(uint8_t dma_out) {
+ ao_gpio_set(WAIT_PORT, WAIT_BIT, WAIT_PIN, dma_out);
+}
+
+void
+tpb_isr(void) {
+ /* Latch low address and data on rising edge of TPB */
+ if (TPB())
+ TPB_rising();
+ else
+ TPB_falling();
+}
+
+void
+tpa_isr(void) {
+ /* Latch high address on rising edge of TPA */
+ if (TPA())
+ TPA_rising();
+}
+
+#define ao_1802_in(port, bit, mode) do { \
+ ao_gpio_set_mode(port, bit, mode); \
+ ao_set_input(port, bit); \
+ } while (0)
+
+#define ao_1802_in_isr(port, bit, mode) do { \
+ ao_gpio_set_mode(port, bit, mode); \
+ ao_set_input(port, bit); \
+ ao_exti_enable(port, bit); \
+ } while (0)
+
+#define ao_1802_out_isr(port, bit) do { \
+ ao_exti_disable(port, bit); \
+ ao_set_output(port, bit); \
+ } while (0)
+
+void
+MUX_1802(void)
+{
+ if (MUX_CONTROL != _MUX_1802) {
+ /* Set pins to input, but pulled to idle value */
+ ao_1802_in(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP);
+ ao_1802_in(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP);
+ ao_1802_in_isr(TPB_PORT, TPB_BIT, AO_EXTI_MODE_PULL_DOWN);
+ ao_1802_in_isr(TPA_PORT, TPA_BIT, AO_EXTI_MODE_PULL_DOWN);
+ ao_set_input_mask(MA_PORT, MA_MASK << MA_SHIFT);
+
+ ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 0);
+
+ /* Now change the pins to eliminate the pull up/down */
+ ao_gpio_set_mode(MRD_PORT, MRD_BIT, 0);
+ ao_gpio_set_mode(MWR_PORT, MWR_BIT, 0);
+ ao_gpio_set_mode(TPB_PORT, TPB_BIT, 0);
+ ao_gpio_set_mode(TPA_PORT, TPA_BIT, 0);
+
+ MUX_CONTROL = _MUX_1802;
+ }
+}
+
+void
+MUX_stm(void)
+{
+ if (MUX_CONTROL != _MUX_STM) {
+ /* Set the pins back to pull to the idle value */
+ ao_gpio_set_mode(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP);
+ ao_gpio_set_mode(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP);
+ ao_gpio_set_mode(TPB_PORT, TPB_BIT, AO_EXTI_MODE_PULL_DOWN);
+ ao_gpio_set_mode(TPA_PORT, TPA_BIT, AO_EXTI_MODE_PULL_DOWN);
+
+ ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 1);
+
+ /* Now set the pins as output, driven to the idle value */
+ ao_set_output(MRD_PORT, MRD_BIT, MRD_PIN, 1);
+ ao_set_output(MWR_PORT, MWR_BIT, MWR_PIN, 1);
+ ao_set_output(TPB_PORT, TPB_BIT, TPB_PIN, 0);
+ ao_set_output(TPA_PORT, TPA_BIT, TPA_PIN, 0);
+ ao_set_output_mask(MA_PORT, MA_MASK << MA_SHIFT);
+ MUX_CONTROL = _MUX_STM;
+ }
+}
+
+void
+ao_1802_init(void)
+{
+ /* Multiplexed signals*/
+
+ /* active low signals */
+ ao_enable_input(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP);
+ ao_enable_input(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP);
+
+ /* active high signals with interrupts */
+ ao_exti_setup(TPA_PORT, TPA_BIT,
+ AO_EXTI_MODE_PULL_DOWN | AO_EXTI_MODE_RISING | AO_EXTI_MODE_FALLING,
+ tpa_isr);
+ ao_exti_setup(TPB_PORT, TPB_BIT,
+ AO_EXTI_MODE_PULL_DOWN | AO_EXTI_MODE_RISING | AO_EXTI_MODE_FALLING,
+ tpb_isr);
+
+ /* multiplexed address bus */
+ ao_enable_input_mask(MA_PORT, MA_MASK << MA_SHIFT, 0);
+
+ /* Data bus */
+
+ ao_enable_input_mask(BUS_PORT, BUS_MASK << BUS_SHIFT, 0);
+
+ /* Pins controlled by 1802 */
+ ao_enable_input_mask(SC_PORT, SC_MASK << SC_SHIFT, 0);
+ ao_enable_input(Q_PORT, Q_BIT, 0);
+ ao_enable_input_mask(N_PORT, N_MASK << N_SHIFT, 0);
+
+ /* Pins controlled by STM */
+ ao_enable_output_mask(EF_PORT, 0, EF_MASK << EF_SHIFT);
+ ao_enable_output(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN, 1);
+ ao_enable_output(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN, 1);
+ ao_enable_output(INT_PORT, INT_BIT, INT_PIN, 1);
+ ao_enable_output(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN, 1);
+ ao_enable_output(WAIT_PORT, WAIT_BIT, WAIT_PIN, 1);
+
+ /* Force configuration to STM so that MUX_1802 will do something */
+ MUX_CONTROL = _MUX_STM;
+ MUX_1802();
+}
diff --git a/src/cortexelf-v1/ao_1802.h b/src/cortexelf-v1/ao_1802.h
new file mode 100644
index 00000000..5ea89fee
--- /dev/null
+++ b/src/cortexelf-v1/ao_1802.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#ifndef _AO_1802_H_
+#define _AO_1802_H_
+
+/* Decoded address driven by TPA/TPB signals */
+extern uint16_t ADDRESS;
+
+/* Decoded data, driven by TPB signal */
+extern uint8_t DATA;
+
+uint8_t
+MRD(void);
+
+void
+MRD_set(uint8_t value);
+
+uint8_t
+MWR(void);
+
+void
+MWR_set(uint8_t value);
+
+uint8_t
+TPA(void);
+
+void
+TPA_set(uint8_t tpa);
+
+uint8_t
+TPB(void);
+
+void
+TPB_set(uint8_t tpb);
+
+uint8_t
+MA(void);
+
+void
+MA_set(uint8_t ma);
+
+/* Tri-state data bus */
+
+uint8_t
+BUS(void);
+
+void
+BUS_set(uint8_t bus);
+
+void
+BUS_stm(void);
+
+void
+BUS_1802(void);
+
+/* Pins controlled by 1802 */
+uint8_t
+SC(void);
+
+uint8_t
+Q(void);
+
+uint8_t
+N(void);
+
+/* Pins controlled by STM */
+uint8_t
+EF(void);
+
+void
+EF_set(uint8_t ef);
+
+uint8_t
+DMA_IN(void);
+
+void
+DMA_IN_set(uint8_t dma_in);
+
+uint8_t
+DMA_OUT(void);
+
+void
+DMA_OUT_set(uint8_t dma_out);
+
+uint8_t
+INT(void);
+
+void
+INT_set(uint8_t dma_out);
+
+uint8_t
+CLEAR(void);
+
+void
+CLEAR_set(uint8_t dma_out);
+
+uint8_t
+WAIT(void);
+
+void
+WAIT_set(uint8_t dma_out);
+
+#define SC_FETCH 0
+#define SC_EXECUTE 1
+#define SC_DMA 2
+#define SC_INTERRUPT 3
+
+void
+MUX_1802(void);
+
+void
+MUX_stm(void);
+
+void
+ao_1802_init(void);
+
+#endif /* _AO_1802_H_ */
diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c
new file mode 100644
index 00000000..61a9d219
--- /dev/null
+++ b/src/cortexelf-v1/ao_cortexelf.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright © 2011 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_exti.h>
+#include <ao_profile.h>
+#if HAS_STACK_GUARD
+#include <ao_mpu.h>
+#endif
+#include <ao_ps2.h>
+#include <ao_vga.h>
+#include <ao_console.h>
+#include <ao_sdcard.h>
+#include <ao_fat.h>
+#include <ao_lisp.h>
+#include <ao_button.h>
+#include <ao_event.h>
+#include <ao_as1107.h>
+#include <ao_hex.h>
+#include <ao_1802.h>
+
+struct ao_task ball_task;
+
+#define BALL_WIDTH 5
+#define BALL_HEIGHT 5
+
+static int ball_x;
+static int ball_y;
+static int ball_dx, ball_dy;
+
+uint8_t ball_enable;
+
+void
+ao_ball(void)
+{
+ ball_dx = 1;
+ ball_dy = 1;
+ ball_x = 0;
+ ball_y = 0;
+ for (;;) {
+ while (!ball_enable)
+ ao_sleep(&ball_enable);
+ for (;;) {
+ ao_line(&ao_vga_bitmap,
+ -100, -100, ball_x*2, ball_y*2,
+ 1, AO_XOR);
+ ao_text(&ao_vga_bitmap,
+ ball_x, ball_y - 10,
+ "Hello, Bdale!",
+ 1, AO_XOR);
+ ao_rect(&ao_vga_bitmap,
+ ball_x, ball_y,
+ BALL_WIDTH,
+ BALL_HEIGHT,
+ 1,
+ AO_XOR);
+ ao_delay(AO_MS_TO_TICKS(10));
+ ao_rect(&ao_vga_bitmap,
+ ball_x, ball_y,
+ BALL_WIDTH,
+ BALL_HEIGHT,
+ 1,
+ AO_XOR);
+ ao_text(&ao_vga_bitmap,
+ ball_x, ball_y - 10,
+ "Hello, Bdale!",
+ 1, AO_XOR);
+ ao_line(&ao_vga_bitmap,
+ -100, -100, ball_x*2, ball_y*2,
+ 1, AO_XOR);
+ if (!ball_enable)
+ break;
+ ball_x += ball_dx;
+ ball_y += ball_dy;
+ if (ball_x + BALL_WIDTH > AO_VGA_WIDTH) {
+ ball_x = AO_VGA_WIDTH - BALL_WIDTH;
+ ball_dx = -ball_dx;
+ }
+ if (ball_x < 0) {
+ ball_x = -ball_x;
+ ball_dx = -ball_dx;
+ }
+ if (ball_y + BALL_HEIGHT > AO_VGA_HEIGHT) {
+ ball_y = AO_VGA_HEIGHT - BALL_HEIGHT;
+ ball_dy = -ball_dy;
+ }
+ if (ball_y < 0) {
+ ball_y = -ball_y;
+ ball_dy = -ball_dy;
+ }
+ }
+ }
+}
+
+static void
+ao_fb_init(void)
+{
+ ao_rect(&ao_vga_bitmap,
+ 0, 0, AO_VGA_WIDTH, AO_VGA_HEIGHT,
+ 1, AO_COPY);
+
+ ao_rect(&ao_vga_bitmap,
+ 10, 10, 10, 10,
+ 0, AO_COPY);
+
+ ao_rect(&ao_vga_bitmap,
+ AO_VGA_WIDTH - 20, 10, 10, 10,
+ 0, AO_COPY);
+
+ ao_rect(&ao_vga_bitmap,
+ 10, AO_VGA_HEIGHT - 20, 10, 10,
+ 0, AO_COPY);
+
+ ao_rect(&ao_vga_bitmap,
+ AO_VGA_WIDTH - 20, AO_VGA_HEIGHT - 20, 10, 10,
+ 0, AO_COPY);
+
+ ao_text(&ao_vga_bitmap,
+ 20, 100,
+ "Hello, Bdale!",
+ 0, AO_COPY);
+
+ ao_text(&ao_vga_bitmap,
+ 1, ao_font.ascent,
+ "UL",
+ 0, AO_COPY);
+
+ ao_text(&ao_vga_bitmap,
+ 1, AO_VGA_HEIGHT - ao_font.descent,
+ "BL",
+ 0, AO_COPY);
+}
+
+static void
+ao_video_toggle(void)
+{
+ ao_cmd_decimal();
+ if (ao_cmd_lex_i)
+ ao_fb_init();
+ ao_vga_enable(ao_cmd_lex_i);
+}
+
+static void
+ao_ball_toggle(void)
+{
+ ao_cmd_decimal();
+ ball_enable = ao_cmd_lex_i;
+ ao_wakeup(&ball_enable);
+}
+
+static void
+ao_ps2_read_keys(void)
+{
+ char c;
+
+ for (;;) {
+ c = ao_ps2_getchar();
+ printf("%02x %c\n", c, ' ' <= c && c < 0x7f ? c : '.');
+ flush();
+ if (c == ' ')
+ break;
+ }
+}
+
+static void
+ao_console_send(void)
+{
+ char c;
+
+ while ((c = getchar()) != '~') {
+ ao_console_putchar(c);
+ flush();
+ }
+}
+
+static void lisp_cmd() {
+ ao_lisp_read_eval_print();
+}
+
+static void
+ao_serial_blather(void)
+{
+ char c;
+
+ while ((c = getchar()) != '~') {
+ ao_serial1_putchar(c);
+ ao_serial2_putchar(c);
+ }
+}
+
+static void
+led_cmd(void)
+{
+ uint8_t start;
+ uint8_t value;
+ ao_cmd_decimal();
+
+ start = ao_cmd_lex_i;
+ ao_cmd_hex();
+ value = ao_cmd_lex_i;
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+ ao_as1107_write_8(start, value);
+}
+
+__code struct ao_cmds ao_demo_cmds[] = {
+ { ao_video_toggle, "V\0Toggle video" },
+ { ao_ball_toggle, "B\0Toggle ball" },
+ { ao_ps2_read_keys, "K\0Read keys from keyboard" },
+ { ao_console_send, "C\0Send data to console, end with ~" },
+ { ao_serial_blather, "S\0Blather on serial ports briefly" },
+ { lisp_cmd, "l\0Run lisp interpreter" },
+ { led_cmd, "L start value\0Show value (byte) at digit start" },
+ { 0, NULL }
+};
+
+static struct ao_task event_task;
+
+static void
+ao_event_loop(void)
+{
+ for (;;) {
+ struct ao_event ev;
+
+ ao_event_get(&ev);
+ printf("type %d uint %d tick %d value %d\n",
+ ev.type, ev.unit, ev.tick, ev.value);
+ flush();
+ }
+}
+
+int
+main(void)
+{
+ ao_clock_init();
+
+#if HAS_STACK_GUARD
+ ao_mpu_init();
+#endif
+
+ ao_task_init();
+ ao_serial_init();
+ ao_timer_init();
+
+ ao_spi_init();
+ ao_dma_init();
+ ao_exti_init();
+
+ ao_sdcard_init();
+ ao_fat_init();
+
+ ao_ps2_init();
+ ao_vga_init();
+ ao_console_init();
+
+ ao_cmd_init();
+
+ ao_usb_init();
+
+ ao_button_init();
+
+ ao_as1107_init();
+ ao_matrix_init();
+ ao_1802_init();
+
+ ao_hex_init();
+
+ ao_config_init();
+
+ ao_add_task(&ball_task, ao_ball, "ball");
+ ao_add_task(&event_task, ao_event_loop, "events");
+ ao_cmd_register(&ao_demo_cmds[0]);
+
+ ao_start_scheduler();
+ return 0;
+}
diff --git a/src/cortexelf-v1/ao_flip_bits.5c b/src/cortexelf-v1/ao_flip_bits.5c
new file mode 100644
index 00000000..cd5507cc
--- /dev/null
+++ b/src/cortexelf-v1/ao_flip_bits.5c
@@ -0,0 +1,24 @@
+#!/usr/bin/nickle
+
+int flip_bits(int a, int n)
+{
+ int result = 0;
+ for (int pos = 0; pos < n; pos++)
+ if ((a & (1 << pos)) != 0)
+ result |= (1 << (n - 1 - pos));
+ return result;
+}
+
+void print_flip_bits(string name, int n) {
+ printf ("static const uint8_t %s_%d[%d] = {\n", name, n, 1 << n);
+
+ for (int i = 0; i < 1 << n; i++) {
+ printf (" 0x%02x,", flip_bits(i, n));
+ if ((i & 0xf) == 0xf)
+ printf("\n");
+ }
+ printf("};\n");
+}
+
+print_flip_bits("ao_flip_bits", 8);
+print_flip_bits("ao_flip_bits", 2);
diff --git a/src/cortexelf-v1/ao_hex.c b/src/cortexelf-v1/ao_hex.c
new file mode 100644
index 00000000..1507407b
--- /dev/null
+++ b/src/cortexelf-v1/ao_hex.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#include <ao.h>
+#include "ao_hex.h"
+#include "ao_as1107.h"
+#include "ao_1802.h"
+
+static struct ao_task ao_hex_task;
+
+static void
+ao_hex(void)
+{
+ for (;;) {
+ ao_as1107_write_16(0, ADDRESS);
+ ao_as1107_write_8(6, DATA);
+ ao_sleep(&ADDRESS);
+ }
+}
+
+void
+ao_hex_init(void)
+{
+ ao_add_task(&ao_hex_task, ao_hex, "hex");
+}
diff --git a/src/cortexelf-v1/ao_hex.h b/src/cortexelf-v1/ao_hex.h
new file mode 100644
index 00000000..674c1eee
--- /dev/null
+++ b/src/cortexelf-v1/ao_hex.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#ifndef _AO_HEX_H_
+#define _AO_HEX_H_
+
+void
+ao_hex_init(void);
+
+#endif /* _AO_HEX_H_ */
diff --git a/src/cortexelf-v1/ao_lisp_os.h b/src/cortexelf-v1/ao_lisp_os.h
new file mode 100644
index 00000000..d0c1f7b7
--- /dev/null
+++ b/src/cortexelf-v1/ao_lisp_os.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2016 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; version 2 of the License.
+ *
+ * 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_LISP_OS_H_
+#define _AO_LISP_OS_H_
+
+#include "ao.h"
+
+#define AO_LISP_POOL_TOTAL 16384
+#define AO_LISP_SAVE 1
+
+static inline int
+ao_lisp_getc() {
+ static uint8_t at_eol;
+ int c;
+
+ if (at_eol) {
+ ao_cmd_readline();
+ at_eol = 0;
+ }
+ c = ao_cmd_lex();
+ if (c == '\n')
+ at_eol = 1;
+ return c;
+}
+
+static inline void
+ao_lisp_os_flush(void)
+{
+ flush();
+}
+
+static inline void
+ao_lisp_abort(void)
+{
+ ao_panic(1);
+}
+
+static inline void
+ao_lisp_os_led(int led)
+{
+ (void) led;
+}
+
+static inline void
+ao_lisp_os_delay(int delay)
+{
+ ao_delay(AO_MS_TO_TICKS(delay));
+}
+
+#endif
diff --git a/src/cortexelf-v1/ao_lisp_os_save.c b/src/cortexelf-v1/ao_lisp_os_save.c
new file mode 100644
index 00000000..7c853990
--- /dev/null
+++ b/src/cortexelf-v1/ao_lisp_os_save.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2016 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.
+ */
+
+#include <ao.h>
+#include <ao_lisp.h>
+#include <ao_flash.h>
+
+extern uint8_t __flash__[];
+
+/* saved variables to rebuild the heap
+
+ ao_lisp_atoms
+ ao_lisp_frame_global
+ */
+
+int
+ao_lisp_os_save(void)
+{
+ int i;
+
+ for (i = 0; i < AO_LISP_POOL_TOTAL; i += 256) {
+ uint32_t *dst = (uint32_t *) (void *) &__flash__[i];
+ uint32_t *src = (uint32_t *) (void *) &ao_lisp_pool[i];
+
+ ao_flash_page(dst, src);
+ }
+ return 1;
+}
+
+int
+ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset)
+{
+ memcpy(save, &__flash__[offset], sizeof (struct ao_lisp_os_save));
+ return 1;
+}
+
+int
+ao_lisp_os_restore(void)
+{
+ memcpy(ao_lisp_pool, __flash__, AO_LISP_POOL_TOTAL);
+ return 1;
+}
diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h
new file mode 100644
index 00000000..258ffe31
--- /dev/null
+++ b/src/cortexelf-v1/ao_pins.h
@@ -0,0 +1,265 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_TASK_QUEUE 1
+
+/* 8MHz High speed external crystal */
+#define AO_HSE 8000000
+
+/* PLLVCO = 96MHz (so that USB will work) */
+#define AO_PLLMUL 12
+#define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_12)
+
+/* SYSCLK = 24MHz */
+#define AO_PLLDIV 4
+#define AO_RCC_CFGR_PLLDIV (STM_RCC_CFGR_PLLDIV_4)
+
+/* HCLK = 24MHz (CPU clock) */
+#define AO_AHB_PRESCALER 1
+#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1
+
+/* Run APB1 at HCLK/1 */
+#define AO_APB1_PRESCALER 1
+#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE1_DIV_1
+
+/* Run APB2 at HCLK/1 */
+#define AO_APB2_PRESCALER 1
+#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_1
+
+/* Allow for non-maskable interrupts at priority 0 */
+#define AO_NONMASK_INTERRUPT 1
+
+/* PS/2 keyboard connection */
+#define AO_PS2_CLOCK_PORT (&stm_gpiod)
+#define AO_PS2_CLOCK_BIT 9
+#define AO_PS2_DATA_PORT (&stm_gpiod)
+#define AO_PS2_DATA_BIT 8
+
+#define HAS_SERIAL_1 1
+#define USE_SERIAL_1_STDIN 1
+#define SERIAL_1_PB6_PB7 1
+#define SERIAL_1_PA9_PA10 0
+
+#define HAS_SERIAL_2 1
+#define USE_SERIAL_2_STDIN 1
+#define SERIAL_2_PA2_PA3 0
+#define SERIAL_2_PD5_PD6 1
+
+#define HAS_SERIAL_3 0
+#define USE_SERIAL_3_STDIN 0
+#define SERIAL_3_PB10_PB11 0
+#define SERIAL_3_PC10_PC11 0
+#define SERIAL_3_PD8_PD9 0
+
+#define HAS_EEPROM 0
+#define USE_INTERNAL_FLASH 0
+#define USE_EEPROM_CONFIG 0
+#define USE_STORAGE_CONFIG 0
+#define HAS_USB 1
+#define HAS_BEEP 0
+#define HAS_BATTERY_REPORT 0
+#define HAS_RADIO 0
+#define HAS_TELEMETRY 0
+#define HAS_APRS 0
+#define HAS_COMPANION 0
+
+#define HAS_SPI_1 0
+#define SPI_1_PA5_PA6_PA7 0
+#define SPI_1_PB3_PB4_PB5 0
+#define SPI_1_PE13_PE14_PE15 0
+#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz
+
+#define HAS_SPI_2 1
+#define SPI_2_PB13_PB14_PB15 0
+#define SPI_2_PD1_PD3_PD4 1 /* LED displays, microSD */
+#define SPI_2_OSPEEDR STM_OSPEEDR_40MHz
+
+#define SPI_2_PORT (&stm_gpiod)
+//#define SPI_2_SCK_PIN 1
+//#define SPI_2_MISO_PIN 3
+//#define SPI_2_MOSI_PIN 4
+
+#define HAS_I2C_1 0
+#define I2C_1_PB8_PB9 0
+
+#define HAS_I2C_2 0
+#define I2C_2_PB10_PB11 0
+
+#define PACKET_HAS_SLAVE 0
+#define PACKET_HAS_MASTER 0
+
+#define LOW_LEVEL_DEBUG 0
+
+#define HAS_GPS 0
+#define HAS_FLIGHT 0
+#define HAS_ADC 0
+#define HAS_ADC_TEMP 0
+#define HAS_LOG 0
+
+#define NUM_CMDS 16
+
+/* SD card */
+#define AO_SDCARD_SPI_BUS AO_SPI_2_PD1_PD3_PD4
+#define AO_SDCARD_SPI_CS_PORT (&stm_gpiod)
+#define AO_SDCARD_SPI_CS_PIN 2
+#define AO_SDCARD_SPI_PORT (&stm_gpiod)
+#define AO_SDCARD_SPI_SCK_PIN 1
+#define AO_SDCARD_SPI_MISO_PIN 3
+#define AO_SDCARD_SPI_MOSI_PIN 4
+
+/* VGA */
+#define STM_DMA1_3_STOLEN 1
+/* Buttons */
+
+#define AO_EVENT 1
+
+#define AO_BUTTON_COUNT 4
+#define AO_BUTTON_MODE AO_EXTI_MODE_PULL_DOWN
+#define AO_BUTTON_INVERTED 0
+
+/* INPUT */
+#define AO_BUTTON_0_PORT (&stm_gpioc)
+#define AO_BUTTON_0 8
+
+/* MP */
+#define AO_BUTTON_1_PORT (&stm_gpioc)
+#define AO_BUTTON_1 9
+
+/* RUN */
+#define AO_BUTTON_2_PORT (&stm_gpioc)
+#define AO_BUTTON_2 10
+
+/* LOAD */
+#define AO_BUTTON_3_PORT (&stm_gpioc)
+#define AO_BUTTON_3 11
+
+/* AS1107 */
+#define AO_AS1107_NUM_DIGITS 8
+
+/* Set the hex digits up for decode, leave the extra leds alone */
+
+#define AO_AS1107_DECODE ((1 << 7) | \
+ (1 << 6) | \
+ (1 << 4) | \
+ (1 << 3) | \
+ (1 << 1) | \
+ (1 << 0))
+
+#define AO_AS1107_SPI_INDEX AO_SPI_2_PD1_PD3_PD4
+#define AO_AS1107_SPI_SPEED AO_SPI_SPEED_8MHz
+#define AO_AS1107_CS_PORT (&stm_gpiod)
+#define AO_AS1107_CS_PIN 0
+
+/* Hex keypad */
+
+#define AO_MATRIX_ROWS 4
+#define AO_MATRIX_COLS 4
+
+#define AO_MATRIX_KEYCODES { \
+ { 0x0, 0x1, 0x2, 0x3 }, \
+ { 0x4, 0x5, 0x6, 0x7 }, \
+ { 0x8, 0x9, 0xa, 0xb }, \
+ { 0xc, 0xd, 0xe, 0xf } \
+ }
+
+#include <ao_matrix.h>
+
+#define AO_TIMER_HOOK ao_matrix_poll()
+
+#define AO_MATRIX_ROW_0_PORT (&stm_gpioc)
+#define AO_MATRIX_ROW_0_PIN 4
+
+#define AO_MATRIX_ROW_1_PORT (&stm_gpioc)
+#define AO_MATRIX_ROW_1_PIN 1
+
+#define AO_MATRIX_ROW_2_PORT (&stm_gpioc)
+#define AO_MATRIX_ROW_2_PIN 7
+
+#define AO_MATRIX_ROW_3_PORT (&stm_gpioc)
+#define AO_MATRIX_ROW_3_PIN 0
+
+#define AO_MATRIX_COL_0_PORT (&stm_gpioc)
+#define AO_MATRIX_COL_0_PIN 2
+
+#define AO_MATRIX_COL_1_PORT (&stm_gpioc)
+#define AO_MATRIX_COL_1_PIN 3
+
+#define AO_MATRIX_COL_2_PORT (&stm_gpioc)
+#define AO_MATRIX_COL_2_PIN 5
+
+#define AO_MATRIX_COL_3_PORT (&stm_gpioc)
+#define AO_MATRIX_COL_3_PIN 6
+
+/* 1802 connections */
+#define MRD_PORT (&stm_gpiob)
+#define MRD_BIT 15
+
+#define MWR_PORT (&stm_gpioa)
+#define MWR_BIT 3
+
+#define TPB_PORT (&stm_gpioa)
+#define TPB_BIT 7
+
+#define TPA_PORT (&stm_gpioa)
+#define TPA_BIT 6
+
+#define MA_PORT (&stm_gpioe)
+#define MA_SHIFT 0
+#define MA_MASK 0xff
+
+#define BUS_PORT (&stm_gpioe)
+#define BUS_SHIFT 8
+#define BUS_MASK 0xff
+
+#define SC_PORT (&stm_gpiob)
+#define SC_SHIFT 13
+#define SC_MASK 3
+
+#define Q_PORT (&stm_gpiob)
+#define Q_BIT 12
+
+#define N_PORT (&stm_gpiod)
+#define N_SHIFT 13
+#define N_MASK 7
+
+#define EF_PORT (&stm_gpiob)
+#define EF_SHIFT 8
+#define EF_MASK 0xf
+
+#define DMA_IN_PORT (&stm_gpioa)
+#define DMA_IN_BIT 0
+
+#define DMA_OUT_PORT (&stm_gpioa)
+#define DMA_OUT_BIT 9
+
+#define INT_PORT (&stm_gpioa)
+#define INT_BIT 2
+
+#define CLEAR_PORT (&stm_gpioa)
+#define CLEAR_BIT 10
+
+#define WAIT_PORT (&stm_gpioa)
+#define WAIT_BIT 4
+
+#define MUX_PORT (&stm_gpiob)
+#define MUX_BIT 1
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/cortexelf-v1/cortexelf.ld b/src/cortexelf-v1/cortexelf.ld
new file mode 100644
index 00000000..6ad2a679
--- /dev/null
+++ b/src/cortexelf-v1/cortexelf.ld
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+MEMORY {
+ rom (rx) : ORIGIN = 0x08001000, LENGTH = 492K
+ flash (r) : ORIGIN = 0x0807c000, LENGTH = 16K
+ ram (!w) : ORIGIN = 0x20000000, LENGTH = 81408
+ stack (!w) : ORIGIN = 0x20013e00, LENGTH = 512
+}
+
+INCLUDE registers.ld
+
+EXTERN (stm_interrupt_vector)
+
+SECTIONS {
+ /*
+ * Rom contents
+ */
+
+ .text ORIGIN(rom) : {
+ __text_start__ = .;
+ *(.interrupt) /* Interrupt vectors */
+
+ . = ORIGIN(rom) + 0x100;
+
+
+ /* Ick. What I want is to specify the
+ * addresses of some global constants so
+ * that I can find them across versions
+ * of the application. I can't figure out
+ * how to make gnu ld do that, so instead
+ * we just load the two files that include
+ * these defines in the right order here and
+ * expect things to 'just work'. Don't change
+ * the contents of those files, ok?
+ */
+ ao_romconfig.o(.romconfig*)
+ ao_product.o(.romconfig*)
+ *(.text*) /* Executable code */
+ *(.rodata*) /* Constants */
+
+ } > rom
+
+ .ARM.exidx : {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } > rom
+ __text_end__ = .;
+
+ /* Boot data which must live at the start of ram so that
+ * the application and bootloader share the same addresses.
+ * This must be all uninitialized data
+ */
+ .boot (NOLOAD) : {
+ __boot_start__ = .;
+ *(.boot)
+ . = ALIGN(4);
+ __boot_end__ = .;
+ } >ram
+
+ /* Data -- relocated to RAM, but written to ROM
+ */
+ .data : {
+ __data_start__ = .;
+ *(.data) /* initialized data */
+ . = ALIGN(4);
+ __data_end__ = .;
+ } >ram AT>rom
+
+ .bss : {
+ __bss_start__ = .;
+ *(.bss)
+ *(COMMON)
+ . = ALIGN(4);
+ __bss_end__ = .;
+ } >ram
+
+ PROVIDE(end = .);
+
+ PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
+
+ __flash__ = ORIGIN(flash);
+}
+
+ENTRY(start);
+
+
diff --git a/src/cortexelf-v1/flash-loader/Makefile b/src/cortexelf-v1/flash-loader/Makefile
new file mode 100644
index 00000000..19cf84e4
--- /dev/null
+++ b/src/cortexelf-v1/flash-loader/Makefile
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=cortexelf-v1
+include $(TOPDIR)/stm/Makefile-flash.defs
diff --git a/src/cortexelf-v1/flash-loader/ao_pins.h b/src/cortexelf-v1/flash-loader/ao_pins.h
new file mode 100644
index 00000000..5d63dc2c
--- /dev/null
+++ b/src/cortexelf-v1/flash-loader/ao_pins.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2013 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_PINS_H_
+#define _AO_PINS_H_
+
+/* External crystal at 8MHz */
+#define AO_HSE 8000000
+
+#include <ao_flash_stm_pins.h>
+
+/* MP switch, gpioc 9 */
+
+#define AO_BOOT_PIN 1
+#define AO_BOOT_APPLICATION_GPIO stm_gpioc
+#define AO_BOOT_APPLICATION_PIN 9
+#define AO_BOOT_APPLICATION_VALUE 1
+#define AO_BOOT_APPLICATION_MODE 0
+
+#endif /* _AO_PINS_H_ */