summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore11
-rw-r--r--Makefile42
-rw-r--r--asm.h7
-rw-r--r--crt0.s32
-rw-r--r--flashconf.s6
-rw-r--r--fmk.c9
-rw-r--r--layout.ld38
-rw-r--r--lib/le.c54
-rw-r--r--lib/le.h12
-rw-r--r--lib/reg.h45
-rw-r--r--lib/reg/gpio.h41
-rw-r--r--lib/reg/mcg.h56
-rw-r--r--lib/reg/pmc.h27
-rw-r--r--lib/reg/port.h42
-rw-r--r--lib/reg/regdefs.h25
-rw-r--r--lib/reg/sim.h70
-rw-r--r--lib/reg/uart.h8
-rw-r--r--lib/reg/usbotg.h202
-rw-r--r--lib/reg/wdog.h37
-rw-r--r--lib/string.c38
-rw-r--r--lib/string.h10
-rw-r--r--setup.c90
-rw-r--r--uart/uart.c5
-rw-r--r--uart/uart.h6
-rw-r--r--usb/bdt.h14
-rw-r--r--usb/ds_conf.xxd34
-rw-r--r--usb/ds_dev.xxd18
-rw-r--r--usb/ds_lang.xxd4
-rw-r--r--usb/ds_str1.xxd22
-rw-r--r--usb/endpt0.c199
-rw-r--r--usb/endpt0.h10
-rw-r--r--usb/endpt1.c36
-rw-r--r--usb/endpt1.h8
-rw-r--r--usb/usb.c94
-rw-r--r--usb/usb.h7
-rw-r--r--vectors.s98
36 files changed, 1457 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..98b3802
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+*.o
+*.bin
+fmk
+
+*.xxo
+*.xxh
+
+*.d
+
+tags
+TAGS
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..64ab87d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,42 @@
+CPU = cortex-m4
+MCU = MK20DX256
+TARGET_ARCH = -mcpu=$(CPU) -mthumb
+
+AS = arm-none-eabi-as
+CC = arm-none-eabi-gcc
+OBJCOPY = arm-none-eabi-objcopy
+XXD = xxd
+
+HKTOOL = hktool $(MCU)
+
+WARNINGS = -Wpointer-arith -Wcast-align -Wformat=2 \
+ -Wsuggest-attribute=format -Wall \
+ -Wextra -Wpedantic -Winit-self -Wshadow -Wcast-qual \
+ -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS = -std=c11 $(WARNINGS) -O2 -flto -MMD -MP -ffreestanding -nostdlib -Ilib
+LDFLAGS = -T layout.ld -O2 -flto -ffreestanding -nostdlib
+ASFLAGS = $(TARGET_ARCH)
+
+OBJ := crt0.o vectors.o flashconf.o setup.o fmk.o lib/string.o lib/le.o usb/usb.o usb/endpt0.o usb/endpt1.o
+
+%.bin: %
+ $(OBJCOPY) -O binary $< $@
+%.xxo: %.xxd
+ awk '{print $$1}' $< | $(XXD) -r -p -c1 >$@
+%.xxh: %.xxo
+ $(XXD) -i $< | sed -e 's/_xxo//' >$@
+
+all: fmk.bin
+fmk: $(OBJ)
+
+flash: fmk.bin
+ hktool 0x40000 1024 64 0 $<
+ hktool -r
+
+clean:
+ $(RM) $(OBJ) $(OBJ:.o=.d) $(wildcard usb/*.xxh) fmk fmk.bin
+
+-include $(OBJ:.o=.d)
+usb/endpt0.o: usb/ds_dev.xxh usb/ds_conf.xxh usb/ds_lang.xxh usb/ds_str1.xxh
+
+.PHONY: all flash clean
diff --git a/asm.h b/asm.h
new file mode 100644
index 0000000..f6489e6
--- /dev/null
+++ b/asm.h
@@ -0,0 +1,7 @@
+#ifndef ASM_H
+#define ASM_H
+
+#define CLI() __asm__ volatile ("cpsid i")
+#define STI() __asm__ volatile ("cpsie i")
+
+#endif /* ASM_H */
diff --git a/crt0.s b/crt0.s
new file mode 100644
index 0000000..6949ecc
--- /dev/null
+++ b/crt0.s
@@ -0,0 +1,32 @@
+.syntax unified
+
+.extern setup
+.extern main
+
+.section ".startup","x",%progbits
+
+.thumb_func
+.global _start
+_start:
+ mov r0, #0
+ mov r1, #0
+ mov r2, #0
+ mov r3, #0
+ mov r4, #0
+ mov r5, #0
+ mov r6, #0
+ mov r7, #0
+ mov r8, #0
+ mov r9, #0
+ mov r10, #0
+ mov r11, #0
+ mov r12, #0
+
+ bl setup
+ bl main
+
+ b _halt
+
+.thumb_func
+.global _halt
+_halt: b .
diff --git a/flashconf.s b/flashconf.s
new file mode 100644
index 0000000..9a82db2
--- /dev/null
+++ b/flashconf.s
@@ -0,0 +1,6 @@
+.syntax unified
+.section ".flashconfig"
+.long 0xFFFFFFFF
+.long 0xFFFFFFFF
+.long 0xFFFFFFFF
+.long 0xFFFFFFFE
diff --git a/fmk.c b/fmk.c
new file mode 100644
index 0000000..9df6082
--- /dev/null
+++ b/fmk.c
@@ -0,0 +1,9 @@
+#include <reg.h>
+#include <stdint.h>
+
+int main(void)
+{
+ /* TODO: Replace with an indefinite wait */
+ while (1)
+ ;
+}
diff --git a/layout.ld b/layout.ld
new file mode 100644
index 0000000..7431496
--- /dev/null
+++ b/layout.ld
@@ -0,0 +1,38 @@
+MEMORY {
+ FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K
+ RAM (rw!x) : ORIGIN = 0x1FFF8000, LENGTH = 64K
+}
+
+SECTIONS {
+ . = 0x00000000;
+ .text : {
+ KEEP(*(.vectors))
+ . = 0x400;
+ KEEP(*(.flashconfig*))
+ *(.startup*)
+ *(.text*)
+ *(.rodata*)
+ . = ALIGN(4);
+ } > FLASH
+
+ .data : {
+ . = ALIGN(4);
+ _sflashdata = LOADADDR(.data);
+ _sdata = .;
+ *(.fastrun*)
+ *(.data*)
+ . = ALIGN(4);
+ _edata = .;
+ } > RAM AT > FLASH
+
+ .bss : {
+ . = ALIGN(4);
+ _sbss = .;
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } > RAM
+
+ _estack = ORIGIN(RAM) + LENGTH(RAM);
+}
diff --git a/lib/le.c b/lib/le.c
new file mode 100644
index 0000000..47ed5f8
--- /dev/null
+++ b/lib/le.c
@@ -0,0 +1,54 @@
+/* lib/le.c -- Basic little endian byte order functions
+ *
+ * Copyright (C) 2016 Tomasz Kramkowski <tk@the-tk.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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <stdint.h>
+
+#include "le.h"
+
+uint16_t le16toh(const void *_data)
+{
+ const unsigned char *data = _data;
+
+ return (uint16_t)data[0] | (uint16_t)data[1] << 8;
+}
+
+uint32_t le32toh(const void *_data)
+{
+ const unsigned char *data = _data;
+
+ return (uint32_t)data[0] | (uint32_t)data[1] << 8
+ | (uint32_t)data[2] << 16 | (uint32_t)data[3] << 24;
+}
+
+void htole16(void *_data, uint16_t value)
+{
+ unsigned char *data = _data;
+
+ data[0] = value >> 0 & 0xff;
+ data[1] = value >> 8 & 0xff;
+}
+
+void htole32(void *_data, uint32_t value)
+{
+ unsigned char *data = _data;
+
+ data[0] = value >> 0 & 0xff;
+ data[1] = value >> 8 & 0xff;
+ data[2] = value >> 16 & 0xff;
+ data[3] = value >> 24 & 0xff;
+}
diff --git a/lib/le.h b/lib/le.h
new file mode 100644
index 0000000..e1341a7
--- /dev/null
+++ b/lib/le.h
@@ -0,0 +1,12 @@
+#ifndef LE_H
+#define LE_H
+
+#include <stdint.h>
+
+uint16_t le16toh(const void *data);
+uint32_t le32toh(const void *data);
+
+void htole16(void *data, uint16_t value);
+void htole32(void *data, uint32_t value);
+
+#endif /* LE_H */
diff --git a/lib/reg.h b/lib/reg.h
new file mode 100644
index 0000000..1a10792
--- /dev/null
+++ b/lib/reg.h
@@ -0,0 +1,45 @@
+#ifndef LIB_REG_H
+#define LIB_REG_H
+
+#include <reg/port.h>
+#include <reg/sim.h>
+//#include <reg/rcm.h>
+//#include <reg/smc.h>
+#include <reg/pmc.h>
+//#include <reg/llwu.h>
+//#include <reg/mcm.h>
+//#include <reg/axbs.h>
+//#include <reg/aips.h>
+//#include <reg/dmamux.h>
+//#include <reg/dma.h>
+//#include <reg/ewm.h>
+#include <reg/wdog.h>
+#include <reg/mcg.h>
+//#include <reg/osc.h>
+//#include <reg/rtc.h>
+//#include <reg/fmc.h>
+//#include <reg/ftfl.h>
+/*#include <reg/ezport.h>*/
+//#include <reg/crc.h>
+//#include <reg/adc.h>
+//#include <reg/cmp.h>
+//#include <reg/dac.h>
+//#include <reg/vref.h>
+//#include <reg/pdb.h>
+//#include <reg/ftm.h>
+//#include <reg/pit.h>
+//#include <reg/lptmr.h>
+//#include <reg/cmt.h>
+//#include <reg/rtc.h>
+//#include <reg/usbotg.h>
+//#include <reg/usbdcd.h>
+//#include <reg/can.h>
+//#include <reg/spi.h>
+//#include <reg/i2c.h>
+#include <reg/uart.h>
+//#include <reg/i2s.h>
+#include <reg/gpio.h>
+//#include <reg/tsi.h>
+//#include <reg/jtagc.h>
+
+#endif /* LIB_REG_H */
diff --git a/lib/reg/gpio.h b/lib/reg/gpio.h
new file mode 100644
index 0000000..6bb8d34
--- /dev/null
+++ b/lib/reg/gpio.h
@@ -0,0 +1,41 @@
+#ifndef LIB_REG_GPIO_H
+#define LIB_REG_GPIO_H
+
+#include <reg/regdefs.h>
+
+#define GPIOA_PDOR REG_32(0x400FF000) /* Port Data Output Register */
+#define GPIOA_PSOR REG_32(0x400FF004) /* Port Set Output Register */
+#define GPIOA_PCOR REG_32(0x400FF008) /* Port Clear Output Register */
+#define GPIOA_PTOR REG_32(0x400FF00C) /* Port Toggle Output Register */
+#define GPIOA_PDIR REG_32(0x400FF010) /* Port Data Input Register */
+#define GPIOA_PDDR REG_32(0x400FF014) /* Port Data Direction Register */
+
+#define GPIOB_PDOR REG_32(0x400FF040) /* Port Data Output Register */
+#define GPIOB_PSOR REG_32(0x400FF044) /* Port Set Output Register */
+#define GPIOB_PCOR REG_32(0x400FF048) /* Port Clear Output Register */
+#define GPIOB_PTOR REG_32(0x400FF04C) /* Port Toggle Output Register */
+#define GPIOB_PDIR REG_32(0x400FF050) /* Port Data Input Register */
+#define GPIOB_PDDR REG_32(0x400FF054) /* Port Data Direction Register */
+
+#define GPIOC_PDOR REG_32(0x400FF080) /* Port Data Output Register */
+#define GPIOC_PSOR REG_32(0x400FF084) /* Port Set Output Register */
+#define GPIOC_PCOR REG_32(0x400FF088) /* Port Clear Output Register */
+#define GPIOC_PTOR REG_32(0x400FF08C) /* Port Toggle Output Register */
+#define GPIOC_PDIR REG_32(0x400FF090) /* Port Data Input Register */
+#define GPIOC_PDDR REG_32(0x400FF094) /* Port Data Direction Register */
+
+#define GPIOD_PDOR REG_32(0x400FF0C0) /* Port Data Output Register */
+#define GPIOD_PSOR REG_32(0x400FF0C4) /* Port Set Output Register */
+#define GPIOD_PCOR REG_32(0x400FF0C8) /* Port Clear Output Register */
+#define GPIOD_PTOR REG_32(0x400FF0CC) /* Port Toggle Output Register */
+#define GPIOD_PDIR REG_32(0x400FF0D0) /* Port Data Input Register */
+#define GPIOD_PDDR REG_32(0x400FF0D4) /* Port Data Direction Register */
+
+#define GPIOE_PDOR REG_32(0x400FF100) /* Port Data Output Register */
+#define GPIOE_PSOR REG_32(0x400FF104) /* Port Set Output Register */
+#define GPIOE_PCOR REG_32(0x400FF108) /* Port Clear Output Register */
+#define GPIOE_PTOR REG_32(0x400FF10C) /* Port Toggle Output Register */
+#define GPIOE_PDIR REG_32(0x400FF110) /* Port Data Input Register */
+#define GPIOE_PDDR REG_32(0x400FF114) /* Port Data Direction Register */
+
+#endif /* LIB_REG_GPIO_H */
diff --git a/lib/reg/mcg.h b/lib/reg/mcg.h
new file mode 100644
index 0000000..bc1afcf
--- /dev/null
+++ b/lib/reg/mcg.h
@@ -0,0 +1,56 @@
+#ifndef LIB_REG_MCG_H
+#define LIB_REG_MCG_H
+
+#include <reg/regdefs.h>
+
+#define MCG_C1 REG_8(0x40064000) /* MCG Control 1 Register */
+#define C1_CLKS 6 /* Clock Source Select */
+#define C1_CLKS_M (uint8_t)(BITS(2) << C1_CLKS)
+#define C1_FRDIV 3 /* FLL External Reference Divider */
+#define C1_FRDIV_M (uint8_t)(BITS(3) << C1_FRDIV)
+#define C1_IREFS 2 /* Internal Reference Select */
+#define C1_IRCLKEN 1 /* Internal Reference Clock Enable */
+#define C1_IREFSTEN 0 /* Internal Reference Stop Enable */
+
+#define MCG_C2 REG_8(0x40064001) /* MCG Control 2 Register */
+#define C2_LOCRE0 7 /* Loss of Clock Reset Enable */
+#define C2_RANGE0 4 /* Frequency Range Select */
+#define C2_RANGE0_M (uint8_t)(BITS(2) << C2_RANGE0)
+#define C2_HGO0 3 /* High Gain Oscillator Select */
+#define C2_EREFS0 2 /* External Reference Select */
+#define C2_LP 1 /* Low Power Select */
+#define C2_IRCS 0 /* Internal Reference Clock Select */
+
+#define MCG_C3 REG_8(0x40064002) /* MCG Control 3 Register */
+#define MCG_C4 REG_8(0x40064003) /* MCG Control 4 Register */
+
+#define MCG_C5 REG_8(0x40064004) /* MCG Control 5 Register */
+#define C5_PLLCLKEN0 6 /* PLL Clock Enable */
+#define C5_PLLSTEN0 5 /* PLL Stop Enable */
+#define C5_PRDIV0 0 /* PLL External Reference Divider */
+#define C5_PRDIV0_M (uint8_t)(BITS(5) << C5_PRDIV0)
+
+#define MCG_C6 REG_8(0x40064005) /* MCG Control 6 Register */
+#define C6_LOLIE0 7 /* Loss of Lock Interrrupt Enable */
+#define C6_PLLS 6 /* PLL Select */
+#define C6_CME0 5 /* Clock Monitor Enable */
+#define C6_VDIV0 0 /* VCO 0 Divider */
+#define C6_VDIV0_M (uint8_t)(BITS(5) << C6_VDIV0)
+
+#define MCG_S REG_8(0x40064006) /* MCG Status Register */
+#define S_LOLS0 7 /* Loss of Lock Status */
+#define S_LOCK0 6 /* Lock Status */
+#define S_PLLST 5 /* PLL Select Status */
+#define S_IREFST 4 /* Internal Reference Status */
+#define S_CLKST 2 /* Clock Mode Status */
+#define S_CLKST_M (uint8_t)(BITS(2) << S_CLKST)
+#define S_OSCINIT0 1 /* OSC Initialization */
+#define S_IRCST 0 /* Internal Reference Clock Status */
+
+#define MCG_SC REG_8(0x40064008) /* MCG Status and Control Register */
+#define MCG_ATCVH REG_8(0x4006400A) /* MCG Auto Trim Compare Value High Register */
+#define MCG_ATCVL REG_8(0x4006400B) /* MCG Auto Trim Compare Value Low Register */
+#define MCG_C7 REG_8(0x4006400C) /* MCG Control 7 Register */
+#define MCG_C8 REG_8(0x4006400D) /* MCG Control 8 Register */
+
+#endif /* LIB_REG_MCG_H */
diff --git a/lib/reg/pmc.h b/lib/reg/pmc.h
new file mode 100644
index 0000000..4aef0be
--- /dev/null
+++ b/lib/reg/pmc.h
@@ -0,0 +1,27 @@
+#ifndef LIB_REG_PMC_H
+#define LIB_REG_PMC_H
+
+#include <reg/regdefs.h>
+
+#define PMC_LVDSC1 REG_8(0x4007D000) /* Low Voltage Detect Status And Control 1 register */
+#define LVDSC1_LVDF 7 /* Low-Voltage Detect Flag */
+#define LVDSC1_LVDACK 6 /* Low-Voltage Detect Acknowledge */
+#define LVDSC1_LVDIE 5 /* Low-Voltage Detect Interrupt Enable */
+#define LVDSC1_LVDRE 4 /* Low-Voltage Detect Reset Enable */
+#define LVDSC1_LVDV 0 /* Low-Voltage Detect Voltage Select */
+#define LVDSC1_LVDV_M (uint8_t)(BITS(2) << LVDSC1_LVDV)
+
+#define PMC_LVDSC2 REG_8(0x4007D001) /* Low Voltage Detect Status And Control 2 register */
+#define LVDSC2_LVWF 7 /* Low-Voltage Warning Flag */
+#define LVDSC2_LVWACK 6 /* Low-Voltage Warning Acknowledge */
+#define LVDSC2_LVWIE 5 /* Low-Voltage Warning Interrupt Enable */
+#define LVDSC2_LVWV 0 /* Low-Voltage Warning Voltage Select */
+#define LVDSC2_LVWV_M (uint8_t)(BITS(2) << LVDSC2_LVWV)
+
+#define PMC_REGSC REG_8(0x4007D002) /* Regulator Status And Control register */
+#define REGSC_BGEN 4 /* Bandgap Enable In VLPx Operation */
+#define REGSC_ACKISO 3 /* Acknowledge Isolation */
+#define REGSC_REGONS 2 /* Regulator In Run Regulation Status */
+#define REGSC_BGBE 1 /* Bandgap Buffer Enable */
+
+#endif /* LIB_REG_PMC_H */
diff --git a/lib/reg/port.h b/lib/reg/port.h
new file mode 100644
index 0000000..76b8d9c
--- /dev/null
+++ b/lib/reg/port.h
@@ -0,0 +1,42 @@
+#ifndef LIB_REG_PORT_H
+#define LIB_REG_PORT_H
+
+#include <reg/regdefs.h>
+
+#define PORTA_PCR(n) REG_32(0x40049000 + 4 * (n)) /* Pin Control Register n */
+#define PORTB_PCR(n) REG_32(0x4004A000 + 4 * (n)) /* Pin Control Register n */
+#define PORTC_PCR(n) REG_32(0x4004B000 + 4 * (n)) /* Pin Control Register n */
+#define PORTD_PCR(n) REG_32(0x4004C000 + 4 * (n)) /* Pin Control Register n */
+#define PORTE_PCR(n) REG_32(0x4004D000 + 4 * (n)) /* Pin Control Register n */
+#define PCR_ISF 24 /* Interrupt Status Flag */
+#define PCR_IRQC 16 /* Interrupt Configuration */
+#define PCR_IRQC_M (uint32_t)(BITS(4) << PCR_IRQC)
+#define PCR_LK 15 /* Lock Register */
+#define PCR_MUX 8 /* Pin Mux Control */
+#define PCR_MUX_M (uint32_t)(BITS(3) << PCR_MUX)
+#define PCR_DSE 6 /* Drive Strength Enable */
+#define PCR_ODE 5 /* Open Drain Enable */
+#define PCR_PFE 4 /* Passive Filter Enable */
+#define PCR_SRE 2 /* Slew Rate Enable */
+#define PCR_PE 1 /* Pull Enable */
+#define PCR_PS 0 /* Pull Select */
+
+#define PORTA_GPCLR REG_32(0x40049080) /* Global Pin Control Low Register */
+#define PORTB_GPCLR REG_32(0x4004A080) /* Global Pin Control Low Register */
+#define PORTC_GPCLR REG_32(0x4004B080) /* Global Pin Control Low Register */
+#define PORTD_GPCLR REG_32(0x4004C080) /* Global Pin Control Low Register */
+#define PORTE_GPCLR REG_32(0x4004D080) /* Global Pin Control Low Register */
+
+#define PORTA_GPCHR REG_32(0x40049084) /* Global Pin Control High Register */
+#define PORTB_GPCHR REG_32(0x4004A084) /* Global Pin Control High Register */
+#define PORTC_GPCHR REG_32(0x4004B084) /* Global Pin Control High Register */
+#define PORTD_GPCHR REG_32(0x4004C084) /* Global Pin Control High Register */
+#define PORTE_GPCHR REG_32(0x4004D084) /* Global Pin Control High Register */
+
+#define PORTA_ISFR REG_32(0x400490A0) /* Interrupt Status Flag Register */
+#define PORTB_ISFR REG_32(0x4004A0A0) /* Interrupt Status Flag Register */
+#define PORTC_ISFR REG_32(0x4004B0A0) /* Interrupt Status Flag Register */
+#define PORTD_ISFR REG_32(0x4004C0A0) /* Interrupt Status Flag Register */
+#define PORTE_ISFR REG_32(0x4004D0A0) /* Interrupt Status Flag Register */
+
+#endif /* LIB_REG_PORT_H */
diff --git a/lib/reg/regdefs.h b/lib/reg/regdefs.h
new file mode 100644
index 0000000..6a38c76
--- /dev/null
+++ b/lib/reg/regdefs.h
@@ -0,0 +1,25 @@
+#ifndef LIB_REG_REGDEFS_H
+#define LIB_REG_REGDEFS_H
+
+#include <stdint.h>
+
+#define REG_8(a) (*(volatile uint8_t *)(a))
+#define REG_16(a) (*(volatile uint16_t *)(a))
+#define REG_32(a) (*(volatile uint32_t *)(a))
+
+#define BV(b) (1 << (b))
+#define IS_BIT_SET(reg, bit) (!!((reg) & BV(bit)))
+#define WAIT_BIT_UNSET(reg, bit) do { } while (IS_BIT_SET(reg, bit))
+#define WAIT_BIT_SET(reg, bit) do { } while (!IS_BIT_SET(reg, bit))
+
+#define SET_BIT(reg, bit) ((reg) |= BV(bit))
+#define UNSET_BIT(reg, bit) ((reg) &= ~BV(bit))
+
+#define GET_BIT(reg, bit) !!((reg) & BV(bit))
+#define GET_BITS(reg, offset) (((reg) & (offset ## _M)) >> (offset))
+
+#define SET_MASKED(reg, mask, bits) ((reg) = ((reg) & ~(mask)) | ((bits) & (mask)))
+
+#define BITS(n) (0xffffffff >> (32 - (n)))
+
+#endif /* LIB_REG_REGDEFS_H */
diff --git a/lib/reg/sim.h b/lib/reg/sim.h
new file mode 100644
index 0000000..93839e8
--- /dev/null
+++ b/lib/reg/sim.h
@@ -0,0 +1,70 @@
+#ifndef LIB_REG_SIM_H
+#define LIB_REG_SIM_H
+
+#include <reg/regdefs.h>
+
+#define SIM_SOPT REG_32(0x140047000) /* System Options Register 1 */
+#define SIM_SOPT1CFG REG_32(0x40047004) /* SOPT1 Configuration Register */
+
+#define SIM_SOPT2 REG_32(0x40048004) /* System Options Register 2 */
+#define SOPT2_USBSRC 18 /* USB clock source select */
+#define SOPT2_PLLFLLSEL 16 /* PLL/FLL clock select */
+#define SOPT2_TRACECLKSEL 12 /* Debug trace clock select */
+#define SOPT2_PTD7PAD 11 /* PTD7 pad drive strength */
+#define SOPT2_CLKOUTSEL 5 /* CLKOUT select */
+#define SOPT2_CLKOUTSEL_M (BITS(3) << SOPT2_CLKOUTSEL)
+#define SOPT2_RTCCLKOUTSEL 4 /* RTC clock out select */
+
+#define SIM_SOPT4 REG_32(0x4004800C) /* System Options Register 4 */
+#define SIM_SOPT5 REG_32(0x40048010) /* System Options Register 5 */
+#define SIM_SOPT7 REG_32(0x40048018) /* System Options Register 7 */
+#define SIM_SDID REG_32(0x40048024) /* System Device Identification Register */
+#define SIM_SCGC1 REG_32(0x40048028) /* System Clock Gating Control Register 1 */
+#define SIM_SCGC2 REG_32(0x4004802C) /* System Clock Gating Control Register 2 */
+#define SIM_SCGC3 REG_32(0x40048030) /* System Clock Gating Control Register 3 */
+
+#define SIM_SCGC4 REG_32(0x40048034) /* System Clock Gating Control Register 4 */
+#define SCGC4_VREF 20 /* VREF Clock Gate Control */
+#define SCGC4_CMP 19 /* Comparator Clock Gate Control */
+#define SCGC4_USBOTG 18 /* USB Clock Gate Control */
+#define SCGC4_UART2 12 /* UART2 Clock Gate Control */
+#define SCGC4_UART1 11 /* UART1 Clock Gate Control */
+#define SCGC4_UART0 10 /* UART0 Clock Gate Control */
+#define SCGC4_I2C1 7 /* I2C1 Clock Gate Control */
+#define SCGC4_I2C0 6 /* I2C0 Clock Gate Control */
+#define SCGC4_CMT 2 /* CMT Clock Gate Control */
+#define SCGC4_EWM 1 /* EWM Clock Gate Control */
+
+#define SIM_SCGC5 REG_32(0x40048038) /* System Clock Gating Control Register 5 */
+#define SCGC5_PORTE 13 /* Port E Clock Gate Control */
+#define SCGC5_PORTD 12 /* Port D Clock Gate Control */
+#define SCGC5_PORTC 11 /* Port C Clock Gate Control */
+#define SCGC5_PORTB 10 /* Port B Clock Gate Control */
+#define SCGC5_PORTA 9 /* Port A Clock Gate Control */
+#define SCGC5_TSI 5 /* TSI Clock Gate Control */
+#define SCGC5_LPTIMER 0 /* Low Power Timer Access Control */
+
+#define SIM_SCGC6 REG_32(0x4004803C) /* System Clock Gating Control Register 6 */
+#define SIM_SCGC7 REG_32(0x40048040) /* System Clock Gating Control Register 7 */
+
+#define SIM_CLKDIV1 REG_32(0x40048044) /* System Clock Divider Register 1 */
+#define CLKDIV1_OUTDIV1 28 /* Clock 1 output divider value */
+#define CLKDIV1_OUTDIV1_M (uint32_t)(BITS(4) << CLKDIV1_OUTDIV1)
+#define CLKDIV1_OUTDIV2 24 /* Clock 2 output divider value */
+#define CLKDIV1_OUTDIV2_M (uint32_t)(BITS(4) << CLKDIV1_OUTDIV2)
+#define CLKDIV1_OUTDIV4 16 /* Clock 4 output divider value */
+#define CLKDIV1_OUTDIV4_M (uint32_t)(BITS(4) << CLKDIV1_OUTDIV4)
+
+#define SIM_CLKDIV2 REG_32(0x40048048) /* System Clock Divider Register 2 */
+#define CLKDIV2_USBDIV 1 /* USB clock divider divisor */
+#define CLKDIV2_USBDIV_M (uint32_t)(BITS(3) << CLKDIV2_USBDIV)
+#define CLKDIV2_USBFRAC 0 /* USB clock divider fraction */
+
+#define SIM_FCFG1 REG_32(0x4004804C) /* Flash Configuration Register 1 */
+#define SIM_FCFG2 REG_32(0x40048050) /* Flash Configuration Register 2 */
+#define SIM_UIDH REG_32(0x40048054) /* Unique Identification Register High */
+#define SIM_UIDMH REG_32(0x40048058) /* Unique Identification Register Mid-High */
+#define SIM_UIDML REG_32(0x4004805C) /* Unique Identification Register Mid Low */
+#define SIM_UIDL REG_32(0x40048060) /* Unique Identification Register Low */
+
+#endif /* LIB_REG_SIM_H */
diff --git a/lib/reg/uart.h b/lib/reg/uart.h
new file mode 100644
index 0000000..a23d2f6
--- /dev/null
+++ b/lib/reg/uart.h
@@ -0,0 +1,8 @@
+#ifndef LIB_REG_UART_H
+#define LIB_REG_UART_H
+
+#include "regdefs.h"
+
+
+
+#endif /* LIB_REG_UART_H */
diff --git a/lib/reg/usbotg.h b/lib/reg/usbotg.h
new file mode 100644
index 0000000..56f00aa
--- /dev/null
+++ b/lib/reg/usbotg.h
@@ -0,0 +1,202 @@
+#ifndef LIB_REG_USBOTG_H
+#define LIB_REG_USBOTG_H
+
+#include "regdefs.h"
+
+#define USB0_PERID REG_8(0x40072000) /* Peripheral ID register */
+#define PERID_ID 0 /* Peripheral Identification */
+#define PERID_ID_M (uint8_t)(0x3F)
+
+#define USB0_IDCOMP REG_8(0x40072004) /* Peripheral ID Complement register */
+#define IDCOMP_NID 0 /* Ones complement of peripheral identification bits. */
+#define IDCOMP_NID_M (uint8_t)(0x3F)
+
+#define USB0_REV REG_8(0x40072008) /* Peripheral Revision register */
+#define REV_REV 0 /* Revision */
+#define REV_REV_M (uint8_t)(0xFF)
+
+#define USB0_ADDINFO REG_8(0x4007200C) /* Peripheral Additional Info register */
+#define ADDINFO_IRQNUM 3 /* Assigned Interrupt Request Number. */
+#define ADDINFO_IRQNUM_M (uint8_t)(BITS(5) << ADDINFO_IRQNUM)
+#define ADDINFO_IEHOST 0 /* Set if SIE is in host mode. */
+
+#define USB0_OTGISTAT REG_8(0x40072010) /* OTG Interrupt Status register */
+#define OTGISTAT_IDCHG 7 /* Set on change in the ID Signal from the USB connector. */
+#define OTGISTAT_ONEMSEC 6 /* Set on 1 ms timer expire. */
+#define OTGISTAT_LINE_STATE_CHG 5 /* Set when USB line state changes. */
+#define OTGISTAT_SESSVLDCHG 3
+#define OTGISTAT_B_SESS_CHG 2
+#define OTGISTAT_AVBUSCHG 0
+
+#define USB0_OTGICR REG_8(0x40072014) /* OTG Interrupt Control Register */
+#define OTGICR_IDEN 7 /* ID Interrupt Enable */
+#define OTGICR_ONEMSECEN 6 /* One Millisecond Interrupt Enable */
+#define OTGICR_LINESTATEEN 5 /* Line State Change Interrupt Enable */
+#define OTGICR_SESSVLDEN 3 /* Session Valid Interrupt Enable */
+#define OTGICR_BSESSEN 2 /* B Session END Interrupt Enable */
+#define OTGICR_AVBUSEN 0 /* A VBUS Valid Interrupt Enable */
+
+#define USB0_OTGSTAT REG_8(0x40072018) /* OTG Status register */
+#define OTGSTAT_ID 7
+#define OTGSTAT_ONEMSECEN 6
+#define OTGSTAT_LINESTATESTABLE 5
+#define OTGSTAT_SESS_VLD 3
+#define OTGSTAT_BSESSEND 2
+#define OTGSTAT_AVBUSVLD 0
+
+#define USB0_OTGCTL REG_8(0x4007201C) /* OTG Control register */
+#define OTGCTL_DPHIGH 7 /* D+ Data Line pullup resistor enable */
+#define OTGCTL_DPLOW 5 /* D+ Data Line pull-down resistor enable */
+#define OTGCTL_DMLOW 4 /* D– Data Line pull-down resistor enable */
+#define OTGCTL_OTGEN 2 /* On-The-Go pullup/pulldown resistor enable */
+
+#define USB0_ISTAT REG_8(0x40072080) /* Interrupt Status register */
+#define ISTAT_STALL 7 /* Stall Interrupt */
+#define ISTAT_ATTACH 6 /* Attach Interrupt */
+#define ISTAT_RESUME 5
+#define ISTAT_SLEEP 4
+#define ISTAT_TOKDNE 3
+#define ISTAT_SOFTOK 2
+#define ISTAT_ERROR 1
+#define ISTAT_USBRST 0
+
+#define USB0_INTEN REG_8(0x40072084) /* Interrupt Enable register */
+#define INTEN_STALLEN 7 /* STALL Interrupt Enable */
+#define INTEN_ATTACHEN 6 /* ATTACH Interrupt Enable */
+#define INTEN_RESUMEEN 5 /* RESUME Interrupt Enable */
+#define INTEN_SLEEPEN 4 /* SLEEP Interrupt Enable */
+#define INTEN_TOKDNEEN 3 /* TOKDNE Interrupt Enable */
+#define INTEN_SOFTOKEN 2 /* SOFTOK Interrupt Enable */
+#define INTEN_ERROREN 1 /* ERROR Interrupt Enable */
+#define INTEN_USBRSTEN 0 /* USBRST Interrupt Enable */
+
+#define USB0_ERRSTAT REG_8(0x40072088) /* Error Interrupt Status register */
+#define ERRSTAT_BTSERR 7
+#define ERRSTAT_DMAERR 5
+#define ERRSTAT_BTOERR 4
+#define ERRSTAT_DFN8 3
+#define ERRSTAT_CRC16 2
+#define ERRSTAT_CRC5EOF 1
+#define ERRSTAT_PIDERR 0
+
+#define USB0_ERREN REG_8(0x4007208C) /* Error Interrupt Enable register */
+#define ERREN_BTSERREN 7 /* BTSERR Interrupt Enable */
+#define ERREN_DMAERREN 5 /* DMAERR Interrupt Enable */
+#define ERREN_BTOERREN 4 /* BTOERR Interrupt Enable */
+#define ERREN_DFN8EN 3 /* DFN8 Interrupt Enable */
+#define ERREN_CRC16EN 2 /* CRC16 Interrupt Enable */
+#define ERREN_CRC5EOFEN 1 /* CRC5EOF Interrupt Enable */
+#define ERREN_PIDERREN 0 /* PIDERR Interrupt Enable */
+
+#define USB0_STAT REG_8(0x40072090) /* Status register */
+#define STAT_ENDP 4
+#define STAT_ENDP_M (uint8_t)(BITS(4) << STAT_ENDP)
+#define STAT_TX 3 /* Transmit Indicator */
+#define STAT_ODD 2
+
+#define USB0_CTL REG_8(0x40072094) /* Control register */
+#define CTL_JSTATE 7 /* Live USB differential receiver JSTATE signal */
+#define CTL_SE0 6 /* Live USB Single Ended Zero signal */
+#define CTL_TXSUSPENDTOKENBUSY 5
+#define CTL_RESET 4
+#define CTL_HOSTMODEEN 3
+#define CTL_RESUME 2
+#define CTL_ODDRST 1
+#define CTL_USBENSOFEN 0 /* USB Enable */
+
+#define USB0_ADDR REG_8(0x40072098) /* Address register */
+#define ADDR_LSEN 7
+#define ADDR_ADDR 0
+#define ADDR_ADDR_M (uint8_t)(BITS(7))
+
+#define USB0_BDTPAGE1 REG_8(0x4007209C) /* BDT Page Register 1 */
+
+#define USB0_FRMNUML REG_8(0x400720A0) /* Frame Number Register Low */
+#define FRMNUML_FRM 0
+#define FRMNUML_FRM_M (uint8_t)(BITS(8) << FRMNUML_FRM)
+
+#define USB0_FRMNUMH REG_8(0x400720A4) /* Frame Number Register High */
+#define FRMNUMH_FRM 0
+#define FRMNUMH_FRM_M (uint8_t)(BITS(3) << FRMNUMH_FRM_M)
+
+#define USB0_TOKEN REG_8(0x400720A8) /* Token register */
+#define TOKEN_TOKENPID 4
+#define TOKEN_TOKENPID_M (uint8_t)(BITS(4) << TOKEN_TOKENPID)
+#define TOKEN_TOKENENDPT 0
+#define TOKEN_TOKENENDPT_M (uint8_t)(BITS(4) << TOKEN_TOKENENDPT)
+
+#define USB0_SOFTHLD REG_8(0x400720AC) /* SOF Threshold Register */
+#define SOFTHLD_CNT 0
+#define SOFTHLD_CNT_M (uint8_t)(BITS(8) << SOFTHLD_CNT)
+
+#define USB0_BDTPAGE2 REG_8(0x400720B0) /* BDT Page Register 2 */
+#define BDTPAGE2_BDTBA 0
+#define BDTPAGE2_BDTBA_M (uint8_t)(BITS(8) << BDTPAGE2_BDTBA)
+
+#define USB0_BDTPAGE3 REG_8(0x400720B4) /* BDT Page Register 3 */
+#define BDTPAGE3_BDTBA 0
+#define BDTPAGE3_BDTBA_M (uint8_t)(BITS(8) << BDTPAGE3_BDTBA)
+
+#define USB0_ENDPT(n) REG_8(0x400720C0 + 4 * (n)) /* Endpoint Control register */
+#define ENDPT_HOSTWOHUB 7
+#define ENDPT_RETRYDIS 6
+#define ENDPT_EPCTLDIS 4
+#define ENDPT_EPRXEN 3
+#define ENDPT_EPTXEN 2
+#define ENDPT_EPSTALL 1
+#define ENDPT_EPHSHK 0
+
+#define USB0_USBCTRL REG_8(0x40072100) /* USB Control register */
+#define USBCTRL_SUSP 7 /* Places the USB transceiver into the suspend state. */
+#define USBCTRL_PDE 6 /* Enables the weak pulldowns on the USB transceiver. */
+
+#define USB0_OBSERVE REG_8(0x40072104) /* USB OTG Observe register */
+#define OBSERVE_DPPU 7 /* Provides observability of the D+ Pullup */
+#define OBSERVE_DPPD 6 /* Provides observability of the D+ Pulldown */
+#define OBSERVE_DMPD 4 /* Provides observability of the D- Pulldown */
+
+#define USB0_CONTROL REG_8(0x40072108) /* USB OTG Control register */
+#define CONTROL_DPPULLUPNONOTG 4 /* DP Pullup in non-OTG device mode state */
+
+#define USB0_USBTRC0 REG_8(0x4007210C) /* USB Transceiver Control Register 0 */
+#define USBTRC0_USBRESET 7 /* USB Reset */
+#define USBTRC0_USBRESMEN 5 /* Asynchronous Resume Interrupt Enable */
+#define USBTRC0_SYNC_DET 1 /* Synchronous USB Interrupt Detect */
+#define USBTRC0_USB_RESUME_INT 0 /* USB Asynchronous Interrupt */
+
+#define USB0_USBFRMADJUST REG_8(0x40072114) /* Frame Adjust Register */
+#define USBFRMADJUST_ADJ 0
+#define USBFRMADJUST_ADJ_M (uint8_t)(BITS(8) << USBFRMADJUST_ADJ)
+
+__attribute__ ((packed))
+struct usb0_bd {
+ uint32_t desc;
+ void *addr;
+};
+//#define USB0_BD(desc, addr) (struct usb0_bd){(desc), (addr)}
+#define USB0_BD_INIT(size, data01) ((size) << BD_BC | BV(BD_OWN) | \
+ ((data01) & 1) << BD_DATA01 | BV(BD_DTS))
+#define BD_BC 16 /* Byte Count */
+#define BD_BC_M (uint32_t)(BITS(10) << BC)
+#define BD_OWN 7
+#define BD_DATA01 6
+#define BD_KEEP 5
+#define BD_NINC 4
+#define BD_DTS 3
+#define BD_BDT_STALL 2
+#define BD_TOK_PID 2
+#define BD_TOK_PID_M (uint32_t)(BITS(4) << BD_TOK_PID)
+
+#define BD_TOK_PID_OUT 0x1
+#define BD_TOK_PID_IN 0x9
+#define BD_TOK_PID_SETUP 0xd
+
+#define BD_TOK_PID_DATA0 0x3
+#define BD_TOK_PID_DATA1 0xb
+#define BD_TOK_PID_ACK 0x2
+#define BD_TOK_PID_STALL 0xe
+#define BD_TOK_PID_NAK 0xa
+#define BD_TOK_PID_TIMEOUT 0x0
+#define BD_TOK_PID_ERROR 0xf
+
+#endif /* LIB_REG_USBOTG_H */
diff --git a/lib/reg/wdog.h b/lib/reg/wdog.h
new file mode 100644
index 0000000..a2596c8
--- /dev/null
+++ b/lib/reg/wdog.h
@@ -0,0 +1,37 @@
+#ifndef LIB_REG_WDOG_H
+#define LIB_REG_WDOG_H
+
+#include <reg/regdefs.h>
+
+#define WDOG_STCTRLH REG_16(0x40052000) /* Watchdog Status and Control Register High */
+#define STCTRLH_DISTESTWDOG 14 /* Functional test mode disable */
+#define STCTRLH_BYTESEL 12 /* Byte test mode byte selector */
+#define STCTRLH_BYTESEL_M (uint16_t)(BITS(2) << STCTRLH_BYTESEL)
+#define STCTRLH_TESTSEL 11 /* Functional test mode test selector */
+#define STCTRLH_TESTWDOG 10 /* Functional test mode enable */
+#define STCTRLH_WAITEN 7 /* Wait mode WDOG enable */
+#define STCTRLH_STOPEN 6 /* Stop mode WDOG enable */
+#define STCTRLH_DBGEN 5 /* Debug mode WDOG enable */
+#define STCTRLH_ALLOWUPDATE 4 /* Allow further updates to write-once registers */
+#define STCTRLH_WINEN 3 /* Windowing mode enable */
+#define STCTRLH_IRQRSTEN 2 /* Debug breadcrumbs feature enable */
+#define STCTRLH_CLKSRC 1 /* Clock source selector */
+#define STCTRLH_WDOGEN 0 /* WDOG enable */
+
+#define WDOG_STCTRLL REG_16(0x40052002) /* Watchdog Status and Control Register Low */
+#define WDOG_TOVALH REG_16(0x40052004) /* Watchdog Time-out Value Register High */
+#define WDOG_TOVALL REG_16(0x40052006) /* Watchdog Time-out Value Register Low */
+#define WDOG_WINH REG_16(0x40052008) /* Watchdog Window Register High */
+#define WDOG_WINL REG_16(0x4005200A) /* Watchdog Window Register Low */
+#define WDOG_REFRESH REG_16(0x4005200C) /* Watchdog Refresh register */
+
+#define WDOG_UNLOCK REG_16(0x4005200E) /* Watchdog Unlock Register */
+#define WDOG_UNLOCK_S1 0xC520 /* Unlock Sequence 1/2 */
+#define WDOG_UNLOCK_S2 0xD928 /* Unlock Sequence 2/2 */
+
+#define WDOG_TMROUTH REG_16(0x40052010) /* Watchdog Timer Output Register High */
+#define WDOG_TMROUTL REG_16(0x40052012) /* Watchdog Timer Output Register Low */
+#define WDOG_RSTCNT REG_16(0x40052014) /* Watchdog Reset Count register */
+#define WDOG_PRESC REG_16(0x40052016) /* Watchdog Prescaler register */
+
+#endif /* LIB_REG_WDOG_H */
diff --git a/lib/string.c b/lib/string.c
new file mode 100644
index 0000000..25935b3
--- /dev/null
+++ b/lib/string.c
@@ -0,0 +1,38 @@
+#include <string.h>
+#include <stddef.h>
+
+void *memcpy(void * restrict _dest, const void * restrict _src, size_t n)
+{
+ unsigned char *dest = _dest;
+ const unsigned char *src = _src;
+
+ for (size_t i = 0; i < n; i++)
+ dest[i] = src[i];
+
+ return dest;
+}
+
+void *memmove(void *_dest, const void *_src, size_t n)
+{
+ unsigned char *dest = _dest;
+ const unsigned char *src = _src;
+
+ if (_src < _dest) {
+ for (size_t i = 0; i < n; i++)
+ dest[i] = src[i];
+ } else {
+ for (size_t i = n; i > 0; i++)
+ dest[i - 1] = src[i - 1];
+ }
+
+ return dest;
+}
+
+void *memset(void *_s, int _c, size_t n)
+{
+ unsigned char *s = _s, c = (unsigned char)_c;
+ for (size_t i = 0; i < n; i++)
+ s[i] = c;
+
+ return _s;
+}
diff --git a/lib/string.h b/lib/string.h
new file mode 100644
index 0000000..9c204dd
--- /dev/null
+++ b/lib/string.h
@@ -0,0 +1,10 @@
+#ifndef LIB_STRING_H
+#define LIB_STRING_H
+
+#include <stddef.h>
+
+void *memcpy(void * restrict dest, const void * restrict src, size_t n);
+void *memmove(void *dest, const void *src, size_t n);
+void *memset(void *s, int c, size_t n);
+
+#endif /* LIB_STRING_H */
diff --git a/setup.c b/setup.c
new file mode 100644
index 0000000..ad29e40
--- /dev/null
+++ b/setup.c
@@ -0,0 +1,90 @@
+#include <reg.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "asm.h"
+#include "usb/usb.h"
+
+extern char _sflashdata[], _sdata[], _edata[];
+extern char _sbss[], _ebss[];
+
+#define RANGE0_VAL 2 /* Very High Frequency */
+#define HGO0_VAL 0 /* High Gain Mode Disabled */
+#define FRDIV_VAL 4 /* Divide 16 MHz by 512 to produce 31.25 kHz FLL Reference */
+#define PRDIV0_VAL 7 /* Divide 16 MHz by 8 to produce 2 MHz PLL Reference */
+#define VDIV0_VAL 12 /* Multiply 2 MHz by 36 to produce 72 MHz resulting clock */
+
+/* Option 2 Clock Configuration */
+#define OUTDIV1_VAL 0 /* 72 MHz / 1 = 72 MHz Core / system clocks */
+#define OUTDIV2_VAL 1 /* 72 MHz / 2 = 36 MHz Bus clock */
+#define OUTDIV4_VAL 2 /* 72 MHz / 3 = 24 MHz Flash clock */
+
+void setup(void);
+void setup(void)
+{
+ /* Disable interrupts for setup */
+ CLI();
+
+ /* Disable Watchdog Timer */
+ WDOG_UNLOCK = WDOG_UNLOCK_S1;
+ WDOG_UNLOCK = WDOG_UNLOCK_S2;
+ UNSET_BIT(WDOG_STCTRLH, STCTRLH_WDOGEN);
+
+ /* Copy data and clear bss */
+ memcpy(_sdata, _sflashdata, _edata - _sdata);
+ memset(_sbss, 0, _ebss - _sdata);
+
+ /* Enable port clocks */
+ SIM_SCGC5 |= BV(SCGC5_PORTE) | BV(SCGC5_PORTD) | BV(SCGC5_PORTC)
+ | BV(SCGC5_PORTB) | BV(SCGC5_PORTA);
+
+ /* Change Clock Dividers */
+ SIM_CLKDIV1 = OUTDIV1_VAL << CLKDIV1_OUTDIV1
+ | OUTDIV2_VAL << CLKDIV1_OUTDIV2
+ | OUTDIV4_VAL << CLKDIV1_OUTDIV4;
+
+ /* Clear latched peripherals and I/O */
+ if (IS_BIT_SET(PMC_REGSC, REGSC_ACKISO))
+ SET_BIT(PMC_REGSC, REGSC_ACKISO);
+
+ /*
+ * CLOCKING SETUP
+ */
+
+ /* FEI to FBE */
+ SET_MASKED(MCG_C2, C2_RANGE0_M | BV(C2_HGO0) | BV(C2_EREFS0),
+ RANGE0_VAL << C2_RANGE0 | BV(C2_EREFS0));
+
+ SET_MASKED(MCG_C1, C1_CLKS_M | C1_FRDIV_M | BV(C1_IREFS),
+ 2 << C1_CLKS | FRDIV_VAL << C1_FRDIV);
+
+ WAIT_BIT_SET(MCG_S, S_OSCINIT0);
+ WAIT_BIT_UNSET(MCG_S, S_IREFST);
+ do { } while (GET_BITS(MCG_S, S_CLKST) != 2);
+
+ /* Enable Clock Monitor */
+ SET_BIT(MCG_C6, C6_CME0);
+
+
+ /* FBE to PBE */
+ SET_MASKED(MCG_C5, C5_PRDIV0_M, PRDIV0_VAL << C5_PRDIV0);
+ SET_MASKED(MCG_C6, BV(C6_PLLS) | C6_VDIV0_M, BV(C6_PLLS) | VDIV0_VAL << C6_VDIV0);
+
+ WAIT_BIT_SET(MCG_S, S_PLLST);
+ WAIT_BIT_SET(MCG_S, S_LOCK0);
+
+ /* PBE to PEE */
+ SET_MASKED(MCG_C1, C1_CLKS_M, 0);
+
+ do { } while (GET_BITS(MCG_S, S_CLKST) != 3);
+
+ /* Set PLL as the clock to use for things which can take PLL or FLL */
+ SET_BIT(SIM_SOPT2, SOPT2_PLLFLLSEL);
+ SET_MASKED(SIM_SOPT2, SOPT2_CLKOUTSEL_M, 4 << SOPT2_CLKOUTSEL);
+
+
+ usb_setup();
+
+ /* Enable interrupts for setup */
+ STI();
+}
diff --git a/uart/uart.c b/uart/uart.c
new file mode 100644
index 0000000..031cf74
--- /dev/null
+++ b/uart/uart.c
@@ -0,0 +1,5 @@
+#include "uart.h"
+
+void uart_setup(void)
+{
+}
diff --git a/uart/uart.h b/uart/uart.h
new file mode 100644
index 0000000..984d704
--- /dev/null
+++ b/uart/uart.h
@@ -0,0 +1,6 @@
+#ifndef UART_UART_H
+#define UART_UART_H
+
+void uart_setup(void);
+
+#endif /* UART_UART_H */
diff --git a/usb/bdt.h b/usb/bdt.h
new file mode 100644
index 0000000..5f0a123
--- /dev/null
+++ b/usb/bdt.h
@@ -0,0 +1,14 @@
+#ifndef USB_BDT_H
+#define USB_BDT_H
+
+#include <reg/usbotg.h>
+
+extern struct usb0_bd usb_bdt[4 * 16];
+
+#define BDT_ENDPT(n, tx, odd) (usb_bdt[(n) << 2 | (tx & 1) << 1 | (odd & 1)])
+#define BDT_RX 0
+#define BDT_TX 1
+#define BDT_EVEN 0
+#define BDT_ODD 1
+
+#endif /* USB_BDT_H */
diff --git a/usb/ds_conf.xxd b/usb/ds_conf.xxd
new file mode 100644
index 0000000..89c6e16
--- /dev/null
+++ b/usb/ds_conf.xxd
@@ -0,0 +1,34 @@
+09 1 Length - 9
+02 1 Descriptor Type - 2 (Configuration)
+22 2 Total Length - 32
+00
+01 1 Number of Interfaces - 1
+01 1 Configuration Value - 1
+00 1 Configuration String - 0
+c0 1 Attributes - none
+32 1 Maximum Current - 100mA
+09 1 Length - 9
+04 1 Descriptor Type - 4 (Interface)
+00 1 Interface Number - 0
+00 1 Alternate Setting - 0
+01 1 Number of Endpoints - 1
+03 1 Interface Class - 3 (HID)
+01 1 Interface Sub Class - 1 (Boot)
+02 1 Interface Protocol - 1 (Keyboard)
+00 1 Interface String - 0
+09 1 Length (HID Descriptor) - 9
+21 1 Descriptor Type - 33 (HID)
+11 2 HID Class Spec Version - 1.1
+01
+00 1 Country Code - N/A
+01 1 Number of Descriptors - 1
+22 1 Descriptor Type - 34 (REPORT)
+34 2 Descriptor Length - 52
+00
+07 1 Length - 7
+05 1 Descriptor Type - 5 (Endpoint)
+81 1 Endpoint Address - 1 IN
+03 1 Attributes - Interrupt; Data Endpoint
+08 2 Maximum packet size - 8
+00
+40 1 Interval - 60 Frames
diff --git a/usb/ds_dev.xxd b/usb/ds_dev.xxd
new file mode 100644
index 0000000..306da63
--- /dev/null
+++ b/usb/ds_dev.xxd
@@ -0,0 +1,18 @@
+12 1 Length - 18
+01 1 Descriptor type - 1
+00 2 USB Release - 2.0
+02
+ff 1 Device Class - Interface Specific
+00 1 Device Sub Class - Interface Specific
+00 1 Device Protocol - Interface Specific
+40 1 Max Packet Size - 64
+c0 2 VID (0x16c0)
+16
+dc 2 PID (0x047c)
+05
+01 2 Device Release BCD - 0.01
+00
+01 1 Manufacturer String - 1
+00 1 Product String - 0
+00 1 Serial Number String - 0
+01 1 Number of Configurations - 1
diff --git a/usb/ds_lang.xxd b/usb/ds_lang.xxd
new file mode 100644
index 0000000..e6e334c
--- /dev/null
+++ b/usb/ds_lang.xxd
@@ -0,0 +1,4 @@
+04 1 Length - 4
+03 1 Type - 3 (Language)
+09 2 LANGID - EN US
+04
diff --git a/usb/ds_str1.xxd b/usb/ds_str1.xxd
new file mode 100644
index 0000000..1aea777
--- /dev/null
+++ b/usb/ds_str1.xxd
@@ -0,0 +1,22 @@
+16 1 Length - 22
+03 1 Type - 3 (String)
+74 20 - the-tk.com
+00
+68
+00
+65
+00
+2d
+00
+74
+00
+6b
+00
+2e
+00
+63
+00
+6f
+00
+6d
+00
diff --git a/usb/endpt0.c b/usb/endpt0.c
new file mode 100644
index 0000000..a60e1a4
--- /dev/null
+++ b/usb/endpt0.c
@@ -0,0 +1,199 @@
+#include <le.h>
+#include <reg/usbotg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <reg/gpio.h>
+
+#include "bdt.h"
+#include "endpt0.h"
+
+#include "ds_conf.xxh"
+#include "ds_dev.xxh"
+#include "ds_lang.xxh"
+#include "ds_str1.xxh"
+
+#define MAX_PACKET 64
+static unsigned char buf[2][MAX_PACKET];
+static bool odd;
+static bool data01;
+
+static volatile unsigned int nextaddr;
+
+static const void *tx_data;
+static size_t tx_size;
+
+struct tok_setup {
+ uint8_t reqtyp;
+ uint8_t req;
+ uint16_t value;
+ uint16_t index;
+ uint16_t length;
+};
+
+/* read_setup: parse a SETUP token's data */
+static void read_setup(struct tok_setup *setup, const void *_data)
+{
+ const unsigned char *data = _data;
+
+ setup->reqtyp = data[0];
+ setup->req = data[1];
+ setup->value = le16toh(&data[2]);
+ setup->index = le16toh(&data[4]);
+ setup->length = le16toh(&data[6]);
+}
+
+/* TODO: Make this a shared thing across all USB endpoints */
+
+/* puttx: place data in the current buffer descriptor */
+static bool puttx(const void *data, size_t size)
+{
+ if (GET_BIT(BDT_ENDPT(0, BDT_TX, odd).desc, BD_OWN))
+ return false;
+
+ BDT_ENDPT(0, BDT_TX, odd).addr = (void *)data;
+ BDT_ENDPT(0, BDT_TX, odd).desc = USB0_BD_INIT(size, data01);
+ odd = !odd;
+ data01 = !data01;
+
+ return true;
+}
+
+/* pushtx: attempt to push rest of the current transmission into a BD */
+static bool pushtx(void)
+{
+ size_t size = tx_size;
+
+ if (tx_data == NULL)
+ return false;
+
+ if (size > MAX_PACKET)
+ size = MAX_PACKET;
+
+ if (!puttx(tx_data, size))
+ return false;
+
+ tx_data = (const char *)tx_data + size;
+ tx_size -= size;
+
+ if (tx_size == 0 && size < MAX_PACKET)
+ tx_data = NULL;
+
+ return true;
+}
+
+/* quetx: enqueue a transmission */
+static void quetx(const void *data, size_t size)
+{
+ tx_data = data;
+ tx_size = size;
+
+ while (pushtx())
+ ;
+}
+
+/* usb_endpt0_disable: Disable endpoint 0 (not valid) */
+void usb_endpt0_disable(void)
+{
+}
+
+/* usb_endpt0_enable: Enable and reset endpoint 0 */
+void usb_endpt0_enable(void)
+{
+ BDT_ENDPT(0, BDT_RX, BDT_EVEN).addr = buf[0];
+ BDT_ENDPT(0, BDT_RX, BDT_EVEN).desc = USB0_BD_INIT(sizeof buf[0], 0);
+
+ BDT_ENDPT(0, BDT_RX, BDT_ODD).addr = buf[1];
+ BDT_ENDPT(0, BDT_RX, BDT_ODD).desc = USB0_BD_INIT(sizeof buf[1], 0);
+
+ BDT_ENDPT(0, BDT_TX, BDT_EVEN).addr = NULL;
+ BDT_ENDPT(0, BDT_TX, BDT_EVEN).desc = 0;
+
+ BDT_ENDPT(0, BDT_TX, BDT_ODD).addr = NULL;
+ BDT_ENDPT(0, BDT_TX, BDT_ODD).desc = 0;
+
+ USB0_ENDPT(0) = BV(ENDPT_EPRXEN) | BV(ENDPT_EPTXEN) | BV(ENDPT_EPHSHK);
+ nextaddr = 0;
+ tx_data = NULL;
+ odd = 0;
+ data01 = 0;
+}
+
+/* trunc: truncate size_t to a limit TODO: MOVE THIS */
+static inline size_t trunc(size_t val, size_t max)
+{
+ if (val > max)
+ return max;
+ return val;
+}
+
+/* tok_setup: process a setup token */
+static void tok_setup(struct tok_setup *setup)
+{
+ switch (setup->reqtyp << 8 | setup->req) {
+ case 0x0005: /* SET ADDRESS */
+ nextaddr = setup->value;
+ puttx(NULL, 0);
+ break;
+ case 0x0009: /* SET CONFIGURATION */
+ puttx(NULL, 0);
+ break;
+ case 0x8006: /* GET DESCRIPTOR */
+ switch (setup->value) {
+ case 0x0100: /* DEVICE */
+ quetx(usb_ds_dev, trunc(usb_ds_dev_len, setup->length));
+ return;
+ case 0x0200: /* CONFIGURATION */
+ quetx(usb_ds_conf, trunc(usb_ds_conf_len, setup->length));
+ return;
+ case 0x0300: /* STRING 0 */
+ quetx(usb_ds_lang, trunc(usb_ds_lang_len, setup->length));
+ return;
+ case 0x0301: /* STRING 1 */
+ quetx(usb_ds_str1, trunc(usb_ds_str1_len, setup->length));
+ return;
+ }
+ /* fall through */
+ default:
+ SET_BIT(USB0_ENDPT(0), ENDPT_EPSTALL);
+ break;
+ }
+}
+
+void usb_endpt0_token(uint8_t state)
+{
+ struct usb0_bd *bd;
+ struct tok_setup setup;
+
+ bd = &BDT_ENDPT(0, GET_BIT(state, STAT_TX), GET_BIT(state, STAT_ODD));
+
+
+ switch (GET_BITS(bd->desc, BD_TOK_PID)) {
+ case BD_TOK_PID_OUT:
+ bd->desc = USB0_BD_INIT(sizeof buf[0], 1);
+ break;
+ case BD_TOK_PID_IN:
+ pushtx();
+ if (nextaddr) {
+ USB0_ADDR = nextaddr;
+ nextaddr = 0;
+ }
+ break;
+ case BD_TOK_PID_SETUP:
+ read_setup(&setup, bd->addr);
+ bd->desc = USB0_BD_INIT(sizeof buf[0], 1);
+
+ BDT_ENDPT(0, BDT_TX, BDT_EVEN).desc = 0;
+ BDT_ENDPT(0, BDT_TX, BDT_ODD).desc = 0;
+ tx_data = NULL;
+
+ data01 = 1;
+
+ tok_setup(&setup);
+
+ break;
+ }
+
+ USB0_CTL = BV(CTL_USBENSOFEN);
+}
diff --git a/usb/endpt0.h b/usb/endpt0.h
new file mode 100644
index 0000000..4ba89ed
--- /dev/null
+++ b/usb/endpt0.h
@@ -0,0 +1,10 @@
+#ifndef USB_ENDPT0_H
+#define USB_ENDPT0_H
+
+#include <stdint.h>
+
+void usb_endpt0_disable(void);
+void usb_endpt0_enable(void);
+void usb_endpt0_token(uint8_t state);
+
+#endif /* USB_ENDPT0_H */
diff --git a/usb/endpt1.c b/usb/endpt1.c
new file mode 100644
index 0000000..b29c3bb
--- /dev/null
+++ b/usb/endpt1.c
@@ -0,0 +1,36 @@
+#include <reg/usbotg.h>
+#include <stdint.h>
+
+#include "bdt.h"
+#include "endpt1.h"
+
+#define MAX_PACKET 64
+
+static unsigned char buf[2][MAX_PACKET];
+
+void usb_endpt1_enable(void)
+{
+}
+
+void usb_endpt1_disable(void)
+{
+}
+
+void usb_endpt1_token(uint8_t state)
+{
+ struct usb0_bd *bd;
+
+ bd = &BDT_ENDPT(1, GET_BIT(state, STAT_TX), GET_BIT(state, STAT_ODD));
+
+ switch (GET_BITS(bd->desc, BD_TOK_PID)) {
+ case BD_TOK_PID_OUT:
+ bd->desc = USB0_BD_INIT(sizeof buf[0], 1);
+ /* should never happen */
+ break;
+ case BD_TOK_PID_IN:
+ /*pushtx();*/
+ break;
+ }
+
+ /*USB0_CTL = BV(CTL_USBENSOFEN);*/
+}
diff --git a/usb/endpt1.h b/usb/endpt1.h
new file mode 100644
index 0000000..9be7522
--- /dev/null
+++ b/usb/endpt1.h
@@ -0,0 +1,8 @@
+#ifndef USB_ENDPT1_H
+#define USB_ENDPT1_H
+
+void usb_endpt1_enable(void);
+void usb_endpt1_disable(void);
+void usb_endpt1_token(uint8_t state);
+
+#endif /* USB_ENDPT1_H */
diff --git a/usb/usb.c b/usb/usb.c
new file mode 100644
index 0000000..ebd3179
--- /dev/null
+++ b/usb/usb.c
@@ -0,0 +1,94 @@
+#include <reg/sim.h>
+#include <reg/usbotg.h>
+#include <reg/gpio.h>
+#include <stddef.h>
+
+#include "usb.h"
+#include "bdt.h"
+#include "endpt0.h"
+#include "endpt1.h"
+
+#define USBFRAC_VAL 1 /* 72 MHz * 2 = 144 MHz (Top of Fraction) */
+#define USBDIV_VAL 2 /* 144 MHz / 3 = 48 MHz (Bottom of Fraction) */
+
+/* TODO: Move this to lib somewhere */
+#define CLRPEND(n) REG_32(0xE000E280 + 4 * (n))
+#define ISR_CLRPEND(i) CLRPEND((i) / 32) = BV((i) % 32);
+
+#define SETENA(n) REG_32(0xE000E100 + 4 * (n))
+#define ISR_SETENA(i) SETENA((i) / 32) = BV((i) % 32);
+
+
+__attribute__ ((aligned(512)))
+struct usb0_bd usb_bdt[16 * 4]; /* TODO: Only use the number of endpoints that are needed */
+
+/* usb_setup: Setup function for USB subsystem */
+void usb_setup(void)
+{
+ /* Clock Setup */
+ SET_BIT(SIM_SOPT2, SOPT2_USBSRC);
+ SET_MASKED(SIM_CLKDIV2, CLKDIV2_USBDIV_M | BV(CLKDIV2_USBFRAC),
+ USBDIV_VAL << CLKDIV2_USBDIV | USBFRAC_VAL << CLKDIV2_USBFRAC);
+ SET_BIT(SIM_SCGC4, SCGC4_USBOTG);
+
+ /* Reset USB and wait more than 2 USB clock cycles */
+ SET_BIT(USB0_USBTRC0, USBTRC0_USBRESET);
+ for (int i = 0; i < 5; i++)
+ ;
+
+ /* 512 bit aligned BDT address */
+ USB0_BDTPAGE1 = (uintptr_t)usb_bdt >> 8 & 0xff;
+ USB0_BDTPAGE2 = (uintptr_t)usb_bdt >> 16 & 0xff;
+ USB0_BDTPAGE3 = (uintptr_t)usb_bdt >> 24 & 0xff;
+
+ /* Initial Configuration */
+ SET_MASKED(USB0_USBCTRL, BV(USBCTRL_SUSP) | BV(USBCTRL_PDE), 0);
+ SET_BIT(USB0_CONTROL, CONTROL_DPPULLUPNONOTG);
+ SET_BIT(USB0_INTEN, INTEN_USBRSTEN);
+
+ /* NVIC Enable interrupt */
+ ISR_CLRPEND(73);
+ ISR_SETENA(73);
+
+ /* Enable USB */
+ USB0_CTL = BV(CTL_USBENSOFEN);
+}
+
+/* i_usbrst: Handler for USBRST USB interrupt */
+static void i_usbrst(void)
+{
+ SET_BIT(USB0_CTL, CTL_ODDRST);
+
+ usb_endpt0_enable();
+ usb_endpt1_disable();
+
+ USB0_ADDR = 0;
+
+ SET_BIT(USB0_INTEN, INTEN_TOKDNEEN);
+}
+
+/* i_tokdne: Handler for TOKDNE USB interrupt */
+static void i_tokdne(void)
+{
+ uint8_t stat = USB0_STAT;
+
+ switch (GET_BITS(stat, STAT_ENDP)) {
+ case 0: usb_endpt0_token(stat); break;
+ case 1: usb_endpt1_token(stat); break;
+ }
+}
+
+/* usb_isr: interrupt service routine for the USB FS SIE */
+void usb_isr(void)
+{
+ uint8_t stat = USB0_ISTAT;
+
+ if (IS_BIT_SET(stat, ISTAT_TOKDNE)) {
+ i_tokdne();
+ USB0_ISTAT = BV(ISTAT_TOKDNE);
+ }
+ if (IS_BIT_SET(stat, ISTAT_USBRST)) {
+ i_usbrst();
+ USB0_ISTAT = BV(ISTAT_USBRST);
+ }
+}
diff --git a/usb/usb.h b/usb/usb.h
new file mode 100644
index 0000000..64d0585
--- /dev/null
+++ b/usb/usb.h
@@ -0,0 +1,7 @@
+#ifndef USB_H
+#define USB_H
+
+void usb_setup(void);
+void usb_isr(void);
+
+#endif /* USB_H */
diff --git a/vectors.s b/vectors.s
new file mode 100644
index 0000000..1981eb5
--- /dev/null
+++ b/vectors.s
@@ -0,0 +1,98 @@
+.syntax unified
+
+.section ".vectors"
+// ARM Core System Handler Vectors
+.long _estack // 0 ARM: Initial Stack Pointer
+.long _start // 1 ARM: Initial Program Counter
+.long _halt // 2 ARM: Non-maskable Interrupt (NMI)
+.long _halt // 3 ARM: Hard Fault
+.long _halt // 4 ARM: MemManage Fault
+.long _halt // 5 ARM: Bus Fault
+.long _halt // 6 ARM: Usage Fault
+.fill 4,4,0 // 7..10
+.long 0 // 11 ARM: Supervisor call (SVCall)
+.long 0 // 12 ARM: Debug Monitor
+.long 0 // 13 -
+.long 0 // 14 ARM: Pendable request for system service (PendableSrvReq)
+.long 0 // 15 ARM: System tick timer (SysTick)
+
+// Non-Core Vectors
+.long 0 // 16 DMA: DMA channel 0 transfer complete
+.long 0 // 17 DMA: DMA channel 1 transfer complete
+.long 0 // 18 DMA: DMA channel 2 transfer complete
+.long 0 // 19 DMA: DMA channel 3 transfer complete
+.long 0 // 20 DMA: DMA channel 4 transfer complete
+.long 0 // 21 DMA: DMA channel 5 transfer complete
+.long 0 // 22 DMA: DMA channel 6 transfer complete
+.long 0 // 23 DMA: DMA channel 7 transfer complete
+.long 0 // 24 DMA: DMA channel 8 transfer complete
+.long 0 // 25 DMA: DMA channel 9 transfer complete
+.long 0 // 26 DMA: DMA channel 10 transfer complete
+.long 0 // 27 DMA: DMA channel 11 transfer complete
+.long 0 // 28 DMA: DMA channel 12 transfer complete
+.long 0 // 29 DMA: DMA channel 13 transfer complete
+.long 0 // 30 DMA: DMA channel 14 transfer complete
+.long 0 // 31 DMA: DMA channel 15 transfer complete
+.long 0 // 32 DMA: DMA error interrupt channels 0-15
+.long 0 // 33 -
+.long 0 // 34 Flash_memory: Command complete
+.long 0 // 35 Flash_memory: Read collision
+.long 0 // 36 Mode_Controller: Low-voltage detect, low-voltage warning
+.long 0 // 37 LLWU: Low Leakage Wakeup
+.long 0 // 38 WDOG or EWM: Both watchdog modules share this interrupt.
+.long 0 // 39 -
+.long 0 // 40 I2C0: -
+.long 0 // 41 I2C1: -
+.long 0 // 42 SPI0: Single interrupt vector for all sources
+.long 0 // 43 SPI1: Single interrupt vector for all sources
+.long 0 // 44 -
+.long 0 // 45 CAN0: OR'ed Message buffer (0-15)
+.long 0 // 46 CAN0: Bus Off
+.long 0 // 47 CAN0: Error
+.long 0 // 48 CAN0: Transmit Warning
+.long 0 // 49 CAN0: Receive Warning
+.long 0 // 50 CAN0: Wake Up Transmit
+.long 0 // 51 I2S0: Transmit
+.long 0 // 52 I2S0: Receive
+.fill 7,4,0 // 53..59 -
+.long 0 // 60 UART0: Single interrupt vector for UART LON sources
+.long 0 // 61 UART0: Single interrupt vector for UART status sources
+.long 0 // 62 UART0: Single interrupt vector for UART error sources
+.long 0 // 63 UART1: Single interrupt vector for UART status sources
+.long 0 // 64 UART1: Single interrupt vector for UART error sources
+.long 0 // 65 UART2: Single interrupt vector for UART status sources
+.long 0 // 66 UART2: Single interrupt vector for UART error sources
+.fill 6,4,0 // 67..72 -
+.long 0 // 73 ADC0: -
+.long 0 // 74 ADC1: -
+.long 0 // 75 CMP0: -
+.long 0 // 76 CMP1: -
+.long 0 // 77 CMP2: -
+.long 0 // 78 FTM0: Single interrupt vector for all sources
+.long 0 // 79 FTM1: Single interrupt vector for all sources
+.long 0 // 80 FTM2: Single interrupt vector for all sources
+.long 0 // 81 CMT: -
+.long 0 // 82 RTC: Alarm interrupt
+.long 0 // 83 RTC: Seconds interrupt
+.long 0 // 84 PIT: Channel 0
+.long 0 // 85 PIT: Channel 1
+.long 0 // 86 PIT: Channel 2
+.long 0 // 87 PIT: Channel 3
+.long 0 // 88 PDB: -
+.long usb_isr // 89 USBOTG: -
+.long 0 // 90 USB_Charger_Detect: -
+.fill 6,4,0 // 91..96
+.long 0 // 97 DAC0: -
+.long 0 // 98 -
+.long 0 // 99 TSI: Single interrupt vector for all sources
+.long 0 // 100 MCG: -
+.long 0 // 101 LPT: -
+.long 0 // 102 -
+.long 0 // 103 Port_control_module: Pin detect (Port A)
+.long 0 // 104 Port_control_module: Pin detect (Port B)
+.long 0 // 105 Port_control_module: Pin detect (Port C)
+.long 0 // 106 Port_control_module: Pin detect (Port D)
+.long 0 // 107 Port_control_module: Pin detect (Port E)
+.long 0 // 108 -
+.long 0 // 109 -
+.long 0 // 110 Software: Software interrupt 4