From 416b19eb6e62b4f5025f238f037f385c8ca188e1 Mon Sep 17 00:00:00 2001 From: frntc <48584231+frntc@users.noreply.github.com> Date: Sun, 15 Nov 2020 18:20:40 +0100 Subject: [PATCH] Disk2EasyFlash integration --- D2EF/C64/Makefile | 34 + D2EF/C64/binaries.php | 32 + D2EF/C64/copyright.php | 11 + D2EF/C64/emu_chrin.asm | 60 ++ D2EF/C64/emu_helper.asm | 82 ++ D2EF/C64/emu_load.asm | 164 ++++ D2EF/C64/emu_vectors.asm | 205 +++++ D2EF/C64/helper/commands.asm | 444 +++++++++++ D2EF/C64/helper/commands16.asm | 464 +++++++++++ D2EF/C64/helper/commands8.asm | 248 ++++++ D2EF/C64/helper/macros.asm | 111 +++ D2EF/C64/kapi_hi.asm | 5 + D2EF/C64/kapi_lo.asm | 5 + D2EF/C64/kapi_nm.asm | 5 + D2EF/C64/launcher_hi.asm | 32 + D2EF/C64/main.asm | 199 +++++ D2EF/C64/mkdep.php | 26 + D2EF/C64/startup.bin | Bin 0 -> 512 bytes D2EF/C64/startup.s | 265 +++++++ D2EF/binaries.cpp | 15 + D2EF/binaries.h | 31 + D2EF/bundle.cpp | 170 ++++ D2EF/bundle.h | 15 + D2EF/cart.h | 71 ++ D2EF/d64.cpp | 121 +++ D2EF/d64.h | 9 + D2EF/disk2easyflash.cpp | 305 ++++++++ D2EF/diskimage.cpp | 1337 ++++++++++++++++++++++++++++++++ D2EF/diskimage.h | 90 +++ D2EF/m2i.cpp | 117 +++ D2EF/m2i.h | 21 + D2EF/readme.txt | 8 + 32 files changed, 4702 insertions(+) create mode 100644 D2EF/C64/Makefile create mode 100644 D2EF/C64/binaries.php create mode 100644 D2EF/C64/copyright.php create mode 100644 D2EF/C64/emu_chrin.asm create mode 100644 D2EF/C64/emu_helper.asm create mode 100644 D2EF/C64/emu_load.asm create mode 100644 D2EF/C64/emu_vectors.asm create mode 100644 D2EF/C64/helper/commands.asm create mode 100644 D2EF/C64/helper/commands16.asm create mode 100644 D2EF/C64/helper/commands8.asm create mode 100644 D2EF/C64/helper/macros.asm create mode 100644 D2EF/C64/kapi_hi.asm create mode 100644 D2EF/C64/kapi_lo.asm create mode 100644 D2EF/C64/kapi_nm.asm create mode 100644 D2EF/C64/launcher_hi.asm create mode 100644 D2EF/C64/main.asm create mode 100644 D2EF/C64/mkdep.php create mode 100644 D2EF/C64/startup.bin create mode 100644 D2EF/C64/startup.s create mode 100644 D2EF/binaries.cpp create mode 100644 D2EF/binaries.h create mode 100644 D2EF/bundle.cpp create mode 100644 D2EF/bundle.h create mode 100644 D2EF/cart.h create mode 100644 D2EF/d64.cpp create mode 100644 D2EF/d64.h create mode 100644 D2EF/disk2easyflash.cpp create mode 100644 D2EF/diskimage.cpp create mode 100644 D2EF/diskimage.h create mode 100644 D2EF/m2i.cpp create mode 100644 D2EF/m2i.h create mode 100644 D2EF/readme.txt 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 @@ +\n"); + +$fh = fopen("binaries.h", "w"); +fwrite($fh, "#ifndef BINARIES_H +#define BINARIES_H + +#include +"); + +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 @@ += 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 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 @@ + z5VkYQ5wFopBPa@9a&qg6rG9}^ykXuv<_#bYsXJ`NM1U8}+_Le2z1^|rd!=9bhP)yS zT7@5cp;tZb=Dv!QoYrrE?-LNUzde(Q!DDmxQkCQ5xus?^&zwB&+Fl zs@J{)eY^PUT!l{p6hn#!fuck4!AiTh=9&%21n@$hjdE@B3;AaN#qPwi7|t(^kd&C U=?Uqhq(`I$V*U+E^ImS7FL-rM+W-In literal 0 HcmV?d00001 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 +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 +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 +#include +//#include "getopt.h" +#include +//#include +#include +//#include "dirent.h" +#include + +//#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; jname); 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 +#include + +#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 + +// 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 +#include +//#include "getopt.h" +#include +//#include +#include +//#include "dirent.h" +#include + +#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 +#include +#include +#include +#include + +#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; iname); 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; idata[entry->length++] = 0x20; // SPACE + } + + entry->data[entry->length++] = 0x22; // QUOTE + for(i=0; iname); 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; idata[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 +#include +#include +#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 +#include +//#include "getopt.h" +#include +//#include +#include +#include "dirent.h" +#include + +#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 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 +#include + +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 + + +