diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..c59931ab --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +*.inc linguist-language=Assembly +*.s linguist-language=Assembly +*.asm linguist-language=Assembly +Makefile.* linguist-language=Makefile +Makefile linguist-language=Makefile +*.bin linguist-language=Binary +*.prg linguist-language=Binary +*.d64 linguist-language=Binary +*.D64 linguist-language=Binary +*.d81 linguist-language=Binary +*.D81 linguist-language=Binary diff --git a/.gitignore b/.gitignore index cd4b31c3..14a54542 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,11 @@ -GEOS64.D64 -desktop.cvt +.*.swp +*.o +/*.bin +*.prg +*.d64 +*.d81 +/desktop.cvt +/kernal.map +/GEOS64.D64 +/GEOS64.D81 build diff --git a/Makefile b/Makefile index 5ef06e3c..e43474e8 100755 --- a/Makefile +++ b/Makefile @@ -6,9 +6,12 @@ INPUT ?= joydrv AS = ca65 LD = ld65 C1541 = c1541 +EXOMIZER = exomizer PUCRUNCH = pucrunch D64_TEMPLATE = GEOS64.D64 D64_RESULT = geos.d64 +D81_TEMPLATE = GEOS64.D81 +D81_RESULT = geos.d81 DESKTOP_CVT = desktop.cvt ASFLAGS = -I inc -I . @@ -58,6 +61,8 @@ KERNAL_SOURCES= \ kernal/wheels/loadb.s \ kernal/wheels/tobasicb.s \ kernal/wheels/reux.s \ + kernal/vars.s \ + c65/start.s DRIVER_SOURCES= \ drv/drv1541.bin \ @@ -71,6 +76,7 @@ DRIVER_SOURCES= \ input/pcanalog.bin DEPS= \ + Makefile \ config.inc \ inc/c64.inc \ inc/const.inc \ @@ -95,6 +101,7 @@ ALL_BINS= \ $(BUILD_DIR)/drv/drv1541.bin \ $(BUILD_DIR)/drv/drv1571.bin \ $(BUILD_DIR)/drv/drv1581.bin \ + $(BUILD_DIR)/drv/drvf011.bin \ $(BUILD_DIR)/input/joydrv.bin \ $(BUILD_DIR)/input/amigamse.bin \ $(BUILD_DIR)/input/lightpen.bin \ @@ -103,7 +110,7 @@ ALL_BINS= \ $(BUILD_DIR)/input/pcanalog.bin -all: $(BUILD_DIR)/$(D64_RESULT) +all: $(BUILD_DIR)/$(D64_RESULT) $(BUILD_DIR)/$(D81_RESULT) regress: @echo "********** Building variant 'bsw'" @@ -129,9 +136,30 @@ $(BUILD_DIR)/$(D64_RESULT): $(BUILD_DIR)/kernal_compressed.prg echo \*\*\* Created fresh $@.; \ fi; -$(BUILD_DIR)/kernal_compressed.prg: $(BUILD_DIR)/kernal_combined.prg +$(D81_RESULT): compressed.prg compressed_c65.prg + if [ -s $(D81_TEMPLATE) ]; then \ + cp $(D81_TEMPLATE) $(D81_RESULT); \ + echo 'delete geos geoboot configure "geos kernal"' | $(C1541) $(D81_RESULT) >/dev/null; \ + echo write compressed.prg geos | $(C1541) $(D81_RESULT) >/dev/null; \ + echo write compressed_c65.prg geos65 | $(C1541) $(D81_RESULT) >/dev/null; \ + echo \*\*\* Created $(D81_RESULT) based on $(D81_TEMPLATE).; \ + else \ + rm -f $(D81_RESULT); \ + echo format geos,00 d81 $(D81_RESULT) | $(C1541) >/dev/null; \ + echo write compressed.prg geos | $(C1541) $(D81_RESULT) >/dev/null; \ + echo write compressed_c65.prg geos65 | $(C1541) $(D81_RESULT) >/dev/null; \ + if [ -e desktop.cvt ]; then echo geoswrite desktop.cvt | $(C1541) $(D81_RESULT); fi >/dev/null; \ + echo \*\*\* Created fresh $(D81_RESULT).; \ + fi; + +(BUILD_DIR)/kernal_compressed.prg: $(BUILD_DIR)/kernal_combined.prg @echo Creating $@ - $(PUCRUNCH) -f -c64 -x0x5000 $< $@ 2> /dev/null + +compressed_c65.prg: compressed.bin c65/uncrunch.o c65/loader.o + $(LD) -C c65/loader.cfg c65/loader.o c65/uncrunch.o -o $@ + +compressed.prg: combined.prg + $(PUCRUNCH) +f -c64 -x0x5000 $< $@ $(BUILD_DIR)/kernal_combined.prg: $(ALL_BINS) @echo Creating $@ from kernal.bin $(DRIVE).bin $(INPUT).bin @@ -142,6 +170,9 @@ $(BUILD_DIR)/kernal_combined.prg: $(ALL_BINS) @cat $(BUILD_DIR)/input/$(INPUT).bin >> $(BUILD_DIR)/tmp.bin 2> /dev/null @mv $(BUILD_DIR)/tmp.bin $(BUILD_DIR)/kernal_combined.prg +compressed.bin: combined.bin + $(EXOMIZER) mem $<,0x5002 -o $@ + $(BUILD_DIR)/drv/drv1541.bin: $(BUILD_DIR)/drv/drv1541.o drv/drv1541.cfg $(DEPS) $(LD) -C drv/drv1541.cfg $(BUILD_DIR)/drv/drv1541.o -o $@ @@ -151,6 +182,9 @@ $(BUILD_DIR)/drv/drv1571.bin: $(BUILD_DIR)/drv/drv1571.o drv/drv1571.cfg $(DEPS) $(BUILD_DIR)/drv/drv1581.bin: $(BUILD_DIR)/drv/drv1581.o drv/drv1581.cfg $(DEPS) $(LD) -C drv/drv1581.cfg $(BUILD_DIR)/drv/drv1581.o -o $@ +$(BUILD_DIR)/drv/drvf011.bin: $(BUILD_DIR)/drv/drvf011.o drv/drvf011.cfg $(DEPS) + $(LD) -C drv/drvf011.cfg $(BUILD_DIR)/drv/drvf011.o -o $@ + $(BUILD_DIR)/input/amigamse.bin: $(BUILD_DIR)/input/amigamse.o input/amigamse.cfg $(DEPS) $(LD) -C input/amigamse.cfg $(BUILD_DIR)/input/amigamse.o -o $@ @@ -180,3 +214,8 @@ $(BUILD_DIR)/kernal/kernal.bin: $(PREFIXED_KERNAL_OBJS) kernal/kernal_$(VARIANT) # a must! love: @echo "Not war, eh?" +the: + @echo "Just read the .PHONY line in Makefile ;-)" + +.PHONY: + clean all the love diff --git a/README.md b/README.md old mode 100755 new mode 100644 index 2b98ca6f..6719c269 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ by Berkeley Softworks, reverse engineered by *Maciej Witkowiak*, *Michael Steil*. +## Branch + +This branch of the code forms my playground for testing different MEGA65 integration strategies. + ## Description [GEOS](https://en.wikipedia.org/wiki/GEOS_(8-bit_operating_system)) is a **graphical user interface for 6502-based computers**. In the 1980s, it was commercially available for the **Commodore 64**, 128 and Plus/4 as well as the Apple II. diff --git a/c65/README.md b/c65/README.md new file mode 100644 index 00000000..b2a82579 --- /dev/null +++ b/c65/README.md @@ -0,0 +1,49 @@ +# Commodore-65 / Mega65 + +Now, for C65 build, you need CA65 (from the CC65 package) which knowns about +65CE02/4510 opcodes, maybe the GIT version from github.org. Thus file +`c65/c65.inc` is gone which had some intent to provide several 65CE02 opcodes +for the old CA65 versions. + +## Loader + +`c65/loader.s` and `c65/loader.cfg` are the source and LD65 linker configuration +file for the C65 loader, which is a standard "BASIC stub" loader must be started +from C65 mode (**not from C64 mode **). It does: + +* standard BASIC "SYS stub" stuff, also used BANK 0 +* turn fancy C65 memory mappings (`MAP`, VIC-III port $30, std CPU port ...) off +* uses exomizer's decruncher routine to derunch compressed GEOS kernal image. + Exomizer is used, as - at least for me - pucrunch didn't worked because of the + overlap between the compressed kernal and the uncompressing target area (on + C65, the BASIC are starts at a higher address than on C64), I have no idea if + pucrunch supports backward uncrunching at all to avoid this problem. Also + exomizer seems to give a better result of compression, so the situation is + good enough for me. File `uncrunch.s` is simply the source of the Exomizer's + uncrunch routine, with the settings we need. + +## Kernal + +`c65/start.s` is an extension of the "purgeable init code" from address $5000. +Call to `InitC65` is done from `kernal/start.s`. Because I liked the idea to be +able to be complied with `trap=1` as well in `config.inc`, I used another memory +segment (modified `kernal/kernal.cfg`) and the C65 specific stuff purges itself +after its turn, giving control back to `_ResetHandle` which should found the +original state. + +Currently this code does almost nothing, later it can do more (ie, M65 detection +and change disk driver to M65 specific one, so C65 is also supported this way +still). + +## Makefile and building + +Makefile was modified by me for *my* taste :-) Also the "glue" of binary fragments +done with the assembler itself, so the config.inc can be used to customize this +process, instead of hacking the Makefile ... Modifications: `Makefile` and +new file `constructor.s` in the top directory. + +## Disk driver code + +Well, that's simply borrowed from here: https://github.com/frehwagen/geos + +Source is `c65/drvf011.s`, LD65 linker configuration file is `c65/drvf011.s`. diff --git a/c65/drvf011.cfg b/c65/drvf011.cfg new file mode 100644 index 00000000..99edda9a --- /dev/null +++ b/c65/drvf011.cfg @@ -0,0 +1,7 @@ +MEMORY { + DISK_BASE: start = $9000, size = $0D80 file = %O; +} + +SEGMENTS { + drvf011: load = DISK_BASE, type = ro; +} diff --git a/c65/drvf011.s b/c65/drvf011.s new file mode 100644 index 00000000..ef13d61e --- /dev/null +++ b/c65/drvf011.s @@ -0,0 +1,1093 @@ + +;GEOS F1011 disk driver +;reassembled by Maciej 'YTM/Elysium' Witkowiak +;31.08-3.09.2001 +;ported 1581 to F011 for MEGA65 compatiblity +;05.08.2016 - 08.08.2016 + + ;*=DISK_BASE + +.include "const.inc" +.include "geossym.inc" +.include "geosmac.inc" +.include "kernal.inc" +.include "jumptab.inc" +.include "c64.inc" + +.segment "drvf011" + +DriveAddy = $0300 + +dir3Head = $9c80 + +_InitForIO: .word __InitForIO ;9000 +_DoneWithIO: .word __DoneWithIO ;9002 +_ExitTurbo: .word __ExitTurbo ;9004 +_PurgeTurbo: .word __PurgeTurbo ;9006 +_EnterTurbo: .word __EnterTurbo ;9008 +_ChangeDiskDevice: .word __ChangeDiskDevice ;900a +_NewDisk: .word __NewDisk ;900c +_ReadBlock: .word __ReadBlock ;900e +_WriteBlock: .word __WriteBlock ;9010 +_VerWriteBlock: .word __VerWriteBlock ;9012 +_OpenDisk: .word __OpenDisk ;9014 +_GetBlock: .word __GetBlock ;9016 +_PutBlock: .word __PutBlock ;9018 +_GetDirHead: .word __GetDirHead ;901a +_PutDirHead: .word __PutDirHead ;901c +_GetFreeDirBlk: .word __GetFreeDirBlk ;901e +_CalcBlksFree: .word __CalcBlksFree ;9020 +_FreeBlock: .word __FreeBlock ;9022 +_SetNextFree: .word __SetNextFree ;9024 +_FindBAMBit: .word __FindBAMBit ;9026 +_NxtBlkAlloc: .word __NxtBlkAlloc ;9028 +_BlkAlloc: .word __BlkAlloc ;902a +_ChkDkGEOS: .word __ChkDkGEOS ;902c +_SetGEOSDisk: .word __SetGEOSDisk ;902e + +Get1stDirEntry: JMP _Get1stDirEntry ;9030 +GetNxtDirEntry: JMP _GetNxtDirEntry ;9033 +GetBorder: JMP _GetBorder ;9036 +AddDirBlock: JMP _AddDirBlock ;9039 +ReadBuff: JMP _ReadBuff ;903c +WriteBuff: JMP _WriteBuff ;903f + JMP __I9042 ;9042 + JMP GetDOSError ;9045 +AllocateBlock: JMP _AllocateBlock ;9048 +ReadLink: JMP _ReadLink ;904b + +E904E: .byte $03 ;904e + +; ============================================================================== + +uname: .byte "U? 2 0 ", NULL +utands: .byte "00 00", NULL + .byte $0d +uname_end: + +bpname: .byte "B-P 2 0", NULL +bpname_end: + +cmdname: .byte " ", NULL +cmdnameLength: .byte 0 + +; ============================================================================== + +__GetDirHead: + JSR SetDirHead_1 ;904f + JSR __GetBlock + BNE GDH_0 + JSR SetDirHead_2 + JSR __GetBlock + BNE GDH_0 + JSR SetDirHead_3 + BNE __GetBlock +GDH_0: + RTS ;9064 + +_ReadBuff: + LoadW r4, diskBlkBuf ;9065 + +__GetBlock: + JSR InitForIO + JSR ReadBlock + JSR DoneWithIO + + TXA + RTS + +__PutDirHead: ;907d + JSR SetDirHead_1 + JSR __PutBlock + BNE PDH_0 + JSR SetDirHead_2 + JSR __PutBlock + BNE PDH_0 + JSR SetDirHead_3 + BNE __PutBlock +PDH_0: + RTS ;9092 + +_WriteBuff: + LoadW r4, diskBlkBuf ;9093 +__PutBlock: + JSR InitForIO + JSR WriteBlock + bnex PutBlk0 + JSR VerWriteBlock + +PutBlk0: + JSR DoneWithIO ;90ac + + TXA + RTS + +SetDirHead_1: + LDX #>curDirHead ;90b1 + LDY #dir2Head ;90b9 + LDY #dir3Head ;90c1 + LDY #cname + JSR $FFBD ; call SETNAM + + LDA #$02 ; file number 2 + LDX $BA ; last used device number + BNE _OpenBlockSkip + LDX #$08 ; default to device 8 + +_OpenBlockSkip: + LDY #$02 ; secondary address 2 + JSR $FFBA ; call SETLFS + + LDX #0 + JSR $FFC0 ; call OPEN + BCS _OpenBlockError ; if carry set, the file could not be opened + + ; open the command channel + LDA cmdnameLength + LDX #cmdname + JSR $FFBD ; call SETNAM + LDA #$0F ; file number 15 + LDX $BA ; last used device number + LDY #$0F ; secondary address 15 + JSR $FFBA ; call SETLFS + + LDX #0 + JSR $FFC0 ; call OPEN (open command channel and send U? command) + BCS _OpenBlockError + +_OpenBlockEnd: + RTS + +_OpenBlockError: + JSR $FFB7 + TAX + + JMP _OpenBlockEnd + +; ============================================================================== + +AToPetscii: + LDY #$2f + LDX #$3a + SEC +_loop1: + INY + SBC #100 + BCS _loop1 +_loop2: + DEX + ADC #10 + BMI _loop2 + ADC #$2f + + LDY #1 + STA (r4),Y + + DEY + TXA + STA (r4),Y + + RTS diff --git a/c65/loader.cfg b/c65/loader.cfg new file mode 100644 index 00000000..c5d8252e --- /dev/null +++ b/c65/loader.cfg @@ -0,0 +1,13 @@ +FEATURES { + STARTADDRESS: default = $2001; +} +MEMORY { + LOADADDR: file = %O, start = %S - 2, size = 2; + STUFF: file = %O, start = %S, size = $A000; +} +SEGMENTS { + LOADADDR: load = LOADADDR; + STUB: load = STUFF, define = yes; + CODE: load = STUFF; + GEOS: load = STUFF, define = yes; +} diff --git a/c65/loader.s b/c65/loader.s new file mode 100644 index 00000000..7f7b535a --- /dev/null +++ b/c65/loader.s @@ -0,0 +1,75 @@ +; Kind of C65 GEOS "loader" / basic stub / decruncher. +; +; (C)2016 LGB Gábor Lénárt + +;.INCLUDE "c65.inc" + +.SETCPU "4510" + +.SEGMENT "LOADADDR" + .IMPORT __STUB_LOAD__ + .WORD __STUB_LOAD__ + + +.SEGMENT "STUB" +.SCOPE + .WORD next + .WORD 2016 + .BYTE $FE, $02 ; BASIC token (double byte ...) for "BANK" + .BYTE " 0 : " + .BYTE $9E, " " ; SYS token + .BYTE <(main/10000+48) + .BYTE <(main/1000 .MOD 10+48) + .BYTE <(main/100 .MOD 10+48) + .BYTE <(main/10 .MOD 10+48) + .BYTE <(main .MOD 10+48) + .BYTE " : GEOS LOADER AND KERNAL FOR C65 MODE ONLY" + .BYTE 0 +next: .WORD 0 +.ENDSCOPE + + + +.CODE +.PROC main + SEI + CLD + LDA #0 + TAX + TAY + TAZ ; we use Z register as zero, so STZ is about the same as on 65C02 + MAP ; no CPU mapping + TAB ; just to be sure: ZP at $0000 + INY + TYS ; just to be sure: stack at $100 + SEE ; just to be sure: 8 bit stack + EOM + ; Just to be sure, enable newVic mode, to access eg VIC-3 register $30 + ; We don't need Mega65 fast mode here at any price, let's do that + ; later maybe, in c65/start.s + LDA #$A5 + STA $D02F + LDA #$96 + STA $D02F + ; CPU port stuff + LDA #$2F + STA 0 + LDA #$37 + STA 1 + ; Various VIC register stuffs + STZ $D030 ; turn ROM mappings / etc OFF + STZ $D019 ; disable VIC interrupts + STZ $D01A + LDA #$30 ; full RAM for uncrunching + STA 1 + .IMPORT uncruncher + JSR uncruncher + STZ 53280 + STZ 53281 + JMP $5000 +.ENDPROC + + + +.SEGMENT "GEOS" +.INCBIN "compressed.bin",2 diff --git a/c65/start.s b/c65/start.s new file mode 100644 index 00000000..c625be4a --- /dev/null +++ b/c65/start.s @@ -0,0 +1,81 @@ +; C65 specific stuffs, already int he combined kernal image, not the loader! +; (C)2016 LGB Gábor Lénárt + +.include "config.inc" + +.if (c65) + +.segment "c65start" +.setcpu "4510" +; Note: we can't use const.inc here, as would conflict ie with MAP constant +; with the MAP opcode defined in c65.inc ... +.import _ResetHandle +.import __c65start_LOAD__ +.import __c65start_SIZE__ +.export InitC65 + +; Relocated to $100 (well, there is place in stack ...) and executed +; there. The reason for this is commented in InitC65 +.PROC relocated_segment_nullifier + sta __c65start_LOAD__,x + inx + bne relocated_segment_nullifier + inc $102 ; self-mod of the first STA arg + dey + bne relocated_segment_nullifier + jmp _ResetHandle ; call the original stuff (at $5000) +.ENDPROC + + +.PROC InitC65 + ; We don't do MAP, LDZ #0, stack/BP setup etc here, already done in the "BASIC stub" loader, in c65/loader.s + sei + cld + ldx #$FF + txs + ; Patch out the call for this func. + ; It needs to be able to work with the trap=1 setting, it seems. + ; The same for "relocated_segment_nullifier" stuff at the end + lda #$78 ; sei + sta _ResetHandle + lda #$D8 ; cld + sta _ResetHandle+1 + lda #$A2 ; ldx immed. + sta _ResetHandle+2 + ; We need I/O + LDA #$35 + STA 1 + ; Various VIC register stuffs + LDA #$A5 ; 2 values sequence for enabling "newVic" I/O mode (that is, C65 I/O, for M65, another seq is needed) + STA $D02F + LDA #$96 + STA $D02F + LDA #64 + STA $D031 ; turn maybe used enhanched VIC3 capabilities OFF (other than FAST mode!) + STZ $D030 ; turn ROM mappings / etc OFF + STZ $D019 ; disable VIC interrupts + STZ $D01A + LDA #$15 + STA $D018 + ; give up newVic mode + ; that is for GEOS may touch new I/O regs (expecting for VIC-2 "echoes" etc) and screws up ... + ; I'm not sure if this is needed, try to remove it. + ; if someone wants to use C65 feature, than it's another question + STA $D02F + ; Clear our "c65start" segment with the relocated code to $100 and then jump to + ; the original stuff there. +to_geos: + ldx #0 +@cp: + lda relocated_segment_nullifier,x + sta $100,x + inx + bpl @cp ; 128 bytes should be enough for everyone. + ldx #0 + txa + ldy #.HIBYTE(__c65start_SIZE__) + 1 + EOM ; well just to be sure, a previous MAP does not cause problem with disabled interrupts ... + jmp $100 +.ENDPROC + +.endif diff --git a/c65/uncrunch.s b/c65/uncrunch.s new file mode 100644 index 00000000..4ad9af9d --- /dev/null +++ b/c65/uncrunch.s @@ -0,0 +1,341 @@ +; EXOMIZER is used now instead of pucrunch. We use "backward" crunching, as +; on C65 the start of BASIC area is at higher address, unpack address and +; packed stream is overlap! +; +; Copyright (c) 2002 - 2005 Magnus Lind. +; +; 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 distribution. +; +; 4. The names of this software and/or it's copyright holders may not be +; used to endorse or promote products derived from this software without +; specific prior written permission. +; +; ------------------------------------------------------------------- +; The decruncher jsr:s to the get_crunched_byte address when it wants to +; read a crunched byte. This subroutine has to preserve x and y register +; and must not modify the state of the carry flag. +; ------------------------------------------------------------------- +; ------------------------------------------------------------------- +; this function is the heart of the decruncher. +; It initializes the decruncher zeropage locations and precalculates the +; decrunch tables and decrunches the data +; This function will not change the interrupt status bit and it will not +; modify the memory configuration. +; ------------------------------------------------------------------- +; ------------------------------------------------------------------- +; if literal sequences is not used (the data was crunched with the -c +; flag) then the following line can be uncommented for shorter code. +;EXOD_LITERAL_SEQUENCES_NOT_USED = 1 + + +.CODE + +.EXPORT uncruncher +uncruncher = exod_decrunch + +exod_get_crunched_byte: + lda opbase + 1 + bne nowrap + dec opbase + 2 +nowrap: dec opbase + 1 + ; LGB: ie, backward decrunching. It's needed as on C65 the packed stream + ; would overlap with $5000, the target of the uncrunch process. +.IMPORT __GEOS_LOAD__ +.IMPORT __GEOS_SIZE__ +opbase: lda __GEOS_LOAD__ + __GEOS_SIZE__ + rts + +; ------------------------------------------------------------------- +; zero page addresses used +; ------------------------------------------------------------------- +exod_zp_len_lo = $a7 + +exod_zp_src_lo = $ae +exod_zp_src_hi = exod_zp_src_lo + 1 + +exod_zp_bits_hi = $fc + +exod_zp_bitbuf = $fd +exod_zp_dest_lo = exod_zp_bitbuf + 1 ; dest addr lo +exod_zp_dest_hi = exod_zp_bitbuf + 2 ; dest addr hi + +exod_tabl_bi = exod_decrunch_table +exod_tabl_lo = exod_decrunch_table + 52 +exod_tabl_hi = exod_decrunch_table + 104 + +; ------------------------------------------------------------------- +; no code below this comment has to be modified in order to generate +; a working decruncher of this source file. +; However, you may want to relocate the tables last in the file to a +; more suitable address. +; ------------------------------------------------------------------- + +; ------------------------------------------------------------------- +; jsr this label to decrunch, it will in turn init the tables and +; call the decruncher +; no constraints on register content, however the +; decimal flag has to be #0 (it almost always is, otherwise do a cld) +exod_decrunch: +; ------------------------------------------------------------------- +; init zeropage, x and y regs. (12 bytes) +; + ldy #0 + ldx #3 +exod_init_zp: + jsr exod_get_crunched_byte + sta exod_zp_bitbuf - 1,x + dex + bne exod_init_zp +; ------------------------------------------------------------------- +; calculate tables (50 bytes) +; x and y must be #0 when entering +; +exod_nextone: + inx + tya + and #$0f + beq exod_shortcut ; start new sequence + + txa ; this clears reg a + lsr ; and sets the carry flag + ldx exod_tabl_bi-1,y +exod_rolle: + rol + rol exod_zp_bits_hi + dex + bpl exod_rolle ; c = 0 after this (rol exod_zp_bits_hi) + + adc exod_tabl_lo-1,y + tax + + lda exod_zp_bits_hi + adc exod_tabl_hi-1,y +exod_shortcut: + sta exod_tabl_hi,y + txa + sta exod_tabl_lo,y + + ldx #4 + jsr exod_get_bits ; clears x-reg. + sta exod_tabl_bi,y + iny + cpy #52 + bne exod_nextone + ldy #0 + beq exod_begin +; ------------------------------------------------------------------- +; get bits (29 bytes) +; +; args: +; x = number of bits to get +; returns: +; a = #bits_lo +; x = #0 +; c = 0 +; z = 1 +; exod_zp_bits_hi = #bits_hi +; notes: +; y is untouched +; ------------------------------------------------------------------- +exod_get_bits: + lda #$00 + sta exod_zp_bits_hi + cpx #$01 + bcc exod_bits_done +exod_bits_next: + lsr exod_zp_bitbuf + bne exod_ok + pha +exod_literal_get_byte: + jsr exod_get_crunched_byte + bcc exod_literal_byte_gotten + ror + sta exod_zp_bitbuf + pla +exod_ok: + rol + rol exod_zp_bits_hi + dex + bne exod_bits_next +exod_bits_done: + rts +; ------------------------------------------------------------------- +; main copy loop (18(16) bytes) +; +exod_copy_next_hi: + dex + dec exod_zp_dest_hi + dec exod_zp_src_hi +exod_copy_next: + dey + .IFNDEF EXOD_LITERAL_SEQUENCES_NOT_USED + bcc exod_literal_get_byte + .ENDIF + lda (exod_zp_src_lo),y +exod_literal_byte_gotten: + sta (exod_zp_dest_lo),y +exod_copy_start: + tya + bne exod_copy_next +exod_begin: + txa + bne exod_copy_next_hi +; ------------------------------------------------------------------- +; decruncher entry point, needs calculated tables (21(13) bytes) +; x and y must be #0 when entering +; + .IFNDEF EXOD_LITERAL_SEQUENCES_NOT_USED + inx + jsr exod_get_bits + tay + bne exod_literal_start1 + .ELSE + dey + .ENDIF +exod_begin2: + inx + jsr exod_bits_next + lsr + iny + bcc exod_begin2 + .IFDEF EXOD_LITERAL_SEQUENCES_NOT_USED + beq exod_literal_start + .ENDIF + cpy #$11 + .IFNDEF EXOD_LITERAL_SEQUENCES_NOT_USED + bcc exod_sequence_start + beq exod_bits_done +; ------------------------------------------------------------------- +; literal sequence handling (13(2) bytes) +; + ldx #$10 + jsr exod_get_bits +exod_literal_start1: + sta