commit:74330f6c75c1a7e0392ba8b0d1d6f1dc1da0d94e
author:Chip
committer:Chip
date:Sun Feb 4 19:44:12 2024 -0600
parents:
Initial commit
diff --git a/.gitignore b/.gitignore
line changes: +4/-0
index 0000000..cf5f2e6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.o
+read-rom
+mass-erase
+led-test

diff --git a/Makefile b/Makefile
line changes: +17/-0
index 0000000..e8f75ac
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,17 @@
+.PHONY: all
+all: read-rom mass-erase led-test
+
+%.o: %.s
+	arm-none-eabi-as -g -c $< -o $@
+
+%.o: %.c
+	arm-none-eabi-gcc -march=armv6-m -O2 -g -c $< -o $@
+
+read-rom: read-rom.o
+	arm-none-eabi-ld -T memory-ram.x $^ -o $@
+
+mass-erase: mass-erase.o
+	arm-none-eabi-ld -T memory-ram.x $^ -o $@
+
+led-test: crt0.o led-bits.o led-test.o
+	arm-none-eabi-ld -T memory-flash.x $^ /usr/lib/gcc/arm-none-eabi/10.3.1/thumb/v6-m/nofp/libgcc.a -o $@

diff --git a/crt0.s b/crt0.s
line changes: +69/-0
index 0000000..8fd578b
--- /dev/null
+++ b/crt0.s
@@ -0,0 +1,69 @@
+.section .vectors, "ax"
+.align 2
+.global __vectors, __VECTOR_TABLE
+__VECTOR_TABLE:
+__vectors:
+.word __StackTop
+.word _start
+.word _end           // NMI
+.word _end           // HardFault
+.word _end           // Reserved
+.word _end           // Reserved
+.word _end           // Reserved
+.word _end           // Reserved
+.word _end           // Reserved
+.word _end           // Reserved
+.word _end           // Reserved
+.word _end           // SVCall
+.word _end           // Reserved
+.word _end           // Reserved
+.word _end           // PendSV
+.word _end           // SysTick
+.word _end           // LVD
+.word _end           // RTC
+.word _end           // FMC
+.word _end           // WKUP
+.word _end           // EXTI0-1
+.word _end           // EXTI2-3
+.word _end           // EXTI4-15
+.word _end           // CMP
+.word _end           // ADC
+.word _end           // Reserved
+.word _end           // MCTM
+.word _end           // GPTM1
+.word _end           // GPTM0
+.word _end           // SCTM0
+.word _end           // SCTM1
+.word _end           // Reserved
+.word _end           // Reserved
+.word _end           // BFTM0
+.word _end           // BFTM1
+.word _end           // I2C0
+.word _end           // I2C1
+.word _end           // SPI0
+.word _end           // SPI1
+.word _end           // USART0
+.word _end           // USART1
+.word _end           // UART0
+.word _end           // UART1
+.word _end           // SCI0-1
+.word _end           // I2S
+.word _end           // USB
+.word _end           // PDMA_CH0-1
+.word _end           // PDMA_CH2-5
+
+.text
+
+.type _start,%function
+.thumb_func
+.global _start
+_start:
+	ldr r0, =__stack
+	mov sp, r0
+	b main
+.thumb_func
+_end:
+	b _end
+
+.align
+.pool

diff --git a/led-bits.s b/led-bits.s
line changes: +49/-0
index 0000000..3079efa
--- /dev/null
+++ b/led-bits.s
@@ -0,0 +1,49 @@
+.thumb
+
+.global sendword
+sendword:
+	push {r4, r5, r6}
+	mov r1, #1
+	lsl r1, #23          // r1 - bit mask
+	ldr r3, =0x400b2024  // PORTB Set/Reset register
+	mov r4, #1
+	lsl r4, #16          // r4 - set          
+	mov r5, #1           // r5 - reset (inverted due to output MOSFET driver)
+	mov r6, #24          // r6 - bit counter
+	b 2f
+1:
+	sub r6, #1
+	beq 4f
+	lsl r0, #1
+2:
+	mov r2, r0
+	and r2, r1
+	beq 3f
+	// 1 bit
+	str r4, [r3]         // set
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	str r5, [r3]         // reset
+	b 1b
+3:
+	str r4, [r3]
+	nop
+	nop
+	nop
+	nop
+	str r5, [r3]
+	nop
+	nop
+	nop
+	nop
+	b 1b
+4:
+	pop {r4, r5, r6}
+	bx lr

diff --git a/led-test.c b/led-test.c
line changes: +69/-0
index 0000000..195e0b7
--- /dev/null
+++ b/led-test.c
@@ -0,0 +1,69 @@
+#include <stdint.h>
+
+#define CKCU_BASE 0x40088000
+#define AHBCCR 0x24
+#define GPIOB_BASE 0x400b2000
+#define DIRCR 0x000 // Port A Data Direction Control Register
+#define INER  0x004 // Port A Input Function Enable Control Register
+#define PUR   0x008 // Port A Pull-Up Selection Register
+#define PDR   0x00C // Port A Pull-Down Selection Register
+#define ODR   0x010 // Port A Open Drain Selection Register
+#define DRVR  0x014 // Port A Drive Current Selection Register
+#define LOCKR 0x018 // Port A Lock Register
+#define DINR  0x01C // Port A Data Input Register
+#define DOUTR 0x020 // Port A Data Output Register
+#define SRR   0x024 // Port A Output Set and Reset Control Register
+#define RR    0x028 // Port A Output Reset Control Register
+
+#define LED_D_OFF (*(uint32_t*)(GPIOB_BASE + SRR) = 1)
+#define LED_D_ON  (*(uint32_t*)(GPIOB_BASE + SRR) = 1 << 16)
+
+void sendword(uint32_t w);
+
+void delay(int n) {
+	n <<= 4;
+	for (int i = 0; i < n; i++) {
+		__asm__("nop");
+	}
+}
+
+void reset() {
+	LED_D_OFF;
+	delay(100);
+}
+
+// a * (c / 255) + b * ((255 - c) / 255)
+uint32_t lerp(uint32_t a, uint32_t b, uint8_t c) {
+	uint8_t* aa = (uint8_t*)&a;
+	uint8_t* bb = (uint8_t*)&b;
+	uint32_t r;
+	uint8_t* rr = (uint8_t*)&r;
+	
+	for (int i = 0; i < 3; i++) {
+		uint32_t ac = ((uint32_t)aa[i] * c) / 255;
+		uint32_t bc = ((uint64_t)bb[i] * (255 - c)) / 255;
+		rr[i] = (uint8_t)ac + bc;
+	}
+	return r;
+}
+
+void main() {
+	// Enable GPIOB peripheral
+	*(uint32_t*)(CKCU_BASE + AHBCCR) |= 0x00020000;
+	// Enable output direction on B0
+	*(uint32_t*)(GPIOB_BASE + DIRCR) = 1;
+
+	uint8_t j = 0;
+	uint32_t values[15];
+	while (1) {
+		for (int i = 0; i < 15; i++) {
+			//values[i] = lerp(0x002020, 0x400000, (j + i * 10) % 255);
+			values[i] = (i % 2) ^ (j < 128) ? (j < 128 ? 0x000f0f : 0x1e0000) : 0x000000;
+		}
+		for (int i = 0; i < 15; i++) {
+			sendword(values[i]);
+		}
+		delay(1000);
+		j += 5;
+	}
+}

diff --git a/mass-erase.s b/mass-erase.s
line changes: +30/-0
index 0000000..80e9d03
--- /dev/null
+++ b/mass-erase.s
@@ -0,0 +1,30 @@
+.text
+.thumb
+
+.global _start
+_start:
+	ldr r0, OCMR
+	ldr r1, OPCR
+	bl idle_check
+
+	mov r2, #0xA
+	str r2, [r0]    // store 0xA in OCMR
+	lsl r2, #1      // Shift left into OPM location
+	str r2, [r1]    // store 0xa in OPCR.OPM
+
+	bl idle_check
+
+end:
+	b end
+
+idle_check:
+	mov r3, #8      // Compare bit 3
+1:
+	ldr r2, [r1]    // load OPCR
+	and r2, r3      // If bit 3 is clear,
+	beq 1b          // a flash operation is in progress
+	bx lr
+
+.align
+OCMR:	.word 0x4008000c
+OPCR:	.word 0x40080010

diff --git a/memory-flash.x b/memory-flash.x
line changes: +183/-0
index 0000000..7604eaa
--- /dev/null
+++ b/memory-flash.x
@@ -0,0 +1,183 @@
+/* Based on GCC ARM embedded samples.
+   Defines the following symbols for use by code:
+    __exidx_start
+    __exidx_end
+    __etext
+    __data_start__
+    __preinit_array_start
+    __preinit_array_end
+    __init_array_start
+    __init_array_end
+    __fini_array_start
+    __fini_array_end
+    __data_end__
+    __bss_start__
+    __bss_end__
+    __end__
+    end
+    __HeapLimit
+    __StackLimit
+    __StackTop
+    __stack (== StackTop)
+*/
+
+MEMORY
+{
+    FLASH(rx) : ORIGIN = 0x00000000, LENGTH = 128k
+    RAM(rwx) : ORIGIN =  0x20000000, LENGTH = 16k
+}
+
+ENTRY(_start)
+
+SECTIONS
+{
+    .text : {
+        __logical_binary_start = .;
+        KEEP (*(.vectors))
+        KEEP (*(.binary_info_header))
+        __binary_info_header_end = .;
+        KEEP (*(.reset))
+        /* TODO revisit this now memset/memcpy/float in ROM */
+        /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from
+         * FLASH ... we will include any thing excluded here in .data below by default */
+        *(.init)
+        *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*)
+        *(.fini)
+        /* Pull all c'tors into .text */
+        *crtbegin.o(.ctors)
+        *crtbegin?.o(.ctors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+        *(SORT(.ctors.*))
+        *(.ctors)
+        /* Followed by destructors */
+        *crtbegin.o(.dtors)
+        *crtbegin?.o(.dtors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+        *(SORT(.dtors.*))
+        *(.dtors)
+
+        *(.eh_frame*)
+        . = ALIGN(4);
+    } > FLASH
+
+    .rodata : {
+        *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
+        . = ALIGN(4);
+        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+        . = ALIGN(4);
+    } > FLASH
+
+    .ARM.extab :
+    {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+    } > FLASH
+
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > FLASH
+    __exidx_end = .;
+
+    /* Machine inspectable binary information */
+    . = ALIGN(4);
+    __binary_info_start = .;
+    .binary_info :
+    {
+        KEEP(*(.binary_info.keep.*))
+        *(.binary_info.*)
+    } > FLASH
+    __binary_info_end = .;
+    . = ALIGN(4);
+
+   .ram_vector_table (NOLOAD): {
+        *(.ram_vector_table)
+    } > RAM
+
+    .data : {
+        __data_start__ = .;
+        *(vtable)
+
+        *(.time_critical*)
+
+        /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */
+        *(.text*)
+        . = ALIGN(4);
+        *(.rodata*)
+        . = ALIGN(4);
+
+        *(.data*)
+
+        . = ALIGN(4);
+        *(.after_data.*)
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__mutex_array_start = .);
+        KEEP(*(SORT(.mutex_array.*)))
+        KEEP(*(.mutex_array))
+        PROVIDE_HIDDEN (__mutex_array_end = .);
+
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__preinit_array_start = .);
+        KEEP(*(SORT(.preinit_array.*)))
+        KEEP(*(.preinit_array))
+        PROVIDE_HIDDEN (__preinit_array_end = .);
+
+        . = ALIGN(4);
+        /* init data */
+        PROVIDE_HIDDEN (__init_array_start = .);
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        PROVIDE_HIDDEN (__init_array_end = .);
+
+        . = ALIGN(4);
+        /* finit data */
+        PROVIDE_HIDDEN (__fini_array_start = .);
+        *(SORT(.fini_array.*))
+        *(.fini_array)
+        PROVIDE_HIDDEN (__fini_array_end = .);
+
+        *(.jcr)
+        . = ALIGN(4);
+        /* All data end */
+        __data_end__ = .;
+    } > RAM AT> FLASH
+    /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */
+    __etext = LOADADDR(.data);
+
+    .uninitialized_data (NOLOAD): {
+        . = ALIGN(4);
+        *(.uninitialized_data*)
+    } > RAM
+
+
+    .bss  : {
+        . = ALIGN(4);
+        __bss_start__ = .;
+        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+        *(COMMON)
+        . = ALIGN(4);
+        __bss_end__ = .;
+    } > RAM
+
+    .heap (NOLOAD):
+    {
+        __end__ = .;
+        end = __end__;
+        KEEP(*(.heap*))
+        __HeapLimit = .;
+    } > RAM
+
+    /* stack limit is poorly named, but historically is maximum heap ptr */
+    __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+    __StackTop = __StackLimit;
+    PROVIDE(__stack = __StackTop);
+
+    /* Check if data + heap + stack exceeds RAM limit */
+    ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+
+    ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
+    /* todo assert on extra code */
+}
+

diff --git a/memory-ram.x b/memory-ram.x
line changes: +177/-0
index 0000000..94e036e
--- /dev/null
+++ b/memory-ram.x
@@ -0,0 +1,177 @@
+/* Based on GCC ARM embedded samples.
+   Defines the following symbols for use by code:
+    __exidx_start
+    __exidx_end
+    __etext
+    __data_start__
+    __preinit_array_start
+    __preinit_array_end
+    __init_array_start
+    __init_array_end
+    __fini_array_start
+    __fini_array_end
+    __data_end__
+    __bss_start__
+    __bss_end__
+    __end__
+    end
+    __HeapLimit
+    __StackLimit
+    __StackTop
+    __stack (== StackTop)
+*/
+
+MEMORY
+{
+    RAM(rwx) : ORIGIN =  0x20000000, LENGTH = 16k
+}
+
+ENTRY(_start)
+
+SECTIONS
+{
+    /* Note in NO_FLASH builds the entry point for both the bootrom, and debugger
+       entry (ELF entry point), are *first* in the image, and the vector table
+       follows immediately afterward. This is because the bootrom enters RAM
+       binaries directly at their lowest address (preferring main RAM over XIP
+       cache-as-SRAM if both are used).
+    */
+
+    .text : {
+        __logical_binary_start = .;
+        __reset_start = .;
+        KEEP (*(.reset))
+        __reset_end = .;
+        KEEP (*(.binary_info_header))
+        __binary_info_header_end = .;
+        . = ALIGN(256);
+          KEEP (*(.vectors))
+        *(.time_critical*)
+        *(.text*)
+        . = ALIGN(4);
+        *(.init)
+        *(.fini)
+        /* Pull all c'tors into .text */
+        *crtbegin.o(.ctors)
+        *crtbegin?.o(.ctors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+        *(SORT(.ctors.*))
+        *(.ctors)
+        /* Followed by destructors */
+        *crtbegin.o(.dtors)
+        *crtbegin?.o(.dtors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+        *(SORT(.dtors.*))
+        *(.dtors)
+
+        *(.eh_frame*)
+    } > RAM
+
+    .rodata : {
+        *(.rodata*)
+        . = ALIGN(4);
+        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+        . = ALIGN(4);
+    } > RAM
+
+    .ARM.extab :
+    {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+    } > RAM
+
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > RAM
+    __exidx_end = .;
+
+    /* Machine inspectable binary information */
+    . = ALIGN(4);
+    __binary_info_start = .;
+    .binary_info :
+    {
+        KEEP(*(.binary_info.keep.*))
+        *(.binary_info.*)
+    } > RAM
+    __binary_info_end = .;
+    . = ALIGN(4);
+
+    .data : {
+        __data_start__ = .;
+        *(vtable)
+        *(.data*)
+
+        . = ALIGN(4);
+        *(.after_data.*)
+
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__mutex_array_start = .);
+        KEEP(*(SORT(.mutex_array.*)))
+        KEEP(*(.mutex_array))
+        PROVIDE_HIDDEN (__mutex_array_end = .);
+
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__preinit_array_start = .);
+        KEEP(*(SORT(.preinit_array.*)))
+        KEEP(*(.preinit_array))
+        PROVIDE_HIDDEN (__preinit_array_end = .);
+
+        . = ALIGN(4);
+        /* init data */
+        PROVIDE_HIDDEN (__init_array_start = .);
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        PROVIDE_HIDDEN (__init_array_end = .);
+
+        . = ALIGN(4);
+        /* finit data */
+        PROVIDE_HIDDEN (__fini_array_start = .);
+        *(SORT(.fini_array.*))
+        *(.fini_array)
+        PROVIDE_HIDDEN (__fini_array_end = .);
+
+        *(.jcr)
+        . = ALIGN(4);
+        /* All data end */
+        __data_end__ = .;
+    } > RAM
+
+    .uninitialized_data (NOLOAD): {
+        . = ALIGN(4);
+        *(.uninitialized_data*)
+    } > RAM
+    /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */
+    __etext = LOADADDR(.data);
+
+    .bss  : {
+        . = ALIGN(4);
+        __bss_start__ = .;
+        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+        *(COMMON)
+        . = ALIGN(4);
+        __bss_end__ = .;
+    } > RAM
+
+    .heap (NOLOAD):
+    {
+        __end__ = .;
+        end = __end__;
+        KEEP(*(.heap*))
+        __HeapLimit = .;
+    } > RAM
+
+    /* stack limit is poorly named, but historically is maximum heap ptr */
+    __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+    __StackTop = __StackLimit;
+    PROVIDE(__stack = __StackTop);
+
+    /* Check if data + heap + stack exceeds RAM limit */
+    ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+
+    ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
+    /* todo assert on extra code */
+}
+

diff --git a/read-rom.s b/read-rom.s
line changes: +21/-0
index 0000000..3b0ea75
--- /dev/null
+++ b/read-rom.s
@@ -0,0 +1,21 @@
+.text
+.thumb
+
+.global _start
+_start:
+	movs r0, #1
+	lsl r0, #13
+	ldr r1, RAM
+	mov r2, #1
+	lsl r2, #13
+loop:
+	ldr r3, [r0, r2]
+	str r3, [r1, r2]
+	sub r2, #4
+	bne loop
+end:
+	b end
+
+.align
+RAM:	.word 0x20001000
+GPIO_A: .word 0x400b0000