diff --git a/D2EF/C64/Makefile b/D2EF/C64/Makefile
new file mode 100644
index 00000000..60982216
--- /dev/null
+++ b/D2EF/C64/Makefile
@@ -0,0 +1,34 @@
+
+all: binaries.c
+
+kapi: kapi_hi.prg kapi_lo.prg kapi_nm.prg
+launcher: launcher_hi.bin
+
+DEPDIR = .
+df = $(DEPDIR)/$(*F)
+
+SRCS = kapi_hi.asm kapi_lo.asm kapi_nm.asm
+
+N = "\\033[0m"
+B = "\\033[1m"
+
+copyright.bin: copyright.php
+	@echo "$(B)Assembling $@$(N)"
+	php copyright.php
+
+%.prg: %.asm
+	@echo "$(B)Assembling $<$(N)"
+	php mkdep.php $< > $(df).P
+	java -jar KickAss2.25/KickAss.jar -showmem -vicesymbols -o $@ $<
+
+launcher_hi.bin: launcher_hi.asm
+	@echo "$(B)Assembling $<$(N)"
+	java -jar KickAss3.42/KickAss.jar -binfile -showmem launcher_hi.asm -o launcher_hi.bin
+
+binaries.c: kapi launcher
+	@echo "$(B)Assembling $@$(N)"
+	php binaries.php
+
+# autodep
+
+-include $(SRCS:%.asm=$(DEPDIR)/%.P)
diff --git a/D2EF/C64/binaries.php b/D2EF/C64/binaries.php
new file mode 100644
index 00000000..ce0125d1
--- /dev/null
+++ b/D2EF/C64/binaries.php
@@ -0,0 +1,32 @@
+<?php
+
+$fc = fopen("binaries.c", "w");
+fwrite($fc, "#include <stdint.h>\n");
+
+$fh = fopen("binaries.h", "w");
+fwrite($fh, "#ifndef BINARIES_H
+#define BINARIES_H
+
+#include <stdint.h>
+");
+
+foreach (array(
+           'kapi_hi.prg' => 2,
+           'kapi_nm.prg' => 2,
+           'kapi_lo.prg' => 2,
+           'launcher_hi.bin' => 0,
+           'startup.bin' => 0,
+           'sprites.bin' => 0,
+         ) AS $file => $offset) {
+  $bin = substr(file_get_contents($file), $offset);
+  fwrite($fc, 'uint8_t '.substr($file, 0, -4).'[] = {');
+  for ($i = 0; $i < strlen($bin); $i++) {
+    fwrite($fc, ord($bin[$i]).', ');
+  }
+  fwrite($fc, "};\n");
+
+  fwrite($fh, 'extern uint8_t '.substr($file, 0, -4)."[];\n");
+  fwrite($fh, '#define '.substr($file, 0, -4).'_size '.strlen($bin)."\n");
+}
+
+fwrite($fh, "#endif\n");
diff --git a/D2EF/C64/copyright.php b/D2EF/C64/copyright.php
new file mode 100644
index 00000000..0df64102
--- /dev/null
+++ b/D2EF/C64/copyright.php
@@ -0,0 +1,11 @@
+<?php
+
+$text = '  ALEX\'S DISK2EASYFLASH - "LOAD" V0.92  ';
+
+for ($i = 0; $i < strlen($text); $i++) {
+  if (ord($text[$i]) >= 0x41 && ord($text[$i]) <= 0x5A) {
+    $text[$i] = chr(ord($text[$i]) - 0x40);
+  }
+}
+
+file_put_contents("copyright.bin", $text);
diff --git a/D2EF/C64/emu_chrin.asm b/D2EF/C64/emu_chrin.asm
new file mode 100644
index 00000000..1f887333
--- /dev/null
+++ b/D2EF/C64/emu_chrin.asm
@@ -0,0 +1,60 @@
+.pc = * "CHRIN"
+	DO_CHRIN:
+
+		// in: -
+		// used: A
+		// out: A, C
+
+		// setup exit
+		:mov #$4c ; RETURN_COMMAND
+		:mov16 REAL_CHRIN ; RETURN_ADDR
+
+		// check active device
+		lda $99
+		bne !just_rts+ // other device = just the orig. routine
+
+	!keyboard:
+		lda $d0
+		bne !just_rts+
+
+		sty TEMP1
+
+jmp get_out
+		lda AUTOTYPE_STATUS
+		bne !line1+
+	!line2:
+		ldy #[autotype_line2 - autotype_line1]
+		.byte $2c
+	!line1:
+		ldy #0
+
+	!loop:
+		lda autotype_line1, y
+		beq !new_line+
+		jsr $e716 // print char
+		inc $c8
+		iny
+		bne !loop-
+
+	!new_line:
+		sta $0292
+		sta $d3
+		sta $d4
+		inc $d0
+
+	!exit_chrin:
+		ldy TEMP1
+		dec AUTOTYPE_STATUS
+		bpl !just_rts+
+
+get_out:
+		// disable CHRIN
+		:mov16 REAL_CHRIN ; $0324
+
+	!just_rts:
+		jmp DISABLE_CRT
+
+autotype_line1:
+	.byte $4c, $4f, $41, $44, $22, $2a, $22, $2c, $38, $2c, $31, 0
+autotype_line2:
+	.byte $52, $55, $4e, 0
diff --git a/D2EF/C64/emu_helper.asm b/D2EF/C64/emu_helper.asm
new file mode 100644
index 00000000..e95511f4
--- /dev/null
+++ b/D2EF/C64/emu_helper.asm
@@ -0,0 +1,82 @@
+.pc = * "Helpers"
+
+.if(!fast_load){
+	READ_BYTE: // TRASHES X!!
+		:if SMC_ADDR+2 ; EQ ; #[[BANK_START + BANK_SIZE] >> 8] ; ENDIF ; !endif+
+			// go to next bank
+			:mov #BANK_START>>8 ; SMC_ADDR+2
+			inc SMC_BANK+1
+		!endif:
+		ldx SMC_OUR_BANK+1
+		jsr RAM_READ_BYTE
+		:inc16 SMC_ADDR+1
+		:dec16 OPEN_SIZE_TODO ; X
+		rts
+}
+
+	// temporary variables
+	.const FILENAME_LEN = $bf
+
+	FIND_FILE:
+		// requires that the filename is copied to FILENAME
+		// return C=error
+
+		// y=len of filename
+		ldy $b7
+
+		// check for empty filename
+		beq file_not_found
+
+		// if len > 16 chars: fail
+		:if Y ; GT ; #16 ; use_real_load
+
+		// find last non-space char
+	!loop:
+		dey
+		lda FILENAME, y
+		cmp #$20
+		beq !loop-
+		// remember length
+		iny
+		sty FILENAME_LEN
+
+		// find the entry
+		:mov16 #DIR-24 ; ENTRY_PTR
+	find_loop:
+		:add16_8 ENTRY_PTR ; #24
+		ldy #0
+		lda (ENTRY_PTR), y
+		beq file_not_found // EOF = file not found
+
+	!loop:
+		lda FILENAME, y
+		cmp #$2a // '*'
+		beq file_found // match (due to a *) -> found file
+		cmp (ENTRY_PTR), y
+		bne find_loop // mismatch -> next line
+
+		iny // next char
+		cpy FILENAME_LEN
+		bne !loop- // not at enf of name -> next char
+
+		cpy #16
+		beq !skip+
+		// found a file whith <16 chars -> check for \0 as next char in name
+		lda (ENTRY_PTR), y
+		bne find_loop // filenamelen mismatch
+	!skip:
+
+	file_found:
+		clc
+		rts
+
+	file_not_found:
+		sec
+		rts
+
+
+
+	RETURN_SUCCESS:
+		clc
+		:mov #$60 ; RETURN_COMMAND
+		jmp DISABLE_CRT
diff --git a/D2EF/C64/emu_load.asm b/D2EF/C64/emu_load.asm
new file mode 100644
index 00000000..6ba2eb6b
--- /dev/null
+++ b/D2EF/C64/emu_load.asm
@@ -0,0 +1,164 @@
+.pc = * "LOAD"
+	DO_LOAD:
+
+		// check weather load is active
+		lda $93
+		bne use_real_load // we do'nt support verify -> use real load
+
+		// check drive#
+		lda $ba
+		cmp #$08
+		beq find_file // if drive is not 8 -> use real load
+
+	use_real_load:
+
+		// failure+return
+		:mov #$4c ; RETURN_COMMAND
+		:mov16 REAL_LOAD ; RETURN_ADDR
+
+		lda $93
+		ldx $c3
+		ldy $c4
+
+		jmp DISABLE_CRT
+
+
+		// search file - exit if not found
+	find_file:
+		jsr FIND_FILE
+		bcs use_real_load
+
+		// print SEARCHING
+		:mov16 #$f5af ; SMC_PRINT_SEARCH_LOADING+1
+		jsr PRINT_SEARCH_LOADING
+		// wait, if it's the first time
+		lda AUTOTYPE_STATUS
+		bmi !skip+
+		ldx #0
+		ldy #0
+	!loop:
+		lda ($00, x)
+		lda ($00, x)
+		lda ($00, x)
+		lda ($00, x)
+		inx
+		bne !loop-
+		iny
+		bne !loop-
+	!skip:
+		// print LOADING
+		:mov16 #$f5d2 ; SMC_PRINT_SEARCH_LOADING+1
+		jsr PRINT_SEARCH_LOADING
+
+
+		ldy #16
+		// copy bank
+		lda (ENTRY_PTR), y
+		clc
+		adc $df00
+.if(!fast_load){
+		sta SMC_BANK+1
+}else{
+		sta ZP_BANK
+}
+		iny
+		iny // upper bank-register
+		// copy offset
+		lda (ENTRY_PTR), y
+.if(!fast_load){
+		sta SMC_ADDR+1
+}else{
+		sta SRC_PTR+0
+}
+		iny
+		lda (ENTRY_PTR), y
+.if(!fast_load){
+		sta SMC_ADDR+2
+}else{
+		sta SRC_PTR+1
+}
+		iny
+		// copy load-address
+		lda (ENTRY_PTR), y
+		sta DEST_PTR+0
+		iny
+		lda (ENTRY_PTR), y
+		sta DEST_PTR+1
+		iny
+		// copy size
+		lda (ENTRY_PTR), y
+		pha
+		iny
+		lda (ENTRY_PTR), y
+		sta SIZE+1
+		//iny
+		pla
+		sta SIZE+0
+
+		// load-address
+		lda $b9
+		bne copy_file
+
+	use_own_la:
+		// use the laodaddress specified
+		:mov $c3 ; DEST_PTR+0
+		:mov $c4 ; DEST_PTR+1
+
+	copy_file:
+.if(!fast_load){
+		// dec 1, because we count to underflow
+		:dec16 SIZE
+
+		ldy #0
+	!loop:
+		jsr READ_BYTE
+		sta (DEST_PTR), y
+		:inc16 DEST_PTR
+		lda SIZE+0
+		bne nodecupper
+		lda SIZE+1
+		beq !exit+
+		dec SIZE+1
+	nodecupper:
+		dec SIZE+0
+		jmp !loop-
+
+	!exit:
+		// success+return
+		ldx DEST_PTR+0
+		ldy DEST_PTR+1
+		clc
+		:mov #$60 ; RETURN_COMMAND
+
+		jmp DISABLE_CRT
+
+
+}else{
+
+
+	// update size (for faked start < 0)
+	:add16_8 SIZE ; SRC_PTR
+
+	// lower source -> y ; copy always block-wise
+	:sub16_8 DEST_PTR ; SRC_PTR
+	ldy SRC_PTR
+	:mov #0 ; SRC_PTR
+	sta smc_limit+1
+
+	:if SIZE+1 ; NE ; #$00 ; JMP ; COPY_FILE
+	sty smc_limit+1
+	jmp COPY_FILE_LESS_THEN_ONE_PAGE
+
+}
+
+/*
+
+	fast:
+  ADDR AC XR YR SP 00 01 NV-BDIZC LIN CYC
+.;dfc6 60 00 3a f7 2f 37 00110100 000 004
+
+	slow:
+  ADDR AC XR YR SP 00 01 NV-BDIZC LIN CYC
+.;82db 60 00 3a f7 2f 37 00110100 000 004
+
+*/
diff --git a/D2EF/C64/emu_vectors.asm b/D2EF/C64/emu_vectors.asm
new file mode 100644
index 00000000..1a124d47
--- /dev/null
+++ b/D2EF/C64/emu_vectors.asm
@@ -0,0 +1,205 @@
+
+.pseudopc $df02 {
+
+	/*
+	** LOAD emulation (vector)
+	*/
+
+	VECTOR_LOAD:
+		// save REGS
+		sta $93
+//		stx $c3 - already done before calling
+//		sty $c4 - already done before calling
+
+		jsr copy_filename
+		jmp DO_LOAD
+
+	/*
+	** CHRIN emulation (vector)
+	*/
+
+	VECTOR_CHRIN:
+		jsr ENABLE_CRT
+		jmp DO_CHRIN
+
+	/*
+	** Variables
+	*/
+
+	REAL_CHRIN:
+		.fill 2, 0
+	REAL_LOAD:
+		.fill 2, 0
+
+	AUTOTYPE_STATUS:
+		.byte $01
+
+	FILENAME:
+		.fill 16, 0
+
+
+	/*
+	** read a byte
+	*/
+
+.if(!fast_load){
+	RAM_READ_BYTE:
+	SMC_BANK:
+		lda #$00
+		sta $de00
+	SMC_ADDR:
+		lda $ffff
+		stx $de00
+		rts
+}
+
+	copy_filename:
+		// copy filename
+		ldy #15
+	!loop:
+		lda ($bb), y
+		sta FILENAME, y
+		dey
+		bpl !loop-
+
+//		jmp ENABLE_CRT // return this subroutine
+
+	ENABLE_CRT:
+		pha
+		// no interrupts
+		sei
+		// remember 01 setting
+		lda $01
+		sta smc_one+1
+		// enable basic (cart), kernal (should already be) and i/o (should already be)
+		ora #$07
+		sta $01
+		// backup ZP-VARS
+		txa
+		pha
+		ldx #ZP_SIZE-1
+	!loop:
+		lda $100 - ZP_SIZE, x
+		sta BACKUP_ZP, x
+		dex
+		bpl !loop-
+		pla
+		tax
+		// enable rom
+		lda #MODE_16k|$80
+		sta IO_MODE
+		// jump to home bank
+	SMC_OUR_BANK:
+		lda #$00
+		sta $de00
+		//
+		pla
+		rts
+
+	PRINT_SEARCH_LOADING:
+		// disable rom
+		lda #MODE_RAM
+		sta IO_MODE
+		// call kernal
+	SMC_PRINT_SEARCH_LOADING:
+		jsr $ffff
+		// enable rom
+		lda #MODE_16k|$80
+		sta IO_MODE
+		rts
+
+.if(fast_load){
+
+	/*
+		do the file-copy
+	*/
+
+	add_bank:
+		:mov #BANK_START >> 8 ; SRC_PTR+1
+		inc ZP_BANK
+	COPY_FILE:
+		lda ZP_BANK
+		sta $de00
+	!loop:
+		lda (SRC_PTR), y
+		sta (DEST_PTR), y
+		iny
+		bne !loop-
+		inc DEST_PTR+1
+		inc SRC_PTR+1
+		dec SIZE+1
+		beq !skip+
+		:if SRC_PTR+1 ; EQ ; #[BANK_START+BANK_SIZE] >> 8; add_bank
+		jmp !loop-
+end_of_full_page:
+	!skip:
+		:if SRC_PTR+1 ; EQ ; #[BANK_START+BANK_SIZE] >> 8 ; ENDIF ; !endif+
+			:mov #BANK_START >> 8 ; SRC_PTR+1
+			inc ZP_BANK
+	COPY_FILE_LESS_THEN_ONE_PAGE:
+			lda ZP_BANK
+			sta $de00
+		!endif:
+		ldy SIZE
+		beq !skip+
+	!loop:
+		dey
+		lda (SRC_PTR), y
+		sta (DEST_PTR), y
+	smc_limit:
+		cpy #$00
+		bne !loop-
+
+	!skip:
+
+		// setup end of program
+		:add16_8 DEST_PTR ; SIZE
+
+		// success+return
+		ldx DEST_PTR+0
+		ldy DEST_PTR+1
+		clc
+		:mov #$60 ; RETURN_COMMAND
+	//	jmp DISABLE_CRT -- is done due to next address
+
+
+}
+
+	DISABLE_CRT:
+		php
+		pha
+		// restore ZP-VARS
+		txa
+		pha
+		ldx #ZP_SIZE-1
+	!loop:
+		lda BACKUP_ZP, x
+		sta $100 - ZP_SIZE, x
+		dex
+		bpl !loop-
+		pla
+		tax
+		// disable rom
+		lda #MODE_RAM
+		sta IO_MODE
+		// restore 01 setting
+	smc_one:
+		lda #$00
+		sta $01
+		//
+		pla
+		plp
+		// interrupts
+		cli
+	RETURN_COMMAND:
+		.fill 1, 0
+	RETURN_ADDR:
+		.fill 2, 0
+
+	BACKUP_ZP:
+		.fill ZP_SIZE, $ff
+
+
+
+
+}
diff --git a/D2EF/C64/helper/commands.asm b/D2EF/C64/helper/commands.asm
new file mode 100644
index 00000000..73010fab
--- /dev/null
+++ b/D2EF/C64/helper/commands.asm
@@ -0,0 +1,444 @@
+/*
+**
+**  Please read the manual!
+**
+**
+**
+**
+**  This file do contains only the constants and all the internal stuff...
+**  All internal functions have to be called with all arguments set.
+**  hop is always either _DEFAULT or a register
+*/
+
+
+/*
+** registers & other tags
+*/
+
+.var _noneid = 1
+
+.enum {
+	// default (for hop)
+	_DEFAULT = CmdArgument(AT_NONE, _noneid++),
+	
+	// 8bit registers
+	A = CmdArgument(AT_NONE, _noneid++),
+	X = CmdArgument(AT_NONE, _noneid++),
+	Y = CmdArgument(AT_NONE, _noneid++),
+	
+	// 16bit registers
+	XY = CmdArgument(AT_NONE, _noneid++),
+	
+	// self modifying code
+	SMC = CmdArgument(AT_NONE, _noneid++),
+
+	// mode:J	
+	JMP = CmdArgument(AT_NONE, _noneid++),
+	JSR = CmdArgument(AT_NONE, _noneid++),
+	BRANCH = CmdArgument(AT_NONE, _noneid++),
+	
+	// comparators
+	EQ = CmdArgument(AT_NONE, _noneid++),
+	NE = CmdArgument(AT_NONE, _noneid++),
+	LT = CmdArgument(AT_NONE, _noneid++),
+	LE = CmdArgument(AT_NONE, _noneid++),
+	GE = CmdArgument(AT_NONE, _noneid++),
+	GT = CmdArgument(AT_NONE, _noneid++),
+	Lx = CmdArgument(AT_NONE, _noneid++),
+	Gx = CmdArgument(AT_NONE, _noneid++),
+	
+	// not / skip
+	NOT = CmdArgument(AT_NONE, _noneid++),
+	ELSE = CmdArgument(AT_NONE, _noneid),  // dont inc, it's same as SKIP
+	ENDIF = CmdArgument(AT_NONE, _noneid),  // dont inc, it's same as SKIP
+	SKIP = CmdArgument(AT_NONE, _noneid++)
+}
+
+/*
+** special tags
+*/
+
+.function _isunset(r){
+	.return r.getType() == AT_NONE && r.getValue() == 0
+}
+
+.function _isdefault(r){
+	.return r.getType() == AT_NONE && r.getValue() == _DEFAULT.getValue()
+}
+
+.function _isSMC(r){
+	.return r.getType() == AT_NONE && r.getValue() == SMC.getValue()
+}
+
+.function _isBRANCH(r){
+	.return r.getType() == AT_NONE && r.getValue() == BRANCH.getValue()
+}
+
+.function _isJMP(r){
+	.return r.getType() == AT_NONE && r.getValue() == JMP.getValue()
+}
+
+.function _isJSR(r){
+	.return r.getType() == AT_NONE && r.getValue() == JSR.getValue()
+}
+
+.function _isjump(r){
+	.return r.getType() == AT_NONE && r.getValue() >= JMP.getValue() && r.getValue() <= BRANCH.getValue()
+}
+
+.function _isNOT(r){
+	.return r.getType() == AT_NONE && r.getValue() == NOT.getValue()
+}
+
+.function _isSKIP(r){
+	.return r.getType() == AT_NONE && r.getValue() == SKIP.getValue()
+}
+
+/*
+** 8bit
+*/
+
+.function _isregister8(r){
+	.return r.getType() == AT_NONE && r.getValue() >= A.getValue() && r.getValue() <= Y.getValue()
+}
+
+.function _equalregisters8(r1, r2){
+	.return _isregister8(r1) && _isregister8(r2) && r1.getValue() == r2.getValue()
+}
+
+.pseudocommand _load reg ; arg {
+	.if(_equalregisters8(reg, A)){
+		lda arg
+	}else .if(_equalregisters8(reg, X)){
+		ldx arg
+	}else .if(_equalregisters8(reg, Y)){
+		ldy arg
+	}else{
+		.error "can only load memory into the registers A,X,Y"
+	}
+}
+
+.pseudocommand _store reg ; arg {
+	.if(_equalregisters8(reg, A)){
+		sta arg
+	}else .if(_equalregisters8(reg, X)){
+		stx arg
+	}else .if(_equalregisters8(reg, Y)){
+		sty arg
+	}else{
+		.error "can only store the registers A,X,Y into memory"
+	}
+}
+
+.pseudocommand _compare reg ; arg {
+	.if(_equalregisters8(reg, A)){
+		cmp arg
+	}else .if(_equalregisters8(reg, X)){
+		cpx arg
+	}else .if(_equalregisters8(reg, Y)){
+		cpy arg
+	}else{
+		.error "can only compare registers A,X,Y with memory"
+	}
+}
+
+/*
+** 16bit
+*/
+
+.function _isregister16(r){
+	.return r.getType() == AT_NONE && r.getValue() >= XY.getValue() && r.getValue() <= XY.getValue()
+}
+
+.function _equalregisters16(r1, r2){
+	.return _isregister16(r1) && _isregister16(r2) && r1.getValue() == r2.getValue()
+}
+
+.function _16bit_lowerArgument(arg) { 
+	.if (arg.getType() == AT_IMMEDIATE){
+		.return CmdArgument(arg.getType(), <arg.getValue())
+	}else .if(_equalregisters16(arg, XY)){
+		.return X
+	}else{
+		.return arg
+	}
+} 
+
+.function _16bit_upperArgument(arg) { 
+	.if (arg.getType() == AT_IMMEDIATE){
+		.return CmdArgument(arg.getType(), >arg.getValue())
+	}else .if(_equalregisters16(arg, XY)){
+		.return Y
+	}else{
+		.return CmdArgument(arg.getType(), arg.getValue()+1)
+	}
+} 
+
+/*
+** 24bit
+*/
+
+.function _24bit_lowerArgument(arg) { 
+		.return arg
+} 
+
+.function _24bit_middleArgument(arg) { 
+		.return CmdArgument(arg.getType(), arg.getValue()+1)
+} 
+
+.function _24bit_upperArgument(arg) { 
+		.return CmdArgument(arg.getType(), arg.getValue()+2)
+} 
+
+/*
+** branching
+*/
+
+.pseudocommand _beq mode ; pc {
+	.if(_isBRANCH(mode)){
+			beq pc
+	}else .if(_isJMP(mode)){
+			bne skip
+			jmp pc
+		skip:
+	}else .if(_isJSR(mode)){
+			bne skip
+			jsr pc
+		skip:
+	}else{
+		.error "unknown branch/jump mode"
+	}
+}
+
+.pseudocommand _bne mode ; pc {
+	.if(_isBRANCH(mode)){
+			bne pc
+	}else .if(_isJMP(mode)){
+			beq skip
+			jmp pc
+		skip:
+	}else .if(_isJSR(mode)){
+			beq skip
+			jsr pc
+		skip:
+	}else{
+		.error "unknown branch/jump mode"
+	}
+}
+
+.pseudocommand _bcc mode ; pc {
+	.if(_isBRANCH(mode)){
+			bcc pc
+	}else .if(_isJMP(mode)){
+			bcs skip
+			jmp pc
+		skip:
+	}else .if(_isJSR(mode)){
+			bcs skip
+			jsr pc
+		skip:
+	}else{
+		.error "unknown branch/jump mode"
+	}
+}
+
+.pseudocommand _bcs mode ; pc {
+	.if(_isBRANCH(mode)){
+			bcs pc
+	}else .if(_isJMP(mode)){
+			bcc skip
+			jmp pc
+		skip:
+	}else .if(_isJSR(mode)){
+			bcc skip
+			jsr pc
+		skip:
+	}else{
+		.error "unknown branch/jump mode"
+	}
+}
+
+/*
+** compare
+*/
+
+.function _iscomparator(r){
+	.return r.getType() == AT_NONE && r.getValue() >= EQ.getValue() && r.getValue() <= Gx.getValue()
+}
+
+.function _equalcomparators(c1, c2){
+	.return _iscomparator(c1) && _iscomparator(c2) && c1.getValue() == c2.getValue()
+}
+
+.pseudocommand _eq hop ; arg1 ; arg2 ; mode ; pc {
+	.if(_isregister8(arg1)){
+		.if(!_isdefault(hop)){
+			.error "if: if at least one of the args is a register, hop must be not set"
+		}
+		:_compare arg1 ; arg2
+	}else .if(_isregister8(arg2)){
+		.if(!_isdefault(hop)){
+			.error "if: if at least one of the args is a register, hop must be not set"
+		}
+		:_compare arg2 ; arg1
+	}else{
+		.if(_isdefault(hop)){
+			.eval hop = A
+		}
+		:_load hop ; arg1
+		.if(arg2.getType() != AT_IMMEDIATE || arg2.getValue() != 0){
+			:_compare hop ; arg2
+		}
+	}
+	:_beq mode ; pc
+}
+
+.pseudocommand _ne hop ; arg1 ; arg2 ; mode ; pc {
+	.if(_isregister8(arg1)){
+		.if(!_isdefault(hop)){
+			.error "if: if at least one of the args is a register, hop must be not set"
+		}
+		:_compare arg1 ; arg2
+	}else .if(_isregister8(arg2)){
+		.if(!_isdefault(hop)){
+			.error "if: if at least one of the args is a register, hop must be not set"
+		}
+		:_compare arg2 ; arg1
+	}else{
+		.if(_isdefault(hop)){
+			.eval hop = A
+		}
+		:_load hop ; arg1
+		.if(arg2.getType() != AT_IMMEDIATE || arg2.getValue() != 0){
+			:_compare hop ; arg2
+		}
+	}
+	:_bne mode ; pc
+}
+
+.pseudocommand _le hop ; arg1 ; arg2 ; mode ; pc {
+	.if(_isregister8(arg1)){
+		.if(!_isdefault(hop)){
+			.error "if: if at least one of the args is a register, hop must be not set"
+		}
+		.if(arg2.getType() == AT_IMMEDIATE){
+			.if(arg2.getValue() == 255){
+				.error "if: R <= 255 is always true"
+			}else{
+				// R <= M  ->  R < M+1
+				:_compare arg1 ; # arg2.getValue()+1
+				:_bcc mode ; pc
+			}
+		}else{
+			:_compare arg1 ; arg2
+			:_beq mode ; pc
+			:_bcc mode ; pc
+		}
+	}else .if(_isregister8(arg2)){
+		.if(!_isdefault(hop)){
+			.error "if: if at least one of the args is a register, hop must be not set"
+		}
+		// M <= R   ->   R >= M
+		:_compare arg2 ; arg1
+		:_bcs mode ; pc
+	}else{
+		.if(_isdefault(hop)){
+			.eval hop = A
+		}
+		// M <= N   ->   N >= M
+		:_load hop ; arg2
+		:_compare hop ; arg1
+		:_bcs mode ; pc
+	}
+}
+
+.pseudocommand _lt hop ; arg1 ; arg2 ; mode ; pc {
+	.if(_isregister8(arg1)){
+		.if(!_isdefault(hop)){
+			.error "if: if at least one of the args is a register, hop must be not set"
+		}
+		// R < M
+		:_compare arg1 ; arg2
+		:_bcc mode ; pc
+	}else .if(_isregister8(arg2)){
+		.if(!_isdefault(hop)){
+			.error "if: if at least one of the args is a register, hop must be not set"
+		}
+		// M < R  ->  R > M
+		:_gt arg2 ; arg1 ; pc
+	}else{
+		.if(_isdefault(hop)){
+			.eval hop = A
+		}
+		// M < N
+		:_load hop ; arg1
+		:_compare hop ; arg2
+		:_bcc mode ; pc
+	}
+}
+
+.pseudocommand _ge hop ; arg1 ; arg2 ; mode ; pc {
+	.if(_isregister8(arg1)){
+		.if(!_isdefault(hop)){
+			.error "if: if at least one of the args is a register, hop must be not set"
+		}
+		// R >= M
+		:_compare arg1 ; arg2
+		:_bcs mode ; pc
+	}else .if(_isregister8(arg2)){
+		.if(!_isdefault(hop)){
+			.error "if: if at least one of the args is a register, hop must be not set"
+		}
+		// M >= R  ->  R <= M
+		:_le arg2 ; arg1 ; pc
+	}else{
+		.if(_isdefault(hop)){
+			.eval hop = A
+		}
+		// M >= N
+		:_load hop ; arg1
+		:_compare hop ; arg2
+		:_bcs mode ; pc
+	}
+}
+
+.pseudocommand _gt hop ; arg1 ; arg2 ; mode ; pc {
+	.if(_isregister8(arg1)){
+		.if(!_isdefault(hop)){
+			.error "if: if at least one of the args is a register, hop must be not set"
+		}
+		.if(arg2.getType() == AT_IMMEDIATE){
+			.if(arg2.getValue() == 255){
+				.error "if: R > 255 is always false"
+			}else{
+				// R > M  ->  R >= M+1
+				:_compare arg1 ; # arg2.getValue()+1
+				:_bcs mode ; pc
+			}
+		}else{
+				:_compare arg1 ; arg2
+				beq skip
+				:_bcs mode ; pc
+			skip:
+		}
+	}else .if(_isregister8(arg2)){
+		.if(!_isdefault(hop)){
+			.error "if: if at least one of the args is a register, hop must be not set"
+		}
+		// M > R   ->   R < M
+		:_compare arg2 ; arg1
+		:_bcc mode ; pc
+	}else{
+		.if(_isdefault(hop)){
+			.eval hop = A
+		}
+		// M > N   ->   N < M
+		:_load hop ; arg2
+		:_compare hop ; arg1
+		:_bcc mode ; pc
+	}
+}
+
+
+//import source "commands8.asm"
+//import source "commands16.asm"
diff --git a/D2EF/C64/helper/commands16.asm b/D2EF/C64/helper/commands16.asm
new file mode 100644
index 00000000..2a07a1e6
--- /dev/null
+++ b/D2EF/C64/helper/commands16.asm
@@ -0,0 +1,464 @@
+/*
+** 16bit commands
+*/
+
+.pseudocommand clr16 dst ; hop {
+	.if(_isregister16(dst)){
+		:_load _16bit_lowerArgument(dst) ; #0
+		:_load _16bit_upperArgument(dst) ; #0
+	}else{
+		.if(_isunset(hop)){
+			.eval hop = A
+		}else .if(! _isregister8(hop)){
+			.error "clr16: hop is not a register"
+		}
+		:_load hop ; #0
+		:_store hop ; _16bit_lowerArgument(dst)
+		:_store hop ; _16bit_upperArgument(dst)
+	}
+} 
+ 
+.pseudocommand mov16 src ; hop ; dst { 
+	.if(_isunset(dst)){
+		.eval dst = hop
+		.eval hop = _DEFAULT
+	}else .if(_isunset(hop)){
+		.eval hop = _DEFAULT
+	}else .if(! _isregister8(hop)){
+		.error "mov16: hop is not a register"
+	}
+	:mov _16bit_lowerArgument(src) ; hop ; _16bit_lowerArgument(dst)
+	:mov _16bit_upperArgument(src) ; hop ; _16bit_upperArgument(dst)
+} 
+
+.pseudocommand inc16 arg { 
+		:inc _16bit_lowerArgument(arg) 
+		bne over 
+		:inc _16bit_upperArgument(arg) 
+	over: 
+} 
+ 
+.pseudocommand dec16 arg ; hop {
+		.if(_isunset(hop)){
+			.eval hop = A
+		}else .if(! _isregister8(hop)){
+			.error "dec16: hop is not a register"
+		}
+		.if(_isregister16(arg)){
+			:_compare _16bit_lowerArgument(arg) ; #0
+		}else{
+			:_load hop ; _16bit_lowerArgument(arg)
+		}
+		bne nodecupper
+		:dec _16bit_upperArgument(arg)
+	nodecupper:
+		:dec _16bit_lowerArgument(arg) 
+} 
+ 
+.pseudocommand ror16 src ; dst {
+	.if(_isunset(dst) /*|| dst.getValue() == src.getValue()*/){
+		ror _16bit_upperArgument(src)
+		ror _16bit_lowerArgument(src)
+	}else{
+		lda _16bit_upperArgument(src)
+		ror
+		sta _16bit_upperArgument(dst) 
+		lda _16bit_lowerArgument(src)
+		ror
+		sta _16bit_lowerArgument(dst)
+	}
+}
+
+.pseudocommand lsr16 src ; dst {
+	.if(_isunset(dst) /*|| dst.getValue() == src.getValue()*/){
+		lsr _16bit_upperArgument(src)
+		ror _16bit_lowerArgument(src)
+	}else{
+		lda _16bit_upperArgument(src)
+		lsr
+		sta _16bit_upperArgument(dst) 
+		lda _16bit_lowerArgument(src)
+		ror
+		sta _16bit_lowerArgument(dst)
+	}
+}
+
+.pseudocommand rol16 src ; dst {
+	.if(_isunset(dst) /*|| dst.getValue() == src.getValue()*/){
+		rol _16bit_lowerArgument(src)
+		rol _16bit_upperArgument(src)
+	}else{
+		lda _16bit_lowerArgument(src)
+		rol
+		sta _16bit_lowerArgument(dst)
+		lda _16bit_upperArgument(src)
+		rol
+		sta _16bit_upperArgument(dst) 
+	}
+}
+
+.pseudocommand asl16 src ; dst {
+	.if(_isunset(dst) /*|| dst.getValue() == src.getValue()*/){
+		asl _16bit_lowerArgument(src)
+		rol _16bit_upperArgument(src)
+	}else{
+		lda _16bit_lowerArgument(src)
+		asl
+		sta _16bit_lowerArgument(dst)
+		lda _16bit_upperArgument(src)
+		rol
+		sta _16bit_upperArgument(dst) 
+	}
+}
+
+.pseudocommand adc16 src1 ; src2 ; dst { 
+	.if(src2.getType() == AT_IMMEDIATE && src2.getValue() < 256){
+		// src2 is immediate ("#xxx") and less than 256: use shorter command
+		:adc16_8 src1 ; src2 ; dst
+	}else{
+		.if(_equalregisters8(src1, A)){
+			// dst = A(8bit) + src2
+			adc _16bit_lowerArgument(src2)
+			sta _16bit_lowerArgument(dst)
+			lda #0
+			adc _16bit_upperArgument(src2)
+			sta _16bit_upperArgument(dst)
+/*
+**	sorry, can't do this...
+		}else .if(src1.getValue() == src2.getValue()){
+			// (src1 | dst) = src1 + src1 = 2*src1 = src1<<1
+			:rol16 src1 ; dst
+*/
+		}else{
+			// (src1 | dst) = src1 + src2
+			.if(_isunset(dst)){
+				.eval dst = src1
+			}
+			lda _16bit_lowerArgument(src1)
+			adc _16bit_lowerArgument(src2)
+			sta _16bit_lowerArgument(dst)
+			lda _16bit_upperArgument(src1)
+			adc _16bit_upperArgument(src2)
+			sta _16bit_upperArgument(dst)
+		}
+	}
+}
+
+.pseudocommand add16 src1 ; src2 ; dst {
+/*
+**	sorry, can't do this...
+	.if(! _equalregisters8(src1, A) && src1.getValue() == src2.getValue()){
+		// (src1 | dst) = src1 + src1 = 2*src1 = src1<<1
+		:asl16 src1 ; dst
+	}else{
+*/
+		clc
+		:adc16 src1 ; src2 ; dst
+//	}
+}
+
+.pseudocommand adc16_8 src1 ; src2 ; dst {
+	.if(_equalregisters8(src1, A)){
+		// dst = A(8bit) + src2(8bit)
+			adc src2
+			sta _16bit_lowerArgument(dst)
+			adc #0
+			sta _16bit_upperArgument(dst)
+	}else .if(_isunset(dst) /*|| dst.getValue() == src1.getValue()*/){
+		// (src1==dst) = src1 + src2(8bit)
+			lda _16bit_lowerArgument(src1)
+			adc src2
+			sta _16bit_lowerArgument(src1)
+			bcc skip
+			inc _16bit_upperArgument(src1) 
+		skip:
+	}else{
+		// dst = src1 + src2(8bit)
+			lda _16bit_lowerArgument(src1)
+			adc src2
+			sta _16bit_lowerArgument(dst)
+			lda _16bit_upperArgument(src1) 
+			adc #0
+			sta _16bit_upperArgument(dst) 
+	}
+}
+
+.pseudocommand add16_8 src1 ; src2 ; dst { 
+	clc
+	:adc16_8 src1 ; src2 ; dst
+}
+
+.pseudocommand sbc16 src1 ; src2 ; dst {
+		lda _16bit_lowerArgument(src1)
+		sbc _16bit_lowerArgument(src2)
+		sta _16bit_lowerArgument(dst)
+		lda _16bit_upperArgument(src1)
+		sbc _16bit_upperArgument(src2)
+		sta _16bit_upperArgument(dst)
+}
+
+.pseudocommand sub16 src1 ; src2 ; dst {
+	sec
+	:sbc16 src1 ; src2 ; dst
+}
+
+.pseudocommand sbc16_8 src1 ; src2 ; dst {
+	.if(_isunset(dst)){
+			lda _16bit_lowerArgument(src1)
+			sbc _16bit_lowerArgument(src2)
+			sta _16bit_lowerArgument(src1)
+			bcs !skip+
+			dec _16bit_upperArgument(src1)
+		!skip:
+	}else{
+			lda _16bit_lowerArgument(src1)
+			sbc _16bit_lowerArgument(src2)
+			sta _16bit_lowerArgument(dst)
+			lda _16bit_upperArgument(src1)
+			sbc #0
+			sta _16bit_upperArgument(dst)
+	}
+}
+
+.pseudocommand sub16_8 src1 ; src2 ; dst {
+	sec
+	:sbc16_8 src1 ; src2 ; dst
+}
+
+.pseudocommand mul16 src1 ; src2 ; dst ; hop {
+		// src1 will be destroyed
+		:clr16 dst
+		:_load hop ; #16
+	loop:
+		:asl16 dst
+		:asl16 src1
+		bcc next
+		:add16 dst ; src2
+	next:
+		:dec hop
+		bpl loop
+}
+
+.pseudocommand mul16_8 src1 ; src2 ; dst {
+	lda #$00
+	tay
+	beq enterLoop
+
+doAdd:
+	clc
+	adc src1.getValue()+0
+	tax
+
+	tya
+	adc src1.getValue()+1
+	tay
+	txa
+
+loop:
+	asl src1.getValue()+0
+	rol src1.getValue()+1
+enterLoop:
+	lsr src2
+	bcs doAdd
+	bne loop
+
+	sta dst.getValue()+0
+	sty dst.getValue()+1
+}
+
+.pseudocommand div16_rem_is_zero src1 ; src2 ; quo ; rem ; hop { 
+		// src1 will be destroyed
+		:_load hop ; #16
+	loop:
+		:asl16 src1
+		:rol16 rem
+		:sub16 rem ; src2 ; rem
+		bcs next
+		:add16 rem ; src2 ; rem
+		clc
+	next:
+		:rol16 quo
+		:dec hop
+		bne loop
+}
+
+.pseudocommand div16 src1 ; src2 ; quo ; rem ; hop { 
+		:clr16 rem
+		:div16_rem_is_zero src1 ; src2 ; quo ; rem ; hop
+}
+
+.pseudocommand div16_round src1 ; src2 ; quo ; rem ; hop { 
+	:div16 src1 ; src2 ; quo ; rem ; hop
+	:asl16 rem
+	:if16 rem ; GE ; src2 ; ENDIF ; !endif+
+		:inc16 quo
+	!endif:
+}
+
+.pseudocommand if16 not ; arg1 ; cmpr ; arg2 ; skip ; mode ; pc ; hop {
+	.if(_isNOT(not)){
+		.eval not = true
+	}else{
+		.eval hop = pc
+		.eval pc = mode
+		.eval mode = skip
+		.eval skip = arg2
+		.eval arg2 = cmpr
+		.eval cmpr = arg1
+		.eval arg1 = not
+		.eval not = false
+	}
+	.if(_isSKIP(skip)){
+		.eval skip = true
+	}else{
+		.eval hop = pc
+		.eval pc = mode
+		.eval mode = skip
+		.eval skip = false
+	}
+	
+	.if(!_isjump(mode)){
+		.eval hop = pc
+		.eval pc = mode
+		.eval mode = BRANCH
+	}
+	
+	.if(not){
+		.if(_equalcomparators(cmpr, EQ)){
+			.eval cmpr = NE
+		}else .if(_equalcomparators(cmpr, NE)){
+			.eval cmpr = EQ
+		}else .if(_equalcomparators(cmpr, LT)){
+			.eval cmpr = GE
+		}else .if(_equalcomparators(cmpr, LE)){
+			.eval cmpr = GT
+		}else .if(_equalcomparators(cmpr, GE)){
+			.eval cmpr = LT
+		}else .if(_equalcomparators(cmpr, GT)){
+			.eval cmpr = LE
+		}else .if(_equalcomparators(cmpr, Lx)){
+			.eval cmpr = Gx
+		}else .if(_equalcomparators(cmpr, Gx)){
+			.eval cmpr = Lx
+		}
+	}
+	
+	.if(_equalcomparators(cmpr, EQ) || _equalcomparators(cmpr, NE)){
+	
+		.if(!skip){
+			.if(_isBRANCH(mode)){
+				:if NOT ; _16bit_upperArgument(arg1) ; cmpr ; _16bit_upperArgument(arg2) ; done ; hop
+				:if       _16bit_lowerArgument(arg1) ; cmpr ; _16bit_lowerArgument(arg2) ; pc ; hop
+			}else{
+				:if NOT ; _16bit_upperArgument(arg1) ; cmpr ; _16bit_upperArgument(arg2) ; done ; hop
+				:if NOT ; _16bit_lowerArgument(arg1) ; cmpr ; _16bit_lowerArgument(arg2) ; done ; hop
+				.if(_isJMP(mode)){
+					jmp pc
+				}else{
+					jsr pc
+				}
+			}
+		}else{
+			.if(_isBRANCH(mode)){
+				:if NOT ; _16bit_upperArgument(arg1) ; cmpr ; _16bit_upperArgument(arg2) ; pc ; hop
+				:if NOT ; _16bit_lowerArgument(arg1) ; cmpr ; _16bit_lowerArgument(arg2) ; pc ; hop
+			}else{
+				:if       _16bit_upperArgument(arg1) ; cmpr ; _16bit_upperArgument(arg2) ; check2 ; hop
+				.if(_isJMP(mode)){
+					jmp pc
+				}else{
+					jsr pc
+				}
+			check2:
+				:if       _16bit_lowerArgument(arg1) ; cmpr ; _16bit_lowerArgument(arg2) ; done ; hop
+				.if(_isJMP(mode)){
+					jmp pc
+				}else{
+					jsr pc
+				}
+			}
+		}
+		done:
+	}else{
+	
+		.if(_equalcomparators(cmpr, LT) || _equalcomparators(cmpr, LE) || _equalcomparators(cmpr, Lx)){
+			.var pos = LT
+			.var neg = GT
+		}else .if(_equalcomparators(cmpr, GT) || _equalcomparators(cmpr, GE) || _equalcomparators(cmpr, Gx)){
+			.var pos = GT
+			.var neg = LT
+		}else{
+			.error "if16: unknown comparator"
+		}
+		
+		// all text's refer to less... greater will also handled
+		.if(!skip){
+			.if(_isBRANCH(mode)){
+				// check weather upper is less = early done
+				:if       _16bit_upperArgument(arg1) ;  pos ; _16bit_upperArgument(arg2) ; pc ; hop
+
+				// check weather upper is bigger = early fail
+				:if       _16bit_upperArgument(arg1) ;  neg ; _16bit_upperArgument(arg2) ; done ; hop
+
+				// check weather lower fits...
+				:if       _16bit_lowerArgument(arg1) ; cmpr ; _16bit_lowerArgument(arg2) ; pc ; hop
+
+			}else{
+				// check weather upper is less = early done
+				:if NOT ; _16bit_upperArgument(arg1) ;  pos ; _16bit_upperArgument(arg2) ; check2 ; hop
+				.if(_isJMP(mode)){
+					jmp pc
+				}else{
+					jsr pc
+				}
+			check2:
+
+				// check weather upper is bigger = early fail
+				:if       _16bit_upperArgument(arg1) ;  neg ; _16bit_upperArgument(arg2) ; done ; hop
+
+				// check weather lower fits...
+				:if NOT ; _16bit_lowerArgument(arg1) ; cmpr ; _16bit_lowerArgument(arg2) ; done ; hop
+				.if(_isJMP(mode)){
+					jmp pc
+				}else{
+					jsr pc
+				}
+			}
+		}else{ // skip mode (aka ELSE, ENDIF)
+			.if(_isBRANCH(mode)){
+				// check weather upper is less = early done
+				:if       _16bit_upperArgument(arg1) ;  pos ; _16bit_upperArgument(arg2) ; done ; hop
+
+				// check weather upper is bigger = early fail
+				:if       _16bit_upperArgument(arg1) ;  neg ; _16bit_upperArgument(arg2) ; pc ; hop
+
+				// check weather lower fits...
+				:if NOT ; _16bit_lowerArgument(arg1) ; cmpr ; _16bit_lowerArgument(arg2) ; pc ; hop
+
+			}else{
+				.error "skip + jump on L? and G? is currently not supported"
+				// check weather upper is less = early done
+				:if NOT ; _16bit_upperArgument(arg1) ;  pos ; _16bit_upperArgument(arg2) ; check2 ; hop
+				.if(_isJMP(mode)){
+					jmp pc
+				}else{
+					jsr pc
+				}
+			check2:
+
+				// check weather upper is bigger = early fail
+				:if       _16bit_upperArgument(arg1) ;  neg ; _16bit_upperArgument(arg2) ; done ; hop
+
+				// check weather lower fits...
+				:if NOT ; _16bit_lowerArgument(arg1) ; cmpr ; _16bit_lowerArgument(arg2) ; done ; hop
+				.if(_isJMP(mode)){
+					jmp pc
+				}else{
+					jsr pc
+				}
+			}
+		}
+		done:
+	}
+	
+}
diff --git a/D2EF/C64/helper/commands8.asm b/D2EF/C64/helper/commands8.asm
new file mode 100644
index 00000000..102b9607
--- /dev/null
+++ b/D2EF/C64/helper/commands8.asm
@@ -0,0 +1,248 @@
+/*
+** 8bit commands
+*/
+
+.pseudocommand clr dst ; hop { 
+	.if(_isregister8(dst)){
+		:load dst ; #0
+	}else{
+		.if(_isunset(hop)){
+			.eval hop = A
+		}else .if(! _isregister8(hop)){
+			.error "clr: hop is not a register"
+		}
+		:_load hop ; #0
+		:_store hop ; tar
+	}
+}
+
+.pseudocommand mov src ; hop ; dst {
+	// load src in hop (default A) and store it to dst
+	// hop is ignored when src and/or dst is a register
+	.if(_isunset(dst)){
+		.eval dst = hop
+		.eval hop = _DEFAULT
+	}else .if(_isunset(hop)){
+		.eval hop = _DEFAULT
+	}else .if(! _isregister8(hop) && !_isdefault(hop)){
+		.error "mov: hop is not a register"
+	}
+	.if(_isregister8(src)){
+		.if(! _isdefault(hop)){
+			.error "mov: if src and/or dst is a register hop must not be set"
+		}
+		// src = REGISTER
+		.if(_isregister8(dst)){
+			// src && dst = REGISTER
+			.if(_equalregisters8(src, dst)){
+				// same register: done
+			}else .if(_equalregisters8(src, A) && _equalregisters8(dst, X)){
+				tax
+			}else .if(_equalregisters8(src, A) && _equalregisters8(dst, Y)){
+				tay
+			}else .if(_equalregisters8(src, X) && _equalregisters8(dst, A)){
+				txa
+			}else .if(_equalregisters8(src, Y) && _equalregisters8(dst, A)){
+				tya
+			}else{
+				.error "mov: unable to move register " + src + " directly to register " + dst
+			}
+		}else{
+			// src = REGISTER; dst = no regsiter
+			:_store src ; dst
+		}
+	}else .if(_isregister8(dst)){
+		.if(! _isdefault(hop)){
+			.error "mov: if src and/or dst is a register hop must not be set"
+		}
+		// src = no regsiter; dst = REGISTER
+		:_load dst ; src
+	}else{
+		.if(_isdefault(hop)){
+			.eval hop = A
+		}
+		:_load hop ; src
+		:_store hop ; dst
+	}
+}
+
+.pseudocommand inc dst {
+	.if(_equalregisters8(dst, A)){
+		clc
+		adc #1
+	}else .if(_equalregisters8(dst, X)){
+		inx
+	}else .if(_equalregisters8(dst, Y)){
+		iny
+	}else{
+		inc dst
+	}
+}
+
+.pseudocommand dec dst {
+	.if(_equalregisters8(dst, A)){
+		sec
+		sbc #1
+	}else .if(_equalregisters8(dst, X)){
+		dex
+	}else .if(_equalregisters8(dst, Y)){
+		dey
+	}else{
+		dec dst
+	}
+}
+
+.pseudocommand adc src1 ; src2 ; dst {
+	.if(! _equalregisters8(src1, A)){
+		lda src1
+	}
+		
+	adc src2 
+	
+	.if(_isunset(dst)){
+		.eval dst = src1
+	}
+
+	.if(! _equalregisters8(dst, A)){
+		sta dst
+	}
+}
+
+.pseudocommand add src1 ; src2 ; dst { 
+	clc
+	:adc src1 ; src2 ; dst
+}
+
+.pseudocommand sbc src1 ; src2 ; dst {
+	.if(! _equalregisters8(src1, A)){
+		lda src1
+	}
+		
+	sbc src2 
+	
+	.if(_isunset(dst)){
+		.eval dst = src1
+	}
+
+	.if(! _equalregisters8(dst, A)){
+		sta dst
+	}
+}
+
+.pseudocommand sub src1 ; src2 ; dst { 
+	sec
+	:sbc src1 ; src2 ; dst
+}
+
+.pseudocommand mul8_16 src1 ; src2 ; dst ; hop {
+		:_load hop ; #8
+		:clr16 dst
+	loop:
+		:asl16 dst
+		asl src1
+		bcc next
+		lda dst
+		clc
+		adc src2
+		sta _16bit_lowerArgument(dst)
+		bcc next
+		inc _16bit_upperArgument(dst)
+	next:
+		:dec hop
+		bne loop
+}
+
+.pseudocommand mul10 src ; tar ; buffer {
+	.if(!_equalregisters8(src, A)){
+		lda arg1
+	}
+	.if(_isSMC(buffer)){
+		// use self-modifying code
+		asl
+		sta two+1
+		asl
+		asl
+		clc
+		two: adc #0
+	}else{
+		// use a buffer anywhere
+		asl
+		sta buffer
+		asl
+		asl
+		clc
+		adc buffer
+	}
+	.if(!_equalregisters8(tar, A)){
+		sta tar
+	}
+}
+
+.pseudocommand if not ; arg1 ; cmpr ; arg2 ; skip ; mode ; pc ; hop {
+	.if(_isNOT(not)){
+		.eval not = true
+	}else{
+		.eval pc = mode
+		.eval mode = skip
+		.eval skip = arg2
+		.eval arg2 = cmpr
+		.eval cmpr = arg1
+		.eval arg1 = not
+		.eval not = false
+	}
+	.if(_isSKIP(skip)){
+		.eval not = ! not
+	}else .if(!_isunset(skip)){
+		.eval hop = pc
+		.eval pc = mode
+		.eval mode = skip
+		//.eval skip = ... is not used anymore
+	}
+	.if(_isunset(pc) || _isregister8(pc)){
+		.eval hop = pc
+		.eval pc = mode
+		.eval mode = BRANCH
+	}
+	.if(_isunset(hop)){
+		.eval hop = _DEFAULT
+	}else .if(! _isregister8(hop)){
+		.error "if: hop is not a register"
+	}
+	
+	.if(not){
+		.if(_equalcomparators(cmpr, EQ)){
+			.eval cmpr = NE
+		}else .if(_equalcomparators(cmpr, NE)){
+			.eval cmpr = EQ
+		}else .if(_equalcomparators(cmpr, LT)){
+			.eval cmpr = GE
+		}else .if(_equalcomparators(cmpr, LE)){
+			.eval cmpr = GT
+		}else .if(_equalcomparators(cmpr, GE)){
+			.eval cmpr = LT
+		}else .if(_equalcomparators(cmpr, GT)){
+			.eval cmpr = LE
+		}else .if(_equalcomparators(cmpr, Lx)){
+			.eval cmpr = Gx
+		}else .if(_equalcomparators(cmpr, Gx)){
+			.eval cmpr = Lx
+		}
+	}
+	
+	.if(_equalcomparators(cmpr, EQ)){
+		:_eq hop ; arg1 ; arg2 ; mode ; pc
+	}else .if(_equalcomparators(cmpr, NE)){
+		:_ne hop ; arg1 ; arg2 ; mode ; pc
+	}else .if(_equalcomparators(cmpr, LT) || _equalcomparators(cmpr, Lx)){
+		:_lt hop ; arg1 ; arg2 ; mode ; pc
+	}else .if(_equalcomparators(cmpr, LE)){
+		:_le hop ; arg1 ; arg2 ; mode ; pc
+	}else .if(_equalcomparators(cmpr, GE) || _equalcomparators(cmpr, Gx)){
+		:_ge hop ; arg1 ; arg2 ; mode ; pc
+	}else .if(_equalcomparators(cmpr, GT)){
+		:_gt hop ; arg1 ; arg2 ; mode ; pc
+	}else{
+		.error "if: unknown comparator"
+	}
+	
+}
diff --git a/D2EF/C64/helper/macros.asm b/D2EF/C64/helper/macros.asm
new file mode 100644
index 00000000..d44731ce
--- /dev/null
+++ b/D2EF/C64/helper/macros.asm
@@ -0,0 +1,111 @@
+/*
+** basic loader
+*/
+
+.macro BasicLoader(start){
+	.pc = $0801 "Basic Loader"
+		.word nextline
+		.word 3880
+		.byte $9e
+		.text toIntString(start)
+		.byte 0
+	nextline:
+		.word 0
+}
+
+/*
+** read a full charset
+*/
+
+.macro CharSet(file){
+	.var charset = LoadPicture(file, List().add($ffffff, $000000)) 
+	.for (var y=0; y<8; y++) 
+		.for (var x=0;x<32; x++) 
+			.for(var charPosY=0; charPosY<8; charPosY++) 
+				.byte charset.getSinglecolorByte(x,charPosY+y*8) 
+}
+
+
+/*
+** Overall Memorymap
+*/
+
+/*
+.pc = $0000 "Zero Page" virtual
+.fill $100, 0
+.pc = $0100 "Stack" virtual
+.fill $100, 0
+.pc = $0200 "Kernal/Basic Temp" virtual
+.fill $200, 0
+.pc = $a000 "BASIC ROM" virtual
+.fill $2000, 0
+.pc = $d000 "I/O or Char Rom" virtual
+.fill $1000, 0
+.pc = $e000 "KERNAL ROM" virtual
+.fill $2000, 0
+.pc = $d800 "Color Memory" virtual
+.fill $400, 0
+*/
+
+/*
+** load indirect
+*/
+
+.macro lday(zp, ofs) {
+	ldy #ofs
+	lda (zp), y
+}
+
+.macro stay(zp, ofs) {
+	ldy #ofs
+	sta (zp), y
+}
+
+.macro movy(zp, ofs, dst) {
+	ldy #ofs
+	lda (zp), y
+	sta dst
+}
+
+/*
+** Constants
+*/
+
+// VIC
+.const BORDER_COLOR = $d020
+.const BACKGROUND_COLOR = $d021
+.const COLOR_MEMORY = $d800
+
+// KERNAL
+.const READST = $ffb7
+.const SETLFS = $ffba
+.const SETNAM = $ffbd
+.const OPEN = $ffc0
+.const CLOSE = $ffc3
+.const CHKIN = $ffc6
+.const CHKOUT = $ffc9
+.const CHRIN = $ffcf
+.const CHROUT = $ffd2
+.const GETIN = $ffe4
+
+.const ZP_LAST_USED_DRIVE = $ba
+
+/*
+** en-/disable kernal
+*/
+
+.macro UseHidden(){
+		sei
+		:mov #$31 ; $01 // only I/O
+}
+
+.macro UseKernal(){
+		:mov #$36 ; $01 // only I/O + KERNAL
+		cli
+}
+
+.macro CallHidden(func){
+		:UseHidden()
+		jsr func
+		:UseKernal()
+}
diff --git a/D2EF/C64/kapi_hi.asm b/D2EF/C64/kapi_hi.asm
new file mode 100644
index 00000000..4e0ee183
--- /dev/null
+++ b/D2EF/C64/kapi_hi.asm
@@ -0,0 +1,5 @@
+.const ULTIMAX = true
+.const BANK_START = $a000
+.const BANK_SIZE = $2000
+
+.import source "main.asm"
diff --git a/D2EF/C64/kapi_lo.asm b/D2EF/C64/kapi_lo.asm
new file mode 100644
index 00000000..a13259a1
--- /dev/null
+++ b/D2EF/C64/kapi_lo.asm
@@ -0,0 +1,5 @@
+.const ULTIMAX = false
+.const BANK_START = $8000
+.const BANK_SIZE = $2000
+
+.import source "main.asm"
diff --git a/D2EF/C64/kapi_nm.asm b/D2EF/C64/kapi_nm.asm
new file mode 100644
index 00000000..a778c127
--- /dev/null
+++ b/D2EF/C64/kapi_nm.asm
@@ -0,0 +1,5 @@
+.const ULTIMAX = false
+.const BANK_START = $8000
+.const BANK_SIZE = $4000
+
+.import source "main.asm"
diff --git a/D2EF/C64/launcher_hi.asm b/D2EF/C64/launcher_hi.asm
new file mode 100644
index 00000000..761aec8c
--- /dev/null
+++ b/D2EF/C64/launcher_hi.asm
@@ -0,0 +1,32 @@
+	// dont load the bank, its X. if bank 1 then with INX before
+	.pc = $ffe5 "jumper"
+
+	jump_start:
+		// store bank
+		lda #$07 // 16k-mode
+		sta $de02
+		jmp $a000 // jump into the cartridge
+
+	.pc = * "copy it"
+
+	start:
+		sei
+		// since no calculations are made and the stack is not used we do'nt initialize them
+		ldx #[start-jump_start]
+	// first, initialize ram
+	// second, copy a few bytes to $02+
+	loop:
+		lda jump_start-1, x
+		sta $02-1, x
+		dex
+		bne loop
+
+		// X is now zero
+		beq $10002
+
+	.pc = $fffa "vectors"
+		.word do_rti
+		.word start // @fffc -> address of reset routine
+	do_rti:
+		rti
+		.byte $78
diff --git a/D2EF/C64/main.asm b/D2EF/C64/main.asm
new file mode 100644
index 00000000..98526d4a
--- /dev/null
+++ b/D2EF/C64/main.asm
@@ -0,0 +1,199 @@
+/*
+	java -jar KickAss.jar kapi_nm.asm -showmem -vicesymbols
+*/
+
+.const MODE_RAM = $04
+.const MODE_16k = $07
+.const MODE_8k  = $06
+.const MODE_ULT = $05
+
+.const IO_MODE = $de02
+
+.var DIR = DISPLAY+40
+
+
+
+/*
+** and now some often used variables
+*/
+
+// points to the current entry in the dir (after FIND_FILE)
+.const ENTRY_PTR = $fb // $fc
+.const TEMP1 = $fd
+.const TEMP2 = $fe
+.const TEMP3 = $ff
+
+.const ZP_SIZE = 5
+
+// during LOAD
+.const ZP_BANK = TEMP1
+.const SRC_PTR = TEMP2 // TEMP3
+.const SIZE = ENTRY_PTR
+.const DEST_PTR = $ae // $af
+
+.const fast_load = true
+
+
+.import source "helper/commands.asm"
+.import source "helper/commands8.asm"
+.import source "helper/commands16.asm"
+.import source "helper/macros.asm"
+
+.pc = BANK_START "Init"
+
+.if(! ULTIMAX){
+	.word start
+	.word start
+	.byte $c3, $c2, $cd, $38, $30 // CBM80
+start:
+}
+
+	// quick init
+	sei
+	ldx #$ff
+	txs
+	cld
+	stx $8004 // no CBM80
+	:mov #$e7 ; $01
+	:mov #$2f ; $00
+
+	lda #MODE_16k|$80
+	sta IO_MODE
+
+	// copy reset-routine
+	ldx #[RESET_END - RESET_START]+1
+!loop:
+	lda RESET_START-1, x
+	sta $df02-1, x
+	dex
+	bne !loop-
+
+	// activate reset-routine
+	jmp $df02
+
+.pc = * "Reset routine"
+
+	// the reset-routine
+RESET_START:
+	.pseudopc $df02 {
+		/*
+			PARTIAL RESET
+		*/
+
+		// disable rom
+		lda #MODE_RAM
+		sta IO_MODE
+
+		// do a partial reset
+		ldx #$05
+		stx $d016
+		jsr $fda3
+		jsr $fd50
+		jsr $fd15
+		jsr $ff5b
+
+		// change CHRIN vector
+		:mov16 $324 ; ORIG_CHRIN_VECTOR
+
+		// add our vector
+		:mov16 #RESET_TRAP ; $324
+
+		/*
+			RESET, PART 2
+		*/
+
+	GO_RESET:
+		jmp $fcfe
+
+	/*
+	** RESET IS DONE
+	** RESTORE VECTOR
+	** JUMP BACK IN CARTRIDGE
+	*/
+
+	RESET_TRAP:
+		// disable interrups
+		sei
+
+		// enable rom
+		lda #MODE_16k|$80
+		sta IO_MODE
+
+		// install
+		jmp INSTALL_API
+
+	ORIG_CHRIN_VECTOR:
+	}
+RESET_END:
+
+.print "size 'reset' = " + [RESET_END - RESET_START]
+
+.pc = * "Install Vectors"
+
+INSTALL_API:
+	// keep x (in $02)
+	stx $02
+
+	ldx #39
+!loop:
+	lda launchmessage, x
+	sta $0400+1*40, x
+	lda lower_line, x
+	sta $0400+3*40, x
+	lda #WHITE
+	sta $d800+1*40, x
+	sta $d800+3*40, x
+	dex
+	bpl !loop-
+
+	// save orig.chrin vector
+	:mov16 ORIG_CHRIN_VECTOR ; $fe
+
+	// copy reset-routine
+	ldx #[MAIN_END - MAIN_START]+1
+!loop:
+	lda MAIN_START-1, x
+	sta $df02-1, x
+	dex
+	bne !loop-
+
+	// save orig.vector
+	:mov16 $fe ; REAL_CHRIN
+
+	// copy vectors
+	:mov16 $0330 ; REAL_LOAD
+
+	// setup new vectors
+	:mov16 #VECTOR_CHRIN ; $0324
+	:mov16 #VECTOR_LOAD ; $0330
+
+	// use "lda #$xx" instead of "lda $xxxx"
+	:mov $df00 ; SMC_OUR_BANK+1
+
+	// restore X
+	ldx $02
+
+	// continue CHRIN
+	jmp VECTOR_CHRIN
+
+lower_line:
+	.import binary "copyright.bin"
+	//.byte $20, $02, $19, $20, $01, $0c, $05, $18, $27, $13, $20, $0d, $32, $09, $2d, $14, $0f, $2d, $05, $01, $13, $19, $06, $0c, $01, $13, $08, $20, $22, $0c, $0f, $01, $04, $22, $20, $16, $30, $2e, $37, $20
+
+.pc = * "Vectors"
+
+MAIN_START:
+	.import source "emu_vectors.asm"
+MAIN_END:
+
+.print "size 'new functions' = " + [MAIN_END - MAIN_START]
+
+.import source "emu_chrin.asm"
+.import source "emu_helper.asm"
+.import source "emu_load.asm"
+
+launchmessage:
+.text "   sidekick64 disk image launch using   "
+
+DISPLAY:
+//     0123456789012345678901234567890123456789
diff --git a/D2EF/C64/mkdep.php b/D2EF/C64/mkdep.php
new file mode 100644
index 00000000..4c02cc21
--- /dev/null
+++ b/D2EF/C64/mkdep.php
@@ -0,0 +1,26 @@
+<?php
+
+$target = $argv[1];
+$exclude = array_slice($argv, 2);
+
+echo substr($argv[1], 0, -3).'prg: '.implode(' ', mkdep($argv[1]))."\n";
+
+function mkdep($src) {
+  global $exclude;
+
+  if (!is_file($src))
+    return array();
+
+  $file = file_get_contents($src);
+
+  if (!preg_match_all('!.*\.import [a-z0-9]+ "(.*?)"!', $file, $M, PREG_SET_ORDER))
+    return array();
+
+  $deps = array();
+  foreach ($M as $ln) {
+    if (strpos($ln[0], '//') === false && array_search($ln[1], $exclude) === false)
+      $deps = array_merge($deps, array($ln[1]), mkdep($ln[1]));
+  }
+
+  return $deps;
+}
diff --git a/D2EF/C64/startup.bin b/D2EF/C64/startup.bin
new file mode 100644
index 00000000..ad25f086
Binary files /dev/null and b/D2EF/C64/startup.bin differ
diff --git a/D2EF/C64/startup.s b/D2EF/C64/startup.s
new file mode 100644
index 00000000..185220b8
--- /dev/null
+++ b/D2EF/C64/startup.s
@@ -0,0 +1,265 @@
+;
+; EasyFlash - startup.s - Start-up code for stand-alone cartridges (acme)
+;
+; (c) 2009 Thomas 'skoe' Giesel
+;
+; This software is provided 'as-is', without any express or implied
+; warranty.  In no event will the authors be held liable for any damages
+; arising from the use of this software.
+;
+; Permission is granted to anyone to use this software for any purpose,
+; including commercial applications, and to alter it and redistribute it
+; freely, subject to the following restrictions:
+;
+; 1. The origin of this software must not be misrepresented; you must not
+;    claim that you wrote the original software. If you use this software
+;    in a product, an acknowledgment in the product documentation would be
+;    appreciated but is not required.
+; 2. Altered source versions must be plainly marked as such, and must not be
+;    misrepresented as being the original software.
+; 3. This notice may not be removed or altered from any source distribution.
+
+; This code runs in Ultimax mode after reset, so this memory becomes
+; visible at $e000..$ffff first and must contain a reset vector
+
+
+; this start PC leads to 512 bytes of code: $fe00..$ffff
+; keep in sync with writeStartUpCode in write.c
+* = $fe00
+
+EASYFLASH_BANK    = $DE00
+EASYFLASH_CONTROL = $DE02
+EASYFLASH_LED     = $80
+EASYFLASH_16K     = $07
+EASYFLASH_KILL    = $04
+EASYFLASH_XBANK   = $DF00
+
+DELAY_COUNTER     = $0200
+
+; must be in the area $0000 to $0FFF
+SCREEN_MEM        = $0400
+START_MEM         = $0400
+SPRITE_RAM        = $0600
+
+; In Ultimax mode we see the sprites there:
+SPRITE_ROM        = $F800
+
+startBank:
+        ; this must be the 1st byte in this code, so it's easy to patch it from outside
+        !byte 0
+
+startConfig:
+        ; this must be the 2nd byte in this code, so it's easy to patch it from outside
+        !byte 0
+
+; ============================================================================
+startUpCode:
+        !pseudopc START_MEM {
+            ; === this is copied to the START_MEM, does some inits ===
+            ; === scans the keyboard and kills the cartridge or    ===
+            ; === starts the main cartridge                        ===
+            lda #EASYFLASH_16K | EASYFLASH_LED
+            sta EASYFLASH_CONTROL
+
+; ============ prepare screen and sprites ============
+            ; set color ram to black
+            lda #0
+            ldx #251
+colorClear:
+            sta $d7ff, x
+            sta $d7ff + 250, x
+            sta $d7ff + 500, x
+            sta $d7ff + 750, x
+            dex
+            bne colorClear
+
+            ; init VIC
+            ldx #$2f
+vicInit:
+            lda vicData, x
+            sta $d000, x
+            dex
+            bpl vicInit
+
+            ; set 7 sprite pointers
+            ldx #SPRITE_RAM / 64 + 6
+            ldy #6
+spritePtrs:
+            txa
+            sta SCREEN_MEM + 1016, y
+            dex
+            dey
+            bpl spritePtrs
+
+            ; Prepare the CIA to scan the keyboard
+            lda #$7f
+            sta $dc00       ; pull down row 7 (DPA)
+
+            ldx #$ff
+            stx $dc02       ; DDRA $ff = output (X is still $ff from copy loop)
+            inx
+            stx $dc03       ; DDRB $00 = input
+
+; ============ fade in sprites ============
+            ldx #0          ; x counts the color index 0..7
+fadeIn:
+            jsr waitFrame
+            jsr waitFrame
+
+            lda fadeWhite, x
+            ldy #3
+in1:
+            sta $d027, y    ; first 4 sprites are fade to white
+            dey
+            bpl in1
+
+            lda fadeOrange, x
+            sta $d027 + 4   ; sprite with "flash2" fades to orange
+
+            inx             ; next color
+            cpx #8
+            bne fadeIn
+
+; ============ wait and scan keyboard ============
+            ldx #100
+checkAgain:
+            jsr waitFrame
+
+            ; Read the keys pressed on this row
+            lda $dc01   ; read coloumns (DPB)
+
+            ; Check if one of the magic kill keys was pressed
+            and #$e0    ; only leave "Run/Stop", "Q" and "C="
+            cmp #$e0
+            bne kill    ; branch if one of these keys is pressed
+
+            dex
+            bne checkAgain
+
+; ============ fade out sprites ============
+            ldx #7          ; x counts the color index 0..7
+fadeOut:
+            jsr waitFrame
+            jsr waitFrame
+
+            lda fadeWhite, x
+            ldy #3
+out1:
+            sta $d027, y    ; first 4 sprites are fade to white
+            dey
+            bpl out1
+
+            lda fadeOrange, x
+            sta $d027 + 4   ; sprite with "flash2" fades to orange
+
+            dex             ; next color
+            bpl fadeOut
+
+; ============ start or kill the cartridge  ============
+startCart:
+            ; start the cartridge code on the right bank
+patchStartBank = * + 1
+            lda #0          ; start bank will be put here
+            sta EASYFLASH_BANK
+
+            ; put the start bank into EF RAM, so an xbank CRT knows where it is
+            sta EASYFLASH_XBANK
+            ; put high byte here, in case we need it one day
+
+patchStartConfig = * + 1
+            lda #0          ; start config will be put here
+            !byte $2c       ; skip next instruction
+kill:
+            lda #EASYFLASH_KILL
+reset:
+            sta EASYFLASH_CONTROL
+
+            ; Restore CIA registers to the state after (hard) reset
+            lda #0
+            sta $dc02       ; DDRA input again
+            sta $dc00       ; No row pulled down
+
+            sta $d015       ; disable sprites
+
+            jmp ($fffc)     ; reset
+
+; ============ wait for the next frame (up to 1/50 s) ============
+waitFrame:
+            lda #$ff
+wf0:
+            cmp $d012
+            bne wf0         ; wait for raster line 0xff
+wf1:
+            cmp $d012
+            beq wf1         ; wait for raster line != 0xff
+            rts
+
+fadeWhite:
+            !byte  0, 9, 11, 4
+            !byte 12, 5, 15, 1
+fadeOrange:
+            !byte  0, 9, 11, 4
+            !byte 12, 5,  8, 8
+
+vicData:
+            !byte 0, 50, 24, 50, 48, 50, 72, 50  ; D000..D00F Sprite X/Y
+            !byte 36, 50, 20, 231, 44, 231, 0, 0
+            !byte $1f, $9B, $37, 0, 0            ; D010 Sprite X MSBs..D014
+            !byte $7f                            ; D015 Sprite Enable
+            !byte 8, 0                           ; D017
+            !byte $14, $0F, 0, 0, 0, 0, 0, 0     ; D018..D01F
+            !byte 0, 0, 0, 0, 0, 0, 0            ; D020..D026
+            !byte 0, 0, 0, 0, 0, 12, 5, 0        ; D027..D02E Sprite Colors
+        }
+startUpEnd:
+
+; ============================================================================
+coldStart:
+        ; === the reset vector points here ===
+        sei
+        ldx #$ff
+        txs
+        cld
+
+        lda #8
+        sta $d016       ; Enable VIC (e.g. RAM refresh)
+
+        ; Wait to make sure RESET is deasserted on all chips and write
+        ; to RAM to make sure it started up correctly (=> RAM datasheets)
+startWait:
+        sta $0100, x
+        dex
+        bne startWait
+
+        ; copy the final start-up code to RAM
+        ; we simply copy 512 bytes, that's fast enough and simple
+        ; and we copy 512 bytes from SPRITE_ROM to SRPITE_RAM
+        ldx #0
+copyLoop:
+        lda startUpCode, x
+        sta START_MEM, x
+        lda startUpCode + 0x100, x
+        sta START_MEM + 0x100, x
+        lda SPRITE_ROM, x
+        sta SPRITE_RAM, x
+        lda SPRITE_ROM + 0x100, x
+        sta SPRITE_RAM + 0x100, x
+        dex
+        bne copyLoop
+        lda startConfig
+        sta patchStartConfig
+        lda startBank
+        sta patchStartBank
+
+        jmp START_MEM
+
+        ; fill it up to $FFFA to put the vectors there
+        !align $ffff, $fffa, $ff
+
+        !word reti        ; NMI
+        !word coldStart   ; RESET
+
+        ; we don't need the IRQ vector and can put RTI here to save space :)
+reti:
+        rti
+        !byte 0xff
diff --git a/D2EF/binaries.cpp b/D2EF/binaries.cpp
new file mode 100644
index 00000000..59169c5c
--- /dev/null
+++ b/D2EF/binaries.cpp
@@ -0,0 +1,15 @@
+#include <stdint.h>
+uint8_t kapi_hi_auto[] = {120, 162, 255, 154, 216, 142, 4, 128, 169, 231, 133, 1, 169, 47, 133, 0, 169, 135, 141, 2, 222, 162, 57, 189, 34, 160, 157, 1, 223, 202, 208, 247, 76, 2, 223, 169, 4, 141, 2, 222, 162, 5, 142, 22, 208, 32, 163, 253, 32, 80, 253, 32, 21, 253, 32, 91, 255, 173, 36, 3, 141, 58, 223, 173, 37, 3, 141, 59, 223, 169, 49, 141, 36, 3, 169, 223, 141, 37, 3, 76, 254, 252, 120, 169, 135, 141, 2, 222, 76, 91, 160, 134, 2, 162, 39, 189, 49, 163, 157, 40, 4, 189, 192, 160, 157, 120, 4, 169, 1, 157, 40, 216, 157, 120, 216, 202, 16, 233, 173, 58, 223, 133, 254, 173, 59, 223, 133, 255, 162, 219, 189, 231, 160, 157, 1, 223, 202, 208, 247, 165, 254, 141, 16, 223, 165, 255, 141, 17, 223, 173, 48, 3, 141, 18, 223, 173, 49, 3, 141, 19, 223, 169, 10, 141, 36, 3, 169, 223, 141, 37, 3, 169, 2, 141, 48, 3, 169, 223, 141, 49, 3, 173, 0, 223, 141, 78, 223, 166, 2, 76, 10, 223, 32, 32, 1, 12, 5, 24, 39, 19, 32, 4, 9, 19, 11, 50, 5, 1, 19, 25, 6, 12, 1, 19, 8, 32, 45, 32, 34, 12, 15, 1, 4, 34, 32, 22, 48, 46, 57, 50, 32, 32, 133, 147, 32, 37, 223, 76, 116, 162, 32, 47, 223, 76, 194, 161, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 15, 177, 187, 153, 21, 223, 136, 16, 248, 72, 120, 165, 1, 141, 206, 223, 9, 7, 133, 1, 138, 72, 162, 4, 181, 251, 157, 215, 223, 202, 16, 248, 104, 170, 169, 135, 141, 2, 222, 169, 0, 141, 0, 222, 104, 96, 169, 4, 141, 2, 222, 32, 255, 255, 169, 135, 141, 2, 222, 96, 169, 160, 133, 255, 230, 253, 165, 253, 141, 0, 222, 177, 254, 145, 174, 200, 208, 249, 230, 175, 230, 255, 198, 252, 240, 9, 165, 255, 201, 192, 240, 224, 76, 109, 223, 165, 255, 201, 192, 208, 11, 169, 160, 133, 255, 230, 253, 165, 253, 141, 0, 222, 164, 251, 240, 9, 136, 177, 254, 145, 174, 192, 0, 208, 247, 24, 165, 174, 101, 251, 133, 174, 144, 2, 230, 175, 166, 174, 164, 175, 24, 169, 96, 141, 212, 223, 8, 72, 138, 72, 162, 4, 189, 215, 223, 149, 251, 202, 16, 248, 104, 170, 169, 4, 141, 2, 222, 169, 0, 133, 1, 104, 40, 88, 0, 0, 0, 255, 255, 255, 255, 255, 169, 76, 141, 212, 223, 173, 16, 223, 141, 213, 223, 173, 17, 223, 141, 214, 223, 165, 153, 208, 57, 165, 208, 208, 53, 132, 253, 173, 20, 223, 208, 3, 160, 12, 44, 160, 0, 185, 19, 162, 240, 8, 32, 22, 231, 230, 200, 200, 208, 243, 141, 146, 2, 133, 211, 133, 212, 230, 208, 164, 253, 206, 20, 223, 16, 12, 173, 16, 223, 141, 36, 3, 173, 17, 223, 141, 37, 3, 76, 184, 223, 76, 79, 65, 68, 34, 42, 34, 44, 56, 44, 49, 0, 82, 85, 78, 0, 164, 183, 240, 66, 192, 17, 176, 83, 136, 185, 21, 223, 201, 32, 240, 248, 200, 132, 191, 169, 105, 133, 251, 169, 163, 133, 252, 24, 165, 251, 105, 24, 133, 251, 144, 2, 230, 252, 160, 0, 177, 251, 240, 26, 185, 21, 223, 201, 42, 240, 17, 209, 251, 208, 228, 200, 196, 191, 208, 240, 192, 16, 240, 4, 177, 251, 208, 215, 24, 96, 56, 96, 24, 169, 96, 141, 212, 223, 76, 184, 223, 165, 147, 208, 6, 165, 186, 201, 8, 240, 26, 169, 76, 141, 212, 223, 173, 18, 223, 141, 213, 223, 173, 19, 223, 141, 214, 223, 165, 147, 166, 195, 164, 196, 76, 184, 223, 32, 35, 162, 176, 225, 169, 175, 141, 90, 223, 169, 245, 141, 91, 223, 32, 84, 223, 173, 20, 223, 48, 18, 162, 0, 160, 0, 161, 0, 161, 0, 161, 0, 161, 0, 232, 208, 245, 200, 208, 242, 169, 210, 141, 90, 223, 169, 245, 141, 91, 223, 32, 84, 223, 160, 16, 177, 251, 24, 109, 0, 223, 133, 253, 200, 200, 177, 251, 133, 254, 200, 177, 251, 133, 255, 200, 177, 251, 133, 174, 200, 177, 251, 133, 175, 200, 177, 251, 72, 200, 177, 251, 133, 252, 104, 133, 251, 165, 185, 208, 8, 165, 195, 133, 174, 165, 196, 133, 175, 24, 165, 251, 101, 254, 133, 251, 144, 2, 230, 252, 56, 165, 174, 229, 254, 133, 174, 176, 2, 198, 175, 164, 254, 169, 0, 133, 254, 141, 160, 223, 165, 252, 240, 3, 76, 104, 223, 140, 160, 223, 76, 145, 223, 32, 32, 32, 19, 9, 4, 5, 11, 9, 3, 11, 54, 52, 32, 4, 9, 19, 11, 32, 9, 13, 1, 7, 5, 32, 12, 1, 21, 14, 3, 8, 32, 21, 19, 9, 14, 7, 32, 32, 32, };
+uint8_t kapi_nm_auto[] = {9, 128, 9, 128, 195, 194, 205, 56, 48, 120, 162, 255, 154, 216, 142, 4, 128, 169, 231, 133, 1, 169, 47, 133, 0, 169, 135, 141, 2, 222, 162, 57, 189, 43, 128, 157, 1, 223, 202, 208, 247, 76, 2, 223, 169, 4, 141, 2, 222, 162, 5, 142, 22, 208, 32, 163, 253, 32, 80, 253, 32, 21, 253, 32, 91, 255, 173, 36, 3, 141, 58, 223, 173, 37, 3, 141, 59, 223, 169, 49, 141, 36, 3, 169, 223, 141, 37, 3, 76, 254, 252, 120, 169, 135, 141, 2, 222, 76, 100, 128, 134, 2, 162, 39, 189, 58, 131, 157, 40, 4, 189, 201, 128, 157, 120, 4, 169, 1, 157, 40, 216, 157, 120, 216, 202, 16, 233, 173, 58, 223, 133, 254, 173, 59, 223, 133, 255, 162, 219, 189, 240, 128, 157, 1, 223, 202, 208, 247, 165, 254, 141, 16, 223, 165, 255, 141, 17, 223, 173, 48, 3, 141, 18, 223, 173, 49, 3, 141, 19, 223, 169, 10, 141, 36, 3, 169, 223, 141, 37, 3, 169, 2, 141, 48, 3, 169, 223, 141, 49, 3, 173, 0, 223, 141, 78, 223, 166, 2, 76, 10, 223, 32, 32, 1, 12, 5, 24, 39, 19, 32, 4, 9, 19, 11, 50, 5, 1, 19, 25, 6, 12, 1, 19, 8, 32, 45, 32, 34, 12, 15, 1, 4, 34, 32, 22, 48, 46, 57, 50, 32, 32, 133, 147, 32, 37, 223, 76, 125, 130, 32, 47, 223, 76, 203, 129, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 15, 177, 187, 153, 21, 223, 136, 16, 248, 72, 120, 165, 1, 141, 206, 223, 9, 7, 133, 1, 138, 72, 162, 4, 181, 251, 157, 215, 223, 202, 16, 248, 104, 170, 169, 135, 141, 2, 222, 169, 0, 141, 0, 222, 104, 96, 169, 4, 141, 2, 222, 32, 255, 255, 169, 135, 141, 2, 222, 96, 169, 128, 133, 255, 230, 253, 165, 253, 141, 0, 222, 177, 254, 145, 174, 200, 208, 249, 230, 175, 230, 255, 198, 252, 240, 9, 165, 255, 201, 192, 240, 224, 76, 109, 223, 165, 255, 201, 192, 208, 11, 169, 128, 133, 255, 230, 253, 165, 253, 141, 0, 222, 164, 251, 240, 9, 136, 177, 254, 145, 174, 192, 0, 208, 247, 24, 165, 174, 101, 251, 133, 174, 144, 2, 230, 175, 166, 174, 164, 175, 24, 169, 96, 141, 212, 223, 8, 72, 138, 72, 162, 4, 189, 215, 223, 149, 251, 202, 16, 248, 104, 170, 169, 4, 141, 2, 222, 169, 0, 133, 1, 104, 40, 88, 0, 0, 0, 255, 255, 255, 255, 255, 169, 76, 141, 212, 223, 173, 16, 223, 141, 213, 223, 173, 17, 223, 141, 214, 223, 165, 153, 208, 57, 165, 208, 208, 53, 132, 253, 173, 20, 223, 208, 3, 160, 12, 44, 160, 0, 185, 28, 130, 240, 8, 32, 22, 231, 230, 200, 200, 208, 243, 141, 146, 2, 133, 211, 133, 212, 230, 208, 164, 253, 206, 20, 223, 16, 12, 173, 16, 223, 141, 36, 3, 173, 17, 223, 141, 37, 3, 76, 184, 223, 76, 79, 65, 68, 34, 42, 34, 44, 56, 44, 49, 0, 82, 85, 78, 0, 164, 183, 240, 66, 192, 17, 176, 83, 136, 185, 21, 223, 201, 32, 240, 248, 200, 132, 191, 169, 114, 133, 251, 169, 131, 133, 252, 24, 165, 251, 105, 24, 133, 251, 144, 2, 230, 252, 160, 0, 177, 251, 240, 26, 185, 21, 223, 201, 42, 240, 17, 209, 251, 208, 228, 200, 196, 191, 208, 240, 192, 16, 240, 4, 177, 251, 208, 215, 24, 96, 56, 96, 24, 169, 96, 141, 212, 223, 76, 184, 223, 165, 147, 208, 6, 165, 186, 201, 8, 240, 26, 169, 76, 141, 212, 223, 173, 18, 223, 141, 213, 223, 173, 19, 223, 141, 214, 223, 165, 147, 166, 195, 164, 196, 76, 184, 223, 32, 44, 130, 176, 225, 169, 175, 141, 90, 223, 169, 245, 141, 91, 223, 32, 84, 223, 173, 20, 223, 48, 18, 162, 0, 160, 0, 161, 0, 161, 0, 161, 0, 161, 0, 232, 208, 245, 200, 208, 242, 169, 210, 141, 90, 223, 169, 245, 141, 91, 223, 32, 84, 223, 160, 16, 177, 251, 24, 109, 0, 223, 133, 253, 200, 200, 177, 251, 133, 254, 200, 177, 251, 133, 255, 200, 177, 251, 133, 174, 200, 177, 251, 133, 175, 200, 177, 251, 72, 200, 177, 251, 133, 252, 104, 133, 251, 165, 185, 208, 8, 165, 195, 133, 174, 165, 196, 133, 175, 24, 165, 251, 101, 254, 133, 251, 144, 2, 230, 252, 56, 165, 174, 229, 254, 133, 174, 176, 2, 198, 175, 164, 254, 169, 0, 133, 254, 141, 160, 223, 165, 252, 240, 3, 76, 104, 223, 140, 160, 223, 76, 145, 223, 32, 32, 32, 19, 9, 4, 5, 11, 9, 3, 11, 54, 52, 32, 4, 9, 19, 11, 32, 9, 13, 1, 7, 5, 32, 12, 1, 21, 14, 3, 8, 32, 21, 19, 9, 14, 7, 32, 32, 32, };
+uint8_t kapi_lo_auto[] = {9, 128, 9, 128, 195, 194, 205, 56, 48, 120, 162, 255, 154, 216, 142, 4, 128, 169, 231, 133, 1, 169, 47, 133, 0, 169, 135, 141, 2, 222, 162, 57, 189, 43, 128, 157, 1, 223, 202, 208, 247, 76, 2, 223, 169, 4, 141, 2, 222, 162, 5, 142, 22, 208, 32, 163, 253, 32, 80, 253, 32, 21, 253, 32, 91, 255, 173, 36, 3, 141, 58, 223, 173, 37, 3, 141, 59, 223, 169, 49, 141, 36, 3, 169, 223, 141, 37, 3, 76, 254, 252, 120, 169, 135, 141, 2, 222, 76, 100, 128, 134, 2, 162, 39, 189, 58, 131, 157, 40, 4, 189, 201, 128, 157, 120, 4, 169, 1, 157, 40, 216, 157, 120, 216, 202, 16, 233, 173, 58, 223, 133, 254, 173, 59, 223, 133, 255, 162, 219, 189, 240, 128, 157, 1, 223, 202, 208, 247, 165, 254, 141, 16, 223, 165, 255, 141, 17, 223, 173, 48, 3, 141, 18, 223, 173, 49, 3, 141, 19, 223, 169, 10, 141, 36, 3, 169, 223, 141, 37, 3, 169, 2, 141, 48, 3, 169, 223, 141, 49, 3, 173, 0, 223, 141, 78, 223, 166, 2, 76, 10, 223, 32, 32, 1, 12, 5, 24, 39, 19, 32, 4, 9, 19, 11, 50, 5, 1, 19, 25, 6, 12, 1, 19, 8, 32, 45, 32, 34, 12, 15, 1, 4, 34, 32, 22, 48, 46, 57, 50, 32, 32, 133, 147, 32, 37, 223, 76, 125, 130, 32, 47, 223, 76, 203, 129, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 15, 177, 187, 153, 21, 223, 136, 16, 248, 72, 120, 165, 1, 141, 206, 223, 9, 7, 133, 1, 138, 72, 162, 4, 181, 251, 157, 215, 223, 202, 16, 248, 104, 170, 169, 135, 141, 2, 222, 169, 0, 141, 0, 222, 104, 96, 169, 4, 141, 2, 222, 32, 255, 255, 169, 135, 141, 2, 222, 96, 169, 128, 133, 255, 230, 253, 165, 253, 141, 0, 222, 177, 254, 145, 174, 200, 208, 249, 230, 175, 230, 255, 198, 252, 240, 9, 165, 255, 201, 160, 240, 224, 76, 109, 223, 165, 255, 201, 160, 208, 11, 169, 128, 133, 255, 230, 253, 165, 253, 141, 0, 222, 164, 251, 240, 9, 136, 177, 254, 145, 174, 192, 0, 208, 247, 24, 165, 174, 101, 251, 133, 174, 144, 2, 230, 175, 166, 174, 164, 175, 24, 169, 96, 141, 212, 223, 8, 72, 138, 72, 162, 4, 189, 215, 223, 149, 251, 202, 16, 248, 104, 170, 169, 4, 141, 2, 222, 169, 0, 133, 1, 104, 40, 88, 0, 0, 0, 255, 255, 255, 255, 255, 169, 76, 141, 212, 223, 173, 16, 223, 141, 213, 223, 173, 17, 223, 141, 214, 223, 165, 153, 208, 57, 165, 208, 208, 53, 132, 253, 173, 20, 223, 208, 3, 160, 12, 44, 160, 0, 185, 28, 130, 240, 8, 32, 22, 231, 230, 200, 200, 208, 243, 141, 146, 2, 133, 211, 133, 212, 230, 208, 164, 253, 206, 20, 223, 16, 12, 173, 16, 223, 141, 36, 3, 173, 17, 223, 141, 37, 3, 76, 184, 223, 76, 79, 65, 68, 34, 42, 34, 44, 56, 44, 49, 0, 82, 85, 78, 0, 164, 183, 240, 66, 192, 17, 176, 83, 136, 185, 21, 223, 201, 32, 240, 248, 200, 132, 191, 169, 114, 133, 251, 169, 131, 133, 252, 24, 165, 251, 105, 24, 133, 251, 144, 2, 230, 252, 160, 0, 177, 251, 240, 26, 185, 21, 223, 201, 42, 240, 17, 209, 251, 208, 228, 200, 196, 191, 208, 240, 192, 16, 240, 4, 177, 251, 208, 215, 24, 96, 56, 96, 24, 169, 96, 141, 212, 223, 76, 184, 223, 165, 147, 208, 6, 165, 186, 201, 8, 240, 26, 169, 76, 141, 212, 223, 173, 18, 223, 141, 213, 223, 173, 19, 223, 141, 214, 223, 165, 147, 166, 195, 164, 196, 76, 184, 223, 32, 44, 130, 176, 225, 169, 175, 141, 90, 223, 169, 245, 141, 91, 223, 32, 84, 223, 173, 20, 223, 48, 18, 162, 0, 160, 0, 161, 0, 161, 0, 161, 0, 161, 0, 232, 208, 245, 200, 208, 242, 169, 210, 141, 90, 223, 169, 245, 141, 91, 223, 32, 84, 223, 160, 16, 177, 251, 24, 109, 0, 223, 133, 253, 200, 200, 177, 251, 133, 254, 200, 177, 251, 133, 255, 200, 177, 251, 133, 174, 200, 177, 251, 133, 175, 200, 177, 251, 72, 200, 177, 251, 133, 252, 104, 133, 251, 165, 185, 208, 8, 165, 195, 133, 174, 165, 196, 133, 175, 24, 165, 251, 101, 254, 133, 251, 144, 2, 230, 252, 56, 165, 174, 229, 254, 133, 174, 176, 2, 198, 175, 164, 254, 169, 0, 133, 254, 141, 160, 223, 165, 252, 240, 3, 76, 104, 223, 140, 160, 223, 76, 145, 223, 32, 32, 32, 19, 9, 4, 5, 11, 9, 3, 11, 54, 52, 32, 4, 9, 19, 11, 32, 9, 13, 1, 7, 5, 32, 12, 1, 21, 14, 3, 8, 32, 21, 19, 9, 14, 7, 32, 32, 32, };
+uint8_t launcher_hi_auto[] = {169, 7, 141, 2, 222, 76, 0, 160, 120, 162, 8, 189, 228, 255, 149, 1, 202, 208, 248, 240, 8, 254, 255, 237, 255, 64, 120, };
+uint8_t startup_auto[] = {0, 0, 169, 135, 141, 2, 222, 76, 136, 4, 169, 0, 162, 251, 157, 255, 215, 157, 249, 216, 157, 243, 217, 157, 237, 218, 202, 208, 241, 162, 47, 189, 195, 4, 157, 0, 208, 202, 16, 247, 162, 30, 160, 6, 138, 153, 248, 7, 202, 136, 16, 248, 169, 127, 141, 0, 220, 162, 255, 142, 2, 220, 232, 142, 3, 220, 162, 0, 32, 166, 4, 189, 179, 4, 160, 3, 153, 39, 208, 136, 16, 250, 189, 187, 4, 141, 43, 208, 232, 224, 8, 208, 231, 162, 100, 32, 166, 4, 173, 1, 220, 41, 224, 201, 224, 208, 42, 202, 208, 241, 162, 7, 32, 166, 4, 32, 166, 4, 189, 179, 4, 160, 3, 153, 39, 208, 136, 16, 250, 189, 187, 4, 141, 43, 208, 202, 16, 230, 169, 0, 141, 0, 222, 141, 0, 223, 169, 0, 44, 169, 4, 141, 2, 222, 169, 0, 141, 2, 220, 141, 0, 220, 141, 21, 208, 108, 252, 255, 169, 255, 205, 18, 208, 208, 251, 205, 18, 208, 240, 251, 96, 0, 9, 11, 4, 12, 5, 15, 1, 0, 9, 11, 4, 12, 5, 8, 8, 0, 50, 24, 50, 48, 50, 72, 50, 36, 50, 20, 231, 44, 231, 0, 0, 31, 155, 55, 0, 0, 127, 8, 0, 20, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 5, 0, 120, 162, 255, 154, 216, 169, 8, 141, 22, 208, 157, 0, 1, 202, 208, 250, 162, 0, 189, 2, 254, 157, 0, 4, 189, 2, 255, 157, 0, 5, 189, 0, 248, 157, 0, 6, 189, 0, 249, 157, 0, 7, 202, 208, 229, 173, 1, 254, 141, 145, 4, 173, 0, 254, 141, 137, 4, 76, 0, 4, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 244, 254, 64, 255, };
+uint8_t sprites_auto[] = {0, 0, 0, 0, 0, 0, 124, 62, 31, 254, 127, 63, 198, 99, 49, 198, 99, 49, 198, 3, 48, 198, 3, 48, 198, 3, 48, 254, 127, 63, 254, 127, 63, 192, 99, 1, 192, 99, 1, 192, 99, 1, 198, 99, 49, 198, 99, 49, 254, 127, 63, 124, 62, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 192, 1, 152, 192, 3, 152, 192, 3, 152, 192, 3, 24, 192, 3, 24, 192, 3, 24, 192, 3, 159, 192, 3, 159, 192, 3, 128, 192, 3, 128, 192, 3, 128, 192, 3, 152, 192, 3, 152, 192, 3, 159, 192, 3, 15, 128, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 3, 225, 243, 7, 243, 3, 6, 51, 3, 6, 51, 3, 0, 51, 3, 0, 51, 3, 0, 51, 227, 7, 243, 227, 7, 243, 3, 6, 48, 3, 6, 48, 3, 6, 48, 3, 6, 51, 3, 6, 51, 3, 231, 243, 1, 227, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 140, 0, 249, 140, 0, 25, 140, 0, 25, 140, 0, 1, 140, 0, 1, 140, 0, 1, 140, 0, 249, 252, 0, 249, 140, 0, 25, 140, 0, 25, 140, 0, 25, 140, 0, 25, 140, 0, 25, 140, 0, 249, 140, 0, 241, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 24, 0, 0, 24, 0, 0, 28, 0, 0, 28, 0, 0, 28, 0, 0, 14, 0, 0, 14, 0, 0, 255, 0, 0, 255, 0, 0, 112, 0, 0, 112, 0, 0, 56, 0, 0, 56, 0, 0, 56, 0, 0, 24, 0, 0, 24, 0, 0, 8, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 128, 1, 0, 64, 2, 0, 32, 2, 56, 32, 2, 68, 32, 2, 71, 32, 2, 64, 32, 2, 71, 32, 2, 68, 32, 2, 56, 32, 2, 0, 32, 1, 0, 64, 0, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 128, 128, 0, 128, 186, 174, 128, 162, 164, 128, 185, 36, 128, 162, 164, 128, 186, 164, 128, 128, 0, 128, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 248, 124, 249, 252, 254, 25, 140, 198, 25, 140, 198, 25, 140, 198, 25, 140, 198, 25, 140, 198, 249, 252, 198, 249, 252, 198, 1, 240, 198, 1, 176, 198, 1, 184, 198, 1, 152, 198, 1, 156, 198, 1, 140, 254, 1, 140, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 127, 0, 0, 99, 0, 0, 99, 0, 0, 96, 0, 0, 96, 0, 0, 96, 0, 0, 111, 0, 0, 111, 0, 0, 99, 0, 0, 99, 0, 0, 99, 0, 0, 99, 0, 0, 99, 0, 0, 127, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
+
+uint8_t kapi_hi[] = {120, 162, 255, 154, 216, 142, 4, 128, 169, 231, 133, 1, 169, 47, 133, 0, 169, 135, 141, 2, 222, 162, 57, 189, 34, 160, 157, 1, 223, 202, 208, 247, 76, 2, 223, 169, 4, 141, 2, 222, 162, 5, 142, 22, 208, 32, 163, 253, 32, 80, 253, 32, 21, 253, 32, 91, 255, 173, 36, 3, 141, 58, 223, 173, 37, 3, 141, 59, 223, 169, 49, 141, 36, 3, 169, 223, 141, 37, 3, 76, 254, 252, 120, 169, 135, 141, 2, 222, 76, 91, 160, 134, 2, 162, 39, 189, 52, 163, 157, 40, 4, 189, 192, 160, 157, 120, 4, 169, 1, 157, 40, 216, 157, 120, 216, 202, 16, 233, 173, 58, 223, 133, 254, 173, 59, 223, 133, 255, 162, 219, 189, 231, 160, 157, 1, 223, 202, 208, 247, 165, 254, 141, 16, 223, 165, 255, 141, 17, 223, 173, 48, 3, 141, 18, 223, 173, 49, 3, 141, 19, 223, 169, 10, 141, 36, 3, 169, 223, 141, 37, 3, 169, 2, 141, 48, 3, 169, 223, 141, 49, 3, 173, 0, 223, 141, 78, 223, 166, 2, 76, 10, 223, 32, 32, 1, 12, 5, 24, 39, 19, 32, 4, 9, 19, 11, 50, 5, 1, 19, 25, 6, 12, 1, 19, 8, 32, 45, 32, 34, 12, 15, 1, 4, 34, 32, 22, 48, 46, 57, 50, 32, 32, 133, 147, 32, 37, 223, 76, 119, 162, 32, 47, 223, 76, 194, 161, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 15, 177, 187, 153, 21, 223, 136, 16, 248, 72, 120, 165, 1, 141, 206, 223, 9, 7, 133, 1, 138, 72, 162, 4, 181, 251, 157, 215, 223, 202, 16, 248, 104, 170, 169, 135, 141, 2, 222, 169, 0, 141, 0, 222, 104, 96, 169, 4, 141, 2, 222, 32, 255, 255, 169, 135, 141, 2, 222, 96, 169, 160, 133, 255, 230, 253, 165, 253, 141, 0, 222, 177, 254, 145, 174, 200, 208, 249, 230, 175, 230, 255, 198, 252, 240, 9, 165, 255, 201, 192, 240, 224, 76, 109, 223, 165, 255, 201, 192, 208, 11, 169, 160, 133, 255, 230, 253, 165, 253, 141, 0, 222, 164, 251, 240, 9, 136, 177, 254, 145, 174, 192, 0, 208, 247, 24, 165, 174, 101, 251, 133, 174, 144, 2, 230, 175, 166, 174, 164, 175, 24, 169, 96, 141, 212, 223, 8, 72, 138, 72, 162, 4, 189, 215, 223, 149, 251, 202, 16, 248, 104, 170, 169, 4, 141, 2, 222, 169, 0, 133, 1, 104, 40, 88, 0, 0, 0, 255, 255, 255, 255, 255, 169, 76, 141, 212, 223, 173, 16, 223, 141, 213, 223, 173, 17, 223, 141, 214, 223, 165, 153, 208, 60, 165, 208, 208, 56, 132, 253, 76, 7, 162, 173, 20, 223, 208, 3, 160, 12, 44, 160, 0, 185, 22, 162, 240, 8, 32, 22, 231, 230, 200, 200, 208, 243, 141, 146, 2, 133, 211, 133, 212, 230, 208, 164, 253, 206, 20, 223, 16, 12, 173, 16, 223, 141, 36, 3, 173, 17, 223, 141, 37, 3, 76, 184, 223, 76, 79, 65, 68, 34, 42, 34, 44, 56, 44, 49, 0, 82, 85, 78, 0, 164, 183, 240, 66, 192, 17, 176, 83, 136, 185, 21, 223, 201, 32, 240, 248, 200, 132, 191, 169, 108, 133, 251, 169, 163, 133, 252, 24, 165, 251, 105, 24, 133, 251, 144, 2, 230, 252, 160, 0, 177, 251, 240, 26, 185, 21, 223, 201, 42, 240, 17, 209, 251, 208, 228, 200, 196, 191, 208, 240, 192, 16, 240, 4, 177, 251, 208, 215, 24, 96, 56, 96, 24, 169, 96, 141, 212, 223, 76, 184, 223, 165, 147, 208, 6, 165, 186, 201, 8, 240, 26, 169, 76, 141, 212, 223, 173, 18, 223, 141, 213, 223, 173, 19, 223, 141, 214, 223, 165, 147, 166, 195, 164, 196, 76, 184, 223, 32, 38, 162, 176, 225, 169, 175, 141, 90, 223, 169, 245, 141, 91, 223, 32, 84, 223, 173, 20, 223, 48, 18, 162, 0, 160, 0, 161, 0, 161, 0, 161, 0, 161, 0, 232, 208, 245, 200, 208, 242, 169, 210, 141, 90, 223, 169, 245, 141, 91, 223, 32, 84, 223, 160, 16, 177, 251, 24, 109, 0, 223, 133, 253, 200, 200, 177, 251, 133, 254, 200, 177, 251, 133, 255, 200, 177, 251, 133, 174, 200, 177, 251, 133, 175, 200, 177, 251, 72, 200, 177, 251, 133, 252, 104, 133, 251, 165, 185, 208, 8, 165, 195, 133, 174, 165, 196, 133, 175, 24, 165, 251, 101, 254, 133, 251, 144, 2, 230, 252, 56, 165, 174, 229, 254, 133, 174, 176, 2, 198, 175, 164, 254, 169, 0, 133, 254, 141, 160, 223, 165, 252, 240, 3, 76, 104, 223, 140, 160, 223, 76, 145, 223, 32, 32, 32, 19, 9, 4, 5, 11, 9, 3, 11, 54, 52, 32, 4, 9, 19, 11, 32, 9, 13, 1, 7, 5, 32, 12, 1, 21, 14, 3, 8, 32, 21, 19, 9, 14, 7, 32, 32, 32, };
+uint8_t kapi_nm[] = {9, 128, 9, 128, 195, 194, 205, 56, 48, 120, 162, 255, 154, 216, 142, 4, 128, 169, 231, 133, 1, 169, 47, 133, 0, 169, 135, 141, 2, 222, 162, 57, 189, 43, 128, 157, 1, 223, 202, 208, 247, 76, 2, 223, 169, 4, 141, 2, 222, 162, 5, 142, 22, 208, 32, 163, 253, 32, 80, 253, 32, 21, 253, 32, 91, 255, 173, 36, 3, 141, 58, 223, 173, 37, 3, 141, 59, 223, 169, 49, 141, 36, 3, 169, 223, 141, 37, 3, 76, 254, 252, 120, 169, 135, 141, 2, 222, 76, 100, 128, 134, 2, 162, 39, 189, 61, 131, 157, 40, 4, 189, 201, 128, 157, 120, 4, 169, 1, 157, 40, 216, 157, 120, 216, 202, 16, 233, 173, 58, 223, 133, 254, 173, 59, 223, 133, 255, 162, 219, 189, 240, 128, 157, 1, 223, 202, 208, 247, 165, 254, 141, 16, 223, 165, 255, 141, 17, 223, 173, 48, 3, 141, 18, 223, 173, 49, 3, 141, 19, 223, 169, 10, 141, 36, 3, 169, 223, 141, 37, 3, 169, 2, 141, 48, 3, 169, 223, 141, 49, 3, 173, 0, 223, 141, 78, 223, 166, 2, 76, 10, 223, 32, 32, 1, 12, 5, 24, 39, 19, 32, 4, 9, 19, 11, 50, 5, 1, 19, 25, 6, 12, 1, 19, 8, 32, 45, 32, 34, 12, 15, 1, 4, 34, 32, 22, 48, 46, 57, 50, 32, 32, 133, 147, 32, 37, 223, 76, 128, 130, 32, 47, 223, 76, 203, 129, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 15, 177, 187, 153, 21, 223, 136, 16, 248, 72, 120, 165, 1, 141, 206, 223, 9, 7, 133, 1, 138, 72, 162, 4, 181, 251, 157, 215, 223, 202, 16, 248, 104, 170, 169, 135, 141, 2, 222, 169, 0, 141, 0, 222, 104, 96, 169, 4, 141, 2, 222, 32, 255, 255, 169, 135, 141, 2, 222, 96, 169, 128, 133, 255, 230, 253, 165, 253, 141, 0, 222, 177, 254, 145, 174, 200, 208, 249, 230, 175, 230, 255, 198, 252, 240, 9, 165, 255, 201, 192, 240, 224, 76, 109, 223, 165, 255, 201, 192, 208, 11, 169, 128, 133, 255, 230, 253, 165, 253, 141, 0, 222, 164, 251, 240, 9, 136, 177, 254, 145, 174, 192, 0, 208, 247, 24, 165, 174, 101, 251, 133, 174, 144, 2, 230, 175, 166, 174, 164, 175, 24, 169, 96, 141, 212, 223, 8, 72, 138, 72, 162, 4, 189, 215, 223, 149, 251, 202, 16, 248, 104, 170, 169, 4, 141, 2, 222, 169, 0, 133, 1, 104, 40, 88, 0, 0, 0, 255, 255, 255, 255, 255, 169, 76, 141, 212, 223, 173, 16, 223, 141, 213, 223, 173, 17, 223, 141, 214, 223, 165, 153, 208, 60, 165, 208, 208, 56, 132, 253, 76, 16, 130, 173, 20, 223, 208, 3, 160, 12, 44, 160, 0, 185, 31, 130, 240, 8, 32, 22, 231, 230, 200, 200, 208, 243, 141, 146, 2, 133, 211, 133, 212, 230, 208, 164, 253, 206, 20, 223, 16, 12, 173, 16, 223, 141, 36, 3, 173, 17, 223, 141, 37, 3, 76, 184, 223, 76, 79, 65, 68, 34, 42, 34, 44, 56, 44, 49, 0, 82, 85, 78, 0, 164, 183, 240, 66, 192, 17, 176, 83, 136, 185, 21, 223, 201, 32, 240, 248, 200, 132, 191, 169, 117, 133, 251, 169, 131, 133, 252, 24, 165, 251, 105, 24, 133, 251, 144, 2, 230, 252, 160, 0, 177, 251, 240, 26, 185, 21, 223, 201, 42, 240, 17, 209, 251, 208, 228, 200, 196, 191, 208, 240, 192, 16, 240, 4, 177, 251, 208, 215, 24, 96, 56, 96, 24, 169, 96, 141, 212, 223, 76, 184, 223, 165, 147, 208, 6, 165, 186, 201, 8, 240, 26, 169, 76, 141, 212, 223, 173, 18, 223, 141, 213, 223, 173, 19, 223, 141, 214, 223, 165, 147, 166, 195, 164, 196, 76, 184, 223, 32, 47, 130, 176, 225, 169, 175, 141, 90, 223, 169, 245, 141, 91, 223, 32, 84, 223, 173, 20, 223, 48, 18, 162, 0, 160, 0, 161, 0, 161, 0, 161, 0, 161, 0, 232, 208, 245, 200, 208, 242, 169, 210, 141, 90, 223, 169, 245, 141, 91, 223, 32, 84, 223, 160, 16, 177, 251, 24, 109, 0, 223, 133, 253, 200, 200, 177, 251, 133, 254, 200, 177, 251, 133, 255, 200, 177, 251, 133, 174, 200, 177, 251, 133, 175, 200, 177, 251, 72, 200, 177, 251, 133, 252, 104, 133, 251, 165, 185, 208, 8, 165, 195, 133, 174, 165, 196, 133, 175, 24, 165, 251, 101, 254, 133, 251, 144, 2, 230, 252, 56, 165, 174, 229, 254, 133, 174, 176, 2, 198, 175, 164, 254, 169, 0, 133, 254, 141, 160, 223, 165, 252, 240, 3, 76, 104, 223, 140, 160, 223, 76, 145, 223, 32, 32, 32, 19, 9, 4, 5, 11, 9, 3, 11, 54, 52, 32, 4, 9, 19, 11, 32, 9, 13, 1, 7, 5, 32, 12, 1, 21, 14, 3, 8, 32, 21, 19, 9, 14, 7, 32, 32, 32, };
+uint8_t kapi_lo[] = {9, 128, 9, 128, 195, 194, 205, 56, 48, 120, 162, 255, 154, 216, 142, 4, 128, 169, 231, 133, 1, 169, 47, 133, 0, 169, 135, 141, 2, 222, 162, 57, 189, 43, 128, 157, 1, 223, 202, 208, 247, 76, 2, 223, 169, 4, 141, 2, 222, 162, 5, 142, 22, 208, 32, 163, 253, 32, 80, 253, 32, 21, 253, 32, 91, 255, 173, 36, 3, 141, 58, 223, 173, 37, 3, 141, 59, 223, 169, 49, 141, 36, 3, 169, 223, 141, 37, 3, 76, 254, 252, 120, 169, 135, 141, 2, 222, 76, 100, 128, 134, 2, 162, 39, 189, 61, 131, 157, 40, 4, 189, 201, 128, 157, 120, 4, 169, 1, 157, 40, 216, 157, 120, 216, 202, 16, 233, 173, 58, 223, 133, 254, 173, 59, 223, 133, 255, 162, 219, 189, 240, 128, 157, 1, 223, 202, 208, 247, 165, 254, 141, 16, 223, 165, 255, 141, 17, 223, 173, 48, 3, 141, 18, 223, 173, 49, 3, 141, 19, 223, 169, 10, 141, 36, 3, 169, 223, 141, 37, 3, 169, 2, 141, 48, 3, 169, 223, 141, 49, 3, 173, 0, 223, 141, 78, 223, 166, 2, 76, 10, 223, 32, 32, 1, 12, 5, 24, 39, 19, 32, 4, 9, 19, 11, 50, 5, 1, 19, 25, 6, 12, 1, 19, 8, 32, 45, 32, 34, 12, 15, 1, 4, 34, 32, 22, 48, 46, 57, 50, 32, 32, 133, 147, 32, 37, 223, 76, 128, 130, 32, 47, 223, 76, 203, 129, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 15, 177, 187, 153, 21, 223, 136, 16, 248, 72, 120, 165, 1, 141, 206, 223, 9, 7, 133, 1, 138, 72, 162, 4, 181, 251, 157, 215, 223, 202, 16, 248, 104, 170, 169, 135, 141, 2, 222, 169, 0, 141, 0, 222, 104, 96, 169, 4, 141, 2, 222, 32, 255, 255, 169, 135, 141, 2, 222, 96, 169, 128, 133, 255, 230, 253, 165, 253, 141, 0, 222, 177, 254, 145, 174, 200, 208, 249, 230, 175, 230, 255, 198, 252, 240, 9, 165, 255, 201, 160, 240, 224, 76, 109, 223, 165, 255, 201, 160, 208, 11, 169, 128, 133, 255, 230, 253, 165, 253, 141, 0, 222, 164, 251, 240, 9, 136, 177, 254, 145, 174, 192, 0, 208, 247, 24, 165, 174, 101, 251, 133, 174, 144, 2, 230, 175, 166, 174, 164, 175, 24, 169, 96, 141, 212, 223, 8, 72, 138, 72, 162, 4, 189, 215, 223, 149, 251, 202, 16, 248, 104, 170, 169, 4, 141, 2, 222, 169, 0, 133, 1, 104, 40, 88, 0, 0, 0, 255, 255, 255, 255, 255, 169, 76, 141, 212, 223, 173, 16, 223, 141, 213, 223, 173, 17, 223, 141, 214, 223, 165, 153, 208, 60, 165, 208, 208, 56, 132, 253, 76, 16, 130, 173, 20, 223, 208, 3, 160, 12, 44, 160, 0, 185, 31, 130, 240, 8, 32, 22, 231, 230, 200, 200, 208, 243, 141, 146, 2, 133, 211, 133, 212, 230, 208, 164, 253, 206, 20, 223, 16, 12, 173, 16, 223, 141, 36, 3, 173, 17, 223, 141, 37, 3, 76, 184, 223, 76, 79, 65, 68, 34, 42, 34, 44, 56, 44, 49, 0, 82, 85, 78, 0, 164, 183, 240, 66, 192, 17, 176, 83, 136, 185, 21, 223, 201, 32, 240, 248, 200, 132, 191, 169, 117, 133, 251, 169, 131, 133, 252, 24, 165, 251, 105, 24, 133, 251, 144, 2, 230, 252, 160, 0, 177, 251, 240, 26, 185, 21, 223, 201, 42, 240, 17, 209, 251, 208, 228, 200, 196, 191, 208, 240, 192, 16, 240, 4, 177, 251, 208, 215, 24, 96, 56, 96, 24, 169, 96, 141, 212, 223, 76, 184, 223, 165, 147, 208, 6, 165, 186, 201, 8, 240, 26, 169, 76, 141, 212, 223, 173, 18, 223, 141, 213, 223, 173, 19, 223, 141, 214, 223, 165, 147, 166, 195, 164, 196, 76, 184, 223, 32, 47, 130, 176, 225, 169, 175, 141, 90, 223, 169, 245, 141, 91, 223, 32, 84, 223, 173, 20, 223, 48, 18, 162, 0, 160, 0, 161, 0, 161, 0, 161, 0, 161, 0, 232, 208, 245, 200, 208, 242, 169, 210, 141, 90, 223, 169, 245, 141, 91, 223, 32, 84, 223, 160, 16, 177, 251, 24, 109, 0, 223, 133, 253, 200, 200, 177, 251, 133, 254, 200, 177, 251, 133, 255, 200, 177, 251, 133, 174, 200, 177, 251, 133, 175, 200, 177, 251, 72, 200, 177, 251, 133, 252, 104, 133, 251, 165, 185, 208, 8, 165, 195, 133, 174, 165, 196, 133, 175, 24, 165, 251, 101, 254, 133, 251, 144, 2, 230, 252, 56, 165, 174, 229, 254, 133, 174, 176, 2, 198, 175, 164, 254, 169, 0, 133, 254, 141, 160, 223, 165, 252, 240, 3, 76, 104, 223, 140, 160, 223, 76, 145, 223, 32, 32, 32, 19, 9, 4, 5, 11, 9, 3, 11, 54, 52, 32, 4, 9, 19, 11, 32, 9, 13, 1, 7, 5, 32, 12, 1, 21, 14, 3, 8, 32, 21, 19, 9, 14, 7, 32, 32, 32, };
+uint8_t launcher_hi[] = {169, 7, 141, 2, 222, 76, 0, 160, 120, 162, 8, 189, 228, 255, 149, 1, 202, 208, 248, 240, 8, 254, 255, 237, 255, 64, 120, };
+uint8_t startup[] = {0, 0, 169, 135, 141, 2, 222, 76, 136, 4, 169, 0, 162, 251, 157, 255, 215, 157, 249, 216, 157, 243, 217, 157, 237, 218, 202, 208, 241, 162, 47, 189, 195, 4, 157, 0, 208, 202, 16, 247, 162, 30, 160, 6, 138, 153, 248, 7, 202, 136, 16, 248, 169, 127, 141, 0, 220, 162, 255, 142, 2, 220, 232, 142, 3, 220, 162, 0, 32, 166, 4, 189, 179, 4, 160, 3, 153, 39, 208, 136, 16, 250, 189, 187, 4, 141, 43, 208, 232, 224, 8, 208, 231, 162, 100, 32, 166, 4, 173, 1, 220, 41, 224, 201, 224, 208, 42, 202, 208, 241, 162, 7, 32, 166, 4, 32, 166, 4, 189, 179, 4, 160, 3, 153, 39, 208, 136, 16, 250, 189, 187, 4, 141, 43, 208, 202, 16, 230, 169, 0, 141, 0, 222, 141, 0, 223, 169, 0, 44, 169, 4, 141, 2, 222, 169, 0, 141, 2, 220, 141, 0, 220, 141, 21, 208, 108, 252, 255, 169, 255, 205, 18, 208, 208, 251, 205, 18, 208, 240, 251, 96, 0, 9, 11, 4, 12, 5, 15, 1, 0, 9, 11, 4, 12, 5, 8, 8, 0, 50, 24, 50, 48, 50, 72, 50, 36, 50, 20, 231, 44, 231, 0, 0, 31, 155, 55, 0, 0, 127, 8, 0, 20, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 5, 0, 120, 162, 255, 154, 216, 169, 8, 141, 22, 208, 157, 0, 1, 202, 208, 250, 162, 0, 189, 2, 254, 157, 0, 4, 189, 2, 255, 157, 0, 5, 189, 0, 248, 157, 0, 6, 189, 0, 249, 157, 0, 7, 202, 208, 229, 173, 1, 254, 141, 145, 4, 173, 0, 254, 141, 137, 4, 76, 0, 4, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 244, 254, 64, 255, };
+uint8_t sprites[] = {0, 0, 0, 0, 0, 0, 124, 62, 31, 254, 127, 63, 198, 99, 49, 198, 99, 49, 198, 3, 48, 198, 3, 48, 198, 3, 48, 254, 127, 63, 254, 127, 63, 192, 99, 1, 192, 99, 1, 192, 99, 1, 198, 99, 49, 198, 99, 49, 254, 127, 63, 124, 62, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 192, 1, 152, 192, 3, 152, 192, 3, 152, 192, 3, 24, 192, 3, 24, 192, 3, 24, 192, 3, 159, 192, 3, 159, 192, 3, 128, 192, 3, 128, 192, 3, 128, 192, 3, 152, 192, 3, 152, 192, 3, 159, 192, 3, 15, 128, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 3, 225, 243, 7, 243, 3, 6, 51, 3, 6, 51, 3, 0, 51, 3, 0, 51, 3, 0, 51, 227, 7, 243, 227, 7, 243, 3, 6, 48, 3, 6, 48, 3, 6, 48, 3, 6, 51, 3, 6, 51, 3, 231, 243, 1, 227, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 140, 0, 249, 140, 0, 25, 140, 0, 25, 140, 0, 1, 140, 0, 1, 140, 0, 1, 140, 0, 249, 252, 0, 249, 140, 0, 25, 140, 0, 25, 140, 0, 25, 140, 0, 25, 140, 0, 25, 140, 0, 249, 140, 0, 241, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 24, 0, 0, 24, 0, 0, 28, 0, 0, 28, 0, 0, 28, 0, 0, 14, 0, 0, 14, 0, 0, 255, 0, 0, 255, 0, 0, 112, 0, 0, 112, 0, 0, 56, 0, 0, 56, 0, 0, 56, 0, 0, 24, 0, 0, 24, 0, 0, 8, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 128, 1, 0, 64, 2, 0, 32, 2, 56, 32, 2, 68, 32, 2, 71, 32, 2, 64, 32, 2, 71, 32, 2, 68, 32, 2, 56, 32, 2, 0, 32, 1, 0, 64, 0, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 128, 128, 0, 128, 186, 174, 128, 162, 164, 128, 185, 36, 128, 162, 164, 128, 186, 164, 128, 128, 0, 128, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 248, 124, 249, 252, 254, 25, 140, 198, 25, 140, 198, 25, 140, 198, 25, 140, 198, 25, 140, 198, 249, 252, 198, 249, 252, 198, 1, 240, 198, 1, 176, 198, 1, 184, 198, 1, 152, 198, 1, 156, 198, 1, 140, 254, 1, 140, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 127, 0, 0, 99, 0, 0, 99, 0, 0, 96, 0, 0, 96, 0, 0, 96, 0, 0, 111, 0, 0, 111, 0, 0, 99, 0, 0, 99, 0, 0, 99, 0, 0, 99, 0, 0, 99, 0, 0, 127, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
+
diff --git a/D2EF/binaries.h b/D2EF/binaries.h
new file mode 100644
index 00000000..25d081c0
--- /dev/null
+++ b/D2EF/binaries.h
@@ -0,0 +1,31 @@
+#ifndef BINARIES_H
+#define BINARIES_H
+
+#include <stdint.h>
+extern uint8_t kapi_hi_auto[];
+#define kapi_hi_size_auto 857
+extern uint8_t kapi_nm_auto[];
+#define kapi_nm_size_auto 866
+extern uint8_t kapi_lo_auto[];
+#define kapi_lo_size_auto 866
+extern uint8_t launcher_hi_auto[];
+#define launcher_hi_size_auto 27
+extern uint8_t startup_auto[];
+#define startup_size_auto 512
+extern uint8_t sprites_auto[];
+#define sprites_size_auto 576
+
+extern uint8_t kapi_hi[];
+#define kapi_hi_size 860
+extern uint8_t kapi_nm[];
+#define kapi_nm_size 869
+extern uint8_t kapi_lo[];
+#define kapi_lo_size 869
+extern uint8_t launcher_hi[];
+#define launcher_hi_size 27
+extern uint8_t startup[];
+#define startup_size 512
+extern uint8_t sprites[];
+#define sprites_size 576
+
+#endif
diff --git a/D2EF/bundle.cpp b/D2EF/bundle.cpp
new file mode 100644
index 00000000..3b072aea
--- /dev/null
+++ b/D2EF/bundle.cpp
@@ -0,0 +1,170 @@
+#include <stdlib.h>
+#include <stdio.h>
+//#include "getopt.h"
+#include <errno.h>
+//#include <libgen.h>
+#include <sys/stat.h>
+//#include "dirent.h"
+#include <string.h>
+
+//#include "m2i.h"
+#include "bundle.h"
+#include "cart.h"
+
+static unsigned char toupper( unsigned char c )
+{
+	if ( c >= 'a' && c <= 'z' )
+		return c + 'A' - 'a';
+	return c;
+}
+
+
+uint8_t flash_memory[MAX_BANKS * 0x4000];
+
+struct dir_entry {
+	char name[16];
+	uint8_t bank[2]; // lo/hi
+	uint8_t offset[2]; // lo/hi
+	uint8_t loadaddress[2]; // lo/hi
+	uint8_t size[2]; // lo/hi
+};
+
+void bundle(unsigned char **out, struct m2i *entries, 
+			uint32_t bank_size, uint32_t bank_offset, uint32_t bank_shift, 
+			uint8_t *api, uint32_t api_length, uint8_t *launcher, uint32_t launcher_length,
+			uint16_t first_bank
+			){
+	uint32_t pos = 0, dir_pos;
+	struct m2i *entr;
+	int i, j;
+	BankHeader BankHeader;
+	
+	// set everything to 0xff
+	memset(flash_memory, 0xff, MAX_BANKS * 0x4000);
+	
+	// add the api
+	memcpy(&flash_memory[pos], api, api_length);
+	pos += api_length;
+	
+	// add the visible line
+	for(i=strlen(entries->name); entries->name[i-1] == 0x20; i--);
+	entries->name[i] = '\0';
+	i = (31-strlen(entries->name)) / 2;
+	memset(&flash_memory[pos], 0x20, 40);
+	flash_memory[pos+i+0] = '*';
+	flash_memory[pos+i+1] = '*';
+	flash_memory[pos+i+2] = '*';
+	flash_memory[pos+i+3] = '*';
+	for(j=0; j<strlen(entries->name); j++){
+		if(toupper(entries->name[j]) >= 0x41 && toupper(entries->name[j]) <= 0x5a){
+			flash_memory[pos+i+5+j] = toupper(entries->name[j]) - 0x40;
+		}else{
+			flash_memory[pos+i+5+j] = toupper(entries->name[j]);
+		}
+	}
+	flash_memory[pos+i+5+strlen(entries->name)+1] = '*';
+	flash_memory[pos+i+5+strlen(entries->name)+2] = '*';
+	flash_memory[pos+i+5+strlen(entries->name)+3] = '*';
+	flash_memory[pos+i+5+strlen(entries->name)+4] = '*';
+	pos += 40;
+	
+	// setup dir_pos (but the dir is still empty)
+	dir_pos = pos;
+	for(i=0, entr = entries->next; entr != NULL; entr=entr->next){
+		if(entr->type == 'p'){
+			i++;
+		}
+	}
+	pos += i*24;
+	
+	// setup "end of dir marker"
+	flash_memory[pos++] = 0;
+	
+	// add an ultimax launcher, if needed
+	if(launcher != NULL){
+		memcpy(&flash_memory[bank_size - launcher_length], launcher, launcher_length);
+		pos = bank_size;
+	}
+	
+	// add all files!
+	for(entr = entries->next; entr != NULL; entr = entr->next){
+		if(entr->type == 'p'){
+			// is a PRG, the only thing we store
+			uint32_t bank, offset, size;
+			struct dir_entry *dir_entry = (struct dir_entry *) (&flash_memory[dir_pos]);
+			
+			bank = pos >> bank_shift;
+			offset = pos & (bank_size-1);
+			offset += bank_offset;
+			size = entr->length - 2;
+			
+			if(strlen(entr->name) == 16){
+				memcpy(dir_entry->name, entr->name, 16);
+			}else{
+				strcpy(dir_entry->name, entr->name);
+			}
+			dir_entry->bank[0] = bank & 0xff;
+			dir_entry->bank[1] = bank >> 8;
+			dir_entry->offset[0] = offset & 0xff;
+			dir_entry->offset[1] = offset >> 8;
+			dir_entry->size[0] = size & 0xff;
+			dir_entry->size[1] = size >> 8;
+			dir_entry->loadaddress[0] = entr->data[0];
+			dir_entry->loadaddress[1] = entr->data[1];
+			
+			memcpy(&flash_memory[pos], &entr->data[2], size);
+			pos += size;
+			
+			dir_pos += sizeof(struct dir_entry);
+		}
+	}
+	
+	// setup commons	
+	char chip_singnature[] = { 0x43, 0x48, 0x49, 0x50 };
+
+	memcpy(BankHeader.signature, chip_singnature, 4);
+	BankHeader.packetLen[0] = 0x00;
+	BankHeader.packetLen[1] = 0x00;
+	BankHeader.packetLen[2] = 0x20;
+	BankHeader.packetLen[3] = 0x10;
+	BankHeader.chipType[0] = 0x00;
+	BankHeader.chipType[1] = 0x00;
+	BankHeader.loadAddr[1] = 0x00;
+	BankHeader.romLen[0] = 0x20;
+	BankHeader.romLen[1] = 0x00;
+	
+	for(dir_pos=0; dir_pos<((pos+0x1fff) >> 13); dir_pos++){
+		if(bank_size == 0x4000){
+			BankHeader.bank[0] = ((first_bank<<1) + dir_pos) >> 9;
+			BankHeader.bank[1] = ((first_bank<<1) + dir_pos) >> 1;
+			BankHeader.loadAddr[0] = (0x8000 >> 8) + (dir_pos & 1 ? 0x20 : 0x00);
+		}else{
+			BankHeader.bank[0] = (first_bank + dir_pos) >> 8;
+			BankHeader.bank[1] = (first_bank + dir_pos);
+			BankHeader.loadAddr[0] = (0x8000 | (bank_offset & 0x2000)) >> 8;
+		}
+		//fwrite(&BankHeader, 1, sizeof(BankHeader), out);
+		memcpy( *out, &BankHeader, sizeof(BankHeader) );
+		*out += sizeof(BankHeader);
+		
+		//fwrite(&flash_memory[dir_pos << 13], 1, 0x2000, out);
+		memcpy( *out, &flash_memory[dir_pos << 13], 0x2000 );
+		*out += 0x2000;
+
+	}
+	
+	/*if(bank_size == 0x4000){
+		fprintf(stderr, "disk2easyflash conversion finished: %d%s banks (%d KiB) used   (%d bytes used in the last 8 KiB bank)\n",
+				dir_pos >> 1,
+				(dir_pos & 1) ? ".5" : "",
+				dir_pos * 8,
+				pos - ((dir_pos-1) << 13)
+				);
+	}else{
+		fprintf(stderr, "disk2easyflash conversion finished: %d banks (%d KiB) used   (%d bytes used in the last 8 KiB bank)\n",
+				dir_pos,
+				dir_pos * 8,
+				pos - ((dir_pos-1) << 13)
+				);
+	}*/
+}
diff --git a/D2EF/bundle.h b/D2EF/bundle.h
new file mode 100644
index 00000000..6944b62f
--- /dev/null
+++ b/D2EF/bundle.h
@@ -0,0 +1,15 @@
+#ifndef BUNDLE_H
+#define BUNDLE_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "m2i.h"
+
+extern void bundle(unsigned char **out, struct m2i *entries, 
+		uint32_t bank_size, uint32_t bank_offset, uint32_t bank_shift, 
+		uint8_t *api, uint32_t api_length, uint8_t *launcher, uint32_t launcher_length,
+		uint16_t first_bank
+);
+
+#endif
\ No newline at end of file
diff --git a/D2EF/cart.h b/D2EF/cart.h
new file mode 100644
index 00000000..0f513f10
--- /dev/null
+++ b/D2EF/cart.h
@@ -0,0 +1,71 @@
+
+#ifndef CART_H
+#define CART_H
+
+#include <stdint.h>
+
+// Reference: http://ist.uwaterloo.ca/~schepers/formats/CRT.TXT
+typedef struct CartHeader_s
+{
+    // Cartridge signature "C64 CARTRIDGE" (padded with space chars)
+    char signature[16];
+
+    // File header length  ($00000040,  high/low)
+    uint8_t headerLen[4];
+
+    // Cartridge version (high/low, presently 01.00)
+    uint8_t version[2];
+
+    // Cartridge hardware type ($0000, high/low)
+    uint8_t type[2];
+
+    // Cartridge port EXROM line status (1 = active)
+    uint8_t exromLine;
+
+    // Cartridge port GAME line status (1 = active)
+    uint8_t gameLine;
+
+    // Reserved for future use (6 bytes)
+    uint8_t reserved[6];
+
+    // 32-byte cartridge name (uppercase,  padded with 0)
+    char name[32];
+}
+CartHeader;
+
+
+typedef struct BankHeader_s
+{
+    // Contained ROM signature "CHIP"
+    char signature[4];
+
+    // Total packet length, ROM image size + header (high/low format)
+    uint8_t packetLen[4];
+
+    // Chip type: 0 - ROM, 1 - RAM, no ROM data, 2 - Flash ROM
+    uint8_t chipType[2];
+
+    // Bank number ($0000 - normal cartridge) (?)
+    uint8_t bank[2];
+
+    // Starting load address (high/low format) (?)
+    uint8_t loadAddr[2];
+
+    // ROM image size (high/low format, typically $2000 or $4000)
+    uint8_t romLen[2];
+}
+BankHeader;
+
+
+// "C64 CARTRIDGE   "
+#define CART_SIGNATURE { 0x43, 0x36, 0x34, 0x20, 0x43, 0x41, 0x52, 0x54, 0x52, 0x49, 0x44, 0x47, 0x45, 0x20, 0x20, 0x20 }
+#define CHIP_SIGNATURE { 0x43, 0x48, 0x49, 0x50 }
+
+// These are the cartridge types from the file header
+#define CART_TYPE_EASYFLASH       32
+#define CART_TYPE_EASYFLASH_XBANK 33
+
+#define MAX_BANKS 63
+// one less than the easyflash can, because we need space to add a lancher
+
+#endif // CART_H
diff --git a/D2EF/d64.cpp b/D2EF/d64.cpp
new file mode 100644
index 00000000..7826edf2
--- /dev/null
+++ b/D2EF/d64.cpp
@@ -0,0 +1,121 @@
+#include <stdlib.h>
+#include <stdio.h>
+//#include "getopt.h"
+#include <errno.h>
+//#include <libgen.h>
+#include <sys/stat.h>
+//#include "dirent.h"
+#include <string.h>
+
+#include "m2i.h"
+#include "diskimage.h"
+
+//struct m2i * parse_d64(char *filename){
+struct m2i * parse_d64(unsigned char *image, int imageSize){
+	struct m2i *first, *last;
+	DiskImage *di;
+	ImageFile *dh, *fdh;
+	unsigned char buffer[254];
+	int offset;
+	//	FILE *f;
+	
+	first = (m2i*)malloc(sizeof(struct m2i));
+	first->next = NULL;
+	first->type = '*';
+	last = first;
+	
+	/* Load image into ram */
+//	if ((di = di_load_image(filename)) == NULL) {
+	if ((di = di_load_image(image, imageSize)) == NULL) {
+		//fprintf(stderr, "unable to open \"%s\"\n", filename);
+		//exit(1);
+	}
+	
+	/* Convert title */
+	di_name_from_rawname(first->name, di_title(di));
+	
+	/* Convert ID */
+	memcpy(first->id, di_title(di) + 18, 5);
+	first->id[5] = 0;
+	
+	/* Open directory for reading */
+	if ((dh = di_open(di, (unsigned char *) "$", T_PRG, "rb")) == NULL) {
+		//fprintf(stderr, "unable to read directory \"%s\"\n", filename);
+		//exit(1);
+	}
+	
+	/* Read first block into buffer */
+	if (di_read(dh, buffer, 254) != 254) {
+		//fprintf(stderr, "unable to read bam \"%s\"\n", filename);
+		//exit(1);
+	}
+	
+	/* Read directory blocks */
+	while (di_read(dh, buffer, 254) == 254) {
+		for (offset = -2; offset < 254; offset += 32) {
+			
+			/* If file type != 0 */
+			if (buffer[offset+2]) {
+				
+				struct m2i *entry = (m2i*)malloc(sizeof(struct m2i));
+				
+				entry->next = NULL;
+				di_name_from_rawname(entry->name, buffer + offset + 5);
+				
+				//	type = buffer[offset + 2] & 7;
+				//	closed = buffer[offset + 2] & 0x80;
+				//	locked = buffer[offset + 2] & 0x40;
+				//	size = buffer[offset + 31]<<8 | buffer[offset + 30];
+				
+				switch(buffer[offset + 2] & 7){
+					case 0: // DEL
+						entry->type = 'd';
+						break;
+					case 2: // PRG
+						entry->type = 'p';
+						break;
+					default:
+						//fprintf(stderr, "unsuported type %d", buffer[offset + 2] & 7);
+						//exit(1);
+						break;
+				}
+				
+				if(entry->type == 'd'){
+					entry->length = 0;
+					last->next = entry;
+					last = entry;
+				}else{
+#define temp_space (1024*1024)
+					int len;
+					
+					entry->data = (uint8_t*)malloc(temp_space);
+					entry->length = 0;
+					
+					if ((fdh = di_open(di, buffer + offset + 5, (FileType)(buffer[offset + 2] & 7), "rb")) == NULL) {
+						//fprintf(stderr, "warning: unable to open file \"%s\" in d64 \"%s\"\n", last->name, filename);
+					}else{
+						
+						while ((len = di_read(fdh, &entry->data[entry->length], temp_space - entry->length)) > 0) {
+							entry->length += len;
+						}
+						
+						entry->data = (uint8_t*)realloc(entry->data, entry->length);
+						
+						di_close(fdh);
+						last->next = entry;
+						last = entry;
+						
+					}
+					
+				}
+				
+			}
+		}
+	}
+	
+	
+	di_close(dh);
+	di_free_image(di);
+	
+	return first;
+}
diff --git a/D2EF/d64.h b/D2EF/d64.h
new file mode 100644
index 00000000..41756693
--- /dev/null
+++ b/D2EF/d64.h
@@ -0,0 +1,9 @@
+#ifndef D64_H
+#define D64_H
+
+#include "m2i.h"
+
+//struct m2i * parse_d64(char *filename);
+struct m2i * parse_d64(unsigned char *image, int imageSize);
+
+#endif
diff --git a/D2EF/disk2easyflash.cpp b/D2EF/disk2easyflash.cpp
new file mode 100644
index 00000000..96a967f5
--- /dev/null
+++ b/D2EF/disk2easyflash.cpp
@@ -0,0 +1,305 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include "d64.h"
+#include "bundle.h"
+#include "binaries.h"
+#include "cart.h"
+
+#define mode_lo 0
+#define mode_nm 1
+#define mode_hi 2
+
+#define build_none 0
+#define build_xbank 1
+#define build_crt 2
+#define build_list 3
+
+//unsigned char cart[ 1024 * 1024 + 128 ];
+//unsigned char diskimage[ 1024 * 1024 ];
+//int imageSize;
+
+int createD2EF( unsigned char *diskimage, int imageSize, unsigned char *cart, int build, int mode, int autostart )
+{
+/*	build = build_crt;
+	mode = mode_nm;
+	int autostart = 0;*/
+
+	static char cart_singnature[] = { 0x43, 0x36, 0x34, 0x20, 0x43, 0x41, 0x52, 0x54, 0x52, 0x49, 0x44, 0x47, 0x45, 0x20, 0x20, 0x20 };
+	static char chip_singnature[] = { 0x43, 0x48, 0x49, 0x50 };
+
+	char txt_blocks_free[] = "BLOCKS FREE.";
+	char txt_prg[] = "PRG";
+	char txt_del[] = "DEL";
+
+	int i;
+	int nolisting = 0;
+	int blocksfree = 2;
+	//int verbose = 0;
+	//struct stat m2i_stat;
+	struct m2i *entries, *entr;
+	unsigned char *out;
+
+	CartHeader CartHeader;
+
+	out = cart;
+
+	entries = parse_d64(diskimage, imageSize);
+	
+	if(!nolisting){
+		struct m2i *entry = (struct m2i *)malloc(sizeof(struct m2i));
+		int num;
+		
+		// search last entry
+		for(num = 0, entr = entries; entr != NULL; num++, entr = entr->next);
+		
+		// fill up entry
+		entry->next = NULL;
+		strcpy(entry->name, "$");
+		entry->type = 'p';
+		entry->data = (uint8_t*)malloc(50 + num * 30);
+		entry->length = 0;
+		
+		// basic setup 
+		entr = entries;
+		
+		entry->data[entry->length++] = 0x01; // laod address
+		entry->data[entry->length++] = 0x04;
+		
+		// first line
+		entry->data[entry->length++] = 0x01; // next ptr
+		entry->data[entry->length++] = 0x01;
+		entry->data[entry->length++] = 0x00; // size
+		entry->data[entry->length++] = 0x00;
+		entry->data[entry->length++] = 0x12; // REVERSE
+		entry->data[entry->length++] = 0x22; // QUOTE
+		for(i=0; i<strlen(entr->name); i++){
+			entry->data[entry->length++] = entr->name[i]; // name
+		}
+		for(; i<16; i++){
+			entry->data[entry->length++] = 0x20; // SPACE
+		}
+		entry->data[entry->length++] = 0x22; // QUOTE
+		entry->data[entry->length++] = 0x20; // SPACE
+		for(i=0; i<5; i++){
+			entry->data[entry->length++] = entr->id[i]; // name
+		}
+		entry->data[entry->length++] = 0x00; // END OF LINE
+		
+		for(entr = entries->next; entr != NULL; entr = entr->next){
+			char *type = entr->type == 'd' ? txt_del : txt_prg;
+			int size = (entr->length + 253) / 254;
+			
+			// entry
+			entry->data[entry->length++] = 0x01; // next ptr
+			entry->data[entry->length++] = 0x01;
+			entry->data[entry->length++] = size; // size
+			entry->data[entry->length++] = size >> 8;
+			
+			// convert size -> 4-strlen("size")
+			if(size < 10){
+				size = 3;
+			}else if(size < 100){
+				size = 2;
+			}else{
+				size = 1;
+			}
+			
+			for(i=0; i<size; i++){
+				entry->data[entry->length++] = 0x20; // SPACE
+			}
+			
+			entry->data[entry->length++] = 0x22; // QUOTE
+			for(i=0; i<strlen(entr->name); i++){
+				entry->data[entry->length++] = entr->name[i]; // name
+			}
+			entry->data[entry->length++] = 0x22; // QUOTE
+			for(; i<17; i++){
+				entry->data[entry->length++] = 0x20; // SPACE
+			}
+			for(i=0; i<3; i++){
+				entry->data[entry->length++] = type[i]; // type (PRG/DEL)
+			}
+			entry->data[entry->length++] = 0x00; // END OF LINE
+			
+		}
+		
+		// last line
+		entry->data[entry->length++] = 0x01; // next ptr
+		entry->data[entry->length++] = 0x01;
+		entry->data[entry->length++] = blocksfree; // size
+		entry->data[entry->length++] = blocksfree >> 8;
+		for(i=0; i<strlen(txt_blocks_free); i++){
+			entry->data[entry->length++] = txt_blocks_free[i]; // name
+		}
+		entry->data[entry->length++] = 0x00; // END OF LINE
+		
+		// end of file		
+		entry->data[entry->length++] = 0x00; // END OF FILE
+		entry->data[entry->length++] = 0x00;
+		
+		// search last entry, add
+		for(entr = entries; entr->next != NULL; entr = entr->next);
+		entr->next = entry;
+		
+	}
+	
+	
+	
+	
+	/*if(build == build_list || verbose){
+		char quotename[19];
+		int num;
+		
+		printf("      | 0 \"%-16s\" %s |\n", entries->name, entries->id);
+		
+		for(num=1, entr = entries->next; nolisting ? (entr != NULL) : (entr->next != NULL); num++, entr = entr->next){
+			if(entr->type == '*' || (entr->type != 'p' && nolisting)){
+				continue;
+			}
+			
+			//		printf("%c:%s:%d\n", entr->type, entr->name, entr->length);
+			
+			sprintf(quotename, "\"%s\"", entr->name);
+			
+			// Print directory entry 
+			printf("%4d  | %-4d  %-18s %s |  %5d Bytes%s\n", num, (entr->length+253)/254, quotename, entr->type == 'd' ? "DEL" : "PRG", entr->length, entr->type == 'q' ? ", not in flash, only in listing" : "");
+			
+		}
+		
+		if(build != build_list && entr != NULL){
+			// the listing
+			printf("      |       The Listing (\"$\")      |  %5d Bytes\n", entr->length);
+		}
+		
+	}*/
+	
+	if(build != build_list){
+		
+		/*out = fopen("test.crt", "wb");
+		if(!out){
+			fprintf(stderr, "unable to open \"%s\" for output", argv[1]);
+			exit(1);
+		}*/
+		
+		memcpy(CartHeader.signature, cart_singnature, 16);
+		CartHeader.headerLen[0] = 0x00;
+		CartHeader.headerLen[1] = 0x00;
+		CartHeader.headerLen[2] = 0x00;
+		CartHeader.headerLen[3] = 0x40;
+		CartHeader.version[0] = 0x01;
+		CartHeader.version[1] = 0x00;
+		if(build == build_xbank){
+			CartHeader.type[0] = CART_TYPE_EASYFLASH_XBANK >> 8;
+			CartHeader.type[1] = CART_TYPE_EASYFLASH_XBANK & 0xff;
+			CartHeader.exromLine = (mode == mode_hi) ? 1 : 0;
+			CartHeader.gameLine = (mode == mode_hi) ? 0 : ((mode == mode_lo) ? 1 : 0);
+		}else{
+			CartHeader.type[0] = CART_TYPE_EASYFLASH >> 8;
+			CartHeader.type[1] = CART_TYPE_EASYFLASH & 0xff;
+			CartHeader.exromLine = 1;
+			CartHeader.gameLine = 0;
+		}
+		CartHeader.reserved[0] = 0;
+		CartHeader.reserved[1] = 0;
+		CartHeader.reserved[2] = 0;
+		CartHeader.reserved[3] = 0;
+		CartHeader.reserved[4] = 0;
+		CartHeader.reserved[5] = 0;
+		memset(CartHeader.name, 0, 32);
+		
+//		strncpy(CartHeader.name, basename(argv[0]), 32);
+		strncpy(CartHeader.name, "D2EF", 32);
+		
+		//fwrite(&CartHeader, 1, sizeof(CartHeader), out);
+		memcpy( out, &CartHeader, sizeof(CartHeader) );
+		out += sizeof(CartHeader);
+		
+		if(build == build_crt){
+			char buffer[0x2000];
+			BankHeader BankHeader;
+			
+			memset(buffer, 0xff, 0x2000);
+			memcpy(buffer+0x1800, sprites, sprites_size);
+			memcpy(buffer+0x1e00, startup, startup_size);
+			buffer[0x2000-startup_size+0] = 1; // BANK
+			switch(mode){
+				case mode_nm:
+					buffer[0x2000-startup_size+1] = 7; // MODE
+					break;
+				case mode_lo:
+					buffer[0x2000-startup_size+1] = 6; // MODE
+					break;
+				case mode_hi:
+					buffer[0x2000-startup_size+1] = 5; // MODE
+					break;
+			}
+			// setup commons	
+			memcpy(BankHeader.signature, chip_singnature, 4);
+			BankHeader.packetLen[0] = 0x00;
+			BankHeader.packetLen[1] = 0x00;
+			BankHeader.packetLen[2] = 0x20;
+			BankHeader.packetLen[3] = 0x10;
+			BankHeader.chipType[0] = 0x00;
+			BankHeader.chipType[1] = 0x00;
+			BankHeader.bank[0] = 0x00;
+			BankHeader.bank[1] = 0x00;
+			BankHeader.loadAddr[0] = 0xa0;
+			BankHeader.loadAddr[1] = 0x00;
+			BankHeader.romLen[0] = 0x20;
+			BankHeader.romLen[1] = 0x00;
+			
+			//fwrite(&BankHeader, 1, sizeof(BankHeader), out);
+			memcpy( out, &BankHeader, sizeof(BankHeader) );
+			out += sizeof(BankHeader);
+			
+			//fwrite(buffer, 1, 0x2000, out);
+			memcpy( out, buffer, 0x2000 );
+			out += 0x2000;
+		}
+		
+		switch(mode){
+			case mode_nm:
+				if ( autostart )
+					bundle(&out, entries, 0x4000, 0x8000, 14, kapi_nm_auto, kapi_nm_size_auto, NULL, 0, build == build_xbank ? 0 : 1); else
+					bundle(&out, entries, 0x4000, 0x8000, 14, kapi_nm, kapi_nm_size, NULL, 0, build == build_xbank ? 0 : 1);
+				break;
+			case mode_lo:
+				if ( autostart )
+					bundle(&out, entries, 0x2000, 0x8000, 13, kapi_lo_auto, kapi_lo_size_auto, NULL, 0, build == build_xbank ? 0 : 1); else
+					bundle(&out, entries, 0x2000, 0x8000, 13, kapi_lo, kapi_lo_size, NULL, 0, build == build_xbank ? 0 : 1);
+				break;
+			case mode_hi:
+				if ( autostart )
+					bundle(&out, entries, 0x2000, 0xa000, 13, kapi_hi_auto, kapi_hi_size_auto, launcher_hi, launcher_hi_size_auto, build == build_xbank ? 0 : 1); else
+					bundle(&out, entries, 0x2000, 0xa000, 13, kapi_hi, kapi_hi_size, launcher_hi, launcher_hi_size, build == build_xbank ? 0 : 1);
+				break;
+		}
+		
+	}
+
+	return out-cart;
+}
+
+/*
+int main(int argc, char** argv)
+{
+	FILE *f = fopen( "test.d64", "rb" );
+	fseek( f, 0, SEEK_END );
+	imageSize = ftell( f );
+	fseek( f, 0, SEEK_SET );
+	fread( diskimage, 1, imageSize, f );
+	fclose( f );
+
+	int crtSize = createD2EF( diskimage, imageSize, cart, build_crt, mode_nm, 1 );
+
+	f = fopen("test.crt", "wb");
+	fwrite( cart, 1, crtSize, f );
+	fclose( f );
+
+	exit(0);
+}
+*/
\ No newline at end of file
diff --git a/D2EF/diskimage.cpp b/D2EF/diskimage.cpp
new file mode 100644
index 00000000..a51c171c
--- /dev/null
+++ b/D2EF/diskimage.cpp
@@ -0,0 +1,1337 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "diskimage.h"
+
+
+typedef struct errormessage {
+  signed int number;
+  char *string;
+} ErrorMessage;
+
+
+ErrorMessage error_msg[] = {
+  /* non-errors */
+  { 0, "ok" },
+  { 1, "files scratched" },
+  { 2, "partition selected" },
+  /* errors */
+  { 20, "read error (block header not found)" },
+  { 21, "read error (drive not ready)" },
+  { 22, "read error (data block not found)" },
+  { 23, "read error (crc error in data block)" },
+  { 24, "read error (byte sector header)" },
+  { 25, "write error (write-verify error)" },
+  { 26, "write protect on" },
+  { 27, "read error (crc error in header)" },
+  { 30, "syntax error (general syntax)" },
+  { 31, "syntax error (invalid command)" },
+  { 32, "syntax error (long line)" },
+  { 33, "syntax error (invalid file name)" },
+  { 34, "syntax error (no file given)" },
+  { 39, "syntax error (invalid command)" },
+  { 50, "record not present" },
+  { 51, "overflow in record" },
+  { 52, "file too large" },
+  { 60, "write file open" },
+  { 61, "file not open" },
+  { 62, "file not found" },
+  { 63, "file exists" },
+  { 64, "file type mismatch" },
+  { 65, "no block" },
+  { 66, "illegal track and sector" },
+  { 67, "illegal system t or s" },
+  { 70, "no channel" },
+  { 71, "directory error" },
+  { 72, "disk full" },
+  { 73, "dos mismatch" },
+  { 74, "drive not ready" },
+  { 75, "format error" },
+  { 76, "controller error" },
+  { 77, "selected partition illegal" },
+  { -1, NULL }
+};
+
+
+/* convert to rawname */
+int di_rawname_from_name(unsigned char *rawname, char *name) {
+  int i;
+
+  memset(rawname, 0xa0, 16);
+  for (i = 0; i < 16 && name[i]; ++i) {
+    rawname[i] = name[i];
+  }
+  return(i);
+}
+
+
+/* convert from rawname */
+int di_name_from_rawname(char *name, unsigned char *rawname) {
+  int i;
+
+  for (i = 0; i < 16 && rawname[i] != 0xa0; ++i) {
+    name[i] = rawname[i];
+  }
+  name[i] = 0;
+  return(i);
+}
+
+
+/* return status string */
+int di_status(DiskImage *di, char *status) {
+  ErrorMessage *err = error_msg;
+
+  /* special case for power up */
+  if (di->status == 254) {
+    switch (di->type) {
+    case D64:
+      sprintf(status, "73,cbm dos v2.6 1541,00,00");
+      break;
+    case D71:
+      sprintf(status, "73,cbm dos v3.0 1571,00,00");
+      break;
+    case D81:
+      sprintf(status, "73,copyright cbm dos v10 1581,00,00");
+      break;
+    }
+    return(73);
+  }
+
+  while (err->number >= 0) {
+    if (di->status == err->number) {
+      sprintf(status, "%02d,%s,%02d,%02d", di->status, err->string, di->statusts.track, di->statusts.sector);
+      return(di->status);
+    }
+    err->number++;
+  }
+  sprintf(status, "%02d,unknown error,%02d,%02d", di->status, di->statusts.track, di->statusts.sector);
+  return(di->status);
+}
+
+
+int set_status(DiskImage *di, int status, int track, int sector) {
+  di->status = status;
+  di->statusts.track = track;
+  di->statusts.sector = sector;
+  return(status);
+}
+
+
+/* return write interleave */
+int interleave(ImageType type) {
+  switch (type) {
+  case D64:
+    return(10);
+    break;
+  case D71:
+    return(6);
+    break;
+  default:
+    return(1);
+    break;
+  }
+}
+
+
+/* return number of tracks for image type */
+int di_tracks(ImageType type) {
+  switch (type) {
+  case D64:
+    return(35);
+    break;
+  case D71:
+    return(70);
+    break;
+  case D81:
+    return(80);
+    break;
+  }
+  return(0);
+}
+
+
+/* return disk geometry for track */
+int di_sectors_per_track(ImageType type, int track) {
+  switch (type) {
+  case D71:
+    if (track > 35) {
+      track -= 35;
+    }
+    // fall through
+  case D64:
+    if (track < 18) {
+      return(21);
+    } else if (track < 25) {
+      return(19);
+    } else if (track < 31) {
+      return(18);
+    } else {
+      return(17);
+    }
+    break;
+  case D81:
+    return(40);
+    break;
+  }
+  return(0);
+}
+
+/* convert track, sector to blocknum */
+int get_block_num(ImageType type, TrackSector ts) {
+  int block;
+
+  switch (type) {
+  case D64:
+    if (ts.track < 18) {
+      block = (ts.track - 1) * 21;
+    } else if (ts.track < 25) {
+      block = (ts.track - 18) * 19 + 17 * 21;
+    } else if (ts.track < 31) {
+      block = (ts.track - 25) * 18 + 17 * 21 + 7 * 19;
+    } else {
+      block = (ts.track - 31) * 17 + 17 * 21 + 7 * 19 + 6 * 18;
+    }
+    return(block + ts.sector);
+    break;
+  case D71:
+    if (ts.track > 35) {
+      block = 683;
+      ts.track -= 35;
+    } else {
+      block = 0;
+    }
+    if (ts.track < 18) {
+      block += (ts.track - 1) * 21;
+    } else if (ts.track < 25) {
+      block += (ts.track - 18) * 19 + 17 * 21;
+    } else if (ts.track < 31) {
+      block += (ts.track - 25) * 18 + 17 * 21 + 7 * 19;
+    } else {
+      block += (ts.track - 31) * 17 + 17 * 21 + 7 * 19 + 6 * 18;
+    }
+    return(block + ts.sector);
+    break;
+  case D81:
+    return((ts.track - 1) * 40 + ts.sector);
+    break;
+  }
+  return(0);
+}
+
+
+/* get a pointer to block data */
+unsigned char *get_ts_addr(DiskImage *di, TrackSector ts) {
+  return(di->image + get_block_num(di->type, ts) * 256);
+}
+
+
+/* return a pointer to the next block in the chain */
+TrackSector next_ts_in_chain(DiskImage *di, TrackSector ts) {
+  unsigned char *p;
+  TrackSector newts;
+
+  p = get_ts_addr(di, ts);
+  newts.track = p[0];
+  newts.sector = p[1];
+  if (p[0] > di_tracks(di->type)) {
+    newts.track = 0;
+    newts.sector = 0;
+  } else if (p[1] > di_sectors_per_track(di->type, p[0])) {
+    newts.track = 0;
+    newts.sector = 0;
+  }
+  return(newts);
+}
+
+
+/* return a pointer to the disk title */
+unsigned char *di_title(DiskImage *di) {
+  switch (di->type) {
+  default:
+  case D64:
+  case D71:
+    return(get_ts_addr(di, di->dir) + 144);
+    break;
+  case D81:
+    return(get_ts_addr(di, di->dir) + 4);
+    break;
+  }
+}
+
+
+/* return number of free blocks in track */
+int di_track_blocks_free(DiskImage *di, int track) {
+  unsigned char *bam;
+
+  switch (di->type) {
+  default:
+  case D64:
+    bam = get_ts_addr(di, di->bam);
+    break;
+  case D71:
+    bam = get_ts_addr(di, di->bam);
+    if (track >= 36) {
+      return(bam[track + 185]);
+    }
+    break;
+  case D81:
+    if (track <= 40) {
+      bam = get_ts_addr(di, di->bam);
+    } else {
+      bam = get_ts_addr(di, di->bam2);
+      track -= 40;
+    }
+    return(bam[track * 6 + 10]);
+    break;
+  }
+  return(bam[track * 4]);
+}
+
+
+/* count number of free blocks */
+int blocks_free(DiskImage *di) {
+  int track;
+  int blocks = 0;
+
+  for (track = 1; track <= di_tracks(di->type); ++track) {
+    if (track != di->dir.track) {
+      blocks += di_track_blocks_free(di, track);
+    }
+  }
+  return(blocks);
+}
+
+
+/* check if track, sector is free in BAM */
+int di_is_ts_free(DiskImage *di, TrackSector ts) {
+  unsigned char mask;
+  unsigned char *bam;
+
+  switch (di->type) {
+  case D64:
+    bam = get_ts_addr(di, di->bam);
+    if (bam[ts.track * 4]) {
+      mask = 1<<(ts.sector & 7);
+      return(bam[ts.track * 4 + ts.sector / 8 + 1] & mask ? 1 : 0);
+    } else {
+      return(0);
+    }
+    break;
+  case D71:
+    mask = 1<<(ts.sector & 7);
+    if (ts.track < 36) {
+      bam = get_ts_addr(di, di->bam);
+      return(bam[ts.track * 4 + ts.sector / 8 + 1] & mask ? 1 : 0);
+    } else {
+      bam = get_ts_addr(di, di->bam2);
+      return(bam[(ts.track - 35) * 3 + ts.sector / 8 - 3] & mask ? 1 : 0);
+    }
+    break;
+  case D81:
+    mask = 1<<(ts.sector & 7);
+    if (ts.track < 41) {
+      bam = get_ts_addr(di, di->bam);
+    } else {
+      bam = get_ts_addr(di, di->bam2);
+      ts.track -= 40;
+    }
+    return(bam[ts.track * 6 + ts.sector / 8 + 11] & mask ? 1 : 0);
+    break;
+  }
+  return(0);
+}
+
+
+/* allocate track, sector in BAM */
+void di_alloc_ts(DiskImage *di, TrackSector ts) {
+  unsigned char mask;
+  unsigned char *bam;
+
+  di->modified = 1;
+  switch (di->type) {
+  case D64:
+    bam = get_ts_addr(di, di->bam);
+    bam[ts.track * 4] -= 1;
+    mask = 1<<(ts.sector & 7);
+    bam[ts.track * 4 + ts.sector / 8 + 1] &= ~mask;
+    break;
+  case D71:
+    mask = 1<<(ts.sector & 7);
+    if (ts.track < 36) {
+      bam = get_ts_addr(di, di->bam);
+      bam[ts.track * 4] -= 1;
+      bam[ts.track * 4 + ts.sector / 8 + 1] &= ~mask;
+    } else {
+      bam = get_ts_addr(di, di->bam);
+      bam[ts.track + 185] -= 1;
+      bam = get_ts_addr(di, di->bam2);
+      bam[(ts.track - 35) * 3 + ts.sector / 8 - 3] &= ~mask;
+    }
+    break;
+  case D81:
+    if (ts.track < 41) {
+      bam = get_ts_addr(di, di->bam);
+    } else {
+      bam = get_ts_addr(di, di->bam2);
+      ts.track -= 40;
+    }
+    bam[ts.track * 6 + 10] -= 1;
+    mask = 1<<(ts.sector & 7);
+    bam[ts.track * 6 + ts.sector / 8 + 11] &= ~mask;
+    break;
+  }
+}
+
+
+/* allocate next available block */
+TrackSector alloc_next_ts(DiskImage *di, TrackSector prevts) {
+  unsigned char *bam;
+  int spt, s1, s2, t1, t2, bpt, boff, res1, res2;
+  TrackSector ts;
+
+  switch (di->type) {
+  default:
+  case D64:
+    s1 = 1;
+    t1 = 35;
+    s2 = 1;
+    t2 = 35;
+    res1 = 18;
+    res2 = 0;
+    bpt = 4;
+    boff = 0;
+    break;
+  case D71:
+    s1 = 1;
+    t1 = 35;
+    s2 = 36;
+    t2 = 70;
+    res1 = 18;
+    res2 = 53;
+    bpt = 4;
+    boff = 0;
+    break;
+  case D81:
+    s1 = 1;
+    t1 = 40;
+    s2 = 41;
+    t2 = 80;
+    res1 = 40;
+    res2 = 0;
+    bpt = 6;
+    boff = 10;
+    break;
+  }
+
+  bam = get_ts_addr(di, di->bam);
+  for (ts.track = s1; ts.track <= t1; ++ts.track) {
+    if (ts.track != res1) {
+      if  (bam[ts.track * bpt + boff]) {
+	spt = di_sectors_per_track(di->type, ts.track);
+	ts.sector = (prevts.sector + interleave(di->type)) % spt;
+	for (; ; ts.sector = (ts.sector + 1) % spt) {
+	  if (di_is_ts_free(di, ts)) {
+	    di_alloc_ts(di, ts);
+	    return(ts);
+	  }
+	}
+      }
+    }
+  }
+
+  if (di->type == D71 || di->type == D81) {
+    bam = get_ts_addr(di, di->bam2);
+    for (ts.track = s2; ts.track <= t2; ++ts.track) {
+      if (ts.track != res2) {
+	if  (bam[(ts.track - t1) * bpt + boff]) {
+	  spt = di_sectors_per_track(di->type, ts.track);
+	  ts.sector = (prevts.sector + interleave(di->type)) % spt;
+	  for (; ; ts.sector = (ts.sector + 1) % spt) {
+	    if (di_is_ts_free(di, ts)) {
+	      di_alloc_ts(di, ts);
+	      return(ts);
+	    }
+	  }
+	}
+      }
+    }
+  }
+
+  ts.track = 0;
+  ts.sector = 0;
+  return(ts);
+}
+
+
+/* allocate next available directory block */
+TrackSector alloc_next_dir_ts(DiskImage *di) {
+  unsigned char *p;
+  int spt;
+  TrackSector ts, lastts;
+
+  if (di_track_blocks_free(di, di->bam.track)) {
+    ts.track = di->bam.track;
+    ts.sector = 0;
+    while (ts.track) {
+      lastts = ts;
+      ts = next_ts_in_chain(di, ts);
+    }
+    ts.track = lastts.track;
+    ts.sector = lastts.sector + 3;
+    spt = di_sectors_per_track(di->type, ts.track);
+    for (; ; ts.sector = (ts.sector + 1) % spt) {
+      if (di_is_ts_free(di, ts)) {
+	di_alloc_ts(di, ts);
+	p = get_ts_addr(di, lastts);
+	p[0] = ts.track;
+	p[1] = ts.sector;
+	p = get_ts_addr(di, ts);
+	memset(p, 0, 256);
+	p[1] = 0xff;
+	di->modified = 1;
+	return(ts);
+      }
+    }
+  } else {
+    ts.track = 0;
+    ts.sector = 0;
+    return(ts);
+  }
+}
+
+
+/* free a block in the BAM */
+void di_free_ts(DiskImage *di, TrackSector ts) {
+  unsigned char mask;
+  unsigned char *bam;
+
+  di->modified = 1;
+  switch (di->type) {
+  case D64:
+    mask = 1<<(ts.sector & 7);
+    bam = get_ts_addr(di, di->bam);
+    bam[ts.track * 4 + ts.sector / 8 + 1] |= mask;
+    bam[ts.track * 4] += 1;
+    break;
+  case D71:
+    mask = 1<<(ts.sector & 7);
+    if (ts.track < 36) {
+      bam = get_ts_addr(di, di->bam);
+      bam[ts.track * 4 + ts.sector / 8 + 1] |= mask;
+      bam[ts.track * 4] += 1;
+    } else {
+      bam = get_ts_addr(di, di->bam);
+      bam[ts.track + 185] += 1;
+      bam = get_ts_addr(di, di->bam2);
+      bam[(ts.track - 35) * 3 + ts.sector / 8 - 3] |= mask;
+    }
+    break;
+  case D81:
+    if (ts.track < 41) {
+      bam = get_ts_addr(di, di->bam);
+    } else {
+      bam = get_ts_addr(di, di->bam2);
+      ts.track -= 40;
+    }
+    mask = 1<<(ts.sector & 7);
+    bam[ts.track * 6 + ts.sector / 8 + 11] |= mask;
+    bam[ts.track * 6 + 10] += 1;
+    break;
+  default:
+    break;
+  }
+}
+
+
+/* free a chain of blocks */
+void free_chain(DiskImage *di, TrackSector ts) {
+  while (ts.track) {
+    di_free_ts(di, ts);
+    ts = next_ts_in_chain(di, ts);
+  }
+}
+
+
+//DiskImage *di_load_image(char *name) {
+DiskImage *di_load_image(unsigned char *image, int imageSize) {
+  //FILE *file;
+  int filesize, l, read;
+  DiskImage *di;
+
+  /* open image */
+/*  if ((file = fopen(name, "rb")) == NULL) {
+    //puts("fopen failed");
+    return(NULL);
+  }*/
+
+  /* get file size*/
+  /*if (fseek(file, 0, SEEK_END)) {
+    //puts("fseek failed");
+    fclose(file);
+    return(NULL);
+  }
+  filesize = ftell(file);
+  fseek(file, 0, SEEK_SET);*/
+  filesize = imageSize;
+
+  if ((di = (DiskImage*)malloc(sizeof(*di))) == NULL) {
+    //puts("malloc failed");
+    //fclose(file);
+    return(NULL);
+  }
+
+  /* check image type */
+  switch (filesize) {
+  case 174848: // standard D64
+  case 175531: // D64 with error info (which we just ignore)
+    di->type = D64;
+    di->bam.track = 18;
+    di->bam.sector = 0;
+    di->dir = di->bam;
+    break;
+  case 349696:
+    di->type = D71;
+    di->bam.track = 18;
+    di->bam.sector = 0;
+    di->bam2.track = 53;
+    di->bam2.sector = 0;
+    di->dir = di->bam;
+    break;
+  case 819200:
+    di->type = D81;
+    di->bam.track = 40;
+    di->bam.sector = 1;
+    di->bam2.track = 40;
+    di->bam2.sector = 2;
+    di->dir.track = 40;
+    di->dir.sector = 0;
+    break;
+  default:
+    //puts("unknown type");
+    free(di);
+    //fclose(file);
+    return(NULL);
+  }
+
+  di->size = filesize;
+
+  /* allocate buffer for image */
+  if ((di->image = (unsigned char*)malloc(filesize)) == NULL) {
+    //puts("image malloc failed");
+    free(di);
+    //fclose(file);
+    return(NULL);
+  }
+
+  /* read file into buffer */
+/*  read = 0;
+  while (read < filesize) {
+    if ((l = fread(di->image, 1, filesize - read, file))) {
+      read += l;
+    } else {
+      //puts("fread failed");
+      free(di->image);
+      free(di);
+      fclose(file);
+      return(NULL);
+    }
+  }*/
+  memcpy( di->image, image, filesize );
+
+//  di->filename = malloc(strlen(name) + 1);
+//  strcpy(di->filename, name);
+  di->filename = (char*)malloc(5);
+  strcpy(di->filename, "D2EF");
+  di->openfiles = 0;
+  di->blocksfree = blocks_free(di);
+  di->modified = 0;
+  //fclose(file);
+  set_status(di, 254, 0, 0);
+  return(di);
+}
+
+
+DiskImage *di_create_image(char *name, int size) {
+  DiskImage *di;
+
+  if ((di = (DiskImage*)malloc(sizeof(*di))) == NULL) {
+    //puts("malloc failed");
+    return(NULL);
+  }
+
+  /* check image type */
+  switch (size) {
+  case 174848: // standard D64
+  case 175531: // D64 with error info (which we just ignore)
+    di->type = D64;
+    di->bam.track = 18;
+    di->bam.sector = 0;
+    di->dir = di->bam;
+    break;
+  case 349696:
+    di->type = D71;
+    di->bam.track = 18;
+    di->bam.sector = 0;
+    di->bam2.track = 53;
+    di->bam2.sector = 0;
+    di->dir = di->bam;
+    break;
+  case 819200:
+    di->type = D81;
+    di->bam.track = 40;
+    di->bam.sector = 1;
+    di->bam2.track = 40;
+    di->bam2.sector = 2;
+    di->dir.track = 40;
+    di->dir.sector = 0;
+    break;
+  default:
+    //puts("unknown type");
+    free(di);
+    return(NULL);
+  }
+
+  di->size = size;
+
+  /* allocate buffer for image */
+  if ((di->image = (unsigned char*)malloc(size)) == NULL) {
+    //puts("image malloc failed");
+    free(di);
+    return(NULL);
+  }
+  memset(di->image, 0, size);
+
+  di->filename = (char*)malloc(strlen(name) + 1);
+  strcpy(di->filename, name);
+  di->openfiles = 0;
+  di->blocksfree = blocks_free(di);
+  di->modified = 1;
+  set_status(di, 254, 0, 0);
+  return(di);
+}
+
+
+void di_sync(DiskImage *di) {
+/*  FILE *file;
+  int l, left;
+  unsigned char *image;
+
+  if ((file = fopen(di->filename, "wb"))) {
+    image = di->image;
+    left = di->size;
+    l = 0;
+    while (left) {
+      if ((l = fwrite(image, 1, left, file)) == 0) {
+	fclose(file);
+	return;
+      }
+      left -= l;
+      image += l;
+    }
+    fclose(file);
+    di->modified = 0;
+  }*/
+}
+
+
+void di_free_image(DiskImage *di) {
+  if (di->modified) {
+    di_sync(di);
+  }
+  if (di->filename) {
+    free(di->filename);
+  }
+  free(di->image);
+  free(di);
+}
+
+
+int match_pattern(unsigned char *rawpattern, unsigned char *rawname) {
+  int i;
+
+  for (i = 0; i < 16; ++i) {
+    if (rawpattern[i] == '*') {
+      return(1);
+    }
+    if (rawname[i] == 0xa0) {
+      if (rawpattern[i] == 0xa0) {
+	return(1);
+      } else {
+	return(0);
+      }
+    } else {
+      if (rawpattern[i] == '?' || rawpattern[i] == rawname[i]) {
+      } else {
+	return(0);
+      }
+    }
+  }
+  return(1);
+}
+
+
+RawDirEntry *find_file_entry(DiskImage *di, unsigned char *rawpattern, FileType type) {
+  unsigned char *buffer;
+  TrackSector ts;
+  RawDirEntry *rde;
+  int offset;
+
+  ts = next_ts_in_chain(di, di->bam);
+  while (ts.track) {
+    buffer = get_ts_addr(di, ts);
+    for (offset = 0; offset < 256; offset += 32) {
+      rde = (RawDirEntry *)(buffer + offset);
+      if ((rde->type & ~0x40) == (type | 0x80)) {
+	if (match_pattern(rawpattern, rde->rawname)) {
+	  return(rde);
+	}
+      }
+    }
+    ts = next_ts_in_chain(di, ts);
+  }
+  return(NULL);
+}
+
+
+RawDirEntry *alloc_file_entry(DiskImage *di, unsigned char *rawname, FileType type) {
+  unsigned char *buffer;
+  TrackSector ts, lastts;
+  RawDirEntry *rde;
+  int offset;
+
+  /* check if file already exists */
+  ts = next_ts_in_chain(di, di->bam);
+  while (ts.track) {
+    buffer = get_ts_addr(di, ts);
+    for (offset = 0; offset < 256; offset += 32) {
+      rde = (RawDirEntry *)(buffer + offset);
+      if (rde->type) {
+	if (strncmp((const char*)rawname, (const char*)rde->rawname, 16) == 0) {
+	  set_status(di, 63, 0, 0);
+	  //puts("file exists");
+	  return(NULL);
+	}
+      }
+    }
+    ts = next_ts_in_chain(di, ts);
+  }
+
+  /* allocate empty slot */
+  ts = next_ts_in_chain(di, di->bam);
+  while (ts.track) {
+    buffer = get_ts_addr(di, ts);
+    for (offset = 0; offset < 256; offset += 32) {
+      rde = (RawDirEntry *)(buffer + offset);
+      if (rde->type == 0) {
+	memset((unsigned char *)rde + 2, 0, 30);
+	memcpy(rde->rawname, rawname, 16);
+	rde->type = type;
+	di->modified = 1;
+	return(rde);
+      }
+    }
+    lastts = ts;
+    ts = next_ts_in_chain(di, ts);
+  }
+
+  /* allocate new dir block */
+  ts = alloc_next_dir_ts(di);
+  if (ts.track) {
+    rde = (RawDirEntry *)get_ts_addr(di, ts);
+    memset((unsigned char *)rde + 2, 0, 30);
+    memcpy(rde->rawname, rawname, 16);
+    rde->type = type;
+    di->modified = 1;
+    return(rde);
+  } else {
+    set_status(di, 72, 0, 0);
+    //puts("directory full");
+    return(NULL);
+  }
+}
+
+
+/* open a file */
+ImageFile *di_open(DiskImage *di, unsigned char *rawname, FileType type, char *mode) {
+  ImageFile *imgfile;
+  RawDirEntry *rde;
+  unsigned char *p;
+
+  set_status(di, 255, 0, 0);
+
+  if (strcmp("rb", mode) == 0) {
+
+    if ((imgfile = (ImageFile*)malloc(sizeof(*imgfile))) == NULL) {
+      //puts("malloc failed");
+      return(NULL);
+    }
+    if (strcmp("$", (const char*)rawname) == 0) {
+      imgfile->mode = 'r';
+      imgfile->ts = di->dir;
+      p = get_ts_addr(di, di->dir);
+      imgfile->buffer = p + 2;
+      if ((di->type == D64) || (di->type == D71)) {
+	imgfile->nextts.track = 18; // 1541/71 ignores bam t/s link
+	imgfile->nextts.sector = 1;
+      } else {
+	imgfile->nextts.track = p[0];
+	imgfile->nextts.sector = p[1];
+      }
+      imgfile->buflen = 254;
+      rde = NULL;
+    } else {
+      if ((rde = find_file_entry(di, rawname, type)) == NULL) {
+	set_status(di, 62, 0, 0);
+	//puts("find_file_entry failed");
+	free(imgfile);
+	return(NULL);
+      }
+      imgfile->mode = 'r';
+      imgfile->ts = rde->startts;
+      if (imgfile->ts.track > di_tracks(di->type)) {
+	return(NULL);
+      }
+      p = get_ts_addr(di, rde->startts);
+      imgfile->buffer = p + 2;
+      imgfile->nextts.track = p[0];
+      imgfile->nextts.sector = p[1];
+      if (imgfile->nextts.track == 0) {
+	imgfile->buflen = imgfile->nextts.sector - 1;
+      } else {
+	imgfile->buflen = 254;
+      }
+    }
+
+  } else if (strcmp("wb", mode) == 0) {
+
+    if ((rde = alloc_file_entry(di, rawname, type)) == NULL) {
+      //puts("alloc_file_entry failed");
+      return(NULL);
+    }
+    if ((imgfile = (ImageFile*)malloc(sizeof(*imgfile))) == NULL) {
+      //puts("malloc failed");
+      return(NULL);
+    }
+    imgfile->mode = 'w';
+    imgfile->ts.track = 0;
+    imgfile->ts.sector = 0;
+    if ((imgfile->buffer = (unsigned char*)malloc(254)) == NULL) {
+      free(imgfile);
+      //puts("malloc failed");
+      return(NULL);
+    }
+    imgfile->buflen = 254;
+    di->modified = 1;
+
+  } else {
+    return(NULL);
+  }
+
+  imgfile->diskimage = di;
+  imgfile->rawdirentry = rde;
+  imgfile->position = 0;
+  imgfile->bufptr = 0;
+
+  ++(di->openfiles);
+  set_status(di, 0, 0, 0);
+  return(imgfile);
+}
+
+
+int di_read(ImageFile *imgfile, unsigned char *buffer, int len) {
+  unsigned char *p;
+  int bytesleft;
+  int counter = 0;
+
+  while (len) {
+    bytesleft = imgfile->buflen - imgfile->bufptr;
+    if (bytesleft == 0) {
+      if (imgfile->nextts.track == 0) {
+	return(counter);
+      }
+      if (((imgfile->diskimage->type == D64) || (imgfile->diskimage->type == D71)) && imgfile->ts.track == 18 && imgfile->ts.sector == 0) {
+	imgfile->ts.track = 18;
+	imgfile->ts.sector = 1;
+      } else {
+	imgfile->ts = next_ts_in_chain(imgfile->diskimage, imgfile->ts);
+      }
+      if (imgfile->ts.track == 0) {
+	return(counter);
+      }
+      p = get_ts_addr(imgfile->diskimage, imgfile->ts);
+      imgfile->buffer = p + 2;
+      imgfile->nextts.track = p[0];
+      imgfile->nextts.sector = p[1];
+      if (imgfile->nextts.track == 0) {
+	imgfile->buflen = imgfile->nextts.sector - 1;
+      } else {
+	imgfile->buflen = 254;
+      }
+      imgfile->bufptr = 0;
+    } else {
+      if (len >= bytesleft) {
+	while (bytesleft) {
+	  *buffer++ = imgfile->buffer[imgfile->bufptr++];
+	  --len;
+	  --bytesleft;
+	  ++counter;
+	  ++(imgfile->position);
+	}
+      } else {
+	while (len) {
+	  *buffer++ = imgfile->buffer[imgfile->bufptr++];
+	  --len;
+	  --bytesleft;
+	  ++counter;
+	  ++(imgfile->position);
+	}
+      }
+    }
+  }
+  return(counter);
+}
+
+
+int di_write(ImageFile *imgfile, unsigned char *buffer, int len) {
+  unsigned char *p;
+  int bytesleft;
+  int counter = 0;
+
+  while (len) {
+    bytesleft = imgfile->buflen - imgfile->bufptr;
+    if (bytesleft == 0) {
+      if (imgfile->diskimage->blocksfree == 0) {
+	set_status(imgfile->diskimage, 72, 0, 0);
+	return(counter);
+      }
+      imgfile->nextts = alloc_next_ts(imgfile->diskimage, imgfile->ts);
+      if (imgfile->ts.track == 0) {
+	imgfile->rawdirentry->startts = imgfile->nextts;
+      } else {
+	p = get_ts_addr(imgfile->diskimage, imgfile->ts);
+	p[0] = imgfile->nextts.track;
+	p[1] = imgfile->nextts.sector;
+      }
+      imgfile->ts = imgfile->nextts;
+      p = get_ts_addr(imgfile->diskimage, imgfile->ts);
+      p[0] = 0;
+      p[1] = 0xff;
+      memcpy(p + 2, imgfile->buffer, 254);
+      imgfile->bufptr = 0;
+      if (++(imgfile->rawdirentry->sizelo) == 0) {
+	++(imgfile->rawdirentry->sizehi);
+      }
+      --(imgfile->diskimage->blocksfree);
+    } else {
+      if (len >= bytesleft) {
+	while (bytesleft) {
+	  imgfile->buffer[imgfile->bufptr++] = *buffer++;
+	  --len;
+	  --bytesleft;
+	  ++counter;
+	  ++(imgfile->position);
+	}
+      } else {
+	while (len) {
+	  imgfile->buffer[imgfile->bufptr++] = *buffer++;
+	  --len;
+	  --bytesleft;
+	  ++counter;
+	  ++(imgfile->position);
+	}
+      }
+    }
+  }
+  return(counter);
+}
+
+
+void di_close(ImageFile *imgfile) {
+  unsigned char *p;
+
+  if (imgfile->mode == 'w') {
+    if (imgfile->bufptr) {
+      if (imgfile->diskimage->blocksfree) {
+	imgfile->nextts = alloc_next_ts(imgfile->diskimage, imgfile->ts);
+	if (imgfile->ts.track == 0) {
+	  imgfile->rawdirentry->startts = imgfile->nextts;
+	} else {
+	  p = get_ts_addr(imgfile->diskimage, imgfile->ts);
+	  p[0] = imgfile->nextts.track;
+	  p[1] = imgfile->nextts.sector;
+	}
+	imgfile->ts = imgfile->nextts;
+	p = get_ts_addr(imgfile->diskimage, imgfile->ts);
+	p[0] = 0;
+	p[1] = 0xff;
+	memcpy(p + 2, imgfile->buffer, 254);
+	imgfile->bufptr = 0;
+	if (++(imgfile->rawdirentry->sizelo) == 0) {
+	  ++(imgfile->rawdirentry->sizehi);
+	}
+	--(imgfile->diskimage->blocksfree);
+	imgfile->rawdirentry->type |= 0x80;
+      }
+    } else {
+      imgfile->rawdirentry->type |= 0x80;
+    }
+    free(imgfile->buffer);
+  }
+  --(imgfile->diskimage->openfiles);
+  free(imgfile);
+}
+
+
+int di_format(DiskImage *di, unsigned char *rawname, unsigned char *rawid) {
+  unsigned char *p;
+  TrackSector ts;
+
+  di->modified = 1;
+
+  switch (di->type) {
+
+  case D64:
+    /* erase disk */
+    if (rawid) {
+      memset(di->image, 0, 174848);
+    }
+
+    /* get ptr to bam */
+    p = get_ts_addr(di, di->bam);
+
+    /* setup header */
+    p[0] = 18;
+    p[1] = 1;
+    p[2] = 'A';
+    p[3] = 0;
+
+    /* clear bam */
+    memset(p + 4, 0, 0x8c);
+
+    /* free blocks */
+    for (ts.track = 1; ts.track <= di_tracks(di->type); ++ts.track) {
+      for (ts.sector = 0; ts.sector < di_sectors_per_track(di->type, ts.track); ++ts.sector) {
+	di_free_ts(di, ts);
+      }
+    }
+
+    /* allocate bam and dir */
+    ts.track = 18;
+    ts.sector = 0;
+    di_alloc_ts(di, ts);
+    ts.sector = 1;
+    di_alloc_ts(di, ts);
+
+    /* copy name */
+    memcpy(p + 0x90, rawname, 16);
+
+    /* set id */
+    memset(p + 0xa0, 0xa0, 2);
+    if (rawid) {
+      memcpy(p + 0xa2, rawid, 2);
+    }
+    memset(p + 0xa4, 0xa0, 7);
+    p[0xa5] = '2';
+    p[0xa6] = 'A';
+
+    /* clear unused bytes */
+    memset(p + 0xab, 0, 0x55);
+
+    /* clear first dir block */
+    memset(p + 256, 0, 256);
+    p[257] = 0xff;
+    break;
+
+  case D71:
+    /* erase disk */
+    if (rawid) {
+      memset(di->image, 0, 349696);
+    }
+
+    /* get ptr to bam2 */
+    p = get_ts_addr(di, di->bam2);
+
+    /* clear bam2 */
+    memset(p, 0, 256);
+
+    /* get ptr to bam */
+    p = get_ts_addr(di, di->bam);
+
+    /* setup header */
+    p[0] = 18;
+    p[1] = 1;
+    p[2] = 'A';
+    p[3] = 0x80;
+
+    /* clear bam */
+    memset(p + 4, 0, 0x8c);
+
+    /* clear bam2 counters */
+    memset(p + 0xdd, 0, 0x23);
+
+    /* free blocks */
+    for (ts.track = 1; ts.track <= di_tracks(di->type); ++ts.track) {
+      if (ts.track != 53) {
+	for (ts.sector = 0; ts.sector < di_sectors_per_track(di->type, ts.track); ++ts.sector) {
+	  di_free_ts(di, ts);
+	}
+      }
+    }
+
+    /* allocate bam and dir */
+    ts.track = 18;
+    ts.sector = 0;
+    di_alloc_ts(di, ts);
+    ts.sector = 1;
+    di_alloc_ts(di, ts);
+
+    /* copy name */
+    memcpy(p + 0x90, rawname, 16);
+
+    /* set id */
+    memset(p + 0xa0, 0xa0, 2);
+    if (rawid) {
+      memcpy(p + 0xa2, rawid, 2);
+    }
+    memset(p + 0xa4, 0xa0, 7);
+    p[0xa5] = '2';
+    p[0xa6] = 'A';
+
+    /* clear unused bytes */
+    memset(p + 0xab, 0, 0x32);
+
+    /* clear first dir block */
+    memset(p + 256, 0, 256);
+    p[257] = 0xff;
+    break;
+
+  case D81:
+    /* erase disk */
+    if (rawid) {
+      memset(di->image, 0, 819200);
+    }
+
+    /* get ptr to bam */
+    p = get_ts_addr(di, di->bam);
+
+    /* setup header */
+    p[0] = 0x28;
+    p[1] = 0x02;
+    p[2] = 0x44;
+    p[3] = 0xbb;
+    p[6] = 0xc0;
+
+    /* set id */
+    if (rawid) {
+      memcpy(p + 4, rawid, 2);
+    }
+
+    /* clear bam */
+    memset(p + 7, 0, 0xfa);
+
+    /* get ptr to bam2 */
+    p = get_ts_addr(di, di->bam2);
+
+    /* setup header */
+    p[0] = 0x00;
+    p[1] = 0xff;
+    p[2] = 0x44;
+    p[3] = 0xbb;
+    p[6] = 0xc0;
+
+    /* set id */
+    if (rawid) {
+      memcpy(p + 4, rawid, 2);
+    }
+
+    /* clear bam2 */
+    memset(p + 7, 0, 0xfa);
+
+    /* free blocks */
+    for (ts.track = 1; ts.track <= di_tracks(di->type); ++ts.track) {
+      for (ts.sector = 0; ts.sector < di_sectors_per_track(di->type, ts.track); ++ts.sector) {
+	di_free_ts(di, ts);
+      }
+    }
+
+    /* allocate bam and dir */
+    ts.track = 40;
+    ts.sector = 0;
+    di_alloc_ts(di, ts);
+    ts.sector = 1;
+    di_alloc_ts(di, ts);
+    ts.sector = 2;
+    di_alloc_ts(di, ts);
+    ts.sector = 3;
+    di_alloc_ts(di, ts);
+
+    /* get ptr to dir */
+    p = get_ts_addr(di, di->dir);
+
+    /* copy name */
+    memcpy(p + 4, rawname, 16);
+
+    /* set id */
+    memset(p + 0x14, 0xa0, 2);
+    if (rawid) {
+      memcpy(p + 0x16, rawid, 2);
+    }
+    memset(p + 0x18, 0xa0, 5);
+    p[0x19] = '3';
+    p[0x1a] = 'D';
+
+    /* clear unused bytes */
+    memset(p + 0x1d, 0, 0xe3);
+
+    /* clear first dir block */
+    memset(p + 768, 0, 256);
+    p[769] = 0xff;
+    break;
+
+  }
+
+  di->blocksfree = blocks_free(di);
+
+  return(set_status(di, 0, 0, 0));
+}
+
+
+int di_delete(DiskImage *di, unsigned char *rawpattern, FileType type) {
+  RawDirEntry *rde;
+  int delcount = 0;
+
+  switch (type) {
+
+  case T_SEQ:
+  case T_PRG:
+  case T_USR:
+    while ((rde = find_file_entry(di, rawpattern, type))) {
+      free_chain(di, rde->startts);
+      rde->type = 0;
+      ++delcount;
+    }
+    if (delcount) {
+      return(set_status(di, 1, delcount, 0));
+    } else {
+      return(set_status(di, 62, 0, 0));
+    }
+    break;
+
+  default:
+    return(set_status(di, 64, 0, 0));
+    break;
+
+  }
+}
+
+
+int di_rename(DiskImage *di, unsigned char *oldrawname, unsigned char *newrawname, FileType type) {
+  RawDirEntry *rde;
+
+  if ((rde = find_file_entry(di, oldrawname, type))) {
+    memcpy(rde->rawname, newrawname, 16);
+    return(set_status(di, 0, 0, 0));
+  } else {
+    return(set_status(di, 62, 0, 0));
+  }
+}
diff --git a/D2EF/diskimage.h b/D2EF/diskimage.h
new file mode 100644
index 00000000..73c94d98
--- /dev/null
+++ b/D2EF/diskimage.h
@@ -0,0 +1,90 @@
+typedef enum imagetype {
+  D64 = 1,
+  D71,
+  D81
+} ImageType;
+
+typedef enum filetype {
+  T_DEL = 0,
+  T_SEQ,
+  T_PRG,
+  T_USR,
+  T_REL,
+  T_CBM,
+  T_DIR
+} FileType;
+
+typedef struct ts {
+  unsigned char track;
+  unsigned char sector;
+} TrackSector;
+
+typedef struct diskimage {
+  char *filename;
+  int size;
+  ImageType type;
+  unsigned char *image;
+  TrackSector bam;
+  TrackSector bam2;
+  TrackSector dir;
+  int openfiles;
+  int blocksfree;
+  int modified;
+  int status;
+  TrackSector statusts;
+} DiskImage;
+
+typedef struct rawdirentry {
+  TrackSector nextts;
+  unsigned char type;
+  TrackSector startts;
+  unsigned char rawname[16];
+  TrackSector relsidets;
+  unsigned char relrecsize;
+  unsigned char unused[4];
+  TrackSector replacetemp;
+  unsigned char sizelo;
+  unsigned char sizehi;
+} RawDirEntry;
+
+typedef struct imagefile {
+  DiskImage *diskimage;
+  RawDirEntry *rawdirentry;
+  char mode;
+  int position;
+  TrackSector ts;
+  TrackSector nextts;
+  unsigned char *buffer;
+  int bufptr;
+  int buflen;
+} ImageFile;
+
+
+//DiskImage *di_load_image(char *name);
+DiskImage *di_load_image(unsigned char *image, int imageSize);
+DiskImage *di_create_image(char *name, int size);
+void di_free_image(DiskImage *di);
+void di_sync(DiskImage *di);
+
+int di_status(DiskImage *di, char *status);
+
+ImageFile *di_open(DiskImage *di, unsigned char *rawname, FileType type, char *mode);
+void di_close(ImageFile *imgfile);
+int di_read(ImageFile *imgfile, unsigned char *buffer, int len);
+int di_write(ImageFile *imgfile, unsigned char *buffer, int len);
+
+int di_format(DiskImage *di, unsigned char *rawname, unsigned char *rawid);
+int di_delete(DiskImage *di, unsigned char *rawpattern, FileType type);
+int di_rename(DiskImage *di, unsigned char *oldrawname, unsigned char *newrawname, FileType type);
+
+int di_sectors_per_track(ImageType type, int track);
+int di_tracks(ImageType type);
+
+unsigned char *di_title(DiskImage *di);
+int di_track_blocks_free(DiskImage *di, int track);
+int di_is_ts_free(DiskImage *di, TrackSector ts);
+void di_alloc_ts(DiskImage *di, TrackSector ts);
+void di_free_ts(DiskImage *di, TrackSector ts);
+
+int di_rawname_from_name(unsigned char *rawname, char *name);
+int di_name_from_rawname(char *name, unsigned char *rawname);
diff --git a/D2EF/m2i.cpp b/D2EF/m2i.cpp
new file mode 100644
index 00000000..ddd98d59
--- /dev/null
+++ b/D2EF/m2i.cpp
@@ -0,0 +1,117 @@
+#include <stdlib.h>
+#include <stdio.h>
+//#include "getopt.h"
+#include <errno.h>
+//#include <libgen.h>
+#include <sys/stat.h>
+#include "dirent.h"
+#include <string.h>
+
+#include "m2i.h"
+
+struct m2i * parse_m2i(char *filename){
+	//char *m2idir = dirname(filename);
+	char *m2idir = filename;
+	char buffer[1000], filenamebuffer[1000];
+	FILE *f;
+	struct m2i *first, *last;
+	
+	f = fopen(filename, "r");
+	if(!f){
+		fprintf(stderr, "unable to open \"%s\"\n", filename);
+		exit(1);
+	}
+	read_line(f, 1000, buffer);
+	first = malloc(sizeof(struct m2i));
+	first->next = NULL;
+	first->type = '*';
+	strncpy(first->name, buffer, 16);
+	first->name[16] = '\0';
+	strcpy(first->id, "EF 2A");
+	last = first;
+	
+	while(read_line(f, 1000, buffer)){
+			if(strlen(buffer) == 0 || buffer[0] != '#'){
+				struct m2i *entry = malloc(sizeof(struct m2i));
+				entry->next = NULL;
+				last->next = entry;
+				last = entry;
+				int col1, col2, i;
+				// find the first two colons
+				for(col1 = 0; col1 < strlen(buffer)-1 && buffer[col1] != ':'; col1++);
+				for(col2 = col1+1; col2 < strlen(buffer)-1 && buffer[col2] != ':'; col2++);
+				// convert the colons in <end of line> and go to next char
+				buffer[col1++] = '\0';
+				buffer[col2++] = '\0';
+				// chop off spaces at the end
+				for(i=strlen(&buffer[col1]); i > 0 && buffer[col1+i-1] == ' '; i--);
+				buffer[col1+i] = '\0';
+				for(i=strlen(&buffer[col2]); i > 0 && buffer[col2+i-1] == ' '; i--);
+				buffer[col2+i] = '\0';
+				// quick check
+				if(strlen(buffer) == 0 || strlen(&buffer[col2]) == 0){
+					fprintf(stderr, "error while parsing \"%s\"\n", buffer);
+					exit(1);
+				}
+				// create entry
+				entry->type = tolower(buffer[0]);
+				if(entry->type != 'd' && entry->type != 'p' && entry->type != 'q'){
+					fprintf(stderr, "bad type: \"%s\"\n", buffer);
+					exit(1);
+				}
+				strncpy(entry->name, &buffer[col2], 16);
+				entry->name[16] = '\0';
+				if(entry->type == 'p' || entry->type == 'q'){
+					FILE *df;
+					strcpy(filenamebuffer, m2idir);
+					strcat(filenamebuffer, "/");
+					strcat(filenamebuffer, &buffer[col1]);
+					df = fopen(filenamebuffer, "rb");
+					if(!df){
+						fprintf(stderr, "unable to open file: \"%s\" (of line \"%s\")\n", filenamebuffer, buffer);
+						exit(1);
+					}
+					fseek(df, 0, SEEK_END);
+					entry->length = ftell(df);
+					fseek(df, 0, SEEK_SET);
+					entry->data = malloc(entry->length);
+					fread(entry->data, 1, entry->length, df);
+					fclose(df);
+				}
+			}
+	}
+	
+	fclose(f);
+	
+	return first;
+}
+
+int read_line(FILE *f, int maxlength, char* buffer){
+	static int next_char = -1;
+	int i=0;
+	
+	while(i < maxlength-1){
+		int ch = next_char >= 0 ? next_char : fgetc(f);
+		next_char = -1;
+		if(ch < 0){
+			if(i == 0)
+				return 0;
+			else
+				break;
+		}
+		if(ch == '\n' || ch == '\0'){
+			// found an newline
+			break;
+		}
+		if(ch == '\r'){
+			// found a carrige return
+			ch = fgetc(f);
+			if(ch != '\n')
+				next_char = ch;
+			break;
+		}
+		buffer[i++] = ch;
+	}
+	buffer[i] = '\0';
+	return 1;
+}
diff --git a/D2EF/m2i.h b/D2EF/m2i.h
new file mode 100644
index 00000000..e03a13ba
--- /dev/null
+++ b/D2EF/m2i.h
@@ -0,0 +1,21 @@
+#ifndef M2I_H
+#define M2I_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+struct m2i {
+	// next entry
+	struct m2i *next;
+	// m2i data
+	char type;
+	char name[17];
+	char id[6];
+	uint8_t *data;
+	uint32_t length;
+	// later processing
+};
+
+struct m2i * parse_m2i(char *filename);
+
+#endif
diff --git a/D2EF/readme.txt b/D2EF/readme.txt
new file mode 100644
index 00000000..fcedd793
--- /dev/null
+++ b/D2EF/readme.txt
@@ -0,0 +1,8 @@
+This subdirectory contains a quickly adapted version of ALeX's Disk2EasyFlash. Thanks for letting me use D2EF!
+
+The modifications are mostly removing everything that does not compile with vanilla Circle etc.
+
+The original source code can be found in this repository: https://github.com/alexkazik/disk2easyflash
+
+
+