commit 1b4559aa03e8793a3901fd4a21dfb673f6e8b8e1
parent 33c90067c1043e4163e9736f1730bf54384c908c
Author: Brian Swetland <swetland@frotz.net>
Date: Wed, 8 Mar 2023 15:01:38 -0800
flash agents
- import the flash agents from mdebug
- replace u32 with uint32_t throughout
Diffstat:
18 files changed, 1714 insertions(+), 10 deletions(-)
diff --git a/Makefile b/Makefile
@@ -5,24 +5,84 @@ CFLAGS := -Wall -g -O1
CFLAGS += -Itui -Itermbox -D_XOPEN_SOURCE
LIBS := -lusb-1.0
+# TOOLCHAIN := arm-none-eabi-
+
+ifneq ($(TOOLCHAIN),)
+# if there's a cross-compiler, build agents from source
+
+TARGET_CC := $(TOOLCHAIN)gcc
+TARGET_OBJCOPY := $(TOOLCHAIN)objcopy
+TARGET_OBJDUMP := $(TOOLCHAIN)objdump
+
+ARCH_M3_CFLAGS := -mcpu=cortex-m3 -mthumb
+ARCH_M3_LIBS := $(shell $(TARGET_CC) $(ARCH_M3_CFLAGS) -print-libgcc-file-name)
+
+ARCH_M0_CFLAGS := -mcpu=cortex-m0 -mthumb
+ARCH_M0_LIBS := $(shell $(TARGET_CC) $(ARCH_M0_CFLAGS) -print-libgcc-file-name)
+
+TARGET_CFLAGS := -g -Os -Wall -I. -Iinclude
+TARGET_CFLAGS += -Wno-unused-but-set-variable
+TARGET_CFLAGS += -ffunction-sections -fdata-sections
+TARGET_CFLAGS += -fno-builtin -nostdlib -ffreestanding
+
+agent = $(eval AGENTS += $(strip $1))\
+$(eval ALL += $(patsubst %,out/agents/%.bin,$(strip $1)))\
+$(eval ALL += $(patsubst %,out/agents/%.lst,$(strip $1)))\
+$(eval out/agents/$(strip $1).elf: LOADADDR := $(strip $2))\
+$(eval out/agents/$(strip $1).elf: ARCH := $(strip $3))
+
+$(call agent, lpclink2, 0x10080400, M3)
+$(call agent, stm32f4xx, 0x20000400, M3)
+$(call agent, stm32f0xx, 0x20000400, M0)
+$(call agent, lpc13xx, 0x10000400, M3)
+$(call agent, lpc15xx, 0x02000400, M3)
+$(call agent, cc13xx, 0x20000400, M3)
+$(call agent, nrf528xx, 0x20000400, M3)
+$(call agent, efr32bg2x, 0x20000400, M3)
+$(call agent, pico, 0x20000400, M0)
+
+out/mkbuiltins: tools/mkbuiltins.c
+ @mkdir -p $(dir $@)
+ gcc -o $@ $(CFLAGS) $<
+
+AGENT_BINS := $(patsubst %,out/agents/%.bin,$(AGENTS))
+
+gen/builtins.c: $(AGENT_BINS) out/mkbuiltins
+ @mkdir -p $(dir $@)
+ ./out/mkbuiltins $(AGENT_BINS) > $@
+
+out/agents/%.bin: out/agents/%.elf
+ @mkdir -p $(dir $@)
+ $(TARGET_OBJCOPY) -O binary $< $@
+
+out/agents/%.lst: out/agents/%.elf
+ @mkdir -p $(dir $@)
+ $(TARGET_OBJDUMP) -d $< > $@
+
+out/agents/%.elf: agents/%.c
+ @mkdir -p $(dir $@)
+ $(TARGET_CC) $(TARGET_CFLAGS) $(ARCH_$(ARCH)_CFLAGS) -Wl,--script=include/agent.ld -Wl,-Ttext=$(LOADADDR) -o $@ $< $(ARCH_$(ARCH)_LIBS)
+
+endif
+
COMMON := src/transport-arm-debug.c src/transport-dap.c src/usb.c
-XTESTSRCS := src/xtest.c $(COMMON)
-XTESTOBJS := $(addprefix out/,$(patsubst %.c,%.o,$(filter %.c,$(XTESTSRCS))))
+XTEST_SRCS := src/xtest.c $(COMMON)
+XTEST_OBJS := $(addprefix out/,$(patsubst %.c,%.o,$(filter %.c,$(XTEST_SRCS))))
-XDEBUGSRCS := src/xdebug.c src/commands.c $(COMMON)
-XDEBUGSRCS += tui/tui.c termbox/termbox.c termbox/utf8.c
-XDEBUGOBJS := $(addprefix out/,$(patsubst %.c,%.o,$(filter %.c,$(XDEBUGSRCS))))
+XDEBUG_SRCS := src/xdebug.c src/commands.c $(COMMON)
+XDEBUG_SRCS += tui/tui.c termbox/termbox.c termbox/utf8.c gen/builtins.c
+XDEBUG_OBJS := $(addprefix out/,$(patsubst %.c,%.o,$(filter %.c,$(XDEBUG_SRCS))))
-out/xtest: $(XTESTOBJS)
+out/xtest: $(XTEST_OBJS)
@mkdir -p $(dir $@)
- gcc -o $@ -Wall -g -O1 $(XTESTOBJS) $(LIBS)
+ gcc -o $@ -Wall -g -O1 $(XTEST_OBJS) $(LIBS)
-out/xdebug: $(XDEBUGOBJS)
+out/xdebug: $(XDEBUG_OBJS)
@mkdir -p $(dir $@)
- gcc -o $@ -Wall -g -O1 $(XDEBUGOBJS) $(LIBS)
+ gcc -o $@ -Wall -g -O1 $(XDEBUG_OBJS) $(LIBS)
# remove dups
-OBJS := $(sort $(XTESTOBJS) $(XDEBUGOBJS))
+OBJS := $(sort $(XTEST_OBJS) $(XDEBUG_OBJS))
$(OBJS): out/%.o: %.c $(XDEPS)
@mkdir -p $(dir $@)
diff --git a/agents/cc13xx-romapi.h b/agents/cc13xx-romapi.h
@@ -0,0 +1,35 @@
+
+#define ROM_API_TABLE ((uint32_t*) 0x10000180)
+#define ROM_API_FLASH_TABLE ((uint32_t*) (ROM_API_TABLE[10]))
+
+#define ROM_FlashPowerModeGet \
+ ((uint32_t (*)(void)) \
+ ROM_API_FLASH_TABLE[1])
+
+#define ROM_FlashProtectionSet \
+ ((void (*)(uint32_t ui32SectorAddress, uint32_t ui32ProtectMode)) \
+ ROM_API_FLASH_TABLE[2])
+
+#define ROM_FlashProtectionGet \
+ ((uint32_t (*)(uint32_t ui32SectorAddress)) \
+ ROM_API_FLASH_TABLE[3])
+
+#define ROM_FlashProtectionSave \
+ ((uint32_t (*)(uint32_t ui32SectorAddress)) \
+ ROM_API_FLASH_TABLE[4])
+
+#define ROM_FlashSectorErase \
+ ((uint32_t (*)(uint32_t ui32SectorAddress)) \
+ ROM_API_FLASH_TABLE[5])
+
+#define ROM_FlashProgram \
+ ((uint32_t (*)(const void *pui8DataBuffer, uint32_t ui32Address, uint32_t ui32Count)) \
+ ROM_API_FLASH_TABLE[6])
+
+#define ROM_FlashEfuseReadRow \
+ ((uint32_t (*)(uint32_t* pui32EfuseData, uint32_t ui32RowAddress)) \
+ ROM_API_FLASH_TABLE[8])
+
+#define ROM_FlashDisableSectorsForWrite \
+ ((void (*)(void)) \
+ ROM_API_FLASH_TABLE[9])
diff --git a/agents/cc13xx.c b/agents/cc13xx.c
@@ -0,0 +1,70 @@
+// agent-lpc15xx/main.c
+//
+// Copyright 2016 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <agent/flash.h>
+#include "cc13xx-romapi.h"
+
+int flash_agent_setup(flash_agent *agent) {
+ return ERR_NONE;
+}
+
+int flash_agent_erase(uint32_t flash_addr, uint32_t length) {
+ if (flash_addr & 0xFFF) {
+ return ERR_ALIGNMENT;
+ }
+ while (length > 0) {
+ if (ROM_FlashSectorErase(flash_addr)) {
+ return ERR_FAIL;
+ }
+ if (length > 4096) {
+ length -= 4096;
+ flash_addr += 4096;
+ } else {
+ break;
+ }
+ }
+ return 0;
+}
+
+int flash_agent_write(uint32_t flash_addr, const void *data, uint32_t length) {
+ if (flash_addr & 0xFFF) {
+ return ERR_ALIGNMENT;
+ }
+ if (ROM_FlashProgram(data, flash_addr, length)) {
+ return ERR_FAIL;
+ }
+ return 0;
+}
+
+
+int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) {
+ return ERR_INVALID;
+}
+
+const flash_agent __attribute((section(".vectors"))) FlashAgent = {
+ .magic = AGENT_MAGIC,
+ .version = AGENT_VERSION,
+ .flags = 0,
+ .load_addr = 0x20000400,
+ .data_addr = 0x20001000,
+ .data_size = 0x1000,
+ .flash_addr = 0x00000000,
+ .flash_size = 0x00020000,
+ .setup = flash_agent_setup,
+ .erase = flash_agent_erase,
+ .write = flash_agent_write,
+ .ioctl = flash_agent_ioctl,
+};
diff --git a/agents/efr32bg2x.c b/agents/efr32bg2x.c
@@ -0,0 +1,167 @@
+// agents/efr32bg2x.c
+//
+// Copyright 2022 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#define LOADADDR 0x20000400
+
+#define FLASH_BASE 0x00000000
+
+#include <agent/flash.h>
+#include <fw/io.h>
+
+#define CMU_CLKEN1_SET 0x40009068
+#define CMU_CLKEN1_MSC (1U<<17)
+
+#define MSC_WRITECTRL 0x4003000C
+#define MSC_WRITECTRL_SET 0x4003100C
+#define MSC_WRITECTRL_CLR 0x4003200C
+#define MSC_WRITECMD 0x40030010
+#define MSC_WRITECMD_SET 0x40031010
+#define MSC_WRITECMD_CLR 0x40032010
+#define MSC_ADDRB 0x40030014
+#define MSC_WDATA 0x40030018
+#define MSC_STATUS 0x4003001C
+
+#define MSC_WRITECTRL_WREN 1
+
+#define MSC_WRITECMD_WRITEND (1U<<2)
+#define MSC_WRITECMD_ERASEPAGE (1U<<1)
+
+#define MSC_STATUS_WREADY (1U<<27)
+#define MSC_STATUS_PWRON (1U<<24)
+#define MSC_STATUS_REGLOCK (1U<<16)
+#define MSC_STATUS_TIMEOUT (1U<<6)
+#define MSC_STATUS_PENDING (1U<<5)
+#define MSC_STATUS_ERASEABORTYED (1U<<4)
+#define MSC_STATUS_WDATAREADY (1U<<3)
+#define MSC_STATUS_INVADDR (1U<<2)
+#define MSC_STATUS_LOCKED (1U<<1)
+#define MSC_STATUS_BUSY (1U<<0)
+
+static unsigned FLASH_PAGE_SIZE = 8192;
+static unsigned FLASH_SIZE = 352 * 1024;
+
+int flash_agent_setup(flash_agent *agent) {
+ // TODO - validate part ID
+ if (0) {
+ // unknown part
+ return ERR_INVALID;
+ }
+
+ // TODO: read from userdata
+ agent->flash_size = FLASH_SIZE;
+
+ return ERR_NONE;
+}
+
+int flash_agent_erase(uint32_t flash_addr, uint32_t length) {
+ unsigned v;
+ int status = ERR_NONE;
+ if (flash_addr > FLASH_SIZE) {
+ return ERR_INVALID;
+ }
+ if (flash_addr & (FLASH_PAGE_SIZE - 1)) {
+ return ERR_ALIGNMENT;
+ }
+
+ writel(CMU_CLKEN1_MSC, CMU_CLKEN1_SET);
+ writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_SET);
+ while (length > 0) {
+ writel(flash_addr, MSC_ADDRB);
+ v = readl(MSC_STATUS);
+ if (v & (MSC_STATUS_INVADDR | MSC_STATUS_LOCKED)) {
+ status = ERR_INVALID;
+ break;
+ }
+ if (!(v & MSC_STATUS_WREADY)) {
+ status = ERR_FAIL;
+ break;
+ }
+ if (length > FLASH_PAGE_SIZE) {
+ length -= FLASH_PAGE_SIZE;
+ } else {
+ length = 0;
+ }
+ writel(MSC_WRITECMD_ERASEPAGE, MSC_WRITECMD_SET);
+ while (readl(MSC_STATUS) & MSC_STATUS_BUSY) ;
+ for (unsigned n = 0; n < FLASH_PAGE_SIZE; n += 4) {
+ if (readl(flash_addr + n) != 0xFFFFFFFF) {
+ status = ERR_FAIL;
+ goto done;
+ }
+ }
+ flash_addr += FLASH_PAGE_SIZE;
+ }
+done:
+ writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_CLR);
+ return status;
+}
+
+int flash_agent_write(uint32_t flash_addr, const void *_data, uint32_t length) {
+ int status = ERR_NONE;
+ const unsigned *data = _data;
+ unsigned v;
+ if (flash_addr > FLASH_SIZE) {
+ return ERR_INVALID;
+ }
+ if ((flash_addr & 3) || (length & 3)) {
+ return ERR_ALIGNMENT;
+ }
+ writel(CMU_CLKEN1_MSC, CMU_CLKEN1_SET);
+ writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_SET);
+ while (length > 0) {
+ writel(flash_addr, MSC_ADDRB);
+ v = readl(MSC_STATUS);
+ if (v & (MSC_STATUS_INVADDR | MSC_STATUS_LOCKED)) {
+ status = ERR_INVALID;
+ break;
+ }
+ if (!(v & MSC_STATUS_WREADY)) {
+ status = ERR_FAIL;
+ break;
+ }
+ writel(*data, MSC_WDATA);
+ while (readl(MSC_STATUS) & MSC_STATUS_BUSY) ;
+ if (readl(flash_addr) != *data) {
+ status = ERR_FAIL;
+ goto done;
+ }
+ data++;
+ length -= 4;
+ flash_addr += 4;
+ }
+done:
+ writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_CLR);
+ return status;
+}
+
+int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) {
+ return ERR_INVALID;
+}
+
+const flash_agent __attribute((section(".vectors"))) FlashAgent = {
+ .magic = AGENT_MAGIC,
+ .version = AGENT_VERSION,
+ .flags = 0,
+ .load_addr = LOADADDR,
+ .data_addr = LOADADDR + 0x400,
+ .data_size = 0x4000,
+ .flash_addr = FLASH_BASE,
+ .flash_size = 0,
+ .setup = flash_agent_setup,
+ .erase = flash_agent_erase,
+ .write = flash_agent_write,
+ .ioctl = flash_agent_ioctl,
+};
diff --git a/agents/lpc13xx.c b/agents/lpc13xx.c
@@ -0,0 +1,5 @@
+#define LOADADDR 0x10000400
+#define FLASH_BASE 0x00000000
+#define FLASH_SIZE 0x00008000
+
+#include "lpc13xx_lpc15xx.c"
diff --git a/agents/lpc13xx_lpc15xx.c b/agents/lpc13xx_lpc15xx.c
@@ -0,0 +1,119 @@
+// agent-lpc15xx/main.c
+//
+// Copyright 2015 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <agent/flash.h>
+
+#ifdef ARCH_LPC15XX
+#define LPC_IAP_FUNC 0x03000205
+#else
+#define LPC_IAP_FUNC 0x1fff1ff1
+#endif
+
+#define LPC_IAP_PREPARE 50
+#define LPC_IAP_WRITE 51
+#define LPC_IAP_ERASE 52
+
+// Note that while the databook claims you can reuse the same array
+// for both parameters and results, this is a lie. Attempting to
+// do so causes an invalid command failure.
+
+
+int flash_agent_setup(flash_agent *agent) {
+ return ERR_NONE;
+}
+
+int flash_agent_erase(uint32_t flash_addr, uint32_t length) {
+ void (*romcall)(uint32_t *, uint32_t *) = (void*) LPC_IAP_FUNC;
+ uint32_t p[5],r[4];
+ uint32_t page = flash_addr >> 12;
+ uint32_t last = page + ((length - 1) >> 12);
+ if (flash_addr & 0xFFF) {
+ return ERR_ALIGNMENT;
+ }
+
+ p[0] = LPC_IAP_PREPARE;
+ p[1] = page;
+ p[2] = last;
+ romcall(p,r);
+ if (r[0]) {
+ return ERR_FAIL;
+ }
+
+ p[0] = LPC_IAP_ERASE;
+ p[1] = page;
+ p[2] = last;
+ p[3] = 0x2ee0;
+ romcall(p,r);
+ if (r[0]) {
+ return ERR_FAIL;
+ }
+ return ERR_NONE;
+}
+
+int flash_agent_write(uint32_t flash_addr, const void *data, uint32_t length) {
+ void (*romcall)(uint32_t *,uint32_t *) = (void*) LPC_IAP_FUNC;
+ uint32_t p[5],r[4];
+ uint32_t page = flash_addr >> 12;
+ if (flash_addr & 0xFFF) {
+ return ERR_ALIGNMENT;
+ }
+
+ p[0] = LPC_IAP_PREPARE;
+ p[1] = page;
+ p[2] = page;
+ romcall(p,r);
+ if (r[0]) {
+ return ERR_FAIL;
+ }
+
+ // todo: smaller writes, etc
+ if (length != 4096) {
+ int n;
+ for (n = length; n < 4096; n++) {
+ ((char*) data)[n] = 0;
+ }
+ }
+ p[0] = LPC_IAP_WRITE;
+ p[1] = flash_addr;
+ p[2] = (uint32_t) data;
+ p[3] = 0x1000;
+ p[4] = 0x2ee0;
+ romcall(p,r);
+ if (r[0]) {
+ return ERR_FAIL;
+ }
+
+ return ERR_NONE;
+}
+
+int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) {
+ return ERR_INVALID;
+}
+
+const flash_agent __attribute((section(".vectors"))) FlashAgent = {
+ .magic = AGENT_MAGIC,
+ .version = AGENT_VERSION,
+ .flags = FLAG_BOOT_ROM_HACK,
+ .load_addr = LOADADDR,
+ .data_addr = LOADADDR + 0x400,
+ .data_size = 0x1000,
+ .flash_addr = FLASH_BASE,
+ .flash_size = FLASH_SIZE,
+ .setup = flash_agent_setup,
+ .erase = flash_agent_erase,
+ .write = flash_agent_write,
+ .ioctl = flash_agent_ioctl,
+};
diff --git a/agents/lpc15xx.c b/agents/lpc15xx.c
@@ -0,0 +1,7 @@
+#define ARCH_LPC15XX 1
+
+#define LOADADDR 0x02000400
+#define FLASH_BASE 0x00000000
+#define FLASH_SIZE 0x00010000
+
+#include "lpc13xx_lpc15xx.c"
diff --git a/agents/lpc43xx-spifi.c b/agents/lpc43xx-spifi.c
@@ -0,0 +1,226 @@
+// agent-lpc15xx/main.c
+//
+// Copyright 2015 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <agent/flash.h>
+#include <fw/io.h>
+
+// ---- pinmux
+
+#define PIN_CFG(m,n) (0x40086000 + ((m) * 0x80) + ((n) * 4))
+#define PIN_MODE(n) ((n) & 3)
+#define PIN_PULLUP (0 << 3) // pull-up, no pull-down
+#define PIN_REPEATER (1 << 3) // repeater mode
+#define PIN_PLAIN (2 << 3) // no pull-up, no pull-down
+#define PIN_PULLDOWN (3 << 3) // pull-down, no pull-up
+#define PIN_SLOW (0 << 5) // slow slew rate (low noise, medium speed)
+#define PIN_FAST (1 << 5) // fast slew rate (medium noise, fast speed)
+#define PIN_INPUT (1 << 6) // enable input buffer, required for inputs
+#define PIN_FILTER (1 << 7) // enable glitch filter, not for >30MHz signals
+
+// ---- spifi serial flash controller
+
+#define SPIFI_CTRL 0x40003000 // Control
+#define SPIFI_CMD 0x40003004 // Command
+#define SPIFI_ADDR 0x40003008 // Address
+#define SPIFI_IDATA 0x4000300C // Intermediate Data
+#define SPIFI_CLIMIT 0x40003010 // Cache Limit
+#define SPIFI_DATA 0x40003014 // Data
+#define SPIFI_MCMD 0x40003018 // Memory Command
+#define SPIFI_STAT 0x4000301C // Status
+
+#define CTRL_TIMEOUT(n) ((n) & 0xFFFF)
+#define CTRL_CSHIGH(n) (((n) & 0xF) << 16) // Minimum /CS high time (serclks - 1)
+#define CTRL_D_PRFTCH_DIS (1 << 21) // Disable Prefetch of Data
+#define CTRL_INTEN (1 << 22) // Enable IRQ on end of command
+#define CTRL_MODE3 (1 << 23) // 0=SCK low after +edge of last bit, 1=high
+#define CTRL_PRFTCH_DIS (1 << 27) // Disable Prefetch
+#define CTRL_DUAL (1 << 28) // 0=Quad 1=Dual (bits in "wide" ops)
+#define CTRL_QUAD (0 << 28)
+#define CTRL_RFCLK (1 << 29) // 1=sample read data on -edge clock
+#define CTRL_FBCLK (1 << 30) // use feedback clock from SCK pin for sampling
+#define CTRL_DMAEN (1 << 31) // enable DMA request output
+
+#define CMD_DATALEN(n) ((n) & 0x3FFF)
+#define CMD_POLL (1 << 14) // if set, read byte repeatedly until condition
+#define CMD_POLLBIT(n) ((n) & 7) // which bit# to check
+#define CMD_POLLSET (1 << 3) // condition is bit# set
+#define CMD_POLLCLR (0 << 3) // condition is bit# clear
+#define CMD_DOUT (1 << 15) // 1=data phase output, 0=data phase input
+#define CMD_DIN (0 << 15)
+#define CMD_INTLEN(n) (((n) & 7) << 16) // count of intermediate bytes
+#define CMD_FF_SERIAL (0 << 19) // all command fields serial
+#define CMD_FF_WIDE_DATA (1 << 19) // data is wide, all other fields serial
+#define CMD_FF_SERIAL_OPCODE (2 << 19) // opcode is serial, all other fields wide
+#define CMD_FF_WIDE (3 << 19) // all command fields wide
+#define CMD_FR_OP (1 << 21) // frame format: opcode only
+#define CMD_FR_OP_1B (2 << 21) // opcode, lsb addr
+#define CMD_FR_OP_2B (3 << 21) // opcode, 2 lsb addr
+#define CMD_FR_OP_3B (4 << 21) // opcode, 3 lsb addr
+#define CMD_FR_OP_4B (5 << 21) // opcode, 4b address
+#define CMD_FR_3B (6 << 21) // 3 lsb addr
+#define CMD_FR_4B (7 << 21) // 4 lsb addr
+#define CMD_OPCODE(n) ((n) << 24)
+
+#define STAT_MCINIT (1 << 0) // set on sw write to MCMD, clear on RST, wr(0)
+#define STAT_CMD (1 << 1) // set when CMD written, clear on CS, RST
+#define STAT_RESET (1 << 4) // write 1 to abort current txn or memory mode
+#define STAT_INTRQ (1 << 5) // read IRQ status, wr(1) to clear
+
+#define CMD_PAGE_PROGRAM 0x02
+#define CMD_READ_DATA 0x03
+#define CMD_READ_STATUS 0x05
+#define CMD_WRITE_ENABLE 0x06
+#define CMD_SECTOR_ERASE 0x20
+
+static void spifi_write_enable(void) {
+ writel(CMD_FF_SERIAL | CMD_FR_OP | CMD_OPCODE(CMD_WRITE_ENABLE),
+ SPIFI_CMD);
+ while (readl(SPIFI_STAT) & STAT_CMD) ;
+}
+
+static void spifi_wait_busy(void) {
+ while (readl(SPIFI_STAT) & STAT_CMD) ;
+ writel(CMD_POLLBIT(0) | CMD_POLLCLR | CMD_POLL |
+ CMD_FF_SERIAL | CMD_FR_OP | CMD_OPCODE(CMD_READ_STATUS),
+ SPIFI_CMD);
+ while (readl(SPIFI_STAT) & STAT_CMD) ;
+ // discard matching status byte from fifo
+ readb(SPIFI_DATA);
+}
+
+static void spifi_page_program(uint32_t addr, uint32_t *ptr, uint32_t count) {
+ spifi_write_enable();
+ writel(addr, SPIFI_ADDR);
+ writel(CMD_DATALEN(count * 4) | CMD_FF_SERIAL | CMD_FR_OP_3B |
+ CMD_DOUT | CMD_OPCODE(CMD_PAGE_PROGRAM), SPIFI_CMD);
+ while (count-- > 0) {
+ writel(*ptr++, SPIFI_DATA);
+ }
+ spifi_wait_busy();
+}
+
+static void spifi_sector_erase(uint32_t addr) {
+ spifi_write_enable();
+ writel(addr, SPIFI_ADDR);
+ writel(CMD_FF_SERIAL | CMD_FR_OP_3B | CMD_OPCODE(CMD_SECTOR_ERASE),
+ SPIFI_CMD);
+ spifi_wait_busy();
+}
+
+static int verify_erased(uint32_t addr, uint32_t count) {
+ int err = 0;
+ writel(addr, SPIFI_ADDR);
+ writel(CMD_DATALEN(count * 4) | CMD_FF_SERIAL | CMD_FR_OP_3B |
+ CMD_OPCODE(CMD_READ_DATA), SPIFI_CMD);
+ while (count-- > 0) {
+ if (readl(SPIFI_DATA) != 0xFFFFFFFF) err = -1;
+ }
+ while (readl(SPIFI_STAT) & STAT_CMD) ;
+ return err;
+}
+
+static int verify_page(uint32_t addr, uint32_t *ptr) {
+ int count = 256 / 4;
+ int err = 0;
+ writel(addr, SPIFI_ADDR);
+ writel(CMD_DATALEN(count * 4) | CMD_FF_SERIAL | CMD_FR_OP_3B |
+ CMD_OPCODE(CMD_READ_DATA), SPIFI_CMD);
+ while (count-- > 0) {
+ if (readl(SPIFI_DATA) != *ptr++) err = -1;
+ }
+ while (readl(SPIFI_STAT) & STAT_CMD) ;
+ return err;
+}
+
+// at reset-stop, all clocks are running from 12MHz internal osc
+// todo: run SPIFI_CLK at a much higher rate
+// todo: use 4bit modes
+int flash_agent_setup(flash_agent *agent) {
+ // configure pinmux
+ writel(PIN_MODE(3) | PIN_PLAIN, PIN_CFG(3,3)); // SPIFI_SCK
+ writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 4)); // SPIFI_SIO3
+ writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 5)); // SPIFI_SIO2
+ writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 6)); // SPIFI_MISO
+ writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 7)); // SPIFI_MOSI
+ writel(PIN_MODE(3) | PIN_PLAIN, PIN_CFG(3, 8)); // SPIFI_CS
+
+ // reset spifi controller
+ writel(STAT_RESET, SPIFI_STAT);
+ while (readl(SPIFI_STAT) & STAT_RESET) ;
+ writel(0xFFFFF, SPIFI_CTRL);
+
+ return ERR_NONE;
+}
+
+int flash_agent_erase(uint32_t flash_addr, uint32_t length) {
+ if (flash_addr & 0xFFF) {
+ return ERR_ALIGNMENT;
+ }
+ while (length != 0) {
+ spifi_sector_erase(flash_addr);
+ if (verify_erased(flash_addr, 0x1000/4)) {
+ return ERR_FAIL;
+ }
+ if (length < 0x1000) break;
+ length -= 0x1000;
+ flash_addr += 0x1000;
+ }
+ return ERR_NONE;
+}
+
+int flash_agent_write(uint32_t flash_addr, const void *data, uint32_t length) {
+ char *x = (void*) data;
+ if (flash_addr & 0xFFF) {
+ return ERR_ALIGNMENT;
+ }
+ while (length != 0) {
+ if (length < 256) {
+ int n;
+ for (n = length; n < 256; n++) {
+ x[n] = 0;
+ }
+ }
+ spifi_page_program(flash_addr, (void*) x, 256 / 4);
+ if (verify_page(flash_addr, (void*) x)) {
+ return ERR_FAIL;
+ }
+ if (length < 256) break;
+ length -= 256;
+ flash_addr += 256;
+ x += 256;
+ }
+ writel(CMD_FF_SERIAL | CMD_FR_OP_3B | CMD_OPCODE(CMD_READ_DATA), SPIFI_MCMD);
+ return ERR_NONE;
+}
+
+int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) {
+ return ERR_INVALID;
+}
+
+const flash_agent __attribute((section(".vectors"))) FlashAgent = {
+ .magic = AGENT_MAGIC,
+ .version = AGENT_VERSION,
+ .flags = 0,
+ .load_addr = LOADADDR,
+ .data_addr = LOADADDR + 0x400,
+ .data_size = 0x8000,
+ .flash_addr = FLASH_BASE,
+ .flash_size = FLASH_SIZE,
+ .setup = flash_agent_setup,
+ .erase = flash_agent_erase,
+ .write = flash_agent_write,
+ .ioctl = flash_agent_ioctl,
+};
diff --git a/agents/lpclink2.c b/agents/lpclink2.c
@@ -0,0 +1,5 @@
+#define FLASH_BASE 0x00000000
+#define FLASH_SIZE 0x00100000
+#define LOADADDR 0x10080400
+
+#include "lpc43xx-spifi.c"
diff --git a/agents/nrf528xx.c b/agents/nrf528xx.c
@@ -0,0 +1,127 @@
+// agents/nrf528xx.c
+//
+// Copyright 2019 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#define LOADADDR 0x20000400
+
+#define FLASH_BASE 0x00000000
+
+#include <agent/flash.h>
+#include <fw/io.h>
+
+#define NVMC_READY 0x4001E400
+#define NVMC_CONFIG 0x4001E504
+#define NVMC_CONFIG_READ 0
+#define NVMC_CONFIG_WRITE 1
+#define NVMC_CONFIG_ERASE 2
+#define NVMC_ERASEPAGE 0x4001E508
+
+#define FICR_CODEPAGESIZE 0x10000010
+#define FICR_CODESIZE 0x10000014
+
+static unsigned FLASH_PAGE_SIZE = 1024;
+static unsigned FLASH_SIZE = 192 * 1024;
+
+int flash_agent_setup(flash_agent *agent) {
+
+ // TODO - validate part ID
+ if (0) {
+ // unknown part
+ return ERR_INVALID;
+ }
+
+ // check flash size
+ FLASH_PAGE_SIZE = readl(FICR_CODEPAGESIZE);
+ FLASH_SIZE = FLASH_PAGE_SIZE * readl(FICR_CODESIZE);
+
+ agent->flash_size = FLASH_SIZE;
+
+ return ERR_NONE;
+}
+
+int flash_agent_erase(uint32_t flash_addr, uint32_t length) {
+ int status = ERR_NONE;
+ if (flash_addr > FLASH_SIZE) {
+ return ERR_INVALID;
+ }
+ if (flash_addr & (FLASH_PAGE_SIZE - 1)) {
+ return ERR_ALIGNMENT;
+ }
+ writel(NVMC_CONFIG_ERASE, NVMC_CONFIG);
+ while (length > 0) {
+ if (length > FLASH_PAGE_SIZE) {
+ length -= FLASH_PAGE_SIZE;
+ } else {
+ length = 0;
+ }
+ writel(flash_addr, NVMC_ERASEPAGE);
+ while (readl(NVMC_READY) != 1) ;
+ for (unsigned n = 0; n < FLASH_PAGE_SIZE; n += 4) {
+ if (readl(flash_addr + n) != 0xFFFFFFFF) {
+ status = ERR_FAIL;
+ goto done;
+ }
+ }
+ flash_addr += FLASH_PAGE_SIZE;
+ }
+done:
+ writel(NVMC_CONFIG_READ, NVMC_CONFIG);
+ return status;
+}
+
+int flash_agent_write(uint32_t flash_addr, const void *_data, uint32_t length) {
+ int status = ERR_NONE;
+ const unsigned *data = _data;
+ if (flash_addr > FLASH_SIZE) {
+ return ERR_INVALID;
+ }
+ if ((flash_addr & 3) || (length & 3)) {
+ return ERR_ALIGNMENT;
+ }
+ writel(NVMC_CONFIG_WRITE, NVMC_CONFIG);
+ while (length > 0) {
+ writel(*data, flash_addr);
+ while (readl(NVMC_READY) != 1) ;
+ if (readl(flash_addr) != *data) {
+ status = ERR_FAIL;
+ goto done;
+ }
+ data++;
+ length -= 4;
+ flash_addr += 4;
+ }
+done:
+ writel(NVMC_CONFIG_READ, NVMC_CONFIG);
+ return status;
+}
+
+int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) {
+ return ERR_INVALID;
+}
+
+const flash_agent __attribute((section(".vectors"))) FlashAgent = {
+ .magic = AGENT_MAGIC,
+ .version = AGENT_VERSION,
+ .flags = 0,
+ .load_addr = LOADADDR,
+ .data_addr = LOADADDR + 0x400,
+ .data_size = 0x4000,
+ .flash_addr = FLASH_BASE,
+ .flash_size = 0,
+ .setup = flash_agent_setup,
+ .erase = flash_agent_erase,
+ .write = flash_agent_write,
+ .ioctl = flash_agent_ioctl,
+};
diff --git a/agents/pico.c b/agents/pico.c
@@ -0,0 +1,147 @@
+// agents/pico.c
+//
+// Copyright 2020 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#define LOADADDR 0x20000400
+
+#define FLASH_BASE 0x00000000
+
+#include <stdint.h>
+#include <agent/flash.h>
+#include <fw/io.h>
+
+static unsigned FLASH_BLOCK_SIZE = 256;
+static unsigned FLASH_PAGE_SIZE = 4096;
+static unsigned FLASH_SIZE = 4 * 1024 * 1024;
+
+#define FLASH_XIP_BASE 0x10000000
+
+#define CODE(c1, c2) (((c2) << 8) | (c1))
+
+#define ROM_LOOKUP_FN_PTR 0x18
+#define ROM_FN_TABLE_PTR 0x14
+
+// lookup fn for code using ROM lookup helper and ROM fn table
+void* lookup_fn(uint32_t code) {
+ void* (*lookup)(uint32_t table, uint32_t code) =
+ (void*) (uintptr_t) *((uint16_t*) ROM_LOOKUP_FN_PTR);
+
+ return lookup(*((uint16_t*)ROM_FN_TABLE_PTR), code);
+}
+
+static void (*_flash_connect)(void);
+static void (*_flash_exit_xip)(void);
+static void (*_flash_erase)(uint32_t addr, uint32_t len,
+ uint32_t block_size, uint32_t block_cmd);
+static void (*_flash_write)(uint32_t addr, const void* data, uint32_t len);
+static void (*_flash_flush_cache)(void);
+static void (*_flash_enter_xip)(void);
+
+// erase: addr and count must be 4096 aligned
+// write: addr and len must be 256 aligned
+
+int flash_agent_setup(flash_agent *agent) {
+ // TODO - validate part ID
+ if (0) {
+ // unknown part
+ return ERR_INVALID;
+ }
+
+ _flash_connect = lookup_fn(CODE('I','F'));
+ _flash_exit_xip = lookup_fn(CODE('E','X'));
+ _flash_erase = lookup_fn(CODE('R','E'));
+ _flash_write = lookup_fn(CODE('R','P'));
+ _flash_flush_cache = lookup_fn(CODE('F','C'));
+ _flash_enter_xip = lookup_fn(CODE('C','X'));
+
+ // TODO: obtain from spi flash
+ agent->flash_size = FLASH_SIZE;
+
+ return ERR_NONE;
+}
+
+int flash_agent_erase(uint32_t flash_addr, uint32_t length) {
+ if (flash_addr > FLASH_SIZE) {
+ return ERR_INVALID;
+ }
+ if (flash_addr & (FLASH_PAGE_SIZE - 1)) {
+ return ERR_ALIGNMENT;
+ }
+ if (length & (FLASH_PAGE_SIZE-1)) {
+ length = (length & (~(FLASH_PAGE_SIZE-1))) + FLASH_PAGE_SIZE;
+ }
+
+ _flash_connect();
+ _flash_exit_xip();
+ _flash_erase(flash_addr, length, 65536, 0xD8);
+ _flash_flush_cache();
+ _flash_enter_xip();
+
+ uint32_t* flash = (void*) (flash_addr + FLASH_XIP_BASE);
+ for (uint32_t n = 0; n < length; n+= 4) {
+ if (*flash++ != 0xFFFFFFFF) {
+ return ERR_FAIL;
+ }
+ }
+
+ return ERR_NONE;
+}
+
+int flash_agent_write(uint32_t flash_addr, const void *data, uint32_t length) {
+ if (flash_addr > FLASH_SIZE) {
+ return ERR_INVALID;
+ }
+ if (flash_addr & (FLASH_BLOCK_SIZE - 1)) {
+ return ERR_ALIGNMENT;
+ }
+ if (length & (FLASH_BLOCK_SIZE-1)) {
+ length = (length & (~(FLASH_BLOCK_SIZE-1))) + FLASH_BLOCK_SIZE;
+ }
+
+ _flash_connect();
+ _flash_exit_xip();
+ _flash_write(flash_addr, data, length);
+ _flash_flush_cache();
+ _flash_enter_xip();
+
+ uint32_t* flash = (void*) (flash_addr + FLASH_XIP_BASE);
+ const uint32_t* xdata = data;
+ for (uint32_t n = 0; n < length; n += 4) {
+ if (*flash++ != *xdata++) {
+ return ERR_FAIL;
+ }
+ }
+
+ return ERR_NONE;
+}
+
+int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) {
+ return ERR_INVALID;
+}
+
+const flash_agent __attribute((section(".vectors"))) FlashAgent = {
+ .magic = AGENT_MAGIC,
+ .version = AGENT_VERSION,
+ .flags = 0,
+ .load_addr = LOADADDR,
+ .data_addr = LOADADDR + 0x400,
+ .data_size = 0x4000,
+ .flash_addr = FLASH_BASE,
+ .flash_size = 0,
+ .setup = flash_agent_setup,
+ .erase = flash_agent_erase,
+ .write = flash_agent_write,
+ .ioctl = flash_agent_ioctl,
+};
diff --git a/agents/stm32f0xx.c b/agents/stm32f0xx.c
@@ -0,0 +1,154 @@
+// agents/stm-main.c
+//
+// Copyright 2015 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#define LOADADDR 0x20000400
+
+#define FLASH_BASE 0x08000000
+#define FLASH_SIZE 0x00004000
+
+#include <agent/flash.h>
+#include <fw/io.h>
+
+#define _FLASH_BASE 0x40022000
+#define FLASH_ACR (_FLASH_BASE + 0x00)
+
+#define FLASH_KEYR (_FLASH_BASE + 0x04)
+#define FLASH_KEYR_KEY1 0x45670123
+#define FLASH_KEYR_KEY2 0xCDEF89AB
+
+#define FLASH_SR (_FLASH_BASE + 0x0C)
+#define FLASH_SR_EOP (1 << 5) // end of operation
+#define FLASH_SR_WP_ERR (1 << 4) // write protect error
+#define FLASH_SR_PG_ERR (1 << 2) // programming error
+#define FLASH_SR_BSY (1 << 0) // busy
+#define FLASH_SR_ERR_MASK (FLASH_SR_WP_ERR | FLASH_SR_PG_ERR)
+
+#define FLASH_CR (_FLASH_BASE + 0x10)
+#define FLASH_CR_OBL_LAUNCH (1 << 13) // reload option byte & reset system
+#define FLASH_CR_EOPIE (1 << 12) // enable end-of-op irq
+#define FLASH_CR_ERRIE (1 << 10) // enable error irq
+#define FLASH_CR_OPTWRE (1 << 9) // option byte write enable
+#define FLASH_CR_LOCK (1 << 7) // indicates flash is locked
+#define FLASH_CR_STRT (1 << 6) // start erase operation
+#define FLASH_CR_OPTER (1 << 5) // option byte erase
+#define FLASH_CR_OPTPG (1 << 4) // option byte program
+#define FLASH_CR_MER (1 << 2) // mass erase
+#define FLASH_CR_PER (1 << 1) // page erase
+#define FLASH_CR_PG (1 << 0) // programming
+#define FLASH_CR_MASK (~0x000036F7) // bits to not modify
+
+#define FLASH_AR (_FLASH_BASE + 0x14)
+
+static unsigned FLASH_PAGE_SIZE = 1024;
+
+int flash_agent_setup(flash_agent *agent) {
+
+ // check MCU ID
+ switch (readl(0x40015800) & 0xFFF) {
+ case 0x444: // F03x
+ case 0x445: // F04x
+ case 0x440: // F05x
+ break;
+ case 0x448: // F07x
+ case 0x442: // F09x
+ FLASH_PAGE_SIZE = 2048;
+ break;
+ default:
+ // unknown part
+ return ERR_INVALID;
+ }
+
+ // check flash size
+ agent->flash_size = readw(0x1FFFF7CC) * 1024;
+
+ writel(FLASH_KEYR_KEY1, FLASH_KEYR);
+ writel(FLASH_KEYR_KEY2, FLASH_KEYR);
+ if (readl(FLASH_CR) & FLASH_CR_LOCK) {
+ return ERR_FAIL;
+ } else {
+ return ERR_NONE;
+ }
+}
+
+int flash_agent_erase(uint32_t flash_addr, uint32_t length) {
+ uint32_t cr;
+ int n;
+ if (flash_addr & (FLASH_PAGE_SIZE - 1)) {
+ return ERR_ALIGNMENT;
+ }
+ cr = readl(FLASH_CR) & FLASH_CR_MASK;
+
+ while (length > 0) {
+ if (length > FLASH_PAGE_SIZE) {
+ length -= FLASH_PAGE_SIZE;
+ } else {
+ length = 0;
+ }
+ writel(cr | FLASH_CR_PER, FLASH_CR);
+ writel(flash_addr, FLASH_AR);
+ writel(cr | FLASH_CR_PER | FLASH_CR_STRT, FLASH_CR);
+ while (readl(FLASH_SR) & FLASH_SR_BSY) ;
+ for (n = 0; n < FLASH_PAGE_SIZE; n += 4) {
+ if (readl(flash_addr + n) != 0xFFFFFFFF) {
+ return ERR_FAIL;
+ }
+ }
+ flash_addr += FLASH_PAGE_SIZE;
+ }
+ return ERR_NONE;
+}
+
+int flash_agent_write(uint32_t flash_addr, const void *_data, uint32_t length) {
+ const unsigned short *data = _data;
+ uint32_t v, cr;
+ if ((flash_addr & 3) || (length & 3)) {
+ return ERR_ALIGNMENT;
+ }
+ cr = readl(FLASH_CR) & FLASH_CR_MASK;
+ writel(cr | FLASH_CR_PG, FLASH_CR);
+ while (length > 0) {
+ writew(*data, flash_addr);
+ while ((v = readl(FLASH_SR)) & FLASH_SR_BSY) ;
+ if (readw(flash_addr) != *data) {
+ writel(cr, FLASH_CR);
+ return ERR_FAIL;
+ }
+ data++;
+ length -= 2;
+ flash_addr += 2;
+ }
+ writel(cr, FLASH_CR);
+ return ERR_NONE;
+}
+
+int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) {
+ return ERR_INVALID;
+}
+
+const flash_agent __attribute((section(".vectors"))) FlashAgent = {
+ .magic = AGENT_MAGIC,
+ .version = AGENT_VERSION,
+ .flags = 0,
+ .load_addr = LOADADDR,
+ .data_addr = LOADADDR + 0x400,
+ .data_size = 0x1000,
+ .flash_addr = FLASH_BASE,
+ .flash_size = FLASH_SIZE,
+ .setup = flash_agent_setup,
+ .erase = flash_agent_erase,
+ .write = flash_agent_write,
+ .ioctl = flash_agent_ioctl,
+};
diff --git a/agents/stm32f4xx.c b/agents/stm32f4xx.c
@@ -0,0 +1,6 @@
+#define LOADADDR 0x20000400
+
+#define FLASH_BASE 0x00000000
+#define FLASH_SIZE 0x00100000
+
+#include "stm32fxxx.c"
diff --git a/agents/stm32fxxx.c b/agents/stm32fxxx.c
@@ -0,0 +1,141 @@
+// agents/stm-main.c
+//
+// Copyright 2015 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <agent/flash.h>
+#include <fw/io.h>
+
+#define _FLASH_BASE 0x40023C00
+#define FLASH_ACR (_FLASH_BASE + 0x00)
+
+#define FLASH_KEYR (_FLASH_BASE + 0x04)
+#define FLASH_KEYR_KEY1 0x45670123
+#define FLASH_KEYR_KEY2 0xCDEF89AB
+
+#define FLASH_SR (_FLASH_BASE + 0x0C)
+#define FLASH_SR_BSY (1 << 16)
+#define FLASH_SR_PGSERR (1 << 7) // sequence error
+#define FLASH_SR_PGPERR (1 << 6) // parallelism error
+#define FLASH_SR_PGAERR (1 << 5) // alignment error
+#define FLASH_SR_WRPERR (1 << 4) // write-protect error
+#define FLASH_SR_OPERR (1 << 1) // operation error
+#define FLASH_SR_ERRMASK 0xF2
+#define FLASH_SR_EOP (1 << 0) // end of operation
+
+#define FLASH_CR (_FLASH_BASE + 0x10)
+#define FLASH_CR_LOCK (1 << 31)
+#define FLASH_CR_ERRIE (1 << 25) // error irq en
+#define FLASH_CR_EOPIE (1 << 24) // end of op irq en
+#define FLASH_CR_STRT (1 << 16) // start
+#define FLASH_CR_PSIZE_8 (0 << 8)
+#define FLASH_CR_PSIZE_16 (1 << 8)
+#define FLASH_CR_PSIZE_32 (2 << 8)
+#define FLASH_CR_PSIZE_64 (3 << 8)
+#define FLASH_CR_SNB(n) (((n) & 15) << 3) // sector number
+#define FLASH_CR_MER (1 << 2) // mass erase
+#define FLASH_CR_SER (1 << 1) // sector erase
+#define FLASH_CR_PG (1 << 0) // programming
+
+
+#define SECTORS 12
+
+static uint32_t sectors[SECTORS + 1] = {
+ 0x00000000,
+ 0x00004000,
+ 0x00008000,
+ 0x0000C000,
+ 0x00010000,
+ 0x00020000,
+ 0x00040000,
+ 0x00060000,
+ 0x00080000,
+ 0x000A0000,
+ 0x000C0000,
+ 0x000E0000,
+ 0x00100000,
+};
+
+int flash_agent_setup(flash_agent *agent) {
+ writel(FLASH_KEYR_KEY1, FLASH_KEYR);
+ writel(FLASH_KEYR_KEY2, FLASH_KEYR);
+ if (readl(FLASH_CR) & FLASH_CR_LOCK) {
+ return ERR_FAIL;
+ } else {
+ return ERR_NONE;
+ }
+}
+
+int flash_agent_erase(uint32_t flash_addr, uint32_t length) {
+ uint32_t v;
+ int n;
+ for (n = 0; n < SECTORS; n++) {
+ if (flash_addr == sectors[n]) goto ok;
+ }
+ return ERR_ALIGNMENT;
+ok:
+ for (;;) {
+ writel(FLASH_CR_SER | FLASH_CR_SNB(n), FLASH_CR);
+ writel(FLASH_CR_STRT | FLASH_CR_SER | FLASH_CR_SNB(n), FLASH_CR);
+ while ((v = readl(FLASH_SR)) & FLASH_SR_BSY) ;
+ if (v & FLASH_SR_ERRMASK) {
+ return ERR_FAIL;
+ }
+ n++;
+ if (n == SECTORS) break;
+ if ((sectors[n] - flash_addr) >= length) break;
+ }
+ return ERR_NONE;
+}
+
+int flash_agent_write(uint32_t flash_addr, const void *_data, uint32_t length) {
+ const uint32_t *data = _data;
+ uint32_t v;
+ if ((flash_addr & 3) || (length & 3)) {
+ return ERR_ALIGNMENT;
+ }
+ writel(FLASH_CR_PG | FLASH_CR_PSIZE_32, FLASH_CR);
+ while (length > 0) {
+ writel(*data, flash_addr);
+ data++;
+ length -= 4;
+ flash_addr += 4;
+ while ((v = readl(FLASH_SR)) & FLASH_SR_BSY) ;
+ if (v & FLASH_SR_ERRMASK) {
+ writel(0, FLASH_CR);
+ return ERR_FAIL;
+ }
+ }
+ writel(0, FLASH_CR);
+ return ERR_NONE;
+}
+
+int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) {
+ return ERR_INVALID;
+}
+
+const flash_agent __attribute((section(".vectors"))) FlashAgent = {
+ .magic = AGENT_MAGIC,
+ .version = AGENT_VERSION,
+ .flags = 0,
+ .load_addr = LOADADDR,
+ .data_addr = LOADADDR + 0x400,
+ .data_size = 0x8000,
+ .flash_addr = FLASH_BASE,
+ .flash_size = FLASH_SIZE,
+ .setup = flash_agent_setup,
+ .erase = flash_agent_erase,
+ .write = flash_agent_write,
+ .ioctl = flash_agent_ioctl,
+};
diff --git a/gen/builtins.c b/gen/builtins.c
@@ -0,0 +1,248 @@
+/* this file is machine-generated by mkbuiltins -- do not modify */
+
+#include <string.h>
+#include <stdint.h>
+
+static struct {
+ const char *name;
+ size_t size;
+ void *data;
+} files[] = {
+ { "lpclink2.bin", 488,
+ "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x08\x10"
+ "\x00\x08\x08\x10\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x61\x04\x08\x10\xA5\x04\x08\x10\x25\x05\x08\x10\x9D\x04\x08\x10"
+ "\x05\x4B\xDA\x69\x91\x07\xFC\xD4\x04\x4A\x5A\x60\xDA\x69\x92\x07"
+ "\xFC\xD4\x1B\x7D\x70\x47\x00\xBF\x00\x30\x00\x40\x00\x40\x20\x05"
+ "\x53\x22\x13\x21\x0B\x4B\xC3\xF8\x8C\x11\xC3\xF8\x90\x21\xC3\xF8"
+ "\x94\x21\xC3\xF8\x98\x21\xC3\xF8\x9C\x21\x10\x22\xC3\xF8\xA0\x11"
+ "\xA3\xF5\x03\x23\xDA\x61\xD8\x69\x10\xF0\x10\x00\xFB\xD1\x02\x4A"
+ "\x1A\x60\x70\x47\x00\x60\x08\x40\xFF\xFF\x0F\x00\x6F\xF0\x01\x00"
+ "\x70\x47\x00\x00\x2D\xE9\xF8\x43\xC0\xF3\x0B\x03\x88\x46\x73\xBB"
+ "\x0E\x46\x1A\x4C\xDF\xF8\x68\x90\x00\xEB\x08\x07\xBF\x1B\xD6\xB1"
+ "\x4F\xF0\xC4\x63\x63\x60\xE5\x69\x15\xF0\x02\x05\xFB\xD1\x4F\xF0"
+ "\x02\x53\xA7\x60\x63\x60\xFF\xF7\xB3\xFF\x40\xF2\x01\x42\xA7\x60"
+ "\xC4\xF8\x04\x90\x01\x3A\x09\xD1\xE2\x69\x93\x07\xFC\xD4\x8D\xB9"
+ "\xB6\xF5\x80\x5F\x08\xD2\x00\x20\xBD\xE8\xF8\x83\x61\x69\x01\x31"
+ "\x18\xBF\x4F\xF0\xFF\x35\xED\xE7\xA6\xF5\x80\x56\xD4\xE7\x6F\xF0"
+ "\x02\x00\xF1\xE7\x4F\xF0\xFF\x30\xEE\xE7\x00\xBF\x00\x30\x00\x40"
+ "\x00\x10\x80\x03\xC0\xF3\x0B\x03\x2D\xE9\xF0\x47\x91\x46\x00\x2B"
+ "\x4E\xD1\x15\x46\xDF\xF8\xA4\x80\xDF\xF8\xA4\xA0\x01\xF5\x80\x74"
+ "\x00\xEB\x09\x07\x7F\x1B\xA4\xF5\x80\x76\x4D\xB3\xFF\x2D\x05\xD8"
+ "\x00\x22\x73\x19\x03\xF8\x01\x2B\xA3\x42\xFB\xD1\x4F\xF0\xC4\x63"
+ "\xC8\xF8\x04\x30\xD8\xF8\x1C\x30\x99\x07\xFB\xD4\x33\x46\xC8\xF8"
+ "\x08\x70\xC8\xF8\x04\xA0\xA3\x42\x19\xD1\xFF\xF7\x61\xFF\x19\x4B"
+ "\xC8\xF8\x08\x70\xC8\xF8\x04\x30\x00\x23\xA6\x42\x14\xD1\xD8\xF8"
+ "\x1C\x20\x92\x07\xFB\xD4\xF3\xB9\xFF\x2D\x04\xF5\x80\x74\x14\xD8"
+ "\x4F\xF0\x60\x72\x00\x20\x0D\x4B\x9A\x61\xBD\xE8\xF0\x87\x53\xF8"
+ "\x04\x2B\xC8\xF8\x14\x20\xDE\xE7\xD8\xF8\x14\x10\x56\xF8\x04\x2B"
+ "\x91\x42\x18\xBF\x4F\xF0\xFF\x33\xDF\xE7\xA5\xF5\x80\x75\xB7\xE7"
+ "\x6F\xF0\x02\x00\xE9\xE7\x4F\xF0\xFF\x30\xE6\xE7\x00\x30\x00\x40"
+ "\x00\x81\x80\x02\x00\x01\x80\x03"
+ },
+ { "stm32f4xx.bin", 340,
+ "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x00\x20"
+ "\x00\x08\x00\x20\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x41\x04\x00\x20\x61\x04\x00\x20\xD1\x04\x00\x20\xC9\x04\x00\x20"
+ "\x05\x4B\x06\x4A\xC3\xF8\x04\x2C\x02\xF1\x88\x32\xC3\xF8\x04\x2C"
+ "\xD3\xF8\x10\x0C\xC0\x17\x70\x47\x00\x30\x02\x40\x23\x01\x67\x45"
+ "\x16\x4B\xF0\xB5\x00\x22\x04\x46\x1E\x46\x53\xF8\x04\x0B\xA0\x42"
+ "\x1B\xD1\x13\x4D\x13\x4F\xD3\x00\x03\xF0\x78\x03\x43\xF0\x02\x00"
+ "\x3B\x43\xC5\xF8\x10\x0C\xC5\xF8\x10\x3C\xD5\xF8\x0C\x0C\xC3\x03"
+ "\xFB\xD4\x10\xF0\xF2\x00\x0E\xD1\x01\x32\x0C\x2A\x0A\xD0\x56\xF8"
+ "\x22\x30\x1B\x1B\x8B\x42\xE6\xD3\x04\xE0\x01\x32\x0C\x2A\xDC\xD1"
+ "\x6F\xF0\x02\x00\xF0\xBD\x4F\xF0\xFF\x30\xFB\xE7\x20\x05\x00\x20"
+ "\x00\x30\x02\x40\x02\x00\x01\x00\x6F\xF0\x01\x00\x70\x47\x00\x00"
+ "\x40\xEA\x02\x03\x9B\x07\x30\xB5\x1C\xD1\x40\xF2\x01\x24\x0F\x4B"
+ "\x0A\x44\xC3\xF8\x10\x4C\x40\x1A\x8A\x42\x03\xD1\x00\x20\xC3\xF8"
+ "\x10\x0C\x0E\xE0\x0C\x68\x44\x50\x04\x31\xD3\xF8\x0C\x4C\x14\xF4"
+ "\x80\x35\xFA\xD1\x14\xF0\xF2\x0F\xEE\xD0\x4F\xF0\xFF\x30\xC3\xF8"
+ "\x10\x5C\x30\xBD\x6F\xF0\x02\x00\xFB\xE7\x00\xBF\x00\x30\x02\x40"
+ "\x00\x00\x00\x00\x00\x40\x00\x00\x00\x80\x00\x00\x00\xC0\x00\x00"
+ "\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x06\x00"
+ "\x00\x00\x08\x00\x00\x00\x0A\x00\x00\x00\x0C\x00\x00\x00\x0E\x00"
+ "\x00\x00\x10\x00"
+ },
+ { "stm32f0xx.bin", 432,
+ "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x00\x20"
+ "\x00\x08\x00\x20\x00\x10\x00\x00\x00\x00\x00\x08\x00\x40\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x41\x05\x00\x20\x55\x04\x00\x20\xD9\x04\x00\x20\x39\x05\x00\x20"
+ "\x02\xB4\x71\x46\x49\x08\x49\x00\x09\x5C\x49\x00\x8E\x44\x02\xBC"
+ "\x70\x47\xC0\x46\xF7\xB5\x1B\x4A\x13\x68\x01\x3B\x18\x42\x2B\xD1"
+ "\x19\x4C\x1A\x4B\x25\x68\x1D\x40\x02\x23\x2B\x43\x01\x93\x42\x23"
+ "\x1D\x43\x00\x29\x01\xD1\x08\x00\xFE\xBD\x13\x68\x8B\x42\x13\xD2"
+ "\xC9\x1A\x01\x9B\x01\x26\x23\x60\x11\x4B\x18\x60\x11\x4B\x25\x60"
+ "\x9C\x46\x63\x46\x1F\x68\x3B\x00\x33\x40\x37\x42\xF9\xD1\x16\x68"
+ "\x9E\x42\x03\xD8\x80\x19\xE4\xE7\x00\x21\xEA\xE7\xC7\x18\x3F\x68"
+ "\x01\x37\x04\xD1\x04\x33\xF3\xE7\x03\x20\x40\x42\xDC\xE7\x01\x20"
+ "\xFB\xE7\xC0\x46\xAC\x05\x00\x20\x10\x20\x02\x40\x08\xC9\xFF\xFF"
+ "\x14\x20\x02\x40\x0C\x20\x02\x40\x03\x00\x13\x43\xF7\xB5\x9B\x07"
+ "\x22\xD1\x12\x4C\x12\x4B\x25\x68\x8A\x18\x2B\x40\x01\x25\x2E\x00"
+ "\x1E\x43\x26\x60\x0F\x4F\x00\x92\x42\x1A\x01\x92\x00\x9A\x8A\x42"
+ "\x02\xD1\x00\x20\x23\x60\xFE\xBD\x01\x9A\x56\x18\x0A\x88\x32\x80"
+ "\x38\x68\x28\x42\xFC\xD1\x36\x88\xB2\x42\x03\xD0\x01\x20\x23\x60"
+ "\x40\x42\xF0\xE7\x02\x31\xE9\xE7\x03\x20\xF9\xE7\x10\x20\x02\x40"
+ "\x08\xC9\xFF\xFF\x0C\x20\x02\x40\x02\x20\x40\x42\x70\x47\x00\x00"
+ "\x12\x4A\x03\x00\x10\x68\x12\x4A\x00\x05\x00\x0D\x80\x18\x00\xB5"
+ "\x08\x28\x18\xD8\xFF\xF7\x74\xFF\x09\x17\x05\x17\x09\x09\x17\x17"
+ "\x05\x00\x80\x21\x0B\x4A\x09\x01\x11\x60\x0B\x4A\x12\x88\x92\x02"
+ "\xDA\x61\x0A\x4B\x0A\x4A\x1A\x60\x0A\x4A\x1A\x60\x0A\x4B\x18\x68"
+ "\x00\x06\xC0\x17\x00\xBD\x02\x20\x40\x42\xFB\xE7\x00\x58\x01\x40"
+ "\xC0\xFB\xFF\xFF\xAC\x05\x00\x20\xCC\xF7\xFF\x1F\x04\x20\x02\x40"
+ "\x23\x01\x67\x45\xAB\x89\xEF\xCD\x10\x20\x02\x40\x00\x04\x00\x00"
+ },
+ { "lpc13xx.bin", 284,
+ "\x66\x61\x77\x42\x00\x00\x01\x00\x01\x00\x00\x00\x00\x04\x00\x10"
+ "\x00\x08\x00\x10\x00\x10\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x41\x04\x00\x10\x45\x04\x00\x10\xA1\x04\x00\x10\x15\x05\x00\x10"
+ "\x00\x20\x70\x47\x70\xB5\x4C\x1E\x24\x0B\x06\x0B\x04\xEB\x10\x34"
+ "\xC0\xF3\x0B\x00\x8A\xB0\xD0\xB9\x32\x23\x10\x4D\xCD\xE9\x05\x36"
+ "\x07\x94\x01\xA9\x05\xA8\xA8\x47\x01\x9B\x9B\xB9\x34\x23\xCD\xE9"
+ "\x05\x36\x42\xF6\xE0\x63\x05\xA8\x07\x94\x08\x93\x01\xA9\xA8\x47"
+ "\x01\x98\x00\x38\x18\xBF\x01\x20\x40\x42\x0A\xB0\x70\xBD\x6F\xF0"
+ "\x02\x00\xFA\xE7\x4F\xF0\xFF\x30\xF7\xE7\x00\xBF\xF1\x1F\xFF\x1F"
+ "\x70\xB5\x14\x46\xC0\xF3\x0B\x02\x05\x46\x0E\x46\x8A\xB0\x03\x0B"
+ "\x42\xBB\x32\x22\x07\x93\xCD\xE9\x05\x23\x01\xA9\x14\x4B\x05\xA8"
+ "\x98\x47\x01\x9B\x0B\xBB\xB4\xF5\x80\x5F\x14\xD1\x33\x23\x4F\xF4"
+ "\x80\x52\xCD\xE9\x05\x35\x42\xF6\xE0\x63\x05\xA8\xCD\xE9\x08\x23"
+ "\x07\x96\x0B\x4B\x01\xA9\x98\x47\x01\x98\x00\x38\x18\xBF\x01\x20"
+ "\x40\x42\x0A\xB0\x70\xBD\x22\x46\xB2\xF5\x80\x5F\xE6\xDA\xB3\x54"
+ "\x01\x32\xF9\xE7\x6F\xF0\x02\x00\xF3\xE7\x4F\xF0\xFF\x30\xF0\xE7"
+ "\xF1\x1F\xFF\x1F\x6F\xF0\x01\x00\x70\x47\x00\x00"
+ },
+ { "lpc15xx.bin", 284,
+ "\x66\x61\x77\x42\x00\x00\x01\x00\x01\x00\x00\x00\x00\x04\x00\x02"
+ "\x00\x08\x00\x02\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x41\x04\x00\x02\x45\x04\x00\x02\xA1\x04\x00\x02\x15\x05\x00\x02"
+ "\x00\x20\x70\x47\x70\xB5\x4C\x1E\x24\x0B\x06\x0B\x04\xEB\x10\x34"
+ "\xC0\xF3\x0B\x00\x8A\xB0\xD0\xB9\x32\x23\x10\x4D\xCD\xE9\x05\x36"
+ "\x07\x94\x01\xA9\x05\xA8\xA8\x47\x01\x9B\x9B\xB9\x34\x23\xCD\xE9"
+ "\x05\x36\x42\xF6\xE0\x63\x05\xA8\x07\x94\x08\x93\x01\xA9\xA8\x47"
+ "\x01\x98\x00\x38\x18\xBF\x01\x20\x40\x42\x0A\xB0\x70\xBD\x6F\xF0"
+ "\x02\x00\xFA\xE7\x4F\xF0\xFF\x30\xF7\xE7\x00\xBF\x05\x02\x00\x03"
+ "\x70\xB5\x14\x46\xC0\xF3\x0B\x02\x05\x46\x0E\x46\x8A\xB0\x03\x0B"
+ "\x42\xBB\x32\x22\x07\x93\xCD\xE9\x05\x23\x01\xA9\x14\x4B\x05\xA8"
+ "\x98\x47\x01\x9B\x0B\xBB\xB4\xF5\x80\x5F\x14\xD1\x33\x23\x4F\xF4"
+ "\x80\x52\xCD\xE9\x05\x35\x42\xF6\xE0\x63\x05\xA8\xCD\xE9\x08\x23"
+ "\x07\x96\x0B\x4B\x01\xA9\x98\x47\x01\x98\x00\x38\x18\xBF\x01\x20"
+ "\x40\x42\x0A\xB0\x70\xBD\x22\x46\xB2\xF5\x80\x5F\xE6\xDA\xB3\x54"
+ "\x01\x32\xF9\xE7\x6F\xF0\x02\x00\xF3\xE7\x4F\xF0\xFF\x30\xF0\xE7"
+ "\x05\x02\x00\x03\x6F\xF0\x01\x00\x70\x47\x00\x00"
+ },
+ { "cc13xx.bin", 176,
+ "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x00\x20"
+ "\x00\x10\x00\x20\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x41\x04\x00\x20\x75\x04\x00\x20\x45\x04\x00\x20\x6F\x04\x00\x20"
+ "\x00\x20\x70\x47\x03\x46\x08\x46\xC3\xF3\x0B\x01\x10\xB5\x59\xB9"
+ "\x4F\xF0\x80\x51\xD1\xF8\xA8\x11\x8C\x69\x19\x46\xA0\x47\x00\x38"
+ "\x18\xBF\x01\x20\x40\x42\x10\xBD\x6F\xF0\x02\x00\xFB\xE7\x6F\xF0"
+ "\x01\x00\x70\x47\xC0\xF3\x0B\x03\x70\xB5\x0C\x46\x8B\xB9\x4F\xF0"
+ "\x80\x56\x45\x18\x28\x1B\x3C\xB1\xD6\xF8\xA8\x31\x5B\x69\x98\x47"
+ "\x50\xB9\xB4\xF5\x80\x5F\x01\xD8\x00\x20\x70\xBD\xA4\xF5\x80\x54"
+ "\xF0\xE7\x6F\xF0\x02\x00\xF8\xE7\x4F\xF0\xFF\x30\xF5\xE7\x00\x00"
+ },
+ { "nrf528xx.bin", 324,
+ "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x00\x20"
+ "\x00\x08\x00\x20\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x41\x04\x00\x20\x69\x04\x00\x20\xDD\x04\x00\x20\x61\x04\x00\x20"
+ "\x4F\xF0\x80\x52\x04\x49\x13\x69\x0B\x60\x52\x69\x53\x43\x03\x4A"
+ "\xC3\x61\x13\x60\x00\x20\x70\x47\x3C\x05\x00\x20\x40\x05\x00\x20"
+ "\x6F\xF0\x01\x00\x70\x47\x00\x00\x19\x4B\x70\xB5\x1B\x68\x83\x42"
+ "\x28\xD3\x18\x4A\x13\x68\x01\x3B\x03\x42\x26\xD1\x02\x23\x16\x4C"
+ "\xC4\xF8\x04\x35\x29\xB9\x08\x46\x00\x22\x13\x4B\xC3\xF8\x04\x25"
+ "\x70\xBD\x13\x68\xC4\xF8\x08\x05\x8B\x42\x2C\xBF\x00\x21\xC9\x1A"
+ "\xD4\xF8\x00\x34\x01\x2B\xFB\xD1\x00\x23\x15\x68\xAB\x42\x01\xD3"
+ "\x28\x44\xE7\xE7\xC6\x58\x01\x36\x01\xD1\x04\x33\xF6\xE7\x4F\xF0"
+ "\xFF\x30\xE1\xE7\x6F\xF0\x01\x00\xE2\xE7\x6F\xF0\x02\x00\xDF\xE7"
+ "\x40\x05\x00\x20\x3C\x05\x00\x20\x00\xE0\x01\x40\x15\x4B\x70\xB5"
+ "\x1B\x68\x83\x42\x1F\xD3\x40\xEA\x02\x03\x9B\x07\x1E\xD1\x01\x24"
+ "\x11\x4B\x0A\x44\xC3\xF8\x04\x45\x40\x1A\x91\x42\x05\xD1\x00\x20"
+ "\x00\x22\x0D\x4B\xC3\xF8\x04\x25\x70\xBD\x0C\x68\x45\x18\x44\x50"
+ "\xD3\xF8\x00\x64\x01\x2E\xFB\xD1\x2D\x68\x04\x31\xAC\x42\xEC\xD0"
+ "\x4F\xF0\xFF\x30\xEC\xE7\x6F\xF0\x01\x00\xED\xE7\x6F\xF0\x02\x00"
+ "\xEA\xE7\x00\xBF\x40\x05\x00\x20\x00\xE0\x01\x40\x00\x04\x00\x00"
+ "\x00\x00\x03\x00"
+ },
+ { "efr32bg2x.bin", 344,
+ "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x00\x20"
+ "\x00\x08\x00\x20\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x41\x04\x00\x20\x51\x04\x00\x20\xDD\x04\x00\x20\x4B\x04\x00\x20"
+ "\x4F\xF4\xB0\x23\xC3\x61\x00\x20\x70\x47\x6F\xF0\x01\x00\x70\x47"
+ "\x03\x46\xB3\xF5\xB0\x2F\x08\x46\x70\xB5\x31\xD8\xC3\xF3\x0C\x02"
+ "\x8A\xBB\x4F\xF4\x00\x31\x19\x4A\x02\x26\x91\x66\x01\x22\x18\x4C"
+ "\x18\x49\xE2\x60\x40\xB1\x4B\x61\xCA\x69\x12\xF0\x06\x05\x1C\xD1"
+ "\x12\x01\x05\xD4\x4F\xF0\xFF\x30\x01\x22\x13\x4B\xDA\x60\x70\xBD"
+ "\xB0\xF5\x00\x5F\x88\xBF\xA0\xF5\x00\x55\x26\x61\xCA\x69\x12\xF0"
+ "\x01\x02\xFB\xD1\xD0\x58\x01\x30\xEC\xD1\x04\x32\xB2\xF5\x00\x5F"
+ "\xF8\xD1\x28\x46\x03\xF5\x00\x53\xDC\xE7\x6F\xF0\x01\x00\xE3\xE7"
+ "\x6F\xF0\x01\x00\xE3\xE7\x6F\xF0\x02\x00\xE0\xE7\x00\x90\x00\x40"
+ "\x00\x10\x03\x40\x00\x00\x03\x40\x00\x20\x03\x40\xB0\xF5\xB0\x2F"
+ "\x30\xB5\x2F\xD8\x40\xEA\x02\x03\x9B\x07\x2E\xD1\x4F\xF4\x00\x34"
+ "\x17\x4B\x04\x39\x9C\x66\x01\x24\x03\xF5\x20\x33\xDC\x60\x02\x44"
+ "\xA3\xF5\x80\x53\x90\x42\x01\xD1\x00\x20\x08\xE0\x58\x61\xDC\x69"
+ "\x14\xF0\x06\x0F\x13\xD1\x25\x01\x05\xD4\x4F\xF0\xFF\x30\x01\x22"
+ "\x0C\x4B\xDA\x60\x30\xBD\x4C\x68\x9C\x61\xDC\x69\xE4\x07\xFC\xD4"
+ "\x05\x68\x51\xF8\x04\x4F\xA5\x42\xEF\xD1\x04\x30\xE2\xE7\x6F\xF0"
+ "\x01\x00\xEC\xE7\x6F\xF0\x01\x00\xEC\xE7\x6F\xF0\x02\x00\xE9\xE7"
+ "\x00\x90\x00\x40\x00\x20\x03\x40"
+ },
+ { "pico.bin", 484,
+ "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x00\x20"
+ "\x00\x08\x00\x20\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x69\x05\x00\x20\x41\x04\x00\x20\xC9\x04\x00\x20\x51\x05\x00\x20"
+ "\x80\x23\x70\xB5\xDB\x03\x05\x00\x0C\x00\x98\x42\x2C\xD8\x03\x05"
+ "\x2D\xD1\x0B\x05\x04\xD0\x80\x23\x0C\x0B\x24\x03\x5B\x01\xE4\x18"
+ "\x14\x4B\x1B\x68\x98\x47\x14\x4B\x1B\x68\x98\x47\x80\x22\x13\x4B"
+ "\x28\x00\x21\x00\x52\x02\x1E\x68\xD8\x23\xB0\x47\x10\x4B\x1B\x68"
+ "\x98\x47\x10\x4B\x1B\x68\x98\x47\x80\x23\xF0\x20\x5B\x05\x00\x06"
+ "\xEB\x18\x45\x1B\x5A\x19\xA2\x42\x01\xD3\x00\x20\x70\xBD\x04\xCB"
+ "\x01\x32\xF7\xD0\x01\x20\x00\xE0\x02\x20\x40\x42\xF6\xE7\x03\x20"
+ "\xFB\xE7\xC0\x46\xE4\x05\x00\x20\xF0\x05\x00\x20\xEC\x05\x00\x20"
+ "\xF4\x05\x00\x20\xE8\x05\x00\x20\xF8\xB5\x80\x23\x05\x00\x0F\x00"
+ "\x14\x00\xDB\x03\x98\x42\x29\xD8\xFF\x23\x06\x00\x1E\x40\x18\x42"
+ "\x27\xD1\x1A\x42\x02\xD0\x9C\x43\x01\x34\xFF\x34\x13\x4B\x1B\x68"
+ "\x98\x47\x13\x4B\x1B\x68\x98\x47\x12\x4B\x28\x00\x22\x00\x39\x00"
+ "\x1B\x68\x98\x47\x10\x4B\x1B\x68\x98\x47\x10\x4B\x1B\x68\x98\x47"
+ "\x80\x23\x5B\x05\xED\x18\xAB\x19\xB4\x42\x01\xD8\x00\x20\xF8\xBD"
+ "\x1B\x68\xBA\x59\x93\x42\x06\xD1\x04\x36\xF4\xE7\x02\x20\x40\x42"
+ "\xF5\xE7\x03\x20\xFB\xE7\x01\x20\xF9\xE7\xC0\x46\xE4\x05\x00\x20"
+ "\xF0\x05\x00\x20\xF8\x05\x00\x20\xF4\x05\x00\x20\xE8\x05\x00\x20"
+ "\x02\x20\x40\x42\x70\x47\x14\x23\x10\xB5\x01\x00\x18\x88\x04\x33"
+ "\x1B\x88\x98\x47\x10\xBD\x00\x00\x10\xB5\x04\x00\x11\x48\xFF\xF7"
+ "\xF2\xFF\x11\x4B\x18\x60\x11\x48\xFF\xF7\xED\xFF\x10\x4B\x18\x60"
+ "\x10\x48\xFF\xF7\xE8\xFF\x10\x4B\x18\x60\x10\x48\xFF\xF7\xE3\xFF"
+ "\x0F\x4B\x18\x60\x0F\x48\xFF\xF7\xDE\xFF\x0F\x4B\x18\x60\x0F\x48"
+ "\xFF\xF7\xD9\xFF\x0E\x4B\x18\x60\x80\x23\xDB\x03\x00\x20\xE3\x61"
+ "\x10\xBD\xC0\x46\x49\x46\x00\x00\xE4\x05\x00\x20\x45\x58\x00\x00"
+ "\xF0\x05\x00\x20\x52\x45\x00\x00\xEC\x05\x00\x20\x52\x50\x00\x00"
+ "\xF8\x05\x00\x20\x46\x43\x00\x00\xF4\x05\x00\x20\x43\x58\x00\x00"
+ "\xE8\x05\x00\x20"
+ },
+};
+
+void *get_builtin_file(const char *name, size_t *sz) {
+ int n;
+ for (n = 0; n < (sizeof(files)/sizeof(files[0])); n++) {
+ if (!strcmp(name, files[n].name)) {
+ *sz = files[n].size;
+ return files[n].data;
+ }
+ }
+ return NULL;
+}
+
+const char *get_builtin_filename(unsigned n) {
+ if (n >= (sizeof(files)/sizeof(files[0]))) {
+ return NULL;
+ }
+ return files[n].name;
+}
diff --git a/include/agent.ld b/include/agent.ld
@@ -0,0 +1,32 @@
+
+/* RAM only binary layout */
+
+SECTIONS {
+ .text : {
+ . = ALIGN(4);
+ KEEP (*(.vectors))
+ *(.text)
+ *(.text.*)
+ *(.rodata)
+ *(.rodata.*)
+ . = ALIGN(4);
+ __data_init__ = . ;
+ } /* >RAM */
+ .data : {
+ . = ALIGN(4);
+ __data_start__ = . ;
+ *(.data)
+ *(.data.*)
+ . = ALIGN(4);
+ __data_end__ = . ;
+ } /* >RAM */
+ .bss : {
+ . = ALIGN(4);
+ __bss_start__ = . ;
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ . = ALIGN(4);
+ __bss_end__ = . ;
+ } /*>RAM */
+}
diff --git a/include/agent/flash.h b/include/agent/flash.h
@@ -0,0 +1,140 @@
+// agent/flash.h
+//
+// Copyright 2015 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _AGENT_FLASH_H_
+#define _AGENT_FLASH_H_
+
+#include <stdint.h>
+
+#define AGENT_MAGIC 0x42776166
+#define AGENT_VERSION 0x00010000
+
+typedef struct flash_agent {
+ uint32_t magic;
+ uint32_t version;
+ uint32_t flags;
+ uint32_t load_addr;
+
+ uint32_t data_addr;
+ uint32_t data_size; // bytes
+ uint32_t flash_addr;
+ uint32_t flash_size; // bytes
+
+ uint32_t reserved0;
+ uint32_t reserved1;
+ uint32_t reserved2;
+ uint32_t reserved3;
+
+#ifdef _AGENT_HOST_
+ uint32_t setup;
+ uint32_t erase;
+ uint32_t write;
+ uint32_t ioctl;
+#else
+ int (*setup)(struct flash_agent *agent);
+ int (*erase)(uint32_t flash_addr, uint32_t length);
+ int (*write)(uint32_t flash_addr, const void *data, uint32_t length);
+ int (*ioctl)(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1);
+#endif
+} flash_agent;
+
+#ifndef _AGENT_HOST_
+int flash_agent_setup(flash_agent *agent);
+int flash_agent_erase(uint32_t flash_addr, uint32_t length);
+int flash_agent_write(uint32_t flash_addr, const void *data, uint32_t length);
+int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1);
+#endif
+
+#define ERR_NONE 0
+#define ERR_FAIL -1
+#define ERR_INVALID -2
+#define ERR_ALIGNMENT -3
+
+#define FLAG_WSZ_256B 0x00000100
+#define FLAG_WSZ_512B 0x00000200
+#define FLAG_WSZ_1K 0x00000400
+#define FLAG_WSZ_2K 0x00000800
+#define FLAG_WSZ_4K 0x00001000
+// optional hints as to underlying write block sizes
+
+#define FLAG_BOOT_ROM_HACK 0x00000001
+// Allow a boot ROM to run after RESET by setting a watchpoint
+// at 0 and running until the watchpoint is hit. Necessary on
+// some parts which require boot ROM initialization of Flash
+// timing registers, etc.
+
+
+// Flash agent binaries will be downloaded to device memory at
+// fa.load_addr. The memory below this address will be used as
+// the stack for method calls. It should be sized appropriately.
+//
+// The fa.magic field will be replaced with 0xbe00be00 (two
+// Thumb BKPT instructions) before download to device.
+//
+// Calling convention for flash_agent methods:
+// 1. SP will be set to fa.load_addr - 4
+// 2. LR will be set to fa.load_addr
+// 3. PC will be set to the method address
+// 4. R0..R3 will be loaded with method arguments
+// 5. Processor will be resumed (in Privileged Thread mode)
+// 6. Upon processor entry to debug mode
+// a. if PC == fa.base_addr, status read from R0
+// b. else status = fatal error
+
+
+// setup() must be invoked after processor reset and before any
+// other methods are invoked. The fields data_addr, data_size,
+// flash_addr, and flash_size are read back after this method
+// returns success (to allow it to dynamically size flash based
+// on part ID, etc).
+// - ERR_INVALID indicates an unsupported part
+
+// fa.data_size must be a multiple of the minimum block size that
+// fa.write requires, so that if the host has to issue a series
+// of fa.write calls to do a larger-than-data-buffer-sized flash write,
+// subsequent write calls will have appropriate alignment.
+//
+// fa.write() may round writes up the the minimum write block size
+// as necessary, and should fill with 0s in that case.*
+//
+// fa.write() behaviour is undefined if the underlying flash has not
+// been erased first. It may fail (ERR_FAIL) or it may appear to
+// succeed, but flash contents may be incorrect.
+//
+// fa.write() may fail (ERR_ALIGN) if the start address is not aligned
+// with a flash page or block.*
+//
+// fa.erase() may round up to the next erasure block size if necessary
+// to ensure the requested region is erased.*
+//
+// fa.erase(fa.flash_addr, fa.flash_size) should cause a full erase if
+// possible.
+//
+// fa.ioctl() must return ERR_INVALID if op is unsupported.
+// Currently no ops are defined, but OTP/EEPROM/Config bits are
+// planned to be managed with ioctls.
+//
+// Bogus parameters may cause failure (ERR_INVALID)
+//
+// * In general, conveying the full complexity of embedded flash
+// configuration (which could include various banks of various sizes,
+// with differing write and erase block size requirements) is not
+// attempted. The goal is to provide an agent that can reasonably
+// handle reasonable flash requests (eg the user knows what a sane
+// starting alignment, etc is, does not split logical "partitions"
+// across physical erase block boundaries, etc)
+
+#endif
diff --git a/include/fw/io.h b/include/fw/io.h
@@ -0,0 +1,15 @@
+/* io.h */
+
+#ifndef _IO_H_
+#define _IO_H_
+
+#define readb(a) (*((volatile unsigned char *) (a)))
+#define writeb(v, a) (*((volatile unsigned char *) (a)) = (v))
+
+#define readw(a) (*((volatile unsigned short *) (a)))
+#define writew(v, a) (*((volatile unsigned short *) (a)) = (v))
+
+#define readl(a) (*((volatile unsigned int *) (a)))
+#define writel(v, a) (*((volatile unsigned int *) (a)) = (v))
+
+#endif